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