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