LCOV - code coverage report
Current view: top level - EnergyPlus - PlantPipingSystemsManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 84.5 % 2917 2464
Test Date: 2025-06-02 07:23:51 Functions: 94.1 % 85 80

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

Generated by: LCOV version 2.0-1