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 <cmath>
50 : #include <memory>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Array.functions.hh>
54 : #include <ObjexxFCL/Array3D.hh>
55 : #include <ObjexxFCL/Fmath.hh>
56 :
57 : // EnergyPlus Headers
58 : #include <EnergyPlus/BranchNodeConnections.hh>
59 : #include <EnergyPlus/Construction.hh>
60 : #include <EnergyPlus/ConvectionCoefficients.hh>
61 : #include <EnergyPlus/Data/EnergyPlusData.hh>
62 : #include <EnergyPlus/DataEnvironment.hh>
63 : #include <EnergyPlus/DataHVACGlobals.hh>
64 : #include <EnergyPlus/DataHeatBalance.hh>
65 : #include <EnergyPlus/DataIPShortCuts.hh>
66 : #include <EnergyPlus/DataLoopNode.hh>
67 : #include <EnergyPlus/FluidProperties.hh>
68 : #include <EnergyPlus/General.hh>
69 : #include <EnergyPlus/GlobalNames.hh>
70 : #include <EnergyPlus/GroundTemperatureModeling/GroundTemperatureModelManager.hh>
71 : #include <EnergyPlus/HeatBalanceInternalHeatGains.hh>
72 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
73 : #include <EnergyPlus/Material.hh>
74 : #include <EnergyPlus/NodeInputManager.hh>
75 : #include <EnergyPlus/OutAirNodeManager.hh>
76 : #include <EnergyPlus/OutputProcessor.hh>
77 : #include <EnergyPlus/PipeHeatTransfer.hh>
78 : #include <EnergyPlus/Plant/DataPlant.hh>
79 : #include <EnergyPlus/PlantUtilities.hh>
80 : #include <EnergyPlus/ScheduleManager.hh>
81 : #include <EnergyPlus/UtilityRoutines.hh>
82 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
83 :
84 : namespace EnergyPlus::PipeHeatTransfer {
85 :
86 : // Module containing the routines dealing with pipes with transport delay
87 : // and heat transfer.
88 :
89 : // MODULE INFORMATION:
90 : // AUTHOR Simon Rees
91 : // DATE WRITTEN July 2007
92 : // MODIFIED May 2008
93 : // RE-ENGINEERED na
94 :
95 : // PURPOSE OF THIS MODULE:
96 : // The purpose of this module is to simulate a pipe with heat transfer
97 :
98 : // METHODOLOGY EMPLOYED:
99 : // An implicit finite difference method is used to solve the temperature distribution of the
100 : // fluid in the pipe as a result of the transport delay and heat transfer to the environment.
101 : // For buried pipes, the simulation involves an implicit finite difference model of the soil,
102 : // which was originally based on Piechowski's thesis (below). Equation numbers for
103 : // pipe:underground calculations are from Piechowski's thesis. In Piechowski, the near-pipe
104 : // region is solved with a detailed finite difference grid, this current model makes use of
105 : // the Hanby model to simulate the actual pipe.
106 :
107 : // Kusuda, T. & Achenbach, P. (1965), 'Earth temperature and thermal diffusivity at
108 : // selected stations in the united states', ASHRAE Transactions 71(1), 61-75.
109 : // Piechowski, M. (1996), A Ground Coupled Heat Pump System with Energy Storage,
110 : // PhD thesis, University of Melbourne.
111 :
112 : // OTHER NOTES: Equation Numbers listed in buried pipe routines are from Piechowski's thesis
113 :
114 : enum class PipeIndoorBoundaryType
115 : {
116 : Invalid = -1,
117 : Zone,
118 : Schedule,
119 : Num
120 : };
121 : constexpr std::array<std::string_view, static_cast<int>(PipeIndoorBoundaryType::Num)> pipeIndoorBoundaryTypeNamesUC = {"ZONE", "SCHEDULE"};
122 :
123 : // Using/Aliasing
124 : using namespace GroundTemperatureManager;
125 :
126 : // Functions
127 :
128 4 : PlantComponent *PipeHTData::factory(EnergyPlusData &state, DataPlant::PlantEquipmentType objectType, std::string const &objectName)
129 : {
130 : // Process the input data for pipes if it hasn't been done already
131 4 : if (state.dataPipeHT->GetPipeInputFlag) {
132 4 : GetPipesHeatTransfer(state);
133 4 : state.dataPipeHT->GetPipeInputFlag = false;
134 : }
135 : // Now look for this particular pipe in the list
136 4 : for (auto &pipe : state.dataPipeHT->PipeHT) {
137 4 : if (pipe.Type == objectType && pipe.Name == objectName) {
138 4 : return &pipe;
139 : }
140 : }
141 : // If we didn't find it, fatal
142 0 : ShowFatalError(state, "PipeHTFactory: Error getting inputs for pipe named: " + objectName);
143 : // Shut up the compiler
144 0 : return nullptr;
145 : }
146 :
147 58388 : void PipeHTData::simulate(EnergyPlusData &state,
148 : [[maybe_unused]] const PlantLocation &calledFromLocation,
149 : bool const FirstHVACIteration,
150 : [[maybe_unused]] Real64 &CurLoad,
151 : [[maybe_unused]] bool const RunFlag)
152 : {
153 58388 : this->InitPipesHeatTransfer(state, FirstHVACIteration);
154 : // make the calculations
155 803776 : for (int InnerTimeStepCtr = 1; InnerTimeStepCtr <= state.dataPipeHT->nsvNumInnerTimeSteps; ++InnerTimeStepCtr) {
156 745388 : switch (this->EnvironmentPtr) {
157 186347 : case EnvrnPtr::GroundEnv: {
158 186347 : this->CalcBuriedPipeSoil(state);
159 186347 : } break;
160 559041 : default: {
161 559041 : this->CalcPipesHeatTransfer(state);
162 559041 : } break;
163 : }
164 745388 : this->PushInnerTimeStepArrays();
165 : }
166 : // update variables
167 58388 : this->UpdatePipesHeatTransfer(state);
168 : // update report variables
169 58388 : this->ReportPipesHeatTransfer(state);
170 58388 : }
171 :
172 745388 : void PipeHTData::PushInnerTimeStepArrays()
173 : {
174 745388 : if (this->EnvironmentPtr == EnvrnPtr::GroundEnv) {
175 3726940 : for (int LengthIndex = 2; LengthIndex <= this->NumSections; ++LengthIndex) {
176 31865337 : for (int DepthIndex = 1; DepthIndex <= this->NumDepthNodes; ++DepthIndex) {
177 113298976 : for (int WidthIndex = 2; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
178 : // This will store the old 'current' values as the new 'previous values' This allows
179 : // us to use the previous time array as history terms in the equations
180 84974232 : this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Previous) =
181 84974232 : this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Current);
182 : }
183 : }
184 : }
185 : }
186 : // Then update the Hanby near pipe model temperatures
187 745388 : this->PreviousFluidTemp = this->FluidTemp;
188 745388 : this->PreviousPipeTemp = this->PipeTemp;
189 745388 : }
190 :
191 4 : void GetPipesHeatTransfer(EnergyPlusData &state)
192 : {
193 :
194 : // SUBROUTINE INFORMATION:
195 : // AUTHOR Simon Rees
196 : // DATE WRITTEN July 2007
197 : // MODIFIED na
198 : // RE-ENGINEERED na
199 : // PURPOSE OF THIS SUBROUTINE:
200 : // This subroutine reads the input for hydronic Pipe Heat Transfers
201 : // from the user input file. This will contain all of the information
202 : // needed to define and simulate the surface.
203 :
204 : // Using/Aliasing
205 : using BranchNodeConnections::TestCompSet;
206 :
207 : using NodeInputManager::GetOnlySingleNode;
208 : using namespace DataLoopNode;
209 : using OutAirNodeManager::CheckOutAirNodeNumber;
210 : using ScheduleManager::GetScheduleIndex;
211 :
212 : // SUBROUTINE PARAMETER DEFINITIONS:
213 4 : int constexpr NumPipeSections(20);
214 4 : int constexpr NumberOfDepthNodes(8); // Number of nodes in the cartesian grid-Should be an even # for now
215 4 : Real64 const SecondsInHour(DataGlobalConstants::SecInHour);
216 :
217 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
218 4 : bool ErrorsFound(false); // Set to true if errors in input,
219 :
220 : // fatal at end of routine
221 : int IOStatus; // Used in GetObjectItem
222 : int Item; // Item to be "gotten"
223 : int PipeItem;
224 : int NumAlphas; // Number of Alphas for each GetObjectItem call
225 : int NumNumbers; // Number of Numbers for each GetObjectItem call
226 : int NumOfPipeHTInt; // Number of Pipe Heat Transfer objects
227 : int NumOfPipeHTExt; // Number of Pipe Heat Transfer objects
228 : int NumOfPipeHTUG; // Number of Pipe Heat Transfer objects
229 : int NumSections; // total number of sections in pipe
230 4 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
231 : // Initializations and allocations
232 4 : cCurrentModuleObject = "Pipe:Indoor";
233 4 : NumOfPipeHTInt = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
234 4 : cCurrentModuleObject = "Pipe:Outdoor";
235 4 : NumOfPipeHTExt = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
236 4 : cCurrentModuleObject = "Pipe:Underground";
237 4 : NumOfPipeHTUG = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
238 :
239 4 : state.dataPipeHT->nsvNumOfPipeHT = NumOfPipeHTInt + NumOfPipeHTExt + NumOfPipeHTUG;
240 : // allocate data structures
241 4 : if (allocated(state.dataPipeHT->PipeHT)) state.dataPipeHT->PipeHT.deallocate();
242 :
243 4 : state.dataPipeHT->PipeHT.allocate(state.dataPipeHT->nsvNumOfPipeHT);
244 4 : state.dataPipeHT->PipeHTUniqueNames.reserve(static_cast<unsigned>(state.dataPipeHT->nsvNumOfPipeHT));
245 4 : Item = 0;
246 :
247 4 : cCurrentModuleObject = "Pipe:Indoor";
248 6 : for (PipeItem = 1; PipeItem <= NumOfPipeHTInt; ++PipeItem) {
249 2 : ++Item;
250 : // get the object name
251 14 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
252 : cCurrentModuleObject,
253 : PipeItem,
254 2 : state.dataIPShortCut->cAlphaArgs,
255 : NumAlphas,
256 2 : state.dataIPShortCut->rNumericArgs,
257 : NumNumbers,
258 : IOStatus,
259 2 : state.dataIPShortCut->lNumericFieldBlanks,
260 2 : state.dataIPShortCut->lAlphaFieldBlanks,
261 2 : state.dataIPShortCut->cAlphaFieldNames,
262 2 : state.dataIPShortCut->cNumericFieldNames);
263 :
264 4 : GlobalNames::VerifyUniqueInterObjectName(state,
265 2 : state.dataPipeHT->PipeHTUniqueNames,
266 2 : state.dataIPShortCut->cAlphaArgs(1),
267 : cCurrentModuleObject,
268 2 : state.dataIPShortCut->cAlphaFieldNames(1),
269 : ErrorsFound);
270 2 : state.dataPipeHT->PipeHT(Item).Name = state.dataIPShortCut->cAlphaArgs(1);
271 2 : state.dataPipeHT->PipeHT(Item).Type = DataPlant::PlantEquipmentType::PipeInterior;
272 :
273 : // General user input data
274 2 : state.dataPipeHT->PipeHT(Item).Construction = state.dataIPShortCut->cAlphaArgs(2);
275 2 : state.dataPipeHT->PipeHT(Item).ConstructionNum =
276 2 : UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataConstruction->Construct);
277 :
278 2 : if (state.dataPipeHT->PipeHT(Item).ConstructionNum == 0) {
279 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(2) + '=' + state.dataIPShortCut->cAlphaArgs(2));
280 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
281 0 : ErrorsFound = true;
282 : }
283 :
284 : // get inlet node data
285 2 : state.dataPipeHT->PipeHT(Item).InletNode = state.dataIPShortCut->cAlphaArgs(3);
286 2 : state.dataPipeHT->PipeHT(Item).InletNodeNum = GetOnlySingleNode(state,
287 2 : state.dataIPShortCut->cAlphaArgs(3),
288 : ErrorsFound,
289 : DataLoopNode::ConnectionObjectType::PipeIndoor,
290 2 : state.dataIPShortCut->cAlphaArgs(1),
291 : DataLoopNode::NodeFluidType::Water,
292 : DataLoopNode::ConnectionType::Inlet,
293 : NodeInputManager::CompFluidStream::Primary,
294 2 : ObjectIsNotParent);
295 2 : if (state.dataPipeHT->PipeHT(Item).InletNodeNum == 0) {
296 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(3) + '=' + state.dataIPShortCut->cAlphaArgs(3));
297 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
298 0 : ErrorsFound = true;
299 : }
300 :
301 : // get outlet node data
302 2 : state.dataPipeHT->PipeHT(Item).OutletNode = state.dataIPShortCut->cAlphaArgs(4);
303 2 : state.dataPipeHT->PipeHT(Item).OutletNodeNum = GetOnlySingleNode(state,
304 2 : state.dataIPShortCut->cAlphaArgs(4),
305 : ErrorsFound,
306 : DataLoopNode::ConnectionObjectType::PipeIndoor,
307 2 : state.dataIPShortCut->cAlphaArgs(1),
308 : DataLoopNode::NodeFluidType::Water,
309 : DataLoopNode::ConnectionType::Outlet,
310 : NodeInputManager::CompFluidStream::Primary,
311 2 : ObjectIsNotParent);
312 2 : if (state.dataPipeHT->PipeHT(Item).OutletNodeNum == 0) {
313 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(4) + '=' + state.dataIPShortCut->cAlphaArgs(4));
314 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
315 0 : ErrorsFound = true;
316 : }
317 :
318 4 : TestCompSet(state,
319 : cCurrentModuleObject,
320 2 : state.dataIPShortCut->cAlphaArgs(1),
321 2 : state.dataIPShortCut->cAlphaArgs(3),
322 2 : state.dataIPShortCut->cAlphaArgs(4),
323 : "Pipe Nodes");
324 :
325 : // get environmental boundary condition type
326 :
327 2 : if (state.dataIPShortCut->lAlphaFieldBlanks(5)) state.dataIPShortCut->cAlphaArgs(5) = "ZONE";
328 :
329 : auto indoorType =
330 2 : static_cast<PipeIndoorBoundaryType>(getEnumerationValue(pipeIndoorBoundaryTypeNamesUC, state.dataIPShortCut->cAlphaArgs(5)));
331 2 : switch (indoorType) {
332 1 : case PipeIndoorBoundaryType::Zone:
333 1 : state.dataPipeHT->PipeHT(Item).EnvironmentPtr = EnvrnPtr::ZoneEnv;
334 1 : state.dataPipeHT->PipeHT(Item).EnvrZonePtr =
335 1 : UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(6), state.dataHeatBal->Zone);
336 1 : if (state.dataPipeHT->PipeHT(Item).EnvrZonePtr == 0) {
337 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(6) + '=' + state.dataIPShortCut->cAlphaArgs(6));
338 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
339 0 : ErrorsFound = true;
340 : }
341 1 : break;
342 :
343 1 : case PipeIndoorBoundaryType::Schedule:
344 1 : state.dataPipeHT->PipeHT(Item).EnvironmentPtr = EnvrnPtr::ScheduleEnv;
345 1 : state.dataPipeHT->PipeHT(Item).EnvrSchedule = state.dataIPShortCut->cAlphaArgs(7);
346 1 : state.dataPipeHT->PipeHT(Item).EnvrSchedPtr = GetScheduleIndex(state, state.dataPipeHT->PipeHT(Item).EnvrSchedule);
347 1 : state.dataPipeHT->PipeHT(Item).EnvrVelSchedule = state.dataIPShortCut->cAlphaArgs(8);
348 1 : state.dataPipeHT->PipeHT(Item).EnvrVelSchedPtr = GetScheduleIndex(state, state.dataPipeHT->PipeHT(Item).EnvrVelSchedule);
349 1 : if (state.dataPipeHT->PipeHT(Item).EnvrSchedPtr == 0) {
350 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(7) + '=' + state.dataIPShortCut->cAlphaArgs(7));
351 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
352 0 : ErrorsFound = true;
353 : }
354 1 : if (state.dataPipeHT->PipeHT(Item).EnvrVelSchedPtr == 0) {
355 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(8) + '=' + state.dataIPShortCut->cAlphaArgs(8));
356 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
357 0 : ErrorsFound = true;
358 : }
359 1 : break;
360 :
361 0 : default:
362 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(5) + '=' + state.dataIPShortCut->cAlphaArgs(5));
363 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
364 0 : ShowContinueError(state, R"(Should be "ZONE" or "SCHEDULE")"); // TODO rename point
365 0 : ErrorsFound = true;
366 : }
367 :
368 : // dimensions
369 2 : state.dataPipeHT->PipeHT(Item).PipeID = state.dataIPShortCut->rNumericArgs(1);
370 2 : if (state.dataIPShortCut->rNumericArgs(1) <= 0.0) { // not really necessary because idd field has "minimum> 0"
371 0 : ShowSevereError(state,
372 0 : format("GetPipesHeatTransfer: invalid {} of {:.4R}",
373 0 : state.dataIPShortCut->cNumericFieldNames(1),
374 0 : state.dataIPShortCut->rNumericArgs(1)));
375 0 : ShowContinueError(state, state.dataIPShortCut->cNumericFieldNames(1) + " must be > 0.0");
376 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
377 :
378 0 : ErrorsFound = true;
379 : }
380 :
381 2 : state.dataPipeHT->PipeHT(Item).Length = state.dataIPShortCut->rNumericArgs(2);
382 2 : if (state.dataIPShortCut->rNumericArgs(2) <= 0.0) { // not really necessary because idd field has "minimum> 0"
383 0 : ShowSevereError(state,
384 0 : format("GetPipesHeatTransfer: invalid {} of {:.4R}",
385 0 : state.dataIPShortCut->cNumericFieldNames(2),
386 0 : state.dataIPShortCut->rNumericArgs(2)));
387 0 : ShowContinueError(state, state.dataIPShortCut->cNumericFieldNames(2) + " must be > 0.0");
388 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
389 0 : ErrorsFound = true;
390 : }
391 :
392 2 : if (state.dataPipeHT->PipeHT(Item).ConstructionNum != 0) {
393 8 : state.dataPipeHT->PipeHT(Item).ValidatePipeConstruction(state,
394 : cCurrentModuleObject,
395 2 : state.dataIPShortCut->cAlphaArgs(2),
396 2 : state.dataIPShortCut->cAlphaFieldNames(2),
397 2 : state.dataPipeHT->PipeHT(Item).ConstructionNum,
398 : ErrorsFound);
399 : }
400 :
401 : } // end of input loop
402 :
403 4 : cCurrentModuleObject = "Pipe:Outdoor";
404 5 : for (PipeItem = 1; PipeItem <= NumOfPipeHTExt; ++PipeItem) {
405 1 : ++Item;
406 : // get the object name
407 7 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
408 : cCurrentModuleObject,
409 : PipeItem,
410 1 : state.dataIPShortCut->cAlphaArgs,
411 : NumAlphas,
412 1 : state.dataIPShortCut->rNumericArgs,
413 : NumNumbers,
414 : IOStatus,
415 1 : state.dataIPShortCut->lNumericFieldBlanks,
416 1 : state.dataIPShortCut->lAlphaFieldBlanks,
417 1 : state.dataIPShortCut->cAlphaFieldNames,
418 1 : state.dataIPShortCut->cNumericFieldNames);
419 :
420 2 : GlobalNames::VerifyUniqueInterObjectName(state,
421 1 : state.dataPipeHT->PipeHTUniqueNames,
422 1 : state.dataIPShortCut->cAlphaArgs(1),
423 : cCurrentModuleObject,
424 1 : state.dataIPShortCut->cAlphaFieldNames(1),
425 : ErrorsFound);
426 1 : state.dataPipeHT->PipeHT(Item).Name = state.dataIPShortCut->cAlphaArgs(1);
427 1 : state.dataPipeHT->PipeHT(Item).Type = DataPlant::PlantEquipmentType::PipeExterior;
428 :
429 : // General user input data
430 1 : state.dataPipeHT->PipeHT(Item).Construction = state.dataIPShortCut->cAlphaArgs(2);
431 1 : state.dataPipeHT->PipeHT(Item).ConstructionNum =
432 1 : UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataConstruction->Construct);
433 :
434 1 : if (state.dataPipeHT->PipeHT(Item).ConstructionNum == 0) {
435 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(2) + '=' + state.dataIPShortCut->cAlphaArgs(2));
436 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
437 0 : ErrorsFound = true;
438 : }
439 :
440 : // get inlet node data
441 1 : state.dataPipeHT->PipeHT(Item).InletNode = state.dataIPShortCut->cAlphaArgs(3);
442 1 : state.dataPipeHT->PipeHT(Item).InletNodeNum = GetOnlySingleNode(state,
443 1 : state.dataIPShortCut->cAlphaArgs(3),
444 : ErrorsFound,
445 : DataLoopNode::ConnectionObjectType::PipeOutdoor,
446 1 : state.dataIPShortCut->cAlphaArgs(1),
447 : DataLoopNode::NodeFluidType::Water,
448 : DataLoopNode::ConnectionType::Inlet,
449 : NodeInputManager::CompFluidStream::Primary,
450 1 : ObjectIsNotParent);
451 1 : if (state.dataPipeHT->PipeHT(Item).InletNodeNum == 0) {
452 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(3) + '=' + state.dataIPShortCut->cAlphaArgs(3));
453 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
454 0 : ErrorsFound = true;
455 : }
456 :
457 : // get outlet node data
458 1 : state.dataPipeHT->PipeHT(Item).OutletNode = state.dataIPShortCut->cAlphaArgs(4);
459 1 : state.dataPipeHT->PipeHT(Item).OutletNodeNum = GetOnlySingleNode(state,
460 1 : state.dataIPShortCut->cAlphaArgs(4),
461 : ErrorsFound,
462 : DataLoopNode::ConnectionObjectType::PipeOutdoor,
463 1 : state.dataIPShortCut->cAlphaArgs(1),
464 : DataLoopNode::NodeFluidType::Water,
465 : DataLoopNode::ConnectionType::Outlet,
466 : NodeInputManager::CompFluidStream::Primary,
467 1 : ObjectIsNotParent);
468 1 : if (state.dataPipeHT->PipeHT(Item).OutletNodeNum == 0) {
469 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(4) + '=' + state.dataIPShortCut->cAlphaArgs(4));
470 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
471 0 : ErrorsFound = true;
472 : }
473 :
474 2 : TestCompSet(state,
475 : cCurrentModuleObject,
476 1 : state.dataIPShortCut->cAlphaArgs(1),
477 1 : state.dataIPShortCut->cAlphaArgs(3),
478 1 : state.dataIPShortCut->cAlphaArgs(4),
479 : "Pipe Nodes");
480 :
481 : // get environmental boundary condition type
482 : // PipeHT(Item)%Environment = 'OutdoorAir'
483 1 : state.dataPipeHT->PipeHT(Item).EnvironmentPtr = EnvrnPtr::OutsideAirEnv;
484 :
485 1 : state.dataPipeHT->PipeHT(Item).EnvrAirNode = state.dataIPShortCut->cAlphaArgs(5);
486 1 : state.dataPipeHT->PipeHT(Item).EnvrAirNodeNum = GetOnlySingleNode(state,
487 1 : state.dataIPShortCut->cAlphaArgs(5),
488 : ErrorsFound,
489 : DataLoopNode::ConnectionObjectType::PipeOutdoor,
490 1 : state.dataIPShortCut->cAlphaArgs(1),
491 : DataLoopNode::NodeFluidType::Air,
492 : DataLoopNode::ConnectionType::OutsideAirReference,
493 : NodeInputManager::CompFluidStream::Primary,
494 1 : ObjectIsNotParent);
495 1 : if (!state.dataIPShortCut->lAlphaFieldBlanks(5)) {
496 1 : if (!CheckOutAirNodeNumber(state, state.dataPipeHT->PipeHT(Item).EnvrAirNodeNum)) {
497 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(5) + '=' + state.dataIPShortCut->cAlphaArgs(5));
498 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
499 0 : ShowContinueError(state, "Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node");
500 0 : ErrorsFound = true;
501 : }
502 : } else {
503 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(5) + '=' + state.dataIPShortCut->cAlphaArgs(5));
504 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
505 0 : ShowContinueError(state, "An " + state.dataIPShortCut->cAlphaFieldNames(5) + " must be used ");
506 0 : ErrorsFound = true;
507 : }
508 :
509 : // dimensions
510 1 : state.dataPipeHT->PipeHT(Item).PipeID = state.dataIPShortCut->rNumericArgs(1);
511 1 : if (state.dataIPShortCut->rNumericArgs(1) <= 0.0) { // not really necessary because idd field has "minimum> 0"
512 0 : ShowSevereError(state,
513 0 : format("Invalid {} of {:.4R}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->rNumericArgs(1)));
514 0 : ShowContinueError(state, state.dataIPShortCut->cNumericFieldNames(1) + " must be > 0.0");
515 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
516 0 : ErrorsFound = true;
517 : }
518 :
519 1 : state.dataPipeHT->PipeHT(Item).Length = state.dataIPShortCut->rNumericArgs(2);
520 1 : if (state.dataIPShortCut->rNumericArgs(2) <= 0.0) { // not really necessary because idd field has "minimum> 0"
521 0 : ShowSevereError(state,
522 0 : format("Invalid {} of {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
523 0 : ShowContinueError(state, state.dataIPShortCut->cNumericFieldNames(2) + " must be > 0.0");
524 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
525 0 : ErrorsFound = true;
526 : }
527 :
528 1 : if (state.dataPipeHT->PipeHT(Item).ConstructionNum != 0) {
529 4 : state.dataPipeHT->PipeHT(Item).ValidatePipeConstruction(state,
530 : cCurrentModuleObject,
531 1 : state.dataIPShortCut->cAlphaArgs(2),
532 1 : state.dataIPShortCut->cAlphaFieldNames(2),
533 1 : state.dataPipeHT->PipeHT(Item).ConstructionNum,
534 : ErrorsFound);
535 : }
536 :
537 : } // end of input loop
538 :
539 4 : cCurrentModuleObject = "Pipe:Underground";
540 5 : for (PipeItem = 1; PipeItem <= NumOfPipeHTUG; ++PipeItem) {
541 :
542 1 : ++Item;
543 : // get the object name
544 7 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
545 : cCurrentModuleObject,
546 : PipeItem,
547 1 : state.dataIPShortCut->cAlphaArgs,
548 : NumAlphas,
549 1 : state.dataIPShortCut->rNumericArgs,
550 : NumNumbers,
551 : IOStatus,
552 1 : state.dataIPShortCut->lNumericFieldBlanks,
553 1 : state.dataIPShortCut->lAlphaFieldBlanks,
554 1 : state.dataIPShortCut->cAlphaFieldNames,
555 1 : state.dataIPShortCut->cNumericFieldNames);
556 :
557 2 : GlobalNames::VerifyUniqueInterObjectName(state,
558 1 : state.dataPipeHT->PipeHTUniqueNames,
559 1 : state.dataIPShortCut->cAlphaArgs(1),
560 : cCurrentModuleObject,
561 1 : state.dataIPShortCut->cAlphaFieldNames(1),
562 : ErrorsFound);
563 1 : state.dataPipeHT->PipeHT(Item).Name = state.dataIPShortCut->cAlphaArgs(1);
564 1 : state.dataPipeHT->PipeHT(Item).Type = DataPlant::PlantEquipmentType::PipeUnderground;
565 :
566 : // General user input data
567 1 : state.dataPipeHT->PipeHT(Item).Construction = state.dataIPShortCut->cAlphaArgs(2);
568 1 : state.dataPipeHT->PipeHT(Item).ConstructionNum =
569 1 : UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataConstruction->Construct);
570 :
571 1 : if (state.dataPipeHT->PipeHT(Item).ConstructionNum == 0) {
572 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(2) + '=' + state.dataIPShortCut->cAlphaArgs(2));
573 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
574 0 : ErrorsFound = true;
575 : }
576 :
577 : // get inlet node data
578 1 : state.dataPipeHT->PipeHT(Item).InletNode = state.dataIPShortCut->cAlphaArgs(3);
579 1 : state.dataPipeHT->PipeHT(Item).InletNodeNum = GetOnlySingleNode(state,
580 1 : state.dataIPShortCut->cAlphaArgs(3),
581 : ErrorsFound,
582 : DataLoopNode::ConnectionObjectType::PipeUnderground,
583 1 : state.dataIPShortCut->cAlphaArgs(1),
584 : DataLoopNode::NodeFluidType::Water,
585 : DataLoopNode::ConnectionType::Inlet,
586 : NodeInputManager::CompFluidStream::Primary,
587 1 : ObjectIsNotParent);
588 1 : if (state.dataPipeHT->PipeHT(Item).InletNodeNum == 0) {
589 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(3) + '=' + state.dataIPShortCut->cAlphaArgs(3));
590 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
591 0 : ErrorsFound = true;
592 : }
593 :
594 : // get outlet node data
595 1 : state.dataPipeHT->PipeHT(Item).OutletNode = state.dataIPShortCut->cAlphaArgs(4);
596 1 : state.dataPipeHT->PipeHT(Item).OutletNodeNum = GetOnlySingleNode(state,
597 1 : state.dataIPShortCut->cAlphaArgs(4),
598 : ErrorsFound,
599 : DataLoopNode::ConnectionObjectType::PipeUnderground,
600 1 : state.dataIPShortCut->cAlphaArgs(1),
601 : DataLoopNode::NodeFluidType::Water,
602 : DataLoopNode::ConnectionType::Outlet,
603 : NodeInputManager::CompFluidStream::Primary,
604 1 : ObjectIsNotParent);
605 1 : if (state.dataPipeHT->PipeHT(Item).OutletNodeNum == 0) {
606 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(4) + '=' + state.dataIPShortCut->cAlphaArgs(4));
607 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
608 0 : ErrorsFound = true;
609 : }
610 :
611 2 : TestCompSet(state,
612 : cCurrentModuleObject,
613 1 : state.dataIPShortCut->cAlphaArgs(1),
614 1 : state.dataIPShortCut->cAlphaArgs(3),
615 1 : state.dataIPShortCut->cAlphaArgs(4),
616 : "Pipe Nodes");
617 :
618 1 : state.dataPipeHT->PipeHT(Item).EnvironmentPtr = EnvrnPtr::GroundEnv;
619 :
620 : // Solar inclusion flag
621 : // A6, \field Sun Exposure
622 1 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(5), "SUNEXPOSED")) {
623 1 : state.dataPipeHT->PipeHT(Item).SolarExposed = true;
624 0 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(5), "NOSUN")) {
625 0 : state.dataPipeHT->PipeHT(Item).SolarExposed = false;
626 : } else {
627 0 : ShowSevereError(state, "GetPipesHeatTransfer: invalid key for sun exposure flag for " + state.dataIPShortCut->cAlphaArgs(1));
628 0 : ShowContinueError(state, "Key should be either SunExposed or NoSun. Entered Key: " + state.dataIPShortCut->cAlphaArgs(5));
629 0 : ErrorsFound = true;
630 : }
631 :
632 : // dimensions
633 1 : state.dataPipeHT->PipeHT(Item).PipeID = state.dataIPShortCut->rNumericArgs(1);
634 1 : if (state.dataIPShortCut->rNumericArgs(1) <= 0.0) { // not really necessary because idd field has "minimum> 0"
635 0 : ShowSevereError(state,
636 0 : format("Invalid {} of {:.4R}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->rNumericArgs(1)));
637 0 : ShowContinueError(state, state.dataIPShortCut->cNumericFieldNames(1) + " must be > 0.0");
638 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
639 0 : ErrorsFound = true;
640 : }
641 :
642 1 : state.dataPipeHT->PipeHT(Item).Length = state.dataIPShortCut->rNumericArgs(2);
643 1 : if (state.dataIPShortCut->rNumericArgs(2) <= 0.0) { // not really necessary because idd field has "minimum> 0"
644 0 : ShowSevereError(state,
645 0 : format("Invalid {} of {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
646 0 : ShowContinueError(state, state.dataIPShortCut->cNumericFieldNames(2) + " must be > 0.0");
647 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
648 0 : ErrorsFound = true;
649 : }
650 :
651 : // Also get the soil material name
652 : // A7, \field Soil Material
653 1 : state.dataPipeHT->PipeHT(Item).SoilMaterial = state.dataIPShortCut->cAlphaArgs(6);
654 1 : state.dataPipeHT->PipeHT(Item).SoilMaterialNum =
655 1 : UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(6), state.dataMaterial->Material);
656 1 : if (state.dataPipeHT->PipeHT(Item).SoilMaterialNum == 0) {
657 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(6) + '=' + state.dataPipeHT->PipeHT(Item).SoilMaterial);
658 0 : ShowContinueError(state, "Found in " + cCurrentModuleObject + '=' + state.dataPipeHT->PipeHT(Item).Name);
659 0 : ErrorsFound = true;
660 : } else {
661 1 : state.dataPipeHT->PipeHT(Item).SoilDensity = state.dataMaterial->Material(state.dataPipeHT->PipeHT(Item).SoilMaterialNum).Density;
662 1 : state.dataPipeHT->PipeHT(Item).SoilDepth = state.dataMaterial->Material(state.dataPipeHT->PipeHT(Item).SoilMaterialNum).Thickness;
663 1 : state.dataPipeHT->PipeHT(Item).SoilCp = state.dataMaterial->Material(state.dataPipeHT->PipeHT(Item).SoilMaterialNum).SpecHeat;
664 1 : state.dataPipeHT->PipeHT(Item).SoilConductivity =
665 1 : state.dataMaterial->Material(state.dataPipeHT->PipeHT(Item).SoilMaterialNum).Conductivity;
666 1 : state.dataPipeHT->PipeHT(Item).SoilThermAbs = state.dataMaterial->Material(state.dataPipeHT->PipeHT(Item).SoilMaterialNum).AbsorpThermal;
667 1 : state.dataPipeHT->PipeHT(Item).SoilSolarAbs = state.dataMaterial->Material(state.dataPipeHT->PipeHT(Item).SoilMaterialNum).AbsorpSolar;
668 1 : state.dataPipeHT->PipeHT(Item).SoilRoughness = state.dataMaterial->Material(state.dataPipeHT->PipeHT(Item).SoilMaterialNum).Roughness;
669 1 : state.dataPipeHT->PipeHT(Item).PipeDepth = state.dataPipeHT->PipeHT(Item).SoilDepth + state.dataPipeHT->PipeHT(Item).PipeID / 2.0;
670 1 : state.dataPipeHT->PipeHT(Item).DomainDepth = state.dataPipeHT->PipeHT(Item).PipeDepth * 2.0;
671 2 : state.dataPipeHT->PipeHT(Item).SoilDiffusivity = state.dataPipeHT->PipeHT(Item).SoilConductivity /
672 1 : (state.dataPipeHT->PipeHT(Item).SoilDensity * state.dataPipeHT->PipeHT(Item).SoilCp);
673 1 : state.dataPipeHT->PipeHT(Item).SoilDiffusivityPerDay =
674 1 : state.dataPipeHT->PipeHT(Item).SoilDiffusivity * SecondsInHour * DataGlobalConstants::HoursInDay;
675 :
676 : // Mesh the cartesian domain
677 1 : state.dataPipeHT->PipeHT(Item).NumDepthNodes = NumberOfDepthNodes;
678 1 : state.dataPipeHT->PipeHT(Item).PipeNodeDepth = state.dataPipeHT->PipeHT(Item).NumDepthNodes / 2;
679 1 : state.dataPipeHT->PipeHT(Item).PipeNodeWidth = state.dataPipeHT->PipeHT(Item).NumDepthNodes / 2;
680 1 : state.dataPipeHT->PipeHT(Item).DomainDepth = state.dataPipeHT->PipeHT(Item).PipeDepth * 2.0;
681 1 : state.dataPipeHT->PipeHT(Item).dSregular =
682 1 : state.dataPipeHT->PipeHT(Item).DomainDepth / (state.dataPipeHT->PipeHT(Item).NumDepthNodes - 1);
683 : }
684 :
685 1 : if (state.dataPipeHT->PipeHT(Item).ConstructionNum != 0) {
686 4 : state.dataPipeHT->PipeHT(Item).ValidatePipeConstruction(state,
687 : cCurrentModuleObject,
688 1 : state.dataIPShortCut->cAlphaArgs(2),
689 1 : state.dataIPShortCut->cAlphaFieldNames(2),
690 1 : state.dataPipeHT->PipeHT(Item).ConstructionNum,
691 : ErrorsFound);
692 : }
693 :
694 : // Get ground temperature model
695 2 : state.dataPipeHT->PipeHT(Item).groundTempModel =
696 3 : GetGroundTempModelAndInit(state, state.dataIPShortCut->cAlphaArgs(7), state.dataIPShortCut->cAlphaArgs(8));
697 :
698 : // Select number of pipe sections. Hanby's optimal number of 20 section is selected.
699 1 : NumSections = NumPipeSections;
700 1 : state.dataPipeHT->PipeHT(Item).NumSections = NumPipeSections;
701 :
702 : // For buried pipes, we need to allocate the cartesian finite difference array
703 3 : state.dataPipeHT->PipeHT(Item).T.allocate(state.dataPipeHT->PipeHT(Item).PipeNodeWidth,
704 1 : state.dataPipeHT->PipeHT(Item).NumDepthNodes,
705 1 : state.dataPipeHT->PipeHT(Item).NumSections,
706 5 : TimeIndex::Tentative);
707 1 : state.dataPipeHT->PipeHT(Item).T = 0.0;
708 :
709 : } // PipeUG input loop
710 :
711 8 : for (Item = 1; Item <= state.dataPipeHT->nsvNumOfPipeHT; ++Item) {
712 : // Select number of pipe sections. Hanby's optimal number of 20 section is selected.
713 4 : NumSections = NumPipeSections;
714 4 : state.dataPipeHT->PipeHT(Item).NumSections = NumPipeSections;
715 :
716 : // We need to allocate the Hanby model arrays for all pipes, including buried
717 4 : state.dataPipeHT->PipeHT(Item).TentativeFluidTemp.allocate({0, NumSections});
718 4 : state.dataPipeHT->PipeHT(Item).TentativePipeTemp.allocate({0, NumSections});
719 4 : state.dataPipeHT->PipeHT(Item).FluidTemp.allocate({0, NumSections});
720 4 : state.dataPipeHT->PipeHT(Item).PreviousFluidTemp.allocate({0, NumSections});
721 4 : state.dataPipeHT->PipeHT(Item).PipeTemp.allocate({0, NumSections});
722 4 : state.dataPipeHT->PipeHT(Item).PreviousPipeTemp.allocate({0, NumSections});
723 :
724 4 : state.dataPipeHT->PipeHT(Item).TentativeFluidTemp = 0.0;
725 4 : state.dataPipeHT->PipeHT(Item).FluidTemp = 0.0;
726 4 : state.dataPipeHT->PipeHT(Item).PreviousFluidTemp = 0.0;
727 4 : state.dataPipeHT->PipeHT(Item).TentativePipeTemp = 0.0;
728 4 : state.dataPipeHT->PipeHT(Item).PipeTemp = 0.0;
729 4 : state.dataPipeHT->PipeHT(Item).PreviousPipeTemp = 0.0;
730 :
731 : // work out heat transfer areas (area per section)
732 4 : state.dataPipeHT->PipeHT(Item).InsideArea =
733 4 : DataGlobalConstants::Pi * state.dataPipeHT->PipeHT(Item).PipeID * state.dataPipeHT->PipeHT(Item).Length / NumSections;
734 4 : state.dataPipeHT->PipeHT(Item).OutsideArea =
735 8 : DataGlobalConstants::Pi * (state.dataPipeHT->PipeHT(Item).PipeOD + 2 * state.dataPipeHT->PipeHT(Item).InsulationThickness) *
736 8 : state.dataPipeHT->PipeHT(Item).Length / NumSections;
737 :
738 : // cross sectional area
739 4 : state.dataPipeHT->PipeHT(Item).SectionArea = DataGlobalConstants::Pi * 0.25 * pow_2(state.dataPipeHT->PipeHT(Item).PipeID);
740 :
741 : // pipe & insulation mass
742 8 : state.dataPipeHT->PipeHT(Item).PipeHeatCapacity = state.dataPipeHT->PipeHT(Item).PipeCp * state.dataPipeHT->PipeHT(Item).PipeDensity *
743 8 : (DataGlobalConstants::Pi * 0.25 * pow_2(state.dataPipeHT->PipeHT(Item).PipeOD) -
744 4 : state.dataPipeHT->PipeHT(Item).SectionArea); // the metal component
745 : }
746 :
747 : // final error check
748 4 : if (ErrorsFound) {
749 0 : ShowFatalError(state, "GetPipesHeatTransfer: Errors found in input. Preceding conditions cause termination.");
750 : }
751 :
752 : // Set up the output variables CurrentModuleObject='Pipe:Indoor/Outdoor/Underground'
753 8 : for (Item = 1; Item <= state.dataPipeHT->nsvNumOfPipeHT; ++Item) {
754 :
755 16 : SetupOutputVariable(state,
756 : "Pipe Fluid Heat Transfer Rate",
757 : OutputProcessor::Unit::W,
758 4 : state.dataPipeHT->PipeHT(Item).FluidHeatLossRate,
759 : OutputProcessor::SOVTimeStepType::Plant,
760 : OutputProcessor::SOVStoreType::Average,
761 8 : state.dataPipeHT->PipeHT(Item).Name);
762 16 : SetupOutputVariable(state,
763 : "Pipe Fluid Heat Transfer Energy",
764 : OutputProcessor::Unit::J,
765 4 : state.dataPipeHT->PipeHT(Item).FluidHeatLossEnergy,
766 : OutputProcessor::SOVTimeStepType::Plant,
767 : OutputProcessor::SOVStoreType::Summed,
768 8 : state.dataPipeHT->PipeHT(Item).Name);
769 :
770 4 : if (state.dataPipeHT->PipeHT(Item).EnvironmentPtr == EnvrnPtr::ZoneEnv) {
771 4 : SetupOutputVariable(state,
772 : "Pipe Ambient Heat Transfer Rate",
773 : OutputProcessor::Unit::W,
774 1 : state.dataPipeHT->PipeHT(Item).EnvironmentHeatLossRate,
775 : OutputProcessor::SOVTimeStepType::Plant,
776 : OutputProcessor::SOVStoreType::Average,
777 2 : state.dataPipeHT->PipeHT(Item).Name);
778 4 : SetupOutputVariable(state,
779 : "Pipe Ambient Heat Transfer Energy",
780 : OutputProcessor::Unit::J,
781 1 : state.dataPipeHT->PipeHT(Item).EnvHeatLossEnergy,
782 : OutputProcessor::SOVTimeStepType::Plant,
783 : OutputProcessor::SOVStoreType::Summed,
784 2 : state.dataPipeHT->PipeHT(Item).Name);
785 :
786 3 : SetupZoneInternalGain(state,
787 1 : state.dataPipeHT->PipeHT(Item).EnvrZonePtr,
788 1 : state.dataPipeHT->PipeHT(Item).Name,
789 : DataHeatBalance::IntGainType::PipeIndoor,
790 1 : &state.dataPipeHT->PipeHT(Item).ZoneHeatGainRate);
791 : }
792 :
793 16 : SetupOutputVariable(state,
794 : "Pipe Mass Flow Rate",
795 : OutputProcessor::Unit::kg_s,
796 4 : state.dataPipeHT->PipeHT(Item).MassFlowRate,
797 : OutputProcessor::SOVTimeStepType::Plant,
798 : OutputProcessor::SOVStoreType::Average,
799 8 : state.dataPipeHT->PipeHT(Item).Name);
800 16 : SetupOutputVariable(state,
801 : "Pipe Volume Flow Rate",
802 : OutputProcessor::Unit::m3_s,
803 4 : state.dataPipeHT->PipeHT(Item).VolumeFlowRate,
804 : OutputProcessor::SOVTimeStepType::Plant,
805 : OutputProcessor::SOVStoreType::Average,
806 8 : state.dataPipeHT->PipeHT(Item).Name);
807 16 : SetupOutputVariable(state,
808 : "Pipe Inlet Temperature",
809 : OutputProcessor::Unit::C,
810 4 : state.dataPipeHT->PipeHT(Item).FluidInletTemp,
811 : OutputProcessor::SOVTimeStepType::Plant,
812 : OutputProcessor::SOVStoreType::Average,
813 8 : state.dataPipeHT->PipeHT(Item).Name);
814 16 : SetupOutputVariable(state,
815 : "Pipe Outlet Temperature",
816 : OutputProcessor::Unit::C,
817 4 : state.dataPipeHT->PipeHT(Item).FluidOutletTemp,
818 : OutputProcessor::SOVTimeStepType::Plant,
819 : OutputProcessor::SOVStoreType::Average,
820 8 : state.dataPipeHT->PipeHT(Item).Name);
821 : }
822 4 : }
823 :
824 4 : void PipeHTData::ValidatePipeConstruction(EnergyPlusData &state,
825 : std::string const &PipeType, // module object of pipe (error messages)
826 : std::string const &ConstructionName, // construction name of pipe (error messages)
827 : std::string_view FieldName, // fieldname of pipe (error messages)
828 : int const ConstructionNum, // pointer into construction data
829 : bool &ErrorsFound // set to true if errors found here
830 : )
831 : {
832 :
833 : // SUBROUTINE INFORMATION:
834 : // AUTHOR Linda Lawrie
835 : // DATE WRITTEN August 2008
836 : // MODIFIED na
837 : // RE-ENGINEERED na
838 :
839 : // PURPOSE OF THIS SUBROUTINE:
840 : // This routine, called from GetInput, validates the pipe construction usage.
841 :
842 : // METHODOLOGY EMPLOYED:
843 : // na
844 :
845 : // REFERENCES:
846 : // na
847 :
848 : // Using/Aliasing
849 :
850 : // Locals
851 : // SUBROUTINE ARGUMENT DEFINITIONS:
852 :
853 : // SUBROUTINE PARAMETER DEFINITIONS:
854 : // na
855 :
856 : // INTERFACE BLOCK SPECIFICATIONS:
857 : // na
858 :
859 : // DERIVED TYPE DEFINITIONS:
860 : // na
861 :
862 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
863 : Real64 Density; // average density [kg/m^3]
864 : Real64 SpHeat; // average specific heat [J/kg.K]
865 4 : Real64 Resistance = 0.0;
866 4 : Real64 TotThickness = 0.0;
867 :
868 : // CTF stuff
869 4 : int TotalLayers = state.dataConstruction->Construct(ConstructionNum).TotLayers;
870 : // get pipe properties
871 4 : if (TotalLayers == 1) { // no insulation layer
872 :
873 0 : this->PipeConductivity = state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(1)).Conductivity;
874 0 : this->PipeDensity = state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(1)).Density;
875 0 : this->PipeCp = state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(1)).SpecHeat;
876 0 : this->PipeOD = this->PipeID + 2.0 * state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(1)).Thickness;
877 0 : this->InsulationOD = this->PipeOD;
878 0 : this->SumTK = state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(1)).Thickness /
879 0 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(1)).Conductivity;
880 :
881 4 : } else if (TotalLayers >= 2) { // first layers are insulation, last layer is pipe
882 :
883 8 : for (int LayerNum = 1; LayerNum <= TotalLayers - 1; ++LayerNum) {
884 8 : Resistance += state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(LayerNum)).Thickness /
885 4 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(LayerNum)).Conductivity;
886 8 : Density = state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(LayerNum)).Density *
887 4 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(LayerNum)).Thickness;
888 4 : TotThickness += state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(LayerNum)).Thickness;
889 8 : SpHeat = state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(LayerNum)).SpecHeat *
890 4 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(LayerNum)).Thickness;
891 4 : this->InsulationThickness =
892 4 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(LayerNum)).Thickness;
893 8 : this->SumTK += state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(LayerNum)).Thickness /
894 4 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(LayerNum)).Conductivity;
895 : }
896 :
897 4 : this->InsulationResistance = Resistance;
898 4 : this->InsulationConductivity = TotThickness / Resistance;
899 4 : this->InsulationDensity = Density / TotThickness;
900 4 : this->InsulationCp = SpHeat / TotThickness;
901 4 : this->InsulationThickness = TotThickness;
902 :
903 4 : this->PipeConductivity =
904 4 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(TotalLayers)).Conductivity;
905 4 : this->PipeDensity = state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(TotalLayers)).Density;
906 4 : this->PipeCp = state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(TotalLayers)).SpecHeat;
907 :
908 4 : this->PipeOD =
909 4 : this->PipeID + 2.0 * state.dataMaterial->Material(state.dataConstruction->Construct(ConstructionNum).LayerPoint(TotalLayers)).Thickness;
910 4 : this->InsulationOD = this->PipeOD + 2.0 * this->InsulationThickness;
911 :
912 : } else {
913 0 : ShowSevereError(
914 0 : state, format("{}: invalid {}=\"{}\", too many layers=[{}], only 1 or 2 allowed.", PipeType, FieldName, ConstructionName, TotalLayers));
915 0 : ErrorsFound = true;
916 : }
917 4 : }
918 :
919 4 : void PipeHTData::oneTimeInit_new(EnergyPlusData &state)
920 : {
921 4 : bool errFlag = false;
922 4 : PlantUtilities::ScanPlantLoopsForObject(state, this->Name, this->Type, this->plantLoc, errFlag, _, _, _, _, _);
923 4 : if (errFlag) {
924 0 : ShowFatalError(state, "InitPipesHeatTransfer: Program terminated due to previous condition(s).");
925 : }
926 4 : }
927 :
928 58388 : void PipeHTData::InitPipesHeatTransfer(EnergyPlusData &state, bool const FirstHVACIteration // component number
929 : )
930 : {
931 :
932 : // SUBROUTINE INFORMATION:
933 : // AUTHOR Simon Rees
934 : // DATE WRITTEN July 2007
935 : // MODIFIED L. Gu, 6/19/08, pipe wall heat capacity has metal layer only
936 : // RE-ENGINEERED na
937 :
938 : // PURPOSE OF THIS SUBROUTINE:
939 : // This subroutine Resets the elements of the data structure as necessary
940 : // at the first step, and start of each call to simulated
941 :
942 : // METHODOLOGY EMPLOYED:
943 : // Check flags and update data structure
944 :
945 : // Using/Aliasing
946 58388 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
947 58388 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
948 : using FluidProperties::GetDensityGlycol;
949 : using FluidProperties::GetSpecificHeatGlycol;
950 : using ScheduleManager::GetCurrentScheduleValue;
951 :
952 : // SUBROUTINE PARAMETER DEFINITIONS:
953 : static constexpr std::string_view RoutineName("InitPipesHeatTransfer");
954 :
955 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
956 :
957 : Real64 FirstTemperatures; // initial temperature of every node in pipe (set to inlet temp) [C]
958 : int TimeIndex;
959 : int LengthIndex;
960 : int DepthIndex;
961 : int WidthIndex;
962 : Real64 CurrentDepth;
963 : Real64 CurTemp;
964 : Real64 CurSimDay;
965 : bool PushArrays;
966 :
967 : // Assign variable
968 58388 : CurSimDay = double(state.dataGlobal->DayOfSim);
969 :
970 : // some useful module variables
971 58388 : state.dataPipeHT->nsvInletNodeNum = this->InletNodeNum;
972 58388 : state.dataPipeHT->nsvOutletNodeNum = this->OutletNodeNum;
973 58388 : state.dataPipeHT->nsvMassFlowRate = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).MassFlowRate;
974 58388 : state.dataPipeHT->nsvInletTemp = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).Temp;
975 :
976 : // initialize temperatures by inlet node temp
977 58388 : if ((state.dataGlobal->BeginSimFlag && this->BeginSimInit) || (state.dataGlobal->BeginEnvrnFlag && this->BeginSimEnvrn)) {
978 :
979 20 : if (this->EnvironmentPtr == EnvrnPtr::GroundEnv) {
980 20 : for (TimeIndex = TimeIndex::Previous; TimeIndex <= TimeIndex::Tentative; ++TimeIndex) {
981 : // Loop through all length, depth, and width of pipe to init soil temperature
982 315 : for (LengthIndex = 1; LengthIndex <= this->NumSections; ++LengthIndex) {
983 2700 : for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes; ++DepthIndex) {
984 12000 : for (WidthIndex = 1; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
985 9600 : CurrentDepth = (DepthIndex - 1) * this->dSregular;
986 9600 : this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex) = this->TBND(state, CurrentDepth);
987 : }
988 : }
989 : }
990 : }
991 : }
992 :
993 : // We also need to re-init the Hanby arrays for all pipes, including buried
994 20 : FirstTemperatures = 21.0; // Node(InletNodeNum)%Temp
995 20 : this->TentativeFluidTemp = FirstTemperatures;
996 20 : this->FluidTemp = FirstTemperatures;
997 20 : this->PreviousFluidTemp = FirstTemperatures;
998 20 : this->TentativePipeTemp = FirstTemperatures;
999 20 : this->PipeTemp = FirstTemperatures;
1000 20 : this->PreviousPipeTemp = FirstTemperatures;
1001 20 : this->PreviousSimTime = 0.0;
1002 20 : state.dataPipeHT->nsvDeltaTime = 0.0;
1003 20 : state.dataPipeHT->nsvOutletTemp = 0.0;
1004 20 : state.dataPipeHT->nsvEnvironmentTemp = 0.0;
1005 20 : state.dataPipeHT->nsvEnvHeatLossRate = 0.0;
1006 20 : state.dataPipeHT->nsvFluidHeatLossRate = 0.0;
1007 :
1008 20 : this->BeginSimInit = false;
1009 20 : this->BeginSimEnvrn = false;
1010 : }
1011 :
1012 58388 : if (!state.dataGlobal->BeginSimFlag) this->BeginSimInit = true;
1013 58388 : if (!state.dataGlobal->BeginEnvrnFlag) this->BeginSimEnvrn = true;
1014 :
1015 : // time step in seconds
1016 58388 : state.dataPipeHT->nsvDeltaTime = TimeStepSys * DataGlobalConstants::SecInHour;
1017 58388 : state.dataPipeHT->nsvNumInnerTimeSteps = int(state.dataPipeHT->nsvDeltaTime / InnerDeltaTime);
1018 :
1019 : // previous temps are updated if necessary at start of timestep rather than end
1020 58388 : if ((FirstHVACIteration && this->FirstHVACupdateFlag) || (state.dataGlobal->BeginEnvrnFlag && this->BeginEnvrnupdateFlag)) {
1021 :
1022 : // We need to update boundary conditions here, as well as updating the arrays
1023 7296 : if (this->EnvironmentPtr == EnvrnPtr::GroundEnv) {
1024 :
1025 : // And then update Ground Boundary Conditions
1026 7296 : for (TimeIndex = 1; TimeIndex <= TimeIndex::Tentative; ++TimeIndex) {
1027 114912 : for (LengthIndex = 1; LengthIndex <= this->NumSections; ++LengthIndex) {
1028 984960 : for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes; ++DepthIndex) {
1029 : // Farfield boundary
1030 875520 : CurrentDepth = (DepthIndex - 1) * this->dSregular;
1031 875520 : CurTemp = this->TBND(state, CurrentDepth);
1032 875520 : this->T(1, DepthIndex, LengthIndex, TimeIndex) = CurTemp;
1033 : }
1034 547200 : for (WidthIndex = 1; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
1035 : // Bottom side of boundary
1036 437760 : CurrentDepth = this->DomainDepth;
1037 437760 : CurTemp = this->TBND(state, CurrentDepth);
1038 437760 : this->T(WidthIndex, this->NumDepthNodes, LengthIndex, TimeIndex) = CurTemp;
1039 : }
1040 : }
1041 : }
1042 : }
1043 :
1044 : // should next choose environment temperature according to coupled with air or ground
1045 7296 : switch (this->EnvironmentPtr) {
1046 1824 : case EnvrnPtr::GroundEnv: {
1047 : // EnvironmentTemp = GroundTemp
1048 1824 : } break;
1049 1824 : case EnvrnPtr::OutsideAirEnv: {
1050 1824 : state.dataPipeHT->nsvEnvironmentTemp = state.dataEnvrn->OutDryBulbTemp;
1051 1824 : } break;
1052 1824 : case EnvrnPtr::ZoneEnv: {
1053 1824 : state.dataPipeHT->nsvEnvironmentTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->EnvrZonePtr).MAT;
1054 1824 : } break;
1055 1824 : case EnvrnPtr::ScheduleEnv: {
1056 1824 : state.dataPipeHT->nsvEnvironmentTemp = GetCurrentScheduleValue(state, this->EnvrSchedPtr);
1057 1824 : } break;
1058 0 : case EnvrnPtr::None: { // default to outside temp
1059 0 : state.dataPipeHT->nsvEnvironmentTemp = state.dataEnvrn->OutDryBulbTemp;
1060 0 : } break;
1061 0 : default:
1062 0 : break;
1063 : }
1064 :
1065 7296 : this->BeginEnvrnupdateFlag = false;
1066 7296 : this->FirstHVACupdateFlag = false;
1067 : }
1068 :
1069 58388 : if (!state.dataGlobal->BeginEnvrnFlag) this->BeginEnvrnupdateFlag = true;
1070 58388 : if (!FirstHVACIteration) this->FirstHVACupdateFlag = true;
1071 :
1072 : // Calculate the current sim time for this pipe (not necessarily structure variable, but it is ok for consistency)
1073 175164 : this->CurrentSimTime = (state.dataGlobal->DayOfSim - 1) * 24 + state.dataGlobal->HourOfDay - 1 +
1074 116776 : (state.dataGlobal->TimeStep - 1) * state.dataGlobal->TimeStepZone + SysTimeElapsed;
1075 58388 : if (std::abs(this->CurrentSimTime - this->PreviousSimTime) > 1.0e-6) {
1076 6404 : PushArrays = true;
1077 6404 : this->PreviousSimTime = this->CurrentSimTime;
1078 : } else {
1079 51984 : PushArrays = false; // Time hasn't passed, don't accept the tentative values yet!
1080 : }
1081 :
1082 58388 : if (PushArrays) {
1083 :
1084 : // If sim time has changed all values from previous runs should have been acceptable.
1085 : // Thus we will now shift the arrays from 2>1 and 3>2 so we can then begin
1086 : // to update 2 and 3 again.
1087 6404 : if (this->EnvironmentPtr == EnvrnPtr::GroundEnv) {
1088 32020 : for (LengthIndex = 2; LengthIndex <= this->NumSections; ++LengthIndex) {
1089 273771 : for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes; ++DepthIndex) {
1090 973408 : for (WidthIndex = 2; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
1091 : // This will essentially 'accept' the tentative values that were calculated last iteration
1092 : // as the new officially 'current' values
1093 730056 : this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Current) =
1094 730056 : this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative);
1095 : }
1096 : }
1097 : }
1098 : }
1099 :
1100 : // Then update the Hanby near pipe model temperatures
1101 6404 : this->FluidTemp = this->TentativeFluidTemp;
1102 6404 : this->PipeTemp = this->TentativePipeTemp;
1103 :
1104 : } else { // IF(.NOT. FirstHVACIteration)THEN
1105 :
1106 : // If we don't have FirstHVAC, the last iteration values were not accepted, and we should
1107 : // not step through time. Thus we will revert our T(3,:,:,:) array back to T(2,:,:,:) to
1108 : // start over with the same values as last time.
1109 1039680 : for (LengthIndex = 2; LengthIndex <= this->NumSections; ++LengthIndex) {
1110 2963088 : for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes; ++DepthIndex) {
1111 7901568 : for (WidthIndex = 2; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
1112 : // This will essentially erase the past iterations and revert back to the correct values
1113 5926176 : this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative) =
1114 5926176 : this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Current);
1115 : }
1116 : }
1117 : }
1118 :
1119 : // Similarly for Hanby model arrays
1120 51984 : this->TentativeFluidTemp = this->FluidTemp;
1121 51984 : this->TentativePipeTemp = this->PipeTemp;
1122 : }
1123 :
1124 : // This still catches even in winter design day
1125 : // Even though the loop eventually has no flow rate, it appears it initializes to a value, then converges to OFF
1126 : // Thus, this is called at the beginning of every time step once.
1127 :
1128 175164 : this->FluidSpecHeat = GetSpecificHeatGlycol(state,
1129 58388 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
1130 58388 : state.dataPipeHT->nsvInletTemp,
1131 58388 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
1132 : RoutineName);
1133 175164 : this->FluidDensity = GetDensityGlycol(state,
1134 58388 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
1135 58388 : state.dataPipeHT->nsvInletTemp,
1136 58388 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
1137 : RoutineName);
1138 :
1139 : // At this point, for all Pipe:Interior objects we should zero out the energy and rate arrays
1140 58388 : this->FluidHeatLossRate = 0.0;
1141 58388 : this->FluidHeatLossEnergy = 0.0;
1142 58388 : this->EnvironmentHeatLossRate = 0.0;
1143 58388 : this->EnvHeatLossEnergy = 0.0;
1144 58388 : this->ZoneHeatGainRate = 0.0;
1145 58388 : state.dataPipeHT->nsvFluidHeatLossRate = 0.0;
1146 58388 : state.dataPipeHT->nsvEnvHeatLossRate = 0.0;
1147 58388 : state.dataPipeHT->nsvOutletTemp = 0.0;
1148 :
1149 58388 : if (this->FluidDensity > 0.0) {
1150 : // The density will only be zero the first time through, which will be a warmup day, and not reported
1151 58388 : state.dataPipeHT->nsvVolumeFlowRate = state.dataPipeHT->nsvMassFlowRate / this->FluidDensity;
1152 : }
1153 58388 : }
1154 :
1155 : //==============================================================================
1156 :
1157 4472201 : void PipeHTData::CalcPipesHeatTransfer(EnergyPlusData &state, Optional_int_const LengthIndex)
1158 : {
1159 :
1160 : // AUTHOR Simon Rees
1161 : // DATE WRITTEN July 2007
1162 : // MODIFIED na
1163 : // RE-ENGINEERED na
1164 :
1165 : // PURPOSE OF THIS SUBROUTINE:
1166 : // This subroutine does all of the stuff that is necessary to simulate
1167 : // a Pipe Heat Transfer. Calls are made to appropriate routines
1168 : // for heat transfer coefficients
1169 :
1170 : // METHODOLOGY EMPLOYED:
1171 : // Differential equations for pipe and fluid nodes along the pipe are solved
1172 : // taking backward differences in time.
1173 : // The heat loss/gain calculations are run continuously, even when the loop is off.
1174 : // Fluid temps will drift according to environmental conditions when there is zero flow.
1175 :
1176 : // REFERENCES:
1177 :
1178 : // Using/Aliasing
1179 : using namespace DataEnvironment;
1180 :
1181 : // fluid node heat balance (see engineering doc).
1182 4472201 : Real64 A1(0.0); // sum of the heat balance terms
1183 4472201 : Real64 A2(0.0); // mass flow term
1184 4472201 : Real64 A3(0.0); // inside pipe wall convection term
1185 4472201 : Real64 A4(0.0); // fluid node heat capacity term
1186 : // pipe wall node heat balance (see engineering doc).
1187 4472201 : Real64 B1(0.0); // sum of the heat balance terms
1188 4472201 : Real64 B2(0.0); // inside pipe wall convection term
1189 4472201 : Real64 B3(0.0); // outside pipe wall convection term
1190 4472201 : Real64 B4(0.0); // fluid node heat capacity term
1191 :
1192 4472201 : Real64 AirConvCoef(0.0); // air-pipe convection coefficient
1193 4472201 : Real64 FluidConvCoef(0.0); // fluid-pipe convection coefficient
1194 4472201 : Real64 EnvHeatTransCoef(0.0); // external convection coefficient (outside pipe)
1195 4472201 : Real64 FluidNodeHeatCapacity(0.0); // local var for MCp for single node of pipe
1196 :
1197 4472201 : int PipeDepth(0);
1198 4472201 : int PipeWidth(0);
1199 : int curnode;
1200 : Real64 TempBelow;
1201 : Real64 TempBeside;
1202 : Real64 TempAbove;
1203 : Real64 Numerator;
1204 : Real64 Denominator;
1205 : Real64 SurfaceTemp;
1206 :
1207 : // traps fluid properties problems such as freezing conditions
1208 4472201 : if (this->FluidSpecHeat <= 0.0 || this->FluidDensity <= 0.0) {
1209 : // leave the state of the pipe as it was
1210 0 : state.dataPipeHT->nsvOutletTemp = this->TentativeFluidTemp(this->NumSections);
1211 : // set heat transfer rates to zero for consistency
1212 0 : state.dataPipeHT->nsvEnvHeatLossRate = 0.0;
1213 0 : state.dataPipeHT->nsvFluidHeatLossRate = 0.0;
1214 0 : return;
1215 : }
1216 :
1217 : // AirConvCoef = OutsidePipeHeatTransCoef(PipeHTNum)
1218 : // Revised by L. Gu by including insulation conductance 6/19/08
1219 :
1220 4472201 : if (this->EnvironmentPtr != EnvrnPtr::GroundEnv) {
1221 559041 : AirConvCoef = 1.0 / (1.0 / this->OutsidePipeHeatTransCoef(state) + this->InsulationResistance);
1222 : }
1223 :
1224 4472201 : FluidConvCoef = this->CalcPipeHeatTransCoef(state, state.dataPipeHT->nsvInletTemp, state.dataPipeHT->nsvMassFlowRate, this->PipeID);
1225 :
1226 : // heat transfer to air or ground
1227 4472201 : switch (this->EnvironmentPtr) {
1228 3913160 : case EnvrnPtr::GroundEnv: {
1229 : // Approximate conductance using ground conductivity, (h=k/L), where L is grid spacing
1230 : // between pipe wall and next closest node.
1231 3913160 : EnvHeatTransCoef = this->SoilConductivity / (this->dSregular - (this->PipeID / 2.0));
1232 3913160 : } break;
1233 186347 : case EnvrnPtr::OutsideAirEnv: {
1234 186347 : EnvHeatTransCoef = AirConvCoef;
1235 186347 : } break;
1236 186347 : case EnvrnPtr::ZoneEnv: {
1237 186347 : EnvHeatTransCoef = AirConvCoef;
1238 186347 : } break;
1239 186347 : case EnvrnPtr::ScheduleEnv: {
1240 186347 : EnvHeatTransCoef = AirConvCoef;
1241 186347 : } break;
1242 0 : case EnvrnPtr::None: {
1243 0 : EnvHeatTransCoef = 0.0;
1244 0 : } break;
1245 0 : default: {
1246 0 : EnvHeatTransCoef = 0.0;
1247 0 : } break;
1248 : }
1249 :
1250 : // work out the coefficients
1251 4472201 : FluidNodeHeatCapacity =
1252 4472201 : this->SectionArea * this->Length / this->NumSections * this->FluidSpecHeat * this->FluidDensity; // Mass of Node x Specific heat
1253 :
1254 : // coef of fluid heat balance
1255 8944402 : A1 = FluidNodeHeatCapacity + state.dataPipeHT->nsvMassFlowRate * this->FluidSpecHeat * state.dataPipeHT->nsvDeltaTime +
1256 4472201 : FluidConvCoef * this->InsideArea * state.dataPipeHT->nsvDeltaTime;
1257 :
1258 4472201 : A2 = state.dataPipeHT->nsvMassFlowRate * this->FluidSpecHeat * state.dataPipeHT->nsvDeltaTime;
1259 :
1260 4472201 : A3 = FluidConvCoef * this->InsideArea * state.dataPipeHT->nsvDeltaTime;
1261 :
1262 4472201 : A4 = FluidNodeHeatCapacity;
1263 :
1264 : // coef of pipe heat balance
1265 8944402 : B1 = this->PipeHeatCapacity + FluidConvCoef * this->InsideArea * state.dataPipeHT->nsvDeltaTime +
1266 4472201 : EnvHeatTransCoef * this->OutsideArea * state.dataPipeHT->nsvDeltaTime;
1267 :
1268 4472201 : B2 = A3;
1269 :
1270 4472201 : B3 = EnvHeatTransCoef * this->OutsideArea * state.dataPipeHT->nsvDeltaTime;
1271 :
1272 4472201 : B4 = this->PipeHeatCapacity;
1273 :
1274 4472201 : this->TentativeFluidTemp(0) = state.dataPipeHT->nsvInletTemp;
1275 :
1276 4472201 : this->TentativePipeTemp(0) = this->PipeTemp(1); // for convenience
1277 :
1278 4472201 : if (present(LengthIndex)) { // Just simulate the single section if being called from Pipe:Underground
1279 :
1280 3913160 : PipeDepth = this->PipeNodeDepth;
1281 3913160 : PipeWidth = this->PipeNodeWidth;
1282 3913160 : TempBelow = this->T(PipeWidth, PipeDepth + 1, LengthIndex, TimeIndex::Current);
1283 3913160 : TempBeside = this->T(PipeWidth - 1, PipeDepth, LengthIndex, TimeIndex::Current);
1284 3913160 : TempAbove = this->T(PipeWidth, PipeDepth - 1, LengthIndex, TimeIndex::Current);
1285 3913160 : state.dataPipeHT->nsvEnvironmentTemp = (TempBelow + TempBeside + TempAbove) / 3.0;
1286 :
1287 11739480 : this->TentativeFluidTemp(LengthIndex) = (A2 * this->TentativeFluidTemp(LengthIndex - 1) +
1288 7826320 : A3 / B1 * (B3 * state.dataPipeHT->nsvEnvironmentTemp + B4 * this->PreviousPipeTemp(LengthIndex)) +
1289 7826320 : A4 * this->PreviousFluidTemp(LengthIndex)) /
1290 3913160 : (A1 - A3 * B2 / B1);
1291 :
1292 3913160 : this->TentativePipeTemp(LengthIndex) =
1293 3913160 : (B2 * this->TentativeFluidTemp(LengthIndex) + B3 * state.dataPipeHT->nsvEnvironmentTemp + B4 * this->PreviousPipeTemp(LengthIndex)) / B1;
1294 :
1295 : // Get exterior surface temperature from energy balance at the surface
1296 3913160 : Numerator = state.dataPipeHT->nsvEnvironmentTemp - this->TentativeFluidTemp(LengthIndex);
1297 3913160 : Denominator = EnvHeatTransCoef * ((1 / EnvHeatTransCoef) + this->SumTK);
1298 3913160 : SurfaceTemp = state.dataPipeHT->nsvEnvironmentTemp - Numerator / Denominator;
1299 :
1300 : // keep track of environmental heat loss rate - not same as fluid loss at same time
1301 3913160 : state.dataPipeHT->nsvEnvHeatLossRate += EnvHeatTransCoef * this->OutsideArea * (SurfaceTemp - state.dataPipeHT->nsvEnvironmentTemp);
1302 :
1303 : } else { // Simulate all sections at once if not pipe:underground
1304 :
1305 : // start loop along pipe
1306 : // b1 must not be zero but this should have been checked on input
1307 11739861 : for (curnode = 1; curnode <= this->NumSections; ++curnode) {
1308 33542460 : this->TentativeFluidTemp(curnode) = (A2 * this->TentativeFluidTemp(curnode - 1) +
1309 22361640 : A3 / B1 * (B3 * state.dataPipeHT->nsvEnvironmentTemp + B4 * this->PreviousPipeTemp(curnode)) +
1310 22361640 : A4 * this->PreviousFluidTemp(curnode)) /
1311 11180820 : (A1 - A3 * B2 / B1);
1312 :
1313 11180820 : this->TentativePipeTemp(curnode) =
1314 11180820 : (B2 * this->TentativeFluidTemp(curnode) + B3 * state.dataPipeHT->nsvEnvironmentTemp + B4 * this->PreviousPipeTemp(curnode)) / B1;
1315 :
1316 : // Get exterior surface temperature from energy balance at the surface
1317 11180820 : Numerator = state.dataPipeHT->nsvEnvironmentTemp - this->TentativeFluidTemp(curnode);
1318 11180820 : Denominator = EnvHeatTransCoef * ((1 / EnvHeatTransCoef) + this->SumTK);
1319 11180820 : SurfaceTemp = state.dataPipeHT->nsvEnvironmentTemp - Numerator / Denominator;
1320 :
1321 : // Keep track of environmental heat loss
1322 11180820 : state.dataPipeHT->nsvEnvHeatLossRate += EnvHeatTransCoef * this->OutsideArea * (SurfaceTemp - state.dataPipeHT->nsvEnvironmentTemp);
1323 : }
1324 : }
1325 :
1326 4472201 : state.dataPipeHT->nsvFluidHeatLossRate =
1327 4472201 : state.dataPipeHT->nsvMassFlowRate * this->FluidSpecHeat * (this->TentativeFluidTemp(0) - this->TentativeFluidTemp(this->NumSections));
1328 :
1329 4472201 : state.dataPipeHT->nsvOutletTemp = this->TentativeFluidTemp(this->NumSections);
1330 : }
1331 :
1332 : //==============================================================================
1333 :
1334 186347 : void PipeHTData::CalcBuriedPipeSoil(EnergyPlusData &state) // Current Simulation Pipe Number
1335 : {
1336 :
1337 : // AUTHOR Edwin Lee
1338 : // DATE WRITTEN May 2008
1339 : // MODIFIED na
1340 : // RE-ENGINEERED na
1341 :
1342 : // PURPOSE OF THIS SUBROUTINE:
1343 : // This subroutine does all of the stuff that is necessary to simulate
1344 : // soil heat transfer with a Buried Pipe.
1345 :
1346 : // METHODOLOGY EMPLOYED:
1347 : // An implicit pseudo 3D finite difference grid
1348 : // is set up, which simulates transient behavior in the soil.
1349 : // This then interfaces with the Hanby model for near-pipe region
1350 :
1351 : // Using/Aliasing
1352 : using ConvectionCoefficients::CalcASHRAESimpExtConvectCoeff;
1353 :
1354 : // SUBROUTINE PARAMETER DEFINITIONS:
1355 186347 : int constexpr NumSections(20);
1356 186347 : Real64 constexpr ConvCrit(0.05);
1357 186347 : int constexpr MaxIterations(200);
1358 186347 : Real64 constexpr StefBoltzmann(5.6697e-08); // Stefan-Boltzmann constant
1359 :
1360 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1361 186347 : int IterationIndex(0); // Index when stepping through equations
1362 186347 : int LengthIndex(0); // Index for nodes along length of pipe
1363 186347 : int DepthIndex(0); // Index for nodes in the depth direction
1364 186347 : int WidthIndex(0); // Index for nodes in the width direction
1365 186347 : Real64 ConvCoef(0.0); // Current convection coefficient = f(Wind Speed,Roughness)
1366 186347 : Real64 RadCoef(0.0); // Current radiation coefficient
1367 186347 : Real64 QSolAbsorbed(0.0); // Current total solar energy absorbed
1368 372694 : Array3D<Real64> T_O(this->PipeNodeWidth, this->NumDepthNodes, NumSections);
1369 :
1370 : // Local variable placeholders for code readability
1371 186347 : Real64 A1(0.0); // Placeholder for CoefA1
1372 186347 : Real64 A2(0.0); // Placeholder for CoefA2
1373 186347 : Real64 NodeBelow(0.0); // Placeholder for Node temp below current node
1374 186347 : Real64 NodeAbove(0.0); // Placeholder for Node temp above current node
1375 186347 : Real64 NodeRight(0.0); // Placeholder for Node temp to the right of current node
1376 186347 : Real64 NodeLeft(0.0); // Placeholder for Node temp to the left of current node
1377 186347 : Real64 NodePast(0.0); // Placeholder for Node temp at current node but previous time step
1378 186347 : Real64 PastNodeTempAbs(0.0); // Placeholder for absolute temperature (K) version of NodePast
1379 186347 : Real64 Ttemp(0.0); // Placeholder for a current temperature node in convergence check
1380 186347 : Real64 SkyTempAbs(0.0); // Placeholder for current sky temperature in Kelvin
1381 186347 : DataSurfaces::SurfaceRoughness TopRoughness(DataSurfaces::SurfaceRoughness::Invalid); // Placeholder for soil surface roughness
1382 186347 : Real64 TopThermAbs(0.0); // Placeholder for soil thermal radiation absorptivity
1383 186347 : Real64 TopSolarAbs(0.0); // Placeholder for soil solar radiation absorptivity
1384 186347 : Real64 kSoil(0.0); // Placeholder for soil conductivity
1385 186347 : Real64 dS(0.0); // Placeholder for soil grid spacing
1386 186347 : Real64 rho(0.0); // Placeholder for soil density
1387 186347 : Real64 Cp(0.0); // Placeholder for soil specific heat
1388 :
1389 : // There are a number of coefficients which change through the simulation, and they are updated here
1390 186347 : this->FourierDS = this->SoilDiffusivity * state.dataPipeHT->nsvDeltaTime / pow_2(this->dSregular); // Eq. D4
1391 186347 : this->CoefA1 = this->FourierDS / (1 + 4 * this->FourierDS); // Eq. D2
1392 186347 : this->CoefA2 = 1 / (1 + 4 * this->FourierDS); // Eq. D3
1393 :
1394 195658 : for (IterationIndex = 1; IterationIndex <= MaxIterations; ++IterationIndex) {
1395 195658 : if (IterationIndex == MaxIterations) {
1396 0 : ShowWarningError(state, "BuriedPipeHeatTransfer: Large number of iterations detected in object: " + this->Name);
1397 : }
1398 :
1399 : // Store computed values in T_O array
1400 3913160 : for (LengthIndex = 2; LengthIndex <= this->NumSections; ++LengthIndex) {
1401 29740016 : for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes - 1; ++DepthIndex) {
1402 104090056 : for (WidthIndex = 2; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
1403 78067542 : T_O(WidthIndex, DepthIndex, LengthIndex) = this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative);
1404 : }
1405 : }
1406 : }
1407 :
1408 : // Loop along entire length of pipe, analyzing cross sects
1409 4108818 : for (LengthIndex = 1; LengthIndex <= this->NumSections; ++LengthIndex) {
1410 31305280 : for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes - 1; ++DepthIndex) {
1411 109568480 : for (WidthIndex = 2; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
1412 :
1413 82176360 : if (DepthIndex == 1) { // Soil Surface Boundary
1414 :
1415 : // If on soil boundary, load up local variables and perform calculations
1416 11739480 : NodePast = this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Previous);
1417 11739480 : PastNodeTempAbs = NodePast + DataGlobalConstants::KelvinConv;
1418 11739480 : SkyTempAbs = state.dataEnvrn->SkyTemp + DataGlobalConstants::KelvinConv;
1419 11739480 : TopRoughness = this->SoilRoughness;
1420 11739480 : TopThermAbs = this->SoilThermAbs;
1421 11739480 : TopSolarAbs = this->SoilSolarAbs;
1422 11739480 : kSoil = this->SoilConductivity;
1423 11739480 : dS = this->dSregular;
1424 11739480 : rho = this->SoilDensity;
1425 11739480 : Cp = this->SoilCp;
1426 :
1427 : // ASHRAE simple convection coefficient model for external surfaces.
1428 11739480 : this->OutdoorConvCoef = CalcASHRAESimpExtConvectCoeff(TopRoughness, state.dataEnvrn->WindSpeed);
1429 11739480 : ConvCoef = this->OutdoorConvCoef;
1430 :
1431 : // thermal radiation coefficient using surf temp from past time step
1432 11739480 : if (std::abs(PastNodeTempAbs - SkyTempAbs) > DataGlobalConstants::rTinyValue) {
1433 11739480 : RadCoef = StefBoltzmann * TopThermAbs * (pow_4(PastNodeTempAbs) - pow_4(SkyTempAbs)) / (PastNodeTempAbs - SkyTempAbs);
1434 : } else {
1435 0 : RadCoef = 0.0;
1436 : }
1437 :
1438 : // total absorbed solar - no ground solar
1439 11739480 : QSolAbsorbed =
1440 11739480 : TopSolarAbs * (max(state.dataEnvrn->SOLCOS(3), 0.0) * state.dataEnvrn->BeamSolarRad + state.dataEnvrn->DifSolarRad);
1441 :
1442 : // If sun is not exposed, then turn off both solar and thermal radiation
1443 11739480 : if (!this->SolarExposed) {
1444 0 : RadCoef = 0.0;
1445 0 : QSolAbsorbed = 0.0;
1446 : }
1447 :
1448 11739480 : if (WidthIndex == this->PipeNodeWidth) { // Symmetric centerline boundary
1449 :
1450 : //-Coefficients and Temperatures
1451 3913160 : NodeBelow = this->T(WidthIndex, DepthIndex + 1, LengthIndex, TimeIndex::Current);
1452 3913160 : NodeLeft = this->T(WidthIndex - 1, DepthIndex, LengthIndex, TimeIndex::Current);
1453 :
1454 : //-Update Equation, basically a detailed energy balance at the surface
1455 3913160 : this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative) =
1456 7826320 : (QSolAbsorbed + RadCoef * state.dataEnvrn->SkyTemp + ConvCoef * state.dataEnvrn->OutDryBulbTemp +
1457 11739480 : (kSoil / dS) * (NodeBelow + 2 * NodeLeft) + (rho * Cp / state.dataPipeHT->nsvDeltaTime) * NodePast) /
1458 3913160 : (RadCoef + ConvCoef + 3 * (kSoil / dS) + (rho * Cp / state.dataPipeHT->nsvDeltaTime));
1459 :
1460 : } else { // Soil surface, but not on centerline
1461 :
1462 : //-Coefficients and Temperatures
1463 7826320 : NodeBelow = this->T(WidthIndex, DepthIndex + 1, LengthIndex, TimeIndex::Current);
1464 7826320 : NodeLeft = this->T(WidthIndex - 1, DepthIndex, LengthIndex, TimeIndex::Current);
1465 7826320 : NodeRight = this->T(WidthIndex + 1, DepthIndex, LengthIndex, TimeIndex::Current);
1466 :
1467 : //-Update Equation
1468 7826320 : this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative) =
1469 15652640 : (QSolAbsorbed + RadCoef * state.dataEnvrn->SkyTemp + ConvCoef * state.dataEnvrn->OutDryBulbTemp +
1470 23478960 : (kSoil / dS) * (NodeBelow + NodeLeft + NodeRight) + (rho * Cp / state.dataPipeHT->nsvDeltaTime) * NodePast) /
1471 7826320 : (RadCoef + ConvCoef + 3 * (kSoil / dS) + (rho * Cp / state.dataPipeHT->nsvDeltaTime));
1472 :
1473 : } // Soil-to-air surface node structure
1474 :
1475 70436880 : } else if (WidthIndex == this->PipeNodeWidth) { // On Symmetric centerline boundary
1476 :
1477 23478960 : if (DepthIndex == this->PipeNodeDepth) { // On the node containing the pipe
1478 :
1479 : //-Call to simulate a single pipe segment (by passing OPTIONAL LengthIndex argument)
1480 3913160 : this->CalcPipesHeatTransfer(state, LengthIndex);
1481 :
1482 : //-Update node for cartesian system
1483 3913160 : this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative) = this->PipeTemp(LengthIndex);
1484 :
1485 19565800 : } else if (DepthIndex != 1) { // Not surface node
1486 :
1487 : //-Coefficients and Temperatures
1488 19565800 : NodeLeft = this->T(WidthIndex - 1, DepthIndex, LengthIndex, TimeIndex::Current);
1489 19565800 : NodeAbove = this->T(WidthIndex, DepthIndex - 1, LengthIndex, TimeIndex::Current);
1490 19565800 : NodeBelow = this->T(WidthIndex, DepthIndex + 1, LengthIndex, TimeIndex::Current);
1491 19565800 : NodePast = this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Current - 1);
1492 19565800 : A1 = this->CoefA1;
1493 19565800 : A2 = this->CoefA2;
1494 :
1495 : //-Update Equation
1496 19565800 : this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative) =
1497 19565800 : A1 * (NodeBelow + NodeAbove + 2 * NodeLeft) + A2 * NodePast;
1498 :
1499 : } // Symmetric centerline node structure
1500 :
1501 : } else { // All Normal Interior Nodes
1502 :
1503 : //-Coefficients and Temperatures
1504 46957920 : A1 = this->CoefA1;
1505 46957920 : A2 = this->CoefA2;
1506 46957920 : NodeBelow = this->T(WidthIndex, DepthIndex + 1, LengthIndex, TimeIndex::Current);
1507 46957920 : NodeAbove = this->T(WidthIndex, DepthIndex - 1, LengthIndex, TimeIndex::Current);
1508 46957920 : NodeRight = this->T(WidthIndex + 1, DepthIndex, LengthIndex, TimeIndex::Current);
1509 46957920 : NodeLeft = this->T(WidthIndex - 1, DepthIndex, LengthIndex, TimeIndex::Current);
1510 46957920 : NodePast = this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Current - 1);
1511 :
1512 : //-Update Equation
1513 46957920 : this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative) =
1514 46957920 : A1 * (NodeBelow + NodeAbove + NodeRight + NodeLeft) + A2 * NodePast; // Eq. D1
1515 : }
1516 : }
1517 : }
1518 : }
1519 :
1520 : // Check for convergence
1521 3742925 : for (LengthIndex = 2; LengthIndex <= this->NumSections; ++LengthIndex) {
1522 28396441 : for (DepthIndex = 1; DepthIndex <= this->NumDepthNodes - 1; ++DepthIndex) {
1523 99374806 : for (WidthIndex = 2; WidthIndex <= this->PipeNodeWidth; ++WidthIndex) {
1524 74534943 : Ttemp = this->T(WidthIndex, DepthIndex, LengthIndex, TimeIndex::Tentative);
1525 74534943 : if (std::abs(T_O(WidthIndex, DepthIndex, LengthIndex) - Ttemp) > ConvCrit) goto IterationLoop_loop;
1526 : }
1527 : }
1528 : }
1529 :
1530 : // If we didn't cycle back, then the system is converged
1531 : // PipeHT(PipeHTNum)%PipeUGIters=IterationIndex
1532 186347 : goto IterationLoop_exit;
1533 :
1534 9311 : IterationLoop_loop:;
1535 : }
1536 0 : IterationLoop_exit:;
1537 186347 : }
1538 :
1539 : //==============================================================================
1540 :
1541 58388 : void PipeHTData::UpdatePipesHeatTransfer(EnergyPlusData &state)
1542 : {
1543 :
1544 : // SUBROUTINE INFORMATION:
1545 : // AUTHOR Simon Rees
1546 : // DATE WRITTEN July 2007
1547 : // MODIFIED na
1548 : // RE-ENGINEERED na
1549 :
1550 : // PURPOSE OF THIS SUBROUTINE:
1551 : // This subroutine does any updating that needs to be done for
1552 : // Pipe Heat Transfers. This routine must also set the outlet water conditions.
1553 :
1554 : // METHODOLOGY EMPLOYED:
1555 :
1556 : // REFERENCES:
1557 : // na
1558 :
1559 : // SUBROUTINE ARGUMENT DEFINITIONS:
1560 : // INTEGER, INTENT(IN) :: PipeHTNum ! Index for the surface
1561 :
1562 : // SUBROUTINE PARAMETER DEFINITIONS:
1563 :
1564 : // INTERFACE BLOCK SPECIFICATIONS
1565 : // na
1566 :
1567 : // DERIVED TYPE DEFINITIONS
1568 : // na
1569 :
1570 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1571 :
1572 : // only outlet node temp should need updating
1573 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).Temp = state.dataPipeHT->nsvOutletTemp;
1574 :
1575 : // pass everything else through
1576 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).TempMin = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).TempMin;
1577 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).TempMax = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).TempMax;
1578 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).MassFlowRate =
1579 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).MassFlowRate;
1580 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).MassFlowRateMin =
1581 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).MassFlowRateMin;
1582 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).MassFlowRateMax =
1583 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).MassFlowRateMax;
1584 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).MassFlowRateMinAvail =
1585 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).MassFlowRateMinAvail;
1586 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).MassFlowRateMaxAvail =
1587 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).MassFlowRateMaxAvail;
1588 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).Quality = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).Quality;
1589 : // Only pass pressure if we aren't doing a pressure simulation
1590 58388 : switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).PressureSimType) {
1591 58388 : case DataPlant::PressSimType::NoPressure:
1592 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).Press = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).Press;
1593 58388 : break;
1594 0 : default:
1595 : // Don't do anything
1596 0 : break;
1597 : }
1598 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).Enthalpy = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).Enthalpy;
1599 58388 : state.dataLoopNodes->Node(state.dataPipeHT->nsvOutletNodeNum).HumRat = state.dataLoopNodes->Node(state.dataPipeHT->nsvInletNodeNum).HumRat;
1600 58388 : }
1601 :
1602 : //==============================================================================
1603 :
1604 58388 : void PipeHTData::ReportPipesHeatTransfer(EnergyPlusData &state)
1605 : {
1606 :
1607 : // SUBROUTINE INFORMATION:
1608 : // AUTHOR Simon Rees
1609 : // DATE WRITTEN July 2007
1610 : // MODIFIED na
1611 : // RE-ENGINEERED na
1612 :
1613 : // PURPOSE OF THIS SUBROUTINE:
1614 : // This subroutine simply updates the report data
1615 :
1616 : // METHODOLOGY EMPLOYED:
1617 : // Standard EnergyPlus methodology.
1618 :
1619 : // REFERENCES:
1620 : // na
1621 :
1622 : // USE STATEMENTS:
1623 :
1624 : // Locals
1625 : // SUBROUTINE ARGUMENT DEFINITIONS:
1626 :
1627 : // SUBROUTINE PARAMETER DEFINITIONS:
1628 : // na
1629 :
1630 : // INTERFACE BLOCK SPECIFICATIONS
1631 : // na
1632 :
1633 : // DERIVED TYPE DEFINITIONS
1634 : // na
1635 :
1636 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1637 :
1638 : // update flows and temps from module variables
1639 58388 : this->FluidInletTemp = state.dataPipeHT->nsvInletTemp;
1640 58388 : this->FluidOutletTemp = state.dataPipeHT->nsvOutletTemp;
1641 58388 : this->MassFlowRate = state.dataPipeHT->nsvMassFlowRate;
1642 58388 : this->VolumeFlowRate = state.dataPipeHT->nsvVolumeFlowRate;
1643 :
1644 : // update other variables from module variables
1645 58388 : this->FluidHeatLossRate = state.dataPipeHT->nsvFluidHeatLossRate;
1646 58388 : this->FluidHeatLossEnergy = state.dataPipeHT->nsvFluidHeatLossRate * state.dataPipeHT->nsvDeltaTime; // DeltaTime is in seconds
1647 58388 : this->PipeInletTemp = this->PipeTemp(1);
1648 58388 : this->PipeOutletTemp = this->PipeTemp(this->NumSections);
1649 :
1650 : // need to average the heat rate because it is now summing over multiple inner time steps
1651 58388 : this->EnvironmentHeatLossRate = state.dataPipeHT->nsvEnvHeatLossRate / state.dataPipeHT->nsvNumInnerTimeSteps;
1652 58388 : this->EnvHeatLossEnergy = this->EnvironmentHeatLossRate * state.dataPipeHT->nsvDeltaTime;
1653 :
1654 : // for zone heat gains, we assign the averaged heat rate over all inner time steps
1655 58388 : if (this->EnvironmentPtr == EnvrnPtr::ZoneEnv) {
1656 14597 : this->ZoneHeatGainRate = this->EnvironmentHeatLossRate;
1657 : }
1658 58388 : }
1659 :
1660 : //==============================================================================
1661 :
1662 2568509 : void PipeHTData::CalcZonePipesHeatGain(EnergyPlusData &state)
1663 : {
1664 :
1665 : // SUBROUTINE INFORMATION:
1666 : // AUTHOR Edwin Lee
1667 : // DATE WRITTEN September 2008
1668 : // MODIFIED
1669 : // RE-ENGINEERED na
1670 :
1671 : // PURPOSE OF THIS SUBROUTINE:
1672 : // Calculates the zone internal gains due to pipe heat transfer objects.
1673 :
1674 : // METHODOLOGY EMPLOYED:
1675 : // Sums the heat losses from all of the water heaters in the zone to add as a gain to the zone.
1676 :
1677 : // Using/Aliasing
1678 2568509 : if (state.dataPipeHT->nsvNumOfPipeHT == 0) return;
1679 :
1680 10808 : if (state.dataGlobal->BeginEnvrnFlag && state.dataPipeHT->MyEnvrnFlag) {
1681 64 : for (auto &e : state.dataPipeHT->PipeHT)
1682 32 : e.ZoneHeatGainRate = 0.0;
1683 32 : state.dataPipeHT->MyEnvrnFlag = false;
1684 : }
1685 :
1686 10808 : if (!state.dataGlobal->BeginEnvrnFlag) state.dataPipeHT->MyEnvrnFlag = true;
1687 : }
1688 :
1689 : //==============================================================================
1690 :
1691 4472201 : Real64 PipeHTData::CalcPipeHeatTransCoef(EnergyPlusData &state,
1692 : Real64 const Temperature, // Temperature of water entering the surface, in C
1693 : Real64 const MassFlowRate, // Mass flow rate, in kg/s
1694 : Real64 const Diameter // Pipe diameter, m
1695 : )
1696 : {
1697 :
1698 : // FUNCTION INFORMATION:
1699 : // AUTHOR Simon Rees
1700 : // DATE WRITTEN July 2007
1701 : // MODIFIED na
1702 : // RE-ENGINEERED na
1703 :
1704 : // PURPOSE OF THIS SUBROUTINE:
1705 : // This subroutine calculates pipe/fluid heat transfer coefficients.
1706 : // This routine is adapted from that in the low temp radiant surface model.
1707 :
1708 : // METHODOLOGY EMPLOYED:
1709 : // Currently assumes water data when calculating Pr and Re
1710 :
1711 : // REFERENCES:
1712 : // See RadiantSystemLowTemp module.
1713 : // Property data for water shown below as parameters taken from
1714 : // Incropera and DeWitt, Introduction to Heat Transfer, Table A.6.
1715 : // Heat exchanger information also from Incropera and DeWitt.
1716 : // Code based loosely on code from IBLAST program (research version)
1717 :
1718 : // Using/Aliasing
1719 : using FluidProperties::GetConductivityGlycol;
1720 : using FluidProperties::GetViscosityGlycol;
1721 :
1722 : // Return value
1723 : Real64 CalcPipeHeatTransCoef;
1724 :
1725 : // Locals
1726 : // SUBROUTINE ARGUMENT DEFINITIONS:
1727 :
1728 : // SUBROUTINE PARAMETER DEFINITIONS:
1729 : static constexpr std::string_view RoutineName("PipeHeatTransfer::CalcPipeHeatTransCoef: ");
1730 4472201 : Real64 constexpr MaxLaminarRe(2300.0); // Maximum Reynolds number for laminar flow
1731 4472201 : int constexpr NumOfPropDivisions(13); // intervals in property correlation
1732 : static constexpr std::array<Real64, NumOfPropDivisions> Temps = {
1733 : 1.85, 6.85, 11.85, 16.85, 21.85, 26.85, 31.85, 36.85, 41.85, 46.85, 51.85, 56.85, 61.85}; // Temperature, in C
1734 : static constexpr std::array<Real64, NumOfPropDivisions> Pr = {
1735 : 12.22, 10.26, 8.81, 7.56, 6.62, 5.83, 5.20, 4.62, 4.16, 3.77, 3.42, 3.15, 2.88}; // Prandtl number (dimensionless)
1736 :
1737 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1738 : int idx;
1739 : Real64 InterpFrac;
1740 : Real64 NuD;
1741 : Real64 ReD;
1742 : Real64 Kactual;
1743 : Real64 MUactual;
1744 : Real64 PRactual;
1745 : int LoopNum;
1746 :
1747 : // retrieve loop index for this component so we can look up fluid properties
1748 4472201 : LoopNum = this->plantLoc.loopNum;
1749 :
1750 : // since the fluid properties routine doesn't have Prandtl, we'll just use water values
1751 4472201 : idx = 0;
1752 35843557 : while (idx < NumOfPropDivisions) {
1753 20157879 : if (Temperature < Temps[idx]) {
1754 4472201 : if (idx == 1) {
1755 0 : PRactual = Pr[idx];
1756 4472201 : } else if (idx > NumOfPropDivisions) {
1757 0 : PRactual = Pr[NumOfPropDivisions - 1];
1758 : } else {
1759 4472201 : InterpFrac = (Temperature - Temps[idx - 1]) / (Temps[idx] - Temps[idx - 1]);
1760 4472201 : PRactual = Pr[idx - 1] + InterpFrac * (Pr[idx] - Pr[idx - 1]);
1761 : }
1762 4472201 : break; // DO loop
1763 : } else {
1764 15685678 : PRactual = Pr[NumOfPropDivisions - 1];
1765 : }
1766 15685678 : ++idx;
1767 : }
1768 :
1769 : // look up conductivity and viscosity
1770 13416603 : Kactual = GetConductivityGlycol(
1771 13416603 : state, state.dataPlnt->PlantLoop(LoopNum).FluidName, this->FluidTemp(0), state.dataPlnt->PlantLoop(LoopNum).FluidIndex, RoutineName); // W/m-K
1772 4472201 : MUactual =
1773 13416603 : GetViscosityGlycol(
1774 13416603 : state, state.dataPlnt->PlantLoop(LoopNum).FluidName, this->FluidTemp(0), state.dataPlnt->PlantLoop(LoopNum).FluidIndex, RoutineName) /
1775 : 1000.0; // Note fluid properties routine returns mPa-s, we need Pa-s
1776 :
1777 : // Calculate the Reynold's number from RE=(4*Mdot)/(Pi*Mu*Diameter) - as RadiantSysLowTemp
1778 4472201 : ReD = 4.0 * MassFlowRate / (DataGlobalConstants::Pi * MUactual * Diameter);
1779 :
1780 4472201 : if (ReD == 0.0) { // No flow
1781 :
1782 : // For now just leave it how it was doing it before
1783 1938541 : NuD = 3.66;
1784 : // Although later it would be nice to have a natural convection correlation
1785 :
1786 : } else { // Calculate the Nusselt number based on what flow regime one is in
1787 :
1788 2533660 : if (ReD >= MaxLaminarRe) { // Turbulent flow --> use Colburn equation
1789 2533660 : NuD = 0.023 * std::pow(ReD, 0.8) * std::pow(PRactual, 1.0 / 3.0);
1790 : } else { // Laminar flow --> use constant surface temperature relation
1791 0 : NuD = 3.66;
1792 : }
1793 : }
1794 :
1795 4472201 : CalcPipeHeatTransCoef = Kactual * NuD / Diameter;
1796 :
1797 4472201 : return CalcPipeHeatTransCoef;
1798 : }
1799 :
1800 : //==============================================================================
1801 :
1802 559041 : Real64 PipeHTData::OutsidePipeHeatTransCoef(EnergyPlusData &state)
1803 : {
1804 :
1805 : // FUNCTION INFORMATION:
1806 : // AUTHOR Dan Fisher
1807 : // DATE WRITTEN July 2007
1808 : // MODIFIED na
1809 : // RE-ENGINEERED na
1810 :
1811 : // PURPOSE OF THIS SUBROUTINE:
1812 : // This subroutine calculates the convection heat transfer
1813 : // coefficient for a cylinder in cross flow.
1814 :
1815 : // REFERENCES:
1816 : // Fundamentals of Heat and Mass Transfer: Incropera and DeWitt, 4th ed.
1817 : // p. 369-370 (Eq. 7:55b)
1818 :
1819 : // Using/Aliasing
1820 : using ScheduleManager::GetCurrentScheduleValue;
1821 :
1822 : // Return value
1823 : Real64 OutsidePipeHeatTransCoef;
1824 :
1825 : // SUBROUTINE PARAMETER DEFINITIONS:
1826 559041 : Real64 constexpr Pr(0.7); // Prandl number for air (assume constant)
1827 559041 : Real64 constexpr CondAir(0.025); // thermal conductivity of air (assume constant) [W/m.K]
1828 559041 : Real64 constexpr RoomAirVel(0.381); // room air velocity of 75 ft./min [m/s]
1829 559041 : Real64 constexpr NaturalConvNusselt(0.36);
1830 : // Nusselt for natural convection for horizontal cylinder
1831 : // from: Correlations for Convective Heat Transfer
1832 : // Dr. Bernhard Spang
1833 : // Chemical Engineers' Resource Page: http://www.cheresources.com/convection.pdf
1834 559041 : int constexpr NumOfParamDivisions(5); // intervals in property correlation
1835 559041 : int constexpr NumOfPropDivisions(12); // intervals in property correlation
1836 :
1837 : static constexpr std::array<Real64, NumOfParamDivisions> CCoef = {0.989, 0.911, 0.683, 0.193, 0.027}; // correlation coefficient
1838 : static constexpr std::array<Real64, NumOfParamDivisions> mExp = {0.33, 0.385, 0.466, 0.618, 0.805}; // exponent
1839 : static constexpr std::array<Real64, NumOfParamDivisions> UpperBound = {4.0, 40.0, 4000.0, 40000.0, 400000.0}; // upper bound of correlation range
1840 : static constexpr std::array<Real64, NumOfPropDivisions> Temperature = {
1841 : -73.0, -23.0, -10.0, 0.0, 10.0, 20.0, 27.0, 30.0, 40.0, 50.0, 76.85, 126.85}; // temperature [C]
1842 : static constexpr std::array<Real64, NumOfPropDivisions> DynVisc = {
1843 : 75.52e-7, 11.37e-6, 12.44e-6, 13.3e-6, 14.18e-6, 15.08e-6, 15.75e-6, 16e-6, 16.95e-6, 17.91e-6, 20.92e-6, 26.41e-6}; // dynamic
1844 : // viscosity
1845 : // [m^2/s]
1846 :
1847 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1848 : int idx;
1849 : Real64 NuD;
1850 : Real64 ReD;
1851 : Real64 Coef;
1852 : Real64 rExp;
1853 : Real64 AirVisc;
1854 : Real64 AirVel;
1855 : Real64 AirTemp;
1856 : Real64 PipeOD;
1857 : bool ViscositySet;
1858 : bool CoefSet;
1859 :
1860 : // Set environmental variables
1861 559041 : switch (this->Type) {
1862 372694 : case DataPlant::PlantEquipmentType::PipeInterior: {
1863 372694 : switch (this->EnvironmentPtr) {
1864 186347 : case EnvrnPtr::ScheduleEnv: {
1865 186347 : AirTemp = GetCurrentScheduleValue(state, this->EnvrSchedPtr);
1866 186347 : AirVel = GetCurrentScheduleValue(state, this->EnvrVelSchedPtr);
1867 186347 : } break;
1868 186347 : case EnvrnPtr::ZoneEnv: {
1869 186347 : AirTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->EnvrZonePtr).MAT;
1870 186347 : AirVel = RoomAirVel;
1871 186347 : } break;
1872 0 : default:
1873 0 : break;
1874 : }
1875 372694 : } break;
1876 186347 : case DataPlant::PlantEquipmentType::PipeExterior: {
1877 186347 : switch (this->EnvironmentPtr) {
1878 186347 : case EnvrnPtr::OutsideAirEnv: {
1879 186347 : AirTemp = state.dataLoopNodes->Node(this->EnvrAirNodeNum).Temp;
1880 186347 : AirVel = state.dataEnvrn->WindSpeed;
1881 186347 : } break;
1882 0 : default:
1883 0 : break;
1884 : }
1885 186347 : } break;
1886 0 : default:
1887 0 : break;
1888 : }
1889 :
1890 559041 : PipeOD = this->InsulationOD;
1891 :
1892 559041 : ViscositySet = false;
1893 3706517 : for (idx = 0; idx < NumOfPropDivisions; ++idx) {
1894 3706517 : if (AirTemp <= Temperature[idx]) {
1895 559041 : AirVisc = DynVisc[idx];
1896 559041 : ViscositySet = true;
1897 559041 : break;
1898 : }
1899 : }
1900 :
1901 559041 : if (!ViscositySet) {
1902 0 : AirVisc = DynVisc[NumOfPropDivisions - 1];
1903 0 : if (AirTemp > Temperature[NumOfPropDivisions - 1]) {
1904 0 : ShowWarningError(state,
1905 0 : "Heat Transfer Pipe = " + this->Name + "Viscosity out of range, air temperature too high, setting to upper limit.");
1906 : }
1907 : }
1908 :
1909 : // Calculate the Reynold's number
1910 559041 : CoefSet = false;
1911 559041 : if (AirVisc > 0.0) {
1912 559041 : ReD = AirVel * PipeOD / (AirVisc);
1913 : }
1914 :
1915 2214001 : for (idx = 0; idx < NumOfParamDivisions; ++idx) {
1916 2214001 : if (ReD <= UpperBound[idx]) {
1917 559041 : Coef = CCoef[idx];
1918 559041 : rExp = mExp[idx];
1919 559041 : CoefSet = true;
1920 559041 : break;
1921 : }
1922 : }
1923 :
1924 559041 : if (!CoefSet) {
1925 0 : Coef = CCoef[NumOfParamDivisions - 1];
1926 0 : rExp = mExp[NumOfParamDivisions - 1];
1927 0 : if (ReD > UpperBound[NumOfParamDivisions - 1]) {
1928 0 : ShowWarningError(state, "Heat Transfer Pipe = " + this->Name + "Reynolds Number out of range, setting coefficients to upper limit.");
1929 : }
1930 : }
1931 :
1932 : // Calculate the Nusselt number
1933 559041 : NuD = Coef * std::pow(ReD, rExp) * std::pow(Pr, 1.0 / 3.0);
1934 :
1935 : // If the wind speed is too small, we need to use natural convection behavior:
1936 559041 : NuD = max(NuD, NaturalConvNusselt);
1937 :
1938 : // h = (k)(Nu)/D
1939 559041 : OutsidePipeHeatTransCoef = CondAir * NuD / PipeOD;
1940 :
1941 559041 : return OutsidePipeHeatTransCoef;
1942 : }
1943 :
1944 : //==============================================================================
1945 :
1946 1322880 : Real64 PipeHTData::TBND(EnergyPlusData &state,
1947 : Real64 const z // Current Depth
1948 : )
1949 : {
1950 :
1951 : // AUTHOR Edwin Lee
1952 : // DATE WRITTEN December 2007
1953 : // MODIFIED na
1954 : // RE-ENGINEERED na
1955 :
1956 : // PURPOSE OF THIS FUNCTION:
1957 : // Returns a temperature to be used on the boundary of the buried pipe model domain
1958 :
1959 : // METHODOLOGY EMPLOYED:
1960 :
1961 : // REFERENCES: See Module Level Description
1962 :
1963 : // Using/Aliasing
1964 1322880 : Real64 curSimTime = state.dataGlobal->DayOfSim * DataGlobalConstants::SecsInDay;
1965 : Real64 TBND;
1966 :
1967 1322880 : TBND = this->groundTempModel->getGroundTempAtTimeInSeconds(state, z, curSimTime);
1968 :
1969 1322880 : return TBND;
1970 : }
1971 :
1972 0 : void PipeHTData::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
1973 : {
1974 0 : }
1975 :
1976 : //===============================================================================
1977 :
1978 : //===============================================================================
1979 :
1980 2313 : } // namespace EnergyPlus::PipeHeatTransfer
|