Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Data/EnergyPlusData.hh>
57 : #include <EnergyPlus/DataEnvironment.hh>
58 : #include <EnergyPlus/DataHVACGlobals.hh>
59 : #include <EnergyPlus/DataHeatBalance.hh>
60 : #include <EnergyPlus/DataIPShortCuts.hh>
61 : #include <EnergyPlus/EarthTube.hh>
62 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
63 : #include <EnergyPlus/OutputProcessor.hh>
64 : #include <EnergyPlus/Psychrometrics.hh>
65 : #include <EnergyPlus/ScheduleManager.hh>
66 : #include <EnergyPlus/UtilityRoutines.hh>
67 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
68 :
69 : namespace EnergyPlus::EarthTube {
70 : // Module containing the data for Earth Tube system
71 :
72 : // MODULE INFORMATION:
73 : // AUTHOR Kwang Ho Lee
74 : // DATE WRITTEN November 2005
75 :
76 : // PURPOSE OF THIS MODULE:
77 : // To encapsulate the data and algorithyms required to manage the EarthTube System Component
78 :
79 : // REFERENCES:
80 : // 1. M. Krarti, "Analytical Model to Predict Annual Soil Surface Temperature Variation",
81 : // Journal of Solar Energy Engineering 117, 1995, pp 91-99
82 : // 2. K. Labs In: J. Cook, editor, "Passive Cooling",
83 : // Cambridge Massachusetts, MIT Press, 1989, pp 206-212
84 :
85 : // This is an interesting one. The actual members of the enum are never explicitly used
86 : // The enum is used in a getEnumValue call to determine what was found in GetInput
87 : // The value is then used as an array index to lookup thermal conductivity and such from some std::arrays
88 : // So the IDE thinks these are unused, and I'm not sure the best way to hint that they sorta aren't
89 : enum class SoilType
90 : {
91 : Invalid = -1,
92 : HeavyAndSat,
93 : HeavyAndDamp,
94 : HeavyAndDry,
95 : LightAndDry,
96 : Num
97 : };
98 :
99 : int totEarthTube = 0;
100 :
101 : constexpr std::array<std::string_view, static_cast<int>(Ventilation::Num)> ventilationNamesUC = {"NATURAL", "INTAKE", "EXHAUST"};
102 : constexpr std::array<std::string_view, static_cast<int>(SoilType::Num)> soilTypeNamesUC = {
103 : "HEAVYANDSATURATED", "HEAVYANDDAMP", "HEAVYANDDRY", "LIGHTANDDRY"};
104 : constexpr std::array<std::string_view, static_cast<int>(EarthTubeModelType::Num)> solutionTypeNamesUC = {"BASIC", "VERTICAL"};
105 :
106 3728073 : void ManageEarthTube(EnergyPlusData &state)
107 : {
108 :
109 : // SUBROUTINE INFORMATION:
110 : // AUTHOR Kwang Ho Lee
111 : // DATE WRITTEN November 2005
112 :
113 : // PURPOSE OF THIS SUBROUTINE:
114 : // This subroutine manages the simulation of EarthTube unit.
115 : // This driver manages the calls to all of
116 : // the other drivers and simulation algorithms.
117 :
118 : // Obtains and Allocates heat balance related parameters from input file
119 3728073 : if (state.dataEarthTube->GetInputFlag) {
120 763 : bool ErrorsFound = false;
121 763 : GetEarthTube(state, ErrorsFound);
122 763 : state.dataEarthTube->GetInputFlag = false;
123 : }
124 :
125 3728073 : if (state.dataEarthTube->EarthTubeSys.empty()) return;
126 :
127 4296 : initEarthTubeVertical(state);
128 :
129 4296 : CalcEarthTube(state);
130 :
131 4296 : ReportEarthTube(state);
132 : }
133 :
134 763 : void GetEarthTube(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
135 : {
136 :
137 : // SUBROUTINE INFORMATION:
138 : // AUTHOR Kwang Ho Lee
139 : // DATE WRITTEN November 2005
140 :
141 : // PURPOSE OF THIS SUBROUTINE:
142 : // This subroutine obtains input data for EarthTube units and
143 : // stores it in the EarthTube data structure.
144 :
145 : // SUBROUTINE PARAMETER DEFINITIONS:
146 763 : Real64 constexpr EarthTubeTempLimit(100.0); // degrees Celsius
147 :
148 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
149 : int NumAlpha;
150 : int NumNumber;
151 : int IOStat;
152 : int Loop;
153 763 : Array1D_bool RepVarSet;
154 :
155 763 : RepVarSet.dimension(state.dataGlobal->NumOfZones, true);
156 :
157 : // Following used for reporting
158 763 : state.dataEarthTube->ZnRptET.allocate(state.dataGlobal->NumOfZones);
159 :
160 763 : std::string_view cCurrentModuleObject = "ZoneEarthtube:Parameters";
161 763 : int totEarthTubePars = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
162 :
163 763 : state.dataEarthTube->EarthTubePars.allocate(totEarthTubePars);
164 :
165 765 : for (Loop = 1; Loop <= totEarthTubePars; ++Loop) {
166 2 : auto &thisEarthTubePars = state.dataEarthTube->EarthTubePars(Loop);
167 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
168 : cCurrentModuleObject,
169 : Loop,
170 2 : state.dataIPShortCut->cAlphaArgs,
171 : NumAlpha,
172 2 : state.dataIPShortCut->rNumericArgs,
173 : NumNumber,
174 : IOStat,
175 2 : state.dataIPShortCut->lNumericFieldBlanks,
176 2 : state.dataIPShortCut->lAlphaFieldBlanks,
177 2 : state.dataIPShortCut->cAlphaFieldNames,
178 2 : state.dataIPShortCut->cNumericFieldNames);
179 :
180 2 : thisEarthTubePars.nameParameters = state.dataIPShortCut->cAlphaArgs(1);
181 : // Check to make sure name is unique
182 3 : for (int otherParams = 1; otherParams < Loop; ++otherParams) {
183 1 : if (Util::SameString(thisEarthTubePars.nameParameters, state.dataEarthTube->EarthTubePars(otherParams).nameParameters)) {
184 0 : ShowSevereError(state,
185 0 : format("{}: {} = {} is not a unique name.",
186 : cCurrentModuleObject,
187 0 : state.dataIPShortCut->cAlphaFieldNames(1),
188 0 : state.dataIPShortCut->cAlphaArgs(1)));
189 0 : ShowContinueError(state, format("Check the other {} names for a duplicate.", cCurrentModuleObject));
190 0 : ErrorsFound = true;
191 : }
192 : }
193 :
194 2 : thisEarthTubePars.numNodesAbove = state.dataIPShortCut->rNumericArgs(1);
195 2 : thisEarthTubePars.numNodesBelow = state.dataIPShortCut->rNumericArgs(2);
196 2 : thisEarthTubePars.dimBoundAbove = state.dataIPShortCut->rNumericArgs(3);
197 2 : thisEarthTubePars.dimBoundBelow = state.dataIPShortCut->rNumericArgs(4);
198 2 : thisEarthTubePars.width = state.dataIPShortCut->rNumericArgs(5);
199 : }
200 :
201 763 : cCurrentModuleObject = "ZoneEarthtube";
202 763 : totEarthTube = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
203 :
204 763 : state.dataEarthTube->EarthTubeSys.allocate(totEarthTube);
205 :
206 769 : for (Loop = 1; Loop <= totEarthTube; ++Loop) {
207 6 : auto &thisEarthTube = state.dataEarthTube->EarthTubeSys(Loop);
208 12 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
209 : cCurrentModuleObject,
210 : Loop,
211 6 : state.dataIPShortCut->cAlphaArgs,
212 : NumAlpha,
213 6 : state.dataIPShortCut->rNumericArgs,
214 : NumNumber,
215 : IOStat,
216 6 : state.dataIPShortCut->lNumericFieldBlanks,
217 6 : state.dataIPShortCut->lAlphaFieldBlanks,
218 6 : state.dataIPShortCut->cAlphaFieldNames,
219 6 : state.dataIPShortCut->cNumericFieldNames);
220 :
221 : // First Alpha is Zone Name
222 6 : thisEarthTube.ZonePtr = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(1), state.dataHeatBal->Zone);
223 6 : if (thisEarthTube.ZonePtr == 0) {
224 0 : ShowSevereError(
225 : state,
226 0 : format("{}: {} not found={}", cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(1), state.dataIPShortCut->cAlphaArgs(1)));
227 0 : ErrorsFound = true;
228 : }
229 :
230 : // Second Alpha is Schedule Name
231 6 : thisEarthTube.SchedPtr = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
232 6 : if (thisEarthTube.SchedPtr == 0) {
233 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
234 0 : ShowSevereError(state,
235 0 : format("{}: {} is required, missing for {}={}",
236 : cCurrentModuleObject,
237 0 : state.dataIPShortCut->cAlphaFieldNames(2),
238 0 : state.dataIPShortCut->cAlphaFieldNames(1),
239 0 : state.dataIPShortCut->cAlphaArgs(1)));
240 : } else {
241 0 : ShowSevereError(state,
242 0 : format("{}: invalid {} entered={} for {}={}",
243 : cCurrentModuleObject,
244 0 : state.dataIPShortCut->cAlphaFieldNames(2),
245 0 : state.dataIPShortCut->cAlphaArgs(2),
246 0 : state.dataIPShortCut->cAlphaFieldNames(1),
247 0 : state.dataIPShortCut->cAlphaArgs(1)));
248 : }
249 0 : ErrorsFound = true;
250 : }
251 :
252 : // Overall parameters and their limits
253 6 : thisEarthTube.DesignLevel = state.dataIPShortCut->rNumericArgs(1);
254 :
255 6 : thisEarthTube.MinTemperature = state.dataIPShortCut->rNumericArgs(2);
256 6 : if ((thisEarthTube.MinTemperature < -EarthTubeTempLimit) || (thisEarthTube.MinTemperature > EarthTubeTempLimit)) {
257 0 : ShowSevereError(state,
258 0 : format("{}: {}={} must have a minimum temperature between -{:.0R}C and {:.0R}C",
259 : cCurrentModuleObject,
260 0 : state.dataIPShortCut->cAlphaFieldNames(1),
261 0 : state.dataIPShortCut->cAlphaArgs(1),
262 : EarthTubeTempLimit,
263 : EarthTubeTempLimit));
264 0 : ShowContinueError(state, format("Entered value={:.0R}", thisEarthTube.MinTemperature));
265 0 : ErrorsFound = true;
266 : }
267 :
268 6 : thisEarthTube.MaxTemperature = state.dataIPShortCut->rNumericArgs(3);
269 6 : if ((thisEarthTube.MaxTemperature < -EarthTubeTempLimit) || (thisEarthTube.MaxTemperature > EarthTubeTempLimit)) {
270 0 : ShowSevereError(state,
271 0 : format("{}: {}={} must have a maximum temperature between -{:.0R}C and {:.0R}C",
272 : cCurrentModuleObject,
273 0 : state.dataIPShortCut->cAlphaFieldNames(1),
274 0 : state.dataIPShortCut->cAlphaArgs(1),
275 : EarthTubeTempLimit,
276 : EarthTubeTempLimit));
277 0 : ShowContinueError(state, format("Entered value={:.0R}", thisEarthTube.MaxTemperature));
278 0 : ErrorsFound = true;
279 : }
280 :
281 6 : thisEarthTube.DelTemperature = state.dataIPShortCut->rNumericArgs(4); // 3/12/03 Negative del temp now allowed COP
282 :
283 : // if we have a blank, then just set it to the Natural type, otherwise, search on it
284 6 : if (state.dataIPShortCut->cAlphaArgs(3).empty()) {
285 0 : thisEarthTube.FanType = Ventilation::Natural;
286 : } else {
287 6 : thisEarthTube.FanType = static_cast<Ventilation>(getEnumValue(ventilationNamesUC, state.dataIPShortCut->cAlphaArgs(3)));
288 6 : if (thisEarthTube.FanType == Ventilation::Invalid) {
289 0 : ShowSevereError(state,
290 0 : format("{}: {}={}, {} invalid={}",
291 : cCurrentModuleObject,
292 0 : state.dataIPShortCut->cAlphaFieldNames(1),
293 0 : state.dataIPShortCut->cAlphaArgs(1),
294 0 : state.dataIPShortCut->cAlphaFieldNames(3),
295 0 : state.dataIPShortCut->cAlphaArgs(3)));
296 0 : ErrorsFound = true;
297 : }
298 : }
299 :
300 6 : thisEarthTube.FanPressure = state.dataIPShortCut->rNumericArgs(5);
301 6 : if (thisEarthTube.FanPressure < 0.0) {
302 0 : ShowSevereError(state,
303 0 : format("{}: {}={}, {} must be positive, entered value={:.2R}",
304 : cCurrentModuleObject,
305 0 : state.dataIPShortCut->cAlphaFieldNames(1),
306 0 : state.dataIPShortCut->cAlphaArgs(1),
307 0 : state.dataIPShortCut->cNumericFieldNames(5),
308 0 : thisEarthTube.FanPressure));
309 0 : ErrorsFound = true;
310 : }
311 :
312 6 : thisEarthTube.FanEfficiency = state.dataIPShortCut->rNumericArgs(6);
313 6 : if ((thisEarthTube.FanEfficiency <= 0.0) || (thisEarthTube.FanEfficiency > 1.0)) {
314 0 : ShowSevereError(state,
315 0 : format("{}: {}={}, {} must be greater than zero and less than or equal to one, entered value={:.2R}",
316 : cCurrentModuleObject,
317 0 : state.dataIPShortCut->cAlphaFieldNames(1),
318 0 : state.dataIPShortCut->cAlphaArgs(1),
319 0 : state.dataIPShortCut->cNumericFieldNames(6),
320 0 : thisEarthTube.FanEfficiency));
321 0 : ErrorsFound = true;
322 : }
323 :
324 6 : thisEarthTube.r1 = state.dataIPShortCut->rNumericArgs(7);
325 6 : if (thisEarthTube.r1 <= 0.0) {
326 0 : ShowSevereError(state,
327 0 : format("{}: {}={}, {} must be positive, entered value={:.2R}",
328 : cCurrentModuleObject,
329 0 : state.dataIPShortCut->cAlphaFieldNames(1),
330 0 : state.dataIPShortCut->cAlphaArgs(1),
331 0 : state.dataIPShortCut->cNumericFieldNames(7),
332 0 : thisEarthTube.r1));
333 0 : ErrorsFound = true;
334 : }
335 :
336 6 : thisEarthTube.r2 = state.dataIPShortCut->rNumericArgs(8);
337 6 : if (thisEarthTube.r2 <= 0.0) {
338 0 : ShowSevereError(state,
339 0 : format("{}: {}={}, {} must be positive, entered value={:.2R}",
340 : cCurrentModuleObject,
341 0 : state.dataIPShortCut->cAlphaFieldNames(1),
342 0 : state.dataIPShortCut->cAlphaArgs(1),
343 0 : state.dataIPShortCut->cNumericFieldNames(8),
344 0 : thisEarthTube.r2));
345 0 : ErrorsFound = true;
346 : }
347 :
348 6 : thisEarthTube.r3 = 2.0 * thisEarthTube.r1;
349 :
350 6 : thisEarthTube.PipeLength = state.dataIPShortCut->rNumericArgs(9);
351 6 : if (thisEarthTube.PipeLength <= 0.0) {
352 0 : ShowSevereError(state,
353 0 : format("{}: {}={}, {} must be positive, entered value={:.2R}",
354 : cCurrentModuleObject,
355 0 : state.dataIPShortCut->cAlphaFieldNames(1),
356 0 : state.dataIPShortCut->cAlphaArgs(1),
357 0 : state.dataIPShortCut->cNumericFieldNames(9),
358 0 : thisEarthTube.PipeLength));
359 0 : ErrorsFound = true;
360 : }
361 :
362 6 : thisEarthTube.PipeThermCond = state.dataIPShortCut->rNumericArgs(10);
363 6 : if (thisEarthTube.PipeThermCond <= 0.0) {
364 0 : ShowSevereError(state,
365 0 : format("{}: {}={}, {} must be positive, entered value={:.2R}",
366 : cCurrentModuleObject,
367 0 : state.dataIPShortCut->cAlphaFieldNames(1),
368 0 : state.dataIPShortCut->cAlphaArgs(1),
369 0 : state.dataIPShortCut->cNumericFieldNames(10),
370 0 : thisEarthTube.PipeThermCond));
371 0 : ErrorsFound = true;
372 : }
373 :
374 6 : thisEarthTube.z = state.dataIPShortCut->rNumericArgs(11);
375 6 : if (thisEarthTube.z <= 0.0) {
376 0 : ShowSevereError(state,
377 0 : format("{}: {}={}, {} must be positive, entered value={:.2R}",
378 : cCurrentModuleObject,
379 0 : state.dataIPShortCut->cAlphaFieldNames(1),
380 0 : state.dataIPShortCut->cAlphaArgs(1),
381 0 : state.dataIPShortCut->cNumericFieldNames(11),
382 0 : thisEarthTube.z));
383 0 : ErrorsFound = true;
384 : }
385 6 : if (thisEarthTube.z <= (thisEarthTube.r1 + thisEarthTube.r2 + thisEarthTube.r3)) {
386 : // Note that code in initEarthTubeVertical assumes that this check remains in place--if this ever gets changed,
387 : // code in initEarthTubeVertical must be modified
388 0 : ShowSevereError(state,
389 0 : format("{}: {}={}, {} must be greater than 3*{} + {} entered value={:.2R} ref sum={:.2R}",
390 : cCurrentModuleObject,
391 0 : state.dataIPShortCut->cAlphaFieldNames(1),
392 0 : state.dataIPShortCut->cAlphaArgs(1),
393 0 : state.dataIPShortCut->cNumericFieldNames(11),
394 0 : state.dataIPShortCut->cNumericFieldNames(7),
395 0 : state.dataIPShortCut->cNumericFieldNames(8),
396 0 : thisEarthTube.z,
397 0 : thisEarthTube.r1 + thisEarthTube.r2 + thisEarthTube.r3));
398 0 : ErrorsFound = true;
399 : }
400 :
401 6 : SoilType soilType = static_cast<SoilType>(getEnumValue(soilTypeNamesUC, state.dataIPShortCut->cAlphaArgs(4)));
402 6 : constexpr std::array<Real64, static_cast<int>(SoilType::Num)> thermalDiffusivity = {0.0781056, 0.055728, 0.0445824, 0.024192};
403 6 : constexpr std::array<Real64, static_cast<int>(SoilType::Num)> thermalConductivity = {2.42, 1.3, 0.865, 0.346};
404 6 : if (soilType == SoilType::Invalid) {
405 0 : ShowSevereError(state,
406 0 : format("{}: {}={}, {} invalid={}",
407 : cCurrentModuleObject,
408 0 : state.dataIPShortCut->cAlphaFieldNames(1),
409 0 : state.dataIPShortCut->cAlphaArgs(1),
410 0 : state.dataIPShortCut->cAlphaFieldNames(4),
411 0 : state.dataIPShortCut->cAlphaArgs(4)));
412 0 : ErrorsFound = true;
413 : } else {
414 6 : thisEarthTube.SoilThermDiff = thermalDiffusivity[static_cast<int>(soilType)];
415 6 : thisEarthTube.SoilThermCond = thermalConductivity[static_cast<int>(soilType)];
416 : }
417 :
418 6 : thisEarthTube.AverSoilSurTemp = state.dataIPShortCut->rNumericArgs(12);
419 6 : thisEarthTube.ApmlSoilSurTemp = state.dataIPShortCut->rNumericArgs(13);
420 6 : thisEarthTube.SoilSurPhaseConst = int(state.dataIPShortCut->rNumericArgs(14));
421 :
422 : // Override any user input for cases where natural ventilation is being used
423 6 : if (thisEarthTube.FanType == Ventilation::Natural) {
424 2 : thisEarthTube.FanPressure = 0.0;
425 2 : thisEarthTube.FanEfficiency = 1.0;
426 : }
427 :
428 6 : thisEarthTube.ConstantTermCoef = state.dataIPShortCut->rNumericArgs(15);
429 6 : thisEarthTube.TemperatureTermCoef = state.dataIPShortCut->rNumericArgs(16);
430 6 : thisEarthTube.VelocityTermCoef = state.dataIPShortCut->rNumericArgs(17);
431 6 : thisEarthTube.VelocitySQTermCoef = state.dataIPShortCut->rNumericArgs(18);
432 :
433 : // cAlphaArgs(5)--Model type: basic or vertical
434 : // only process cAlphaArgs(6) if cAlphaArgs(5) is "Vertical"
435 6 : if (state.dataIPShortCut->cAlphaArgs(5).empty()) {
436 0 : thisEarthTube.ModelType = EarthTubeModelType::Basic;
437 : } else {
438 6 : thisEarthTube.ModelType = static_cast<EarthTubeModelType>(getEnumValue(solutionTypeNamesUC, state.dataIPShortCut->cAlphaArgs(5)));
439 6 : if (thisEarthTube.ModelType == EarthTubeModelType::Invalid) {
440 0 : ShowSevereError(state,
441 0 : format("{}: {}={}, {} invalid={}",
442 : cCurrentModuleObject,
443 0 : state.dataIPShortCut->cAlphaFieldNames(1),
444 0 : state.dataIPShortCut->cAlphaArgs(1),
445 0 : state.dataIPShortCut->cAlphaFieldNames(5),
446 0 : state.dataIPShortCut->cAlphaArgs(5)));
447 0 : ErrorsFound = true;
448 : }
449 : }
450 :
451 6 : if (thisEarthTube.ModelType == EarthTubeModelType::Vertical) {
452 2 : thisEarthTube.r3 = 0.0; // Vertical model does not use this parameter--reset to zero (keep because r3=0 necessary so Rs=0 in calc routine)
453 : // Process the parameters based on the name (link via index)
454 2 : thisEarthTube.vertParametersPtr = 0;
455 3 : for (int parIndex = 1; parIndex <= totEarthTubePars; ++parIndex) {
456 3 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(6), state.dataEarthTube->EarthTubePars(parIndex).nameParameters)) {
457 2 : thisEarthTube.vertParametersPtr = parIndex;
458 2 : break;
459 : }
460 : }
461 2 : if (thisEarthTube.vertParametersPtr == 0) { // didn't find a match
462 0 : ShowSevereError(state,
463 0 : format("{}: {}={}, Parameter Object {} was not found in the input file.",
464 : cCurrentModuleObject,
465 0 : state.dataIPShortCut->cAlphaFieldNames(1),
466 0 : state.dataIPShortCut->cAlphaArgs(1),
467 0 : state.dataIPShortCut->cAlphaArgs(6)));
468 0 : ShowContinueError(state, "Check this name and make sure one of the earth tube parameters objects matches it.");
469 0 : ErrorsFound = true;
470 : }
471 : }
472 :
473 6 : if (thisEarthTube.ZonePtr > 0) {
474 6 : if (RepVarSet(thisEarthTube.ZonePtr)) {
475 6 : RepVarSet(thisEarthTube.ZonePtr) = false;
476 6 : auto &zone = state.dataHeatBal->Zone(thisEarthTube.ZonePtr);
477 6 : auto &thisZnRptET = state.dataEarthTube->ZnRptET(thisEarthTube.ZonePtr);
478 :
479 12 : SetupOutputVariable(state,
480 : "Earth Tube Zone Sensible Cooling Energy",
481 : Constant::Units::J,
482 6 : thisZnRptET.EarthTubeHeatLoss,
483 : OutputProcessor::TimeStepType::System,
484 : OutputProcessor::StoreType::Sum,
485 6 : zone.Name);
486 12 : SetupOutputVariable(state,
487 : "Earth Tube Zone Sensible Cooling Rate",
488 : Constant::Units::W,
489 6 : thisZnRptET.EarthTubeHeatLossRate,
490 : OutputProcessor::TimeStepType::System,
491 : OutputProcessor::StoreType::Average,
492 6 : zone.Name);
493 12 : SetupOutputVariable(state,
494 : "Earth Tube Zone Sensible Heating Energy",
495 : Constant::Units::J,
496 6 : thisZnRptET.EarthTubeHeatGain,
497 : OutputProcessor::TimeStepType::System,
498 : OutputProcessor::StoreType::Sum,
499 6 : zone.Name);
500 12 : SetupOutputVariable(state,
501 : "Earth Tube Zone Sensible Heating Rate",
502 : Constant::Units::W,
503 6 : thisZnRptET.EarthTubeHeatGainRate,
504 : OutputProcessor::TimeStepType::System,
505 : OutputProcessor::StoreType::Average,
506 6 : zone.Name);
507 12 : SetupOutputVariable(state,
508 : "Earth Tube Air Flow Volume",
509 : Constant::Units::m3,
510 6 : thisZnRptET.EarthTubeVolume,
511 : OutputProcessor::TimeStepType::System,
512 : OutputProcessor::StoreType::Sum,
513 6 : zone.Name);
514 12 : SetupOutputVariable(state,
515 : "Earth Tube Current Density Air Volume Flow Rate",
516 : Constant::Units::m3_s,
517 6 : thisZnRptET.EarthTubeVolFlowRate,
518 : OutputProcessor::TimeStepType::System,
519 : OutputProcessor::StoreType::Average,
520 6 : zone.Name);
521 12 : SetupOutputVariable(state,
522 : "Earth Tube Standard Density Air Volume Flow Rate",
523 : Constant::Units::m3_s,
524 6 : thisZnRptET.EarthTubeVolFlowRateStd,
525 : OutputProcessor::TimeStepType::System,
526 : OutputProcessor::StoreType::Average,
527 6 : zone.Name);
528 12 : SetupOutputVariable(state,
529 : "Earth Tube Air Flow Mass",
530 : Constant::Units::kg,
531 6 : thisZnRptET.EarthTubeMass,
532 : OutputProcessor::TimeStepType::System,
533 : OutputProcessor::StoreType::Sum,
534 6 : zone.Name);
535 12 : SetupOutputVariable(state,
536 : "Earth Tube Air Mass Flow Rate",
537 : Constant::Units::kg_s,
538 6 : thisZnRptET.EarthTubeMassFlowRate,
539 : OutputProcessor::TimeStepType::System,
540 : OutputProcessor::StoreType::Average,
541 6 : zone.Name);
542 12 : SetupOutputVariable(state,
543 : "Earth Tube Water Mass Flow Rate",
544 : Constant::Units::kg_s,
545 6 : thisZnRptET.EarthTubeWaterMassFlowRate,
546 : OutputProcessor::TimeStepType::System,
547 : OutputProcessor::StoreType::Average,
548 6 : zone.Name);
549 12 : SetupOutputVariable(state,
550 : "Earth Tube Fan Electricity Energy",
551 : Constant::Units::J,
552 6 : thisZnRptET.EarthTubeFanElec,
553 : OutputProcessor::TimeStepType::System,
554 : OutputProcessor::StoreType::Sum,
555 6 : zone.Name,
556 : Constant::eResource::Electricity,
557 : OutputProcessor::Group::Building);
558 12 : SetupOutputVariable(state,
559 : "Earth Tube Fan Electricity Rate",
560 : Constant::Units::W,
561 6 : thisZnRptET.EarthTubeFanElecPower,
562 : OutputProcessor::TimeStepType::System,
563 : OutputProcessor::StoreType::Average,
564 6 : zone.Name);
565 12 : SetupOutputVariable(state,
566 : "Earth Tube Zone Inlet Air Temperature",
567 : Constant::Units::C,
568 6 : thisZnRptET.EarthTubeAirTemp,
569 : OutputProcessor::TimeStepType::System,
570 : OutputProcessor::StoreType::Average,
571 6 : zone.Name);
572 12 : SetupOutputVariable(state,
573 : "Earth Tube Ground Interface Temperature",
574 : Constant::Units::C,
575 6 : thisEarthTube.GroundTempt,
576 : OutputProcessor::TimeStepType::System,
577 : OutputProcessor::StoreType::Average,
578 6 : zone.Name);
579 12 : SetupOutputVariable(state,
580 : "Earth Tube Outdoor Air Heat Transfer Rate",
581 : Constant::Units::W,
582 6 : thisZnRptET.EarthTubeOATreatmentPower,
583 : OutputProcessor::TimeStepType::System,
584 : OutputProcessor::StoreType::Average,
585 6 : zone.Name);
586 12 : SetupOutputVariable(state,
587 : "Earth Tube Zone Inlet Wet Bulb Temperature",
588 : Constant::Units::C,
589 6 : thisZnRptET.EarthTubeWetBulbTemp,
590 : OutputProcessor::TimeStepType::System,
591 : OutputProcessor::StoreType::Average,
592 6 : zone.Name);
593 12 : SetupOutputVariable(state,
594 : "Earth Tube Zone Inlet Humidity Ratio",
595 : Constant::Units::kgWater_kgDryAir,
596 6 : thisZnRptET.EarthTubeHumRat,
597 : OutputProcessor::TimeStepType::System,
598 : OutputProcessor::StoreType::Average,
599 6 : zone.Name);
600 : }
601 : }
602 : }
603 :
604 763 : CheckEarthTubesInZones(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
605 :
606 763 : if (ErrorsFound) {
607 0 : ShowFatalError(state, format("{}: Errors getting input. Program terminates.", cCurrentModuleObject));
608 : }
609 763 : }
610 :
611 763 : void CheckEarthTubesInZones(EnergyPlusData &state,
612 : std::string const &ZoneName, // name of zone for error reporting
613 : std::string_view FieldName, // name of earth tube in input
614 : bool &ErrorsFound // Found a problem
615 : )
616 : {
617 : // Check to make sure there is only one earth tube statement per zone
618 763 : int numEarthTubes = (int)state.dataEarthTube->EarthTubeSys.size();
619 767 : for (int Loop = 1; Loop <= numEarthTubes - 1; ++Loop) {
620 10 : for (int Loop1 = Loop + 1; Loop1 <= numEarthTubes; ++Loop1) {
621 6 : if (state.dataEarthTube->EarthTubeSys(Loop).ZonePtr == state.dataEarthTube->EarthTubeSys(Loop1).ZonePtr) {
622 0 : ShowSevereError(state, format("{} has more than one {} associated with it.", ZoneName, FieldName));
623 0 : ShowContinueError(state, format("Only one {} is allowed per zone. Check the definitions of {}", FieldName, FieldName));
624 0 : ShowContinueError(state, "in your input file and make sure that there is only one defined for each zone.");
625 0 : ErrorsFound = true;
626 : }
627 : }
628 : }
629 763 : }
630 :
631 4296 : void initEarthTubeVertical(EnergyPlusData &state)
632 : {
633 4296 : if (state.dataEarthTube->initFirstTime) {
634 2 : state.dataEarthTube->initFirstTime = false;
635 8 : for (int etNum = 1; etNum <= totEarthTube; ++etNum) {
636 6 : auto &thisEarthTube = state.dataEarthTube->EarthTubeSys(etNum);
637 6 : if (thisEarthTube.ModelType != EarthTubeModelType::Vertical) continue; // Skip earth tubes that do not use vertical solution
638 2 : auto &thisEarthTubeParams = state.dataEarthTube->EarthTubePars(thisEarthTube.vertParametersPtr);
639 2 : thisEarthTube.totNodes = thisEarthTubeParams.numNodesAbove + thisEarthTubeParams.numNodesBelow + 1;
640 2 : thisEarthTube.aCoeff.resize(thisEarthTube.totNodes);
641 2 : thisEarthTube.bCoeff.resize(thisEarthTube.totNodes);
642 2 : thisEarthTube.cCoeff.resize(thisEarthTube.totNodes);
643 2 : thisEarthTube.cCoeff0.resize(thisEarthTube.totNodes);
644 2 : thisEarthTube.dCoeff.resize(thisEarthTube.totNodes);
645 2 : thisEarthTube.cPrime.resize(thisEarthTube.totNodes);
646 2 : thisEarthTube.dPrime.resize(thisEarthTube.totNodes);
647 2 : thisEarthTube.cPrime0.resize(thisEarthTube.totNodes);
648 2 : thisEarthTube.tCurrent.resize(thisEarthTube.totNodes);
649 2 : thisEarthTube.tLast.resize(thisEarthTube.totNodes);
650 2 : thisEarthTube.depthNode.resize(thisEarthTube.totNodes);
651 2 : thisEarthTube.tUndist.resize(thisEarthTube.totNodes);
652 2 : Real64 thickBase = (thisEarthTube.z - 3.0 * thisEarthTube.r1);
653 2 : Real64 thickTop = thickBase * thisEarthTubeParams.dimBoundAbove / float(thisEarthTubeParams.numNodesAbove);
654 2 : Real64 thickBottom = thickBase * thisEarthTubeParams.dimBoundBelow / float(thisEarthTubeParams.numNodesBelow);
655 2 : Real64 thickEarthTube = 4.0 * thisEarthTube.r1;
656 2 : Real64 deltat = state.dataGlobal->TimeStepZone;
657 2 : Real64 thermDiff = thisEarthTube.SoilThermDiff / Constant::HoursInDay; // convert to "per hour" from "per day"
658 :
659 : // Node equations determine the _Coeff terms--see Engineering Referenve for details on these equation types
660 : // Note that node numbers are shifted for c++ arrays that go from 0 to numNodes-1.
661 : // Node Type 1 (Top Node)
662 2 : Real64 commonTerm = thermDiff * deltat / (thickTop * thickTop);
663 2 : thisEarthTube.aCoeff[0] = 0.0; // no a0 value
664 2 : thisEarthTube.bCoeff[0] = 1.0 + 3.0 * commonTerm;
665 2 : thisEarthTube.cCoeff[0] = -1.0 * commonTerm;
666 2 : thisEarthTube.dMult0 = 2.0 * commonTerm; // does not include temperatures (upper boundary or previous time step)--added later
667 : // Node Type 2 (Generic Top Section Node)
668 13 : for (int nodeNum = 1; nodeNum <= thisEarthTubeParams.numNodesAbove - 2; ++nodeNum) {
669 11 : thisEarthTube.aCoeff[nodeNum] = -1.0 * commonTerm;
670 11 : thisEarthTube.bCoeff[nodeNum] = 1.0 + 2.0 * commonTerm;
671 11 : thisEarthTube.cCoeff[nodeNum] = -1.0 * commonTerm;
672 : }
673 : // Node Type 3 (Last Top Section Node)
674 2 : int thisNode = thisEarthTubeParams.numNodesAbove - 1;
675 2 : Real64 commonTerm2 = 2.0 * thermDiff * deltat / (thickTop + thickEarthTube) / thickTop;
676 2 : thisEarthTube.aCoeff[thisNode] = -1.0 * commonTerm;
677 2 : thisEarthTube.bCoeff[thisNode] = 1.0 + commonTerm + commonTerm2;
678 2 : thisEarthTube.cCoeff[thisNode] = -1.0 * commonTerm2;
679 : // Node Type 4 (Earth Tube Node)
680 2 : thisNode = thisEarthTubeParams.numNodesAbove;
681 2 : commonTerm = 2.0 * thermDiff * deltat / (thickTop + thickEarthTube) / thickEarthTube;
682 2 : commonTerm2 = 2.0 * thermDiff * deltat / (thickBottom + thickEarthTube) / thickEarthTube;
683 2 : thisEarthTube.aCoeff[thisNode] = -1.0 * commonTerm;
684 2 : thisEarthTube.bCoeff[thisNode] = 1.0 + commonTerm + commonTerm2; // does not include earth tube air flow term--added later
685 2 : thisEarthTube.cCoeff[thisNode] = -1.0 * commonTerm2;
686 : // Node Type 5 (First Bottom Section Node)
687 2 : thisNode = thisEarthTubeParams.numNodesAbove + 1;
688 2 : commonTerm = thermDiff * deltat / (thickBottom * thickBottom);
689 2 : commonTerm2 = 2.0 * thermDiff * deltat / (thickBottom + thickEarthTube) / thickBottom;
690 2 : thisEarthTube.aCoeff[thisNode] = -1.0 * commonTerm2;
691 2 : thisEarthTube.bCoeff[thisNode] = 1.0 + commonTerm + commonTerm2;
692 2 : thisEarthTube.cCoeff[thisNode] = -1.0 * commonTerm;
693 : // Node Type 6 (Generic Bottom Section Node)
694 11 : for (int nodeNum = thisNode + 1; nodeNum <= thisEarthTube.totNodes - 2; ++nodeNum) {
695 9 : thisEarthTube.aCoeff[nodeNum] = -1.0 * commonTerm;
696 9 : thisEarthTube.bCoeff[nodeNum] = 1.0 + 2.0 * commonTerm;
697 9 : thisEarthTube.cCoeff[nodeNum] = -1.0 * commonTerm;
698 : }
699 : // Node Type 7 (Last Bottom Section Node, i.e. Last Node)
700 2 : thisNode = thisEarthTube.totNodes - 1; // shifted due to c++ arrays that go from 0 to numNodes-1
701 2 : thisEarthTube.aCoeff[thisNode] = -1.0 * commonTerm;
702 2 : thisEarthTube.bCoeff[thisNode] = 1.0 + 3.0 * commonTerm;
703 2 : thisEarthTube.cCoeff[thisNode] = 0.0; // no cN value
704 2 : thisEarthTube.dMultN = 2.0 * commonTerm; // does not include previous temperature and earth tube air flow terms--added later
705 :
706 : // Initialize node temperatures using undisturbed temperature equation and node depths
707 : // First, nodes above the earth tube
708 2 : thisEarthTube.depthNode[thisEarthTubeParams.numNodesAbove - 1] = thisEarthTube.z - 0.5 * (thickEarthTube + thickTop);
709 15 : for (int nodeNum = thisEarthTubeParams.numNodesAbove - 2; nodeNum >= 0; --nodeNum) {
710 13 : thisEarthTube.depthNode[nodeNum] = thisEarthTube.depthNode[nodeNum + 1] - thickTop;
711 : }
712 : // Now, the earth tube node
713 2 : thisEarthTube.depthNode[thisEarthTubeParams.numNodesAbove] = thisEarthTube.z;
714 : // Finally the nodes below the earth tube
715 2 : thisEarthTube.depthNode[thisEarthTubeParams.numNodesAbove + 1] = thisEarthTube.z + 0.5 * (thickEarthTube + thickBottom);
716 13 : for (int nodeNumBelow = 2; nodeNumBelow <= thisEarthTubeParams.numNodesBelow; ++nodeNumBelow) {
717 11 : int nodeNum = thisEarthTubeParams.numNodesAbove + nodeNumBelow;
718 11 : thisEarthTube.depthNode[nodeNum] = thisEarthTube.depthNode[nodeNum - 1] + thickBottom;
719 : }
720 2 : thisEarthTube.depthUpperBound = thisEarthTube.depthNode[0] - 0.5 * thickTop;
721 2 : thisEarthTube.depthLowerBound = thisEarthTube.depthNode[thisEarthTube.totNodes - 1] + 0.5 * thickBottom;
722 :
723 : // Calculate constant part of air flow term at earth tube node. Note that diffusiity/conductivity = 1/(density*specific_heat)
724 2 : thisEarthTube.airFlowCoeff = state.dataGlobal->TimeStepZone * thermDiff / thisEarthTube.SoilThermCond / thickEarthTube /
725 2 : thisEarthTubeParams.width / thisEarthTube.PipeLength;
726 :
727 : // Calculate some initial values in the Thomas algorithm. This includes c' when effectiveness is zero (entire c').
728 : // For any other effectiveness, c' will be the same as c' when effectiveness for is zero for the nodes above the earth
729 : // tube. So, the c' for effectiveness of zero (cPrime0) can be reused as needed.
730 32 : for (int nodeNum = 0; nodeNum <= thisEarthTube.totNodes - 1; ++nodeNum) {
731 30 : thisEarthTube.cCoeff0[nodeNum] = thisEarthTube.cCoeff[nodeNum];
732 : }
733 2 : thisEarthTube.initCPrime0();
734 :
735 2 : auto &zone = state.dataHeatBal->Zone(thisEarthTube.ZonePtr);
736 32 : for (int nodeNum = 1; nodeNum <= thisEarthTube.totNodes; ++nodeNum) {
737 90 : SetupOutputVariable(state,
738 60 : format("Earth Tube Node Temperature {}", nodeNum),
739 : Constant::Units::C,
740 30 : thisEarthTube.tCurrent[nodeNum - 1],
741 : OutputProcessor::TimeStepType::Zone,
742 : OutputProcessor::StoreType::Average,
743 30 : zone.Name);
744 90 : SetupOutputVariable(state,
745 60 : format("Earth Tube Undisturbed Ground Temperature {}", nodeNum),
746 : Constant::Units::C,
747 30 : thisEarthTube.tUndist[nodeNum - 1],
748 : OutputProcessor::TimeStepType::Zone,
749 : OutputProcessor::StoreType::Average,
750 30 : zone.Name);
751 : }
752 4 : SetupOutputVariable(state,
753 : "Earth Tube Upper Boundary Ground Temperature",
754 : Constant::Units::C,
755 2 : thisEarthTube.tUpperBound,
756 : OutputProcessor::TimeStepType::Zone,
757 : OutputProcessor::StoreType::Average,
758 2 : zone.Name);
759 4 : SetupOutputVariable(state,
760 : "Earth Tube Lower Boundary Ground Temperature",
761 : Constant::Units::C,
762 2 : thisEarthTube.tLowerBound,
763 : OutputProcessor::TimeStepType::Zone,
764 : OutputProcessor::StoreType::Average,
765 2 : zone.Name);
766 : }
767 : } // ...end of firstTimeInits block
768 :
769 : Real64 timeElapsedLoc =
770 4296 : state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
771 4296 : if (state.dataEarthTube->timeElapsed !=
772 : timeElapsedLoc) { // time changed, update last with "current", avoids duplicate initializations and improper updates
773 4171 : if (state.dataGlobal->BeginDayFlag || state.dataGlobal->BeginEnvrnFlag) {
774 : // update all of the undisturbed temperatures (only need to do this once per day because the equation only changes as the day changes
775 228 : for (int etNum = 1; etNum <= totEarthTube; ++etNum) {
776 171 : auto &thisEarthTube = state.dataEarthTube->EarthTubeSys(etNum);
777 171 : if (thisEarthTube.ModelType != EarthTubeModelType::Vertical) continue; // Skip earth tubes that do not use vertical solution
778 58 : thisEarthTube.tUpperBound = thisEarthTube.calcUndisturbedGroundTemperature(state, thisEarthTube.depthUpperBound);
779 58 : thisEarthTube.tLowerBound = thisEarthTube.calcUndisturbedGroundTemperature(state, thisEarthTube.depthLowerBound);
780 928 : for (int nodeNum = 0; nodeNum <= thisEarthTube.totNodes - 1; ++nodeNum) {
781 870 : thisEarthTube.tUndist[nodeNum] = thisEarthTube.calcUndisturbedGroundTemperature(state, thisEarthTube.depthNode[nodeNum]);
782 : }
783 : }
784 : } // ...end of BeginDayFlag block
785 :
786 8321 : if (state.dataGlobal->BeginEnvrnFlag ||
787 4150 : (!state.dataGlobal->WarmupFlag && state.dataGlobal->BeginDayFlag && state.dataGlobal->DayOfSim == 1)) {
788 108 : for (int etNum = 1; etNum <= totEarthTube; ++etNum) {
789 81 : auto &thisEarthTube = state.dataEarthTube->EarthTubeSys(etNum);
790 81 : if (thisEarthTube.ModelType != EarthTubeModelType::Vertical) continue; // Skip earth tubes that do not use vertical solution
791 448 : for (int nodeNum = 0; nodeNum <= thisEarthTube.totNodes - 1; ++nodeNum) {
792 420 : thisEarthTube.tLast[nodeNum] = thisEarthTube.tUndist[nodeNum];
793 420 : thisEarthTube.tCurrent[nodeNum] = thisEarthTube.tLast[nodeNum];
794 : }
795 : }
796 : }
797 :
798 16684 : for (int etNum = 1; etNum <= totEarthTube; ++etNum) {
799 12513 : auto &thisEarthTube = state.dataEarthTube->EarthTubeSys(etNum);
800 12513 : if (thisEarthTube.ModelType != EarthTubeModelType::Vertical) continue; // Skip earth tubes that do not use vertical solution
801 67424 : for (int nodeNum = 0; nodeNum <= thisEarthTube.totNodes - 1; ++nodeNum) {
802 63210 : thisEarthTube.tLast[nodeNum] = thisEarthTube.tCurrent[nodeNum];
803 : }
804 : }
805 : }
806 4296 : state.dataEarthTube->timeElapsed = timeElapsedLoc;
807 4296 : }
808 :
809 2 : void EarthTubeData::initCPrime0()
810 : {
811 : // Calculate c' for when effectiveness is zero. Will use these values when there is no air flow through the earth tube
812 : // and also use the values in the top portion of the solution (before the earth tube node) since these will not change.
813 2 : this->cPrime0[0] = this->cCoeff0[0] / this->bCoeff[0];
814 28 : for (int i = 1; i <= this->totNodes - 2; ++i) {
815 26 : this->cPrime0[i] = this->cCoeff0[i] / (this->bCoeff[i] - this->aCoeff[i] * this->cPrime0[i - 1]);
816 : }
817 2 : cPrime0[this->totNodes - 1] = 0.0;
818 2 : }
819 :
820 4296 : void CalcEarthTube(EnergyPlusData &state)
821 : {
822 :
823 : // SUBROUTINE INFORMATION:
824 : // AUTHOR Kwang Ho Lee
825 : // DATE WRITTEN November 2005
826 :
827 : // PURPOSE OF THIS SUBROUTINE:
828 : // This subroutine simulates the components making up the EarthTube unit.
829 :
830 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
831 : Real64 Process1; // Variable Used in the Middle of the Calculation
832 : Real64 GroundTempt; // Ground Temperature between Depth z at time t
833 :
834 : Real64 AirThermCond; // Thermal Conductivity of Air (W/mC)
835 : Real64 AirKinemVisco; // Kinematic Viscosity of Air (m2/s)
836 : Real64 AirThermDiffus; // Thermal Diffusivity of Air (m2/s)
837 : Real64 Re; // Reynolds Number for Flow Inside Pipe
838 : Real64 Pr; // Prandtl Number for Flow Inside Pipe
839 : Real64 Nu; // Nusselt Number for Flow Inside Pipe
840 : Real64 fa; // Friction Factor of Pipe
841 : Real64 PipeHeatTransCoef; // Convective Heat Transfer Coefficient at Inner Pipe Surface
842 : Real64 Rc; // Thermal Resistance due to Convection between Air and Pipe Inner Surface
843 : Real64 Rp; // Thermal Resistance due to Conduction between Pipe Inner and Outer Surface
844 : Real64 Rs; // Thermal Resistance due to Conduction between Pipe Outer Surface and Soil
845 : Real64 Rt; // Total Thermal Resistance between Pipe Air and Soil
846 : Real64 OverallHeatTransCoef; // Overall Heat Transfer Coefficient of Earth Tube
847 : Real64 AverPipeAirVel; // Average Pipe Air Velocity (m/s)
848 : Real64 AirMassFlowRate; // Actual Mass Flow Rate of Air inside Pipe
849 : Real64 AirSpecHeat; // Specific Heat of Air
850 : Real64 AirDensity; // Density of Air
851 : Real64 EVF;
852 :
853 4296 : int numEarthTubes = (int)state.dataEarthTube->EarthTubeSys.size();
854 4296 : Real64 outTdb = state.dataEnvrn->OutDryBulbTemp;
855 17184 : for (int Loop = 1; Loop <= numEarthTubes; ++Loop) {
856 12888 : auto &thisEarthTube = state.dataEarthTube->EarthTubeSys(Loop);
857 12888 : int NZ = thisEarthTube.ZonePtr;
858 12888 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(NZ);
859 12888 : thisZoneHB.MCPTE = 0.0;
860 12888 : thisZoneHB.MCPE = 0.0;
861 12888 : thisZoneHB.EAMFL = 0.0;
862 12888 : thisZoneHB.EAMFLxHumRat = 0.0;
863 12888 : thisEarthTube.FanPower = 0.0;
864 :
865 : // Don't simulate for Basic Solution if the zone is below the minimum temperature limit, above the maximum temperature limit
866 : // or below the temperature difference limit
867 25776 : bool tempShutDown = thisZoneHB.MAT < thisEarthTube.MinTemperature || thisZoneHB.MAT > thisEarthTube.MaxTemperature ||
868 12888 : std::abs(thisZoneHB.MAT - outTdb) < thisEarthTube.DelTemperature;
869 : // check for Basic model and some temperature limit preventing the earth tube from running
870 12888 : if ((thisEarthTube.ModelType == EarthTubeModelType::Basic) && (tempShutDown)) continue;
871 :
872 10876 : AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, outTdb, state.dataEnvrn->OutHumRat);
873 10876 : AirSpecHeat = Psychrometrics::PsyCpAirFnW(state.dataEnvrn->OutHumRat);
874 10876 : if (tempShutDown) {
875 281 : EVF = 0.0;
876 : } else {
877 10595 : EVF = thisEarthTube.DesignLevel * ScheduleManager::GetCurrentScheduleValue(state, thisEarthTube.SchedPtr);
878 : }
879 10876 : thisZoneHB.MCPE =
880 21752 : EVF * AirDensity * AirSpecHeat *
881 21752 : (thisEarthTube.ConstantTermCoef +
882 10876 : std::abs(outTdb - state.dataZoneTempPredictorCorrector->zoneHeatBalance(NZ).MAT) * thisEarthTube.TemperatureTermCoef +
883 10876 : state.dataEnvrn->WindSpeed * (thisEarthTube.VelocityTermCoef + state.dataEnvrn->WindSpeed * thisEarthTube.VelocitySQTermCoef));
884 :
885 10876 : thisZoneHB.EAMFL = thisZoneHB.MCPE / AirSpecHeat;
886 10876 : if (thisEarthTube.FanEfficiency > 0.0) {
887 10876 : thisEarthTube.FanPower = thisZoneHB.EAMFL * thisEarthTube.FanPressure / (thisEarthTube.FanEfficiency * AirDensity);
888 : }
889 :
890 10876 : AverPipeAirVel = EVF / Constant::Pi / pow_2(thisEarthTube.r1);
891 10876 : AirMassFlowRate = EVF * AirDensity;
892 :
893 10876 : if (thisEarthTube.ModelType == EarthTubeModelType::Basic) {
894 : // Calculation of Ground Temperature at Depth z at time t for Basic model
895 6496 : GroundTempt = thisEarthTube.calcUndisturbedGroundTemperature(state, thisEarthTube.z);
896 6496 : thisEarthTube.GroundTempt = GroundTempt;
897 : }
898 :
899 : // Calculation of Convective Heat Transfer Coefficient at Inner Pipe Surface
900 10876 : AirThermCond = 0.02442 + 0.6992 * outTdb / 10000.0;
901 10876 : AirKinemVisco = (0.1335 + 0.000925 * outTdb) / 10000.0;
902 10876 : AirThermDiffus = (0.0014 * outTdb + 0.1872) / 10000.0;
903 10876 : Re = 2.0 * thisEarthTube.r1 * AverPipeAirVel / AirKinemVisco;
904 10876 : Pr = AirKinemVisco / AirThermDiffus;
905 10876 : if (Re <= 2300.0) {
906 281 : Nu = 3.66;
907 10595 : } else if (Re <= 4000.0) {
908 0 : fa = std::pow(1.58 * std::log(Re) - 3.28, -2);
909 0 : Process1 = (fa / 2.0) * (Re - 1000.0) * Pr / (1.0 + 12.7 * std::sqrt(fa / 2.0) * (std::pow(Pr, 2.0 / 3.0) - 1.0));
910 0 : Nu = (Process1 - 3.66) / (1700.0) * Re + (4000.0 * 3.66 - 2300.0 * Process1) / 1700.0;
911 : } else {
912 10595 : fa = std::pow(1.58 * std::log(Re) - 3.28, -2);
913 10595 : Nu = (fa / 2.0) * (Re - 1000.0) * Pr / (1.0 + 12.7 * std::sqrt(fa / 2.0) * (std::pow(Pr, 2.0 / 3.0) - 1.0));
914 : }
915 10876 : PipeHeatTransCoef = Nu * AirThermCond / 2.0 / thisEarthTube.r1;
916 :
917 : // Calculation of Thermal Resistance and Overall Heat Transfer Coefficient
918 10876 : Rc = 1.0 / 2.0 / Constant::Pi / thisEarthTube.r1 / PipeHeatTransCoef;
919 10876 : Rp = std::log((thisEarthTube.r1 + thisEarthTube.r2) / thisEarthTube.r1) / 2.0 / Constant::Pi / thisEarthTube.PipeThermCond;
920 10876 : if (thisEarthTube.r3 > 0.0) {
921 6496 : Rs = std::log((thisEarthTube.r1 + thisEarthTube.r2 + thisEarthTube.r3) / (thisEarthTube.r1 + thisEarthTube.r2)) / 2.0 / Constant::Pi /
922 6496 : thisEarthTube.SoilThermCond;
923 : } else { // for the Vertical solution .r3 was reset to zero for this
924 4380 : Rs = 0.0;
925 : }
926 10876 : Rt = Rc + Rp + Rs;
927 10876 : OverallHeatTransCoef = 1.0 / Rt;
928 :
929 10876 : switch (thisEarthTube.ModelType) {
930 4380 : case EarthTubeModelType::Vertical: {
931 : // First calculate term that will need to be added at the diagonal for flow and then solve the matrix for new temperatures
932 : Real64 eff; // effectiveness
933 4380 : if (AirMassFlowRate > 0.0) {
934 : // Calculate the NTU parameter: NTU = UA/[(Mdot*Cp)min] where Mdot*Cp is for the air side
935 : // where: U = OverallHeatTransCoef
936 : // A = 2*Pi*r1*TubeLength
937 4099 : Real64 NTU =
938 4099 : OverallHeatTransCoef * 2.0 * Constant::Pi * thisEarthTube.r1 * thisEarthTube.PipeLength / (AirMassFlowRate * AirSpecHeat);
939 :
940 : // Effectiveness is 1 - e(-NTU)
941 4099 : Real64 constexpr maxExpPower(50.0); // Maximum power after which EXP argument would be zero for DP variables
942 4099 : if (NTU > maxExpPower) {
943 0 : eff = 1.0;
944 : } else {
945 4099 : eff = 1.0 - std::exp(-NTU);
946 : }
947 : } else { // if no flow, then eff is zero
948 281 : eff = 0.0;
949 : }
950 :
951 4380 : Real64 airFlowTerm = AirMassFlowRate * AirSpecHeat * eff * thisEarthTube.airFlowCoeff;
952 4380 : thisEarthTube.calcVerticalEarthTube(state, airFlowTerm);
953 :
954 4380 : int nodeET = state.dataEarthTube->EarthTubePars(thisEarthTube.vertParametersPtr).numNodesAbove;
955 4380 : if (eff <= 0.0) { // no flow--air temperature leaving earth tube is the same as what went in
956 281 : thisEarthTube.InsideAirTemp = outTdb;
957 4099 : } else if (eff >= 1.0) { // effectiveness is one so leaving temperature is the same as the ground node temperatre
958 0 : thisEarthTube.InsideAirTemp = thisEarthTube.tCurrent[nodeET];
959 : } else { // the temperature is between the inlet and ground temperatures
960 4099 : thisEarthTube.InsideAirTemp = outTdb - eff * (outTdb - thisEarthTube.tCurrent[nodeET]);
961 : }
962 :
963 4380 : } break;
964 6496 : case EarthTubeModelType::Basic: { // Basic model
965 6496 : if (AirMassFlowRate * AirSpecHeat == 0.0) {
966 0 : thisEarthTube.InsideAirTemp = GroundTempt;
967 :
968 : } else {
969 :
970 : // Calculation of Pipe Outlet Air Temperature
971 6496 : if (outTdb > GroundTempt) {
972 6484 : Process1 =
973 6484 : (std::log(std::abs(outTdb - GroundTempt)) * AirMassFlowRate * AirSpecHeat - OverallHeatTransCoef * thisEarthTube.PipeLength) /
974 6484 : (AirMassFlowRate * AirSpecHeat);
975 6484 : thisEarthTube.InsideAirTemp = std::exp(Process1) + GroundTempt;
976 12 : } else if (outTdb == GroundTempt) {
977 0 : thisEarthTube.InsideAirTemp = GroundTempt;
978 : } else {
979 12 : Process1 =
980 12 : (std::log(std::abs(outTdb - GroundTempt)) * AirMassFlowRate * AirSpecHeat - OverallHeatTransCoef * thisEarthTube.PipeLength) /
981 12 : (AirMassFlowRate * AirSpecHeat);
982 12 : thisEarthTube.InsideAirTemp = GroundTempt - std::exp(Process1);
983 : }
984 : }
985 6496 : } break;
986 0 : default: { // should never get here
987 0 : assert(false);
988 : } break;
989 : }
990 :
991 10876 : thisEarthTube.CalcEarthTubeHumRat(state, NZ);
992 : }
993 4296 : }
994 :
995 7482 : Real64 EarthTubeData::calcUndisturbedGroundTemperature(EnergyPlusData &state, Real64 depth)
996 : {
997 7482 : return this->AverSoilSurTemp -
998 14964 : this->ApmlSoilSurTemp * std::exp(-depth * std::sqrt(Constant::Pi / 365.0 / this->SoilThermDiff)) *
999 7482 : std::cos(2.0 * Constant::Pi / 365.0 *
1000 7482 : (state.dataEnvrn->DayOfYear - this->SoilSurPhaseConst - depth / 2.0 * std::sqrt(365.0 / Constant::Pi / this->SoilThermDiff)));
1001 : }
1002 :
1003 4380 : void EarthTubeData::calcVerticalEarthTube(EnergyPlusData &state, Real64 airFlowTerm)
1004 : {
1005 : // Perform matrix calculations to model the earth tube using the vertical solution.
1006 : // At this point, temperatures have already been shifted so tLast is correct and
1007 : // undisturbed ground temperature have also been calculated. We need to assign/update
1008 : // vectors of coefficients and then perform the Thomas algorithm.
1009 : // Note that airFlowTerm is mdot_a*cp_a*eff*deltat/rho_soil/cp_soil/nodethickness_et/width/length
1010 :
1011 4380 : int nodeET = state.dataEarthTube->EarthTubePars(this->vertParametersPtr).numNodesAbove;
1012 4380 : int nodeLast = this->totNodes - 1; // minus one because c++ arrays start at 0
1013 :
1014 : // First, calculate cPrime in the forward sweep.
1015 : // If airFlowTerm is zero, there is no flow so we can use can use cPrime0 for cPrime.
1016 4380 : if (airFlowTerm <= 0.0) {
1017 4442 : for (int nodeNum = 0; nodeNum <= nodeLast; ++nodeNum) {
1018 4161 : this->cPrime[nodeNum] = this->cPrime0[nodeNum];
1019 : }
1020 : } else { // there is positive flow so calculate cPrime
1021 4099 : this->cPrime[0] = this->cCoeff[0] / this->bCoeff[0];
1022 61539 : for (int nodeNum = 1; nodeNum <= nodeLast; ++nodeNum) {
1023 57440 : Real64 addTerm = 0.0;
1024 57440 : if (nodeNum == nodeET) addTerm = airFlowTerm;
1025 57440 : this->cPrime[nodeNum] = this->cCoeff[nodeNum] / (this->bCoeff[nodeNum] + addTerm - this->aCoeff[nodeNum] * this->cPrime[nodeNum - 1]);
1026 : }
1027 : }
1028 :
1029 : // Second, set-up dCoeff
1030 4380 : this->dCoeff[0] = this->tLast[0] + this->dMult0 * this->tUpperBound;
1031 61320 : for (int nodeNum = 1; nodeNum <= nodeLast - 1; ++nodeNum) {
1032 56940 : if (nodeNum != nodeET) {
1033 52560 : this->dCoeff[nodeNum] = this->tLast[nodeNum];
1034 : } else {
1035 4380 : this->dCoeff[nodeNum] = this->tLast[nodeNum] + airFlowTerm * state.dataEnvrn->OutDryBulbTemp;
1036 : }
1037 : }
1038 4380 : this->dCoeff[nodeLast] = this->tLast[nodeLast] + this->dMultN * this->tLowerBound;
1039 :
1040 : // Third, calculate dPrime in the forward sweep.
1041 4380 : this->dPrime[0] = this->dCoeff[0] / this->bCoeff[0];
1042 65700 : for (int nodeNum = 1; nodeNum <= nodeLast; ++nodeNum) {
1043 61320 : Real64 addTerm = 0.0;
1044 61320 : if (nodeNum == nodeET) addTerm = airFlowTerm;
1045 122640 : this->dPrime[nodeNum] = (this->dCoeff[nodeNum] - this->aCoeff[nodeNum] * this->dPrime[nodeNum - 1]) /
1046 61320 : (this->bCoeff[nodeNum] + addTerm - this->aCoeff[nodeNum] * this->cPrime[nodeNum - 1]);
1047 : }
1048 :
1049 : // Finally, obtain the solution (tCurrent) by back substitution.
1050 4380 : this->tCurrent[nodeLast] = this->dPrime[nodeLast];
1051 65700 : for (int nodeNum = nodeLast - 1; nodeNum >= 0; --nodeNum) {
1052 61320 : this->tCurrent[nodeNum] = this->dPrime[nodeNum] - this->cPrime[nodeNum] * this->tCurrent[nodeNum + 1];
1053 : }
1054 4380 : }
1055 :
1056 10876 : void EarthTubeData::CalcEarthTubeHumRat(EnergyPlusData &state, int const NZ)
1057 : { // Zone number (index)
1058 :
1059 : // SUBROUTINE INFORMATION:
1060 : // AUTHOR Kwang Ho Lee
1061 : // DATE WRITTEN November 2005
1062 : // MODIFIED Rick Strand, June 2017 (made this a separate subroutine)
1063 :
1064 : // PURPOSE OF THIS SUBROUTINE:
1065 : // This subroutine determines the leaving humidity ratio for the EarthTube
1066 : // and calculates parameters associated with humidity ratio.
1067 :
1068 10876 : Real64 InsideDewPointTemp = Psychrometrics::PsyTdpFnWPb(state, state.dataEnvrn->OutHumRat, state.dataEnvrn->OutBaroPress);
1069 10876 : Real64 InsideHumRat = 0.0;
1070 10876 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(NZ);
1071 :
1072 10876 : if (this->InsideAirTemp >= InsideDewPointTemp) {
1073 1099 : InsideHumRat = state.dataEnvrn->OutHumRat;
1074 1099 : Real64 const InsideEnthalpy = Psychrometrics::PsyHFnTdbW(this->InsideAirTemp, state.dataEnvrn->OutHumRat);
1075 : // Intake fans will add some heat to the air, raising the temperature for an intake fan...
1076 1099 : if (this->FanType == Ventilation::Intake) {
1077 : Real64 OutletAirEnthalpy;
1078 337 : if (thisZoneHB.EAMFL == 0.0) {
1079 136 : OutletAirEnthalpy = InsideEnthalpy;
1080 : } else {
1081 201 : OutletAirEnthalpy = InsideEnthalpy + this->FanPower / thisZoneHB.EAMFL;
1082 : }
1083 337 : this->AirTemp = Psychrometrics::PsyTdbFnHW(OutletAirEnthalpy, state.dataEnvrn->OutHumRat);
1084 : } else {
1085 762 : this->AirTemp = this->InsideAirTemp;
1086 : }
1087 1099 : thisZoneHB.MCPTE = thisZoneHB.MCPE * this->AirTemp;
1088 :
1089 : } else {
1090 9777 : InsideHumRat = Psychrometrics::PsyWFnTdpPb(state, this->InsideAirTemp, state.dataEnvrn->OutBaroPress);
1091 9777 : Real64 const InsideEnthalpy = Psychrometrics::PsyHFnTdbW(this->InsideAirTemp, InsideHumRat);
1092 : // Intake fans will add some heat to the air, raising the temperature for an intake fan...
1093 9777 : if (this->FanType == Ventilation::Intake) {
1094 : Real64 OutletAirEnthalpy;
1095 3465 : if (thisZoneHB.EAMFL == 0.0) {
1096 0 : OutletAirEnthalpy = InsideEnthalpy;
1097 : } else {
1098 3465 : OutletAirEnthalpy = InsideEnthalpy + this->FanPower / thisZoneHB.EAMFL;
1099 : }
1100 3465 : this->AirTemp = Psychrometrics::PsyTdbFnHW(OutletAirEnthalpy, InsideHumRat);
1101 : } else {
1102 6312 : this->AirTemp = this->InsideAirTemp;
1103 : }
1104 9777 : thisZoneHB.MCPTE = thisZoneHB.MCPE * this->AirTemp;
1105 : }
1106 :
1107 10876 : this->HumRat = InsideHumRat;
1108 10876 : this->WetBulbTemp = Psychrometrics::PsyTwbFnTdbWPb(state, this->InsideAirTemp, InsideHumRat, state.dataEnvrn->OutBaroPress);
1109 10876 : thisZoneHB.EAMFLxHumRat = thisZoneHB.EAMFL * InsideHumRat;
1110 10876 : }
1111 :
1112 4296 : void ReportEarthTube(EnergyPlusData &state)
1113 : {
1114 :
1115 : // SUBROUTINE INFORMATION:
1116 : // AUTHOR Kwang Ho Lee
1117 : // DATE WRITTEN November 2005
1118 : // MODIFIED B. Griffith April 2010 added output reports
1119 :
1120 : // PURPOSE OF THIS SUBROUTINE: This subroutine fills remaining report variables.
1121 :
1122 4296 : Real64 const ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
1123 :
1124 17184 : for (int ZoneLoop = 1; ZoneLoop <= state.dataGlobal->NumOfZones; ++ZoneLoop) { // Start of zone loads report variable update loop ...
1125 12888 : auto &thisZone = state.dataEarthTube->ZnRptET(ZoneLoop);
1126 12888 : auto const &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneLoop);
1127 :
1128 : // Break the infiltration load into heat gain and loss components.
1129 : Real64 const AirDensity =
1130 12888 : Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutHumRat);
1131 12888 : Real64 const CpAir = Psychrometrics::PsyCpAirFnW(state.dataEnvrn->OutHumRat);
1132 12888 : thisZone.EarthTubeVolume = (thisZoneHB.MCPE / CpAir / AirDensity) * ReportingConstant;
1133 12888 : thisZone.EarthTubeMass = (thisZoneHB.MCPE / CpAir) * ReportingConstant;
1134 12888 : thisZone.EarthTubeVolFlowRate = thisZoneHB.MCPE / CpAir / AirDensity;
1135 12888 : thisZone.EarthTubeVolFlowRateStd = thisZoneHB.MCPE / CpAir / state.dataEnvrn->StdRhoAir;
1136 12888 : thisZone.EarthTubeMassFlowRate = thisZoneHB.MCPE / CpAir;
1137 12888 : thisZone.EarthTubeWaterMassFlowRate = thisZoneHB.EAMFLxHumRat;
1138 :
1139 12888 : thisZone.EarthTubeFanElec = 0.0;
1140 12888 : thisZone.EarthTubeAirTemp = 0.0;
1141 25776 : for (auto const &thisEarthTube : state.dataEarthTube->EarthTubeSys) {
1142 25776 : if (thisEarthTube.ZonePtr == ZoneLoop) {
1143 12888 : thisZone.EarthTubeFanElec = thisEarthTube.FanPower * ReportingConstant;
1144 12888 : thisZone.EarthTubeFanElecPower = thisEarthTube.FanPower;
1145 :
1146 : // Break the EarthTube load into heat gain and loss components.
1147 12888 : if (thisZoneHB.ZT > thisEarthTube.AirTemp) {
1148 12766 : thisZone.EarthTubeHeatLoss = thisZoneHB.MCPE * (thisZoneHB.ZT - thisEarthTube.AirTemp) * ReportingConstant;
1149 12766 : thisZone.EarthTubeHeatLossRate = thisZoneHB.MCPE * (thisZoneHB.ZT - thisEarthTube.AirTemp);
1150 12766 : thisZone.EarthTubeHeatGain = 0.0;
1151 12766 : thisZone.EarthTubeHeatGainRate = 0.0;
1152 : } else {
1153 122 : thisZone.EarthTubeHeatGain = thisZoneHB.MCPE * (thisEarthTube.AirTemp - thisZoneHB.ZT) * ReportingConstant;
1154 122 : thisZone.EarthTubeHeatGainRate = thisZoneHB.MCPE * (thisEarthTube.AirTemp - thisZoneHB.ZT);
1155 122 : thisZone.EarthTubeHeatLoss = 0.0;
1156 122 : thisZone.EarthTubeHeatLossRate = 0.0;
1157 : }
1158 :
1159 12888 : thisZone.EarthTubeAirTemp = thisEarthTube.AirTemp;
1160 12888 : thisZone.EarthTubeWetBulbTemp = thisEarthTube.WetBulbTemp;
1161 12888 : thisZone.EarthTubeHumRat = thisEarthTube.HumRat;
1162 12888 : thisZone.EarthTubeOATreatmentPower = thisZoneHB.MCPE * (thisEarthTube.AirTemp - state.dataEnvrn->OutDryBulbTemp);
1163 12888 : break; // DO loop
1164 : }
1165 12888 : }
1166 :
1167 : } // ... end of zone loads report variable update loop.
1168 4296 : }
1169 :
1170 : } // namespace EnergyPlus::EarthTube
|