LCOV - code coverage report
Current view: top level - EnergyPlus - PlantPipingSystemsManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 74.3 % 2843 2112
Test Date: 2025-05-22 16:09:37 Functions: 91.8 % 85 78

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

Generated by: LCOV version 2.0-1