LCOV - code coverage report
Current view: top level - EnergyPlus - PlantPipingSystemsManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 2442 2900 84.2 %
Date: 2024-08-24 18:31:18 Functions: 80 85 94.1 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cassert>
      50             : #include <cmath>
      51             : #include <memory>
      52             : #include <set>
      53             : 
      54             : // ObjexxFCL Headers
      55             : #include <ObjexxFCL/Array.functions.hh>
      56             : #include <ObjexxFCL/Fmath.hh>
      57             : #include <ObjexxFCL/floops.hh>
      58             : #include <ObjexxFCL/string.functions.hh>
      59             : 
      60             : // EnergyPlus Headers
      61             : #include <EnergyPlus/BranchNodeConnections.hh>
      62             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      63             : #include <EnergyPlus/DataEnvironment.hh>
      64             : #include <EnergyPlus/DataHVACGlobals.hh>
      65             : #include <EnergyPlus/DataHeatBalSurface.hh>
      66             : #include <EnergyPlus/DataHeatBalance.hh>
      67             : #include <EnergyPlus/DataIPShortCuts.hh>
      68             : #include <EnergyPlus/DataLoopNode.hh>
      69             : #include <EnergyPlus/DataSurfaces.hh>
      70             : #include <EnergyPlus/FluidProperties.hh>
      71             : #include <EnergyPlus/General.hh>
      72             : #include <EnergyPlus/GlobalNames.hh>
      73             : #include <EnergyPlus/GroundTemperatureModeling/GroundTemperatureModelManager.hh>
      74             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      75             : #include <EnergyPlus/Material.hh>
      76             : #include <EnergyPlus/NodeInputManager.hh>
      77             : #include <EnergyPlus/OutputProcessor.hh>
      78             : #include <EnergyPlus/Plant/DataPlant.hh>
      79             : #include <EnergyPlus/PlantPipingSystemsManager.hh>
      80             : #include <EnergyPlus/PlantUtilities.hh>
      81             : #include <EnergyPlus/UtilityRoutines.hh>
      82             : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      83             : 
      84             : namespace EnergyPlus {
      85             : 
      86             : namespace PlantPipingSystemsManager {
      87             : 
      88             :     // Module containing the routines dealing with the PipingSystems
      89             : 
      90             :     // MODULE INFORMATION:
      91             :     //       AUTHOR         Edwin Lee
      92             :     //       DATE WRITTEN   Summer 2011
      93             :     //       MODIFIED       na
      94             :     //       RE-ENGINEERED  na
      95             : 
      96             :     // PURPOSE OF THIS MODULE:
      97             :     // Simulate all cases of plant "piping systems"
      98             :     //      PipingSystem:Underground
      99             :     //      PipingSystem:Generalized
     100             : 
     101             :     // METHODOLOGY EMPLOYED:
     102             :     // A 3D mesh is established, with full 3D conduction being employed
     103             :     // For ground simulation, moisture content and soil freezing is included
     104             :     // The mesh can include any number of pipe circuits placed within the domain
     105             :     // The mesh can interact with basement walls also
     106             : 
     107             : #pragma clang diagnostic push
     108             : #pragma ide diagnostic ignored "cert-err58-cpp"
     109             :     // MODULE PARAMETER DEFINITIONS:
     110             :     std::string const ObjName_ug_GeneralDomain("PipingSystem:Underground:Domain");
     111             :     std::string const ObjName_Circuit("PipingSystem:Underground:PipeCircuit");
     112             :     std::string const ObjName_Segment("PipingSystem:Underground:PipeSegment");
     113             :     std::string const ObjName_HorizTrench("GroundHeatExchanger:HorizontalTrench");
     114             :     std::string const ObjName_ZoneCoupled_Slab("Site:GroundDomain:Slab");
     115             :     std::string const ObjName_ZoneCoupled_Basement("Site:GroundDomain:Basement");
     116             :     constexpr std::array<std::string_view, static_cast<int>(SegmentFlow::Num)> flowDirectionNamesUC = {"INCREASINGZ", "DECREASINGZ"};
     117             : 
     118             : #pragma clang diagnostic pop
     119             : 
     120         796 :     void CheckIfAnySlabs(EnergyPlusData &state)
     121             :     {
     122             :         // SUBROUTINE INFORMATION:
     123             :         //       AUTHOR         Matt Mitchell
     124             :         //       DATE WRITTEN   May 2014
     125             :         //       MODIFIED       na
     126             :         //       RE-ENGINEERED  na
     127         796 :         int numSlabsCheck(state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjName_ZoneCoupled_Slab));
     128         796 :         state.dataGlobal->AnySlabsInModel = (numSlabsCheck > 0);
     129         796 :     }
     130             : 
     131         796 :     void CheckIfAnyBasements(EnergyPlusData &state)
     132             :     {
     133             :         // SUBROUTINE INFORMATION:
     134             :         //       AUTHOR         Matt Mitchell
     135             :         //       DATE WRITTEN   May 2014
     136             :         //       MODIFIED       na
     137             :         //       RE-ENGINEERED  na
     138         796 :         int const numBasementsCheck(state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjName_ZoneCoupled_Basement));
     139         796 :         state.dataGlobal->AnyBasementsInModel = (numBasementsCheck > 0);
     140         796 :     }
     141             : 
     142           5 :     PlantComponent *Circuit::factory(EnergyPlusData &state, [[maybe_unused]] DataPlant::PlantEquipmentType objectType, const std::string &objectName)
     143             :     {
     144             :         // Process the input data for circuits if it hasn't been done already
     145           5 :         if (state.dataPlantPipingSysMgr->GetInputFlag) {
     146           5 :             GetPipingSystemsAndGroundDomainsInput(state);
     147           5 :             state.dataPlantPipingSysMgr->GetInputFlag = false;
     148             :         }
     149             :         // Now look for this particular pipe in the list
     150           5 :         for (auto &circuit : state.dataPlantPipingSysMgr->circuits) {
     151           5 :             if (circuit.Name == objectName) {
     152           5 :                 return &circuit;
     153             :             }
     154          10 :         }
     155             :         // If we didn't find it, fatal
     156             :         ShowFatalError(state, format("PipeCircuitInfoFactory: Error getting inputs for circuit named: {}", objectName)); // LCOV_EXCL_LINE
     157             :         // Shut up the compiler
     158             :         return nullptr; // LCOV_EXCL_LINE
     159             :     }
     160             : 
     161       14502 :     void Circuit::simulate(EnergyPlusData &state,
     162             :                            [[maybe_unused]] const PlantLocation &calledFromLocation,
     163             :                            [[maybe_unused]] bool const FirstHVACIteration,
     164             :                            [[maybe_unused]] Real64 &CurLoad,
     165             :                            [[maybe_unused]] bool const RunFlag)
     166             :     {
     167             :         // Retrieve the parent domain index for this pipe circuit
     168       14502 :         auto &thisDomain = state.dataPlantPipingSysMgr->domains[this->ParentDomainIndex];
     169             : 
     170             :         // Do any initialization here
     171       14502 :         thisDomain.InitPipingSystems(state, this);
     172             : 
     173             :         // Update the temperature field
     174       14502 :         thisDomain.PerformIterationLoop(state, this);
     175             : 
     176             :         // Update outlet nodes, etc.
     177       14502 :         thisDomain.UpdatePipingSystems(state, this);
     178       14502 :     }
     179             : 
     180       13446 :     void SimulateGroundDomains(EnergyPlusData &state, bool initOnly)
     181             :     {
     182             : 
     183             :         // SUBROUTINE INFORMATION:
     184             :         //       AUTHOR         Matt Mitchell
     185             :         //       DATE WRITTEN   Spring 2014
     186             :         //       MODIFIED       by Sushobhit Acharya, March 2015
     187             :         //       RE-ENGINEERED  na
     188             : 
     189             :         // Read input if necessary
     190       13446 :         if (state.dataPlantPipingSysMgr->GetInputFlag) {
     191           6 :             GetPipingSystemsAndGroundDomainsInput(state);
     192           6 :             state.dataPlantPipingSysMgr->GetInputFlag = false;
     193             :         }
     194             : 
     195       26892 :         for (auto &thisDomain : state.dataPlantPipingSysMgr->domains) {
     196             : 
     197             :             // if the domain contains a pipe circuit, it shouldn't be initialized here, it has its own entry point
     198       13446 :             if (thisDomain.HasAPipeCircuit) continue;
     199             : 
     200       13446 :             if (thisDomain.DomainNeedsToBeMeshed) {
     201           6 :                 thisDomain.developMesh(state);
     202             :             }
     203             : 
     204       13446 :             thisDomain.DomainNeedsToBeMeshed = false;
     205             : 
     206             :             // The time init should be done here before we DoOneTimeInits because the DoOneTimeInits
     207             :             // includes a ground temperature initialization, which is based on the Cur%CurSimTimeSeconds variable
     208             :             // which would be carried over from the previous environment
     209       13446 :             thisDomain.Cur.CurSimTimeStepSize = state.dataGlobal->TimeStepZone * Constant::SecInHour;
     210       13446 :             thisDomain.Cur.CurSimTimeSeconds =
     211       13446 :                 ((state.dataGlobal->DayOfSim - 1) * 24 + (state.dataGlobal->HourOfDay - 1) +
     212       13446 :                  (state.dataGlobal->TimeStep - 1) * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed) *
     213             :                 Constant::SecInHour;
     214             : 
     215             :             // There are also some inits that are "close to one time" inits...( one-time in standalone, each envrn in E+ )
     216       13446 :             if ((state.dataGlobal->BeginSimFlag && thisDomain.BeginSimInit) || (state.dataGlobal->BeginEnvrnFlag && thisDomain.BeginSimEnvironment)) {
     217             : 
     218          12 :                 thisDomain.DoOneTimeInitializations(state, nullptr);
     219             : 
     220          12 :                 if (thisDomain.HasZoneCoupledSlab) {
     221          10 :                     int Xmax = ubound(thisDomain.Cells, 1);
     222             :                     // int yMax = ubound( thisDomain.Cells, 2 );
     223          10 :                     int Zmax = ubound(thisDomain.Cells, 3);
     224             : 
     225          10 :                     thisDomain.WeightingFactor.allocate({0, Xmax}, {0, Zmax});
     226          10 :                     thisDomain.WeightedHeatFlux.allocate({0, Xmax}, {0, Zmax});
     227             :                 }
     228             : 
     229          12 :                 thisDomain.BeginSimInit = false;
     230          12 :                 thisDomain.BeginSimEnvironment = false;
     231             :             }
     232       13446 :             if (!state.dataGlobal->BeginSimFlag) thisDomain.BeginSimInit = true;
     233       13446 :             if (!state.dataGlobal->BeginEnvrnFlag) thisDomain.BeginSimEnvironment = true;
     234             : 
     235             :             // Reset the heat fluxes if domain update has been completed
     236       13446 :             if (thisDomain.ResetHeatFluxFlag) {
     237       10657 :                 thisDomain.AggregateHeatFlux = 0;
     238       10657 :                 thisDomain.AggregateWallHeatFlux = 0;
     239       10657 :                 thisDomain.AggregateFloorHeatFlux = 0;
     240       10657 :                 thisDomain.NumHeatFlux = 0;
     241       10657 :                 thisDomain.ResetHeatFluxFlag = false;
     242             :             }
     243             : 
     244       13446 :             if (!initOnly) {
     245             :                 // Aggregate the heat flux
     246             :                 // Zone-coupled slab
     247       13440 :                 if (thisDomain.HasZoneCoupledSlab) {
     248       10656 :                     thisDomain.AggregateHeatFlux += thisDomain.GetZoneInterfaceHeatFlux(state);
     249       10656 :                     thisDomain.NumHeatFlux += 1;
     250       10656 :                     thisDomain.HeatFlux = thisDomain.AggregateHeatFlux / thisDomain.NumHeatFlux;
     251             :                 } else { // Coupled basement
     252             : 
     253             :                     // basement walls
     254        2784 :                     thisDomain.AggregateWallHeatFlux += thisDomain.GetBasementWallHeatFlux(state);
     255             :                     // basement floor
     256        2784 :                     thisDomain.AggregateFloorHeatFlux += thisDomain.GetBasementFloorHeatFlux(state);
     257             : 
     258        2784 :                     thisDomain.NumHeatFlux += 1;
     259        2784 :                     thisDomain.WallHeatFlux = thisDomain.AggregateWallHeatFlux / thisDomain.NumHeatFlux;
     260        2784 :                     thisDomain.FloorHeatFlux = thisDomain.AggregateFloorHeatFlux / thisDomain.NumHeatFlux;
     261             :                 }
     262             : 
     263             :                 // Aggregate the heat flux
     264             :                 // Zone-coupled slab
     265       13440 :                 if (thisDomain.HasZoneCoupledSlab) {
     266       10656 :                     thisDomain.AggregateHeatFlux += thisDomain.GetZoneInterfaceHeatFlux(state);
     267       10656 :                     thisDomain.NumHeatFlux += 1;
     268       10656 :                     thisDomain.HeatFlux = thisDomain.AggregateHeatFlux / thisDomain.NumHeatFlux;
     269        2784 :                 } else if (thisDomain.HasZoneCoupledBasement) { // Coupled basement
     270             :                     // basement walls
     271        2784 :                     thisDomain.AggregateWallHeatFlux += thisDomain.GetBasementWallHeatFlux(state);
     272             :                     // basement floor
     273        2784 :                     thisDomain.AggregateFloorHeatFlux += thisDomain.GetBasementFloorHeatFlux(state);
     274             : 
     275        2784 :                     thisDomain.NumHeatFlux += 1;
     276        2784 :                     thisDomain.WallHeatFlux = thisDomain.AggregateWallHeatFlux / thisDomain.NumHeatFlux;
     277        2784 :                     thisDomain.FloorHeatFlux = thisDomain.AggregateFloorHeatFlux / thisDomain.NumHeatFlux;
     278             :                 }
     279             : 
     280             :                 // Zone-coupled slab
     281       13440 :                 if (thisDomain.HasZoneCoupledSlab) {
     282             : 
     283       10656 :                     thisDomain.HeatFlux = thisDomain.AggregateHeatFlux / thisDomain.NumHeatFlux;
     284             : 
     285       10656 :                     Real64 ZoneTemp = 0.0;
     286             : 
     287             :                     // Set ZoneTemp equal to the average air temperature of the zones the coupled surfaces are part of.
     288       39744 :                     for (auto &z : thisDomain.ZoneCoupledSurfaces) {
     289       29088 :                         int ZoneNum = z.Zone;
     290       29088 :                         ZoneTemp += state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).ZTAV;
     291       10656 :                     }
     292             : 
     293       10656 :                     ZoneTemp = ZoneTemp / thisDomain.ZoneCoupledSurfaces.size();
     294       10656 :                     Real64 AvgSlabTemp = thisDomain.GetAverageTempByType(state, CellType::ZoneGroundInterface);
     295             : 
     296       10656 :                     int yMax = ubound(thisDomain.Cells, 2);
     297             : 
     298      149184 :                     for (int Z = lbound(thisDomain.Cells, 3); Z <= ubound(thisDomain.Cells, 3); ++Z) {
     299     1939392 :                         for (int X = lbound(thisDomain.Cells, 1); X <= ubound(thisDomain.Cells, 1); ++X) {
     300             :                             // Zone interface cells
     301     1800864 :                             if (thisDomain.Cells(X, yMax, Z).cellType == CellType::ZoneGroundInterface) {
     302      383616 :                                 thisDomain.WeightingFactor(X, Z) =
     303      383616 :                                     std::abs((ZoneTemp - thisDomain.Cells(X, yMax, Z).Temperature_PrevTimeStep) / (ZoneTemp - AvgSlabTemp));
     304             :                             }
     305             :                         }
     306             :                     }
     307             : 
     308             :                     // Set initial weighted heat flux
     309      149184 :                     for (int Z = lbound(thisDomain.Cells, 3); Z <= ubound(thisDomain.Cells, 3); ++Z) {
     310     1939392 :                         for (int X = lbound(thisDomain.Cells, 1); X <= ubound(thisDomain.Cells, 1); ++X) {
     311             :                             // Zone interface cells
     312     1800864 :                             if (thisDomain.Cells(X, yMax, Z).cellType == CellType::ZoneGroundInterface) {
     313      383616 :                                 thisDomain.WeightedHeatFlux(X, Z) = thisDomain.WeightingFactor(X, Z) * thisDomain.HeatFlux;
     314             :                             }
     315             :                         }
     316             :                     }
     317             : 
     318             :                     // Weighted heat flux and uniform heat flux balance energy may not balance exactly
     319             :                     // Calculate difference and adjust
     320       10656 :                     thisDomain.TotalEnergyUniformHeatFlux = thisDomain.HeatFlux * thisDomain.SlabArea * thisDomain.Cur.CurSimTimeStepSize;
     321       10656 :                     thisDomain.TotalEnergyWeightedHeatFlux = 0.0;
     322             : 
     323      149184 :                     for (int Z = lbound(thisDomain.Cells, 3); Z <= ubound(thisDomain.Cells, 3); ++Z) {
     324     1939392 :                         for (int X = lbound(thisDomain.Cells, 1); X <= ubound(thisDomain.Cells, 1); ++X) {
     325             :                             // Zone interface cells
     326     1800864 :                             if (thisDomain.Cells(X, yMax, Z).cellType == CellType::ZoneGroundInterface) {
     327      383616 :                                 auto &cell = thisDomain.Cells(X, yMax, Z);
     328      383616 :                                 thisDomain.TotalEnergyWeightedHeatFlux +=
     329      383616 :                                     thisDomain.WeightedHeatFlux(X, Z) * cell.width() * cell.depth() * thisDomain.Cur.CurSimTimeStepSize;
     330             :                             }
     331             :                         }
     332             :                     }
     333             : 
     334       10656 :                     thisDomain.HeatFluxWeightingFactor = thisDomain.TotalEnergyWeightedHeatFlux / thisDomain.TotalEnergyUniformHeatFlux;
     335       10656 :                     thisDomain.TotalEnergyWeightedHeatFlux = 0.0;
     336             : 
     337             :                     // Finally, adjust the weighted heat flux so that energy balances
     338      149184 :                     for (int Z = lbound(thisDomain.Cells, 3); Z <= ubound(thisDomain.Cells, 3); ++Z) {
     339     1939392 :                         for (int X = lbound(thisDomain.Cells, 1); X <= ubound(thisDomain.Cells, 1); ++X) {
     340             :                             // Zone interface cells
     341     1800864 :                             if (thisDomain.Cells(X, yMax, Z).cellType == CellType::ZoneGroundInterface) {
     342      383616 :                                 auto &cell = thisDomain.Cells(X, yMax, Z);
     343      383616 :                                 thisDomain.WeightedHeatFlux(X, Z) = thisDomain.WeightedHeatFlux(X, Z) / thisDomain.HeatFluxWeightingFactor;
     344      383616 :                                 thisDomain.TotalEnergyWeightedHeatFlux +=
     345      383616 :                                     thisDomain.WeightedHeatFlux(X, Z) * cell.width() * cell.depth() * thisDomain.Cur.CurSimTimeStepSize;
     346             :                             }
     347             :                         }
     348             :                     }
     349             : 
     350             :                 } else { // Coupled basement
     351        2784 :                     thisDomain.WallHeatFlux = thisDomain.AggregateWallHeatFlux / thisDomain.NumHeatFlux;
     352        2784 :                     thisDomain.FloorHeatFlux = thisDomain.AggregateFloorHeatFlux / thisDomain.NumHeatFlux;
     353             :                 }
     354             : 
     355             :                 // Shift history arrays only if necessary
     356       13440 :                 if (std::abs(thisDomain.Cur.CurSimTimeSeconds - thisDomain.Cur.PrevSimTimeSeconds) > 1.0e-6) {
     357       13440 :                     thisDomain.Cur.PrevSimTimeSeconds = thisDomain.Cur.CurSimTimeSeconds;
     358       13440 :                     thisDomain.ShiftTemperaturesForNewTimeStep();
     359       13440 :                     thisDomain.DomainNeedsSimulation = true;
     360             :                 }
     361       13440 :                 thisDomain.PerformIterationLoop(state);
     362             :             }
     363       13446 :         }
     364             : 
     365       13446 :         if (state.dataPlantPipingSysMgr->WriteEIOFlag) {
     366             :             // Write eio header
     367             :             static constexpr std::string_view DomainCellsToEIOHeader(
     368             :                 "! <Domain Name>, Total Number of Domain Cells, Total Number of Ground Surface Cells, Total Number of Insulation Cells\n");
     369           6 :             print(state.files.eio, DomainCellsToEIOHeader);
     370             : 
     371             :             // Write eio data
     372          12 :             for (auto &thisDomain : state.dataPlantPipingSysMgr->domains) {
     373             :                 static constexpr std::string_view DomainCellsToEIO("{},{:5},{:5},{:5}\n");
     374           6 :                 print(state.files.eio,
     375             :                       DomainCellsToEIO,
     376           6 :                       thisDomain.Name,
     377           6 :                       thisDomain.NumDomainCells,
     378           6 :                       thisDomain.NumGroundSurfCells,
     379           6 :                       thisDomain.NumInsulationCells);
     380           6 :             }
     381           6 :             state.dataPlantPipingSysMgr->WriteEIOFlag = false;
     382             :         }
     383       13446 :     }
     384             : 
     385          11 :     void GetPipingSystemsAndGroundDomainsInput(EnergyPlusData &state)
     386             :     {
     387             : 
     388             :         // SUBROUTINE INFORMATION:
     389             :         //       AUTHOR         Edwin Lee
     390             :         //       DATE WRITTEN   Summer 2011
     391             :         //       MODIFIED       na
     392             :         //       RE-ENGINEERED  na
     393             : 
     394             :         static constexpr std::string_view RoutineName("GetPipingSystemsAndGroundDomainsInput");
     395             : 
     396             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     397          11 :         bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
     398             : 
     399             :         // Read number of objects and allocate main data structures - first domains
     400          11 :         int NumGeneralizedDomains = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjName_ug_GeneralDomain);
     401          11 :         int NumHorizontalTrenches = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjName_HorizTrench);
     402          11 :         int NumZoneCoupledDomains = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjName_ZoneCoupled_Slab);
     403          11 :         int NumBasements = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjName_ZoneCoupled_Basement);
     404          11 :         int TotalNumDomains = NumGeneralizedDomains + NumHorizontalTrenches + NumZoneCoupledDomains + NumBasements;
     405          11 :         state.dataPlantPipingSysMgr->domains.resize(TotalNumDomains);
     406             : 
     407             :         // then circuits
     408          11 :         int NumPipeCircuits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjName_Circuit);
     409             : 
     410             :         // Read in raw inputs, don't try to interpret dependencies yet
     411          11 :         ReadGeneralDomainInputs(state, 1, NumGeneralizedDomains, ErrorsFound);
     412             :         // ReadPipeCircuitInputs(ErrorsFound);
     413          11 :         ReadHorizontalTrenchInputs(state, NumGeneralizedDomains + 1, NumPipeCircuits + 1, ErrorsFound);
     414             : 
     415             :         // This is heavily dependent on the order of the domains in the main array.
     416          11 :         ReadZoneCoupledDomainInputs(state, NumGeneralizedDomains + NumHorizontalTrenches + 1, NumZoneCoupledDomains, ErrorsFound);
     417             : 
     418             :         // This is heavily dependent on the order of the domains in the main array.
     419          11 :         ReadBasementInputs(state, NumGeneralizedDomains + NumHorizontalTrenches + NumZoneCoupledDomains + 1, NumBasements, ErrorsFound);
     420             : 
     421             :         // Report errors that are purely input problems
     422          11 :         if (ErrorsFound) ShowFatalError(state, format("{}: Preceding input errors cause program termination.", RoutineName));
     423             : 
     424             :         // Setup output variables
     425          11 :         SetupPipingSystemOutputVariables(state);
     426             : 
     427             :         // Validate DOMAIN-CIRCUIT cross references
     428          22 :         for (int DomainNum = 0; DomainNum < TotalNumDomains; ++DomainNum) {
     429             : 
     430             :             // Convenience
     431          11 :             auto &thisDomain = state.dataPlantPipingSysMgr->domains[DomainNum];
     432             : 
     433             :             // validate pipe domain-circuit name-to-index references
     434          16 :             for (auto &thisCircuit : thisDomain.circuits) {
     435           5 :                 thisCircuit->ParentDomainIndex = DomainNum;
     436          11 :             }
     437             : 
     438             :             // correct segment locations for: INTERNAL DATA STRUCTURE Y VALUE MEASURED FROM BOTTOM OF DOMAIN,
     439             :             //                                INPUT WAS MEASURED FROM GROUND SURFACE
     440          16 :             for (auto &thisCircuit : thisDomain.circuits) {
     441          19 :                 for (auto &thisSegment : thisCircuit->pipeSegments) {
     442          14 :                     thisSegment->PipeLocation.Y = thisDomain.Extents.yMax - thisSegment->PipeLocation.Y;
     443           5 :                 }
     444          11 :             }
     445             : 
     446             :             // correct segment locations for: BASEMENT X SHIFT
     447          11 :             if (thisDomain.HasBasement && thisDomain.BasementZone.ShiftPipesByWidth) {
     448           2 :                 for (auto &thisCircuit : thisDomain.circuits) {
     449           7 :                     for (auto &thisSegment : thisCircuit->pipeSegments) {
     450           6 :                         thisSegment->PipeLocation.X += thisDomain.BasementZone.Width;
     451           1 :                     }
     452           1 :                 }
     453             :             }
     454             : 
     455             :             // now we will have good values of pipe segment locations, we can validate them
     456          16 :             for (auto &thisCircuit : thisDomain.circuits) {
     457             :                 // check to make sure it isn't outside the domain
     458          19 :                 for (auto &thisSegment : thisCircuit->pipeSegments) {
     459          14 :                     if ((thisSegment->PipeLocation.X > thisDomain.Extents.xMax) || (thisSegment->PipeLocation.X < 0.0) ||
     460          14 :                         (thisSegment->PipeLocation.Y > thisDomain.Extents.yMax) || (thisSegment->PipeLocation.Y < 0.0)) {
     461           0 :                         ShowSevereError(state,
     462           0 :                                         format("PipingSystems::{}: A pipe was outside of the domain extents after performing corrections for "
     463             :                                                "basement or burial depth.",
     464             :                                                RoutineName));
     465           0 :                         ShowContinueError(state, format("Pipe segment name:{}", thisSegment->Name));
     466           0 :                         ShowContinueError(
     467             :                             state,
     468           0 :                             format("Corrected pipe location: ( x,y )=( {:.2T},{:.2T} )", thisSegment->PipeLocation.X, thisSegment->PipeLocation.Y));
     469             :                     }
     470           5 :                 } // segment loop
     471          11 :             }     // circuit loop
     472             : 
     473             :         } // domain loop
     474             : 
     475             :         // If we encountered any other errors that we couldn't handle separately than stop now
     476          11 :         if (ErrorsFound) {
     477           0 :             ShowFatalError(state, format("{}:{}: Errors found in input.", RoutineName, ObjName_ug_GeneralDomain));
     478             :         }
     479          11 :     }
     480             : 
     481          11 :     void ReadGeneralDomainInputs(EnergyPlusData &state, int const IndexStart, int const NumGeneralizedDomains, bool &ErrorsFound)
     482             :     {
     483             : 
     484             :         // SUBROUTINE INFORMATION:
     485             :         //       AUTHOR         Edwin Lee
     486             :         //       DATE WRITTEN   Summer 2011
     487             :         //       MODIFIED       na
     488             :         //       RE-ENGINEERED  na
     489             : 
     490             :         // SUBROUTINE PARAMETER DEFINITIONS:
     491             :         static constexpr std::string_view RoutineName("ReadGeneralDomainInputs");
     492             : 
     493             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     494             :         int NumAlphas;  // Number of Alphas for each GetObjectItem call
     495             :         int NumNumbers; // Number of Numbers for each GetObjectItem call
     496             :         int IOStatus;   // Used in GetObjectItem
     497             :         int CurIndex;
     498             : 
     499          15 :         for (int DomainNum = IndexStart; DomainNum <= NumGeneralizedDomains; ++DomainNum) {
     500             : 
     501             :             // Set up all the inputs for this domain object
     502           8 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     503             :                                                                      ObjName_ug_GeneralDomain,
     504             :                                                                      DomainNum,
     505           4 :                                                                      state.dataIPShortCut->cAlphaArgs,
     506             :                                                                      NumAlphas,
     507           4 :                                                                      state.dataIPShortCut->rNumericArgs,
     508             :                                                                      NumNumbers,
     509             :                                                                      IOStatus,
     510           4 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     511           4 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     512           4 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     513           4 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     514             : 
     515           4 :             auto &thisDomain = state.dataPlantPipingSysMgr->domains[DomainNum - 1];
     516             : 
     517             :             // Get the name, validate
     518           4 :             thisDomain.Name = state.dataIPShortCut->cAlphaArgs(1);
     519           4 :             Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
     520             :             // Mesh extents, validated by IP
     521           4 :             thisDomain.Extents.xMax = state.dataIPShortCut->rNumericArgs(1);
     522           4 :             thisDomain.Extents.yMax = state.dataIPShortCut->rNumericArgs(2);
     523           4 :             thisDomain.Extents.zMax = state.dataIPShortCut->rNumericArgs(3);
     524             : 
     525             :             // X direction mesh inputs, validated by IP
     526           4 :             thisDomain.Mesh.X.RegionMeshCount = static_cast<int>(state.dataIPShortCut->rNumericArgs(4));
     527             :             {
     528           4 :                 std::string const &meshDistribution = state.dataIPShortCut->cAlphaArgs(2);
     529           4 :                 if (meshDistribution == "UNIFORM") {
     530           4 :                     thisDomain.Mesh.X.thisMeshDistribution = MeshDistribution::Uniform;
     531           0 :                 } else if (meshDistribution == "SYMMETRICGEOMETRIC") {
     532           0 :                     thisDomain.Mesh.X.thisMeshDistribution = MeshDistribution::SymmetricGeometric;
     533           0 :                     if (mod(thisDomain.Mesh.X.RegionMeshCount, 2) != 0) {
     534           0 :                         ShowWarningError(state, format("PipingSystems:{}: Invalid mesh type-count combination.", RoutineName));
     535           0 :                         ShowContinueError(state, format("Instance:{}={}", ObjName_ug_GeneralDomain, thisDomain.Name));
     536           0 :                         ShowContinueError(state, "An ODD-valued X mesh count was found in the input for symmetric geometric configuration.");
     537           0 :                         ShowContinueError(state, "This is invalid, mesh count incremented UP by one to next EVEN value.");
     538           0 :                         ++thisDomain.Mesh.X.RegionMeshCount;
     539           0 :                         thisDomain.Mesh.X.GeometricSeriesCoefficient = state.dataIPShortCut->rNumericArgs(5);
     540             :                     } else {
     541           0 :                         thisDomain.Mesh.X.GeometricSeriesCoefficient = 1.0;
     542             :                     }
     543             :                 } else {
     544           0 :                     IssueSevereInputFieldError(state,
     545             :                                                RoutineName,
     546             :                                                ObjName_ug_GeneralDomain,
     547           0 :                                                state.dataIPShortCut->cAlphaArgs(1),
     548           0 :                                                state.dataIPShortCut->cAlphaFieldNames(2),
     549           0 :                                                state.dataIPShortCut->cAlphaArgs(2),
     550             :                                                "Use a choice from the available mesh type keys.",
     551             :                                                ErrorsFound);
     552             :                 }
     553             :             }
     554             : 
     555             :             // Y direction mesh inputs, validated by IP
     556           4 :             thisDomain.Mesh.Y.RegionMeshCount = static_cast<int>(state.dataIPShortCut->rNumericArgs(6));
     557             :             {
     558           4 :                 std::string const meshDistribution = stripped(state.dataIPShortCut->cAlphaArgs(3));
     559           4 :                 if (meshDistribution == "UNIFORM") {
     560           4 :                     thisDomain.Mesh.Y.thisMeshDistribution = MeshDistribution::Uniform;
     561           0 :                 } else if (meshDistribution == "SYMMETRICGEOMETRIC") {
     562           0 :                     thisDomain.Mesh.Y.thisMeshDistribution = MeshDistribution::SymmetricGeometric;
     563           0 :                     if (mod(thisDomain.Mesh.Y.RegionMeshCount, 2) != 0) {
     564           0 :                         ShowWarningError(state, format("PipingSystems:{}: Invalid mesh type-count combination.", RoutineName));
     565           0 :                         ShowContinueError(state, format("Instance:{}={}", ObjName_ug_GeneralDomain, thisDomain.Name));
     566           0 :                         ShowContinueError(state, "An ODD-valued Y mesh count was found in the input for symmetric geometric configuration.");
     567           0 :                         ShowContinueError(state, "This is invalid, mesh count incremented UP by one to next EVEN value.");
     568           0 :                         ++thisDomain.Mesh.Y.RegionMeshCount;
     569           0 :                         thisDomain.Mesh.Y.GeometricSeriesCoefficient = state.dataIPShortCut->rNumericArgs(7);
     570             :                     } else {
     571           0 :                         thisDomain.Mesh.Y.GeometricSeriesCoefficient = 1.0;
     572             :                     }
     573             :                 } else {
     574           0 :                     IssueSevereInputFieldError(state,
     575             :                                                RoutineName,
     576             :                                                ObjName_ug_GeneralDomain,
     577           0 :                                                state.dataIPShortCut->cAlphaArgs(1),
     578           0 :                                                state.dataIPShortCut->cAlphaFieldNames(3),
     579           0 :                                                state.dataIPShortCut->cAlphaArgs(3),
     580             :                                                "Use a choice from the available mesh type keys.",
     581             :                                                ErrorsFound);
     582             :                 }
     583           4 :             }
     584             : 
     585             :             // Z direction mesh inputs, validated by IP
     586           4 :             thisDomain.Mesh.Z.RegionMeshCount = static_cast<int>(state.dataIPShortCut->rNumericArgs(8));
     587             :             {
     588           4 :                 std::string const meshDistribution = stripped(state.dataIPShortCut->cAlphaArgs(4));
     589           4 :                 if (meshDistribution == "UNIFORM") {
     590           4 :                     thisDomain.Mesh.Z.thisMeshDistribution = MeshDistribution::Uniform;
     591           0 :                 } else if (meshDistribution == "SYMMETRICGEOMETRIC") {
     592           0 :                     thisDomain.Mesh.Z.thisMeshDistribution = MeshDistribution::SymmetricGeometric;
     593           0 :                     if (mod(thisDomain.Mesh.Z.RegionMeshCount, 2) != 0) {
     594           0 :                         ShowWarningError(state, format("PipingSystems:{}: Invalid mesh type-count combination.", RoutineName));
     595           0 :                         ShowContinueError(state, format("Instance:{}={}", ObjName_ug_GeneralDomain, thisDomain.Name));
     596           0 :                         ShowContinueError(state, "An ODD-valued Z mesh count was found in the input for symmetric geometric configuration.");
     597           0 :                         ShowContinueError(state, "This is invalid, mesh count incremented UP by one to next EVEN value.");
     598           0 :                         ++thisDomain.Mesh.Z.RegionMeshCount;
     599           0 :                         thisDomain.Mesh.Z.GeometricSeriesCoefficient = state.dataIPShortCut->rNumericArgs(9);
     600             :                     } else {
     601           0 :                         thisDomain.Mesh.Z.GeometricSeriesCoefficient = 1.0;
     602             :                     }
     603             :                 } else {
     604           0 :                     IssueSevereInputFieldError(state,
     605             :                                                RoutineName,
     606             :                                                ObjName_ug_GeneralDomain,
     607           0 :                                                state.dataIPShortCut->cAlphaArgs(1),
     608           0 :                                                state.dataIPShortCut->cAlphaFieldNames(4),
     609           0 :                                                state.dataIPShortCut->cAlphaArgs(4),
     610             :                                                "Use a choice from the available mesh type keys.",
     611             :                                                ErrorsFound);
     612             :                 }
     613           4 :             }
     614             : 
     615             :             // Soil properties, validated min/max by IP
     616           4 :             thisDomain.GroundProperties.Conductivity = state.dataIPShortCut->rNumericArgs(10);
     617           4 :             thisDomain.GroundProperties.Density = state.dataIPShortCut->rNumericArgs(11);
     618           4 :             thisDomain.GroundProperties.SpecificHeat = state.dataIPShortCut->rNumericArgs(12);
     619             : 
     620             :             // Moisture properties, validated min/max by IP, and converted to a fraction for computation here
     621           4 :             thisDomain.Moisture.Theta_liq = state.dataIPShortCut->rNumericArgs(13) / 100.0;
     622           4 :             thisDomain.Moisture.Theta_sat = state.dataIPShortCut->rNumericArgs(14) / 100.0;
     623             : 
     624             :             // check if there is a basement
     625           4 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "YES")) {
     626           1 :                 thisDomain.HasBasement = true;
     627           3 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "NO")) {
     628           3 :                 thisDomain.HasBasement = false;
     629             :             } else {
     630           0 :                 IssueSevereInputFieldError(state,
     631             :                                            RoutineName,
     632             :                                            ObjName_ug_GeneralDomain,
     633           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     634           0 :                                            state.dataIPShortCut->cAlphaFieldNames(7),
     635           0 :                                            state.dataIPShortCut->cAlphaArgs(7),
     636             :                                            "Must enter either yes or no.",
     637             :                                            ErrorsFound);
     638             :             }
     639             : 
     640             :             // more work to do if there is a basement
     641           4 :             if (thisDomain.HasBasement) {
     642             : 
     643             :                 // check if there are blank inputs related to the basement,
     644             :                 // IP can't catch this because they are inherently optional if there ISN'T a basement
     645           2 :                 if (state.dataIPShortCut->lNumericFieldBlanks(15) || state.dataIPShortCut->lNumericFieldBlanks(16) ||
     646           3 :                     state.dataIPShortCut->lAlphaFieldBlanks(8) || state.dataIPShortCut->lAlphaFieldBlanks(9) ||
     647           1 :                     state.dataIPShortCut->lAlphaFieldBlanks(10)) {
     648           0 :                     ShowSevereError(state,
     649           0 :                                     format("Erroneous basement inputs for {}={}", ObjName_ug_GeneralDomain, state.dataIPShortCut->cAlphaArgs(1)));
     650           0 :                     ShowContinueError(state, "Object specified to have a basement, while at least one basement input was left blank.");
     651           0 :                     ErrorsFound = true;
     652             :                 }
     653             : 
     654             :                 // get dimensions for meshing
     655           1 :                 CurIndex = 15;
     656           1 :                 thisDomain.BasementZone.Width = state.dataIPShortCut->rNumericArgs(CurIndex);
     657           1 :                 if (thisDomain.BasementZone.Width <= 0.0) {
     658           0 :                     IssueSevereInputFieldError(state,
     659             :                                                RoutineName,
     660             :                                                ObjName_ug_GeneralDomain,
     661           0 :                                                state.dataIPShortCut->cAlphaArgs(1),
     662           0 :                                                state.dataIPShortCut->cNumericFieldNames(CurIndex),
     663           0 :                                                state.dataIPShortCut->rNumericArgs(CurIndex),
     664             :                                                "Basement width must be a positive nonzero value.",
     665             :                                                ErrorsFound);
     666             :                 }
     667             : 
     668           1 :                 CurIndex = 16;
     669           1 :                 thisDomain.BasementZone.Depth = state.dataIPShortCut->rNumericArgs(CurIndex);
     670           1 :                 if (thisDomain.BasementZone.Depth <= 0.0) {
     671           0 :                     IssueSevereInputFieldError(state,
     672             :                                                RoutineName,
     673             :                                                ObjName_ug_GeneralDomain,
     674           0 :                                                state.dataIPShortCut->cAlphaArgs(1),
     675           0 :                                                state.dataIPShortCut->cNumericFieldNames(CurIndex),
     676           0 :                                                state.dataIPShortCut->rNumericArgs(CurIndex),
     677             :                                                "Basement depth must be a positive nonzero value.",
     678             :                                                ErrorsFound);
     679             :                 }
     680             : 
     681             :                 // check for dimension shift
     682           1 :                 CurIndex = 8;
     683           1 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(CurIndex), "YES")) {
     684           1 :                     thisDomain.BasementZone.ShiftPipesByWidth = true;
     685           0 :                 } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(CurIndex), "NO")) {
     686           0 :                     thisDomain.BasementZone.ShiftPipesByWidth = false;
     687             :                 } else {
     688           0 :                     IssueSevereInputFieldError(state,
     689             :                                                RoutineName,
     690             :                                                ObjName_ug_GeneralDomain,
     691           0 :                                                state.dataIPShortCut->cAlphaArgs(1),
     692           0 :                                                state.dataIPShortCut->cAlphaFieldNames(CurIndex),
     693           0 :                                                state.dataIPShortCut->cAlphaArgs(CurIndex),
     694             :                                                "Must enter either yes or no.",
     695             :                                                ErrorsFound);
     696             :                 }
     697             : 
     698             :                 // get boundary condition model names and indices --error check
     699           1 :                 CurIndex = 9;
     700           1 :                 thisDomain.BasementZone.WallBoundaryOSCMName = state.dataIPShortCut->cAlphaArgs(CurIndex);
     701           1 :                 thisDomain.BasementZone.WallBoundaryOSCMIndex =
     702           1 :                     Util::FindItemInList(thisDomain.BasementZone.WallBoundaryOSCMName, state.dataSurface->OSCM);
     703           1 :                 if (thisDomain.BasementZone.WallBoundaryOSCMIndex <= 0) {
     704           0 :                     IssueSevereInputFieldError(state,
     705             :                                                RoutineName,
     706             :                                                ObjName_ug_GeneralDomain,
     707           0 :                                                state.dataIPShortCut->cAlphaArgs(1),
     708           0 :                                                state.dataIPShortCut->cAlphaFieldNames(CurIndex),
     709           0 :                                                state.dataIPShortCut->cAlphaArgs(CurIndex),
     710             :                                                "Could not match with an Other Side Conditions Model input object.",
     711             :                                                ErrorsFound);
     712             :                 } else {
     713           1 :                     auto const &wallIndexes = GetSurfaceIndecesForOSCM(state, thisDomain.BasementZone.WallBoundaryOSCMIndex);
     714           1 :                     if (wallIndexes.empty()) {
     715           0 :                         IssueSevereInputFieldError(
     716             :                             state,
     717             :                             RoutineName,
     718             :                             ObjName_ug_GeneralDomain,
     719           0 :                             state.dataIPShortCut->cAlphaArgs(1),
     720           0 :                             state.dataIPShortCut->cAlphaFieldNames(CurIndex),
     721           0 :                             state.dataIPShortCut->cAlphaArgs(CurIndex),
     722             :                             "Entry matched an Other Side Conditions Model, but no surfaces were found to be using this Other Side Conditions Model.",
     723             :                             ErrorsFound);
     724             :                     } else {
     725           1 :                         thisDomain.BasementZone.WallSurfacePointers = wallIndexes;
     726             :                     }
     727           1 :                 }
     728             : 
     729           1 :                 CurIndex = 10;
     730           1 :                 thisDomain.BasementZone.FloorBoundaryOSCMName = state.dataIPShortCut->cAlphaArgs(CurIndex);
     731           1 :                 thisDomain.BasementZone.FloorBoundaryOSCMIndex =
     732           1 :                     Util::FindItemInList(thisDomain.BasementZone.FloorBoundaryOSCMName, state.dataSurface->OSCM);
     733           1 :                 if (thisDomain.BasementZone.FloorBoundaryOSCMIndex <= 0) {
     734           0 :                     IssueSevereInputFieldError(state,
     735             :                                                RoutineName,
     736             :                                                ObjName_ug_GeneralDomain,
     737           0 :                                                state.dataIPShortCut->cAlphaArgs(1),
     738           0 :                                                state.dataIPShortCut->cAlphaFieldNames(CurIndex),
     739           0 :                                                state.dataIPShortCut->cAlphaArgs(CurIndex),
     740             :                                                "Could not match with an Other Side Conditions Model input object.",
     741             :                                                ErrorsFound);
     742             :                 } else {
     743           1 :                     auto const &floorIndexes = GetSurfaceIndecesForOSCM(state, thisDomain.BasementZone.FloorBoundaryOSCMIndex);
     744           1 :                     if (floorIndexes.empty()) {
     745           0 :                         IssueSevereInputFieldError(
     746             :                             state,
     747             :                             RoutineName,
     748             :                             ObjName_ug_GeneralDomain,
     749           0 :                             state.dataIPShortCut->cAlphaArgs(1),
     750           0 :                             state.dataIPShortCut->cAlphaFieldNames(CurIndex),
     751           0 :                             state.dataIPShortCut->cAlphaArgs(CurIndex),
     752             :                             "Entry matched an Other Side Conditions Model, but no surfaces were found to be using this Other Side Conditions Model.",
     753             :                             ErrorsFound);
     754             :                     } else {
     755           1 :                         thisDomain.BasementZone.FloorSurfacePointers = floorIndexes;
     756             :                     }
     757           1 :                 }
     758             :             }
     759             : 
     760             :             // get some convergence tolerances, minimum/maximum are enforced by the IP, along with default values if user left them blank
     761           4 :             thisDomain.SimControls.Convergence_CurrentToPrevIteration = state.dataIPShortCut->rNumericArgs(17);
     762           4 :             thisDomain.SimControls.MaxIterationsPerTS = static_cast<int>(state.dataIPShortCut->rNumericArgs(18));
     763             : 
     764             :             // additional evapotranspiration parameter, min/max validated by IP
     765           4 :             thisDomain.Moisture.GroundCoverCoefficient = state.dataIPShortCut->rNumericArgs(19);
     766             : 
     767             :             // Allocate the circuit placeholder arrays
     768           4 :             int const NumCircuitsInThisDomain = int(state.dataIPShortCut->rNumericArgs(20));
     769             : 
     770             :             // Need to store the ground temp stuff because it will get wiped out in the call to the circuit factory
     771           4 :             std::string const groundTempType = state.dataIPShortCut->cAlphaArgs(5);
     772           4 :             std::string const groundTempName = state.dataIPShortCut->cAlphaArgs(6);
     773             : 
     774             :             // Need to loop once to store the names ahead of time because calling the segment factory will override cAlphaArgs
     775           4 :             std::vector<std::string> circuitNamesToFind;
     776           4 :             int constexpr NumAlphasBeforePipeCircOne = 10;
     777           8 :             for (int CircuitCtr = 1; CircuitCtr <= NumCircuitsInThisDomain; ++CircuitCtr) {
     778           4 :                 CurIndex = CircuitCtr + NumAlphasBeforePipeCircOne;
     779           4 :                 if (state.dataIPShortCut->lAlphaFieldBlanks(CurIndex)) {
     780           0 :                     IssueSevereInputFieldError(state,
     781             :                                                RoutineName,
     782             :                                                ObjName_Segment,
     783           0 :                                                state.dataIPShortCut->cAlphaArgs(1),
     784           0 :                                                state.dataIPShortCut->cAlphaFieldNames(CurIndex),
     785           0 :                                                state.dataIPShortCut->cAlphaArgs(CurIndex),
     786             :                                                "Expected a pipe circuit name, check pipe circuit count input field.",
     787             :                                                ErrorsFound);
     788             :                 }
     789           4 :                 circuitNamesToFind.push_back(state.dataIPShortCut->cAlphaArgs(CurIndex));
     790             :             }
     791             :             // then we can loop through and allow the factory to be called and carry on
     792           8 :             for (auto &circuitNameToFind : circuitNamesToFind) {
     793           4 :                 thisDomain.circuits.push_back(Circuit::factory(state, circuitNameToFind, ErrorsFound));
     794           4 :             }
     795             : 
     796             :             // Initialize ground temperature model and get pointer reference
     797           4 :             thisDomain.groundTempModel = GetGroundTempModelAndInit(state, groundTempType, groundTempName);
     798           4 :         }
     799          11 :     }
     800             : 
     801          11 :     void ReadZoneCoupledDomainInputs(EnergyPlusData &state, int const StartingDomainNumForZone, int const NumZoneCoupledDomains, bool &ErrorsFound)
     802             :     {
     803             : 
     804             :         // SUBROUTINE INFORMATION:
     805             :         //       AUTHOR         Edwin Lee
     806             :         //       DATE WRITTEN   Summer 2011
     807             :         //       MODIFIED       Spring 2014 by Matt Mitchell and Sushobhit Acharya to accommodate ground coupled calculations
     808             :         //       RE-ENGINEERED  na
     809             : 
     810             :         // SUBROUTINE PARAMETER DEFINITIONS:
     811             :         static constexpr std::string_view RoutineName("ReadZoneCoupledDomainInputs");
     812             : 
     813             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     814             :         int NumAlphas;  // Number of Alphas for each GetObjectItem call
     815             :         int NumNumbers; // Number of Numbers for each GetObjectItem call
     816             :         int IOStatus;   // Used in GetObjectItem
     817             : 
     818             :         // initialize these counters properly so they can be incremented within the DO loop
     819          11 :         int DomainCtr = StartingDomainNumForZone - 1;
     820             : 
     821             :         // For each domain, we need to process the inputs into a local array of derived type, then resolve each one, creating definitions for a zone
     822             :         // coupled domain. This way, the outer get input routines can handle it as though they were generalized routines
     823             : 
     824          16 :         for (int ZoneCoupledDomainCtr = 1; ZoneCoupledDomainCtr <= NumZoneCoupledDomains; ++ZoneCoupledDomainCtr) {
     825             : 
     826             :             // Increment the domain counters here
     827           5 :             ++DomainCtr;
     828             : 
     829             :             // Read all the inputs for this domain object
     830          10 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     831             :                                                                      ObjName_ZoneCoupled_Slab,
     832             :                                                                      ZoneCoupledDomainCtr,
     833           5 :                                                                      state.dataIPShortCut->cAlphaArgs,
     834             :                                                                      NumAlphas,
     835           5 :                                                                      state.dataIPShortCut->rNumericArgs,
     836             :                                                                      NumNumbers,
     837             :                                                                      IOStatus,
     838           5 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     839           5 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     840           5 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     841           5 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     842             : 
     843           5 :             auto &thisDomain = state.dataPlantPipingSysMgr->domains[DomainCtr - 1];
     844             : 
     845             :             // Get the name, validate
     846             :             // Domain name
     847           5 :             thisDomain.Name = state.dataIPShortCut->cAlphaArgs(1);
     848             : 
     849           5 :             GlobalNames::VerifyUniqueInterObjectName(state,
     850           5 :                                                      state.dataPlantPipingSysMgr->GroundDomainUniqueNames,
     851           5 :                                                      state.dataIPShortCut->cAlphaArgs(1),
     852             :                                                      ObjName_ZoneCoupled_Slab,
     853           5 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     854             :                                                      ErrorsFound);
     855             : 
     856             :             // Read in the rest of the inputs into the local type for clarity during transition
     857           5 :             thisDomain.Extents.yMax = state.dataIPShortCut->rNumericArgs(1);
     858           5 :             thisDomain.PerimeterOffset = state.dataIPShortCut->rNumericArgs(3);
     859           5 :             thisDomain.GroundProperties.Conductivity = state.dataIPShortCut->rNumericArgs(4);
     860           5 :             thisDomain.GroundProperties.Density = state.dataIPShortCut->rNumericArgs(5);
     861           5 :             thisDomain.GroundProperties.SpecificHeat = state.dataIPShortCut->rNumericArgs(6);
     862           5 :             thisDomain.Moisture.Theta_liq = state.dataIPShortCut->rNumericArgs(7) / 100.0;
     863           5 :             thisDomain.Moisture.Theta_sat = state.dataIPShortCut->rNumericArgs(8) / 100.0;
     864           5 :             thisDomain.Moisture.GroundCoverCoefficient = state.dataIPShortCut->rNumericArgs(9);
     865           5 :             thisDomain.HorizInsWidth = state.dataIPShortCut->rNumericArgs(10);
     866           5 :             thisDomain.VertInsDepth = state.dataIPShortCut->rNumericArgs(11);
     867             : 
     868             :             // Set flag for slab in-grade or slab on-grade
     869           5 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(5), "INGRADE")) {
     870           4 :                 thisDomain.SlabInGradeFlag = true;
     871           1 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(5), "ONGRADE")) {
     872           1 :                 thisDomain.SlabInGradeFlag = false;
     873             :             } else {
     874           0 :                 ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5)));
     875           0 :                 ShowContinueError(state, format("Found in: {}", thisDomain.Name));
     876           0 :                 ErrorsFound = true;
     877             :             }
     878             : 
     879             :             // Get slab material properties
     880           5 :             if (thisDomain.SlabInGradeFlag) {
     881           4 :                 thisDomain.SlabMaterialNum =
     882           4 :                     Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(6), state.dataMaterial->Material, state.dataMaterial->TotMaterials);
     883           4 :                 if (thisDomain.SlabMaterialNum == 0) {
     884           0 :                     ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
     885           0 :                     ShowContinueError(state, format("Found in: {}", thisDomain.Name));
     886           0 :                     ErrorsFound = true;
     887             :                 } else {
     888           4 :                     thisDomain.SlabThickness = state.dataMaterial->Material(thisDomain.SlabMaterialNum)->Thickness;
     889           4 :                     thisDomain.SlabProperties.Density = state.dataMaterial->Material(thisDomain.SlabMaterialNum)->Density;
     890           4 :                     thisDomain.SlabProperties.SpecificHeat = state.dataMaterial->Material(thisDomain.SlabMaterialNum)->SpecHeat;
     891           4 :                     thisDomain.SlabProperties.Conductivity = state.dataMaterial->Material(thisDomain.SlabMaterialNum)->Conductivity;
     892             :                 }
     893             :             }
     894             : 
     895             :             // set flag for horizontal insulation
     896           5 :             if (thisDomain.SlabInGradeFlag) {
     897           4 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "NO")) {
     898           0 :                     thisDomain.HorizInsPresentFlag = false;
     899           4 :                 } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "YES")) {
     900           4 :                     thisDomain.HorizInsPresentFlag = true;
     901             :                 } else {
     902           0 :                     ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
     903           0 :                     ShowContinueError(state, format("Found in: {}", thisDomain.Name));
     904           0 :                     ErrorsFound = true;
     905             :                 }
     906             :             }
     907             : 
     908             :             // Get horizontal insulation material properties
     909           5 :             if (thisDomain.HorizInsPresentFlag) {
     910           4 :                 thisDomain.HorizInsMaterialNum =
     911           4 :                     Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(8), state.dataMaterial->Material, state.dataMaterial->TotMaterials);
     912           4 :                 if (thisDomain.HorizInsMaterialNum == 0) {
     913           0 :                     ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8)));
     914           0 :                     ShowContinueError(state, format("Found in: {}", thisDomain.Name));
     915           0 :                     ErrorsFound = true;
     916             :                 } else {
     917           4 :                     thisDomain.HorizInsThickness = state.dataMaterial->Material(thisDomain.HorizInsMaterialNum)->Thickness;
     918           4 :                     thisDomain.HorizInsProperties.Density = state.dataMaterial->Material(thisDomain.HorizInsMaterialNum)->Density;
     919           4 :                     thisDomain.HorizInsProperties.SpecificHeat = state.dataMaterial->Material(thisDomain.HorizInsMaterialNum)->SpecHeat;
     920           4 :                     thisDomain.HorizInsProperties.Conductivity = state.dataMaterial->Material(thisDomain.HorizInsMaterialNum)->Conductivity;
     921           4 :                     if (SiteGroundDomainUsingNoMassMat(state, thisDomain.HorizInsThickness, thisDomain.HorizInsMaterialNum)) {
     922           0 :                         ErrorsFound = true;
     923           0 :                         SiteGroundDomainNoMassMatError(
     924           0 :                             state, state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8), thisDomain.Name);
     925             :                     }
     926             :                 }
     927             : 
     928             :                 // Set flag for horizontal insulation extents
     929           4 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(9), "PERIMETER")) {
     930           0 :                     thisDomain.FullHorizInsPresent = false;
     931             :                     // Horizontal insulation perimeter width
     932           0 :                     if (thisDomain.HorizInsWidth <= 0.0) {
     933           0 :                         ShowSevereError(state, format("Invalid {}", state.dataIPShortCut->cNumericFieldNames(10)));
     934           0 :                         ShowContinueError(state, format("Found in: {}", thisDomain.Name));
     935           0 :                         ErrorsFound = true;
     936             :                     }
     937           4 :                 } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(9), "FULL")) {
     938           4 :                     thisDomain.FullHorizInsPresent = true;
     939             :                 } else {
     940           0 :                     ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9)));
     941           0 :                     ShowContinueError(state, format("Found in: {}", thisDomain.Name));
     942           0 :                     ErrorsFound = true;
     943             :                 }
     944             :             }
     945             : 
     946             :             // set flag for vertical insulation
     947           5 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(10), "NO")) {
     948           0 :                 thisDomain.VertInsPresentFlag = false;
     949           5 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(10), "YES")) {
     950           5 :                 thisDomain.VertInsPresentFlag = true;
     951             :             } else {
     952           0 :                 ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(10), state.dataIPShortCut->cAlphaArgs(10)));
     953           0 :                 ShowContinueError(state, format("Found in: {}", thisDomain.Name));
     954           0 :                 ErrorsFound = true;
     955             :             }
     956             : 
     957             :             // Get vertical insulation material properties
     958           5 :             if (thisDomain.VertInsPresentFlag) {
     959           5 :                 thisDomain.VertInsMaterialNum =
     960           5 :                     Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(11), state.dataMaterial->Material, state.dataMaterial->TotMaterials);
     961           5 :                 if (thisDomain.VertInsMaterialNum == 0) {
     962           0 :                     ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(11), state.dataIPShortCut->cAlphaArgs(11)));
     963           0 :                     ShowContinueError(state, format("Found in: {}", thisDomain.Name));
     964           0 :                     ErrorsFound = true;
     965             :                 } else {
     966           5 :                     thisDomain.VertInsThickness = state.dataMaterial->Material(thisDomain.VertInsMaterialNum)->Thickness;
     967           5 :                     thisDomain.VertInsProperties.Density = state.dataMaterial->Material(thisDomain.VertInsMaterialNum)->Density;
     968           5 :                     thisDomain.VertInsProperties.SpecificHeat = state.dataMaterial->Material(thisDomain.VertInsMaterialNum)->SpecHeat;
     969           5 :                     thisDomain.VertInsProperties.Conductivity = state.dataMaterial->Material(thisDomain.VertInsMaterialNum)->Conductivity;
     970           5 :                     if (SiteGroundDomainUsingNoMassMat(state, thisDomain.VertInsThickness, thisDomain.VertInsMaterialNum)) {
     971           0 :                         ErrorsFound = true;
     972           0 :                         SiteGroundDomainNoMassMatError(
     973           0 :                             state, state.dataIPShortCut->cAlphaFieldNames(11), state.dataIPShortCut->cAlphaArgs(11), thisDomain.Name);
     974             :                     }
     975             :                 }
     976             : 
     977             :                 // vertical insulation depth
     978           5 :                 if (thisDomain.VertInsDepth > thisDomain.Extents.yMax || thisDomain.VertInsDepth <= 0.0) {
     979           0 :                     ShowSevereError(state, format("Invalid {}", state.dataIPShortCut->cNumericFieldNames(11)));
     980           0 :                     ShowContinueError(state, format("Found in: {}", thisDomain.Name));
     981           0 :                     ErrorsFound = true;
     982             :                 }
     983             :             }
     984             : 
     985             :             // Set simulation interval flag
     986           5 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(12), "TIMESTEP")) {
     987           3 :                 thisDomain.SimTimeStepFlag = true;
     988           2 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(12), "HOURLY")) {
     989           2 :                 thisDomain.SimHourlyFlag = true;
     990             :             } else {
     991           0 :                 ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(12), state.dataIPShortCut->cAlphaArgs(12)));
     992           0 :                 ShowContinueError(state, format("Found in: {}", thisDomain.Name));
     993           0 :                 ErrorsFound = true;
     994             :             }
     995             : 
     996             :             //******* We'll first set up the domain ********
     997           5 :             thisDomain.IsActuallyPartOfAHorizontalTrench = false;
     998           5 :             thisDomain.HasAPipeCircuit = false;
     999           5 :             thisDomain.HasZoneCoupledSlab = true;
    1000             : 
    1001             :             // get boundary condition model names and indices -- error check
    1002           5 :             thisDomain.ZoneCoupledOSCMIndex = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataSurface->OSCM);
    1003           5 :             if (thisDomain.ZoneCoupledOSCMIndex <= 0) {
    1004           0 :                 IssueSevereInputFieldError(state,
    1005             :                                            RoutineName,
    1006             :                                            ObjName_ZoneCoupled_Slab,
    1007           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
    1008           0 :                                            state.dataIPShortCut->cAlphaFieldNames(4),
    1009           0 :                                            state.dataIPShortCut->cAlphaArgs(4),
    1010             :                                            "Could not match with an Other Side Conditions Model input object.",
    1011             :                                            ErrorsFound);
    1012           0 :                 ErrorsFound = true;
    1013             :             } else {
    1014           5 :                 int const NumSurfacesWithThisOSCM = GetSurfaceCountForOSCM(state, thisDomain.ZoneCoupledOSCMIndex);
    1015           5 :                 if (NumSurfacesWithThisOSCM <= 0) {
    1016           0 :                     IssueSevereInputFieldError(
    1017             :                         state,
    1018             :                         RoutineName,
    1019             :                         ObjName_ZoneCoupled_Slab,
    1020           0 :                         state.dataIPShortCut->cAlphaArgs(1),
    1021           0 :                         state.dataIPShortCut->cAlphaFieldNames(4),
    1022           0 :                         state.dataIPShortCut->cAlphaArgs(4),
    1023             :                         "Entry matched an Other Side Conditions Model, but no surfaces were found to be using this Other Side Conditions Model.",
    1024             :                         ErrorsFound);
    1025           0 :                     ErrorsFound = true;
    1026             :                 } else {
    1027           5 :                     thisDomain.ZoneCoupledSurfaces = GetSurfaceDataForOSCM(state, thisDomain.ZoneCoupledOSCMIndex);
    1028             :                 }
    1029             :             }
    1030             : 
    1031             :             // Total surface area
    1032          15 :             auto lambda = [](Real64 total, ZoneCoupledSurfaceData const &z) { return total + z.SurfaceArea; };
    1033           5 :             Real64 const ThisArea = std::accumulate(thisDomain.ZoneCoupledSurfaces.begin(), thisDomain.ZoneCoupledSurfaces.end(), 0.0, lambda);
    1034             : 
    1035           5 :             thisDomain.SlabArea = ThisArea / 4; // We are only interested in 1/4 of total area due to symmetry
    1036             : 
    1037             :             // Surface dimensions
    1038           5 :             Real64 thisAspectRatio = state.dataIPShortCut->rNumericArgs(2);
    1039           5 :             thisDomain.SlabWidth = std::sqrt(ThisArea / thisAspectRatio);
    1040           5 :             thisDomain.SlabLength = thisDomain.SlabWidth * thisAspectRatio;
    1041             : 
    1042             :             // Check horizontal insulation width so as to prevent overlapping insulation. VertInsThickness is used here since it is used for vertical
    1043             :             // partition thickness.
    1044           5 :             if (!thisDomain.FullHorizInsPresent && ThisArea > 0.0) {
    1045           1 :                 if (2 * (thisDomain.HorizInsWidth + thisDomain.VertInsThickness) > thisDomain.SlabWidth ||
    1046           1 :                     2 * (thisDomain.HorizInsWidth + thisDomain.VertInsThickness) > thisDomain.SlabLength) {
    1047           0 :                     ShowContinueError(state, format("{}: Perimeter insulation width is too large.", RoutineName));
    1048           0 :                     ShowContinueError(state, "This would cause overlapping insulation. Check inputs.");
    1049           0 :                     ShowContinueError(state, "Defaulting to full horizontal insulation.");
    1050           0 :                     ShowContinueError(state, format("Found in: {}", thisDomain.Name));
    1051           0 :                     thisDomain.FullHorizInsPresent = true;
    1052             :                 }
    1053             :             }
    1054             : 
    1055             :             // Set ground domain dimensions
    1056           5 :             thisDomain.Extents.xMax = thisDomain.PerimeterOffset + thisDomain.SlabWidth / 2;
    1057             :             // thisDomain.Extents.yMax read above
    1058           5 :             thisDomain.Extents.zMax = thisDomain.PerimeterOffset + thisDomain.SlabLength / 2;
    1059             : 
    1060             :             // Get mesh parameters
    1061             : 
    1062             :             // Mesh inputs
    1063           5 :             thisDomain.Mesh.X.thisMeshDistribution = MeshDistribution::SymmetricGeometric;
    1064           5 :             thisDomain.Mesh.Y.thisMeshDistribution = MeshDistribution::SymmetricGeometric;
    1065           5 :             thisDomain.Mesh.Z.thisMeshDistribution = MeshDistribution::SymmetricGeometric;
    1066             : 
    1067           5 :             Real64 MeshCoefficient = state.dataIPShortCut->rNumericArgs(12);
    1068           5 :             if (MeshCoefficient == 0.0) MeshCoefficient = 1.6;
    1069           5 :             thisDomain.Mesh.X.GeometricSeriesCoefficient = MeshCoefficient;
    1070           5 :             thisDomain.Mesh.Y.GeometricSeriesCoefficient = MeshCoefficient;
    1071           5 :             thisDomain.Mesh.Z.GeometricSeriesCoefficient = MeshCoefficient;
    1072             : 
    1073           5 :             int MeshCount = static_cast<int>(state.dataIPShortCut->rNumericArgs(13));
    1074           5 :             if (MeshCount == 0.0) MeshCount = 6;
    1075           5 :             thisDomain.Mesh.X.RegionMeshCount = MeshCount;
    1076           5 :             thisDomain.Mesh.Y.RegionMeshCount = MeshCount;
    1077           5 :             thisDomain.Mesh.Z.RegionMeshCount = MeshCount;
    1078             : 
    1079           5 :             thisDomain.NumSlabCells = thisDomain.Mesh.Y.RegionMeshCount; // Need to clean this out at some point
    1080             : 
    1081             :             // Farfield model
    1082           5 :             thisDomain.groundTempModel = GetGroundTempModelAndInit(state, state.dataIPShortCut->cAlphaArgs(2), state.dataIPShortCut->cAlphaArgs(3));
    1083             : 
    1084             :             // Other parameters
    1085           5 :             thisDomain.SimControls.Convergence_CurrentToPrevIteration = 0.001;
    1086           5 :             thisDomain.SimControls.MaxIterationsPerTS = 250;
    1087             : 
    1088             :             // setup output variables
    1089           5 :             thisDomain.SetupZoneCoupledOutputVariables(state);
    1090             :         }
    1091          11 :     }
    1092             : 
    1093          11 :     void ReadBasementInputs(EnergyPlusData &state, int const StartingDomainNumForBasement, int const NumBasements, bool &ErrorsFound)
    1094             :     {
    1095             : 
    1096             :         // SUBROUTINE INFORMATION:
    1097             :         //       AUTHOR         Edwin Lee
    1098             :         //       DATE WRITTEN   Summer 2011
    1099             :         //       MODIFIED       Summer 2014  Sushobhit Acharya to accommodate basement calculations
    1100             :         //       RE-ENGINEERED  na
    1101             : 
    1102             :         // SUBROUTINE PARAMETER DEFINITIONS:
    1103             :         static constexpr std::string_view RoutineName("ReadBasementInputs");
    1104             : 
    1105             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1106             :         int NumAlphas;  // Number of Alphas for each GetObjectItem call
    1107             :         int NumNumbers; // Number of Numbers for each GetObjectItem call
    1108             :         int IOStatus;   // Used in GetObjectItem
    1109             :         int CurIndex;
    1110             : 
    1111             :         // initialize these counters properly so they can be incremented within the DO loop
    1112          11 :         int DomainNum = StartingDomainNumForBasement - 1;
    1113             : 
    1114             :         // For each domain, we need to process the inputs into a local array of derived type, then resolve each one, creating definitions for a zone
    1115             :         // coupled domain. This way, the outer get input routines can handle it as though they were generalized routines
    1116             : 
    1117          12 :         for (int BasementCtr = 1; BasementCtr <= NumBasements; ++BasementCtr) {
    1118             : 
    1119             :             // Increment the domain counters here
    1120           1 :             ++DomainNum;
    1121             : 
    1122             :             // Read all the inputs for this domain object
    1123           2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1124             :                                                                      ObjName_ZoneCoupled_Basement,
    1125             :                                                                      BasementCtr,
    1126           1 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1127             :                                                                      NumAlphas,
    1128           1 :                                                                      state.dataIPShortCut->rNumericArgs,
    1129             :                                                                      NumNumbers,
    1130             :                                                                      IOStatus,
    1131           1 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1132           1 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1133           1 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1134           1 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1135             : 
    1136           1 :             auto &thisDomain = state.dataPlantPipingSysMgr->domains[DomainNum - 1];
    1137             : 
    1138             :             // Get the name, validate
    1139           1 :             thisDomain.Name = state.dataIPShortCut->cAlphaArgs(1);
    1140           1 :             GlobalNames::VerifyUniqueInterObjectName(state,
    1141           1 :                                                      state.dataPlantPipingSysMgr->GroundDomainUniqueNames,
    1142           1 :                                                      state.dataIPShortCut->cAlphaArgs(1),
    1143             :                                                      ObjName_ZoneCoupled_Basement,
    1144           1 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
    1145             :                                                      ErrorsFound);
    1146             : 
    1147             :             // Read in the some of the inputs into the local type for clarity during transition
    1148           1 :             thisDomain.Extents.yMax = state.dataIPShortCut->rNumericArgs(1);
    1149           1 :             Real64 const thisAspectRatio = state.dataIPShortCut->rNumericArgs(2);
    1150           1 :             thisDomain.PerimeterOffset = state.dataIPShortCut->rNumericArgs(3);
    1151           1 :             thisDomain.HorizInsWidth = state.dataIPShortCut->rNumericArgs(10);
    1152           1 :             thisDomain.VertInsDepth = state.dataIPShortCut->rNumericArgs(12);
    1153             : 
    1154             :             // Other inputs
    1155           1 :             thisDomain.Name = state.dataIPShortCut->cAlphaArgs(1);
    1156             : 
    1157             :             // Soil properties, validated min/max by IP
    1158           1 :             thisDomain.GroundProperties.Conductivity = state.dataIPShortCut->rNumericArgs(4);
    1159           1 :             thisDomain.GroundProperties.Density = state.dataIPShortCut->rNumericArgs(5);
    1160           1 :             thisDomain.GroundProperties.SpecificHeat = state.dataIPShortCut->rNumericArgs(6);
    1161             : 
    1162             :             // Moisture properties, validated min/max by IP, and converted to a fraction for computation here
    1163           1 :             thisDomain.Moisture.Theta_liq = state.dataIPShortCut->rNumericArgs(7) / 100.0;
    1164           1 :             thisDomain.Moisture.Theta_sat = state.dataIPShortCut->rNumericArgs(8) / 100.0;
    1165             : 
    1166             :             // check if there are blank inputs related to the basement,
    1167           2 :             if (state.dataIPShortCut->lNumericFieldBlanks(11) || state.dataIPShortCut->lAlphaFieldBlanks(5) ||
    1168           1 :                 state.dataIPShortCut->lAlphaFieldBlanks(10)) {
    1169           0 :                 ShowSevereError(state,
    1170           0 :                                 format("Erroneous basement inputs for {}={}", ObjName_ZoneCoupled_Basement, state.dataIPShortCut->cAlphaArgs(1)));
    1171           0 :                 ShowContinueError(state, "At least one basement input was left blank.");
    1172           0 :                 ErrorsFound = true;
    1173             :             }
    1174             : 
    1175             :             // Basement zone depth
    1176           1 :             CurIndex = 11;
    1177           1 :             thisDomain.BasementZone.Depth = state.dataIPShortCut->rNumericArgs(CurIndex);
    1178           1 :             if (thisDomain.BasementZone.Depth >= thisDomain.Extents.yMax || thisDomain.BasementZone.Depth <= 0.0) {
    1179           0 :                 ShowSevereError(state, format("Invalid {}", state.dataIPShortCut->cNumericFieldNames(CurIndex)));
    1180           0 :                 ShowContinueError(state, format("Found in: {}", thisDomain.Name));
    1181           0 :                 ErrorsFound = true;
    1182             :             }
    1183             : 
    1184             :             // get boundary condition model names and indices --error check
    1185           1 :             CurIndex = 4;
    1186           1 :             thisDomain.BasementZone.FloorBoundaryOSCMName = state.dataIPShortCut->cAlphaArgs(CurIndex);
    1187           1 :             thisDomain.BasementZone.FloorBoundaryOSCMIndex =
    1188           1 :                 Util::FindItemInList(thisDomain.BasementZone.FloorBoundaryOSCMName, state.dataSurface->OSCM);
    1189           1 :             if (thisDomain.BasementZone.FloorBoundaryOSCMIndex <= 0) {
    1190           0 :                 IssueSevereInputFieldError(state,
    1191             :                                            RoutineName,
    1192             :                                            ObjName_ZoneCoupled_Basement,
    1193           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
    1194           0 :                                            state.dataIPShortCut->cAlphaFieldNames(CurIndex),
    1195           0 :                                            state.dataIPShortCut->cAlphaArgs(CurIndex),
    1196             :                                            "Could not match with an Other Side Conditions Model input object.",
    1197             :                                            ErrorsFound);
    1198             :             } else {
    1199           1 :                 auto const &floorIndexes = GetSurfaceIndecesForOSCM(state, thisDomain.BasementZone.FloorBoundaryOSCMIndex);
    1200           1 :                 if (floorIndexes.empty()) {
    1201           0 :                     IssueSevereInputFieldError(
    1202             :                         state,
    1203             :                         RoutineName,
    1204             :                         ObjName_ZoneCoupled_Basement,
    1205           0 :                         state.dataIPShortCut->cAlphaArgs(1),
    1206           0 :                         state.dataIPShortCut->cAlphaFieldNames(CurIndex),
    1207           0 :                         state.dataIPShortCut->cAlphaArgs(CurIndex),
    1208             :                         "Entry matched an Other Side Conditions Model, but no surfaces were found to be using this Other Side Conditions Model.",
    1209             :                         ErrorsFound);
    1210             :                 } else {
    1211           1 :                     thisDomain.BasementZone.FloorSurfacePointers = floorIndexes;
    1212             :                     // Create GetSurfaceDataForOSCM function
    1213           1 :                     thisDomain.ZoneCoupledSurfaces = GetSurfaceDataForOSCM(state, thisDomain.BasementZone.FloorBoundaryOSCMIndex);
    1214             :                 }
    1215           1 :             }
    1216             : 
    1217           1 :             CurIndex = 8;
    1218           1 :             thisDomain.BasementZone.WallBoundaryOSCMName = state.dataIPShortCut->cAlphaArgs(CurIndex);
    1219           1 :             thisDomain.BasementZone.WallBoundaryOSCMIndex =
    1220           1 :                 Util::FindItemInList(thisDomain.BasementZone.WallBoundaryOSCMName, state.dataSurface->OSCM);
    1221           1 :             if (thisDomain.BasementZone.WallBoundaryOSCMIndex <= 0) {
    1222           0 :                 IssueSevereInputFieldError(state,
    1223             :                                            RoutineName,
    1224             :                                            ObjName_ZoneCoupled_Basement,
    1225           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
    1226           0 :                                            state.dataIPShortCut->cAlphaFieldNames(CurIndex),
    1227           0 :                                            state.dataIPShortCut->cAlphaArgs(CurIndex),
    1228             :                                            "Could not match with an Other Side Conditions Model input object.",
    1229             :                                            ErrorsFound);
    1230           0 :                 ErrorsFound = true;
    1231             :             } else {
    1232           1 :                 auto const &wallIndexes = GetSurfaceIndecesForOSCM(state, thisDomain.BasementZone.WallBoundaryOSCMIndex);
    1233           1 :                 if (wallIndexes.empty()) {
    1234           0 :                     IssueSevereInputFieldError(
    1235             :                         state,
    1236             :                         RoutineName,
    1237             :                         ObjName_ZoneCoupled_Basement,
    1238           0 :                         state.dataIPShortCut->cAlphaArgs(1),
    1239           0 :                         state.dataIPShortCut->cAlphaFieldNames(CurIndex),
    1240           0 :                         state.dataIPShortCut->cAlphaArgs(CurIndex),
    1241             :                         "Entry matched an Other Side Conditions Model, but no surfaces were found to be using this Other Side Conditions Model.",
    1242             :                         ErrorsFound);
    1243           0 :                     ErrorsFound = true;
    1244             :                 } else {
    1245           1 :                     thisDomain.BasementZone.WallSurfacePointers = wallIndexes;
    1246             :                 }
    1247           1 :             }
    1248             : 
    1249             :             // get some convergence tolerances, minimum/maximum are enforced by the IP, along with default values if user left them blank
    1250           1 :             thisDomain.SimControls.Convergence_CurrentToPrevIteration = 0.01;
    1251           1 :             thisDomain.SimControls.MaxIterationsPerTS = 250;
    1252             : 
    1253             :             // additional evapotranspiration parameter, min/max validated by IP
    1254           1 :             thisDomain.Moisture.GroundCoverCoefficient = state.dataIPShortCut->rNumericArgs(9);
    1255             : 
    1256             :             // assign the mesh count
    1257             :             int meshCount;
    1258           1 :             if (state.dataIPShortCut->lNumericFieldBlanks(13)) {
    1259           1 :                 meshCount = 4;
    1260             :             } else {
    1261           0 :                 meshCount = static_cast<int>(state.dataIPShortCut->rNumericArgs(13));
    1262             :             }
    1263           1 :             thisDomain.Mesh.X.RegionMeshCount = meshCount;
    1264           1 :             thisDomain.Mesh.Y.RegionMeshCount = meshCount;
    1265           1 :             thisDomain.Mesh.Z.RegionMeshCount = meshCount;
    1266             : 
    1267           1 :             thisDomain.Mesh.X.thisMeshDistribution = MeshDistribution::Uniform;
    1268           1 :             thisDomain.Mesh.Y.thisMeshDistribution = MeshDistribution::Uniform;
    1269           1 :             thisDomain.Mesh.Z.thisMeshDistribution = MeshDistribution::Uniform;
    1270             : 
    1271             :             // Initialize properties for basement interface cells
    1272           1 :             thisDomain.BasementInterfaceProperties.Conductivity = 500.0;
    1273           1 :             thisDomain.BasementInterfaceProperties.SpecificHeat = 1.0;
    1274           1 :             thisDomain.BasementInterfaceProperties.Density = 1.0;
    1275             : 
    1276             :             // set flag for horizontal insulation
    1277             :             // Check state.dataIPShortCut->cAlphaArgs value
    1278           1 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(5), "NO")) {
    1279           0 :                 thisDomain.HorizInsPresentFlag = false;
    1280           1 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(5), "YES")) {
    1281           1 :                 thisDomain.HorizInsPresentFlag = true;
    1282             :             } else {
    1283           0 :                 ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5)));
    1284           0 :                 ShowContinueError(state, format("Found in: {}", thisDomain.Name));
    1285           0 :                 ErrorsFound = true;
    1286             :             }
    1287             : 
    1288             :             // Get horizontal insulation material properties
    1289           1 :             if (thisDomain.HorizInsPresentFlag) {
    1290           1 :                 thisDomain.HorizInsMaterialNum =
    1291           1 :                     Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(6), state.dataMaterial->Material, state.dataMaterial->TotMaterials);
    1292           1 :                 if (thisDomain.HorizInsMaterialNum == 0) {
    1293           0 :                     ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
    1294           0 :                     ShowContinueError(state, format("Found in: {}", thisDomain.Name));
    1295           0 :                     ErrorsFound = true;
    1296             :                 } else {
    1297           1 :                     thisDomain.HorizInsThickness = state.dataMaterial->Material(thisDomain.HorizInsMaterialNum)->Thickness;
    1298           1 :                     thisDomain.HorizInsProperties.Density = state.dataMaterial->Material(thisDomain.HorizInsMaterialNum)->Density;
    1299           1 :                     thisDomain.HorizInsProperties.SpecificHeat = state.dataMaterial->Material(thisDomain.HorizInsMaterialNum)->SpecHeat;
    1300           1 :                     thisDomain.HorizInsProperties.Conductivity = state.dataMaterial->Material(thisDomain.HorizInsMaterialNum)->Conductivity;
    1301           1 :                     if (SiteGroundDomainUsingNoMassMat(state, thisDomain.HorizInsThickness, thisDomain.HorizInsMaterialNum)) {
    1302           0 :                         ErrorsFound = true;
    1303           0 :                         SiteGroundDomainNoMassMatError(
    1304           0 :                             state, state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6), thisDomain.Name);
    1305             :                     }
    1306             :                 }
    1307             : 
    1308             :                 // Set flag for horizontal insulation extents
    1309           1 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "PERIMETER")) {
    1310           1 :                     thisDomain.FullHorizInsPresent = false;
    1311             :                     // Horizontal insulation perimeter width
    1312           1 :                     if (thisDomain.HorizInsWidth <= 0.0) {
    1313           0 :                         ShowSevereError(state, format("Invalid {}", state.dataIPShortCut->cNumericFieldNames(10)));
    1314           0 :                         ShowContinueError(state, format("Found in: {}", thisDomain.Name));
    1315           0 :                         ErrorsFound = true;
    1316             :                     }
    1317           0 :                 } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "FULL")) {
    1318           0 :                     thisDomain.FullHorizInsPresent = true;
    1319             :                 } else {
    1320           0 :                     ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
    1321           0 :                     ShowContinueError(state, format("Found in: {}", thisDomain.Name));
    1322           0 :                     ErrorsFound = true;
    1323             :                 }
    1324             :             }
    1325             : 
    1326             :             // set flag for vertical insulation
    1327           1 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(9), "NO")) {
    1328           0 :                 thisDomain.VertInsPresentFlag = false;
    1329           1 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(9), "YES")) {
    1330           1 :                 thisDomain.VertInsPresentFlag = true;
    1331             :             } else {
    1332           0 :                 ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9)));
    1333           0 :                 ShowContinueError(state, format("Found in: {}", thisDomain.Name));
    1334           0 :                 ErrorsFound = true;
    1335             :             }
    1336             : 
    1337             :             // Get vertical insulation material properties
    1338           1 :             if (thisDomain.VertInsPresentFlag) {
    1339             :                 // Check if vertical insulation is in domain
    1340           1 :                 if (thisDomain.VertInsDepth >= thisDomain.Extents.yMax || thisDomain.VertInsDepth <= 0.0) {
    1341           0 :                     ShowSevereError(state, format("Invalid {}", state.dataIPShortCut->cNumericFieldNames(12)));
    1342           0 :                     ShowContinueError(state, format("Found in: {}", thisDomain.Name));
    1343           0 :                     ErrorsFound = true;
    1344             :                 }
    1345           1 :                 thisDomain.VertInsMaterialNum =
    1346           1 :                     Util::FindItemInPtrList(state.dataIPShortCut->cAlphaArgs(10), state.dataMaterial->Material, state.dataMaterial->TotMaterials);
    1347           1 :                 if (thisDomain.VertInsMaterialNum == 0) {
    1348           0 :                     ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(10), state.dataIPShortCut->cAlphaArgs(10)));
    1349           0 :                     ShowContinueError(state, format("Found in: {}", thisDomain.Name));
    1350           0 :                     ErrorsFound = true;
    1351             :                 } else {
    1352           1 :                     thisDomain.VertInsThickness = state.dataMaterial->Material(thisDomain.VertInsMaterialNum)->Thickness;
    1353           1 :                     thisDomain.VertInsProperties.Density = state.dataMaterial->Material(thisDomain.VertInsMaterialNum)->Density;
    1354           1 :                     thisDomain.VertInsProperties.SpecificHeat = state.dataMaterial->Material(thisDomain.VertInsMaterialNum)->SpecHeat;
    1355           1 :                     thisDomain.VertInsProperties.Conductivity = state.dataMaterial->Material(thisDomain.VertInsMaterialNum)->Conductivity;
    1356           1 :                     if (SiteGroundDomainUsingNoMassMat(state, thisDomain.VertInsThickness, thisDomain.VertInsMaterialNum)) {
    1357           0 :                         ErrorsFound = true;
    1358           0 :                         SiteGroundDomainNoMassMatError(
    1359           0 :                             state, state.dataIPShortCut->cAlphaFieldNames(10), state.dataIPShortCut->cAlphaArgs(10), thisDomain.Name);
    1360             :                     }
    1361             :                 }
    1362             :             }
    1363             : 
    1364             :             // Set simulation interval flag
    1365           1 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(11), "TIMESTEP")) {
    1366           1 :                 thisDomain.SimTimeStepFlag = true;
    1367           0 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(11), "HOURLY")) {
    1368           0 :                 thisDomain.SimHourlyFlag = true;
    1369             :             } else {
    1370           0 :                 ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(11), state.dataIPShortCut->cAlphaArgs(11)));
    1371           0 :                 ShowContinueError(state, format("Found in: {}", thisDomain.Name));
    1372           0 :                 ErrorsFound = true;
    1373             :             }
    1374             : 
    1375             :             // Farfield ground temperature model -- note this will overwrite the DataIPShortCuts variables
    1376             :             // so any other processing below this line won't have access to the cAlphaArgs, etc., here
    1377           1 :             thisDomain.groundTempModel = GetGroundTempModelAndInit(state, state.dataIPShortCut->cAlphaArgs(2), state.dataIPShortCut->cAlphaArgs(3));
    1378             : 
    1379             :             // Total surface area
    1380           1 :             Real64 ThisArea = 0.0;
    1381           2 :             for (auto &z : thisDomain.ZoneCoupledSurfaces) {
    1382           1 :                 ThisArea += z.SurfaceArea;
    1383           1 :             }
    1384             : 
    1385             :             // Surface dimensions
    1386           1 :             thisDomain.BasementZone.Width = sqrt(ThisArea / thisAspectRatio);
    1387           1 :             thisDomain.BasementZone.Length = thisDomain.BasementZone.Width * thisAspectRatio;
    1388             : 
    1389             :             // Set ground domain dimensions
    1390             :             // get width and length from aspect ratio later
    1391           1 :             thisDomain.Extents.xMax = thisDomain.PerimeterOffset + thisDomain.BasementZone.Width / 2;
    1392           1 :             thisDomain.Extents.zMax = thisDomain.PerimeterOffset + thisDomain.BasementZone.Length / 2;
    1393             : 
    1394             :             // Check horizontal insulation width so as to prevent overlapping insulation. VertInsThickness is used here since it is used for vertical
    1395             :             // partition thickness.
    1396           1 :             if (!thisDomain.FullHorizInsPresent && ThisArea > 0.0) {
    1397           1 :                 if ((thisDomain.HorizInsWidth + thisDomain.VertInsThickness) > thisDomain.BasementZone.Width / 2.0 ||
    1398           1 :                     (thisDomain.HorizInsWidth + thisDomain.VertInsThickness) > thisDomain.BasementZone.Length / 2.0) {
    1399           0 :                     ShowContinueError(state, format("{}: Perimeter insulation width is too large.", RoutineName));
    1400           0 :                     ShowContinueError(state, "This would cause overlapping insulation. Check inputs.");
    1401           0 :                     ShowContinueError(state, "Defaulting to full horizontal insulation.");
    1402           0 :                     ShowContinueError(state, format("Found in: {}", thisDomain.Name));
    1403           0 :                     thisDomain.FullHorizInsPresent = true;
    1404             :                 }
    1405             :             }
    1406             : 
    1407             :             //******* We'll first set up the domain ********
    1408           1 :             thisDomain.IsActuallyPartOfAHorizontalTrench = false;
    1409           1 :             thisDomain.HasAPipeCircuit = false;
    1410           1 :             thisDomain.HasZoneCoupledSlab = false;
    1411           1 :             thisDomain.HasBasement = false;
    1412           1 :             thisDomain.HasZoneCoupledBasement = true;
    1413             : 
    1414             :             // setup output variables
    1415           1 :             thisDomain.SetupZoneCoupledOutputVariables(state);
    1416             :         }
    1417          11 :     }
    1418             : 
    1419          11 :     bool SiteGroundDomainUsingNoMassMat([[maybe_unused]] EnergyPlusData &state, Real64 const MaterialThickness, int const MaterialNum)
    1420             :     {
    1421             : 
    1422          11 :         if ((MaterialThickness <= 0.0) || (state.dataMaterial->Material(MaterialNum)->ROnly)) {
    1423           0 :             return true;
    1424             :         } else {
    1425          11 :             return false;
    1426             :         }
    1427             :     }
    1428             : 
    1429           0 :     void SiteGroundDomainNoMassMatError(EnergyPlusData &state,
    1430             :                                         std::string_view FieldName,
    1431             :                                         std::string const &UserInputField,
    1432             :                                         std::string const &ObjectName)
    1433             :     {
    1434             : 
    1435           0 :         ShowSevereError(state, format("Invalid {}={} was found in: {}", FieldName, UserInputField, ObjectName));
    1436           0 :         ShowContinueError(
    1437             :             state, "The user of no mass materials or ones with no thickness are not allowed for the insulation fields of the following objects:");
    1438           0 :         ShowContinueError(state, format("  {} or {}", ObjName_ZoneCoupled_Slab, ObjName_ZoneCoupled_Basement));
    1439           0 :         ShowContinueError(
    1440             :             state, "Change any insulation designations in these objects from no mass materials to regular materials that have a thickness, etc.");
    1441           0 :     }
    1442             : 
    1443           5 :     void ReadPipeCircuitInputs(EnergyPlusData &state, bool &ErrorsFound)
    1444             :     {
    1445             : 
    1446             :         // SUBROUTINE INFORMATION:
    1447             :         //       AUTHOR         Edwin Lee
    1448             :         //       DATE WRITTEN   Summer 2011
    1449             :         //       MODIFIED       na
    1450             :         //       RE-ENGINEERED  na
    1451             : 
    1452             :         // SUBROUTINE PARAMETER DEFINITIONS:
    1453             :         static constexpr std::string_view RoutineName("ReadPipeCircuitInputs");
    1454             : 
    1455             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1456             :         int NumAlphas;
    1457             :         int NumNumbers;
    1458             :         int IOStatus;
    1459             :         int CurIndex;
    1460             : 
    1461             :         // get all of the actual generalized pipe circuit objects
    1462             : 
    1463           5 :         int NumPipeCircuits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjName_Circuit);
    1464           9 :         for (int PipeCircuitCounter = 1; PipeCircuitCounter <= NumPipeCircuits; ++PipeCircuitCounter) {
    1465             : 
    1466             :             // Read all the inputs for this pipe circuit
    1467           8 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1468             :                                                                      ObjName_Circuit,
    1469             :                                                                      PipeCircuitCounter,
    1470           4 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1471             :                                                                      NumAlphas,
    1472           4 :                                                                      state.dataIPShortCut->rNumericArgs,
    1473             :                                                                      NumNumbers,
    1474             :                                                                      IOStatus,
    1475           4 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1476           4 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1477           4 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1478           4 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1479             : 
    1480           4 :             Circuit thisCircuit = Circuit();
    1481             : 
    1482             :             // Get the name, validate
    1483           4 :             thisCircuit.Name = state.dataIPShortCut->cAlphaArgs(1);
    1484           4 :             Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
    1485             : 
    1486             :             // Read pipe thermal properties, validated by IP
    1487           4 :             thisCircuit.PipeProperties.Conductivity = state.dataIPShortCut->rNumericArgs(1);
    1488           4 :             thisCircuit.PipeProperties.Density = state.dataIPShortCut->rNumericArgs(2);
    1489           4 :             thisCircuit.PipeProperties.SpecificHeat = state.dataIPShortCut->rNumericArgs(3);
    1490             : 
    1491             :             // Read pipe sizing, validated individually by IP, validated comparison here
    1492           4 :             thisCircuit.PipeSize.InnerDia = state.dataIPShortCut->rNumericArgs(4);
    1493           4 :             thisCircuit.PipeSize.OuterDia = state.dataIPShortCut->rNumericArgs(5);
    1494           4 :             if (thisCircuit.PipeSize.InnerDia >= thisCircuit.PipeSize.OuterDia) {
    1495           0 :                 CurIndex = 5;
    1496           0 :                 IssueSevereInputFieldError(state,
    1497             :                                            RoutineName,
    1498             :                                            ObjName_Circuit,
    1499           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
    1500           0 :                                            state.dataIPShortCut->cNumericFieldNames(CurIndex),
    1501           0 :                                            state.dataIPShortCut->rNumericArgs(CurIndex),
    1502             :                                            "Outer diameter must be greater than inner diameter.",
    1503             :                                            ErrorsFound);
    1504             :             }
    1505             : 
    1506             :             // Read design flow rate, validated positive by IP
    1507           4 :             thisCircuit.DesignVolumeFlowRate = state.dataIPShortCut->rNumericArgs(6);
    1508             : 
    1509             :             // Read inlet and outlet node names and validate them
    1510           4 :             thisCircuit.InletNodeName = state.dataIPShortCut->cAlphaArgs(2);
    1511           4 :             thisCircuit.InletNodeNum = NodeInputManager::GetOnlySingleNode(state,
    1512           4 :                                                                            state.dataIPShortCut->cAlphaArgs(2),
    1513             :                                                                            ErrorsFound,
    1514             :                                                                            DataLoopNode::ConnectionObjectType::PipingSystemUndergroundPipeCircuit,
    1515           4 :                                                                            state.dataIPShortCut->cAlphaArgs(1),
    1516             :                                                                            DataLoopNode::NodeFluidType::Water,
    1517             :                                                                            DataLoopNode::ConnectionType::Inlet,
    1518             :                                                                            NodeInputManager::CompFluidStream::Primary,
    1519             :                                                                            DataLoopNode::ObjectIsNotParent);
    1520           4 :             if (thisCircuit.InletNodeNum == 0) {
    1521           0 :                 CurIndex = 2;
    1522           0 :                 IssueSevereInputFieldError(state,
    1523             :                                            RoutineName,
    1524             :                                            ObjName_Circuit,
    1525           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
    1526           0 :                                            state.dataIPShortCut->cAlphaFieldNames(CurIndex),
    1527           0 :                                            state.dataIPShortCut->cAlphaArgs(CurIndex),
    1528             :                                            "Bad node name.",
    1529             :                                            ErrorsFound);
    1530             :             }
    1531           4 :             thisCircuit.OutletNodeName = state.dataIPShortCut->cAlphaArgs(3);
    1532           4 :             thisCircuit.OutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
    1533           4 :                                                                             state.dataIPShortCut->cAlphaArgs(3),
    1534             :                                                                             ErrorsFound,
    1535             :                                                                             DataLoopNode::ConnectionObjectType::PipingSystemUndergroundPipeCircuit,
    1536           4 :                                                                             state.dataIPShortCut->cAlphaArgs(1),
    1537             :                                                                             DataLoopNode::NodeFluidType::Water,
    1538             :                                                                             DataLoopNode::ConnectionType::Outlet,
    1539             :                                                                             NodeInputManager::CompFluidStream::Primary,
    1540             :                                                                             DataLoopNode::ObjectIsNotParent);
    1541           4 :             if (thisCircuit.OutletNodeNum == 0) {
    1542           0 :                 CurIndex = 3;
    1543           0 :                 IssueSevereInputFieldError(state,
    1544             :                                            RoutineName,
    1545             :                                            ObjName_Circuit,
    1546           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
    1547           0 :                                            state.dataIPShortCut->cAlphaFieldNames(CurIndex),
    1548           0 :                                            state.dataIPShortCut->cAlphaArgs(CurIndex),
    1549             :                                            "Bad node name.",
    1550             :                                            ErrorsFound);
    1551             :             }
    1552           8 :             BranchNodeConnections::TestCompSet(state,
    1553             :                                                ObjName_Circuit,
    1554           4 :                                                state.dataIPShortCut->cAlphaArgs(1),
    1555           4 :                                                state.dataIPShortCut->cAlphaArgs(2),
    1556           4 :                                                state.dataIPShortCut->cAlphaArgs(3),
    1557             :                                                "Piping System Circuit Nodes");
    1558             : 
    1559             :             // Convergence tolerance values, validated by IP
    1560           4 :             thisCircuit.Convergence_CurrentToPrevIteration = state.dataIPShortCut->rNumericArgs(7);
    1561           4 :             thisCircuit.MaxIterationsPerTS = static_cast<int>(state.dataIPShortCut->rNumericArgs(8));
    1562             : 
    1563             :             // Radial mesh inputs, validated by IP
    1564             :             // -- mesh thickness should be considered slightly dangerous until mesh dev engine can trap erroneous values
    1565           4 :             thisCircuit.NumRadialCells = static_cast<int>(state.dataIPShortCut->rNumericArgs(9));
    1566           4 :             thisCircuit.RadialMeshThickness = state.dataIPShortCut->rNumericArgs(10);
    1567             : 
    1568             :             // Read number of pipe segments for this circuit, allocate arrays
    1569           4 :             int const NumPipeSegments = static_cast<int>(state.dataIPShortCut->rNumericArgs(11));
    1570             : 
    1571             :             // Need to loop once to store the names ahead of time because calling the segment factory will override cAlphaArgs
    1572           4 :             std::vector<std::string> segmentNamesToFind;
    1573           4 :             int constexpr NumAlphasBeforeSegmentOne = 3;
    1574          16 :             for (int ThisCircuitPipeSegmentCounter = 1; ThisCircuitPipeSegmentCounter <= NumPipeSegments; ++ThisCircuitPipeSegmentCounter) {
    1575          12 :                 CurIndex = ThisCircuitPipeSegmentCounter + NumAlphasBeforeSegmentOne;
    1576          12 :                 if (state.dataIPShortCut->lAlphaFieldBlanks(CurIndex)) {
    1577           0 :                     IssueSevereInputFieldError(state,
    1578             :                                                RoutineName,
    1579             :                                                ObjName_Circuit,
    1580           0 :                                                state.dataIPShortCut->cAlphaArgs(1),
    1581           0 :                                                state.dataIPShortCut->cAlphaFieldNames(CurIndex),
    1582           0 :                                                state.dataIPShortCut->cAlphaArgs(CurIndex),
    1583             :                                                "Expected a pipe segment name, check pipe segment count input field.",
    1584             :                                                ErrorsFound);
    1585             :                 }
    1586          12 :                 segmentNamesToFind.push_back(state.dataIPShortCut->cAlphaArgs(CurIndex));
    1587             :             }
    1588             :             // then we can loop through and allow the factory to be called and carry on
    1589          16 :             for (auto &segmentNameToFind : segmentNamesToFind) {
    1590          12 :                 thisCircuit.pipeSegments.push_back(Segment::factory(state, segmentNameToFind));
    1591           4 :             }
    1592             : 
    1593           4 :             state.dataPlantPipingSysMgr->circuits.push_back(thisCircuit);
    1594             : 
    1595           4 :         } // All pipe circuits in input
    1596             : 
    1597             :         // now get all the pipe circuits related to horizontal trenches
    1598             : 
    1599           5 :         int NumHorizontalTrenches = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjName_HorizTrench);
    1600             : 
    1601             :         // Read in all pipe segments
    1602           6 :         for (int HorizontalGHXCtr = 1; HorizontalGHXCtr <= NumHorizontalTrenches; ++HorizontalGHXCtr) {
    1603             : 
    1604             :             // Read all inputs for this pipe segment
    1605           2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1606             :                                                                      ObjName_HorizTrench,
    1607             :                                                                      HorizontalGHXCtr,
    1608           1 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1609             :                                                                      NumAlphas,
    1610           1 :                                                                      state.dataIPShortCut->rNumericArgs,
    1611             :                                                                      NumNumbers,
    1612             :                                                                      IOStatus,
    1613           1 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1614           1 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1615           1 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1616           1 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1617           1 :             std::string thisTrenchName = state.dataIPShortCut->cAlphaArgs(1);
    1618             : 
    1619           1 :             Circuit thisCircuit;
    1620           1 :             thisCircuit.IsActuallyPartOfAHorizontalTrench = true;
    1621           1 :             thisCircuit.Name = thisTrenchName;
    1622             : 
    1623             :             // Read pipe thermal properties
    1624           1 :             thisCircuit.PipeProperties.Conductivity = state.dataIPShortCut->rNumericArgs(11);
    1625           1 :             thisCircuit.PipeProperties.Density = state.dataIPShortCut->rNumericArgs(12);
    1626           1 :             thisCircuit.PipeProperties.SpecificHeat = state.dataIPShortCut->rNumericArgs(13);
    1627             : 
    1628             :             // Pipe sizing
    1629           1 :             thisCircuit.PipeSize.InnerDia = state.dataIPShortCut->rNumericArgs(5);
    1630           1 :             thisCircuit.PipeSize.OuterDia = state.dataIPShortCut->rNumericArgs(6);
    1631             : 
    1632             :             // Issue a severe if Inner >= Outer diameter
    1633           1 :             if (thisCircuit.PipeSize.InnerDia >= thisCircuit.PipeSize.OuterDia) {
    1634           0 :                 ShowSevereError(
    1635             :                     state,
    1636           0 :                     format("{}: {}=\"{}\" has invalid pipe diameters.", RoutineName, ObjName_HorizTrench, state.dataIPShortCut->cAlphaArgs(1)));
    1637           0 :                 ShowContinueError(state,
    1638           0 :                                   format("Outer diameter [{:.3T}] must be greater than inner diameter [{:.3T}].",
    1639             :                                          thisCircuit.PipeSize.OuterDia,
    1640             :                                          thisCircuit.PipeSize.InnerDia));
    1641           0 :                 ErrorsFound = true;
    1642             :             }
    1643             : 
    1644             :             // Read design flow rate, validated positive by IP
    1645           1 :             thisCircuit.DesignVolumeFlowRate = state.dataIPShortCut->rNumericArgs(1);
    1646             : 
    1647             :             // Read inlet and outlet node names and validate them
    1648           1 :             thisCircuit.InletNodeName = state.dataIPShortCut->cAlphaArgs(2);
    1649           1 :             thisCircuit.InletNodeNum = NodeInputManager::GetOnlySingleNode(state,
    1650             :                                                                            thisCircuit.InletNodeName,
    1651             :                                                                            ErrorsFound,
    1652             :                                                                            DataLoopNode::ConnectionObjectType::GroundHeatExchangerHorizontalTrench,
    1653             :                                                                            thisTrenchName,
    1654             :                                                                            DataLoopNode::NodeFluidType::Water,
    1655             :                                                                            DataLoopNode::ConnectionType::Inlet,
    1656             :                                                                            NodeInputManager::CompFluidStream::Primary,
    1657             :                                                                            DataLoopNode::ObjectIsNotParent);
    1658           1 :             if (thisCircuit.InletNodeNum == 0) {
    1659           0 :                 CurIndex = 2;
    1660             :             }
    1661           1 :             thisCircuit.OutletNodeName = state.dataIPShortCut->cAlphaArgs(3);
    1662           1 :             thisCircuit.OutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
    1663             :                                                                             thisCircuit.OutletNodeName,
    1664             :                                                                             ErrorsFound,
    1665             :                                                                             DataLoopNode::ConnectionObjectType::GroundHeatExchangerHorizontalTrench,
    1666             :                                                                             thisTrenchName,
    1667             :                                                                             DataLoopNode::NodeFluidType::Water,
    1668             :                                                                             DataLoopNode::ConnectionType::Outlet,
    1669             :                                                                             NodeInputManager::CompFluidStream::Primary,
    1670             :                                                                             DataLoopNode::ObjectIsNotParent);
    1671           1 :             if (thisCircuit.OutletNodeNum == 0) {
    1672           0 :                 CurIndex = 3;
    1673             :             }
    1674           1 :             BranchNodeConnections::TestCompSet(
    1675             :                 state, ObjName_HorizTrench, thisTrenchName, thisCircuit.InletNodeName, thisCircuit.OutletNodeName, "Piping System Circuit Nodes");
    1676             : 
    1677             :             // Convergence tolerance values, validated by IP
    1678           1 :             thisCircuit.Convergence_CurrentToPrevIteration = 0.001;
    1679           1 :             thisCircuit.MaxIterationsPerTS = 100;
    1680             : 
    1681             :             // Radial mesh inputs, validated by IP
    1682             :             // -- mesh thickness should be considered slightly dangerous until mesh dev engine can trap erroneous values
    1683           1 :             thisCircuit.NumRadialCells = 4;
    1684           1 :             thisCircuit.RadialMeshThickness = thisCircuit.PipeSize.InnerDia / 2.0;
    1685             : 
    1686             :             // add it to the main vector, then get a reference to it here
    1687           1 :             state.dataPlantPipingSysMgr->circuits.push_back(thisCircuit);
    1688           1 :         }
    1689           5 :     }
    1690             : 
    1691          12 :     Segment *Segment::factory(EnergyPlusData &state, const std::string &segmentName)
    1692             :     {
    1693          12 :         if (state.dataPlantPipingSysMgr->GetSegmentInputFlag) {
    1694           4 :             bool errorsFound = false;
    1695           4 :             ReadPipeSegmentInputs(state, errorsFound);
    1696           4 :             state.dataPlantPipingSysMgr->GetSegmentInputFlag = false;
    1697             :         }
    1698             :         // Now look for this particular segment in the list
    1699          30 :         for (auto &segment : state.dataPlantPipingSysMgr->segments) {
    1700          30 :             if (segment.Name == segmentName) {
    1701          12 :                 return &segment;
    1702             :             }
    1703          24 :         }
    1704             :         // If we didn't find it, fatal
    1705             :         ShowFatalError(state, format("PipeSegmentInfoFactory: Error getting inputs for segment named: {}", segmentName)); // LCOV_EXCL_LINE
    1706             :         // Shut up the compiler
    1707             :         return nullptr; // LCOV_EXCL_LINE
    1708             :     }
    1709             : 
    1710           5 :     Circuit *Circuit::factory(EnergyPlusData &state, const std::string &circuitName, bool &errorsFound)
    1711             :     {
    1712           5 :         if (state.dataPlantPipingSysMgr->GetCircuitInputFlag) {
    1713           5 :             ReadPipeCircuitInputs(state, errorsFound);
    1714           5 :             state.dataPlantPipingSysMgr->GetCircuitInputFlag = false;
    1715             :         }
    1716             :         // Now look for this particular segment in the list
    1717           5 :         for (auto &circuit : state.dataPlantPipingSysMgr->circuits) {
    1718           5 :             if (circuit.Name == circuitName) {
    1719           5 :                 return &circuit;
    1720             :             }
    1721          10 :         }
    1722             :         // If we didn't find it, fatal
    1723             :         ShowFatalError(state, format("PipeCircuitInfoFactory: Error getting inputs for circuit named: {}", circuitName)); // LCOV_EXCL_LINE
    1724             :         // Shut up the compiler
    1725             :         return nullptr; // LCOV_EXCL_LINE
    1726             :     }
    1727             : 
    1728           4 :     void ReadPipeSegmentInputs(EnergyPlusData &state, bool &ErrorsFound)
    1729             :     {
    1730             : 
    1731             :         // SUBROUTINE INFORMATION:
    1732             :         //       AUTHOR         Edwin Lee
    1733             :         //       DATE WRITTEN   Summer 2011
    1734             :         //       MODIFIED       na
    1735             :         //       RE-ENGINEERED  na
    1736             : 
    1737             :         // SUBROUTINE PARAMETER DEFINITIONS:
    1738             :         static constexpr std::string_view RoutineName("ReadPipeSegmentInputs");
    1739             : 
    1740             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1741             :         int NumAlphas;  // Number of Alphas for each GetObjectItem call
    1742             :         int NumNumbers; // Number of Numbers for each GetObjectItem call
    1743             :         int IOStatus;   // Used in GetObjectItem
    1744             :         int CurIndex;
    1745             : 
    1746             :         // Read in all pipe segments
    1747           4 :         int NumPipeSegmentsInInput = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjName_Segment);
    1748          16 :         for (int SegmentCtr = 1; SegmentCtr <= NumPipeSegmentsInInput; ++SegmentCtr) {
    1749             : 
    1750             :             // Read all inputs for this pipe segment
    1751          24 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1752             :                                                                      ObjName_Segment,
    1753             :                                                                      SegmentCtr,
    1754          12 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1755             :                                                                      NumAlphas,
    1756          12 :                                                                      state.dataIPShortCut->rNumericArgs,
    1757             :                                                                      NumNumbers,
    1758             :                                                                      IOStatus,
    1759          12 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1760          12 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1761          12 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1762          12 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1763             : 
    1764          12 :             Segment thisSegment;
    1765             : 
    1766             :             // Get the name, validate
    1767          12 :             thisSegment.Name = state.dataIPShortCut->cAlphaArgs(1);
    1768          12 :             Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
    1769             :             // Read in the pipe location, validated as positive by IP
    1770             :             // -- note that these values will be altered by the main GetInput routine in two ways:
    1771             :             //   1) shift for basement wall if selected
    1772             :             //   2) invert y direction to be measured from domain bottom surface for calculations
    1773          12 :             thisSegment.PipeLocation = PointF(state.dataIPShortCut->rNumericArgs(1), state.dataIPShortCut->rNumericArgs(2));
    1774             : 
    1775             :             // Read in the flow direction
    1776          12 :             thisSegment.FlowDirection = static_cast<SegmentFlow>(getEnumValue(flowDirectionNamesUC, stripped(state.dataIPShortCut->cAlphaArgs(2))));
    1777          12 :             if (thisSegment.FlowDirection == SegmentFlow::Invalid) {
    1778           0 :                 CurIndex = 2;
    1779           0 :                 IssueSevereInputFieldError(state,
    1780             :                                            RoutineName,
    1781             :                                            ObjName_Segment,
    1782           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
    1783           0 :                                            state.dataIPShortCut->cAlphaFieldNames(CurIndex),
    1784           0 :                                            state.dataIPShortCut->cAlphaArgs(CurIndex),
    1785             :                                            "Invalid flow direction, use one of the available keys.",
    1786             :                                            ErrorsFound);
    1787             :             }
    1788             : 
    1789          12 :             state.dataPlantPipingSysMgr->segments.push_back(thisSegment);
    1790          12 :         }
    1791           4 :     }
    1792             : 
    1793          11 :     void ReadHorizontalTrenchInputs(EnergyPlusData &state,
    1794             :                                     int const StartingDomainNumForHorizontal,
    1795             :                                     int const StartingCircuitNumForHorizontal,
    1796             :                                     bool &ErrorsFound)
    1797             :     {
    1798             : 
    1799             :         // SUBROUTINE INFORMATION:
    1800             :         //       AUTHOR         Edwin Lee
    1801             :         //       DATE WRITTEN   September 2012
    1802             :         //       MODIFIED       na
    1803             :         //       RE-ENGINEERED  na
    1804             : 
    1805             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1806             :         int NumAlphas;  // Number of Alphas for each GetObjectItem call
    1807             :         int NumNumbers; // Number of Numbers for each GetObjectItem call
    1808             :         int IOStatus;   // Used in GetObjectItem
    1809             : 
    1810             :         // initialize these counters properly so they can be incremented within the DO loop
    1811          11 :         int DomainCtr = StartingDomainNumForHorizontal - 1;
    1812          11 :         int CircuitCtr = StartingCircuitNumForHorizontal - 1;
    1813             : 
    1814             :         // For each horizontal, we need to process the inputs into a local array of derived type,
    1815             :         //  then resolve each one, creating definitions for a pipe domain, pipe circuit, and series of pipe segments
    1816             :         // This way, the outer get input routines can handle it as though they were generalized routines
    1817             : 
    1818          11 :         int NumHorizontalTrenches = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjName_HorizTrench);
    1819             : 
    1820             :         // Read in all pipe segments
    1821          12 :         for (int HorizontalGHXCtr = 1; HorizontalGHXCtr <= NumHorizontalTrenches; ++HorizontalGHXCtr) {
    1822             : 
    1823             :             // Increment the domain and circuit counters here
    1824           1 :             ++DomainCtr;
    1825           1 :             ++CircuitCtr;
    1826             : 
    1827             :             // Read all inputs for this pipe segment
    1828           2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1829             :                                                                      ObjName_HorizTrench,
    1830             :                                                                      HorizontalGHXCtr,
    1831           1 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1832             :                                                                      NumAlphas,
    1833           1 :                                                                      state.dataIPShortCut->rNumericArgs,
    1834             :                                                                      NumNumbers,
    1835             :                                                                      IOStatus,
    1836           1 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1837           1 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1838           1 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1839           1 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1840             : 
    1841           1 :             auto &thisDomain = state.dataPlantPipingSysMgr->domains[DomainCtr - 1];
    1842             : 
    1843             :             // Get the name, validate
    1844           1 :             std::string thisTrenchName = state.dataIPShortCut->cAlphaArgs(1);
    1845           1 :             Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
    1846             : 
    1847           1 :             int const NumPipeSegments = static_cast<int>(state.dataIPShortCut->rNumericArgs(3));
    1848           1 :             Real64 const thisInterPipeSpacing = state.dataIPShortCut->rNumericArgs(4);
    1849           1 :             Real64 const thisBurialDepth = state.dataIPShortCut->rNumericArgs(7);
    1850             : 
    1851             :             //******* We'll first set up the domain ********
    1852             :             // the extents will be: zMax = axial length; yMax = burial depth*2; xMax = ( NumPipes+1 )*HorizontalPipeSpacing
    1853           1 :             thisDomain.IsActuallyPartOfAHorizontalTrench = true;
    1854           1 :             thisDomain.Name = format("HorizontalTrenchDomain{:4}", HorizontalGHXCtr);
    1855           1 :             thisDomain.Extents.xMax = (double(NumPipeSegments) + 1.0) * thisInterPipeSpacing;
    1856           1 :             thisDomain.Extents.yMax = 2.0 * thisBurialDepth;
    1857           1 :             thisDomain.Extents.zMax = state.dataIPShortCut->rNumericArgs(2);
    1858             : 
    1859             :             // set up the mesh with some default parameters
    1860           1 :             thisDomain.Mesh.X.RegionMeshCount = 4;
    1861           1 :             thisDomain.Mesh.X.thisMeshDistribution = MeshDistribution::Uniform;
    1862           1 :             thisDomain.Mesh.Y.RegionMeshCount = 4;
    1863           1 :             thisDomain.Mesh.Y.thisMeshDistribution = MeshDistribution::Uniform;
    1864           1 :             thisDomain.Mesh.Z.RegionMeshCount = 4;
    1865           1 :             thisDomain.Mesh.Z.thisMeshDistribution = MeshDistribution::Uniform;
    1866             : 
    1867             :             // Soil properties
    1868           1 :             thisDomain.GroundProperties.Conductivity = state.dataIPShortCut->rNumericArgs(8);
    1869           1 :             thisDomain.GroundProperties.Density = state.dataIPShortCut->rNumericArgs(9);
    1870           1 :             thisDomain.GroundProperties.SpecificHeat = state.dataIPShortCut->rNumericArgs(10);
    1871             : 
    1872             :             // Moisture properties
    1873           1 :             thisDomain.Moisture.Theta_liq = state.dataIPShortCut->rNumericArgs(14) / 100.0;
    1874           1 :             thisDomain.Moisture.Theta_sat = state.dataIPShortCut->rNumericArgs(15) / 100.0;
    1875             : 
    1876             :             // Other parameters
    1877           1 :             thisDomain.SimControls.Convergence_CurrentToPrevIteration = 0.001;
    1878           1 :             thisDomain.SimControls.MaxIterationsPerTS = 250;
    1879             : 
    1880             :             // additional evapotranspiration parameter, min/max validated by IP
    1881           1 :             thisDomain.Moisture.GroundCoverCoefficient = state.dataIPShortCut->rNumericArgs(16);
    1882             : 
    1883             :             //******* We'll next set up the circuit ********
    1884             :             // then we can loop through and allow the factory to be called and carry on
    1885           1 :             thisDomain.circuits.push_back(Circuit::factory(state, thisTrenchName, ErrorsFound));
    1886             : 
    1887             :             // Farfield model parameters -- this is pushed down pretty low because it internally calls GetObjectItem
    1888             :             // using DataIPShortCuts, so it will overwrite the cAlphaArgs and rNumericArgs values
    1889           1 :             thisDomain.groundTempModel = GetGroundTempModelAndInit(state, state.dataIPShortCut->cAlphaArgs(4), state.dataIPShortCut->cAlphaArgs(5));
    1890             : 
    1891             :             //******* Then we'll do the segments *******!
    1892           3 :             for (int ThisCircuitPipeSegmentCounter = 1; ThisCircuitPipeSegmentCounter <= NumPipeSegments; ++ThisCircuitPipeSegmentCounter) {
    1893           2 :                 Segment segment;
    1894           2 :                 segment.Name = format("HorizontalTrenchCircuit{}Segment{}", HorizontalGHXCtr, ThisCircuitPipeSegmentCounter);
    1895           2 :                 segment.IsActuallyPartOfAHorizontalTrench = true;
    1896           2 :                 segment.PipeLocation = PointF(ThisCircuitPipeSegmentCounter * thisInterPipeSpacing, thisBurialDepth);
    1897             : 
    1898           2 :                 if (mod(ThisCircuitPipeSegmentCounter, 2) != 0) {
    1899           1 :                     segment.FlowDirection = SegmentFlow::IncreasingZ;
    1900             :                 } else {
    1901           1 :                     segment.FlowDirection = SegmentFlow::DecreasingZ;
    1902             :                 }
    1903             :                 // add it to the main segment array so it has a place to live
    1904           2 :                 state.dataPlantPipingSysMgr->segments.push_back(segment);
    1905           2 :             }
    1906             : 
    1907             :             // now that they are in the main vector, add them here
    1908           1 :             int const newSizeSegmentVector = static_cast<int>(state.dataPlantPipingSysMgr->segments.size());
    1909           3 :             for (int segmentIndexToGrab = newSizeSegmentVector - NumPipeSegments; segmentIndexToGrab < newSizeSegmentVector; ++segmentIndexToGrab) {
    1910           2 :                 thisDomain.circuits[0]->pipeSegments.push_back(&state.dataPlantPipingSysMgr->segments[segmentIndexToGrab]);
    1911             :             }
    1912           1 :         }
    1913          11 :     }
    1914             : 
    1915          11 :     void SetupPipingSystemOutputVariables(EnergyPlusData &state)
    1916             :     {
    1917             : 
    1918             :         // SUBROUTINE INFORMATION:
    1919             :         //       AUTHOR         Edwin Lee
    1920             :         //       DATE WRITTEN   September 2012
    1921             :         //       MODIFIED       na
    1922             :         //       RE-ENGINEERED  na
    1923             : 
    1924          25 :         for (auto &thisSegment : state.dataPlantPipingSysMgr->segments) {
    1925             : 
    1926          14 :             if (!thisSegment.IsActuallyPartOfAHorizontalTrench) {
    1927             : 
    1928          24 :                 SetupOutputVariable(state,
    1929             :                                     "Pipe Segment Inlet Temperature",
    1930             :                                     Constant::Units::C,
    1931          12 :                                     thisSegment.InletTemperature,
    1932             :                                     OutputProcessor::TimeStepType::System,
    1933             :                                     OutputProcessor::StoreType::Average,
    1934          12 :                                     thisSegment.Name);
    1935          24 :                 SetupOutputVariable(state,
    1936             :                                     "Pipe Segment Outlet Temperature",
    1937             :                                     Constant::Units::C,
    1938          12 :                                     thisSegment.OutletTemperature,
    1939             :                                     OutputProcessor::TimeStepType::System,
    1940             :                                     OutputProcessor::StoreType::Average,
    1941          12 :                                     thisSegment.Name);
    1942             : 
    1943          24 :                 SetupOutputVariable(state,
    1944             :                                     "Pipe Segment Fluid Heat Transfer Rate",
    1945             :                                     Constant::Units::W,
    1946          12 :                                     thisSegment.FluidHeatLoss,
    1947             :                                     OutputProcessor::TimeStepType::System,
    1948             :                                     OutputProcessor::StoreType::Average,
    1949          12 :                                     thisSegment.Name);
    1950             :             }
    1951          11 :         }
    1952             : 
    1953          16 :         for (auto &thisCircuit : state.dataPlantPipingSysMgr->circuits) {
    1954             : 
    1955           5 :             if (!thisCircuit.IsActuallyPartOfAHorizontalTrench) {
    1956             : 
    1957           8 :                 SetupOutputVariable(state,
    1958             :                                     "Pipe Circuit Mass Flow Rate",
    1959             :                                     Constant::Units::kg_s,
    1960           4 :                                     thisCircuit.CurCircuitFlowRate,
    1961             :                                     OutputProcessor::TimeStepType::System,
    1962             :                                     OutputProcessor::StoreType::Average,
    1963           4 :                                     thisCircuit.Name);
    1964             : 
    1965           8 :                 SetupOutputVariable(state,
    1966             :                                     "Pipe Circuit Inlet Temperature",
    1967             :                                     Constant::Units::C,
    1968           4 :                                     thisCircuit.InletTemperature,
    1969             :                                     OutputProcessor::TimeStepType::System,
    1970             :                                     OutputProcessor::StoreType::Average,
    1971           4 :                                     thisCircuit.Name);
    1972           8 :                 SetupOutputVariable(state,
    1973             :                                     "Pipe Circuit Outlet Temperature",
    1974             :                                     Constant::Units::C,
    1975           4 :                                     thisCircuit.OutletTemperature,
    1976             :                                     OutputProcessor::TimeStepType::System,
    1977             :                                     OutputProcessor::StoreType::Average,
    1978           4 :                                     thisCircuit.Name);
    1979             : 
    1980           8 :                 SetupOutputVariable(state,
    1981             :                                     "Pipe Circuit Fluid Heat Transfer Rate",
    1982             :                                     Constant::Units::W,
    1983           4 :                                     thisCircuit.FluidHeatLoss,
    1984             :                                     OutputProcessor::TimeStepType::System,
    1985             :                                     OutputProcessor::StoreType::Average,
    1986           4 :                                     thisCircuit.Name);
    1987             : 
    1988             :             } else { // it is a horizontal trench
    1989             : 
    1990           2 :                 SetupOutputVariable(state,
    1991             :                                     "Ground Heat Exchanger Mass Flow Rate",
    1992             :                                     Constant::Units::kg_s,
    1993           1 :                                     thisCircuit.CurCircuitFlowRate,
    1994             :                                     OutputProcessor::TimeStepType::System,
    1995             :                                     OutputProcessor::StoreType::Average,
    1996           1 :                                     thisCircuit.Name);
    1997             : 
    1998           2 :                 SetupOutputVariable(state,
    1999             :                                     "Ground Heat Exchanger Inlet Temperature",
    2000             :                                     Constant::Units::C,
    2001           1 :                                     thisCircuit.InletTemperature,
    2002             :                                     OutputProcessor::TimeStepType::System,
    2003             :                                     OutputProcessor::StoreType::Average,
    2004           1 :                                     thisCircuit.Name);
    2005           2 :                 SetupOutputVariable(state,
    2006             :                                     "Ground Heat Exchanger Outlet Temperature",
    2007             :                                     Constant::Units::C,
    2008           1 :                                     thisCircuit.OutletTemperature,
    2009             :                                     OutputProcessor::TimeStepType::System,
    2010             :                                     OutputProcessor::StoreType::Average,
    2011           1 :                                     thisCircuit.Name);
    2012             : 
    2013           2 :                 SetupOutputVariable(state,
    2014             :                                     "Ground Heat Exchanger Fluid Heat Transfer Rate",
    2015             :                                     Constant::Units::W,
    2016           1 :                                     thisCircuit.FluidHeatLoss,
    2017             :                                     OutputProcessor::TimeStepType::System,
    2018             :                                     OutputProcessor::StoreType::Average,
    2019           1 :                                     thisCircuit.Name);
    2020             :             }
    2021          11 :         }
    2022          11 :     }
    2023             : 
    2024           6 :     void Domain::SetupZoneCoupledOutputVariables(EnergyPlusData &state)
    2025             :     {
    2026             : 
    2027             :         // SUBROUTINE INFORMATION:
    2028             :         //       AUTHOR         Matt Mitchell
    2029             :         //       DATE WRITTEN   August 2014
    2030             :         //       MODIFIED       na
    2031             :         //       RE-ENGINEERED  na
    2032             : 
    2033           6 :         if (this->HasZoneCoupledSlab) {
    2034             :             // Zone-coupled slab outputs
    2035          10 :             SetupOutputVariable(state,
    2036             :                                 "GroundDomain Slab Zone Coupled Surface Heat Flux",
    2037             :                                 Constant::Units::W_m2,
    2038           5 :                                 this->HeatFlux,
    2039             :                                 OutputProcessor::TimeStepType::Zone,
    2040             :                                 OutputProcessor::StoreType::Average,
    2041           5 :                                 this->Name);
    2042          10 :             SetupOutputVariable(state,
    2043             :                                 "GroundDomain Slab Zone Coupled Surface Temperature",
    2044             :                                 Constant::Units::C,
    2045           5 :                                 this->ZoneCoupledSurfaceTemp,
    2046             :                                 OutputProcessor::TimeStepType::Zone,
    2047             :                                 OutputProcessor::StoreType::Average,
    2048           5 :                                 this->Name);
    2049           1 :         } else if (this->HasZoneCoupledBasement) {
    2050             :             // Zone-coupled basement wall outputs
    2051           2 :             SetupOutputVariable(state,
    2052             :                                 "GroundDomain Basement Wall Interface Heat Flux",
    2053             :                                 Constant::Units::W_m2,
    2054           1 :                                 this->WallHeatFlux,
    2055             :                                 OutputProcessor::TimeStepType::Zone,
    2056             :                                 OutputProcessor::StoreType::Average,
    2057           1 :                                 this->Name);
    2058           2 :             SetupOutputVariable(state,
    2059             :                                 "GroundDomain Basement Wall Interface Temperature",
    2060             :                                 Constant::Units::C,
    2061           1 :                                 this->BasementWallTemp,
    2062             :                                 OutputProcessor::TimeStepType::Zone,
    2063             :                                 OutputProcessor::StoreType::Average,
    2064           1 :                                 this->Name);
    2065             :             // Zone-coupled basement floor outputs
    2066           2 :             SetupOutputVariable(state,
    2067             :                                 "GroundDomain Basement Floor Interface Heat Flux",
    2068             :                                 Constant::Units::W_m2,
    2069           1 :                                 this->FloorHeatFlux,
    2070             :                                 OutputProcessor::TimeStepType::Zone,
    2071             :                                 OutputProcessor::StoreType::Average,
    2072           1 :                                 this->Name);
    2073           2 :             SetupOutputVariable(state,
    2074             :                                 "GroundDomain Basement Floor Interface Temperature",
    2075             :                                 Constant::Units::C,
    2076           1 :                                 this->BasementFloorTemp,
    2077             :                                 OutputProcessor::TimeStepType::Zone,
    2078             :                                 OutputProcessor::StoreType::Average,
    2079           1 :                                 this->Name);
    2080             :         }
    2081           6 :     }
    2082             : 
    2083       14502 :     void Domain::InitPipingSystems(EnergyPlusData &state, Circuit *thisCircuit)
    2084             :     {
    2085             : 
    2086             :         // SUBROUTINE INFORMATION:
    2087             :         //       AUTHOR         Edwin Lee
    2088             :         //       DATE WRITTEN   Summer 2011
    2089             :         //       MODIFIED       na
    2090             :         //       RE-ENGINEERED  na
    2091             : 
    2092             :         // SUBROUTINE PARAMETER DEFINITIONS:
    2093             :         static constexpr std::string_view RoutineName("InitPipingSystems");
    2094             : 
    2095             :         // Do any one-time initializations
    2096       14502 :         if (thisCircuit->NeedToFindOnPlantLoop) {
    2097             : 
    2098             :             DataPlant::PlantEquipmentType TypeToLookFor;
    2099           5 :             if (thisCircuit->IsActuallyPartOfAHorizontalTrench) {
    2100           1 :                 TypeToLookFor = DataPlant::PlantEquipmentType::GrndHtExchgHorizTrench;
    2101             :             } else {
    2102           4 :                 TypeToLookFor = DataPlant::PlantEquipmentType::PipingSystemPipeCircuit;
    2103             :             }
    2104             : 
    2105           5 :             bool errFlag = false;
    2106           5 :             PlantUtilities::ScanPlantLoopsForObject(state, thisCircuit->Name, TypeToLookFor, thisCircuit->plantLoc, errFlag, _, _, _, _, _);
    2107           5 :             if (errFlag) {
    2108           0 :                 ShowFatalError(state, format("PipingSystems:{}: Program terminated due to previous condition(s).", RoutineName));
    2109             :             }
    2110             : 
    2111             :             // Once we find ourselves on the plant loop, we can do other things
    2112           5 :             Real64 rho = FluidProperties::GetDensityGlycol(state,
    2113           5 :                                                            state.dataPlnt->PlantLoop(thisCircuit->plantLoc.loopNum).FluidName,
    2114             :                                                            Constant::InitConvTemp,
    2115           5 :                                                            state.dataPlnt->PlantLoop(thisCircuit->plantLoc.loopNum).FluidIndex,
    2116             :                                                            RoutineName);
    2117           5 :             thisCircuit->DesignMassFlowRate = thisCircuit->DesignVolumeFlowRate * rho;
    2118           5 :             thisCircuit->NeedToFindOnPlantLoop = false;
    2119             :         }
    2120             : 
    2121       14502 :         if (this->DomainNeedsToBeMeshed) {
    2122             : 
    2123           5 :             this->developMesh(state);
    2124             : 
    2125             :             // would be OK to do some post-mesh error handling here I think
    2126          10 :             for (auto &thisDomainCircuit : this->circuits) {
    2127          19 :                 for (auto &segment : thisDomainCircuit->pipeSegments) {
    2128          14 :                     if (!segment->PipeCellCoordinatesSet) {
    2129           0 :                         ShowSevereError(state, format("PipingSystems:{}:Pipe segment index not set.", RoutineName));
    2130           0 :                         ShowContinueError(state, "...Possibly because pipe segment was placed outside of the domain.");
    2131           0 :                         ShowContinueError(state, "...Verify piping system domain inputs, circuits, and segments.");
    2132           0 :                         ShowFatalError(state, "Preceding error causes program termination");
    2133             :                     }
    2134           5 :                 }
    2135           5 :             }
    2136             : 
    2137           5 :             this->DomainNeedsToBeMeshed = false;
    2138             :         }
    2139             : 
    2140             :         // The time init should be done here before we DoOneTimeInits because the DoOneTimeInits
    2141             :         // includes a ground temperature initialization, which is based on the Cur%CurSimTimeSeconds variable
    2142             :         // which would be carried over from the previous environment
    2143       14502 :         this->Cur.CurSimTimeStepSize = state.dataHVACGlobal->TimeStepSysSec;
    2144       14502 :         this->Cur.CurSimTimeSeconds = (state.dataGlobal->DayOfSim - 1) * 24 + (state.dataGlobal->HourOfDay - 1) +
    2145       14502 :                                       (state.dataGlobal->TimeStep - 1) * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
    2146             : 
    2147             :         // There are also some inits that are "close to one time" inits...(one-time in standalone, each envrn in E+)
    2148       14502 :         if ((state.dataGlobal->BeginSimFlag && this->BeginSimInit) || (state.dataGlobal->BeginEnvrnFlag && this->BeginSimEnvironment)) {
    2149             : 
    2150             :             // this seemed to clean up a lot of reverse DD stuff because fluid thermal properties were
    2151             :             // being based on the inlet temperature, which wasn't updated until later
    2152          25 :             thisCircuit->CurCircuitInletTemp = state.dataLoopNodes->Node(thisCircuit->InletNodeNum).Temp;
    2153          25 :             thisCircuit->InletTemperature = thisCircuit->CurCircuitInletTemp;
    2154             : 
    2155          25 :             this->DoOneTimeInitializations(state, thisCircuit);
    2156             : 
    2157          25 :             this->BeginSimInit = false;
    2158          25 :             this->BeginSimEnvironment = false;
    2159             :         }
    2160       14502 :         if (!state.dataGlobal->BeginSimFlag) this->BeginSimInit = true;
    2161       14502 :         if (!state.dataGlobal->BeginEnvrnFlag) this->BeginSimEnvironment = true;
    2162             : 
    2163             :         // Shift history arrays only if necessary
    2164       14502 :         if (std::abs(this->Cur.CurSimTimeSeconds - this->Cur.PrevSimTimeSeconds) > 1.0e-6) {
    2165        1770 :             this->Cur.PrevSimTimeSeconds = this->Cur.CurSimTimeSeconds;
    2166        1770 :             this->ShiftTemperaturesForNewTimeStep();
    2167        1770 :             this->DomainNeedsSimulation = true;
    2168             :         }
    2169             : 
    2170             :         // Get the mass flow and inlet temperature to use for this time step
    2171       14502 :         int InletNodeNum = thisCircuit->InletNodeNum;
    2172       14502 :         int OutletNodeNum = thisCircuit->OutletNodeNum;
    2173       14502 :         thisCircuit->CurCircuitInletTemp = state.dataLoopNodes->Node(InletNodeNum).Temp;
    2174             : 
    2175             :         // request design, set component flow will decide what to give us based on restrictions and flow lock status
    2176       14502 :         thisCircuit->CurCircuitFlowRate = thisCircuit->DesignMassFlowRate;
    2177       14502 :         PlantUtilities::SetComponentFlowRate(state, thisCircuit->CurCircuitFlowRate, InletNodeNum, OutletNodeNum, thisCircuit->plantLoc);
    2178       14502 :     }
    2179             : 
    2180       14502 :     void Domain::UpdatePipingSystems(EnergyPlusData &state, Circuit *thisCircuit)
    2181             :     {
    2182             : 
    2183             :         // SUBROUTINE INFORMATION:
    2184             :         //       AUTHOR         Edwin Lee
    2185             :         //       DATE WRITTEN   Summer 2011
    2186             :         //       MODIFIED       na
    2187             :         //       RE-ENGINEERED  na
    2188             : 
    2189       14502 :         int OutletNodeNum = thisCircuit->OutletNodeNum;
    2190       14502 :         auto const &out_cell = thisCircuit->CircuitOutletCell;
    2191       14502 :         state.dataLoopNodes->Node(OutletNodeNum).Temp = this->Cells(out_cell.X, out_cell.Y, out_cell.Z).PipeCellData.Fluid.Temperature;
    2192       14502 :     }
    2193             : 
    2194           0 :     void IssueSevereInputFieldError(EnergyPlusData &state,
    2195             :                                     std::string_view const RoutineName,
    2196             :                                     std::string const &ObjectName,
    2197             :                                     std::string const &InstanceName,
    2198             :                                     std::string_view FieldName,
    2199             :                                     std::string const &FieldEntry,
    2200             :                                     std::string const &Condition,
    2201             :                                     bool &ErrorsFound)
    2202             :     {
    2203             : 
    2204             :         // SUBROUTINE INFORMATION:
    2205             :         //       AUTHOR         Edwin Lee
    2206             :         //       DATE WRITTEN   Summer 2011
    2207             :         //       MODIFIED       na
    2208             :         //       RE-ENGINEERED  na
    2209             : 
    2210           0 :         ShowSevereError(
    2211           0 :             state, format("{}:{}=\"{}\", invalid {}=\"{}\", Condition: {}", RoutineName, ObjectName, InstanceName, FieldName, FieldEntry, Condition));
    2212           0 :         ErrorsFound = true;
    2213           0 :     }
    2214             : 
    2215           0 :     void IssueSevereInputFieldError(EnergyPlusData &state,
    2216             :                                     std::string_view const RoutineName,
    2217             :                                     std::string const &ObjectName,
    2218             :                                     std::string const &InstanceName,
    2219             :                                     std::string_view FieldName,
    2220             :                                     Real64 const FieldEntry,
    2221             :                                     std::string const &Condition,
    2222             :                                     bool &ErrorsFound)
    2223             :     {
    2224             : 
    2225             :         // SUBROUTINE INFORMATION:
    2226             :         //       AUTHOR         Edwin Lee
    2227             :         //       DATE WRITTEN   Summer 2011
    2228             :         //       MODIFIED       na
    2229             :         //       RE-ENGINEERED  na
    2230             : 
    2231           0 :         ShowSevereError(
    2232             :             state,
    2233           0 :             format(R"({}:{}="{}", invalid {}="{:.3T}", Condition: {})", RoutineName, ObjectName, InstanceName, FieldName, FieldEntry, Condition));
    2234           0 :         ErrorsFound = true;
    2235           0 :     }
    2236             : 
    2237           5 :     int GetSurfaceCountForOSCM(EnergyPlusData &state, int const OSCMIndex)
    2238             :     {
    2239             : 
    2240             :         // FUNCTION INFORMATION:
    2241             :         //       AUTHOR         Edwin Lee
    2242             :         //       DATE WRITTEN   Summer 2011
    2243             :         //       MODIFIED       na
    2244             :         //       RE-ENGINEERED  na
    2245             : 
    2246           5 :         int RetVal = 0;
    2247         139 :         for (int SurfCtr = 1; SurfCtr <= isize(state.dataSurface->Surface); ++SurfCtr) {
    2248         134 :             if (state.dataSurface->Surface(SurfCtr).OSCMPtr == OSCMIndex) ++RetVal;
    2249             :         }
    2250           5 :         return RetVal;
    2251             :     }
    2252             : 
    2253           4 :     std::vector<int> GetSurfaceIndecesForOSCM(EnergyPlusData &state, int const OSCMIndex)
    2254             :     {
    2255             : 
    2256             :         // FUNCTION INFORMATION:
    2257             :         //       AUTHOR         Edwin Lee
    2258             :         //       DATE WRITTEN   Summer 2011
    2259             :         //       MODIFIED       na
    2260             :         //       RE-ENGINEERED  na
    2261             : 
    2262           4 :         std::vector<int> retVal;
    2263          52 :         for (int SurfCtr = 1; SurfCtr <= isize(state.dataSurface->Surface); ++SurfCtr) {
    2264          48 :             if (state.dataSurface->Surface(SurfCtr).OSCMPtr == OSCMIndex) {
    2265          10 :                 retVal.push_back(SurfCtr);
    2266             :             }
    2267             :         }
    2268           4 :         return retVal;
    2269           0 :     }
    2270             : 
    2271           6 :     std::vector<ZoneCoupledSurfaceData> GetSurfaceDataForOSCM(EnergyPlusData &state, int const OSCMIndex)
    2272             :     {
    2273             : 
    2274             :         // FUNCTION INFORMATION:
    2275             :         //       AUTHOR         Edwin Lee
    2276             :         //       DATE WRITTEN   Summer 2011
    2277             :         //       MODIFIED       na
    2278             :         //       RE-ENGINEERED  na
    2279             : 
    2280           6 :         std::vector<ZoneCoupledSurfaceData> RetVal;
    2281         152 :         for (int SurfCtr = 1; SurfCtr <= isize(state.dataSurface->Surface); ++SurfCtr) {
    2282         146 :             if (state.dataSurface->Surface(SurfCtr).OSCMPtr == OSCMIndex) {
    2283          16 :                 ZoneCoupledSurfaceData z;
    2284          16 :                 z.IndexInSurfaceArray = SurfCtr;
    2285          16 :                 z.SurfaceArea = state.dataSurface->Surface(SurfCtr).Area;
    2286          16 :                 z.Zone = state.dataSurface->Surface(SurfCtr).Zone;
    2287          16 :                 RetVal.push_back(z);
    2288          16 :             }
    2289             :         }
    2290           6 :         return RetVal;
    2291           0 :     }
    2292             : 
    2293          80 :     void Segment::initPipeCells(int const x, int const y)
    2294             :     {
    2295             : 
    2296             :         // SUBROUTINE INFORMATION:
    2297             :         //       AUTHOR         Edwin Lee
    2298             :         //       DATE WRITTEN   Summer 2011
    2299             :         //       MODIFIED       na
    2300             :         //       RE-ENGINEERED  na
    2301             : 
    2302          80 :         this->PipeCellCoordinates.X = x;
    2303          80 :         this->PipeCellCoordinates.Y = y;
    2304          80 :         this->PipeCellCoordinatesSet = true;
    2305          80 :     }
    2306             : 
    2307           5 :     void Circuit::initInOutCells(CartesianCell const &in, CartesianCell const &out)
    2308             :     {
    2309             : 
    2310             :         // SUBROUTINE INFORMATION:
    2311             :         //       AUTHOR         Edwin Lee
    2312             :         //       DATE WRITTEN   Summer 2011
    2313             :         //       MODIFIED       na
    2314             :         //       RE-ENGINEERED  na
    2315             : 
    2316           5 :         this->CircuitInletCell = Point3DInteger(in.X_index, in.Y_index, in.Z_index);
    2317           5 :         this->CircuitOutletCell = Point3DInteger(out.X_index, out.Y_index, out.Z_index);
    2318           5 :     }
    2319           0 :     void Circuit::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
    2320             :     {
    2321           0 :     }
    2322           5 :     void Circuit::oneTimeInit_new([[maybe_unused]] EnergyPlusData &state)
    2323             :     {
    2324           5 :     }
    2325             : 
    2326      125516 :     bool Domain::IsConverged_CurrentToPrevIteration()
    2327             :     {
    2328             : 
    2329             :         // FUNCTION INFORMATION:
    2330             :         //       AUTHOR         Edwin Lee
    2331             :         //       DATE WRITTEN   Summer 2011
    2332             :         //       MODIFIED       na
    2333             :         //       RE-ENGINEERED  na
    2334             : 
    2335      125516 :         Real64 LocalMax = 0.0;
    2336     1836285 :         for (int X = 0, X_end = this->x_max_index; X <= X_end; ++X) {
    2337    30193343 :             for (int Y = 0, Y_end = this->y_max_index; Y <= Y_end; ++Y) {
    2338   329423232 :                 for (int Z = 0, Z_end = this->z_max_index; Z <= Z_end; ++Z) {
    2339   300940658 :                     auto const &cell = this->Cells(X, Y, Z);
    2340   300940658 :                     LocalMax = max(LocalMax, std::abs(cell.Temperature - cell.Temperature_PrevIteration));
    2341             :                 }
    2342             :             }
    2343             :         }
    2344      125516 :         return (LocalMax < this->SimControls.Convergence_CurrentToPrevIteration);
    2345             :     }
    2346             : 
    2347     7437826 :     bool IsConverged_PipeCurrentToPrevIteration(Circuit *thisCircuit, CartesianCell const &CellToCheck)
    2348             :     {
    2349             : 
    2350             :         // FUNCTION INFORMATION:
    2351             :         //       AUTHOR         Edwin Lee
    2352             :         //       DATE WRITTEN   Summer 2011
    2353             :         //       MODIFIED       na
    2354             :         //       RE-ENGINEERED  na
    2355             : 
    2356             :         Real64 ThisCellMax;
    2357             : 
    2358     7437826 :         Real64 MaxDivAmount = 0.0;
    2359    22687910 :         for (auto &radCell : CellToCheck.PipeCellData.Soil) {
    2360    15250084 :             ThisCellMax = std::abs(radCell.Temperature - radCell.Temperature_PrevIteration);
    2361    15250084 :             if (ThisCellMax > MaxDivAmount) {
    2362    14067536 :                 MaxDivAmount = ThisCellMax;
    2363             :             }
    2364     7437826 :         }
    2365             :         //'also do the pipe cell
    2366     7437826 :         ThisCellMax = std::abs(CellToCheck.PipeCellData.Pipe.Temperature - CellToCheck.PipeCellData.Pipe.Temperature_PrevIteration);
    2367     7437826 :         if (ThisCellMax > MaxDivAmount) {
    2368      800946 :             MaxDivAmount = ThisCellMax;
    2369             :         }
    2370             :         //'also do the water cell
    2371     7437826 :         ThisCellMax = std::abs(CellToCheck.PipeCellData.Fluid.Temperature - CellToCheck.PipeCellData.Fluid.Temperature_PrevIteration);
    2372     7437826 :         if (ThisCellMax > MaxDivAmount) {
    2373      225442 :             MaxDivAmount = ThisCellMax;
    2374             :         }
    2375             :         //'also do insulation if it exists
    2376     7437826 :         if (thisCircuit->HasInsulation) {
    2377           0 :             ThisCellMax = std::abs(CellToCheck.PipeCellData.Insulation.Temperature - CellToCheck.PipeCellData.Insulation.Temperature_PrevIteration);
    2378           0 :             if (ThisCellMax > MaxDivAmount) {
    2379           0 :                 MaxDivAmount = ThisCellMax;
    2380             :             }
    2381             :         }
    2382             : 
    2383     7437826 :         return (MaxDivAmount < thisCircuit->Convergence_CurrentToPrevIteration);
    2384             :     }
    2385             : 
    2386       15210 :     void Domain::ShiftTemperaturesForNewTimeStep()
    2387             :     {
    2388             : 
    2389             :         // SUBROUTINE INFORMATION:
    2390             :         //       AUTHOR         Edwin Lee
    2391             :         //       DATE WRITTEN   Summer 2011
    2392             :         //       MODIFIED       na
    2393             :         //       RE-ENGINEERED  na
    2394             : 
    2395      222528 :         for (int X = 0, X_end = this->x_max_index; X <= X_end; ++X) {
    2396     3656076 :             for (int Y = 0, Y_end = this->y_max_index; Y <= Y_end; ++Y) {
    2397    46578738 :                 for (int Z = 0, Z_end = this->z_max_index; Z <= Z_end; ++Z) {
    2398    43129980 :                     auto &cell = this->Cells(X, Y, Z);
    2399             : 
    2400    43129980 :                     cell.Temperature_PrevTimeStep = cell.Temperature;
    2401             : 
    2402    43129980 :                     if (cell.cellType == CellType::Pipe) {
    2403             : 
    2404      162192 :                         for (auto &radCell : cell.PipeCellData.Soil) {
    2405      108672 :                             radCell.Temperature_PrevTimeStep = radCell.Temperature;
    2406       53520 :                         }
    2407             : 
    2408       53520 :                         cell.PipeCellData.Fluid.Temperature_PrevTimeStep = cell.PipeCellData.Fluid.Temperature;
    2409             : 
    2410       53520 :                         cell.PipeCellData.Pipe.Temperature_PrevTimeStep = cell.PipeCellData.Pipe.Temperature;
    2411             : 
    2412       53520 :                         cell.PipeCellData.Insulation.Temperature_PrevTimeStep = cell.PipeCellData.Insulation.Temperature;
    2413             :                     }
    2414             :                 }
    2415             :             }
    2416             :         }
    2417       15210 :     }
    2418             : 
    2419      125516 :     void Domain::ShiftTemperaturesForNewIteration()
    2420             :     {
    2421             : 
    2422             :         // SUBROUTINE INFORMATION:
    2423             :         //       AUTHOR         Edwin Lee
    2424             :         //       DATE WRITTEN   Summer 2011
    2425             :         //       MODIFIED       na
    2426             :         //       RE-ENGINEERED  na
    2427             : 
    2428     1836285 :         for (int X = 0, X_end = this->x_max_index; X <= X_end; ++X) {
    2429    30193343 :             for (int Y = 0, Y_end = this->y_max_index; Y <= Y_end; ++Y) {
    2430   329423232 :                 for (int Z = 0, Z_end = this->z_max_index; Z <= Z_end; ++Z) {
    2431   300940658 :                     auto &cell = this->Cells(X, Y, Z);
    2432             : 
    2433   300940658 :                     cell.Temperature_PrevIteration = cell.Temperature;
    2434             : 
    2435   300940658 :                     if (cell.cellType == CellType::Pipe) {
    2436             : 
    2437     4220656 :                         for (auto &radCell : cell.PipeCellData.Soil) {
    2438     2825744 :                             radCell.Temperature_PrevIteration = radCell.Temperature;
    2439     1394912 :                         }
    2440             : 
    2441     1394912 :                         cell.PipeCellData.Fluid.Temperature_PrevIteration = cell.PipeCellData.Fluid.Temperature;
    2442             : 
    2443     1394912 :                         cell.PipeCellData.Pipe.Temperature_PrevIteration = cell.PipeCellData.Pipe.Temperature;
    2444             : 
    2445     1394912 :                         cell.PipeCellData.Insulation.Temperature_PrevIteration = cell.PipeCellData.Insulation.Temperature;
    2446             :                     }
    2447             :                 }
    2448             :             }
    2449             :         }
    2450      125516 :     }
    2451             : 
    2452     7437826 :     void ShiftPipeTemperaturesForNewIteration(CartesianCell &ThisPipeCell)
    2453             :     {
    2454             : 
    2455             :         // SUBROUTINE INFORMATION:
    2456             :         //       AUTHOR         Edwin Lee
    2457             :         //       DATE WRITTEN   Summer 2011
    2458             :         //       MODIFIED       na
    2459             :         //       RE-ENGINEERED  na
    2460             : 
    2461     7437826 :         if (ThisPipeCell.cellType == CellType::Pipe) { // It better be!
    2462             : 
    2463    22687910 :             for (auto &radCell : ThisPipeCell.PipeCellData.Soil) {
    2464    15250084 :                 radCell.Temperature_PrevIteration = radCell.Temperature;
    2465     7437826 :             }
    2466             : 
    2467     7437826 :             ThisPipeCell.PipeCellData.Fluid.Temperature_PrevIteration = ThisPipeCell.PipeCellData.Fluid.Temperature;
    2468             : 
    2469     7437826 :             ThisPipeCell.PipeCellData.Pipe.Temperature_PrevIteration = ThisPipeCell.PipeCellData.Pipe.Temperature;
    2470             : 
    2471     7437826 :             ThisPipeCell.PipeCellData.Insulation.Temperature_PrevIteration = ThisPipeCell.PipeCellData.Insulation.Temperature;
    2472             :         }
    2473     7437826 :     }
    2474             : 
    2475      125516 :     bool Domain::CheckForOutOfRangeTemps() const
    2476             :     {
    2477             : 
    2478             :         // FUNCTION INFORMATION:
    2479             :         //       AUTHOR         Edwin Lee
    2480             :         //       DATE WRITTEN   Summer 2011
    2481             :         //       MODIFIED       na
    2482             :         //       RE-ENGINEERED  na
    2483             : 
    2484      125516 :         Real64 const MaxLimit = this->SimControls.MaximumTemperatureLimit;
    2485      125516 :         Real64 const MinLimit = this->SimControls.MinimumTemperatureLimit;
    2486             : 
    2487   301066174 :         for (std::size_t i = 0, e = this->Cells.size(); i < e; ++i) {
    2488   300940658 :             double const Temperature(this->Cells[i].Temperature);
    2489   300940658 :             if ((Temperature > MaxLimit) || (Temperature < MinLimit)) return true;
    2490             :         }
    2491      125516 :         return false;
    2492             :     }
    2493             : 
    2494  1695588369 :     Real64 CartesianCell::normalArea(Direction const direction) const
    2495             :     {
    2496             : 
    2497             :         // FUNCTION INFORMATION:
    2498             :         //       AUTHOR         Edwin Lee
    2499             :         //       DATE WRITTEN   Summer 2011
    2500             :         //       MODIFIED       na
    2501             :         //       RE-ENGINEERED  na
    2502             : 
    2503  1695588369 :         switch (direction) {
    2504   577553805 :         case Direction::PositiveY:
    2505             :         case Direction::NegativeY:
    2506   577553805 :             return this->YNormalArea();
    2507   568566921 :         case Direction::PositiveX:
    2508             :         case Direction::NegativeX:
    2509   568566921 :             return this->XNormalArea();
    2510   549467643 :         case Direction::PositiveZ:
    2511             :         case Direction::NegativeZ:
    2512   549467643 :             return this->ZNormalArea();
    2513           0 :         default:
    2514           0 :             assert(false);
    2515             :         }
    2516             : 
    2517             :         return 0;
    2518             :     }
    2519             : 
    2520          80 :     CartesianPipeCellInformation::CartesianPipeCellInformation(Real64 const GridCellWidth,
    2521             :                                                                PlantPipingSystemsManager::RadialSizing const PipeSizes,
    2522             :                                                                int const NumRadialNodes,
    2523             :                                                                Real64 const CellDepth,
    2524             :                                                                Real64 const InsulationThickness,
    2525             :                                                                Real64 const RadialGridExtent,
    2526          80 :                                                                bool const SimHasInsulation)
    2527             :     {
    2528             : 
    2529             :         // SUBROUTINE INFORMATION:
    2530             :         //       AUTHOR         Edwin Lee
    2531             :         //       DATE WRITTEN   Summer 2011
    2532             :         //       MODIFIED       na
    2533             :         //       RE-ENGINEERED  na
    2534             : 
    2535             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2536             :         Real64 InsulationInnerRadius;
    2537             :         Real64 InsulationOuterRadius;
    2538             :         Real64 InsulationCentroid;
    2539             :         Real64 MinimumSoilRadius;
    2540             : 
    2541             :         //'calculate pipe radius
    2542          80 :         Real64 const PipeOuterRadius = PipeSizes.OuterDia / 2.0;
    2543          80 :         Real64 const PipeInnerRadius = PipeSizes.InnerDia / 2.0;
    2544             : 
    2545             :         //'--we will work from inside out, calculating dimensions and instantiating variables--
    2546             :         //'first instantiate the water cell
    2547          80 :         this->Fluid = FluidCellInformation(PipeInnerRadius, CellDepth);
    2548             : 
    2549             :         //'then the pipe cell
    2550          80 :         this->Pipe = RadialCellInformation((PipeOuterRadius + PipeInnerRadius) / 2.0, PipeInnerRadius, PipeOuterRadius);
    2551             : 
    2552             :         //'then the insulation if we have it
    2553          80 :         if (InsulationThickness > 0.0) {
    2554           0 :             InsulationInnerRadius = PipeOuterRadius;
    2555           0 :             InsulationOuterRadius = InsulationInnerRadius + InsulationThickness;
    2556           0 :             InsulationCentroid = (InsulationInnerRadius + InsulationOuterRadius) / 2.0;
    2557           0 :             this->Insulation = RadialCellInformation(InsulationCentroid, InsulationInnerRadius, InsulationOuterRadius);
    2558             :         }
    2559             : 
    2560             :         //'determine where to start applying the radial soil cells based on whether we have insulation or not
    2561          80 :         if (!SimHasInsulation) {
    2562          80 :             MinimumSoilRadius = PipeOuterRadius;
    2563             :         } else {
    2564           0 :             MinimumSoilRadius = this->Insulation.OuterRadius;
    2565             :         }
    2566             : 
    2567             :         //'the radial cells are distributed evenly throughout this region
    2568          80 :         this->RadialSliceWidth = RadialGridExtent / NumRadialNodes;
    2569             : 
    2570             :         // first set Rval to the minimum soil radius plus half a slice thickness for the innermost radial node
    2571          80 :         Real64 Rval = MinimumSoilRadius + (this->RadialSliceWidth / 2.0);
    2572          80 :         Real64 ThisSliceInnerRadius = MinimumSoilRadius;
    2573          80 :         this->Soil.emplace_back(Rval, ThisSliceInnerRadius, ThisSliceInnerRadius + this->RadialSliceWidth);
    2574             : 
    2575             :         //'then loop through the rest and assign them, each radius is simply one more slice thickness
    2576         176 :         for (int RadialCellCtr = 1; RadialCellCtr < NumRadialNodes; ++RadialCellCtr) {
    2577          96 :             Rval += this->RadialSliceWidth;
    2578          96 :             ThisSliceInnerRadius += this->RadialSliceWidth;
    2579          96 :             this->Soil.emplace_back(Rval, ThisSliceInnerRadius, ThisSliceInnerRadius + this->RadialSliceWidth);
    2580             :         }
    2581             : 
    2582             :         //'also assign the interface cell surrounding the radial system
    2583          80 :         this->InterfaceVolume = (1.0 - (Constant::Pi / 4.0)) * pow_2(GridCellWidth) * CellDepth;
    2584          80 :     }
    2585             : 
    2586          11 :     void Domain::developMesh(EnergyPlusData &state)
    2587             :     {
    2588             : 
    2589             :         // SUBROUTINE INFORMATION:
    2590             :         //       AUTHOR         Edwin Lee
    2591             :         //       DATE WRITTEN   Summer 2011
    2592             :         //       MODIFIED       na
    2593             :         //       RE-ENGINEERED  na
    2594             : 
    2595             :         //'****** LAYOUT PARTITIONS ******'
    2596          11 :         this->createPartitionCenterList(state);
    2597             : 
    2598          11 :         bool XPartitionsExist = !this->Partitions.X.empty();
    2599          11 :         std::vector<GridRegion> XPartitionRegions = this->createPartitionRegionList(state, this->Partitions.X, XPartitionsExist, this->Extents.xMax);
    2600             : 
    2601          11 :         bool YPartitionsExist = !this->Partitions.Y.empty();
    2602          11 :         std::vector<GridRegion> YPartitionRegions = this->createPartitionRegionList(state, this->Partitions.Y, YPartitionsExist, this->Extents.yMax);
    2603             : 
    2604          11 :         bool ZPartitionsExist = !this->Partitions.Z.empty();
    2605          11 :         std::vector<GridRegion> ZPartitionRegions = this->createPartitionRegionList(state, this->Partitions.Z, ZPartitionsExist, this->Extents.zMax);
    2606             : 
    2607             :         //'***** LAYOUT MESH REGIONS *****'
    2608             :         // Zone-coupled slab  models
    2609          11 :         if (this->HasZoneCoupledBasement) {
    2610           2 :             this->createRegionList(XRegions,
    2611             :                                    XPartitionRegions,
    2612             :                                    this->Extents.xMax,
    2613             :                                    RegionType::XDirection,
    2614             :                                    XPartitionsExist,
    2615             :                                    _,
    2616             :                                    _,
    2617           1 :                                    this->XIndex,
    2618           1 :                                    this->XWallIndex,
    2619           1 :                                    this->InsulationXIndex);
    2620             : 
    2621           2 :             this->createRegionList(YRegions,
    2622             :                                    YPartitionRegions,
    2623             :                                    this->Extents.yMax,
    2624             :                                    RegionType::YDirection,
    2625             :                                    YPartitionsExist,
    2626             :                                    _,
    2627             :                                    _,
    2628             :                                    _,
    2629             :                                    _,
    2630             :                                    _,
    2631           1 :                                    this->YIndex,
    2632           1 :                                    this->YFloorIndex,
    2633           1 :                                    this->InsulationYIndex);
    2634             : 
    2635           1 :             this->createRegionList(ZRegions,
    2636             :                                    ZPartitionRegions,
    2637             :                                    this->Extents.zMax,
    2638             :                                    RegionType::ZDirection,
    2639             :                                    ZPartitionsExist,
    2640             :                                    _,
    2641             :                                    _,
    2642             :                                    _,
    2643             :                                    _,
    2644             :                                    _,
    2645             :                                    _,
    2646             :                                    _,
    2647             :                                    _,
    2648           1 :                                    this->ZIndex,
    2649           1 :                                    this->ZWallIndex,
    2650           1 :                                    this->InsulationZIndex);
    2651          10 :         } else if (this->HasZoneCoupledSlab) {
    2652          15 :             this->createRegionList(XRegions,
    2653             :                                    XPartitionRegions,
    2654             :                                    this->Extents.xMax,
    2655             :                                    RegionType::XDirection,
    2656             :                                    XPartitionsExist,
    2657             :                                    _,
    2658             :                                    _,
    2659           5 :                                    this->XIndex,
    2660             :                                    _,
    2661           5 :                                    this->InsulationXIndex);
    2662             : 
    2663          15 :             this->createRegionList(YRegions,
    2664             :                                    YPartitionRegions,
    2665             :                                    this->Extents.yMax,
    2666             :                                    RegionType::YDirection,
    2667             :                                    YPartitionsExist,
    2668             :                                    _,
    2669             :                                    _,
    2670             :                                    _,
    2671             :                                    _,
    2672             :                                    _,
    2673           5 :                                    this->YIndex,
    2674             :                                    _,
    2675           5 :                                    this->InsulationYIndex);
    2676             : 
    2677          10 :             this->createRegionList(ZRegions,
    2678             :                                    ZPartitionRegions,
    2679             :                                    this->Extents.zMax,
    2680             :                                    RegionType::ZDirection,
    2681             :                                    ZPartitionsExist,
    2682             :                                    _,
    2683             :                                    _,
    2684             :                                    _,
    2685             :                                    _,
    2686             :                                    _,
    2687             :                                    _,
    2688             :                                    _,
    2689             :                                    _,
    2690           5 :                                    this->ZIndex,
    2691             :                                    _,
    2692           5 :                                    this->InsulationZIndex);
    2693             :         } else {
    2694          10 :             this->createRegionList(
    2695           5 :                 XRegions, XPartitionRegions, this->Extents.xMax, RegionType::XDirection, XPartitionsExist, this->BasementZone.BasementWallXIndex);
    2696             : 
    2697          15 :             this->createRegionList(
    2698          10 :                 YRegions, YPartitionRegions, this->Extents.yMax, RegionType::YDirection, YPartitionsExist, _, this->BasementZone.BasementFloorYIndex);
    2699             : 
    2700           5 :             this->createRegionList(ZRegions, ZPartitionRegions, this->Extents.zMax, RegionType::ZDirection, ZPartitionsExist);
    2701             :         }
    2702             : 
    2703             :         //'** MAKE REGIONS > BOUNDARIES **'
    2704          11 :         std::vector<Real64> XBoundaryPoints = CreateBoundaryList(XRegions, this->Extents.xMax, RegionType::XDirection);
    2705          11 :         std::vector<Real64> YBoundaryPoints = CreateBoundaryList(YRegions, this->Extents.yMax, RegionType::YDirection);
    2706          11 :         std::vector<Real64> ZBoundaryPoints = CreateBoundaryList(ZRegions, this->Extents.zMax, RegionType::ZDirection);
    2707             : 
    2708             :         //'****** DEVELOP CELL ARRAY *****'
    2709          11 :         this->createCellArray(XBoundaryPoints, YBoundaryPoints, ZBoundaryPoints);
    2710             : 
    2711             :         //'***** SETUP CELL NEIGHBORS ****'
    2712          11 :         this->setupCellNeighbors();
    2713             : 
    2714             :         //'** SET UP PIPE CIRCUIT CELLS **'
    2715          11 :         this->setupPipeCircuitInOutCells();
    2716          11 :     }
    2717             : 
    2718          11 :     void Domain::createPartitionCenterList([[maybe_unused]] EnergyPlusData &state)
    2719             :     {
    2720             : 
    2721             :         // SUBROUTINE INFORMATION:
    2722             :         //       AUTHOR         Edwin Lee
    2723             :         //       DATE WRITTEN   Summer 2011
    2724             :         //       MODIFIED       na
    2725             :         //       RE-ENGINEERED  na
    2726             : 
    2727             :         // SUBROUTINE PARAMETER DEFINITIONS:
    2728          11 :         Real64 constexpr BasementCellFraction(0.001); // the fraction of domain extent to use for the basement cells
    2729             :         // actual dimension shouldn't matter for calculation purposes
    2730             : 
    2731             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2732             :         Real64 BasementDistFromBottom;
    2733             :         Real64 FloorLocation;
    2734             :         Real64 UnderFloorLocation;
    2735             :         Real64 PipeCellWidth;
    2736             :         Real64 SurfCellWidth; // Basement surface...
    2737             :         Real64 SideXLocation;
    2738             :         Real64 SideXWallLocation;
    2739             :         Real64 SideXInsulationLocation;
    2740             :         Real64 SideZLocation;
    2741             :         Real64 SideZWallLocation;
    2742             :         Real64 SideZInsulationLocation;
    2743             :         Real64 SlabDistFromBottom;
    2744             :         Real64 YInsulationLocation;
    2745          11 :         Real64 CellWidth(0.0);
    2746          11 :         Real64 InterfaceCellWidth(0.008);
    2747             : 
    2748             :         // Object Data
    2749          11 :         std::vector<MeshPartition> PreviousEntries;
    2750          11 :         Segment ThisSegment;
    2751             : 
    2752             :         //'NOTE: pipe location y values have already been corrected to be measured from the bottom surface
    2753             :         //'in input they are measured by depth, but internally they are referred to by distance from y = 0, or the bottom boundary
    2754          16 :         for (auto &thisCircuit : this->circuits) {
    2755             : 
    2756             :             // set up a convenience variable here
    2757             :             //'account for the pipe and insulation if necessary
    2758           5 :             if (!thisCircuit->HasInsulation) {
    2759           5 :                 PipeCellWidth = thisCircuit->PipeSize.OuterDia;
    2760             :             } else {
    2761           0 :                 PipeCellWidth = thisCircuit->InsulationSize.OuterDia;
    2762             :             }
    2763             : 
    2764             :             //'then add the radial mesh thickness on both sides of the pipe/insulation construct
    2765           5 :             PipeCellWidth += 2 * thisCircuit->RadialMeshThickness;
    2766             : 
    2767          19 :             for (auto &segment : thisCircuit->pipeSegments) {
    2768          14 :                 if (std::find(this->Partitions.X.begin(), this->Partitions.X.end(), segment->PipeLocation.X) == this->Partitions.X.end()) {
    2769          12 :                     this->Partitions.X.emplace_back(segment->PipeLocation.X, PartitionType::Pipe, PipeCellWidth);
    2770             :                 }
    2771          14 :                 if (std::find(this->Partitions.Y.begin(), this->Partitions.Y.end(), segment->PipeLocation.Y) == this->Partitions.Y.end()) {
    2772           8 :                     this->Partitions.Y.emplace_back(segment->PipeLocation.Y, PartitionType::Pipe, PipeCellWidth);
    2773             :                 }
    2774           5 :             }
    2775          11 :         }
    2776             : 
    2777             :         // Underground Piping Systems Ground domain with basement interaction
    2778          11 :         if (!this->HasZoneCoupledBasement) {
    2779          10 :             if (this->HasBasement) { // FHX model
    2780             :                 //'NOTE: the basement depth is still a depth from the ground surface, need to correct for this here
    2781           1 :                 if (this->BasementZone.Width > 0) {
    2782           1 :                     SurfCellWidth = this->Extents.xMax * BasementCellFraction;
    2783           1 :                     if (std::find(this->Partitions.X.begin(), this->Partitions.X.end(), this->BasementZone.Width) == this->Partitions.X.end()) {
    2784           1 :                         this->Partitions.X.emplace_back(this->BasementZone.Width, PartitionType::BasementWall, SurfCellWidth);
    2785             :                     }
    2786             :                 }
    2787           1 :                 if (this->BasementZone.Depth > 0) {
    2788           1 :                     SurfCellWidth = this->Extents.yMax * BasementCellFraction;
    2789           1 :                     BasementDistFromBottom = this->Extents.yMax - this->BasementZone.Depth;
    2790           1 :                     if (std::find(this->Partitions.Y.begin(), this->Partitions.Y.end(), BasementDistFromBottom) == this->Partitions.Y.end()) {
    2791           1 :                         this->Partitions.Y.emplace_back(BasementDistFromBottom, PartitionType::BasementFloor, SurfCellWidth);
    2792             :                     }
    2793             :                 }
    2794             :             }
    2795             :         } else { // Zone-coupled basement model
    2796             :             //'NOTE: the basement depth is still a depth from the ground surface, need to correct for this here
    2797           1 :             if (this->BasementZone.Width > 0) {
    2798             :                 // Create partitions at basement walls and horizontal insulation edges
    2799           1 :                 CellWidth = this->VertInsThickness;
    2800             :                 // Side X direction - Insulation layer
    2801           1 :                 SideXLocation = this->PerimeterOffset - InterfaceCellWidth - CellWidth / 2.0;
    2802             :                 // Side X direction - Basement Wall Interface
    2803           1 :                 SideXWallLocation = this->PerimeterOffset - InterfaceCellWidth / 2.0;
    2804           1 :                 if (this->HorizInsPresentFlag && !this->FullHorizInsPresent) {
    2805             :                     // Insulation Edge in X direction
    2806           1 :                     SideXInsulationLocation = this->PerimeterOffset + this->HorizInsWidth + InterfaceCellWidth / 2.0;
    2807             :                 } else {
    2808           0 :                     SideXInsulationLocation = -1;
    2809             :                 }
    2810           1 :                 if (std::find(this->Partitions.X.begin(), this->Partitions.X.end(), this->BasementZone.Width) == this->Partitions.X.end()) {
    2811             :                     // Partition at insulation edges in the X direction, if horizontal insulation present
    2812           1 :                     if (this->HorizInsPresentFlag) {
    2813           1 :                         if (!this->FullHorizInsPresent) {
    2814             :                             // Side X direction - Insulation layer
    2815           1 :                             this->Partitions.X.emplace_back(SideXLocation, PartitionType::XSide, CellWidth);
    2816             :                             // Side X direction - Basement Wall interface
    2817           1 :                             this->Partitions.X.emplace_back(SideXWallLocation, PartitionType::XSideWall, InterfaceCellWidth);
    2818             :                             // Insulation Edge X direction
    2819           1 :                             this->Partitions.X.emplace_back(SideXInsulationLocation, PartitionType::HorizInsXSide, InterfaceCellWidth);
    2820             :                         } else {
    2821             :                             // Side X direction - Insulation layer
    2822           0 :                             this->Partitions.X.emplace_back(SideXLocation, PartitionType::XSide, CellWidth);
    2823             :                             // Side X direction -Basement Wall interface
    2824           0 :                             this->Partitions.X.emplace_back(SideXWallLocation, PartitionType::XSideWall, InterfaceCellWidth);
    2825             :                         }
    2826             :                     } else {
    2827             :                         // Side X direction - Insulation layer
    2828           0 :                         this->Partitions.X.emplace_back(SideXLocation, PartitionType::XSide, CellWidth);
    2829             :                         // Side X direction - Basement Wall interface
    2830           0 :                         this->Partitions.X.emplace_back(SideXWallLocation, PartitionType::XSideWall, InterfaceCellWidth);
    2831             :                     }
    2832             :                 }
    2833             :             }
    2834             :             // Zone coupled basement model
    2835           1 :             if (this->BasementZone.Depth > 0) {
    2836           1 :                 CellWidth = this->HorizInsThickness;
    2837             :                 // Distance of basement floor interface from domain bottom
    2838           1 :                 FloorLocation = this->Extents.yMax - this->BasementZone.Depth - InterfaceCellWidth / 2.0;
    2839             :                 // Distance of basement floor insulation layer from domain bottom
    2840           1 :                 UnderFloorLocation = this->Extents.yMax - this->BasementZone.Depth - InterfaceCellWidth - CellWidth / 2.0;
    2841           1 :                 if (this->VertInsPresentFlag) {
    2842           1 :                     YInsulationLocation = this->Extents.yMax - this->VertInsDepth - InterfaceCellWidth / 2.0;
    2843             :                 } else {
    2844           0 :                     YInsulationLocation = -1;
    2845             :                 }
    2846           1 :                 if (std::find(this->Partitions.Y.begin(), this->Partitions.Y.end(), FloorLocation) == this->Partitions.Y.end()) {
    2847             :                     // Partition at bottom edge of vertical insulation, if vertical insulation is present
    2848           1 :                     if (this->VertInsPresentFlag && YInsulationLocation > FloorLocation + CellWidth) {
    2849             :                         // Partition at basement floor interface
    2850           1 :                         this->Partitions.Y.emplace_back(FloorLocation, PartitionType::FloorInside, InterfaceCellWidth);
    2851             :                         // Partition under the basement floor for insulation layer
    2852           1 :                         this->Partitions.Y.emplace_back(UnderFloorLocation, PartitionType::UnderFloor, CellWidth);
    2853             :                         // Vertical-Insulation edge partition
    2854           1 :                         this->Partitions.Y.emplace_back(YInsulationLocation, PartitionType::VertInsLowerEdge, InterfaceCellWidth);
    2855             :                     } else {
    2856           0 :                         this->Partitions.Y.emplace_back(FloorLocation, PartitionType::FloorInside, InterfaceCellWidth);
    2857           0 :                         this->Partitions.Y.emplace_back(UnderFloorLocation, PartitionType::UnderFloor, CellWidth);
    2858             :                     }
    2859             :                 }
    2860             :             }
    2861           1 :             if (this->BasementZone.Width > 0) {
    2862             :                 // Create partitions at basement walls and horizontal insulation edges
    2863           1 :                 CellWidth = this->VertInsThickness;
    2864             :                 // Side Z direction - Insulation layer
    2865           1 :                 SideZLocation = this->PerimeterOffset - InterfaceCellWidth - CellWidth / 2.0;
    2866             :                 // Side Z direction - Basement Wall Interface
    2867           1 :                 SideZWallLocation = this->PerimeterOffset - InterfaceCellWidth / 2.0;
    2868           1 :                 if (this->HorizInsPresentFlag && !this->FullHorizInsPresent) {
    2869             :                     // Insulation Edge Z direction
    2870           1 :                     SideZInsulationLocation = this->PerimeterOffset + this->HorizInsWidth + InterfaceCellWidth / 2.0;
    2871             :                 } else {
    2872           0 :                     SideZInsulationLocation = -1;
    2873             :                 }
    2874           1 :                 if (std::find(this->Partitions.Z.begin(), this->Partitions.Z.end(), this->BasementZone.Width) == this->Partitions.Z.end()) {
    2875             :                     // Partition at insulation edges in the Z direction, if horizontal insulation present
    2876           1 :                     if (this->HorizInsPresentFlag) {
    2877           1 :                         if (!this->FullHorizInsPresent) {
    2878             :                             // Side Z direction - Insulation layer
    2879           1 :                             this->Partitions.Z.emplace_back(SideZLocation, PartitionType::ZSide, CellWidth);
    2880             :                             // Side Z direction - Basement Wall interface
    2881           1 :                             this->Partitions.Z.emplace_back(SideZWallLocation, PartitionType::ZSideWall, InterfaceCellWidth);
    2882             :                             // Insulation Edge Z direction
    2883           1 :                             this->Partitions.Z.emplace_back(SideZInsulationLocation, PartitionType::HorizInsZSide, InterfaceCellWidth);
    2884             :                         } else {
    2885             :                             // Side Z direction - Insulation layer
    2886           0 :                             this->Partitions.Z.emplace_back(SideZLocation, PartitionType::ZSide, CellWidth);
    2887             :                             // Side Z direction -Basement Wall interface
    2888           0 :                             this->Partitions.Z.emplace_back(SideZWallLocation, PartitionType::ZSideWall, InterfaceCellWidth);
    2889             :                         }
    2890             :                     } else {
    2891             :                         // Side Z direction - Insulation layer
    2892           0 :                         this->Partitions.Z.emplace_back(SideZLocation, PartitionType::ZSide, CellWidth);
    2893             :                         // Side Z direction -Basement Wall interface
    2894           0 :                         this->Partitions.Z.emplace_back(SideZWallLocation, PartitionType::ZSideWall, InterfaceCellWidth);
    2895             :                     }
    2896             :                 }
    2897             :             }
    2898             :         }
    2899             : 
    2900             :         // Zone-coupled slab
    2901          11 :         if (this->HasZoneCoupledSlab) {
    2902             :             // NOTE: the slab depth is still a depth from the ground surface, need to correct for this here.
    2903             : 
    2904             :             // Create X-direction partitions
    2905             : 
    2906             :             // Create partition at slab edges in the X direction
    2907           5 :             CellWidth = this->VertInsThickness;
    2908             :             // Side X direction
    2909           5 :             SideXLocation = this->PerimeterOffset - CellWidth / 2.0;
    2910             :             // Insulation Edge X direction
    2911           5 :             if (this->HorizInsPresentFlag && !this->FullHorizInsPresent) {
    2912           0 :                 SideXInsulationLocation = SideXLocation + this->HorizInsWidth;
    2913             :             } else {
    2914           5 :                 SideXInsulationLocation = -1;
    2915             :             }
    2916           5 :             if (std::find(this->Partitions.X.begin(), this->Partitions.X.end(), this->SlabWidth) == this->Partitions.X.end()) {
    2917             :                 // Partition at insulation edges in the X direction, if horizontal insulation present
    2918           5 :                 if (this->HorizInsPresentFlag) {
    2919           4 :                     if (!this->FullHorizInsPresent) {
    2920             :                         // Side X direction
    2921           0 :                         this->Partitions.X.emplace_back(SideXLocation, PartitionType::XSide, CellWidth);
    2922             :                         // Insulation Edge X direction
    2923           0 :                         this->Partitions.X.emplace_back(SideXInsulationLocation, PartitionType::HorizInsXSide, CellWidth);
    2924             :                     } else {
    2925             :                         // Side X direction
    2926           4 :                         this->Partitions.X.emplace_back(SideXLocation, PartitionType::XSide, CellWidth);
    2927             :                     }
    2928             :                 } else {
    2929             :                     // Side X direction
    2930           1 :                     this->Partitions.X.emplace_back(SideXLocation, PartitionType::XSide, CellWidth);
    2931             :                 }
    2932             :             }
    2933             : 
    2934             :             // Create Y-direction partitions
    2935             : 
    2936           5 :             CellWidth = this->HorizInsThickness;
    2937             : 
    2938             :             // Partition at bottom edge of vertical insulation, if vertical insulation present
    2939           5 :             if (this->VertInsPresentFlag) {
    2940           5 :                 YInsulationLocation = this->Extents.yMax - this->VertInsDepth + CellWidth / 2.0;
    2941             :             } else {
    2942           0 :                 YInsulationLocation = -1;
    2943             :             }
    2944             : 
    2945           5 :             if (this->SlabInGradeFlag) { // Slab in-grade case
    2946             : 
    2947           4 :                 SlabDistFromBottom = this->Extents.yMax - this->SlabThickness - CellWidth / 2.0;
    2948             : 
    2949           4 :                 if (std::find(this->Partitions.Y.begin(), this->Partitions.Y.end(), SlabDistFromBottom) == this->Partitions.Y.end()) {
    2950             : 
    2951             :                     // Partition at bottom edge of vertical insulation, if vertical insulation present
    2952           4 :                     if (this->VertInsPresentFlag) {
    2953             :                         // Under-slab partition
    2954           4 :                         this->Partitions.Y.emplace_back(SlabDistFromBottom, PartitionType::UnderFloor, CellWidth);
    2955             :                         // Vertical-Insulation edge partition
    2956           4 :                         this->Partitions.Y.emplace_back(YInsulationLocation, PartitionType::VertInsLowerEdge, CellWidth);
    2957             :                     } else {
    2958             :                         // Under-slab partition
    2959           0 :                         this->Partitions.Y.emplace_back(SlabDistFromBottom, PartitionType::UnderFloor, CellWidth);
    2960             :                     }
    2961             :                 }
    2962             :             } else { // Slab on-grade case
    2963             : 
    2964           1 :                 if (std::find(this->Partitions.Y.begin(), this->Partitions.Y.end(), YInsulationLocation) == this->Partitions.Y.end()) {
    2965             :                     // Partition at bottom edge of vertical insulation, if vertical insulation present
    2966           1 :                     if (this->VertInsPresentFlag) {
    2967             :                         // Vertical-Insulation edge partition
    2968           1 :                         this->Partitions.Y.emplace_back(YInsulationLocation, PartitionType::VertInsLowerEdge, CellWidth);
    2969             :                     }
    2970             :                 }
    2971             :             }
    2972             : 
    2973             :             // Create Z-direction partitions
    2974             : 
    2975           5 :             CellWidth = this->VertInsThickness;
    2976             :             // Side Z direction
    2977           5 :             SideZLocation = this->PerimeterOffset - CellWidth / 2.0;
    2978             :             // Insulation Edge Z direction
    2979           5 :             if (this->HorizInsPresentFlag && !this->FullHorizInsPresent) {
    2980           0 :                 SideZInsulationLocation = SideZLocation + this->HorizInsWidth;
    2981             :             } else {
    2982           5 :                 SideZInsulationLocation = -1;
    2983             :             }
    2984           5 :             if (std::find(this->Partitions.Z.begin(), this->Partitions.Z.end(), this->SlabWidth) == this->Partitions.Z.end()) {
    2985             :                 // Partition at insulation edges in the Z direction, if horizontal insulation present
    2986           5 :                 if (this->HorizInsPresentFlag) {
    2987           4 :                     if (!this->FullHorizInsPresent) {
    2988             :                         // Side Z direction
    2989           0 :                         this->Partitions.Z.emplace_back(SideZLocation, PartitionType::ZSide, CellWidth);
    2990             :                         // Insulation Edge Z direction
    2991           0 :                         this->Partitions.Z.emplace_back(SideZInsulationLocation, PartitionType::HorizInsZSide, CellWidth);
    2992             :                     } else {
    2993             :                         // Side Z direction
    2994           4 :                         this->Partitions.Z.emplace_back(SideZLocation, PartitionType::ZSide, CellWidth);
    2995             :                     }
    2996             :                 } else {
    2997             :                     // Side Z direction
    2998           1 :                     this->Partitions.Z.emplace_back(SideZLocation, PartitionType::ZSide, CellWidth);
    2999             :                 }
    3000             :             }
    3001             :         }
    3002          65 :         auto lambda = [](MeshPartition a, MeshPartition b) { return a.rDimension < b.rDimension; };
    3003          11 :         std::sort(this->Partitions.X.begin(), this->Partitions.X.end(), lambda);
    3004          11 :         std::sort(this->Partitions.Y.begin(), this->Partitions.Y.end(), lambda);
    3005          11 :         std::sort(this->Partitions.Z.begin(), this->Partitions.Z.end(), lambda);
    3006          11 :     }
    3007             : 
    3008          33 :     std::vector<GridRegion> Domain::createPartitionRegionList(EnergyPlusData &state,
    3009             :                                                               std::vector<MeshPartition> const &ThesePartitionCenters,
    3010             :                                                               bool const PartitionsExist,
    3011             :                                                               Real64 const DirExtentMax)
    3012             :     {
    3013             : 
    3014             :         // FUNCTION INFORMATION:
    3015             :         //       AUTHOR         Edwin Lee
    3016             :         //       DATE WRITTEN   Summer 2011
    3017             :         //       MODIFIED       na
    3018             :         //       RE-ENGINEERED  na
    3019             : 
    3020             :         // Return value
    3021          33 :         std::vector<GridRegion> ThesePartitionRegions;
    3022             : 
    3023             :         // FUNCTION PARAMETER DEFINITIONS:
    3024             :         static constexpr std::string_view RoutineName("CreatePartitionRegionList");
    3025             : 
    3026          33 :         if (!PartitionsExist) {
    3027           5 :             return ThesePartitionRegions;
    3028             :         }
    3029             : 
    3030             :         //'loop across all partitions
    3031          78 :         for (int Index = 0; Index < (int)ThesePartitionCenters.size(); ++Index) {
    3032          50 :             auto &thisPartitionCenter = ThesePartitionCenters[Index];
    3033             : 
    3034          50 :             Real64 const ThisCellWidthBy2 = thisPartitionCenter.TotalWidth / 2.0;
    3035          50 :             PartitionType ThisPartitionType = thisPartitionCenter.partitionType;
    3036             : 
    3037             :             //'use this half width to validate the region and add it to the collection
    3038          50 :             Real64 CellLeft = thisPartitionCenter.rDimension - ThisCellWidthBy2;
    3039          50 :             Real64 CellRight = thisPartitionCenter.rDimension + ThisCellWidthBy2;
    3040             : 
    3041             :             // check to make sure this location is valid
    3042          50 :             if (CellLeft < 0.0 || CellRight > DirExtentMax) {
    3043           0 :                 ShowSevereError(state, format("PlantPipingSystems::{}: Invalid partition location in domain.", RoutineName));
    3044           0 :                 ShowContinueError(state, format("Occurs during mesh development for domain={}", this->Name));
    3045           0 :                 ShowContinueError(state, "A pipe or basement is located outside of the domain extents.");
    3046           0 :                 ShowFatalError(state, "Preceding error causes program termination.");
    3047             :             }
    3048             : 
    3049             :             // Scan all grid regions to make sure this range doesn't fall within an already entered range
    3050          87 :             for (int SubIndex = 0; SubIndex <= Index - 1; ++SubIndex) {
    3051          37 :                 auto &thisPartitionRegionSubIndex = ThesePartitionRegions[SubIndex];
    3052             :                 // Coupled-basement model has adjacent partitions: ThesePartitionRegions( 0 ) and ThesePartitionRegions( 1 ) - SA
    3053          37 :                 if (this->HasZoneCoupledBasement && Index == 1) {
    3054           6 :                     if (IsInRange_BasementModel(CellLeft, thisPartitionRegionSubIndex.Min, thisPartitionRegionSubIndex.Max) ||
    3055           3 :                         IsInRangeReal(CellRight, thisPartitionRegionSubIndex.Min, thisPartitionRegionSubIndex.Max)) {
    3056             : 
    3057           0 :                         ShowSevereError(state, format("PlantPipingSystems::{}: Invalid partition location in domain.", RoutineName));
    3058           0 :                         ShowContinueError(state, format("Occurs during mesh development for domain={}", this->Name));
    3059           0 :                         ShowContinueError(state, "A mesh conflict was encountered where partitions were overlapping.");
    3060           0 :                         ShowContinueError(state, "Ensure that all pipes exactly line up or are separated to allow meshing in between them");
    3061           0 :                         ShowContinueError(state, "Also verify the pipe and basement dimensions to avoid conflicts there.");
    3062           0 :                         ShowFatalError(state, "Preceding error causes program termination");
    3063             :                     }
    3064             : 
    3065             :                 } else {
    3066             : 
    3067          68 :                     if (IsInRangeReal(CellLeft, thisPartitionRegionSubIndex.Min, thisPartitionRegionSubIndex.Max) ||
    3068          34 :                         IsInRangeReal(CellRight, thisPartitionRegionSubIndex.Min, thisPartitionRegionSubIndex.Max)) {
    3069             : 
    3070           0 :                         ShowSevereError(state, format("PlantPipingSystems::{}: Invalid partition location in domain.", RoutineName));
    3071           0 :                         ShowContinueError(state, format("Occurs during mesh development for domain={}", this->Name));
    3072           0 :                         ShowContinueError(state, "A mesh conflict was encountered where partitions were overlapping.");
    3073           0 :                         ShowContinueError(state, "Ensure that all pipes exactly line up or are separated to allow meshing in between them");
    3074           0 :                         ShowContinueError(state, "Also verify the pipe and basement dimensions to avoid conflicts there.");
    3075           0 :                         ShowFatalError(state, "Preceding error causes program termination");
    3076             :                     }
    3077             :                 }
    3078             :             }
    3079             : 
    3080          50 :             ThesePartitionRegions.emplace_back();
    3081          50 :             auto &thisNewPartitionRegion = ThesePartitionRegions[Index];
    3082          50 :             thisNewPartitionRegion.Min = CellLeft;
    3083          50 :             thisNewPartitionRegion.Max = CellRight;
    3084             : 
    3085             :             // Need to map partition type into region type parameters, since they are different enumerations
    3086          50 :             if (ThisPartitionType == PartitionType::BasementWall) {
    3087           1 :                 thisNewPartitionRegion.thisRegionType = RegionType::BasementWall;
    3088          49 :             } else if (ThisPartitionType == PartitionType::BasementFloor) {
    3089           1 :                 thisNewPartitionRegion.thisRegionType = RegionType::BasementFloor;
    3090          48 :             } else if (ThisPartitionType == PartitionType::Pipe) {
    3091          20 :                 thisNewPartitionRegion.thisRegionType = RegionType::Pipe;
    3092          28 :             } else if (ThisPartitionType == PartitionType::XSide) {
    3093           6 :                 thisNewPartitionRegion.thisRegionType = RegionType::XSide;
    3094          22 :             } else if (ThisPartitionType == PartitionType::XSideWall) {
    3095           1 :                 thisNewPartitionRegion.thisRegionType = RegionType::XSideWall;
    3096          21 :             } else if (ThisPartitionType == PartitionType::HorizInsXSide) {
    3097           1 :                 thisNewPartitionRegion.thisRegionType = RegionType::HorizInsXSide;
    3098          20 :             } else if (ThisPartitionType == PartitionType::ZSide) {
    3099           6 :                 thisNewPartitionRegion.thisRegionType = RegionType::ZSide;
    3100          14 :             } else if (ThisPartitionType == PartitionType::ZSideWall) {
    3101           1 :                 thisNewPartitionRegion.thisRegionType = RegionType::ZSideWall;
    3102          13 :             } else if (ThisPartitionType == PartitionType::HorizInsZSide) {
    3103           1 :                 thisNewPartitionRegion.thisRegionType = RegionType::HorizInsZSide;
    3104          12 :             } else if (ThisPartitionType == PartitionType::FloorInside) {
    3105           1 :                 thisNewPartitionRegion.thisRegionType = RegionType::FloorInside;
    3106          11 :             } else if (ThisPartitionType == PartitionType::UnderFloor) {
    3107           5 :                 thisNewPartitionRegion.thisRegionType = RegionType::UnderFloor;
    3108           6 :             } else if (ThisPartitionType == PartitionType::VertInsLowerEdge) {
    3109           6 :                 thisNewPartitionRegion.thisRegionType = RegionType::VertInsLowerEdge;
    3110             :             } else {
    3111             :                 // diagnostic error
    3112             :             }
    3113             :         }
    3114             : 
    3115          28 :         return ThesePartitionRegions;
    3116           0 :     }
    3117             : 
    3118             : #pragma clang diagnostic push
    3119             : #pragma ide diagnostic ignored "ArgumentSelectionDefectsInspection"
    3120             : 
    3121          33 :     void Domain::createRegionList(std::vector<GridRegion> &Regions,
    3122             :                                   std::vector<GridRegion> const &ThesePartitionRegions,
    3123             :                                   Real64 const DirExtentMax,
    3124             :                                   RegionType const DirDirection,
    3125             :                                   bool const PartitionsExist,
    3126             :                                   ObjexxFCL::Optional_int BasementWallXIndex,
    3127             :                                   ObjexxFCL::Optional_int BasementFloorYIndex,
    3128             :                                   ObjexxFCL::Optional_int XIndex,
    3129             :                                   ObjexxFCL::Optional_int XWallIndex,
    3130             :                                   ObjexxFCL::Optional_int InsulationXIndex,
    3131             :                                   ObjexxFCL::Optional_int YIndex,
    3132             :                                   ObjexxFCL::Optional_int YFloorIndex,
    3133             :                                   ObjexxFCL::Optional_int InsulationYIndex,
    3134             :                                   ObjexxFCL::Optional_int ZIndex,
    3135             :                                   ObjexxFCL::Optional_int ZWallIndex,
    3136             :                                   ObjexxFCL::Optional_int InsulationZIndex)
    3137             :     {
    3138             : 
    3139             :         // FUNCTION INFORMATION:
    3140             :         //       AUTHOR         Edwin Lee
    3141             :         //       DATE WRITTEN   Summer 2011
    3142             :         //       MODIFIED       na
    3143             :         //       RE-ENGINEERED  na
    3144             : 
    3145          33 :         int cellCountUpToNow = 0;
    3146          33 :         std::vector<Real64> tempCellWidths;
    3147             : 
    3148          33 :         if (PartitionsExist) {
    3149             : 
    3150          78 :             for (int i = 0; i < (int)ThesePartitionRegions.size(); ++i) {
    3151          50 :                 auto &thisPartition = ThesePartitionRegions[i];
    3152             : 
    3153          50 :                 if (i == 0) { // First partition
    3154             :                     // Create region to left of partition
    3155          28 :                     GridRegion tempRegion(0.0, thisPartition.Min, DirDirection, tempCellWidths);
    3156          28 :                     int potentialCellWidthsCount = this->getCellWidthsCount(DirDirection);
    3157          28 :                     if ((thisPartition.Min - 0.0) < 0.00001) {
    3158           0 :                         cellCountUpToNow += 1; // just one cell for extremely tight regions
    3159             :                     } else {
    3160          28 :                         cellCountUpToNow += potentialCellWidthsCount;
    3161             :                     }
    3162          28 :                     this->getCellWidths(tempRegion, tempRegion.thisRegionType);
    3163          28 :                     Regions.push_back(tempRegion);
    3164          50 :                 } else if (i == 1 && this->HasZoneCoupledBasement) {
    3165           3 :                     cellCountUpToNow += 1; // don't add a left partition for partition index 1 of coupled basements
    3166             :                 } else {                   // All other partitions
    3167             :                     // Because of the way the index block below is structured, we need to update cellCount
    3168             :                     //  **after** we pass that block.  We could include logic below to do this, but this block
    3169             :                     //  already fits within the structure properly, so increment it here to account for the
    3170             :                     //  single cell partition layer that was applied at the **end** of the previous partition index
    3171          19 :                     ++cellCountUpToNow;
    3172             :                     // Create region to left of partition
    3173          19 :                     auto &leftPartition = ThesePartitionRegions[i - 1];
    3174          19 :                     auto tempRegion = GridRegion(leftPartition.Max, thisPartition.Min, DirDirection, tempCellWidths); // (AUTO_OK_OBJ)
    3175          19 :                     int potentialCellWidthsCount = this->getCellWidthsCount(DirDirection);
    3176          19 :                     if ((thisPartition.Min - leftPartition.Max) < 0.00001) {
    3177           0 :                         cellCountUpToNow += 1; // just one cell for extremely tight regions
    3178             :                     } else {
    3179          19 :                         cellCountUpToNow += potentialCellWidthsCount;
    3180             :                     }
    3181          19 :                     this->getCellWidths(tempRegion, tempRegion.thisRegionType);
    3182          19 :                     Regions.push_back(tempRegion);
    3183          19 :                 }
    3184             : 
    3185          50 :                 if (thisPartition.thisRegionType == RegionType::BasementWall) {
    3186           1 :                     if (present(BasementWallXIndex)) BasementWallXIndex = cellCountUpToNow;
    3187          49 :                 } else if (thisPartition.thisRegionType == RegionType::BasementFloor) {
    3188           1 :                     if (present(BasementFloorYIndex)) BasementFloorYIndex = cellCountUpToNow;
    3189          48 :                 } else if (thisPartition.thisRegionType == RegionType::XSide) {
    3190           6 :                     if (present(XIndex)) XIndex = cellCountUpToNow;
    3191           6 :                     this->XIndex = XIndex;
    3192          42 :                 } else if (thisPartition.thisRegionType == RegionType::XSideWall) {
    3193           1 :                     if (present(XWallIndex)) XWallIndex = cellCountUpToNow;
    3194           1 :                     this->XWallIndex = XWallIndex;
    3195          41 :                 } else if (thisPartition.thisRegionType == RegionType::ZSide) {
    3196           6 :                     if (present(ZIndex)) ZIndex = cellCountUpToNow;
    3197           6 :                     this->ZIndex = ZIndex;
    3198          35 :                 } else if (thisPartition.thisRegionType == RegionType::ZSideWall) {
    3199           1 :                     if (present(ZWallIndex)) ZWallIndex = cellCountUpToNow;
    3200           1 :                     this->ZWallIndex = ZWallIndex;
    3201          34 :                 } else if (thisPartition.thisRegionType == RegionType::HorizInsXSide) {
    3202           1 :                     if (present(InsulationXIndex)) InsulationXIndex = cellCountUpToNow;
    3203           1 :                     this->InsulationXIndex = InsulationXIndex;
    3204          33 :                 } else if (thisPartition.thisRegionType == RegionType::HorizInsZSide) {
    3205           1 :                     if (present(InsulationZIndex)) InsulationZIndex = cellCountUpToNow;
    3206           1 :                     this->InsulationZIndex = InsulationZIndex;
    3207          32 :                 } else if (thisPartition.thisRegionType == RegionType::FloorInside) {
    3208           1 :                     if (present(YFloorIndex)) YFloorIndex = cellCountUpToNow;
    3209           1 :                     this->YFloorIndex = YFloorIndex;
    3210          31 :                 } else if (thisPartition.thisRegionType == RegionType::UnderFloor) {
    3211           5 :                     if (present(YIndex)) YIndex = cellCountUpToNow;
    3212           5 :                     this->YIndex = YIndex;
    3213          26 :                 } else if (thisPartition.thisRegionType == RegionType::VertInsLowerEdge) {
    3214           6 :                     if (present(InsulationYIndex)) InsulationYIndex = cellCountUpToNow;
    3215           6 :                     this->InsulationYIndex = InsulationYIndex;
    3216             :                 }
    3217             : 
    3218             :                 // Create region for this partition
    3219          50 :                 auto tempRegion = GridRegion(thisPartition.Min, thisPartition.Max, thisPartition.thisRegionType, tempCellWidths); // (AUTO_OK_OBJ)
    3220          50 :                 this->getCellWidths(tempRegion, tempRegion.thisRegionType);
    3221          50 :                 Regions.push_back(tempRegion);
    3222          50 :             }
    3223             : 
    3224             :             // Create final region
    3225          28 :             auto &thisPartition = ThesePartitionRegions[ThesePartitionRegions.size() - 1];
    3226          28 :             auto tempRegion = GridRegion(thisPartition.Max, DirExtentMax, DirDirection, tempCellWidths); // (AUTO_OK_OBJ)
    3227          28 :             this->getCellWidths(tempRegion, tempRegion.thisRegionType);
    3228          28 :             Regions.push_back(tempRegion);
    3229             : 
    3230          28 :         } else {
    3231             :             // Need to create a region anyway if no partitions exist
    3232           5 :             auto tempRegion = GridRegion(0.0, DirExtentMax, DirDirection, tempCellWidths); // (AUTO_OK_OBJ)
    3233           5 :             this->getCellWidths(tempRegion, tempRegion.thisRegionType);
    3234           5 :             Regions.push_back(tempRegion);
    3235           5 :         }
    3236          33 :     }
    3237             : 
    3238             : #pragma clang diagnostic pop
    3239             : 
    3240          33 :     std::vector<Real64> CreateBoundaryList(std::vector<GridRegion> const &RegionList, Real64 const DirExtentMax, RegionType const DirDirection)
    3241             :     {
    3242             : 
    3243             :         // FUNCTION INFORMATION:
    3244             :         //       AUTHOR         Edwin Lee
    3245             :         //       DATE WRITTEN   Summer 2011
    3246             :         //       MODIFIED       na
    3247             :         //       RE-ENGINEERED  na
    3248             : 
    3249          33 :         std::vector<Real64> RetVal;
    3250         163 :         for (auto const &thisRegion : RegionList) {
    3251         130 :             switch (thisRegion.thisRegionType) {
    3252          50 :             case RegionType::Pipe:
    3253             :             case RegionType::BasementFloor:
    3254             :             case RegionType::BasementWall:
    3255             :             case RegionType::XSide:
    3256             :             case RegionType::XSideWall:
    3257             :             case RegionType::ZSide:
    3258             :             case RegionType::ZSideWall:
    3259             :             case RegionType::HorizInsXSide:
    3260             :             case RegionType::HorizInsZSide:
    3261             :             case RegionType::FloorInside:
    3262             :             case RegionType::UnderFloor:
    3263             :             case RegionType::VertInsLowerEdge:
    3264          50 :                 RetVal.push_back(thisRegion.Min);
    3265          50 :                 break;
    3266          80 :             default:
    3267          80 :                 if (thisRegion.thisRegionType == DirDirection) {
    3268          80 :                     Real64 StartingPointCounter = thisRegion.Min;
    3269         422 :                     for (auto &cellWidth : thisRegion.CellWidths) {
    3270         342 :                         RetVal.push_back(StartingPointCounter);
    3271         342 :                         StartingPointCounter += cellWidth;
    3272          80 :                     }
    3273             :                 }
    3274             :             }
    3275          33 :         }
    3276          33 :         RetVal.push_back(DirExtentMax);
    3277          33 :         return RetVal;
    3278           0 :     }
    3279             : 
    3280          11 :     void Domain::createCellArray(std::vector<Real64> const &XBoundaryPoints,
    3281             :                                  std::vector<Real64> const &YBoundaryPoints,
    3282             :                                  std::vector<Real64> const &ZBoundaryPoints)
    3283             :     {
    3284             : 
    3285             :         // SUBROUTINE INFORMATION:
    3286             :         //       AUTHOR         Edwin Lee
    3287             :         //       DATE WRITTEN   Summer 2011
    3288             :         //       MODIFIED       na
    3289             :         //       RE-ENGINEERED  na
    3290             : 
    3291          11 :         int TotNumCells = 0;
    3292          11 :         int NumCutawayBasementCells = 0;
    3293          11 :         int NumInsulationCells = 0;
    3294          11 :         int NumGroundSurfaceCells = 0;
    3295             : 
    3296             :         //'subtract 2 in each dimension:
    3297             :         //'     one for zero based array
    3298             :         //'     one because the boundary points contain one entry more than the number of cells WITHIN the domain
    3299          11 :         this->x_max_index = XBoundaryPoints.size() - 2;
    3300          11 :         this->y_max_index = YBoundaryPoints.size() - 2;
    3301          11 :         this->z_max_index = ZBoundaryPoints.size() - 2;
    3302          11 :         this->Cells.allocate({0, this->x_max_index}, {0, this->y_max_index}, {0, this->z_max_index});
    3303             : 
    3304          11 :         int MaxBasementXNodeIndex = this->BasementZone.BasementWallXIndex;
    3305          11 :         int MinBasementYNodeIndex = this->BasementZone.BasementFloorYIndex;
    3306          11 :         int MinXIndex = this->XIndex;
    3307          11 :         int YIndex = this->YIndex;
    3308          11 :         int MinZIndex = this->ZIndex;
    3309          11 :         int XWallIndex = this->XWallIndex;
    3310          11 :         int YFloorIndex = this->YFloorIndex;
    3311          11 :         int ZWallIndex = this->ZWallIndex;
    3312          11 :         int InsulationXIndex = this->InsulationXIndex;
    3313          11 :         int InsulationYIndex = this->InsulationYIndex;
    3314          11 :         int InsulationZIndex = this->InsulationZIndex;
    3315             : 
    3316          11 :         auto &cells = this->Cells;
    3317         146 :         for (int X = 0, X_end = this->x_max_index; X <= X_end; ++X) {
    3318        2104 :             for (int Y = 0, Y_end = this->y_max_index; Y <= Y_end; ++Y) {
    3319       24019 :                 for (int Z = 0, Z_end = this->z_max_index; Z <= Z_end; ++Z) {
    3320       22050 :                     auto &cell = cells(X, Y, Z);
    3321             : 
    3322             :                     //'set up x-direction variables
    3323       22050 :                     int CellXIndex = X;                            //'zero based index
    3324       22050 :                     Real64 CellXMinValue = XBoundaryPoints[X];     //'left wall x-value
    3325       22050 :                     Real64 CellXMaxValue = XBoundaryPoints[X + 1]; //'right wall x-value
    3326       22050 :                     Real64 CellXCenter = (CellXMinValue + CellXMaxValue) / 2;
    3327       22050 :                     Real64 CellWidth = CellXMaxValue - CellXMinValue;
    3328             : 
    3329             :                     //'set up y-direction variables
    3330       22050 :                     int CellYIndex = Y;                            //'zero based index
    3331       22050 :                     Real64 CellYMinValue = YBoundaryPoints[Y];     //'bottom wall y-value
    3332       22050 :                     Real64 CellYMaxValue = YBoundaryPoints[Y + 1]; //'top wall y-value
    3333       22050 :                     Real64 CellYCenter = (CellYMinValue + CellYMaxValue) / 2;
    3334       22050 :                     Real64 CellHeight = CellYMaxValue - CellYMinValue;
    3335             : 
    3336             :                     //'set up z-direction variables
    3337       22050 :                     int CellZIndex = Z;                            //'zero based index
    3338       22050 :                     Real64 CellZMinValue = ZBoundaryPoints[Z];     //'lower z value
    3339       22050 :                     Real64 CellZMaxValue = ZBoundaryPoints[Z + 1]; //'higher z value
    3340       22050 :                     Real64 CellZCenter = (CellZMinValue + CellZMaxValue) / 2;
    3341             : 
    3342             :                     //'set up an extent class for this cell
    3343             :                     CellExtents theseCellExtents =
    3344       22050 :                         CellExtents(CellXMaxValue, CellYMaxValue, CellZMaxValue, CellXMinValue, CellYMinValue, CellZMinValue);
    3345             : 
    3346             :                     //'set up centroid, index, and overall size
    3347       22050 :                     Point3DReal Centroid = Point3DReal(CellXCenter, CellYCenter, CellZCenter);
    3348       22050 :                     Point3DInteger CellIndeces = Point3DInteger(CellXIndex, CellYIndex, CellZIndex);
    3349       22050 :                     RectangleF XYRectangle = RectangleF(CellXMinValue, CellYMinValue, CellWidth, CellHeight);
    3350             : 
    3351             :                     //'determine cell type
    3352       22050 :                     CellType cellType = CellType::Invalid;
    3353             : 
    3354             :                     //'if this is a pipe node, some flags are needed
    3355       22050 :                     bool pipeCell = false;
    3356       22050 :                     int NumRadialCells = -1;
    3357             : 
    3358             :                     // Adiabatic behavior is now achieved in the SetupCellNeighbors routine, these are simply farfield for now.
    3359       22050 :                     CellType const ZWallCellType = CellType::FarfieldBoundary;
    3360       22050 :                     CellType const UnderBasementBoundary = CellType::FarfieldBoundary;
    3361             : 
    3362             :                     //'apply boundary conditions
    3363             : 
    3364             :                     // For zone-coupled ground domain
    3365       22050 :                     if (this->HasZoneCoupledSlab) {
    3366             : 
    3367             :                         // Assign all cells common between on-grade and in-grade cases first
    3368             :                         // This should be all X/Z-side interface, vertical insulation, far-field,
    3369             :                         // ground surface, and ground/zone interface cells
    3370       15717 :                         if (CellXIndex == MinXIndex && CellZIndex >= MinZIndex) { // Z side interface
    3371             :                             // Check if vertical insulation present
    3372         651 :                             if (this->VertInsPresentFlag) {
    3373         651 :                                 if (CellYIndex <= this->y_max_index && CellYIndex >= InsulationYIndex) { // Check depth of vertical insulation
    3374         441 :                                     cellType = CellType::VertInsulation;
    3375         441 :                                     ++NumInsulationCells;
    3376             :                                 }
    3377           0 :                             } else if (CellYIndex == this->y_max_index) {
    3378           0 :                                 cellType = CellType::GroundSurface;
    3379           0 :                                 ++NumGroundSurfaceCells;
    3380             :                             }
    3381       15066 :                         } else if (CellZIndex == MinZIndex && CellXIndex >= MinXIndex) {                 // X side interface
    3382         558 :                             if (this->VertInsPresentFlag) {                                              // Check if vertical insulation present
    3383         558 :                                 if (CellYIndex <= this->y_max_index && CellYIndex >= InsulationYIndex) { // Check depth of vertical insulation
    3384         378 :                                     cellType = CellType::VertInsulation;
    3385         378 :                                     ++NumInsulationCells;
    3386             :                                 }
    3387           0 :                             } else if (CellYIndex == this->y_max_index) {
    3388           0 :                                 cellType = CellType::GroundSurface;
    3389           0 :                                 ++NumGroundSurfaceCells;
    3390             :                             }
    3391       14508 :                         } else if (CellYIndex == y_max_index) {
    3392         780 :                             if (CellXIndex <= MinXIndex || CellZIndex <= MinZIndex) { // Ground surface
    3393         600 :                                 cellType = CellType::GroundSurface;
    3394         600 :                                 ++NumGroundSurfaceCells;
    3395         180 :                             } else if (CellXIndex >= MinXIndex || CellZIndex >= MinZIndex) { // Zone-ground interface
    3396         180 :                                 cellType = CellType::ZoneGroundInterface;
    3397             :                             }
    3398             :                         }
    3399             : 
    3400       15717 :                         if (CellYIndex == 0 || CellXIndex == 0 || CellZIndex == 0) { // Farfield boundary
    3401        3045 :                             cellType = CellType::FarfieldBoundary;
    3402             :                         }
    3403             : 
    3404             :                         // Assign different cells between in-grade and on-grade cases
    3405       15717 :                         if (this->SlabInGradeFlag) { // In-grade case
    3406             :                             // This will assign the slab cells and horizontal insulation
    3407             : 
    3408       13520 :                             if (CellZIndex > MinZIndex && CellXIndex > MinXIndex) {     // Cells inside bounds of slab
    3409        2880 :                                 if (CellYIndex >= YIndex && CellYIndex < y_max_index) { // Slab cells
    3410         864 :                                     cellType = CellType::Slab;
    3411        2016 :                                 } else if (CellYIndex == (YIndex - 1)) {
    3412         144 :                                     if (this->HorizInsPresentFlag && this->FullHorizInsPresent) { // Full under-slab insulation
    3413         144 :                                         cellType = CellType::HorizInsulation;
    3414           0 :                                     } else if (this->HorizInsPresentFlag && !this->FullHorizInsPresent) { // Perimeter only under-slab insulation
    3415           0 :                                         if (CellZIndex < InsulationZIndex || CellXIndex < InsulationXIndex) {
    3416           0 :                                             cellType = CellType::HorizInsulation;
    3417             :                                         }
    3418             :                                     }
    3419             :                                 }
    3420             :                             }
    3421             : 
    3422             :                         } else { // Slab-on grade
    3423             :                             // Nothing should happen. Interface cells should already be set.
    3424             :                             // Under that are 'General' field cells that should be caught later.
    3425             :                         }
    3426             : 
    3427        6333 :                     } else if (this->HasZoneCoupledBasement) { // basement model, zone-coupled
    3428             :                         // Set the appropriate cell type
    3429        3375 :                         if (CellYIndex == 0) { // Farfield cells
    3430         225 :                             cellType = CellType::FarfieldBoundary;
    3431        3150 :                         } else if (CellXIndex > XWallIndex && CellZIndex > ZWallIndex) {       // Basement cutaway
    3432        1134 :                             if (CellYIndex <= this->y_max_index && CellYIndex > YFloorIndex) { // General basement cells
    3433         729 :                                 cellType = CellType::BasementCutaway;
    3434             :                                 // Not counting basement cutaway cells.
    3435         405 :                             } else if (CellYIndex == YFloorIndex) { // Basement Floor cells
    3436          81 :                                 cellType = CellType::BasementFloor;
    3437         324 :                             } else if (CellYIndex == YIndex) {
    3438             :                                 // Check if horizontal insulation present
    3439          81 :                                 if (this->HorizInsPresentFlag) {
    3440          81 :                                     if (this->FullHorizInsPresent) { // Entire underfloor insulated
    3441           0 :                                         cellType = CellType::HorizInsulation;
    3442           0 :                                         ++NumInsulationCells;
    3443             :                                     } else { // Perimeter insulation
    3444          81 :                                         if (CellXIndex < InsulationXIndex || CellZIndex < InsulationZIndex) {
    3445          56 :                                             cellType = CellType::HorizInsulation;
    3446          56 :                                             ++NumInsulationCells;
    3447             :                                         }
    3448             :                                     }
    3449             :                                 }
    3450             :                             }
    3451        2016 :                         } else if ((CellXIndex == XWallIndex && CellZIndex > ZWallIndex) ||
    3452         210 :                                    (CellZIndex == ZWallIndex && CellXIndex > XWallIndex)) { // Basement Walls
    3453         252 :                             if (CellYIndex <= this->y_max_index && CellYIndex > YFloorIndex) {
    3454         162 :                                 cellType = CellType::BasementWall;
    3455             :                             }
    3456        1764 :                         } else if ((CellXIndex == MinXIndex && CellZIndex > ZWallIndex) ||
    3457         210 :                                    (CellZIndex == MinZIndex && CellXIndex > XWallIndex)) { // Insulation cells
    3458         252 :                             if (CellYIndex <= this->y_max_index && CellYIndex > YFloorIndex) {
    3459             :                                 // Check if vertical insulation present
    3460         162 :                                 if (this->VertInsPresentFlag) {
    3461         162 :                                     if (InsulationYIndex != 0) { // Partial vertical insulation
    3462         162 :                                         if (CellYIndex <= this->y_max_index && CellYIndex > InsulationYIndex) {
    3463          72 :                                             cellType = CellType::VertInsulation;
    3464          72 :                                             ++NumInsulationCells;
    3465             :                                         }
    3466             :                                     } else { // Vertical insulation extends to depth of basement floor
    3467           0 :                                         if (CellYIndex <= this->y_max_index && CellYIndex > YFloorIndex) {
    3468           0 :                                             cellType = CellType::VertInsulation;
    3469           0 :                                             ++NumInsulationCells;
    3470             :                                         }
    3471             :                                     }
    3472             :                                 }
    3473             :                             }
    3474        1512 :                         } else if (CellYIndex == this->y_max_index) { // Surface cells
    3475         108 :                             cellType = CellType::GroundSurface;
    3476         108 :                             ++NumGroundSurfaceCells;
    3477        1404 :                         } else if (CellYIndex == 0 || CellXIndex == 0 || CellZIndex == 0) { // Farfield boundary
    3478         377 :                             cellType = CellType::FarfieldBoundary;
    3479             :                         }
    3480        2958 :                     } else if (CellXIndex == MaxBasementXNodeIndex && CellYIndex == MinBasementYNodeIndex) {
    3481           6 :                         cellType = CellType::BasementCorner;
    3482        2952 :                     } else if (CellXIndex == MaxBasementXNodeIndex && CellYIndex > MinBasementYNodeIndex) {
    3483          84 :                         cellType = CellType::BasementWall;
    3484        2868 :                     } else if (CellXIndex < MaxBasementXNodeIndex && CellYIndex == MinBasementYNodeIndex) {
    3485          12 :                         cellType = CellType::BasementFloor;
    3486        2856 :                     } else if (CellXIndex < MaxBasementXNodeIndex && CellYIndex > MinBasementYNodeIndex) {
    3487         168 :                         cellType = CellType::BasementCutaway;
    3488             :                         // Not counting basement cutaway cells
    3489        2688 :                     } else if (CellYIndex == Y_end) {
    3490         284 :                         cellType = CellType::GroundSurface;
    3491         284 :                         ++NumGroundSurfaceCells;
    3492        2404 :                     } else if (CellXIndex == 0) {
    3493         116 :                         if (this->HasBasement && Y > 0) {
    3494           6 :                             cellType = UnderBasementBoundary; //'this must come after the basement cutaway ELSEIF branch
    3495             :                         } else {
    3496         110 :                             cellType = CellType::FarfieldBoundary;
    3497             :                         }
    3498        2288 :                     } else if (CellXIndex == X_end || CellYIndex == 0) {
    3499         446 :                         cellType = CellType::FarfieldBoundary;
    3500        1842 :                     } else if (CellZIndex == 0 || CellZIndex == Z_end) {
    3501         670 :                         cellType = ZWallCellType;
    3502             :                     }
    3503             : 
    3504             :                     //'check to see if this is a pipe node...
    3505       22050 :                     Real64 InsulationThickness(0.0);
    3506       22050 :                     Real64 RadialMeshThickness(0.0);
    3507       22050 :                     bool HasInsulation(false);
    3508       22050 :                     RadialSizing PipeSizing;
    3509       22050 :                     Circuit *circuitReference = nullptr;
    3510       24928 :                     for (auto &thisCircuit : this->circuits) {
    3511       15618 :                         for (auto &segment : thisCircuit->pipeSegments) {
    3512       12740 :                             if (XYRectangle.contains(segment->PipeLocation)) {
    3513             :                                 //'inform the cell that it is a pipe node
    3514          80 :                                 cellType = CellType::Pipe;
    3515             :                                 //'inform the cell of which pipe it contains
    3516          80 :                                 pipeCell = true;
    3517             :                                 //'inform the cell of which pipe circuit contains it
    3518          80 :                                 circuitReference = thisCircuit;
    3519             :                                 //'inform the pipe of what cell it is inside
    3520          80 :                                 segment->initPipeCells(CellXIndex, CellYIndex);
    3521             :                                 //'set the number of cells to be generated in this near-pipe region
    3522          80 :                                 NumRadialCells = thisCircuit->NumRadialCells;
    3523             :                                 //'exit the pipe counter loop
    3524          80 :                                 goto CircuitLoop_exit;
    3525             :                             }
    3526        3038 :                         }
    3527       22130 :                     }
    3528       22050 :                 CircuitLoop_exit:;
    3529             : 
    3530             :                     //'if it still isn't anything, then it is just an interior node
    3531       22050 :                     switch (cellType) {
    3532         897 :                     case CellType::BasementCutaway:
    3533         897 :                         ++NumCutawayBasementCells;
    3534         897 :                         break;
    3535       12875 :                     case CellType::Invalid:
    3536       12875 :                         cellType = CellType::GeneralField;
    3537             :                         // fallthrough
    3538       21153 :                     default:
    3539       21153 :                         ++TotNumCells;
    3540             :                     }
    3541             : 
    3542             :                     // if we were found on a pipe circuit, get some things for convenience
    3543       22050 :                     if (circuitReference) {
    3544          80 :                         if (circuitReference->HasInsulation) {
    3545           0 :                             InsulationThickness = circuitReference->InsulationSize.thickness();
    3546             :                         }
    3547          80 :                         PipeSizing = circuitReference->PipeSize;
    3548          80 :                         RadialMeshThickness = circuitReference->RadialMeshThickness;
    3549          80 :                         HasInsulation = circuitReference->HasInsulation;
    3550             :                     }
    3551             : 
    3552             :                     //'instantiate the cell class
    3553       22050 :                     cell.X_min = theseCellExtents.Xmin;
    3554       22050 :                     cell.X_max = theseCellExtents.xMax;
    3555       22050 :                     cell.Y_min = theseCellExtents.Ymin;
    3556       22050 :                     cell.Y_max = theseCellExtents.yMax;
    3557       22050 :                     cell.Z_min = theseCellExtents.Zmin;
    3558       22050 :                     cell.Z_max = theseCellExtents.zMax;
    3559       22050 :                     cell.X_index = CellIndeces.X;
    3560       22050 :                     cell.Y_index = CellIndeces.Y;
    3561       22050 :                     cell.Z_index = CellIndeces.Z;
    3562       22050 :                     cell.Centroid = Centroid;
    3563       22050 :                     cell.cellType = cellType;
    3564             : 
    3565       22050 :                     if (pipeCell) {
    3566         160 :                         cell.PipeCellData = CartesianPipeCellInformation(cell.X_max - cell.X_min,
    3567             :                                                                          PipeSizing,
    3568             :                                                                          NumRadialCells,
    3569             :                                                                          cell.depth(),
    3570             :                                                                          InsulationThickness,
    3571             :                                                                          RadialMeshThickness,
    3572          80 :                                                                          HasInsulation);
    3573             :                     }
    3574             : 
    3575             :                 } //'z
    3576             :             }     //'y
    3577             :         }         //'x
    3578             : 
    3579          11 :         this->NumDomainCells = TotNumCells;
    3580          11 :         this->NumGroundSurfCells = NumGroundSurfaceCells;
    3581          11 :         this->NumInsulationCells = NumInsulationCells;
    3582          11 :     }
    3583             : 
    3584          11 :     void Domain::setupCellNeighbors()
    3585             :     {
    3586             : 
    3587             :         // SUBROUTINE INFORMATION:
    3588             :         //       AUTHOR         Edwin Lee
    3589             :         //       DATE WRITTEN   Summer 2011
    3590             :         //       MODIFIED       na
    3591             :         //       RE-ENGINEERED  na
    3592             : 
    3593             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3594             :         Real64 CellRightCentroidX;
    3595             :         Real64 CellRightLeftWallX;
    3596             :         Real64 CellLeftCentroidX;
    3597             :         Real64 CellLeftRightWallX;
    3598             :         Real64 LeftCellCentroidX;
    3599             :         Real64 LeftCellRightWallX;
    3600             :         Real64 RightCellCentroidX;
    3601             :         Real64 RightCellLeftWallX;
    3602             :         Real64 UpperCellCentroidY;
    3603             :         Real64 UpperCellLowerWallY;
    3604             :         Real64 LowerCellCentroidY;
    3605             :         Real64 LowerCellUpperWallY;
    3606             :         Real64 UpperZCellCentroidZ;
    3607             :         Real64 UpperZCellLowerWallZ;
    3608             :         Real64 LowerZCellCentroidZ;
    3609             :         Real64 LowerZCellUpperWallZ;
    3610             : 
    3611          11 :         auto const &cells = this->Cells;
    3612         146 :         for (int X = 0, X_end = this->x_max_index; X <= X_end; ++X) {
    3613        2104 :             for (int Y = 0, Y_end = this->y_max_index; Y <= Y_end; ++Y) {
    3614       24019 :                 for (int Z = 0, Z_end = this->z_max_index; Z <= Z_end; ++Z) {
    3615       22050 :                     auto const &cell = cells(X, Y, Z);
    3616             : 
    3617             :                     //'for convenience
    3618       22050 :                     Real64 const &ThisCellCentroidX = cell.Centroid.X;
    3619       22050 :                     Real64 const &ThisCellCentroidY = cell.Centroid.Y;
    3620       22050 :                     Real64 const &ThisCellCentroidZ = cell.Centroid.Z;
    3621       22050 :                     Real64 ThisAdiabaticMultiplier = 1.0;
    3622       22050 :                     Real64 ThisAdiabaticMultiplierMirror = 1.0;
    3623             : 
    3624             :                     //'setup east/west cell neighbors
    3625       22050 :                     if (X == 0) {
    3626        1662 :                         CellRightCentroidX = cells(X + 1, Y, Z).Centroid.X;
    3627        1662 :                         CellRightLeftWallX = cells(X + 1, Y, Z).X_min;
    3628             :                         // on the X=0 face, the only adiabatic cases are:
    3629             :                         //   1) For a non-zone-coupled basement simulation, where the under basement X=0 cells are adiabatic -- cutaways will also get
    3630             :                         //   adiabatic, but who cares?
    3631        1662 :                         if (((!this->HasZoneCoupledSlab) && (!this->HasZoneCoupledBasement) && (this->HasBasement))) {
    3632         102 :                             ThisAdiabaticMultiplier = 2.0;
    3633         102 :                             ThisAdiabaticMultiplierMirror = 0.0;
    3634             :                         }
    3635        1662 :                         this->addNeighborInformation(X,
    3636             :                                                      Y,
    3637             :                                                      Z,
    3638             :                                                      Direction::PositiveX,
    3639        1662 :                                                      CellRightLeftWallX - ThisCellCentroidX,
    3640             :                                                      CellRightCentroidX - CellRightLeftWallX,
    3641             :                                                      ThisAdiabaticMultiplier);
    3642        1662 :                         this->addNeighborInformation(X, Y, Z, Direction::NegativeX, 0.0, 0.0, ThisAdiabaticMultiplierMirror);
    3643       20388 :                     } else if (X == this->x_max_index) {
    3644             :                         // on the X=XMAX face, the adiabatic cases are:
    3645             :                         //   1) if we are doing a zone coupled slab/basement simulation where we quartered the domain
    3646        1662 :                         if (this->HasZoneCoupledSlab || this->HasZoneCoupledBasement) {
    3647        1434 :                             ThisAdiabaticMultiplier = 2.0;
    3648        1434 :                             ThisAdiabaticMultiplierMirror = 0.0;
    3649             :                         }
    3650        1662 :                         CellLeftCentroidX = cells(X - 1, Y, Z).Centroid.X;
    3651        1662 :                         CellLeftRightWallX = cells(X - 1, Y, Z).X_max;
    3652        1662 :                         this->addNeighborInformation(X,
    3653             :                                                      Y,
    3654             :                                                      Z,
    3655             :                                                      Direction::NegativeX,
    3656        1662 :                                                      ThisCellCentroidX - CellLeftRightWallX,
    3657             :                                                      CellLeftRightWallX - CellLeftCentroidX,
    3658             :                                                      ThisAdiabaticMultiplier);
    3659        1662 :                         this->addNeighborInformation(X, Y, Z, Direction::PositiveX, 0.0, 0.0, ThisAdiabaticMultiplierMirror);
    3660             :                     } else {
    3661       18726 :                         LeftCellCentroidX = cells(X - 1, Y, Z).Centroid.X;
    3662       18726 :                         LeftCellRightWallX = cells(X - 1, Y, Z).X_max;
    3663       18726 :                         RightCellCentroidX = cells(X + 1, Y, Z).Centroid.X;
    3664       18726 :                         RightCellLeftWallX = cells(X + 1, Y, Z).X_min;
    3665       18726 :                         this->addNeighborInformation(X,
    3666             :                                                      Y,
    3667             :                                                      Z,
    3668             :                                                      Direction::NegativeX,
    3669       18726 :                                                      ThisCellCentroidX - LeftCellRightWallX,
    3670             :                                                      LeftCellRightWallX - LeftCellCentroidX,
    3671             :                                                      ThisAdiabaticMultiplier);
    3672       18726 :                         this->addNeighborInformation(X,
    3673             :                                                      Y,
    3674             :                                                      Z,
    3675             :                                                      Direction::PositiveX,
    3676       18726 :                                                      RightCellLeftWallX - ThisCellCentroidX,
    3677             :                                                      RightCellCentroidX - RightCellLeftWallX,
    3678             :                                                      ThisAdiabaticMultiplier);
    3679             :                     }
    3680             : 
    3681             :                     // Reset for the Y direction assignments
    3682       22050 :                     ThisAdiabaticMultiplier = 1.0;
    3683       22050 :                     ThisAdiabaticMultiplierMirror = 1.0;
    3684             : 
    3685             :                     //'setup north/south cell neighbors
    3686       22050 :                     if (Y == 0) {
    3687        1372 :                         UpperCellCentroidY = cells(X, Y + 1, Z).Centroid.Y;
    3688        1372 :                         UpperCellLowerWallY = cells(X, Y + 1, Z).Y_min;
    3689             :                         // on the Y=0 face, the only adiabatic cases are:
    3690             :                         //   1) NONE
    3691        1372 :                         this->addNeighborInformation(X,
    3692             :                                                      Y,
    3693             :                                                      Z,
    3694             :                                                      Direction::PositiveY,
    3695        1372 :                                                      UpperCellLowerWallY - ThisCellCentroidY,
    3696             :                                                      UpperCellCentroidY - UpperCellLowerWallY,
    3697             :                                                      ThisAdiabaticMultiplier);
    3698        1372 :                         this->addNeighborInformation(X, Y, Z, Direction::NegativeY, 0.0, 0.0, ThisAdiabaticMultiplierMirror);
    3699       20678 :                     } else if (Y == this->y_max_index) {
    3700        1372 :                         LowerCellCentroidY = cells(X, Y - 1, Z).Centroid.Y;
    3701        1372 :                         LowerCellUpperWallY = cells(X, Y - 1, Z).Y_max;
    3702             :                         // on the Y=YMAX face, the only adiabatic cases are:
    3703             :                         //   1) NONE
    3704        1372 :                         this->addNeighborInformation(X,
    3705             :                                                      Y,
    3706             :                                                      Z,
    3707             :                                                      Direction::NegativeY,
    3708        1372 :                                                      ThisCellCentroidY - LowerCellUpperWallY,
    3709             :                                                      LowerCellUpperWallY - LowerCellCentroidY,
    3710             :                                                      ThisAdiabaticMultiplier);
    3711        1372 :                         this->addNeighborInformation(X, Y, Z, Direction::PositiveY, 0.0, 0.0, ThisAdiabaticMultiplierMirror);
    3712             :                     } else {
    3713       19306 :                         UpperCellCentroidY = cells(X, Y + 1, Z).Centroid.Y;
    3714       19306 :                         LowerCellCentroidY = cells(X, Y - 1, Z).Centroid.Y;
    3715       19306 :                         UpperCellLowerWallY = cells(X, Y + 1, Z).Y_min;
    3716       19306 :                         LowerCellUpperWallY = cells(X, Y - 1, Z).Y_max;
    3717       19306 :                         this->addNeighborInformation(X,
    3718             :                                                      Y,
    3719             :                                                      Z,
    3720             :                                                      Direction::NegativeY,
    3721       19306 :                                                      ThisCellCentroidY - LowerCellUpperWallY,
    3722             :                                                      LowerCellUpperWallY - LowerCellCentroidY,
    3723             :                                                      ThisAdiabaticMultiplier);
    3724       19306 :                         this->addNeighborInformation(X,
    3725             :                                                      Y,
    3726             :                                                      Z,
    3727             :                                                      Direction::PositiveY,
    3728       19306 :                                                      UpperCellLowerWallY - ThisCellCentroidY,
    3729             :                                                      UpperCellCentroidY - UpperCellLowerWallY,
    3730             :                                                      ThisAdiabaticMultiplier);
    3731             :                     }
    3732             : 
    3733             :                     // Reset for the Z direction assignments
    3734       22050 :                     ThisAdiabaticMultiplier = 1.0;
    3735       22050 :                     ThisAdiabaticMultiplierMirror = 1.0;
    3736             : 
    3737             :                     //'setup forward/backward cell neighbors
    3738       22050 :                     if (Z == 0) {
    3739        1969 :                         UpperZCellCentroidZ = cells(X, Y, Z + 1).Centroid.Z;
    3740        1969 :                         UpperZCellLowerWallZ = cells(X, Y, Z + 1).Z_min;
    3741             :                         // on the Z=0 face, the only adiabatic cases are:
    3742             :                         //   1) for a non-zone-related simulation, such as for a standalone ground HX, or if we have the regular HasBasement
    3743             :                         //   simulation
    3744        1969 :                         if (((!this->HasZoneCoupledSlab) && (!this->HasZoneCoupledBasement))) {
    3745         535 :                             ThisAdiabaticMultiplier = 2.0;
    3746         535 :                             ThisAdiabaticMultiplierMirror = 0.0;
    3747             :                         }
    3748        1969 :                         this->addNeighborInformation(X,
    3749             :                                                      Y,
    3750             :                                                      Z,
    3751             :                                                      Direction::PositiveZ,
    3752        1969 :                                                      UpperZCellLowerWallZ - ThisCellCentroidZ,
    3753             :                                                      UpperZCellCentroidZ - UpperZCellLowerWallZ,
    3754             :                                                      ThisAdiabaticMultiplier);
    3755        1969 :                         this->addNeighborInformation(X, Y, Z, Direction::NegativeZ, 0.0, 0.0, ThisAdiabaticMultiplierMirror);
    3756       20081 :                     } else if (Z == this->z_max_index) {
    3757        1969 :                         LowerZCellCentroidZ = cells(X, Y, Z - 1).Centroid.Z;
    3758        1969 :                         LowerZCellUpperWallZ = cells(X, Y, Z - 1).Z_max;
    3759             :                         // on the Z=ZMAX face, the only adiabatic cases are:
    3760             :                         //   1) this face is always adiabatic?
    3761             :                         // if (  ) {
    3762        1969 :                         ThisAdiabaticMultiplier = 2.0;
    3763        1969 :                         ThisAdiabaticMultiplierMirror = 0.0;
    3764             :                         //}
    3765        1969 :                         this->addNeighborInformation(X,
    3766             :                                                      Y,
    3767             :                                                      Z,
    3768             :                                                      Direction::NegativeZ,
    3769        1969 :                                                      ThisCellCentroidZ - LowerZCellUpperWallZ,
    3770             :                                                      LowerZCellUpperWallZ - LowerZCellCentroidZ,
    3771             :                                                      ThisAdiabaticMultiplier);
    3772        1969 :                         this->addNeighborInformation(X, Y, Z, Direction::PositiveZ, 0.0, 0.0, ThisAdiabaticMultiplierMirror);
    3773             :                     } else {
    3774       18112 :                         LowerZCellCentroidZ = cells(X, Y, Z - 1).Centroid.Z;
    3775       18112 :                         UpperZCellCentroidZ = cells(X, Y, Z + 1).Centroid.Z;
    3776       18112 :                         UpperZCellLowerWallZ = cells(X, Y, Z + 1).Z_min;
    3777       18112 :                         LowerZCellUpperWallZ = cells(X, Y, Z - 1).Z_max;
    3778       18112 :                         this->addNeighborInformation(X,
    3779             :                                                      Y,
    3780             :                                                      Z,
    3781             :                                                      Direction::NegativeZ,
    3782       18112 :                                                      ThisCellCentroidZ - LowerZCellUpperWallZ,
    3783             :                                                      LowerZCellUpperWallZ - LowerZCellCentroidZ,
    3784             :                                                      ThisAdiabaticMultiplier);
    3785       18112 :                         this->addNeighborInformation(X,
    3786             :                                                      Y,
    3787             :                                                      Z,
    3788             :                                                      Direction::PositiveZ,
    3789       18112 :                                                      UpperZCellLowerWallZ - ThisCellCentroidZ,
    3790             :                                                      UpperZCellCentroidZ - UpperZCellLowerWallZ,
    3791             :                                                      ThisAdiabaticMultiplier);
    3792             :                     }
    3793             :                 }
    3794             :             }
    3795             :         }
    3796          11 :     }
    3797             : 
    3798      132300 :     void Domain::addNeighborInformation(int const X,
    3799             :                                         int const Y,
    3800             :                                         int const Z,
    3801             :                                         Direction const direction,
    3802             :                                         Real64 const ThisCentroidToNeighborWall,
    3803             :                                         Real64 const ThisWallToNeighborCentroid,
    3804             :                                         Real64 const ThisAdiabaticMultiplier)
    3805             :     {
    3806             :         // SUBROUTINE INFORMATION:
    3807             :         //       AUTHOR         Edwin Lee
    3808             :         //       DATE WRITTEN   Summer 2011
    3809             :         //       MODIFIED       na
    3810             :         //       RE-ENGINEERED  na
    3811      132300 :         auto &thisNeighborInfo = this->Cells(X, Y, Z).NeighborInfo[direction];
    3812      132300 :         thisNeighborInfo.direction = direction;
    3813      132300 :         thisNeighborInfo.ThisCentroidToNeighborWall = ThisCentroidToNeighborWall;
    3814      132300 :         thisNeighborInfo.ThisWallToNeighborCentroid = ThisWallToNeighborCentroid;
    3815      132300 :         thisNeighborInfo.adiabaticMultiplier = ThisAdiabaticMultiplier;
    3816      132300 :     }
    3817             : 
    3818          11 :     void Domain::setupPipeCircuitInOutCells()
    3819             :     {
    3820             : 
    3821             :         // SUBROUTINE INFORMATION:
    3822             :         //       AUTHOR         Edwin Lee
    3823             :         //       DATE WRITTEN   Summer 2011
    3824             :         //       MODIFIED       na
    3825             :         //       RE-ENGINEERED  na
    3826             : 
    3827          11 :         auto const &cells = this->Cells;
    3828          16 :         for (auto &thisCircuit : this->circuits) {
    3829             : 
    3830           5 :             int SegmentInletCellX = 0;
    3831           5 :             int SegmentInletCellY = 0;
    3832           5 :             int SegmentInletCellZ = 0;
    3833           5 :             int SegmentOutletCellX = 0;
    3834           5 :             int SegmentOutletCellY = 0;
    3835           5 :             int SegmentOutletCellZ = 0;
    3836           5 :             int CircuitInletCellX = 0;
    3837           5 :             int CircuitInletCellY = 0;
    3838           5 :             int CircuitInletCellZ = 0;
    3839           5 :             int CircuitOutletCellX = 0;
    3840           5 :             int CircuitOutletCellY = 0;
    3841           5 :             int CircuitOutletCellZ = 0;
    3842             : 
    3843           5 :             bool CircuitInletCellSet = false;
    3844             : 
    3845          19 :             for (auto &segment : thisCircuit->pipeSegments) {
    3846          14 :                 switch (segment->FlowDirection) {
    3847           7 :                 case SegmentFlow::IncreasingZ:
    3848           7 :                     SegmentInletCellX = segment->PipeCellCoordinates.X;
    3849           7 :                     SegmentInletCellY = segment->PipeCellCoordinates.Y;
    3850           7 :                     SegmentInletCellZ = 0;
    3851           7 :                     SegmentOutletCellX = segment->PipeCellCoordinates.X;
    3852           7 :                     SegmentOutletCellY = segment->PipeCellCoordinates.Y;
    3853           7 :                     SegmentOutletCellZ = this->z_max_index;
    3854           7 :                     break;
    3855           7 :                 case SegmentFlow::DecreasingZ:
    3856           7 :                     SegmentInletCellX = segment->PipeCellCoordinates.X;
    3857           7 :                     SegmentInletCellY = segment->PipeCellCoordinates.Y;
    3858           7 :                     SegmentInletCellZ = this->z_max_index;
    3859           7 :                     SegmentOutletCellX = segment->PipeCellCoordinates.X;
    3860           7 :                     SegmentOutletCellY = segment->PipeCellCoordinates.Y;
    3861           7 :                     SegmentOutletCellZ = 0;
    3862           7 :                     break;
    3863           0 :                 default:
    3864           0 :                     assert(false);
    3865             :                 }
    3866          14 :                 if (!CircuitInletCellSet) {
    3867           5 :                     CircuitInletCellX = SegmentInletCellX;
    3868           5 :                     CircuitInletCellY = SegmentInletCellY;
    3869           5 :                     CircuitInletCellZ = SegmentInletCellZ;
    3870           5 :                     CircuitInletCellSet = true;
    3871             :                 }
    3872          14 :                 CircuitOutletCellX = SegmentOutletCellX;
    3873          14 :                 CircuitOutletCellY = SegmentOutletCellY;
    3874          14 :                 CircuitOutletCellZ = SegmentOutletCellZ;
    3875           5 :             }
    3876             : 
    3877           5 :             thisCircuit->initInOutCells(cells(CircuitInletCellX, CircuitInletCellY, CircuitInletCellZ),
    3878             :                                         cells(CircuitOutletCellX, CircuitOutletCellY, CircuitOutletCellZ));
    3879          11 :         }
    3880          11 :     }
    3881             : 
    3882          47 :     int Domain::getCellWidthsCount(RegionType const dir) const
    3883             :     {
    3884             : 
    3885             :         // FUNCTION INFORMATION:
    3886             :         //       AUTHOR         Edwin Lee
    3887             :         //       DATE WRITTEN   Summer 2011
    3888             :         //       MODIFIED       na
    3889             :         //       RE-ENGINEERED  na
    3890             : 
    3891          47 :         if (dir == RegionType::XDirection) {
    3892          20 :             return this->Mesh.X.RegionMeshCount;
    3893          27 :         } else if (dir == RegionType::YDirection) {
    3894          20 :             return this->Mesh.Y.RegionMeshCount;
    3895           7 :         } else if (dir == RegionType::ZDirection) {
    3896           7 :             return this->Mesh.Z.RegionMeshCount;
    3897             :         } else {
    3898           0 :             return 1; // it's either a mesh region (X,Y,ZDirection), or it is some form of partition -- so 1
    3899             :         }
    3900             :         return 0;
    3901             :     }
    3902             : 
    3903         130 :     void Domain::getCellWidths(GridRegion &g, RegionType const direction) const
    3904             :     {
    3905             : 
    3906             :         // FUNCTION INFORMATION:
    3907             :         //       AUTHOR         Edwin Lee
    3908             :         //       DATE WRITTEN   Summer 2011
    3909             :         //       MODIFIED       na
    3910             :         //       RE-ENGINEERED  na
    3911             : 
    3912             :         // Object Data
    3913         130 :         DistributionStructure ThisMesh;
    3914         130 :         ThisMesh.RegionMeshCount = 0;
    3915         130 :         ThisMesh.GeometricSeriesCoefficient = 0.0;
    3916             : 
    3917         130 :         switch (direction) {
    3918          31 :         case RegionType::XDirection:
    3919          31 :             ThisMesh = this->Mesh.X;
    3920          31 :             break;
    3921          31 :         case RegionType::YDirection:
    3922          31 :             ThisMesh = this->Mesh.Y;
    3923          31 :             break;
    3924          18 :         case RegionType::ZDirection:
    3925          18 :             ThisMesh = this->Mesh.Z;
    3926          18 :             break;
    3927          50 :         default:
    3928          50 :             ThisMesh.RegionMeshCount = 1; // it must be a partition type or something
    3929          50 :             ThisMesh.thisMeshDistribution = MeshDistribution::Uniform;
    3930             :             // ShowSevereError(state,  "Invalid RegionType passed to PlantPipingSystems::Domain::getCellWidths; should be x, y, or z
    3931             :             // direction only." );  ShowContinueError(state,  "This is a developer problem, as the code should never reach this point." );
    3932             :             // ShowFatalError(state, "EnergyPlus aborts due to the previous severe error" );
    3933             :         }
    3934             : 
    3935             :         // just one cell for extremely tight regions
    3936         130 :         if ((g.Max - g.Min) < 0.00001) {
    3937           0 :             ThisMesh.RegionMeshCount = 1;
    3938           0 :             ThisMesh.thisMeshDistribution = MeshDistribution::Uniform;
    3939             :         }
    3940         130 :         assert(g.Max > g.Min);
    3941             : 
    3942         130 :         Real64 GridWidth = g.Max - g.Min;
    3943             : 
    3944         130 :         if (ThisMesh.thisMeshDistribution == MeshDistribution::Uniform) {
    3945          96 :             if (this->HasZoneCoupledSlab && g.thisRegionType == RegionType::YDirection && g.Max == this->Extents.yMax) { // Slab region
    3946           0 :                 Real64 const CellWidth = GridWidth / this->NumSlabCells;
    3947           0 :                 for (int I = 0; I <= this->NumSlabCells - 1; ++I) {
    3948           0 :                     g.CellWidths.push_back(CellWidth);
    3949             :                 }
    3950           0 :             } else {
    3951             :                 // we have it quite simple
    3952          96 :                 assert(ThisMesh.RegionMeshCount > 0);
    3953          96 :                 Real64 const CellWidth = GridWidth / ThisMesh.RegionMeshCount;
    3954         284 :                 for (int I = 0; I <= ThisMesh.RegionMeshCount - 1; ++I) {
    3955         188 :                     g.CellWidths.push_back(CellWidth);
    3956             :                 }
    3957             :             }
    3958          34 :         } else if (ThisMesh.thisMeshDistribution == MeshDistribution::SymmetricGeometric) {
    3959             : 
    3960             :             //'then apply this "direction"'s conditions to generate a cell width array
    3961             :             //'first get the total number of cells on this half of the region
    3962          34 :             int NumCellsOnEachSide = ThisMesh.RegionMeshCount / 2; // Already validated to be an even #
    3963             :             //'calculate geometric series
    3964          34 :             Real64 SummationTerm = 0.0;
    3965         136 :             for (int I = 1; I <= NumCellsOnEachSide; ++I) {
    3966         102 :                 SummationTerm += std::pow(ThisMesh.GeometricSeriesCoefficient, I - 1);
    3967             :             }
    3968             :             //'set up a list of cell widths for this region
    3969          34 :             Real64 CellWidth = (GridWidth / 2) / SummationTerm;
    3970          34 :             g.CellWidths.push_back(CellWidth);
    3971         102 :             for (int I = 1; I <= NumCellsOnEachSide - 1; ++I) {
    3972          68 :                 CellWidth *= ThisMesh.GeometricSeriesCoefficient;
    3973          68 :                 g.CellWidths.push_back(CellWidth);
    3974             :             }
    3975         136 :             for (int I = NumCellsOnEachSide - 1; I >= 0; --I) {
    3976         102 :                 g.CellWidths.push_back(g.CellWidths[I]);
    3977             :             }
    3978             : 
    3979           0 :         } else if (ThisMesh.thisMeshDistribution == MeshDistribution::Geometric) {
    3980             : 
    3981           0 :             int NumCells = ThisMesh.RegionMeshCount;
    3982           0 :             if (g.thisRegionType == RegionType::XDirection || g.thisRegionType == RegionType::ZDirection) {
    3983             :                 //'calculate geometric series
    3984           0 :                 Real64 SummationTerm = 0.0;
    3985           0 :                 for (int I = 1; I <= NumCells; ++I) {
    3986           0 :                     SummationTerm += std::pow(ThisMesh.GeometricSeriesCoefficient, I - 1);
    3987             :                 }
    3988           0 :                 Real64 CellWidth = GridWidth / SummationTerm;
    3989           0 :                 if (g.Min == 0) {
    3990             :                     // Ground region to the left of the slab will have cells expanding to the left
    3991             :                     // adding them here moving forward, then reversing it to get this effect
    3992             :                     // Possible spot for diffs
    3993           0 :                     g.CellWidths.push_back(CellWidth);
    3994           0 :                     for (int I = 0; I < NumCells; ++I) {
    3995           0 :                         CellWidth *= ThisMesh.GeometricSeriesCoefficient;
    3996           0 :                         g.CellWidths.push_back(CellWidth);
    3997             :                     }
    3998           0 :                     std::reverse(g.CellWidths.begin(), g.CellWidths.end());
    3999             :                 } else {
    4000             :                     // Slab region will have cells expanding to the right
    4001           0 :                     g.CellWidths.push_back(CellWidth);
    4002           0 :                     for (int I = 1; I <= NumCells - 1; ++I) {
    4003           0 :                         CellWidth *= ThisMesh.GeometricSeriesCoefficient;
    4004           0 :                         g.CellWidths.push_back(CellWidth);
    4005             :                     }
    4006             :                 }
    4007           0 :             } else if (g.thisRegionType == RegionType::YDirection) {
    4008             :                 // Assign uniform cell thickness to the slab cells.
    4009           0 :                 if (g.Max == this->Extents.yMax) {
    4010           0 :                     NumCells = this->NumSlabCells;
    4011           0 :                     Real64 CellWidth = GridWidth / NumCells;
    4012           0 :                     for (int I = 0; I <= NumCells - 1; ++I) {
    4013           0 :                         g.CellWidths.push_back(CellWidth);
    4014             :                     }
    4015             :                 } else {
    4016             :                     //'calculate geometric series
    4017           0 :                     Real64 SummationTerm = 0.0;
    4018           0 :                     for (int I = 1; I <= NumCells; ++I) {
    4019           0 :                         SummationTerm += std::pow(ThisMesh.GeometricSeriesCoefficient, I - 1);
    4020             :                     }
    4021           0 :                     Real64 CellWidth = GridWidth / SummationTerm;
    4022             :                     // Ground region under the slab will have cells expanding as we go down
    4023             :                     // adding them here moving forward, then reversing it to get this effect
    4024             :                     // Possible spot for diffs
    4025           0 :                     g.CellWidths.push_back(CellWidth);
    4026           0 :                     for (int I = 1; I < NumCells; ++I) {
    4027           0 :                         CellWidth *= ThisMesh.GeometricSeriesCoefficient;
    4028           0 :                         g.CellWidths.push_back(CellWidth);
    4029             :                     }
    4030           0 :                     std::reverse(g.CellWidths.begin(), g.CellWidths.end());
    4031             :                 }
    4032             :             }
    4033             :         }
    4034         130 :     }
    4035             : 
    4036       13440 :     void Domain::PerformIterationLoop(EnergyPlusData &state)
    4037             :     {
    4038             : 
    4039             :         // SUBROUTINE INFORMATION:
    4040             :         //       AUTHOR         Edwin Lee
    4041             :         //       DATE WRITTEN   Summer 2011
    4042             :         //       MODIFIED       na
    4043             :         //       RE-ENGINEERED  na
    4044             : 
    4045             :         // Always do start of time step inits
    4046       13440 :         this->DoStartOfTimeStepInitializations(state);
    4047             : 
    4048             :         // Begin iterating for this time step
    4049       74861 :         for (int IterationIndex = 1; IterationIndex <= this->SimControls.MaxIterationsPerTS; ++IterationIndex) {
    4050       74861 :             this->ShiftTemperaturesForNewIteration();
    4051       74861 :             if (this->DomainNeedsSimulation) this->PerformTemperatureFieldUpdate(state);
    4052       74861 :             bool FinishedIterationLoop = false;
    4053       74861 :             this->DoEndOfIterationOperations(state, FinishedIterationLoop);
    4054       74861 :             if (FinishedIterationLoop) break;
    4055             :         }
    4056             : 
    4057             :         // Update the basement surface temperatures, if any
    4058       13440 :         if (this->HasBasement || this->HasZoneCoupledBasement) {
    4059        2784 :             this->UpdateBasementSurfaceTemperatures(state);
    4060             :         }
    4061             : 
    4062             :         // Update the slab surface temperatures, if any
    4063       13440 :         if (this->HasZoneCoupledSlab) {
    4064       10656 :             this->UpdateZoneSurfaceTemperatures(state);
    4065             :         }
    4066       13440 :     }
    4067             : 
    4068       14502 :     void Domain::PerformIterationLoop(EnergyPlusData &state, Circuit *thisCircuit)
    4069             :     {
    4070             : 
    4071             :         // SUBROUTINE INFORMATION:
    4072             :         //       AUTHOR         Edwin Lee
    4073             :         //       DATE WRITTEN   Summer 2011
    4074             :         //       MODIFIED       na
    4075             :         //       RE-ENGINEERED  na
    4076             : 
    4077             :         // Always do start of time step inits
    4078       14502 :         this->DoStartOfTimeStepInitializations(state, thisCircuit);
    4079             : 
    4080             :         // Prepare the pipe circuit for calculations, but we'll actually do calcs at the iteration level
    4081       14502 :         if (this->HasAPipeCircuit) {
    4082       14502 :             this->PreparePipeCircuitSimulation(thisCircuit);
    4083             :         }
    4084             : 
    4085             :         // Begin iterating for this time step
    4086       50655 :         for (int IterationIndex = 1; IterationIndex <= this->SimControls.MaxIterationsPerTS; ++IterationIndex) {
    4087             : 
    4088       50655 :             this->ShiftTemperaturesForNewIteration();
    4089             : 
    4090       50655 :             if (this->HasAPipeCircuit) {
    4091       50655 :                 this->PerformPipeCircuitSimulation(state, thisCircuit);
    4092             :             }
    4093             : 
    4094       50655 :             if (this->DomainNeedsSimulation) this->PerformTemperatureFieldUpdate(state);
    4095       50655 :             bool FinishedIterationLoop = false;
    4096       50655 :             this->DoEndOfIterationOperations(state, FinishedIterationLoop);
    4097             : 
    4098       50655 :             if (FinishedIterationLoop) break;
    4099             :         }
    4100             : 
    4101             :         // Update the basement surface temperatures, if any
    4102       14502 :         if (this->HasBasement || this->HasZoneCoupledBasement) {
    4103       10982 :             this->UpdateBasementSurfaceTemperatures(state);
    4104             :         }
    4105             : 
    4106             :         // Update the slab surface temperatures, if any
    4107       14502 :         if (this->HasZoneCoupledSlab) {
    4108           0 :             this->UpdateZoneSurfaceTemperatures(state);
    4109             :         }
    4110       14502 :     }
    4111             : 
    4112      125516 :     void Domain::PerformTemperatureFieldUpdate(EnergyPlusData &state)
    4113             :     {
    4114             : 
    4115             :         // SUBROUTINE INFORMATION:
    4116             :         //       AUTHOR         Edwin Lee
    4117             :         //       DATE WRITTEN   Summer 2011
    4118             :         //       MODIFIED       na
    4119             :         //       RE-ENGINEERED  na
    4120             : 
    4121     1836285 :         for (int X = 0, X_end = this->x_max_index; X <= X_end; ++X) {
    4122    30193343 :             for (int Y = 0, Y_end = this->y_max_index; Y <= Y_end; ++Y) {
    4123   329423232 :                 for (int Z = 0, Z_end = this->z_max_index; Z <= Z_end; ++Z) {
    4124   300940658 :                     auto &cell = this->Cells(X, Y, Z);
    4125             : 
    4126   300940658 :                     switch (cell.cellType) {
    4127     1394912 :                     case CellType::Pipe:
    4128             :                         //'pipes are simulated separately
    4129     1394912 :                         break;
    4130   200195517 :                     case CellType::GeneralField:
    4131             :                     case CellType::Slab:
    4132             :                     case CellType::HorizInsulation:
    4133             :                     case CellType::VertInsulation:
    4134   200195517 :                         cell.Temperature = this->EvaluateFieldCellTemperature(cell);
    4135   200195517 :                         break;
    4136    10887544 :                     case CellType::GroundSurface:
    4137    10887544 :                         cell.Temperature = this->EvaluateGroundSurfaceTemperature(state, cell);
    4138    10887544 :                         break;
    4139    67286657 :                     case CellType::FarfieldBoundary:
    4140    67286657 :                         cell.Temperature = this->EvaluateFarfieldBoundaryTemperature(state, cell);
    4141    67286657 :                         break;
    4142     5856147 :                     case CellType::BasementWall:
    4143             :                     case CellType::BasementCorner:
    4144             :                     case CellType::BasementFloor:
    4145             :                         // basement model, zone-coupled. Call EvaluateZoneInterfaceTemperature routine to handle timestep/hourly simulation.
    4146     5856147 :                         if (this->HasZoneCoupledBasement) {
    4147     2473011 :                             cell.Temperature = this->EvaluateZoneInterfaceTemperature(cell);
    4148             :                         } else { // FHX model
    4149     3383136 :                             cell.Temperature = this->EvaluateBasementCellTemperature(state, cell);
    4150             :                         }
    4151     5856147 :                         break;
    4152     2328624 :                     case CellType::ZoneGroundInterface:
    4153     2328624 :                         cell.Temperature = this->EvaluateZoneInterfaceTemperature(cell);
    4154     2328624 :                         break;
    4155    12991257 :                     case CellType::BasementCutaway:
    4156             :                         // it's ok to not simulate this one
    4157    12991257 :                         break;
    4158           0 :                     default:
    4159           0 :                         assert(false);
    4160             :                     }
    4161             :                 }
    4162             :             }
    4163             :         }
    4164      125516 :     }
    4165             : 
    4166   200195517 :     Real64 Domain::EvaluateFieldCellTemperature(CartesianCell &cell)
    4167             :     {
    4168             : 
    4169             :         // FUNCTION INFORMATION:
    4170             :         //       AUTHOR         Edwin Lee
    4171             :         //       DATE WRITTEN   Summer 2011
    4172             :         //       MODIFIED       na
    4173             :         //       RE-ENGINEERED  na
    4174             : 
    4175             :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    4176   200195517 :         Real64 Numerator = 0.0;
    4177   200195517 :         Real64 Denominator = 0.0;
    4178   200195517 :         Real64 AdiabaticMultiplier = 1.0;
    4179             : 
    4180             :         // add effect from cell history
    4181   200195517 :         Numerator += cell.Temperature_PrevTimeStep;
    4182   200195517 :         ++Denominator;
    4183             : 
    4184             :         // determine the neighbor types based on cell location
    4185   200195517 :         int NumFieldCells = 0, NumBoundaryCells = 0;
    4186   200195517 :         this->EvaluateCellNeighborDirections(cell, NumFieldCells, NumBoundaryCells);
    4187             : 
    4188             :         // loop across each direction in the simulation
    4189  1372395073 :         for (int DirectionCounter = 0; DirectionCounter <= NumFieldCells; ++DirectionCounter) {
    4190             : 
    4191  1172199556 :             Real64 NeighborTemp = 0.0;
    4192  1172199556 :             Real64 Resistance = 0.0;
    4193  1172199556 :             Direction CurDirection = this->NeighborFieldCells[DirectionCounter];
    4194             : 
    4195             :             //'evaluate the transient expression terms
    4196  1172199556 :             this->EvaluateNeighborCharacteristics(cell, CurDirection, NeighborTemp, Resistance, AdiabaticMultiplier);
    4197             : 
    4198  1172199556 :             Numerator += AdiabaticMultiplier * (cell.Beta / Resistance) * NeighborTemp;
    4199  1172199556 :             Denominator += AdiabaticMultiplier * (cell.Beta / Resistance);
    4200             :         }
    4201             : 
    4202             :         //'now that we have passed all directions, update the temperature
    4203   200195517 :         return Numerator / Denominator;
    4204             :     }
    4205             : 
    4206    10887544 :     Real64 Domain::EvaluateGroundSurfaceTemperature(EnergyPlusData &state, CartesianCell &cell)
    4207             :     {
    4208             : 
    4209             :         // FUNCTION INFORMATION:
    4210             :         //       AUTHOR         Edwin Lee
    4211             :         //       DATE WRITTEN   Summer 2011
    4212             :         //       MODIFIED       na
    4213             :         //       RE-ENGINEERED  na
    4214             : 
    4215             :         // FUNCTION PARAMETER DEFINITIONS:
    4216    10887544 :         Real64 constexpr AirDensity(1.22521);   // '[kg/m3]
    4217    10887544 :         Real64 constexpr AirSpecificHeat(1003); // '[J/kg-K]
    4218             :         // evapotranspiration parameters
    4219    10887544 :         Real64 constexpr MeanSolarConstant(0.08196); // 1367 [W/m2], entered in [MJ/m2-minute]
    4220    10887544 :         Real64 constexpr A_s(0.25);                  // ?
    4221    10887544 :         Real64 constexpr B_s(0.5);                   // ?
    4222    10887544 :         Real64 constexpr Absor_Corrected(0.77);
    4223    10887544 :         Real64 const Convert_Wm2_To_MJhrmin(3600.0 / 1000000.0);
    4224    10887544 :         Real64 const Convert_MJhrmin_To_Wm2(1.0 / Convert_Wm2_To_MJhrmin);
    4225    10887544 :         Real64 constexpr Rho_water(998.0); // [kg/m3]
    4226             : 
    4227             :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    4228    10887544 :         Real64 NeighborTemp = 0.0;
    4229             :         Real64 IncidentHeatGain;
    4230             :         Real64 Latitude_Degrees;   // Latitude, degrees N
    4231             :         Real64 StMeridian_Degrees; // Standard meridian, degrees W -- note it is degrees E in DataEnvironment
    4232             :         Real64 Longitude_Degrees;  // Longitude, degrees W -- note it is degrees E in DataEnvironment
    4233             :         // evapotranspiration calculated values
    4234             :         Real64 Latitude_Radians;
    4235             :         Real64 DayOfYear;
    4236             :         Real64 HourOfDay;
    4237             :         Real64 CurSecondsIntoToday;
    4238             :         Real64 dr;
    4239             :         Real64 Declination;
    4240             :         Real64 b_SC;
    4241             :         Real64 Sc;
    4242             :         Real64 Hour_Angle;
    4243             :         Real64 X_sunset;
    4244             :         Real64 Sunset_Angle;
    4245             :         Real64 Solar_Angle_1;
    4246             :         Real64 Solar_Angle_2;
    4247             :         Real64 QRAD_A;
    4248             :         Real64 QRAD_SO;
    4249             :         Real64 Ratio_SO;
    4250             :         Real64 IncidentSolar_MJhrmin;
    4251             :         Real64 AbsorbedIncidentSolar_MJhrmin;
    4252             :         Real64 VaporPressureSaturated_kPa;
    4253             :         Real64 VaporPressureActual_kPa;
    4254             :         Real64 QRAD_NL;
    4255             :         Real64 NetIncidentRadiation_MJhr; // [MJ/hr]
    4256             :         Real64 NetIncidentRadiation_Wm2;  // [W/m2]
    4257             :         Real64 CN;
    4258             :         Real64 G_hr;
    4259             :         Real64 Cd;
    4260             :         Real64 Slope_S;
    4261             :         Real64 Pressure;
    4262             :         Real64 PsychrometricConstant;
    4263             :         Real64 EvapotransFluidLoss_mmhr;
    4264             :         Real64 EvapotransFluidLoss_mhr;
    4265             :         Real64 LatentHeatVaporization;
    4266             :         Real64 EvapotransHeatLoss_MJhrmin; // [MJ/m2-hr]
    4267             :         Real64 EvapotransHeatLoss_Wm2;     // [W/m2]
    4268             :         Real64 CurAirTempK;
    4269             :         Real64 GroundCoverCoefficient;
    4270             : 
    4271             :         // retrieve information from E+ globals
    4272    10887544 :         Latitude_Degrees = state.dataEnvrn->Latitude;
    4273    10887544 :         StMeridian_Degrees = -state.dataEnvrn->TimeZoneMeridian; // Standard meridian, degrees W
    4274    10887544 :         Longitude_Degrees = -state.dataEnvrn->Longitude;         // Longitude, degrees W
    4275             : 
    4276             :         // retrieve any information from input data structure
    4277    10887544 :         GroundCoverCoefficient = this->Moisture.GroundCoverCoefficient;
    4278             : 
    4279             :         // initialize values
    4280    10887544 :         Real64 AdiabaticMultiplier = 1.0;
    4281    10887544 :         Real64 Numerator = 0.0;
    4282    10887544 :         Real64 Denominator = 0.0;
    4283    10887544 :         Real64 Resistance = 0.0;
    4284    10887544 :         Real64 Beta = cell.Beta;
    4285    10887544 :         Real64 ThisNormalArea = cell.normalArea(Direction::PositiveY);
    4286             : 
    4287             :         //'add effect from previous time step
    4288    10887544 :         Numerator += cell.Temperature_PrevTimeStep;
    4289    10887544 :         ++Denominator;
    4290             : 
    4291             :         // now that we aren't infinitesimal, we need to determine the neighbor types based on cell location
    4292    10887544 :         int NumFieldCells = 0, NumBoundaryCells = 0;
    4293    10887544 :         this->EvaluateCellNeighborDirections(cell, NumFieldCells, NumBoundaryCells);
    4294             : 
    4295             :         // loop over all regular neighbor cells, check if we have adiabatic on opposite surface
    4296    62656390 :         for (int DirectionCounter = 0; DirectionCounter <= NumFieldCells; ++DirectionCounter) {
    4297    51768846 :             Direction CurDirection = this->NeighborFieldCells[DirectionCounter];
    4298             : 
    4299             :             // Use the multiplier ( either 1 or 2 ) to calculate the neighbor cell effects
    4300    51768846 :             this->EvaluateNeighborCharacteristics(cell, CurDirection, NeighborTemp, Resistance, AdiabaticMultiplier);
    4301    51768846 :             Numerator = AdiabaticMultiplier * Numerator + (Beta / Resistance) * NeighborTemp;
    4302    51768846 :             Denominator = AdiabaticMultiplier * Denominator + (Beta / Resistance);
    4303             :         }
    4304             : 
    4305             :         // do all non-adiabatic boundary types here
    4306    24443962 :         for (int DirectionCounter = 0; DirectionCounter <= NumBoundaryCells; ++DirectionCounter) {
    4307    13556418 :             Direction CurDirection = this->NeighborBoundaryCells[DirectionCounter];
    4308             : 
    4309             :             // For Zone-coupled slab or basement configuration
    4310    13556418 :             if (this->HasZoneCoupledSlab || this->HasZoneCoupledBasement) {
    4311             :                 //-x-direction will always be a farfield boundary
    4312             :                 //-z will also be a farfield boundary
    4313             :                 //+x and +z will be handled above
    4314             :                 //-y will always be a neighbor cell, so it is handled above
    4315             :                 //+y will always be the outdoor air
    4316     8277662 :                 if (CurDirection == Direction::NegativeX || CurDirection == Direction::NegativeZ) {
    4317             :                     // always farfield
    4318      305310 :                     this->EvaluateFarfieldCharacteristics(state, cell, CurDirection, NeighborTemp, Resistance, AdiabaticMultiplier);
    4319      305310 :                     Numerator += (Beta / Resistance) * NeighborTemp;
    4320      305310 :                     Denominator += (Beta / Resistance);
    4321     7972352 :                 } else if (CurDirection == Direction::PositiveY) {
    4322             :                     // convection at the surface
    4323     7244096 :                     if (state.dataEnvrn->WindSpeed > 0.1) {
    4324     7244096 :                         Resistance = 208.0 / (AirDensity * AirSpecificHeat * state.dataEnvrn->WindSpeed * ThisNormalArea);
    4325     7244096 :                         Numerator += (Beta / Resistance) * this->Cur.CurAirTemp;
    4326     7244096 :                         Denominator += (Beta / Resistance);
    4327             :                     }
    4328      728256 :                 } else if (CurDirection == Direction::NegativeY) {
    4329           0 :                     assert(false); // debug error, can't get here!
    4330             :                 }
    4331             :             } else { // FHX model
    4332             :                 // x-direction will always be a farfield boundary
    4333             :                 // z-direction will be handled above -- adiabatic
    4334             :                 //-y we don't handle here because -y will always be a neighbor cell, so handled above
    4335             :                 //+y will always be the outdoor air
    4336     5278756 :                 if ((CurDirection == Direction::PositiveX) || (CurDirection == Direction::NegativeX)) {
    4337             :                     // always farfield
    4338      399872 :                     this->EvaluateFarfieldCharacteristics(state, cell, CurDirection, NeighborTemp, Resistance, AdiabaticMultiplier);
    4339      399872 :                     Numerator += (Beta / Resistance) * NeighborTemp;
    4340      399872 :                     Denominator += (Beta / Resistance);
    4341     4878884 :                 } else if ((CurDirection == Direction::PositiveZ) || (CurDirection == Direction::NegativeZ)) {
    4342             :                     // debug error, can't get here
    4343     3643448 :                 } else if (CurDirection == Direction::PositiveY) {
    4344             :                     // convection at the surface
    4345     3643448 :                     if (state.dataEnvrn->WindSpeed > 0.1) {
    4346     3589888 :                         Resistance = 208.0 / (AirDensity * AirSpecificHeat * state.dataEnvrn->WindSpeed * ThisNormalArea);
    4347     3589888 :                         Numerator += (Beta / Resistance) * this->Cur.CurAirTemp;
    4348     3589888 :                         Denominator += (Beta / Resistance);
    4349             :                     } else {
    4350             :                         // Future development should include additional natural convection effects here
    4351             :                     }
    4352           0 :                 } else if (CurDirection == Direction::NegativeY) {
    4353           0 :                     assert(false); // debug error, can't get here!
    4354             :                 }
    4355             :             }
    4356             :         }
    4357             : 
    4358             :         // Latitude, converted to radians...positive for northern hemisphere, [radians]
    4359    10887544 :         Latitude_Radians = Constant::Pi / 180.0 * Latitude_Degrees;
    4360             : 
    4361             :         // The day of year at this point in the simulation
    4362    10887544 :         DayOfYear = int(this->Cur.CurSimTimeSeconds / Constant::SecsInDay);
    4363             : 
    4364             :         // The number of seconds into the current day
    4365    10887544 :         CurSecondsIntoToday = int(mod(this->Cur.CurSimTimeSeconds, Constant::SecsInDay));
    4366             : 
    4367             :         // The number of hours into today
    4368    10887544 :         HourOfDay = int(CurSecondsIntoToday / Constant::SecInHour);
    4369             : 
    4370             :         // For convenience convert to Kelvin once
    4371    10887544 :         CurAirTempK = this->Cur.CurAirTemp + 273.15;
    4372             : 
    4373             :         // Calculate some angles
    4374    10887544 :         dr = 1.0 + 0.033 * std::cos(2.0 * Constant::Pi * DayOfYear / 365.0);
    4375    10887544 :         Declination = 0.409 * std::sin(2.0 * Constant::Pi / 365.0 * DayOfYear - 1.39);
    4376    10887544 :         b_SC = 2.0 * Constant::Pi * (DayOfYear - 81.0) / 364.0;
    4377    10887544 :         Sc = 0.1645 * std::sin(2.0 * b_SC) - 0.1255 * std::cos(b_SC) - 0.025 * std::sin(b_SC);
    4378    10887544 :         Hour_Angle = Constant::Pi / 12.0 * (((HourOfDay - 0.5) + 0.06667 * (StMeridian_Degrees - Longitude_Degrees) + Sc) - 12.0);
    4379             : 
    4380             :         // Calculate sunset something, and constrain to a minimum of 0.000001
    4381    10887544 :         X_sunset = 1.0 - pow_2(std::tan(Latitude_Radians)) * pow_2(std::tan(Declination));
    4382    10887544 :         X_sunset = max(X_sunset, 0.000001);
    4383             : 
    4384             :         // Find sunset angle
    4385    10887544 :         Sunset_Angle = Constant::Pi / 2.0 - std::atan(-std::tan(Latitude_Radians) * std::tan(Declination) / std::sqrt(X_sunset));
    4386             : 
    4387             :         // Find solar angles
    4388    10887544 :         Solar_Angle_1 = Hour_Angle - Constant::Pi / 24.0;
    4389    10887544 :         Solar_Angle_2 = Hour_Angle + Constant::Pi / 24.0;
    4390             : 
    4391             :         // Constrain solar angles
    4392    10887544 :         if (Solar_Angle_1 < -Sunset_Angle) Solar_Angle_1 = -Sunset_Angle;
    4393    10887544 :         if (Solar_Angle_2 < -Sunset_Angle) Solar_Angle_2 = -Sunset_Angle;
    4394    10887544 :         if (Solar_Angle_1 > Sunset_Angle) Solar_Angle_1 = Sunset_Angle;
    4395    10887544 :         if (Solar_Angle_2 > Sunset_Angle) Solar_Angle_2 = Sunset_Angle;
    4396    10887544 :         if (Solar_Angle_1 > Solar_Angle_2) Solar_Angle_1 = Solar_Angle_2;
    4397             : 
    4398             :         // Convert input solar radiation [w/m2] into units for ET model, [MJ/hr-min]
    4399    10887544 :         IncidentSolar_MJhrmin = this->Cur.CurIncidentSolar * Convert_Wm2_To_MJhrmin;
    4400             : 
    4401             :         // Calculate another Q term...
    4402    10887544 :         QRAD_A = 12.0 * 60.0 / Constant::Pi * MeanSolarConstant * dr *
    4403    10887544 :                  ((Solar_Angle_2 - Solar_Angle_1) * std::sin(Latitude_Radians) * std::sin(Declination) +
    4404    10887544 :                   std::cos(Latitude_Radians) * std::cos(Declination) * (std::sin(Solar_Angle_2) - std::sin(Solar_Angle_1)));
    4405             : 
    4406             :         // Calculate another Q term...
    4407    10887544 :         QRAD_SO = (A_s + B_s + 0.00002 * state.dataEnvrn->Elevation) * QRAD_A;
    4408             : 
    4409             :         // Correct the Qrad term ... better way??
    4410    10887544 :         if (IncidentSolar_MJhrmin < 0.01) {
    4411     7155069 :             Ratio_SO = 0.0;
    4412             :         } else {
    4413     3732475 :             if (QRAD_SO != 0.0) {
    4414     2110583 :                 Ratio_SO = IncidentSolar_MJhrmin / QRAD_SO;
    4415             :             } else {
    4416             :                 // I used logic below to choose value, divide by 0 = infinity, so value = 1, not sure if correct...
    4417     1621892 :                 Ratio_SO = 1.0;
    4418             :             }
    4419             :         }
    4420             : 
    4421             :         // Constrain Ratio_SO
    4422    10887544 :         Ratio_SO = min(Ratio_SO, 1.0);
    4423    10887544 :         Ratio_SO = max(Ratio_SO, 0.3);
    4424             : 
    4425             :         // Calculate another Q term, [MJ/hr-min]
    4426    10887544 :         AbsorbedIncidentSolar_MJhrmin = Absor_Corrected * IncidentSolar_MJhrmin;
    4427             : 
    4428             :         // Calculate saturated vapor pressure, [kPa]
    4429    10887544 :         VaporPressureSaturated_kPa = 0.6108 * std::exp(17.27 * this->Cur.CurAirTemp / (this->Cur.CurAirTemp + 237.3));
    4430             : 
    4431             :         // Calculate actual vapor pressure, [kPa]
    4432    10887544 :         VaporPressureActual_kPa = VaporPressureSaturated_kPa * this->Cur.CurRelativeHumidity / 100.0;
    4433             : 
    4434             :         // Calculate another Q term, [MJ/m2-hr]
    4435    10887544 :         QRAD_NL = 2.042E-10 * pow_4(CurAirTempK) * (0.34 - 0.14 * std::sqrt(VaporPressureActual_kPa)) * (1.35 * Ratio_SO - 0.35);
    4436             : 
    4437             :         // Calculate another Q term, [MJ/hr]
    4438    10887544 :         NetIncidentRadiation_MJhr = AbsorbedIncidentSolar_MJhrmin - QRAD_NL;
    4439             : 
    4440             :         // ?
    4441    10887544 :         CN = 37.0;
    4442             : 
    4443             :         // Check whether there was sun
    4444    10887544 :         if (NetIncidentRadiation_MJhr < 0.0) {
    4445     7550045 :             G_hr = 0.5 * NetIncidentRadiation_MJhr;
    4446     7550045 :             Cd = 0.96;
    4447             :         } else {
    4448     3337499 :             G_hr = 0.1 * NetIncidentRadiation_MJhr;
    4449     3337499 :             Cd = 0.24;
    4450             :         }
    4451             : 
    4452             :         // Just For Check
    4453             :         // Lu Xing Sep 22 2009
    4454             : 
    4455    10887544 :         Slope_S = 2503.0 * std::exp(17.27 * this->Cur.CurAirTemp / (this->Cur.CurAirTemp + 237.3)) / pow_2(this->Cur.CurAirTemp + 237.3);
    4456    10887544 :         Pressure = 98.0;
    4457    10887544 :         PsychrometricConstant = 0.665e-3 * Pressure;
    4458             : 
    4459             :         // Evapotranspiration constant, [mm/hr]
    4460    10887544 :         EvapotransFluidLoss_mmhr =
    4461    10887544 :             (GroundCoverCoefficient * Slope_S * (NetIncidentRadiation_MJhr - G_hr) +
    4462    10887544 :              PsychrometricConstant * (CN / CurAirTempK) * this->Cur.CurWindSpeed * (VaporPressureSaturated_kPa - VaporPressureActual_kPa)) /
    4463    10887544 :             (Slope_S + PsychrometricConstant * (1 + Cd * this->Cur.CurWindSpeed));
    4464             : 
    4465             :         // Convert units, [m/hr]
    4466    10887544 :         EvapotransFluidLoss_mhr = EvapotransFluidLoss_mmhr / 1000.0;
    4467             : 
    4468             :         // Calculate latent heat, [MJ/kg]
    4469             :         // Full formulation is cubic: L(T) = -0.0000614342 * T**3 + 0.00158927 * T**2 - 2.36418 * T + 2500.79[5]
    4470             :         // In: Cubic fit to Table 2.1,p.16, Textbook: R.R.Rogers & M.K. Yau, A Short Course in Cloud Physics, 3e,(1989), Pergamon press
    4471             :         // But a linear relation should suffice;
    4472             :         // note-for now using the previous time step temperature as an approximation to help ensure stability
    4473    10887544 :         LatentHeatVaporization = 2.501 - 2.361e-3 * cell.Temperature_PrevTimeStep;
    4474             : 
    4475             :         // Calculate evapotranspiration heat loss, [MJ/m2-hr]
    4476    10887544 :         EvapotransHeatLoss_MJhrmin = Rho_water * EvapotransFluidLoss_mhr * LatentHeatVaporization;
    4477             : 
    4478             :         // Convert net incident solar units, [W/m2]
    4479    10887544 :         NetIncidentRadiation_Wm2 = NetIncidentRadiation_MJhr * Convert_MJhrmin_To_Wm2;
    4480             : 
    4481             :         // Convert evapotranspiration units, [W/m2]
    4482    10887544 :         EvapotransHeatLoss_Wm2 = EvapotransHeatLoss_MJhrmin * Convert_MJhrmin_To_Wm2;
    4483             : 
    4484             :         // Calculate overall net heat ?gain? into the cell, [W]
    4485    10887544 :         IncidentHeatGain = (NetIncidentRadiation_Wm2 - EvapotransHeatLoss_Wm2) * ThisNormalArea;
    4486             : 
    4487             :         // Add any solar/evapotranspiration heat gain here
    4488    10887544 :         Numerator += Beta * IncidentHeatGain;
    4489             : 
    4490             :         // Calculate the return temperature and leave
    4491    10887544 :         return Numerator / Denominator;
    4492             :     }
    4493             : 
    4494     3383136 :     Real64 Domain::EvaluateBasementCellTemperature(EnergyPlusData &state, CartesianCell &cell)
    4495             :     {
    4496             : 
    4497             :         // FUNCTION INFORMATION:
    4498             :         //       AUTHOR         Edwin Lee
    4499             :         //       DATE WRITTEN   Summer 2011
    4500             :         //       MODIFIED       na
    4501             :         //       RE-ENGINEERED  na
    4502             : 
    4503             :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    4504             :         Real64 Beta;
    4505     3383136 :         Real64 NeighborTemp = 0.0;
    4506             :         Real64 HeatFlux;
    4507     3383136 :         Real64 Numerator = 0.0;
    4508     3383136 :         Real64 Denominator = 0.0;
    4509     3383136 :         Real64 Resistance = 0.0;
    4510     3383136 :         Real64 AdiabaticMultiplier = 1.0;
    4511             : 
    4512             :         // add effect from previous time step
    4513     3383136 :         Numerator += cell.Temperature_PrevTimeStep;
    4514     3383136 :         ++Denominator;
    4515             : 
    4516     3383136 :         switch (cell.cellType) {
    4517     2786112 :         case CellType::BasementWall:
    4518             : 
    4519             :             // we will only have heat flux from the basement wall and heat conduction to the +x cell
    4520             : 
    4521             :             // This is actually only a half-cell since the basement wall slices right through the middle in one direction
    4522     2786112 :             Beta = cell.Beta / 2.0;
    4523             : 
    4524             :             // get the average basement wall heat flux and add it to the tally
    4525     2786112 :             HeatFlux = this->GetBasementWallHeatFlux(state);
    4526     2786112 :             Numerator += Beta * HeatFlux * cell.height();
    4527             : 
    4528             :             // then get the +x conduction to continue the heat balance
    4529     2786112 :             this->EvaluateNeighborCharacteristics(cell, Direction::PositiveX, NeighborTemp, Resistance, AdiabaticMultiplier);
    4530     2786112 :             Numerator += AdiabaticMultiplier * (Beta / Resistance) * NeighborTemp;
    4531     2786112 :             Denominator += AdiabaticMultiplier * (Beta / Resistance);
    4532             : 
    4533     2786112 :             break;
    4534             : 
    4535      398016 :         case CellType::BasementFloor:
    4536             : 
    4537             :             // we will only have heat flux from the basement floor and heat conduction to the lower cell
    4538             : 
    4539             :             // This is actually only a half-cell since the basement wall slices right through the middle in one direction
    4540      398016 :             Beta = cell.Beta / 2.0;
    4541             : 
    4542             :             // get the average basement floor heat flux and add it to the tally
    4543      398016 :             HeatFlux = this->GetBasementFloorHeatFlux(state);
    4544      398016 :             Numerator += Beta * HeatFlux * cell.width();
    4545             : 
    4546             :             // then get the -y conduction to continue the heat balance
    4547      398016 :             this->EvaluateNeighborCharacteristics(cell, Direction::NegativeY, NeighborTemp, Resistance, AdiabaticMultiplier);
    4548      398016 :             Numerator += AdiabaticMultiplier * (Beta / Resistance) * NeighborTemp;
    4549      398016 :             Denominator += AdiabaticMultiplier * (Beta / Resistance);
    4550             : 
    4551      398016 :             break;
    4552             : 
    4553      199008 :         case CellType::BasementCorner:
    4554             : 
    4555             :             // This is actually only a three-quarter-cell since the basement wall slices right through the middle in both directions
    4556      199008 :             Beta = cell.Beta * 3.0 / 4.0;
    4557             : 
    4558             :             // we will only have heat conduction to the +x and -y cells
    4559      199008 :             this->EvaluateNeighborCharacteristics(cell, Direction::PositiveX, NeighborTemp, Resistance, AdiabaticMultiplier);
    4560      199008 :             Numerator += AdiabaticMultiplier * (Beta / Resistance) * NeighborTemp;
    4561      199008 :             Denominator += AdiabaticMultiplier * (Beta / Resistance);
    4562             : 
    4563      199008 :             this->EvaluateNeighborCharacteristics(cell, Direction::NegativeY, NeighborTemp, Resistance, AdiabaticMultiplier);
    4564      199008 :             Numerator += AdiabaticMultiplier * (Beta / Resistance) * NeighborTemp;
    4565      199008 :             Denominator += AdiabaticMultiplier * (Beta / Resistance);
    4566             : 
    4567      199008 :             break;
    4568             : 
    4569           0 :         default:
    4570             :             // other cell types are not calculated here
    4571           0 :             break;
    4572             :         }
    4573             : 
    4574     3383136 :         return Numerator / Denominator;
    4575             :     }
    4576             : 
    4577    67286657 :     Real64 Domain::EvaluateFarfieldBoundaryTemperature(EnergyPlusData &state, CartesianCell &cell)
    4578             :     {
    4579             : 
    4580             :         // FUNCTION INFORMATION:
    4581             :         //       AUTHOR         Edwin Lee
    4582             :         //       DATE WRITTEN   Summer 2011
    4583             :         //       MODIFIED       na
    4584             :         //       RE-ENGINEERED  na
    4585             : 
    4586             :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    4587    67286657 :         Real64 Numerator = 0.0;
    4588    67286657 :         Real64 Denominator = 0.0;
    4589    67286657 :         Real64 Resistance = 0.0;
    4590    67286657 :         Real64 AdiabaticMultiplier = 1.0;
    4591    67286657 :         Real64 Beta = cell.Beta;
    4592             : 
    4593             :         // add effect from previous time step
    4594    67286657 :         Numerator += cell.Temperature_PrevTimeStep;
    4595    67286657 :         ++Denominator;
    4596             : 
    4597             :         // now that we aren't infinitesimal, we need to determine the neighbor types based on cell location
    4598    67286657 :         int NumFieldCells = 0, NumBoundaryCells = 0;
    4599    67286657 :         this->EvaluateCellNeighborDirections(cell, NumFieldCells, NumBoundaryCells);
    4600             : 
    4601             :         // Do all neighbor cells
    4602   390958882 :         for (int DirectionCounter = 0; DirectionCounter <= NumFieldCells; ++DirectionCounter) {
    4603   323672225 :             Direction CurDirection = this->NeighborFieldCells[DirectionCounter];
    4604   323672225 :             Real64 NeighborTemp = 0.0;
    4605   323672225 :             this->EvaluateNeighborCharacteristics(cell, CurDirection, NeighborTemp, Resistance, AdiabaticMultiplier);
    4606   323672225 :             Numerator += AdiabaticMultiplier * (Beta / Resistance) * NeighborTemp;
    4607   323672225 :             Denominator += AdiabaticMultiplier * (Beta / Resistance);
    4608             :         }
    4609             : 
    4610             :         // Then all farfield boundaries
    4611   147334374 :         for (int DirectionCounter = 0; DirectionCounter <= NumBoundaryCells; ++DirectionCounter) {
    4612    80047717 :             Direction CurDirection = this->NeighborBoundaryCells[DirectionCounter];
    4613    80047717 :             Real64 NeighborTemp = 0.0;
    4614    80047717 :             this->EvaluateFarfieldCharacteristics(state, cell, CurDirection, NeighborTemp, Resistance, AdiabaticMultiplier);
    4615    80047717 :             Numerator += AdiabaticMultiplier * (Beta / Resistance) * NeighborTemp;
    4616    80047717 :             Denominator += AdiabaticMultiplier * (Beta / Resistance);
    4617             :         }
    4618             : 
    4619    67286657 :         return Numerator / Denominator;
    4620             :     }
    4621             : 
    4622     4801635 :     Real64 Domain::EvaluateZoneInterfaceTemperature(CartesianCell &cell)
    4623             :     {
    4624             : 
    4625             :         // FUNCTION INFORMATION:
    4626             :         //       AUTHOR         Edwin Lee
    4627             :         //       DATE WRITTEN   Summer 2011
    4628             :         //       MODIFIED       na
    4629             :         //       RE-ENGINEERED  na
    4630             : 
    4631             :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    4632             :         Real64 HeatFlux;
    4633             :         Real64 ConductionArea;
    4634     4801635 :         Real64 Numerator = 0.0;
    4635     4801635 :         Real64 Denominator = 0.0;
    4636     4801635 :         Real64 Resistance = 0.0;
    4637     4801635 :         Real64 AdiabaticMultiplier = 1.0;
    4638     4801635 :         Real64 Beta = cell.Beta;
    4639             : 
    4640             :         // add effect from previous time step
    4641     4801635 :         Numerator += cell.Temperature_PrevTimeStep;
    4642     4801635 :         ++Denominator;
    4643             : 
    4644     4801635 :         if (cell.cellType == CellType::BasementWall) {
    4645             :             // Get the average basement wall heat flux and add it to the tally
    4646     1648674 :             HeatFlux = this->WallHeatFlux;
    4647     1648674 :             if (cell.X_index == this->XWallIndex) {
    4648      824337 :                 ConductionArea = cell.depth() * cell.height();
    4649      824337 :                 Numerator += Beta * HeatFlux * ConductionArea;
    4650      824337 :             } else if (cell.Z_index == this->ZWallIndex) {
    4651      824337 :                 ConductionArea = cell.width() * cell.height();
    4652      824337 :                 Numerator += Beta * HeatFlux * ConductionArea;
    4653             :             }
    4654     3152961 :         } else if (cell.cellType == CellType::BasementFloor) {
    4655             :             // Get the average basement floor heat flux and add it to the tally
    4656      824337 :             HeatFlux = this->FloorHeatFlux;
    4657      824337 :             ConductionArea = cell.width() * cell.depth();
    4658      824337 :             Numerator += Beta * HeatFlux * ConductionArea;
    4659     2328624 :         } else if (cell.cellType == CellType::ZoneGroundInterface) {
    4660             :             // Get the average slab heat flux and add it to the tally
    4661     2328624 :             HeatFlux = this->WeightedHeatFlux(cell.X_index, cell.Z_index);
    4662     2328624 :             ConductionArea = cell.width() * cell.depth();
    4663     2328624 :             Numerator += Beta * HeatFlux * ConductionArea;
    4664             :         }
    4665             : 
    4666             :         // determine the neighbor types based on cell location
    4667     4801635 :         int NumFieldCells = 0, NumBoundaryCells = 0;
    4668     4801635 :         this->EvaluateCellNeighborDirections(cell, NumFieldCells, NumBoundaryCells);
    4669             : 
    4670             :         // loop across each direction in the simulation
    4671    29957055 :         for (int DirectionCounter = 0; DirectionCounter <= NumFieldCells; ++DirectionCounter) {
    4672             : 
    4673    25155420 :             Real64 NeighborTemp = 0.0;
    4674    25155420 :             Direction CurDirection = this->NeighborFieldCells[DirectionCounter];
    4675             : 
    4676             :             // Have to be careful here to make sure heat conduction happens only in the appropriate directions
    4677    25155420 :             if (cell.cellType == CellType::BasementWall) {
    4678             :                 // No heat conduction from the X-side basement wall cell to the +x cell ( basement cutaway )
    4679     9525672 :                 if (cell.X_index == this->XWallIndex && CurDirection != Direction::PositiveX) {
    4680             :                     // Evaluate the transient expression terms
    4681     3938499 :                     this->EvaluateNeighborCharacteristics(cell, CurDirection, NeighborTemp, Resistance, AdiabaticMultiplier);
    4682     3938499 :                     Numerator += AdiabaticMultiplier * (Beta / Resistance) * NeighborTemp;
    4683     3938499 :                     Denominator += AdiabaticMultiplier * (Beta / Resistance);
    4684             :                 }
    4685             :                 // No heat conduction from the Z-side basement wall cell to the +z cell ( basement cutaway )
    4686     9525672 :                 if (cell.Z_index == this->ZWallIndex && CurDirection != Direction::PositiveZ) {
    4687             :                     // Evaluate the transient expression terms
    4688     3938499 :                     this->EvaluateNeighborCharacteristics(cell, CurDirection, NeighborTemp, Resistance, AdiabaticMultiplier);
    4689     3938499 :                     Numerator += AdiabaticMultiplier * (Beta / Resistance) * NeighborTemp;
    4690     3938499 :                     Denominator += AdiabaticMultiplier * (Beta / Resistance);
    4691             :                 }
    4692    15629748 :             } else if (cell.cellType == CellType::BasementFloor) {
    4693             :                 // No heat conduction from the basement floor cell to the +y cell ( basement cutaway )
    4694     4762836 :                 if (CurDirection != Direction::PositiveY) {
    4695             :                     // Evaluate the transient expression terms
    4696     3938499 :                     this->EvaluateNeighborCharacteristics(cell, CurDirection, NeighborTemp, Resistance, AdiabaticMultiplier);
    4697     3938499 :                     Numerator += AdiabaticMultiplier * (Beta / Resistance) * NeighborTemp;
    4698     3938499 :                     Denominator += AdiabaticMultiplier * (Beta / Resistance);
    4699             :                 }
    4700    10866912 :             } else if (cell.cellType == CellType::ZoneGroundInterface || cell.cellType == CellType::BasementCorner) {
    4701             :                 // Heat conduction in all directions
    4702             :                 // Evaluate the transient expression terms
    4703    10866912 :                 this->EvaluateNeighborCharacteristics(cell, CurDirection, NeighborTemp, Resistance, AdiabaticMultiplier);
    4704    10866912 :                 Numerator += AdiabaticMultiplier * (Beta / Resistance) * NeighborTemp;
    4705    10866912 :                 Denominator += AdiabaticMultiplier * (Beta / Resistance);
    4706             :             }
    4707             :         }
    4708             : 
    4709     4801635 :         return Numerator / Denominator;
    4710             :     }
    4711             : 
    4712     2791680 :     Real64 Domain::GetBasementWallHeatFlux(EnergyPlusData &state)
    4713             :     {
    4714             : 
    4715             :         // FUNCTION INFORMATION:
    4716             :         //       AUTHOR         Edwin Lee
    4717             :         //       DATE WRITTEN   Summer 2011
    4718             :         //       MODIFIED       na
    4719             :         //       RE-ENGINEERED  na
    4720             : 
    4721     2791680 :         Real64 RunningSummation = 0.0;
    4722     2791680 :         unsigned int const numSurfaces = static_cast<unsigned int>(this->BasementZone.WallSurfacePointers.size());
    4723    13958400 :         for (auto &surfaceIndex : this->BasementZone.WallSurfacePointers) {
    4724    11166720 :             RunningSummation += state.dataHeatBalSurf->SurfQdotConvOutPerArea(surfaceIndex);
    4725     2791680 :         }
    4726     2791680 :         return -RunningSummation / numSurfaces; // heat flux is negative here
    4727             :     }
    4728             : 
    4729      403584 :     Real64 Domain::GetBasementFloorHeatFlux(EnergyPlusData &state)
    4730             :     {
    4731             : 
    4732             :         // FUNCTION INFORMATION:
    4733             :         //       AUTHOR         Edwin Lee
    4734             :         //       DATE WRITTEN   Summer 2011
    4735             :         //       MODIFIED       na
    4736             :         //       RE-ENGINEERED  na
    4737             : 
    4738      403584 :         Real64 RunningSummation = 0.0;
    4739      403584 :         unsigned int const numSurfaces = static_cast<unsigned int>(this->BasementZone.FloorSurfacePointers.size());
    4740      807168 :         for (auto &surfaceIndex : this->BasementZone.FloorSurfacePointers) {
    4741      403584 :             RunningSummation += state.dataHeatBalSurf->SurfQdotConvOutPerArea(surfaceIndex);
    4742      403584 :         }
    4743      403584 :         return -RunningSummation / numSurfaces; // heat flux is negative here
    4744             :     }
    4745             : 
    4746       13766 :     void Domain::UpdateBasementSurfaceTemperatures(EnergyPlusData &state)
    4747             :     {
    4748             : 
    4749             :         // SUBROUTINE INFORMATION:
    4750             :         //       AUTHOR         Edwin Lee
    4751             :         //       DATE WRITTEN   Summer 2011
    4752             :         //       MODIFIED       na
    4753             :         //       RE-ENGINEERED  na
    4754             : 
    4755             :         // SUBROUTINE PARAMETER DEFINITIONS:
    4756       13766 :         Real64 constexpr BigNumber(10000.0);
    4757             : 
    4758             :         // First the wall
    4759       13766 :         this->BasementWallTemp = this->GetAverageTempByType(state, CellType::BasementWall);
    4760       13766 :         int OSCMIndex = this->BasementZone.WallBoundaryOSCMIndex;
    4761       13766 :         state.dataSurface->OSCM(OSCMIndex).TConv = this->BasementWallTemp;
    4762       13766 :         state.dataSurface->OSCM(OSCMIndex).HConv = BigNumber;
    4763       13766 :         state.dataSurface->OSCM(OSCMIndex).TRad = this->BasementWallTemp;
    4764       13766 :         state.dataSurface->OSCM(OSCMIndex).HRad = 0.0;
    4765             : 
    4766             :         // Then the floor
    4767       13766 :         this->BasementFloorTemp = this->GetAverageTempByType(state, CellType::BasementFloor);
    4768       13766 :         OSCMIndex = this->BasementZone.FloorBoundaryOSCMIndex;
    4769       13766 :         state.dataSurface->OSCM(OSCMIndex).TConv = this->BasementFloorTemp;
    4770       13766 :         state.dataSurface->OSCM(OSCMIndex).HConv = BigNumber;
    4771       13766 :         state.dataSurface->OSCM(OSCMIndex).TRad = this->BasementFloorTemp;
    4772       13766 :         state.dataSurface->OSCM(OSCMIndex).HRad = 0.0;
    4773       13766 :     }
    4774             : 
    4775       21312 :     Real64 Domain::GetZoneInterfaceHeatFlux(EnergyPlusData &state)
    4776             :     {
    4777             : 
    4778             :         // FUNCTION INFORMATION:
    4779             :         //       AUTHOR         Edwin Lee
    4780             :         //       DATE WRITTEN   Summer 2011
    4781             :         //       MODIFIED       na
    4782             :         //       RE-ENGINEERED  na
    4783             : 
    4784       21312 :         Real64 RunningSummation = 0.0;
    4785       21312 :         int const NumSurfaces = this->ZoneCoupledSurfaces.size();
    4786       79488 :         for (auto &z : this->ZoneCoupledSurfaces) {
    4787       58176 :             RunningSummation += state.dataHeatBalSurf->SurfQdotConvOutPerArea(z.IndexInSurfaceArray);
    4788       21312 :         }
    4789       21312 :         return -RunningSummation / NumSurfaces; // heat flux is negative here
    4790             :     }
    4791             : 
    4792       10656 :     void Domain::UpdateZoneSurfaceTemperatures(EnergyPlusData &state)
    4793             :     {
    4794             : 
    4795             :         // SUBROUTINE INFORMATION:
    4796             :         //       AUTHOR
    4797             :         //       DATE WRITTEN
    4798             :         //       MODIFIED       na
    4799             :         //       RE-ENGINEERED  na
    4800             : 
    4801             :         // SUBROUTINE PARAMETER DEFINITIONS:
    4802       10656 :         Real64 constexpr BigNumber(10000.0);
    4803             : 
    4804       10656 :         this->ZoneCoupledSurfaceTemp = this->GetAverageTempByType(state, CellType::ZoneGroundInterface);
    4805       10656 :         int OSCMIndex = this->ZoneCoupledOSCMIndex;
    4806       10656 :         state.dataSurface->OSCM(OSCMIndex).TConv = this->ZoneCoupledSurfaceTemp;
    4807       10656 :         state.dataSurface->OSCM(OSCMIndex).HConv = BigNumber;
    4808       10656 :         state.dataSurface->OSCM(OSCMIndex).TRad = this->ZoneCoupledSurfaceTemp;
    4809       10656 :         state.dataSurface->OSCM(OSCMIndex).HRad = 0.0;
    4810             : 
    4811             :         // Reset the interface heat flux after iteration
    4812       10656 :         this->ResetHeatFluxFlag = true;
    4813       10656 :     }
    4814             : 
    4815       48844 :     Real64 Domain::GetAverageTempByType(EnergyPlusData &state, CellType const cellType) const
    4816             :     {
    4817             : 
    4818             :         // FUNCTION INFORMATION:
    4819             :         //       AUTHOR         Edwin Lee
    4820             :         //       DATE WRITTEN   Summer 2011
    4821             :         //       MODIFIED       na
    4822             :         //       RE-ENGINEERED  na
    4823             : 
    4824             :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    4825       48844 :         Real64 RunningSummation = 0.0;
    4826       48844 :         Real64 RunningVolume = 0.0;
    4827             : 
    4828       48844 :         auto const &cells = Cells;
    4829      782808 :         for (int X = 0, X_end = this->x_max_index; X <= X_end; ++X) {
    4830    13141656 :             for (int Y = 0, Y_end = this->y_max_index; Y <= Y_end; ++Y) {
    4831   131780116 :                 for (int Z = 0, Z_end = this->z_max_index; Z <= Z_end; ++Z) {
    4832   119372424 :                     auto const &cell = cells(X, Y, Z);
    4833   119372424 :                     if (cell.cellType == cellType) {
    4834     2498016 :                         Real64 CellVolume = cell.volume();
    4835     2498016 :                         RunningVolume += CellVolume;
    4836     2498016 :                         RunningSummation += CellVolume * cell.Temperature;
    4837             :                     }
    4838             :                 }
    4839             :             }
    4840             :         }
    4841             : 
    4842       48844 :         if (RunningVolume <= 0.0) {
    4843           0 :             ShowFatalError(state, "Domain::GetAverageTempByType calculated zero volume, program aborts");
    4844             :         }
    4845             : 
    4846       48844 :         return RunningSummation / RunningVolume;
    4847             :     }
    4848             : 
    4849    80752899 :     void Domain::EvaluateFarfieldCharacteristics(
    4850             :         EnergyPlusData &state, CartesianCell &cell, Direction const direction, Real64 &neighbortemp, Real64 &resistance, Real64 &adiabaticMultiplier)
    4851             :     {
    4852             : 
    4853             :         // SUBROUTINE INFORMATION:
    4854             :         //       AUTHOR         Edwin Lee
    4855             :         //       DATE WRITTEN   Summer 2011
    4856             :         //       MODIFIED       na
    4857             :         //       RE-ENGINEERED  na
    4858             : 
    4859             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4860    80752899 :         Real64 distance(0.0);
    4861             : 
    4862    80752899 :         switch (direction) {
    4863    25131767 :         case Direction::NegativeX:
    4864             :         case Direction::PositiveX:
    4865    25131767 :             distance = (cell.width() / 2.0);
    4866    25131767 :             break;
    4867    19078993 :         case Direction::NegativeY:
    4868             :         case Direction::PositiveY:
    4869    19078993 :             distance = (cell.height() / 2.0);
    4870    19078993 :             break;
    4871    36542139 :         case Direction::NegativeZ:
    4872             :         case Direction::PositiveZ:
    4873    36542139 :             distance = (cell.depth() / 2.0);
    4874    36542139 :             break;
    4875           0 :         default:
    4876           0 :             assert(false);
    4877             :         }
    4878             : 
    4879    80752899 :         resistance = (distance / 2.0) / (cell.Properties.Conductivity * cell.normalArea(direction));
    4880    80752899 :         neighbortemp = this->GetFarfieldTemp(state, cell);
    4881             : 
    4882    80752899 :         adiabaticMultiplier = cell.NeighborInfo[direction].adiabaticMultiplier;
    4883    80752899 :     }
    4884             : 
    4885    80805873 :     Real64 Domain::GetFarfieldTemp(EnergyPlusData &state, CartesianCell const &cell)
    4886             :     {
    4887             : 
    4888             :         // FUNCTION INFORMATION:
    4889             :         //       AUTHOR         Edwin Lee
    4890             :         //       DATE WRITTEN   Summer 2011
    4891             :         //       MODIFIED       na
    4892             :         //       RE-ENGINEERED  na
    4893             : 
    4894    80805873 :         Real64 CurTime = this->Cur.CurSimTimeSeconds;
    4895    80805873 :         Real64 z = this->Extents.yMax - cell.Centroid.Y;
    4896    80805873 :         return this->groundTempModel->getGroundTempAtTimeInSeconds(state, z, CurTime);
    4897             :     }
    4898             : 
    4899       14502 :     void Domain::PreparePipeCircuitSimulation(Circuit *thisCircuit)
    4900             :     {
    4901             : 
    4902             :         // SUBROUTINE INFORMATION:
    4903             :         //       AUTHOR         Edwin Lee
    4904             :         //       DATE WRITTEN   Summer 2011
    4905             :         //       MODIFIED       na
    4906             :         //       RE-ENGINEERED  na
    4907             : 
    4908             :         // SUBROUTINE ARGUMENT DEFINITIONS:
    4909       14502 :         Real64 constexpr StagnantFluidConvCoeff(200.0);
    4910             : 
    4911             :         // Setup circuit flow conditions -- convection coefficient
    4912       14502 :         int const CellX = thisCircuit->CircuitInletCell.X;
    4913       14502 :         int const CellY = thisCircuit->CircuitInletCell.Y;
    4914       14502 :         int const CellZ = thisCircuit->CircuitInletCell.Z;
    4915             : 
    4916             :         // Look up current fluid properties
    4917       14502 :         Real64 const Density = thisCircuit->CurFluidPropertySet.Density;
    4918       14502 :         Real64 const Viscosity = thisCircuit->CurFluidPropertySet.Viscosity;
    4919       14502 :         Real64 const Conductivity = thisCircuit->CurFluidPropertySet.Conductivity;
    4920       14502 :         Real64 const Prandtl = thisCircuit->CurFluidPropertySet.Prandtl;
    4921             : 
    4922             :         // Flow calculations
    4923       14502 :         Real64 const Area_c = (Constant::Pi / 4.0) * pow_2(thisCircuit->PipeSize.InnerDia);
    4924       14502 :         Real64 const Velocity = thisCircuit->CurCircuitFlowRate / (Density * Area_c);
    4925             : 
    4926             :         // Determine convection coefficient based on flow conditions
    4927             :         Real64 ConvCoefficient;
    4928       14502 :         if (Velocity > 0) {
    4929       14430 :             Real64 Reynolds = Density * thisCircuit->PipeSize.InnerDia * Velocity / Viscosity;
    4930             :             Real64 ExponentTerm;
    4931       14430 :             if (this->Cells(CellX, CellY, CellZ).PipeCellData.Fluid.Temperature > this->Cells(CellX, CellY, CellZ).PipeCellData.Pipe.Temperature) {
    4932        3747 :                 ExponentTerm = 0.3;
    4933             :             } else {
    4934       10683 :                 ExponentTerm = 0.4;
    4935             :             }
    4936       14430 :             Real64 const Nusselt = 0.023 * std::pow(Reynolds, 4.0 / 5.0) * std::pow(Prandtl, ExponentTerm);
    4937       14430 :             ConvCoefficient = Nusselt * Conductivity / thisCircuit->PipeSize.InnerDia;
    4938             :         } else {
    4939          72 :             ConvCoefficient = StagnantFluidConvCoeff;
    4940             :         }
    4941             : 
    4942             :         // Assign the convection coefficient
    4943       14502 :         thisCircuit->CurCircuitConvectionCoefficient = ConvCoefficient;
    4944       14502 :     }
    4945             : 
    4946       50655 :     void Domain::PerformPipeCircuitSimulation(EnergyPlusData &state, Circuit *thisCircuit)
    4947             :     {
    4948             : 
    4949             :         // SUBROUTINE INFORMATION:
    4950             :         //       AUTHOR         Edwin Lee
    4951             :         //       DATE WRITTEN   Summer 2011
    4952             :         //       MODIFIED       na
    4953             :         //       RE-ENGINEERED  na
    4954             : 
    4955             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4956       50655 :         Real64 CircuitCrossTemp = 0.0;
    4957             : 
    4958             :         // retrieve initial conditions from the data structure
    4959             :         // these have been set either by the init routine or by the heat pump routine
    4960       50655 :         Real64 const FlowRate = thisCircuit->CurCircuitFlowRate;
    4961       50655 :         Real64 const EnteringTemp = thisCircuit->CurCircuitInletTemp;
    4962             : 
    4963             :         // initialize
    4964       50655 :         int SegmentCellCtr = 0;
    4965       50655 :         unsigned long const NumSegments = thisCircuit->pipeSegments.size();
    4966       50655 :         unsigned long segmentNum = 0;
    4967             : 
    4968             :         //'loop across all segments (pipes) of the circuit
    4969       50655 :         auto &cells = this->Cells;
    4970      284637 :         for (auto &segment : thisCircuit->pipeSegments) {
    4971             : 
    4972      233982 :             segmentNum++;
    4973      233982 :             int StartingZ = 0;
    4974      233982 :             int EndingZ = 0;
    4975      233982 :             int Increment = 0;
    4976             : 
    4977             :             //'set simulation flow direction
    4978      233982 :             switch (segment->FlowDirection) {
    4979      116991 :             case SegmentFlow::IncreasingZ:
    4980      116991 :                 StartingZ = 0;
    4981      116991 :                 EndingZ = this->z_max_index;
    4982      116991 :                 Increment = 1;
    4983      116991 :                 break;
    4984      116991 :             case SegmentFlow::DecreasingZ:
    4985      116991 :                 StartingZ = this->z_max_index;
    4986      116991 :                 EndingZ = 0;
    4987      116991 :                 Increment = -1;
    4988      116991 :                 break;
    4989           0 :             default:
    4990           0 :                 ShowFatalError(state, "Debug error: invalid flow direction on piping system segment");
    4991             :             }
    4992             : 
    4993             :             //'find the cell we are working on in order to retrieve cell and neighbor information
    4994      233982 :             int PipeX = segment->PipeCellCoordinates.X;
    4995      233982 :             int PipeY = segment->PipeCellCoordinates.Y;
    4996             : 
    4997             :             //'loop across all z-direction indeces
    4998      233982 :             int const Zindex_stop(floop_end(StartingZ, EndingZ, Increment));
    4999     1628894 :             for (int Zindex = StartingZ; Zindex != Zindex_stop; Zindex += Increment) {
    5000             : 
    5001             :                 //'overall cell segment counter
    5002     1394912 :                 ++SegmentCellCtr;
    5003             : 
    5004     1394912 :                 if (SegmentCellCtr == 1) {
    5005             :                     //'we have the very first cell, need to pass in circuiting entering temperature
    5006       50655 :                     this->PerformPipeCellSimulation(thisCircuit, cells(PipeX, PipeY, Zindex), FlowRate, EnteringTemp);
    5007             :                 } else {
    5008             :                     //'we don't have the first cell so just normal simulation
    5009     1344257 :                     if (Zindex == EndingZ) {
    5010             :                         // simulate current cell using upstream as entering conditions
    5011      233982 :                         this->PerformPipeCellSimulation(thisCircuit,
    5012             :                                                         cells(PipeX, PipeY, Zindex),
    5013             :                                                         FlowRate,
    5014      233982 :                                                         cells(PipeX, PipeY, Zindex - Increment).PipeCellData.Fluid.Temperature);
    5015             :                         // store this outlet condition to be passed to the next segment
    5016      233982 :                         CircuitCrossTemp = cells(PipeX, PipeY, Zindex).PipeCellData.Fluid.Temperature;
    5017     1110275 :                     } else if (Zindex == StartingZ) {
    5018             :                         // we are starting another segment, use the previous cross temperature
    5019      183327 :                         this->PerformPipeCellSimulation(thisCircuit, cells(PipeX, PipeY, Zindex), FlowRate, CircuitCrossTemp);
    5020             :                     } else {
    5021             :                         // we are in an interior node, so just get the upstream cell and use the main simulation
    5022      926948 :                         this->PerformPipeCellSimulation(thisCircuit,
    5023             :                                                         cells(PipeX, PipeY, Zindex),
    5024             :                                                         FlowRate,
    5025      926948 :                                                         cells(PipeX, PipeY, Zindex - Increment).PipeCellData.Fluid.Temperature);
    5026             :                     }
    5027             :                 }
    5028             : 
    5029             :                 // Bookkeeping: segment fluid temperature updates
    5030     1394912 :                 if (Zindex == StartingZ) {
    5031      233982 :                     if (segmentNum == 1) {
    5032       50655 :                         segment->InletTemperature = EnteringTemp;
    5033             :                     } else {
    5034      183327 :                         segment->InletTemperature = CircuitCrossTemp;
    5035             :                     }
    5036     1160930 :                 } else if (Zindex == EndingZ) {
    5037      233982 :                     segment->OutletTemperature = cells(PipeX, PipeY, Zindex).PipeCellData.Fluid.Temperature;
    5038      233982 :                     segment->FluidHeatLoss =
    5039      233982 :                         FlowRate * thisCircuit->CurFluidPropertySet.SpecificHeat * (segment->InletTemperature - segment->OutletTemperature);
    5040             :                 }
    5041             : 
    5042             :                 // Bookkeeping: circuit fluid temperature updates
    5043     1394912 :                 if ((segmentNum == 1) && (Zindex == StartingZ)) {
    5044       50655 :                     thisCircuit->InletTemperature = EnteringTemp;
    5045     1344257 :                 } else if ((segmentNum == NumSegments) && (Zindex == EndingZ)) {
    5046       50655 :                     thisCircuit->OutletTemperature = cells(PipeX, PipeY, Zindex).PipeCellData.Fluid.Temperature;
    5047       50655 :                     thisCircuit->FluidHeatLoss =
    5048       50655 :                         FlowRate * thisCircuit->CurFluidPropertySet.SpecificHeat * (thisCircuit->InletTemperature - thisCircuit->OutletTemperature);
    5049             :                 }
    5050             :             }
    5051       50655 :         }
    5052       50655 :     }
    5053             : 
    5054     1394912 :     void Domain::PerformPipeCellSimulation(Circuit *thisCircuit, CartesianCell &ThisCell, Real64 const FlowRate, Real64 const EnteringTemp)
    5055             :     {
    5056             : 
    5057             :         // SUBROUTINE INFORMATION:
    5058             :         //       AUTHOR         Edwin Lee
    5059             :         //       DATE WRITTEN   Summer 2011
    5060             :         //       MODIFIED       na
    5061             :         //       RE-ENGINEERED  na
    5062             : 
    5063     7438152 :         for (int Iter = 1; Iter <= thisCircuit->MaxIterationsPerTS; ++Iter) {
    5064             : 
    5065             :             //'shift all the pipe related temperatures for the next internal pipe iteration
    5066     7437826 :             ShiftPipeTemperaturesForNewIteration(ThisCell);
    5067             : 
    5068             :             //'simulate the funny interface soil cell between the radial and cartesian systems
    5069     7437826 :             this->SimulateRadialToCartesianInterface(ThisCell);
    5070             : 
    5071             :             //'simulate the outermost radial slice
    5072     7437826 :             SimulateOuterMostRadialSoilSlice(thisCircuit, ThisCell);
    5073             : 
    5074             :             //'we only need to simulate these if they actually exist!
    5075     7437826 :             if (!ThisCell.PipeCellData.Soil.empty()) {
    5076             : 
    5077             :                 //'simulate all interior radial slices
    5078     7437826 :                 SimulateAllInteriorRadialSoilSlices(ThisCell);
    5079             : 
    5080             :                 //'simulate the innermost radial soil slice
    5081     7437826 :                 SimulateInnerMostRadialSoilSlice(thisCircuit, ThisCell);
    5082             :             }
    5083             : 
    5084     7437826 :             if (thisCircuit->HasInsulation) {
    5085           0 :                 SimulateRadialInsulationCell(ThisCell);
    5086             :             }
    5087             : 
    5088             :             //'simulate the pipe cell
    5089     7437826 :             SimulateRadialPipeCell(thisCircuit, ThisCell);
    5090             : 
    5091             :             //'simulate the water cell
    5092     7437826 :             SimulateFluidCell(thisCircuit, ThisCell, FlowRate, EnteringTemp);
    5093             : 
    5094             :             //'check convergence
    5095     7437826 :             if (IsConverged_PipeCurrentToPrevIteration(thisCircuit, ThisCell)) break; // potential diff source
    5096             :         }
    5097     1394912 :     }
    5098             : 
    5099     7437826 :     void Domain::SimulateRadialToCartesianInterface(CartesianCell &cell)
    5100             :     {
    5101             : 
    5102             :         // SUBROUTINE INFORMATION:
    5103             :         //       AUTHOR         Edwin Lee
    5104             :         //       DATE WRITTEN   Summer 2011
    5105             :         //       MODIFIED       na
    5106             :         //       RE-ENGINEERED  na
    5107             : 
    5108             :         // SUBROUTINE PARAMETER DEFINITIONS:
    5109     7437826 :         static std::vector<Direction> const Directions = {Direction::NegativeX, Direction::NegativeY, Direction::PositiveX, Direction::PositiveY};
    5110             : 
    5111             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5112     7437826 :         Real64 Numerator = 0.0;
    5113     7437826 :         Real64 Denominator = 0.0;
    5114             : 
    5115             :         //'add effects from this cell history
    5116     7437826 :         Numerator += cell.Temperature_PrevTimeStep;
    5117     7437826 :         ++Denominator;
    5118             : 
    5119             :         //'add effects from outermost radial cell
    5120     7437826 :         auto &outerRadialCell = cell.PipeCellData.Soil.back();
    5121     7437826 :         Real64 OutermostRadialCellOuterRadius = outerRadialCell.OuterRadius;
    5122     7437826 :         Real64 OutermostRadialCellRadialCentroid = outerRadialCell.RadialCentroid;
    5123     7437826 :         Real64 OutermostRadialCellTemperature = outerRadialCell.Temperature;
    5124    14875652 :         Real64 Resistance = std::log(OutermostRadialCellOuterRadius / OutermostRadialCellRadialCentroid) /
    5125     7437826 :                             (2.0 * Constant::Pi * cell.depth() * cell.Properties.Conductivity);
    5126     7437826 :         Numerator += (cell.Beta / Resistance) * OutermostRadialCellTemperature;
    5127     7437826 :         Denominator += (cell.Beta / Resistance);
    5128             : 
    5129             :         //'add effects from neighboring Cartesian cells
    5130    37189130 :         for (Direction curDirection : Directions) {
    5131    29751304 :             Real64 AdiabaticMultiplier = 1.0;
    5132    29751304 :             Real64 NeighborTemp = 0.0;
    5133    29751304 :             this->EvaluateNeighborCharacteristics(cell, curDirection, NeighborTemp, Resistance, AdiabaticMultiplier);
    5134    29751304 :             Numerator += AdiabaticMultiplier * (cell.Beta / Resistance) * NeighborTemp;
    5135    29751304 :             Denominator += AdiabaticMultiplier * (cell.Beta / Resistance);
    5136     7437826 :         }
    5137             : 
    5138             :         //'calculate the new temperature
    5139     7437826 :         cell.Temperature = Numerator / Denominator;
    5140     7437826 :     }
    5141             : 
    5142     7437826 :     void SimulateOuterMostRadialSoilSlice(Circuit *thisCircuit, CartesianCell &cell)
    5143             :     {
    5144             : 
    5145             :         // SUBROUTINE INFORMATION:
    5146             :         //       AUTHOR         Edwin Lee
    5147             :         //       DATE WRITTEN   Summer 2011
    5148             :         //       MODIFIED       na
    5149             :         //       RE-ENGINEERED  na
    5150             : 
    5151             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5152             :         Real64 NextOuterRadialCellOuterRadius;
    5153             :         Real64 NextOuterRadialCellRadialCentroid;
    5154             :         Real64 NextOuterRadialCellConductivity;
    5155             :         Real64 NextOuterRadialCellTemperature;
    5156             : 
    5157     7437826 :         Real64 Numerator = 0.0;
    5158     7437826 :         Real64 Denominator = 0.0;
    5159             : 
    5160             :         //'convenience variables
    5161     7437826 :         int const numSoilCells = static_cast<int>(cell.PipeCellData.Soil.size());
    5162     7437826 :         auto &outerMostSoilCell = cell.PipeCellData.Soil[numSoilCells - 1];
    5163     7437826 :         Real64 ThisRadialCellOuterRadius = outerMostSoilCell.OuterRadius;
    5164     7437826 :         Real64 ThisRadialCellRadialCentroid = outerMostSoilCell.RadialCentroid;
    5165     7437826 :         Real64 ThisRadialCellConductivity = outerMostSoilCell.Properties.Conductivity;
    5166     7437826 :         Real64 ThisRadialCellInnerRadius = outerMostSoilCell.InnerRadius;
    5167     7437826 :         Real64 ThisRadialCellTemperature_PrevTimeStep = outerMostSoilCell.Temperature_PrevTimeStep;
    5168     7437826 :         if (numSoilCells == 1) {
    5169           0 :             if (thisCircuit->HasInsulation) {
    5170           0 :                 NextOuterRadialCellOuterRadius = cell.PipeCellData.Insulation.OuterRadius;
    5171           0 :                 NextOuterRadialCellRadialCentroid = cell.PipeCellData.Insulation.RadialCentroid;
    5172           0 :                 NextOuterRadialCellConductivity = cell.PipeCellData.Insulation.Properties.Conductivity;
    5173           0 :                 NextOuterRadialCellTemperature = cell.PipeCellData.Insulation.Temperature;
    5174             :             } else {
    5175           0 :                 NextOuterRadialCellOuterRadius = cell.PipeCellData.Pipe.OuterRadius;
    5176           0 :                 NextOuterRadialCellRadialCentroid = cell.PipeCellData.Pipe.RadialCentroid;
    5177           0 :                 NextOuterRadialCellConductivity = cell.PipeCellData.Pipe.Properties.Conductivity;
    5178           0 :                 NextOuterRadialCellTemperature = cell.PipeCellData.Pipe.Temperature;
    5179             :             }
    5180             :         } else {
    5181     7437826 :             auto &nextOuterMostSoilCell = cell.PipeCellData.Soil[numSoilCells - 2];
    5182     7437826 :             NextOuterRadialCellOuterRadius = nextOuterMostSoilCell.OuterRadius;
    5183     7437826 :             NextOuterRadialCellRadialCentroid = nextOuterMostSoilCell.RadialCentroid;
    5184     7437826 :             NextOuterRadialCellConductivity = nextOuterMostSoilCell.Properties.Conductivity;
    5185     7437826 :             NextOuterRadialCellTemperature = nextOuterMostSoilCell.Temperature;
    5186             :         }
    5187             : 
    5188             :         //'any broadly defined variables
    5189     7437826 :         Real64 Beta = outerMostSoilCell.Beta;
    5190             : 
    5191             :         //'add effects from this cell history
    5192     7437826 :         Numerator += ThisRadialCellTemperature_PrevTimeStep;
    5193     7437826 :         ++Denominator;
    5194             : 
    5195             :         //'add effects from interface cell
    5196             :         Real64 Resistance =
    5197     7437826 :             std::log(ThisRadialCellOuterRadius / ThisRadialCellRadialCentroid) / (2 * Constant::Pi * cell.depth() * ThisRadialCellConductivity);
    5198     7437826 :         Numerator += (Beta / Resistance) * cell.Temperature;
    5199     7437826 :         Denominator += (Beta / Resistance);
    5200             : 
    5201             :         //'add effects from inner radial cell
    5202     7437826 :         Resistance =
    5203     7437826 :             (std::log(ThisRadialCellRadialCentroid / ThisRadialCellInnerRadius) / (2 * Constant::Pi * cell.depth() * ThisRadialCellConductivity)) +
    5204    14875652 :             (std::log(NextOuterRadialCellOuterRadius / NextOuterRadialCellRadialCentroid) /
    5205     7437826 :              (2 * Constant::Pi * cell.depth() * NextOuterRadialCellConductivity));
    5206     7437826 :         Numerator += (Beta / Resistance) * NextOuterRadialCellTemperature;
    5207     7437826 :         Denominator += (Beta / Resistance);
    5208             : 
    5209             :         //'calculate the new temperature
    5210     7437826 :         outerMostSoilCell.Temperature = Numerator / Denominator;
    5211     7437826 :     }
    5212             : 
    5213     7437826 :     void SimulateAllInteriorRadialSoilSlices(CartesianCell &cell)
    5214             :     {
    5215             : 
    5216             :         // SUBROUTINE INFORMATION:
    5217             :         //       AUTHOR         Edwin Lee
    5218             :         //       DATE WRITTEN   Summer 2011
    5219             :         //       MODIFIED       na
    5220             :         //       RE-ENGINEERED  na
    5221             : 
    5222     7812258 :         for (int rCtr = (int)cell.PipeCellData.Soil.size() - 2; rCtr >= 1; --rCtr) {
    5223             : 
    5224      374432 :             Real64 Numerator = 0.0;
    5225      374432 :             Real64 Denominator = 0.0;
    5226             : 
    5227             :             //'convenience variables
    5228      374432 :             auto &thisSoilCell = cell.PipeCellData.Soil[rCtr];
    5229      374432 :             Real64 ThisRadialCellOuterRadius = thisSoilCell.OuterRadius;
    5230      374432 :             Real64 ThisRadialCellRadialCentroid = thisSoilCell.RadialCentroid;
    5231      374432 :             Real64 ThisRadialCellConductivity = thisSoilCell.Properties.Conductivity;
    5232      374432 :             Real64 ThisRadialCellInnerRadius = thisSoilCell.InnerRadius;
    5233      374432 :             Real64 ThisRadialCellTemperature_PrevTimeStep = thisSoilCell.Temperature_PrevTimeStep;
    5234             : 
    5235      374432 :             auto const &minusSoilCell = cell.PipeCellData.Soil[rCtr - 1];
    5236      374432 :             Real64 InnerRadialCellOuterRadius = minusSoilCell.OuterRadius;
    5237      374432 :             Real64 InnerRadialCellRadialCentroid = minusSoilCell.RadialCentroid;
    5238      374432 :             Real64 InnerRadialCellConductivity = minusSoilCell.Properties.Conductivity;
    5239      374432 :             Real64 InnerRadialCellTemperature = minusSoilCell.Temperature;
    5240             : 
    5241      374432 :             auto const &plusSoilCell = cell.PipeCellData.Soil[rCtr + 1];
    5242      374432 :             Real64 OuterRadialCellRadialCentroid = plusSoilCell.RadialCentroid;
    5243      374432 :             Real64 OuterRadialCellConductivity = plusSoilCell.Properties.Conductivity;
    5244      374432 :             Real64 OuterRadialCellInnerRadius = plusSoilCell.InnerRadius;
    5245      374432 :             Real64 OuterRadialCellTemperature = plusSoilCell.Temperature;
    5246             : 
    5247             :             //'add effects from this cell history
    5248      374432 :             Numerator += ThisRadialCellTemperature_PrevTimeStep;
    5249      374432 :             ++Denominator;
    5250             : 
    5251             :             //'add effects from outer cell
    5252             :             Real64 Resistance =
    5253      748864 :                 (std::log(OuterRadialCellRadialCentroid / OuterRadialCellInnerRadius) /
    5254      374432 :                  (2 * Constant::Pi * cell.depth() * OuterRadialCellConductivity)) +
    5255      374432 :                 (std::log(ThisRadialCellOuterRadius / ThisRadialCellRadialCentroid) / (2 * Constant::Pi * cell.depth() * ThisRadialCellConductivity));
    5256      374432 :             Numerator += (thisSoilCell.Beta / Resistance) * OuterRadialCellTemperature;
    5257      374432 :             Denominator += (thisSoilCell.Beta / Resistance);
    5258             : 
    5259             :             //'add effects from inner cell
    5260     1123296 :             Resistance = (std::log(ThisRadialCellRadialCentroid / ThisRadialCellInnerRadius) /
    5261      374432 :                           (2 * Constant::Pi * cell.depth() * ThisRadialCellConductivity)) +
    5262      748864 :                          (std::log(InnerRadialCellOuterRadius / InnerRadialCellRadialCentroid) /
    5263      374432 :                           (2 * Constant::Pi * cell.depth() * InnerRadialCellConductivity));
    5264      374432 :             Numerator += (thisSoilCell.Beta / Resistance) * InnerRadialCellTemperature;
    5265      374432 :             Denominator += (thisSoilCell.Beta / Resistance);
    5266             : 
    5267             :             //'calculate the new temperature
    5268      374432 :             thisSoilCell.Temperature = Numerator / Denominator;
    5269             :         }
    5270     7437826 :     }
    5271             : 
    5272     7437826 :     void SimulateInnerMostRadialSoilSlice(Circuit *thisCircuit, CartesianCell &cell)
    5273             :     {
    5274             : 
    5275             :         // SUBROUTINE INFORMATION:
    5276             :         //       AUTHOR         Edwin Lee
    5277             :         //       DATE WRITTEN   Summer 2011
    5278             :         //       MODIFIED       na
    5279             :         //       RE-ENGINEERED  na
    5280             : 
    5281             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5282             :         Real64 Resistance;
    5283             :         Real64 InnerNeighborRadialCellOuterRadius;
    5284             :         Real64 InnerNeighborRadialCellRadialCentroid;
    5285             :         Real64 InnerNeighborRadialCellConductivity;
    5286             :         Real64 InnerNeighborRadialCellTemperature;
    5287             : 
    5288     7437826 :         Real64 Numerator = 0.0;
    5289     7437826 :         Real64 Denominator = 0.0;
    5290             : 
    5291             :         //'convenience variables
    5292     7437826 :         if (thisCircuit->HasInsulation) {
    5293           0 :             InnerNeighborRadialCellOuterRadius = cell.PipeCellData.Insulation.OuterRadius;
    5294           0 :             InnerNeighborRadialCellRadialCentroid = cell.PipeCellData.Insulation.RadialCentroid;
    5295           0 :             InnerNeighborRadialCellConductivity = cell.PipeCellData.Insulation.Properties.Conductivity;
    5296           0 :             InnerNeighborRadialCellTemperature = cell.PipeCellData.Insulation.Temperature;
    5297             :         } else {
    5298     7437826 :             InnerNeighborRadialCellOuterRadius = cell.PipeCellData.Pipe.OuterRadius;
    5299     7437826 :             InnerNeighborRadialCellRadialCentroid = cell.PipeCellData.Pipe.RadialCentroid;
    5300     7437826 :             InnerNeighborRadialCellConductivity = cell.PipeCellData.Pipe.Properties.Conductivity;
    5301     7437826 :             InnerNeighborRadialCellTemperature = cell.PipeCellData.Pipe.Temperature;
    5302             :         }
    5303             : 
    5304     7437826 :         auto &soilZero = cell.PipeCellData.Soil[0];
    5305     7437826 :         Real64 ThisRadialCellOuterRadius = soilZero.OuterRadius;
    5306     7437826 :         Real64 ThisRadialCellRadialCentroid = soilZero.RadialCentroid;
    5307     7437826 :         Real64 ThisRadialCellConductivity = soilZero.Properties.Conductivity;
    5308     7437826 :         Real64 ThisRadialCellInnerRadius = soilZero.InnerRadius;
    5309     7437826 :         Real64 ThisRadialCellTemperature_PrevTimeStep = soilZero.Temperature_PrevTimeStep;
    5310             : 
    5311     7437826 :         auto const &soilOne = cell.PipeCellData.Soil[1];
    5312     7437826 :         Real64 OuterNeighborRadialCellRadialCentroid = soilOne.RadialCentroid;
    5313     7437826 :         Real64 OuterNeighborRadialCellConductivity = soilOne.Properties.Conductivity;
    5314     7437826 :         Real64 OuterNeighborRadialCellInnerRadius = soilOne.InnerRadius;
    5315     7437826 :         Real64 OuterNeighborRadialCellTemperature = soilOne.Temperature;
    5316             : 
    5317             :         //'add effects from this cell history
    5318     7437826 :         Numerator += ThisRadialCellTemperature_PrevTimeStep;
    5319     7437826 :         ++Denominator;
    5320             : 
    5321             :         //'add effects from outer radial cell
    5322     7437826 :         Resistance =
    5323    14875652 :             (std::log(OuterNeighborRadialCellRadialCentroid / OuterNeighborRadialCellInnerRadius) /
    5324     7437826 :              (2 * Constant::Pi * cell.depth() * OuterNeighborRadialCellConductivity)) +
    5325     7437826 :             (std::log(ThisRadialCellOuterRadius / ThisRadialCellRadialCentroid) / (2 * Constant::Pi * cell.depth() * ThisRadialCellConductivity));
    5326     7437826 :         Numerator += (soilZero.Beta / Resistance) * OuterNeighborRadialCellTemperature;
    5327     7437826 :         Denominator += (soilZero.Beta / Resistance);
    5328             : 
    5329             :         //'add effects from pipe cell
    5330     7437826 :         Resistance =
    5331     7437826 :             (std::log(ThisRadialCellRadialCentroid / ThisRadialCellInnerRadius) / (2 * Constant::Pi * cell.depth() * ThisRadialCellConductivity)) +
    5332    14875652 :             (std::log(InnerNeighborRadialCellOuterRadius / InnerNeighborRadialCellRadialCentroid) /
    5333     7437826 :              (2 * Constant::Pi * cell.depth() * InnerNeighborRadialCellConductivity));
    5334     7437826 :         Numerator += (soilZero.Beta / Resistance) * InnerNeighborRadialCellTemperature;
    5335     7437826 :         Denominator += (soilZero.Beta / Resistance);
    5336             : 
    5337             :         //'calculate the new temperature
    5338     7437826 :         soilZero.Temperature = Numerator / Denominator;
    5339     7437826 :     }
    5340             : 
    5341           0 :     void SimulateRadialInsulationCell(CartesianCell &cell)
    5342             :     {
    5343             : 
    5344             :         // SUBROUTINE INFORMATION:
    5345             :         //       AUTHOR         Edwin Lee
    5346             :         //       DATE WRITTEN   Summer 2011
    5347             :         //       MODIFIED       na
    5348             :         //       RE-ENGINEERED  na
    5349             : 
    5350             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5351           0 :         Real64 Numerator = 0.0;
    5352           0 :         Real64 Denominator = 0.0;
    5353             : 
    5354             :         //'convenience variables
    5355           0 :         auto const &PipeCell = cell.PipeCellData.Pipe;
    5356           0 :         auto const &ThisInsulationCell = cell.PipeCellData.Insulation;
    5357           0 :         auto const &NextInnerRadialCell = cell.PipeCellData.Soil[0];
    5358             : 
    5359             :         //'add effects from this cell history
    5360           0 :         Numerator += ThisInsulationCell.Temperature_PrevTimeStep;
    5361           0 :         ++Denominator;
    5362             : 
    5363             :         //'add effects from outer radial cell
    5364           0 :         Real64 Resistance = (std::log(NextInnerRadialCell.RadialCentroid / NextInnerRadialCell.InnerRadius) /
    5365           0 :                              (2 * Constant::Pi * cell.depth() * NextInnerRadialCell.Properties.Conductivity)) +
    5366           0 :                             (std::log(ThisInsulationCell.OuterRadius / ThisInsulationCell.RadialCentroid) /
    5367           0 :                              (2 * Constant::Pi * cell.depth() * ThisInsulationCell.Properties.Conductivity));
    5368           0 :         Numerator += (ThisInsulationCell.Beta / Resistance) * NextInnerRadialCell.Temperature;
    5369           0 :         Denominator += (ThisInsulationCell.Beta / Resistance);
    5370             : 
    5371             :         //'add effects from pipe cell
    5372           0 :         Resistance =
    5373           0 :             (std::log(ThisInsulationCell.RadialCentroid / ThisInsulationCell.InnerRadius) /
    5374           0 :              (2 * Constant::Pi * cell.depth() * ThisInsulationCell.Properties.Conductivity)) +
    5375           0 :             (std::log(PipeCell.OuterRadius / PipeCell.RadialCentroid) / (2 * Constant::Pi * cell.depth() * PipeCell.Properties.Conductivity));
    5376           0 :         Numerator += (ThisInsulationCell.Beta / Resistance) * PipeCell.Temperature;
    5377           0 :         Denominator += (ThisInsulationCell.Beta / Resistance);
    5378             : 
    5379             :         //'calculate the new temperature
    5380           0 :         cell.PipeCellData.Insulation.Temperature = Numerator / Denominator;
    5381           0 :     }
    5382             : 
    5383     7437826 :     void SimulateRadialPipeCell(Circuit *thisCircuit, CartesianCell &cell)
    5384             :     {
    5385             : 
    5386             :         // SUBROUTINE INFORMATION:
    5387             :         //       AUTHOR         Edwin Lee
    5388             :         //       DATE WRITTEN   Summer 2011
    5389             :         //       MODIFIED       na
    5390             :         //       RE-ENGINEERED  na
    5391             : 
    5392             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5393             :         Real64 OuterNeighborRadialCellRadialCentroid;
    5394             :         Real64 OuterNeighborRadialCellConductivity;
    5395             :         Real64 OuterNeighborRadialCellInnerRadius;
    5396             :         Real64 OuterNeighborRadialCellTemperature;
    5397             : 
    5398     7437826 :         Real64 Numerator = 0.0;
    5399     7437826 :         Real64 Denominator = 0.0;
    5400             : 
    5401             :         //'convenience variables
    5402     7437826 :         if (thisCircuit->HasInsulation) {
    5403           0 :             OuterNeighborRadialCellRadialCentroid = cell.PipeCellData.Insulation.RadialCentroid;
    5404           0 :             OuterNeighborRadialCellConductivity = cell.PipeCellData.Insulation.Properties.Conductivity;
    5405           0 :             OuterNeighborRadialCellInnerRadius = cell.PipeCellData.Insulation.InnerRadius;
    5406           0 :             OuterNeighborRadialCellTemperature = cell.PipeCellData.Insulation.Temperature;
    5407             :         } else {
    5408     7437826 :             auto const &soilZero = cell.PipeCellData.Soil[0];
    5409     7437826 :             OuterNeighborRadialCellRadialCentroid = soilZero.RadialCentroid;
    5410     7437826 :             OuterNeighborRadialCellConductivity = soilZero.Properties.Conductivity;
    5411     7437826 :             OuterNeighborRadialCellInnerRadius = soilZero.InnerRadius;
    5412     7437826 :             OuterNeighborRadialCellTemperature = soilZero.Temperature;
    5413             :         }
    5414             : 
    5415     7437826 :         Real64 const ThisPipeCellOuterRadius = cell.PipeCellData.Pipe.OuterRadius;
    5416     7437826 :         Real64 const ThisPipeCellRadialCentroid = cell.PipeCellData.Pipe.RadialCentroid;
    5417     7437826 :         Real64 const ThisPipeCellConductivity = cell.PipeCellData.Pipe.Properties.Conductivity;
    5418     7437826 :         Real64 const ThisPipeCellInnerRadius = cell.PipeCellData.Pipe.InnerRadius;
    5419     7437826 :         Real64 const ThisPipeCellTemperature_PrevTimeStep = cell.PipeCellData.Pipe.Temperature_PrevTimeStep;
    5420             : 
    5421     7437826 :         Real64 const FluidCellTemperature = cell.PipeCellData.Fluid.Temperature;
    5422             : 
    5423             :         //'add effects from this cell history
    5424     7437826 :         Numerator += ThisPipeCellTemperature_PrevTimeStep;
    5425     7437826 :         ++Denominator;
    5426             : 
    5427             :         //'add effects from outer radial cell
    5428             :         Real64 Resistance =
    5429    14875652 :             (std::log(OuterNeighborRadialCellRadialCentroid / OuterNeighborRadialCellInnerRadius) /
    5430     7437826 :              (2 * Constant::Pi * cell.depth() * OuterNeighborRadialCellConductivity)) +
    5431     7437826 :             (std::log(ThisPipeCellOuterRadius / ThisPipeCellRadialCentroid) / (2 * Constant::Pi * cell.depth() * ThisPipeCellConductivity));
    5432     7437826 :         Numerator += (cell.PipeCellData.Pipe.Beta / Resistance) * OuterNeighborRadialCellTemperature;
    5433     7437826 :         Denominator += (cell.PipeCellData.Pipe.Beta / Resistance);
    5434             : 
    5435             :         //'add effects from water cell
    5436             :         Real64 PipeConductionResistance =
    5437     7437826 :             std::log(ThisPipeCellRadialCentroid / ThisPipeCellInnerRadius) / (2 * Constant::Pi * cell.depth() * ThisPipeCellConductivity);
    5438             :         Real64 ConvectiveResistance =
    5439     7437826 :             1.0 / (thisCircuit->CurCircuitConvectionCoefficient * 2 * Constant::Pi * ThisPipeCellInnerRadius * cell.depth());
    5440     7437826 :         Resistance = PipeConductionResistance + ConvectiveResistance;
    5441     7437826 :         Numerator += (cell.PipeCellData.Pipe.Beta / Resistance) * FluidCellTemperature;
    5442     7437826 :         Denominator += (cell.PipeCellData.Pipe.Beta / Resistance);
    5443             : 
    5444             :         //'calculate new temperature
    5445     7437826 :         cell.PipeCellData.Pipe.Temperature = Numerator / Denominator;
    5446     7437826 :     }
    5447             : 
    5448     7437826 :     void SimulateFluidCell(Circuit *thisCircuit, CartesianCell &cell, Real64 const FlowRate, Real64 const EnteringFluidTemp)
    5449             :     {
    5450             : 
    5451             :         // SUBROUTINE INFORMATION:
    5452             :         //       AUTHOR         Edwin Lee
    5453             :         //       DATE WRITTEN   Summer 2011
    5454             :         //       MODIFIED       na
    5455             :         //       RE-ENGINEERED  na
    5456             : 
    5457             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5458     7437826 :         Real64 Numerator = 0.0;
    5459     7437826 :         Real64 Denominator = 0.0;
    5460             : 
    5461             :         //'convenience variables
    5462     7437826 :         Real64 const FluidCellTemperature_PrevTimeStep = cell.PipeCellData.Fluid.Temperature_PrevTimeStep;
    5463     7437826 :         Real64 const FluidCellSpecificHeat = cell.PipeCellData.Fluid.Properties.SpecificHeat;
    5464             : 
    5465     7437826 :         Real64 const PipeCellRadialCentroid = cell.PipeCellData.Pipe.RadialCentroid;
    5466     7437826 :         Real64 const PipeCellConductivity = cell.PipeCellData.Pipe.Properties.Conductivity;
    5467     7437826 :         Real64 const PipeCellInnerRadius = cell.PipeCellData.Pipe.InnerRadius;
    5468     7437826 :         Real64 const PipeCellTemperature = cell.PipeCellData.Pipe.Temperature;
    5469             : 
    5470             :         //'add effects from this cell history
    5471     7437826 :         Numerator += FluidCellTemperature_PrevTimeStep;
    5472     7437826 :         ++Denominator;
    5473             : 
    5474             :         //'add effects from outer pipe cell
    5475             :         Real64 PipeConductionResistance =
    5476     7437826 :             std::log(PipeCellRadialCentroid / PipeCellInnerRadius) / (2 * Constant::Pi * cell.depth() * PipeCellConductivity);
    5477     7437826 :         Real64 ConvectiveResistance = 1.0 / (thisCircuit->CurCircuitConvectionCoefficient * 2 * Constant::Pi * PipeCellInnerRadius * cell.depth());
    5478     7437826 :         Real64 TotalPipeResistance = PipeConductionResistance + ConvectiveResistance;
    5479     7437826 :         Numerator += (cell.PipeCellData.Fluid.Beta / TotalPipeResistance) * PipeCellTemperature;
    5480     7437826 :         Denominator += (cell.PipeCellData.Fluid.Beta / TotalPipeResistance);
    5481             : 
    5482             :         //'add effects from upstream flow
    5483     7437826 :         if (FlowRate > 0.0) {
    5484     7393222 :             Real64 UpstreamResistance = 1 / (FlowRate * FluidCellSpecificHeat);
    5485     7393222 :             Numerator += (cell.PipeCellData.Fluid.Beta / UpstreamResistance) * EnteringFluidTemp;
    5486     7393222 :             Denominator += (cell.PipeCellData.Fluid.Beta / UpstreamResistance);
    5487             :         }
    5488             : 
    5489             :         //'calculate new temperature
    5490     7437826 :         cell.PipeCellData.Fluid.Temperature = Numerator / Denominator;
    5491     7437826 :     }
    5492             : 
    5493          37 :     void Domain::DoOneTimeInitializations(EnergyPlusData &state, Circuit *thisCircuit)
    5494             :     {
    5495             : 
    5496             :         // SUBROUTINE INFORMATION:
    5497             :         //       AUTHOR         Edwin Lee
    5498             :         //       DATE WRITTEN   Summer 2011
    5499             :         //       MODIFIED       na
    5500             :         //       RE-ENGINEERED  na
    5501             : 
    5502             :         //'initialize cell properties
    5503         472 :         for (int X = 0, X_end = this->x_max_index; X <= X_end; ++X) {
    5504        5978 :             for (int Y = 0, Y_end = this->y_max_index; Y <= Y_end; ++Y) {
    5505       58517 :                 for (int Z = 0, Z_end = this->z_max_index; Z <= Z_end; ++Z) {
    5506       52974 :                     auto &cell = this->Cells(X, Y, Z);
    5507       52974 :                     switch (cell.cellType) {
    5508         400 :                     case CellType::Pipe:
    5509         400 :                         cell.Properties = this->GroundProperties;
    5510        1280 :                         for (auto &soilCell : cell.PipeCellData.Soil) {
    5511         880 :                             soilCell.Properties = this->GroundProperties;
    5512         400 :                         }
    5513         400 :                         if (thisCircuit) {
    5514         400 :                             cell.PipeCellData.Pipe.Properties = thisCircuit->PipeProperties;
    5515         400 :                             if (thisCircuit->HasInsulation) {
    5516           0 :                                 cell.PipeCellData.Insulation.Properties = thisCircuit->InsulationProperties;
    5517             :                             }
    5518             :                         }
    5519         400 :                         break;
    5520       45010 :                     case CellType::GeneralField:
    5521             :                     case CellType::GroundSurface:
    5522             :                     case CellType::FarfieldBoundary:
    5523       45010 :                         cell.Properties = this->GroundProperties;
    5524       45010 :                         break;
    5525         996 :                     case CellType::BasementWall:
    5526             :                     case CellType::BasementFloor:
    5527             :                     case CellType::BasementCorner:
    5528         996 :                         if (this->HasZoneCoupledBasement) { // Basement interface layer
    5529         486 :                             cell.Properties = this->BasementInterfaceProperties;
    5530             :                         } else { // Basement cells are partially ground, give them some props
    5531         510 :                             cell.Properties = this->GroundProperties;
    5532             :                         }
    5533         996 :                         break;
    5534        1728 :                     case CellType::Slab:
    5535        1728 :                         cell.Properties = this->SlabProperties;
    5536        1728 :                         break;
    5537         400 :                     case CellType::HorizInsulation:
    5538         400 :                         cell.Properties = this->HorizInsProperties;
    5539         400 :                         break;
    5540        1782 :                     case CellType::VertInsulation:
    5541        1782 :                         cell.Properties = this->VertInsProperties;
    5542        1782 :                         break;
    5543         360 :                     case CellType::ZoneGroundInterface:
    5544         360 :                         if (this->SlabInGradeFlag) {
    5545         288 :                             cell.Properties = this->SlabProperties;
    5546             :                         } else {
    5547          72 :                             cell.Properties = this->GroundProperties;
    5548             :                         }
    5549         360 :                         break;
    5550        2298 :                     case CellType::BasementCutaway:
    5551        2298 :                         break;
    5552           0 :                     default:
    5553           0 :                         assert(false);
    5554             :                     }
    5555             :                 }
    5556             :             }
    5557             :         }
    5558             : 
    5559             :         //'calculate one-time resistance terms for cartesian cells
    5560         472 :         for (int X = 0, X_end = this->x_max_index; X <= X_end; ++X) {
    5561        5978 :             for (int Y = 0, Y_end = this->y_max_index; Y <= Y_end; ++Y) {
    5562       58517 :                 for (int Z = 0, Z_end = this->z_max_index; Z <= Z_end; ++Z) {
    5563       52974 :                     auto &cell = this->Cells(X, Y, Z);
    5564       52974 :                     int NumFieldCells = 0, NumBoundaryCells = 0;
    5565       52974 :                     this->EvaluateCellNeighborDirections(cell, NumFieldCells, NumBoundaryCells);
    5566      344416 :                     for (int DirectionCtr = 0; DirectionCtr <= NumFieldCells; ++DirectionCtr) {
    5567      291442 :                         Direction CurDirection = this->NeighborFieldCells[DirectionCtr];
    5568      291442 :                         Real64 AdiabaticMultiplier = 1.0, NeighborTemp = 0.0, Resistance = 0.0;
    5569      291442 :                         this->EvaluateNeighborCharacteristics(cell, CurDirection, NeighborTemp, Resistance, AdiabaticMultiplier);
    5570      291442 :                         int NX = 0, NY = 0, NZ = 0;
    5571      291442 :                         cell.EvaluateNeighborCoordinates(CurDirection, NX, NY, NZ);
    5572             :                     }
    5573             :                 }
    5574             :             }
    5575             :         }
    5576             : 
    5577             :         //'initialize freezing calculation variables
    5578          37 :         this->InitializeSoilMoistureCalcs();
    5579             : 
    5580             :         //'we can also initialize the domain based on the farfield temperature here
    5581         472 :         for (int X = 0, X_end = this->x_max_index; X <= X_end; ++X) {
    5582        5978 :             for (int Y = 0, Y_end = this->y_max_index; Y <= Y_end; ++Y) {
    5583       58517 :                 for (int Z = 0, Z_end = this->z_max_index; Z <= Z_end; ++Z) {
    5584       52974 :                     auto &cell = this->Cells(X, Y, Z);
    5585             : 
    5586             :                     // On OneTimeInit, the cur sim time should be zero, so this will be OK
    5587       52974 :                     Real64 ThisCellTemp = this->GetFarfieldTemp(state, cell);
    5588       52974 :                     cell.Temperature = ThisCellTemp;
    5589       52974 :                     cell.Temperature_PrevIteration = ThisCellTemp;
    5590       52974 :                     cell.Temperature_PrevTimeStep = ThisCellTemp;
    5591             : 
    5592       52974 :                     if (cell.cellType == CellType::Pipe) {
    5593             : 
    5594        1280 :                         for (auto &soilCell : cell.PipeCellData.Soil) {
    5595         880 :                             soilCell.Temperature = ThisCellTemp;
    5596         880 :                             soilCell.Temperature_PrevIteration = ThisCellTemp;
    5597         880 :                             soilCell.Temperature_PrevTimeStep = ThisCellTemp;
    5598         400 :                         }
    5599         400 :                         cell.PipeCellData.Pipe.Temperature = ThisCellTemp;
    5600         400 :                         cell.PipeCellData.Pipe.Temperature_PrevIteration = ThisCellTemp;
    5601         400 :                         cell.PipeCellData.Pipe.Temperature_PrevTimeStep = ThisCellTemp;
    5602         400 :                         if (thisCircuit) {
    5603         400 :                             if (thisCircuit->HasInsulation) {
    5604           0 :                                 cell.PipeCellData.Insulation.Temperature = ThisCellTemp;
    5605           0 :                                 cell.PipeCellData.Insulation.Temperature_PrevIteration = ThisCellTemp;
    5606           0 :                                 cell.PipeCellData.Insulation.Temperature_PrevTimeStep = ThisCellTemp;
    5607             :                             }
    5608             :                         }
    5609         400 :                         cell.PipeCellData.Fluid.Temperature = ThisCellTemp;
    5610         400 :                         cell.PipeCellData.Fluid.Temperature_PrevIteration = ThisCellTemp;
    5611         400 :                         cell.PipeCellData.Fluid.Temperature_PrevTimeStep = ThisCellTemp;
    5612             :                     }
    5613             :                 }
    5614             :             }
    5615             :         }
    5616          37 :     }
    5617             : 
    5618       27942 :     void Domain::DoStartOfTimeStepInitializations(EnergyPlusData &state)
    5619             :     {
    5620             :         // Update environmental conditions
    5621       27942 :         this->Cur.CurAirTemp = state.dataEnvrn->OutDryBulbTemp;
    5622       27942 :         this->Cur.CurWindSpeed = state.dataEnvrn->WindSpeed;
    5623       27942 :         this->Cur.CurRelativeHumidity = state.dataEnvrn->OutRelHum;
    5624       27942 :         this->Cur.CurIncidentSolar = state.dataEnvrn->BeamSolarRad * max(state.dataEnvrn->SOLCOS(3), 0.0);
    5625             : 
    5626             :         //'now update cell properties
    5627       27942 :         auto &cells = this->Cells;
    5628      428250 :         for (int X = 0, X_end = this->x_max_index; X <= X_end; ++X) {
    5629     6819000 :             for (int Y = 0, Y_end = this->y_max_index; Y <= Y_end; ++Y) {
    5630    67177008 :                 for (int Z = 0, Z_end = this->z_max_index; Z <= Z_end; ++Z) {
    5631    60758316 :                     auto &cell = cells(X, Y, Z);
    5632    60758316 :                     switch (cell.cellType) {
    5633    52467960 :                     case CellType::GeneralField:
    5634             :                     case CellType::FarfieldBoundary:
    5635             :                     case CellType::GroundSurface:
    5636             :                     case CellType::BasementCorner:
    5637             :                     case CellType::BasementFloor:
    5638             :                     case CellType::BasementWall:
    5639             :                         // UPDATE CELL PROPERTY SETS
    5640             :                         //'main ground cells, update with soil properties
    5641             :                         Real64 CellRhoCp;
    5642    52467960 :                         this->EvaluateSoilRhoCp(cell.Temperature, CellRhoCp);
    5643    52467960 :                         cell.Properties.SpecificHeat = CellRhoCp / cell.Properties.Density;
    5644             :                         // UPDATE BETA VALUE
    5645             :                         //'these are basic cartesian calculation cells
    5646    52467960 :                         cell.Beta = this->Cur.CurSimTimeStepSize / (cell.Properties.Density * cell.volume() * cell.Properties.SpecificHeat);
    5647    52467960 :                         break;
    5648     3981696 :                     case CellType::HorizInsulation:
    5649             :                     case CellType::VertInsulation:
    5650             :                     case CellType::Slab:
    5651             :                     case CellType::ZoneGroundInterface:
    5652     7963392 :                         this->Cells(X, Y, Z).Beta =
    5653     3981696 :                             this->Cur.CurSimTimeStepSize / (cell.Properties.Density * cell.volume() * cell.Properties.SpecificHeat);
    5654     3981696 :                         break;
    5655      434148 :                     case CellType::Pipe:
    5656             :                         // No pipe circuit with this call
    5657      434148 :                         break;
    5658     3874512 :                     case CellType::BasementCutaway:
    5659     3874512 :                         break;
    5660           0 :                     default:
    5661           0 :                         assert(false);
    5662             :                     }
    5663             :                 }
    5664             :             }
    5665             :         }
    5666       27942 :     }
    5667             : 
    5668       14502 :     void Domain::DoStartOfTimeStepInitializations(EnergyPlusData &state, Circuit *thisCircuit)
    5669             :     {
    5670             : 
    5671             :         // SUBROUTINE INFORMATION:
    5672             :         //       AUTHOR         Edwin Lee
    5673             :         //       DATE WRITTEN   Summer 2011
    5674             :         //       MODIFIED       na
    5675             :         //       RE-ENGINEERED  na
    5676             : 
    5677             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5678             :         static constexpr std::string_view RoutineName("PipingSystemCircuit::DoStartOfTimeStepInitializations");
    5679             :         Real64 CellTemp;
    5680             :         Real64 CellRhoCp;
    5681             :         Real64 FluidCp;
    5682             :         Real64 FluidDensity;
    5683             :         Real64 FluidConductivity;
    5684             :         Real64 FluidViscosity;
    5685             :         Real64 FluidPrandtl;
    5686             : 
    5687             :         // do the regular, non-circuit related inits
    5688       14502 :         this->DoStartOfTimeStepInitializations(state);
    5689             : 
    5690             :         // retrieve fluid properties based on the circuit inlet temperature -- which varies during the simulation
    5691             :         // but need to verify the value of inlet temperature during warm up, etc.
    5692       14502 :         FluidCp = FluidProperties::GetSpecificHeatGlycol(state,
    5693       14502 :                                                          state.dataPlnt->PlantLoop(thisCircuit->plantLoc.loopNum).FluidName,
    5694             :                                                          thisCircuit->InletTemperature,
    5695       14502 :                                                          state.dataPlnt->PlantLoop(thisCircuit->plantLoc.loopNum).FluidIndex,
    5696             :                                                          RoutineName);
    5697       14502 :         FluidDensity = FluidProperties::GetDensityGlycol(state,
    5698       14502 :                                                          state.dataPlnt->PlantLoop(thisCircuit->plantLoc.loopNum).FluidName,
    5699             :                                                          thisCircuit->InletTemperature,
    5700       14502 :                                                          state.dataPlnt->PlantLoop(thisCircuit->plantLoc.loopNum).FluidIndex,
    5701             :                                                          RoutineName);
    5702       14502 :         FluidConductivity = FluidProperties::GetConductivityGlycol(state,
    5703       14502 :                                                                    state.dataPlnt->PlantLoop(thisCircuit->plantLoc.loopNum).FluidName,
    5704             :                                                                    thisCircuit->InletTemperature,
    5705       14502 :                                                                    state.dataPlnt->PlantLoop(thisCircuit->plantLoc.loopNum).FluidIndex,
    5706             :                                                                    RoutineName);
    5707       14502 :         FluidViscosity = FluidProperties::GetViscosityGlycol(state,
    5708       14502 :                                                              state.dataPlnt->PlantLoop(thisCircuit->plantLoc.loopNum).FluidName,
    5709             :                                                              thisCircuit->InletTemperature,
    5710       14502 :                                                              state.dataPlnt->PlantLoop(thisCircuit->plantLoc.loopNum).FluidIndex,
    5711             :                                                              RoutineName);
    5712             : 
    5713             :         // Doesn't anyone care about poor Ludwig Prandtl?
    5714       14502 :         FluidPrandtl = 3.0;
    5715             : 
    5716             :         // then assign these fluid properties to the current fluid property set for easy lookup as needed
    5717       14502 :         thisCircuit->CurFluidPropertySet.Conductivity = FluidConductivity;
    5718       14502 :         thisCircuit->CurFluidPropertySet.Density = FluidDensity;
    5719       14502 :         thisCircuit->CurFluidPropertySet.SpecificHeat = FluidCp;
    5720       14502 :         thisCircuit->CurFluidPropertySet.Viscosity = FluidViscosity;
    5721       14502 :         thisCircuit->CurFluidPropertySet.Prandtl = FluidPrandtl;
    5722             : 
    5723             :         //'now update cell properties
    5724       14502 :         auto &cells = this->Cells;
    5725      234522 :         for (int X = 0, X_end = this->x_max_index; X <= X_end; ++X) {
    5726     3608664 :             for (int Y = 0, Y_end = this->y_max_index; Y <= Y_end; ++Y) {
    5727    23503536 :                 for (int Z = 0, Z_end = this->z_max_index; Z <= Z_end; ++Z) {
    5728    20114892 :                     auto &cell = cells(X, Y, Z);
    5729    20114892 :                     if (cell.cellType == CellType::Pipe) {
    5730             :                         // UPDATE CELL PROPERTY SETS
    5731             :                         //'first update the outer cell itself
    5732      434148 :                         CellTemp = cell.Temperature;
    5733      434148 :                         this->EvaluateSoilRhoCp(CellTemp, CellRhoCp);
    5734      434148 :                         cell.Properties.SpecificHeat = CellRhoCp / cell.Properties.Density;
    5735             :                         //'then update all the soil radial cells
    5736     1316220 :                         for (auto &soilCell : cell.PipeCellData.Soil) {
    5737      882072 :                             CellTemp = soilCell.Temperature;
    5738      882072 :                             this->EvaluateSoilRhoCp(CellTemp, CellRhoCp);
    5739      882072 :                             soilCell.Properties.SpecificHeat = CellRhoCp / soilCell.Properties.Density;
    5740      434148 :                         }
    5741             : 
    5742             :                         // UPDATE BETA VALUES
    5743             :                         //'set the interface cell
    5744      434148 :                         cell.Beta = this->Cur.CurSimTimeStepSize /
    5745      434148 :                                     (cell.Properties.Density * cell.PipeCellData.InterfaceVolume * cell.Properties.SpecificHeat);
    5746             : 
    5747             :                         //'set the radial soil cells
    5748     1316220 :                         for (auto &soilCell : cell.PipeCellData.Soil) {
    5749      882072 :                             soilCell.Beta = this->Cur.CurSimTimeStepSize / (soilCell.Properties.Density * soilCell.XY_CrossSectArea() * cell.depth() *
    5750      882072 :                                                                             soilCell.Properties.SpecificHeat);
    5751      434148 :                         }
    5752             : 
    5753             :                         //'then insulation if it exists
    5754      434148 :                         if (thisCircuit->HasInsulation) {
    5755           0 :                             cell.PipeCellData.Insulation.Beta =
    5756           0 :                                 this->Cur.CurSimTimeStepSize /
    5757           0 :                                 (cell.PipeCellData.Insulation.Properties.Density * cell.PipeCellData.Insulation.XY_CrossSectArea() * cell.depth() *
    5758           0 :                                  cell.PipeCellData.Insulation.Properties.SpecificHeat);
    5759             :                         }
    5760             : 
    5761             :                         //'set the pipe cell
    5762      434148 :                         cell.PipeCellData.Pipe.Beta =
    5763      434148 :                             this->Cur.CurSimTimeStepSize / (cell.PipeCellData.Pipe.Properties.Density * cell.PipeCellData.Pipe.XY_CrossSectArea() *
    5764      434148 :                                                             cell.depth() * cell.PipeCellData.Pipe.Properties.SpecificHeat);
    5765             : 
    5766             :                         // now the fluid cell also
    5767      434148 :                         cell.PipeCellData.Fluid.Properties = thisCircuit->CurFluidPropertySet;
    5768      434148 :                         cell.PipeCellData.Fluid.Beta =
    5769      434148 :                             this->Cur.CurSimTimeStepSize / (cell.PipeCellData.Fluid.Properties.Density * cell.PipeCellData.Fluid.Volume *
    5770      434148 :                                                             cell.PipeCellData.Fluid.Properties.SpecificHeat);
    5771             :                     }
    5772             :                 }
    5773             :             }
    5774             :         }
    5775       14502 :     }
    5776             : 
    5777      125516 :     void Domain::DoEndOfIterationOperations(EnergyPlusData &state, bool &Finished)
    5778             :     {
    5779             : 
    5780             :         // SUBROUTINE INFORMATION:
    5781             :         //       AUTHOR         Edwin Lee
    5782             :         //       DATE WRITTEN   Summer 2011
    5783             :         //       MODIFIED       na
    5784             :         //       RE-ENGINEERED  na
    5785             : 
    5786             :         // SUBROUTINE PARAMETER DEFINITIONS:
    5787             :         static constexpr std::string_view RoutineName("DoEndOfIterationOperations");
    5788             : 
    5789             :         //'check if we have converged for this iteration
    5790      125516 :         Finished = this->IsConverged_CurrentToPrevIteration();
    5791             : 
    5792             :         //'check for out of range temperatures here so they aren't plotted
    5793             :         //'this routine should be *much* more restrictive than the exceptions, so we should be safe with this location
    5794      125516 :         bool OutOfRange = this->CheckForOutOfRangeTemps();
    5795      125516 :         if (OutOfRange) {
    5796           0 :             if (this->HasZoneCoupledSlab) {
    5797           0 :                 ShowSevereError(state, format("Site:GroundDomain:Slab{}: Out of range temperatures detected in the ground domain.", RoutineName));
    5798           0 :                 ShowContinueError(state, "This could be due to the size of the loads on the domain.");
    5799           0 :                 ShowContinueError(state, "Verify inputs are correct. If problem persists, notify EnergyPlus support.");
    5800           0 :                 ShowFatalError(state, "Preceding error(s) cause program termination");
    5801           0 :             } else if (this->HasZoneCoupledBasement) {
    5802           0 :                 ShowSevereError(state, format("Site:GroundDomain:Basement{}: Out of range temperatures detected in the ground domain.", RoutineName));
    5803           0 :                 ShowContinueError(state, "This could be due to the size of the loads on the domain.");
    5804           0 :                 ShowContinueError(state, "Verify inputs are correct. If problem persists, notify EnergyPlus support.");
    5805           0 :                 ShowFatalError(state, "Preceding error(s) cause program termination");
    5806             :             } else {
    5807           0 :                 ShowSevereError(state, format("PipingSystems:{}: Out of range temperatures detected in piping system simulation.", RoutineName));
    5808           0 :                 ShowContinueError(state, "This could be due to the size of the pipe circuit in relation to the loads being imposed.");
    5809           0 :                 ShowContinueError(state, "Try increasing the size of the pipe circuit and investigate sizing effects.");
    5810           0 :                 ShowFatalError(state, "Preceding error(s) cause program termination");
    5811             :             }
    5812             :         }
    5813      125516 :     }
    5814             : 
    5815          37 :     void Domain::InitializeSoilMoistureCalcs()
    5816             :     {
    5817             : 
    5818             :         // These vary by domain now, so we must be careful to retrieve them every time
    5819          37 :         Real64 const Theta_liq = this->Moisture.Theta_liq;
    5820          37 :         Real64 const Theta_sat = this->Moisture.Theta_sat;
    5821             : 
    5822             :         // Assumption
    5823          37 :         Real64 const Theta_ice = Theta_liq;
    5824             : 
    5825             :         //'Cp (freezing) calculations
    5826          37 :         Real64 constexpr rho_ice = 917.0;  //'Kg / m3
    5827          37 :         Real64 constexpr rho_liq = 1000.0; //'kg / m3
    5828             : 
    5829             :         //'from( " An improved model for predicting soil thermal conductivity from water content at room temperature, Fig 4" )
    5830          37 :         Real64 constexpr CP_liq = 4180.0;    //'J / KgK
    5831          37 :         Real64 constexpr CP_ice = 2066.0;    //'J / KgK
    5832          37 :         Real64 constexpr Lat_fus = 334000.0; //'J / Kg
    5833          37 :         Real64 const Cp_transient = Lat_fus / 0.4 + (0.5 * CP_ice - (CP_liq + CP_ice) / 2.0 * 0.1) / 0.4;
    5834             : 
    5835             :         //'from( " Numerical and experimental investigation of melting and freezing processes in phase change material storage" )
    5836          37 :         this->Moisture.rhoCp_soil_liq_1 = 1225000.0 / (1.0 - Theta_sat); //'J/m3K
    5837          37 :         this->Moisture.rhoCP_soil_liq = this->Moisture.rhoCp_soil_liq_1 * (1.0 - Theta_sat) + rho_liq * CP_liq * Theta_liq;
    5838          37 :         this->Moisture.rhoCP_soil_transient =
    5839          37 :             this->Moisture.rhoCp_soil_liq_1 * (1.0 - Theta_sat) + ((rho_liq + rho_ice) / 2.0) * Cp_transient * Theta_ice;
    5840          37 :         this->Moisture.rhoCP_soil_ice = this->Moisture.rhoCp_soil_liq_1 * (1.0 - Theta_sat) + rho_ice * CP_ice * Theta_ice; //'!J / m3K
    5841          37 :     }
    5842             : 
    5843    53784180 :     void Domain::EvaluateSoilRhoCp(Real64 const CellTemp, Real64 &rhoCp) const
    5844             :     {
    5845             : 
    5846             :         // SUBROUTINE INFORMATION:
    5847             :         //       AUTHOR         Edwin Lee
    5848             :         //       DATE WRITTEN   Summer 2011
    5849             :         //       MODIFIED       na
    5850             :         //       RE-ENGINEERED  na
    5851             : 
    5852             :         //'set some temperatures here for generalization -- these could be set in the input file
    5853    53784180 :         Real64 constexpr frzAllIce = -0.5;
    5854    53784180 :         Real64 constexpr frzIceTrans = -0.4;
    5855    53784180 :         Real64 constexpr frzLiqTrans = -0.1;
    5856    53784180 :         Real64 constexpr frzAllLiq = 0.0;
    5857             : 
    5858             :         //'calculate this cell's new Cp value based on the cell temperature
    5859    53784180 :         if (CellTemp <= frzAllIce) { // totally frozen
    5860     2682640 :             rhoCp = this->Moisture.rhoCP_soil_ice;
    5861    51101540 :         } else if ((CellTemp > frzAllIce) && (CellTemp < frzIceTrans)) { // in between totally frozen and ice transition
    5862       61285 :             rhoCp = this->Moisture.rhoCP_soil_ice +
    5863       61285 :                     (this->Moisture.rhoCP_soil_transient - this->Moisture.rhoCP_soil_ice) / (frzIceTrans - frzAllIce) * (CellTemp - frzAllIce);
    5864    51040255 :         } else if ((CellTemp >= frzIceTrans) && (CellTemp <= frzLiqTrans)) { // in between ice transition and liquid transition
    5865      470341 :             rhoCp = this->Moisture.rhoCP_soil_transient;
    5866    50569914 :         } else if ((CellTemp > frzLiqTrans) && (CellTemp < frzAllLiq)) { // in between liquid transition and all liquid
    5867      178479 :             rhoCp = this->Moisture.rhoCp_soil_liq_1 +
    5868      178479 :                     (this->Moisture.rhoCP_soil_transient - this->Moisture.rhoCP_soil_liq) / (frzAllLiq - frzLiqTrans) * (frzAllLiq - CellTemp);
    5869             :         } else { // ( CellTemp >= frzAllLiq ) --- greater than or equal to all liquid
    5870    50391435 :             rhoCp = this->Moisture.rhoCp_soil_liq_1;
    5871             :         }
    5872    53784180 :     }
    5873             : 
    5874  1604239368 :     void CartesianCell::EvaluateNeighborCoordinates(Direction const CurDirection, int &NX, int &NY, int &NZ) const
    5875             :     {
    5876             : 
    5877             :         // SUBROUTINE INFORMATION:
    5878             :         //       AUTHOR         Edwin Lee
    5879             :         //       DATE WRITTEN   Summer 2011
    5880             :         //       MODIFIED       na
    5881             :         //       RE-ENGINEERED  na
    5882             : 
    5883  1604239368 :         int const X = this->X_index;
    5884  1604239368 :         int const Y = this->Y_index;
    5885  1604239368 :         int const Z = this->Z_index;
    5886             : 
    5887  1604239368 :         switch (CurDirection) {
    5888   273842958 :         case Direction::PositiveY:
    5889   273842958 :             NX = X;
    5890   273842958 :             NY = Y + 1;
    5891   273842958 :             NZ = Z;
    5892   273842958 :             break;
    5893   273842958 :         case Direction::NegativeY:
    5894   273842958 :             NX = X;
    5895   273842958 :             NY = Y - 1;
    5896   273842958 :             NZ = Z;
    5897   273842958 :             break;
    5898   271766543 :         case Direction::PositiveX:
    5899   271766543 :             NX = X + 1;
    5900   271766543 :             NY = Y;
    5901   271766543 :             NZ = Z;
    5902   271766543 :             break;
    5903   271766543 :         case Direction::NegativeX:
    5904   271766543 :             NX = X - 1;
    5905   271766543 :             NY = Y;
    5906   271766543 :             NZ = Z;
    5907   271766543 :             break;
    5908   256510183 :         case Direction::PositiveZ:
    5909   256510183 :             NX = X;
    5910   256510183 :             NY = Y;
    5911   256510183 :             NZ = Z + 1;
    5912   256510183 :             break;
    5913   256510183 :         case Direction::NegativeZ:
    5914   256510183 :             NX = X;
    5915   256510183 :             NY = Y;
    5916   256510183 :             NZ = Z - 1;
    5917   256510183 :             break;
    5918           0 :         default:
    5919           0 :             assert(false);
    5920             :         }
    5921  1604239368 :     }
    5922             : 
    5923  1603947926 :     void Domain::EvaluateNeighborCharacteristics(
    5924             :         CartesianCell &ThisCell, Direction const CurDirection, Real64 &NeighborTemp, Real64 &Resistance, Real64 &AdiabaticMultiplier)
    5925             :     {
    5926             : 
    5927             :         // SUBROUTINE INFORMATION:
    5928             :         //       AUTHOR         Edwin Lee
    5929             :         //       DATE WRITTEN   Summer 2011
    5930             :         //       MODIFIED       na
    5931             :         //       RE-ENGINEERED  na
    5932             : 
    5933  1603947926 :         int NX = 0, NY = 0, NZ = 0;
    5934  1603947926 :         ThisCell.EvaluateNeighborCoordinates(CurDirection, NX, NY, NZ);
    5935             : 
    5936             :         //'split effects between the two cells so we can carefully calculate resistance values
    5937             :         Real64 ThisCellLength;
    5938             :         Real64 NeighborCellLength;
    5939  1603947926 :         Real64 ThisCellConductivity = 10000.0;
    5940  1603947926 :         if (ThisCell.Properties.Conductivity > 0.0) ThisCellConductivity = ThisCell.Properties.Conductivity;
    5941  1603947926 :         Real64 NeighborConductivity = 10000.0;
    5942  1603947926 :         auto const &cell = this->Cells(NX, NY, NZ);
    5943  1603947926 :         if (cell.Properties.Conductivity > 0.0) NeighborConductivity = cell.Properties.Conductivity;
    5944             : 
    5945             :         //'calculate normal surface area
    5946  1603947926 :         Real64 const ThisNormalArea = ThisCell.normalArea(CurDirection);
    5947             : 
    5948             :         //'set distance based on cell types
    5949  1603947926 :         auto const &TempNeighborInfo = ThisCell.NeighborInfo[CurDirection];
    5950  1603947926 :         if (ThisCell.cellType == CellType::Pipe) {
    5951             :             //'we need to be a bit careful with pipes, as they are full centroid to centroid in the z direction,
    5952             :             //' but only centroid to wall in the x and y directions
    5953    29753564 :             if (CurDirection == Direction::NegativeZ || CurDirection == Direction::PositiveZ) {
    5954         660 :                 ThisCellLength = TempNeighborInfo.ThisCentroidToNeighborWall;
    5955         660 :                 NeighborCellLength = TempNeighborInfo.ThisWallToNeighborCentroid;
    5956             :             } else {
    5957    29752904 :                 ThisCellLength = 0.0;
    5958    29752904 :                 NeighborCellLength = TempNeighborInfo.ThisWallToNeighborCentroid;
    5959             :             }
    5960  1574194362 :         } else if (cell.cellType == CellType::Pipe) {
    5961     5581248 :             ThisCellLength = TempNeighborInfo.ThisCentroidToNeighborWall;
    5962     5581248 :             NeighborCellLength = 0.0;
    5963             :         } else {
    5964  1568613114 :             ThisCellLength = TempNeighborInfo.ThisCentroidToNeighborWall;
    5965  1568613114 :             NeighborCellLength = TempNeighborInfo.ThisWallToNeighborCentroid;
    5966             :         }
    5967             : 
    5968             :         //'calculate resistance based on different conductivities between the two cells
    5969  1603947926 :         Resistance = (ThisCellLength / (ThisNormalArea * ThisCellConductivity)) + (NeighborCellLength / (ThisNormalArea * NeighborConductivity));
    5970             : 
    5971             :         //'return proper temperature for the given simulation type
    5972  1603947926 :         NeighborTemp = cell.Temperature;
    5973             : 
    5974             :         //'return the adiabatic multiplier
    5975  1603947926 :         AdiabaticMultiplier = TempNeighborInfo.adiabaticMultiplier;
    5976  1603947926 :     }
    5977             : 
    5978   283224327 :     void Domain::EvaluateCellNeighborDirections(CartesianCell const &cell, int &NumFieldCells, int &NumBoundaryCells)
    5979             :     {
    5980             : 
    5981             :         // SUBROUTINE INFORMATION:
    5982             :         //       AUTHOR         Edwin Lee
    5983             :         //       DATE WRITTEN   Summer 2011
    5984             :         //       MODIFIED       na
    5985             :         //       RE-ENGINEERED  na
    5986             : 
    5987   283224327 :         NumFieldCells = -1;
    5988   283224327 :         NumBoundaryCells = -1;
    5989             : 
    5990   283224327 :         if (cell.X_index < this->x_max_index) {
    5991   262118968 :             ++NumFieldCells;
    5992   262118968 :             this->NeighborFieldCells[NumFieldCells] = Direction::PositiveX;
    5993             :         } else {
    5994    21105359 :             ++NumBoundaryCells;
    5995    21105359 :             this->NeighborBoundaryCells[NumBoundaryCells] = Direction::PositiveX;
    5996             :         }
    5997             : 
    5998   283224327 :         if (cell.X_index > 0) {
    5999   264279751 :             ++NumFieldCells;
    6000   264279751 :             this->NeighborFieldCells[NumFieldCells] = Direction::NegativeX;
    6001             :         } else {
    6002    18944576 :             ++NumBoundaryCells;
    6003    18944576 :             this->NeighborBoundaryCells[NumBoundaryCells] = Direction::NegativeX;
    6004             :         }
    6005             : 
    6006   283224327 :         if (cell.Y_index < this->y_max_index) {
    6007   267180145 :             ++NumFieldCells;
    6008   267180145 :             this->NeighborFieldCells[NumFieldCells] = Direction::PositiveY;
    6009             :         } else {
    6010    16044182 :             ++NumBoundaryCells;
    6011    16044182 :             this->NeighborBoundaryCells[NumBoundaryCells] = Direction::PositiveY;
    6012             :         }
    6013             : 
    6014   283224327 :         if (cell.Y_index > 0) {
    6015   265758784 :             ++NumFieldCells;
    6016   265758784 :             this->NeighborFieldCells[NumFieldCells] = Direction::NegativeY;
    6017             :         } else {
    6018    17465543 :             ++NumBoundaryCells;
    6019    17465543 :             this->NeighborBoundaryCells[NumBoundaryCells] = Direction::NegativeY;
    6020             :         }
    6021             : 
    6022   283224327 :         if (cell.Z_index < this->z_max_index) {
    6023   257287089 :             ++NumFieldCells;
    6024   257287089 :             this->NeighborFieldCells[NumFieldCells] = Direction::PositiveZ;
    6025             :         } else {
    6026    25937238 :             ++NumBoundaryCells;
    6027    25937238 :             this->NeighborBoundaryCells[NumBoundaryCells] = Direction::PositiveZ;
    6028             :         }
    6029             : 
    6030   283224327 :         if (cell.Z_index > 0) {
    6031   256462752 :             ++NumFieldCells;
    6032   256462752 :             this->NeighborFieldCells[NumFieldCells] = Direction::NegativeZ;
    6033             :         } else {
    6034    26761575 :             ++NumBoundaryCells;
    6035    26761575 :             this->NeighborBoundaryCells[NumBoundaryCells] = Direction::NegativeZ;
    6036             :         }
    6037   283224327 :     }
    6038             : 
    6039             : } // namespace PlantPipingSystemsManager
    6040             : 
    6041             : } // namespace EnergyPlus

Generated by: LCOV version 1.14