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
|