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 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/BranchNodeConnections.hh>
57 : #include <EnergyPlus/ConvectionCoefficients.hh>
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataEnvironment.hh>
60 : #include <EnergyPlus/DataHVACGlobals.hh>
61 : #include <EnergyPlus/DataHeatBalance.hh>
62 : #include <EnergyPlus/DataIPShortCuts.hh>
63 : #include <EnergyPlus/DataLoopNode.hh>
64 : #include <EnergyPlus/DataPrecisionGlobals.hh>
65 : #include <EnergyPlus/FluidProperties.hh>
66 : #include <EnergyPlus/General.hh>
67 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
68 : #include <EnergyPlus/NodeInputManager.hh>
69 : #include <EnergyPlus/OutputProcessor.hh>
70 : #include <EnergyPlus/Plant/DataPlant.hh>
71 : #include <EnergyPlus/PlantUtilities.hh>
72 : #include <EnergyPlus/PondGroundHeatExchanger.hh>
73 : #include <EnergyPlus/Psychrometrics.hh>
74 : #include <EnergyPlus/UtilityRoutines.hh>
75 :
76 : namespace EnergyPlus::PondGroundHeatExchanger {
77 :
78 : // Module containing the routines dealing with pond ground heat exchangers
79 :
80 : // MODULE INFORMATION:
81 : // AUTHOR Simon Rees
82 : // DATE WRITTEN September 2002
83 : // MODIFIED Brent Griffith Sept 2010, plant upgrades
84 : // RE-ENGINEERED na
85 :
86 : // PURPOSE OF THIS MODULE:
87 : // This model represents a shallow pond with submerged hydronic tubes through
88 : // which the heat transfer fluid is circulated. The model represents a 'shallow'
89 : // pond in that no attempt is made to model any stratification effects that may
90 : // be present in deeper ponds. This type of heat rejector is intended to be
91 : // connected in a condenser loop, with or without other forms of heat rejector.
92 : // The pond model is a 'lumped parameter' model where the pond is represented
93 : // by a single node with thermal mass. The pond surface temperature is the same
94 : // as the temperature at this node, i.e. the surface temperature is the same as
95 : // the bulk temperature. A first order differential equation is solved in the
96 : // model to calculated the pond temperature at each time step. This type of heat
97 : // rejector is modelled as several circuits connected in parallel.
98 :
99 : // METHODOLOGY EMPLOYED:
100 : // A heat balance is calculated at a single node that represents the pond.
101 : // heat transfer takes palce by surface convection, long-wave radiation to the
102 : // sky, absoption of solar energy, ground heat transfer and heat exchange with
103 : // the fluid. A heat exchanger analogy is used to calculate the heat transfer
104 : // between the heat transfer fluid and the pond. The differential equation
105 : // defined by the heat balance is solved using a fourth order Runge-Kutta
106 : // numerical integration method.
107 :
108 : // REFERENCES:
109 : // Chiasson, A. Advances in Modeling of Ground-Source Heat Pump Systems.
110 : // M.S. Thesis, Oklahoma State University, December 1999.
111 : // Chiasson, A.D., J.D. Spitler, S.J. Rees, M.D. Smith. 2000. A Model For
112 : // Simulating The Performance Of A Shallow Pond As A Supplemental Heat Rejecter
113 : // With Closed-Loop Ground-Source Heat Pump Systems.
114 : // ASHRAE Transactions. 106(2):107-121.
115 :
116 : Real64 constexpr StefBoltzmann(5.6697e-08); // Stefan-Boltzmann constant
117 : auto constexpr fluidNameWater("WATER");
118 :
119 122895 : void PondGroundHeatExchangerData::simulate(EnergyPlusData &state,
120 : [[maybe_unused]] const PlantLocation &calledFromLocation,
121 : bool const FirstHVACIteration,
122 : [[maybe_unused]] Real64 &CurLoad,
123 : [[maybe_unused]] bool const RunFlag)
124 : {
125 122895 : this->InitPondGroundHeatExchanger(state, FirstHVACIteration);
126 122895 : this->CalcPondGroundHeatExchanger(state);
127 122895 : this->UpdatePondGroundHeatExchanger(state);
128 122895 : }
129 :
130 3 : PlantComponent *PondGroundHeatExchangerData::factory(EnergyPlusData &state, std::string const &objectName)
131 : {
132 3 : if (state.dataPondGHE->GetInputFlag) {
133 3 : GetPondGroundHeatExchanger(state);
134 3 : state.dataPondGHE->GetInputFlag = false;
135 : }
136 3 : for (auto &ghx : state.dataPondGHE->PondGHE) {
137 3 : if (ghx.Name == objectName) {
138 3 : return &ghx;
139 : }
140 : }
141 : // If we didn't find it, fatal
142 0 : ShowFatalError(state, "Pond Heat Exchanger Factory: Error getting inputs for GHX named: " + objectName);
143 : // Shut up the compiler
144 0 : return nullptr;
145 : }
146 :
147 15 : void PondGroundHeatExchangerData::onInitLoopEquip(EnergyPlusData &state, [[maybe_unused]] const PlantLocation &calledFromLocation)
148 : {
149 15 : this->InitPondGroundHeatExchanger(state, true);
150 15 : }
151 :
152 15 : void PondGroundHeatExchangerData::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
153 : [[maybe_unused]] const PlantLocation &calledFromLocation,
154 : Real64 &MaxLoad,
155 : Real64 &MinLoad,
156 : Real64 &OptLoad)
157 : {
158 15 : MaxLoad = this->DesignCapacity;
159 15 : MinLoad = 0.0;
160 15 : OptLoad = this->DesignCapacity;
161 15 : }
162 :
163 3 : void GetPondGroundHeatExchanger(EnergyPlusData &state)
164 : {
165 :
166 : // SUBROUTINE INFORMATION:
167 : // AUTHOR Simon Rees
168 : // DATE WRITTEN August 2002
169 : // MODIFIED na
170 : // RE-ENGINEERED na
171 :
172 : // PURPOSE OF THIS SUBROUTINE:
173 : // This subroutine reads the input for hydronic Pond Ground Heat Exchangers
174 : // from the user input file. This will contain all of the information
175 : // needed to define and simulate the pond.
176 :
177 3 : bool ErrorsFound(false); // Set to true if errors in input,
178 :
179 : int IOStatus; // Used in GetObjectItem
180 : int Item; // Item to be "gotten"
181 : int NumAlphas; // Number of Alphas for each GetObjectItem call
182 : int NumNumbers; // Number of Numbers for each GetObjectItem call
183 :
184 : // Initializations and allocations
185 3 : state.dataIPShortCut->cCurrentModuleObject = "GroundHeatExchanger:Pond";
186 3 : state.dataPondGHE->NumOfPondGHEs =
187 3 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
188 : // allocate data structures
189 3 : if (allocated(state.dataPondGHE->PondGHE)) state.dataPondGHE->PondGHE.deallocate();
190 :
191 3 : state.dataPondGHE->PondGHE.allocate(state.dataPondGHE->NumOfPondGHEs);
192 :
193 : // Obtain all of the user data related to the ponds...
194 6 : for (Item = 1; Item <= state.dataPondGHE->NumOfPondGHEs; ++Item) {
195 :
196 : // get the input data
197 18 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
198 3 : state.dataIPShortCut->cCurrentModuleObject,
199 : Item,
200 3 : state.dataIPShortCut->cAlphaArgs,
201 : NumAlphas,
202 3 : state.dataIPShortCut->rNumericArgs,
203 : NumNumbers,
204 : IOStatus,
205 : _,
206 : _,
207 3 : state.dataIPShortCut->cAlphaFieldNames,
208 3 : state.dataIPShortCut->cNumericFieldNames);
209 :
210 3 : state.dataPondGHE->PondGHE(Item).WaterIndex = FluidProperties::FindGlycol(state, fluidNameWater);
211 :
212 : // General user input data
213 3 : state.dataPondGHE->PondGHE(Item).Name = state.dataIPShortCut->cAlphaArgs(1);
214 :
215 : // get inlet node data
216 3 : state.dataPondGHE->PondGHE(Item).InletNode = state.dataIPShortCut->cAlphaArgs(2);
217 3 : state.dataPondGHE->PondGHE(Item).InletNodeNum =
218 6 : NodeInputManager::GetOnlySingleNode(state,
219 3 : state.dataIPShortCut->cAlphaArgs(2),
220 : ErrorsFound,
221 : DataLoopNode::ConnectionObjectType::GroundHeatExchangerPond,
222 3 : state.dataIPShortCut->cAlphaArgs(1),
223 : DataLoopNode::NodeFluidType::Water,
224 : DataLoopNode::ConnectionType::Inlet,
225 : NodeInputManager::CompFluidStream::Primary,
226 3 : DataLoopNode::ObjectIsNotParent);
227 3 : if (state.dataPondGHE->PondGHE(Item).InletNodeNum == 0) {
228 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(2) + '=' + state.dataIPShortCut->cAlphaArgs(2));
229 0 : ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
230 0 : ErrorsFound = true;
231 : }
232 :
233 : // get outlet node data
234 3 : state.dataPondGHE->PondGHE(Item).OutletNode = state.dataIPShortCut->cAlphaArgs(3);
235 3 : state.dataPondGHE->PondGHE(Item).OutletNodeNum =
236 6 : NodeInputManager::GetOnlySingleNode(state,
237 3 : state.dataIPShortCut->cAlphaArgs(3),
238 : ErrorsFound,
239 : DataLoopNode::ConnectionObjectType::GroundHeatExchangerPond,
240 3 : state.dataIPShortCut->cAlphaArgs(1),
241 : DataLoopNode::NodeFluidType::Water,
242 : DataLoopNode::ConnectionType::Outlet,
243 : NodeInputManager::CompFluidStream::Primary,
244 3 : DataLoopNode::ObjectIsNotParent);
245 3 : if (state.dataPondGHE->PondGHE(Item).OutletNodeNum == 0) {
246 0 : ShowSevereError(state, "Invalid " + state.dataIPShortCut->cAlphaFieldNames(3) + '=' + state.dataIPShortCut->cAlphaArgs(3));
247 0 : ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
248 0 : ErrorsFound = true;
249 : }
250 :
251 9 : BranchNodeConnections::TestCompSet(state,
252 3 : state.dataIPShortCut->cCurrentModuleObject,
253 3 : state.dataIPShortCut->cAlphaArgs(1),
254 3 : state.dataIPShortCut->cAlphaArgs(2),
255 3 : state.dataIPShortCut->cAlphaArgs(3),
256 : "Condenser Water Nodes");
257 :
258 : // pond geometry data
259 3 : state.dataPondGHE->PondGHE(Item).Depth = state.dataIPShortCut->rNumericArgs(1);
260 3 : state.dataPondGHE->PondGHE(Item).Area = state.dataIPShortCut->rNumericArgs(2);
261 3 : if (state.dataIPShortCut->rNumericArgs(1) <= 0.0) {
262 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->rNumericArgs(1)));
263 0 : ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
264 0 : ShowContinueError(state, "Value must be greater than 0.0");
265 0 : ErrorsFound = true;
266 : }
267 3 : if (state.dataIPShortCut->rNumericArgs(2) <= 0.0) {
268 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
269 0 : ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
270 0 : ShowContinueError(state, "Value must be greater than 0.0");
271 0 : ErrorsFound = true;
272 : }
273 :
274 : // tube data
275 3 : state.dataPondGHE->PondGHE(Item).TubeInDiameter = state.dataIPShortCut->rNumericArgs(3);
276 3 : state.dataPondGHE->PondGHE(Item).TubeOutDiameter = state.dataIPShortCut->rNumericArgs(4);
277 :
278 3 : if (state.dataIPShortCut->rNumericArgs(3) <= 0.0) {
279 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(3), state.dataIPShortCut->rNumericArgs(3)));
280 0 : ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
281 0 : ShowContinueError(state, "Value must be greater than 0.0");
282 0 : ErrorsFound = true;
283 : }
284 3 : if (state.dataIPShortCut->rNumericArgs(4) <= 0.0) {
285 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(4), state.dataIPShortCut->rNumericArgs(4)));
286 0 : ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
287 0 : ShowContinueError(state, "Value must be greater than 0.0");
288 0 : ErrorsFound = true;
289 : }
290 3 : if (state.dataIPShortCut->rNumericArgs(3) > state.dataIPShortCut->rNumericArgs(4)) { // error
291 0 : ShowSevereError(state, "For " + state.dataIPShortCut->cCurrentModuleObject + ": " + state.dataIPShortCut->cAlphaArgs(1));
292 0 : ShowContinueError(state,
293 0 : format("{} [{:.2R}] > {} [{:.2R}]",
294 0 : state.dataIPShortCut->cNumericFieldNames(3),
295 0 : state.dataIPShortCut->rNumericArgs(3),
296 0 : state.dataIPShortCut->cNumericFieldNames(4),
297 0 : state.dataIPShortCut->rNumericArgs(4)));
298 0 : ErrorsFound = true;
299 : }
300 :
301 : // thermal conductivity data
302 3 : state.dataPondGHE->PondGHE(Item).TubeConductivity = state.dataIPShortCut->rNumericArgs(5);
303 3 : state.dataPondGHE->PondGHE(Item).GrndConductivity = state.dataIPShortCut->rNumericArgs(6);
304 :
305 3 : if (state.dataIPShortCut->rNumericArgs(5) <= 0.0) {
306 0 : ShowSevereError(state, format("Invalid {}={:.4R}", state.dataIPShortCut->cNumericFieldNames(5), state.dataIPShortCut->rNumericArgs(5)));
307 0 : ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
308 0 : ShowContinueError(state, "Value must be greater than 0.0");
309 0 : ErrorsFound = true;
310 : }
311 3 : if (state.dataIPShortCut->rNumericArgs(6) <= 0.0) {
312 0 : ShowSevereError(state, format("Invalid {}={:.4R}", state.dataIPShortCut->cNumericFieldNames(6), state.dataIPShortCut->rNumericArgs(6)));
313 0 : ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
314 0 : ShowContinueError(state, "Value must be greater than 0.0");
315 0 : ErrorsFound = true;
316 : }
317 :
318 : // circuits
319 3 : state.dataPondGHE->PondGHE(Item).NumCircuits = state.dataIPShortCut->rNumericArgs(7);
320 :
321 3 : if (state.dataIPShortCut->rNumericArgs(7) <= 0) {
322 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(7), state.dataIPShortCut->rNumericArgs(7)));
323 0 : ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
324 0 : ShowContinueError(state, "Value must be greater than 0.0");
325 0 : ErrorsFound = true;
326 : }
327 3 : state.dataPondGHE->PondGHE(Item).CircuitLength = state.dataIPShortCut->rNumericArgs(8);
328 3 : if (state.dataIPShortCut->rNumericArgs(8) <= 0) {
329 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(8), state.dataIPShortCut->rNumericArgs(8)));
330 0 : ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + state.dataIPShortCut->cAlphaArgs(1));
331 0 : ShowContinueError(state, "Value must be greater than 0.0");
332 0 : ErrorsFound = true;
333 : }
334 :
335 : } // end of input loop
336 :
337 : // final error check
338 3 : if (ErrorsFound) {
339 0 : ShowFatalError(state, "Errors found in processing input for " + state.dataIPShortCut->cCurrentModuleObject);
340 : }
341 :
342 3 : if (!state.dataEnvrn->GroundTemp_DeepObjInput) {
343 0 : ShowWarningError(state, "GetPondGroundHeatExchanger: No \"Site:GroundTemperature:Deep\" were input.");
344 0 : ShowContinueError(state, format("Defaults, constant throughout the year of ({:.1R}) will be used.", state.dataEnvrn->GroundTemp_Deep));
345 : }
346 3 : }
347 :
348 3 : void PondGroundHeatExchangerData::setupOutputVars(EnergyPlusData &state)
349 : {
350 6 : SetupOutputVariable(state,
351 : "Pond Heat Exchanger Heat Transfer Rate",
352 : OutputProcessor::Unit::W,
353 : this->HeatTransferRate,
354 : OutputProcessor::SOVTimeStepType::Plant,
355 : OutputProcessor::SOVStoreType::Average,
356 3 : this->Name);
357 6 : SetupOutputVariable(state,
358 : "Pond Heat Exchanger Heat Transfer Energy",
359 : OutputProcessor::Unit::J,
360 : this->Energy,
361 : OutputProcessor::SOVTimeStepType::Plant,
362 : OutputProcessor::SOVStoreType::Summed,
363 3 : this->Name);
364 6 : SetupOutputVariable(state,
365 : "Pond Heat Exchanger Mass Flow Rate",
366 : OutputProcessor::Unit::kg_s,
367 : this->MassFlowRate,
368 : OutputProcessor::SOVTimeStepType::Plant,
369 : OutputProcessor::SOVStoreType::Average,
370 3 : this->Name);
371 6 : SetupOutputVariable(state,
372 : "Pond Heat Exchanger Inlet Temperature",
373 : OutputProcessor::Unit::C,
374 : this->InletTemp,
375 : OutputProcessor::SOVTimeStepType::Plant,
376 : OutputProcessor::SOVStoreType::Average,
377 3 : this->Name);
378 6 : SetupOutputVariable(state,
379 : "Pond Heat Exchanger Outlet Temperature",
380 : OutputProcessor::Unit::C,
381 : this->OutletTemp,
382 : OutputProcessor::SOVTimeStepType::Plant,
383 : OutputProcessor::SOVStoreType::Average,
384 3 : this->Name);
385 6 : SetupOutputVariable(state,
386 : "Pond Heat Exchanger Bulk Temperature",
387 : OutputProcessor::Unit::C,
388 : this->PondTemp,
389 : OutputProcessor::SOVTimeStepType::Plant,
390 : OutputProcessor::SOVStoreType::Average,
391 3 : this->Name);
392 3 : }
393 :
394 122910 : void PondGroundHeatExchangerData::InitPondGroundHeatExchanger(EnergyPlusData &state,
395 : bool const FirstHVACIteration // TRUE if 1st HVAC simulation of system timestep
396 : )
397 : {
398 :
399 : // SUBROUTINE INFORMATION:
400 : // AUTHOR Simon Rees
401 : // DATE WRITTEN August 2002
402 : // MODIFIED na
403 : // RE-ENGINEERED na
404 :
405 : // PURPOSE OF THIS SUBROUTINE:
406 : // This subroutine Resets the elements of the data structure as necessary
407 : // at the first HVAC iteration of each time step.
408 :
409 : // METHODOLOGY EMPLOYED:
410 : // One of the things done here is to update the record of the past pond
411 : // temperature. This is needed in order to solve the diff. eqn. to find
412 : // the temperature at the end of the next time step.
413 : // Also set module variables to data structure for this pond. Set flow rate
414 : // from node data and hypothetical design flow.
415 :
416 : // repeated warm up days tend to drive the initial pond temperature toward the drybulb temperature
417 : // For each environment start the pond midway between drybulb and ground temp.
418 :
419 122910 : this->oneTimeInit(state);
420 :
421 122910 : if (FirstHVACIteration && !state.dataHVACGlobal->ShortenTimeStepSys && this->firstTimeThrough) {
422 : // update past temperature
423 6052 : this->PastBulkTemperature = this->BulkTemperature;
424 6052 : this->firstTimeThrough = false;
425 116858 : } else if (!FirstHVACIteration) {
426 61440 : this->firstTimeThrough = true;
427 : }
428 :
429 122910 : this->InletTemp = state.dataLoopNodes->Node(InletNodeNum).Temp;
430 122910 : this->PondTemp = this->BulkTemperature;
431 :
432 : // Hypothetical design flow rate
433 122910 : Real64 DesignFlow = PlantUtilities::RegulateCondenserCompFlowReqOp(state, this->plantLoc, this->DesignMassFlowRate);
434 :
435 122910 : PlantUtilities::SetComponentFlowRate(state, DesignFlow, this->InletNodeNum, this->OutletNodeNum, this->plantLoc);
436 :
437 : // get the current flow rate - module variable
438 122910 : this->MassFlowRate = state.dataLoopNodes->Node(InletNodeNum).MassFlowRate;
439 122910 : }
440 :
441 122895 : void PondGroundHeatExchangerData::CalcPondGroundHeatExchanger(EnergyPlusData &state)
442 : {
443 :
444 : // AUTHOR Simon Rees
445 : // DATE WRITTEN August 2002
446 : // MODIFIED na
447 : // RE-ENGINEERED na
448 :
449 : // PURPOSE OF THIS SUBROUTINE:
450 : // This subroutine does all of the stuff that is necessary to simulate
451 : // a pond ground heat exchanger. Calls are made to appropriate subroutines
452 : // either in this module or outside of it.
453 :
454 : // METHODOLOGY EMPLOYED:
455 : // The differential equation defined by the heat balance is solved using
456 : // a fourth order Runge-Kutta numerical integration method. The differential
457 : // equation is:
458 : // Mdot*Cp*dT/dt = Sum of fluxes.
459 :
460 : // REFERENCES:
461 : // Chiasson, A. Advances in Modeling of Ground-Source Heat Pump Systems.
462 : // M.S. Thesis, Oklahoma State University, December 1999.
463 : // Chiasson, A.D., J.D. Spitler, S.J. Rees, M.D. Smith. 2000. A Model For
464 : // Simulating The Performance Of A Shallow Pond As A Supplemental Heat
465 : // Rejecter With Closed-Loop Ground-Source Heat Pump Systems.
466 : // ASHRAE Transactions. 106(2):107-121.
467 :
468 : static constexpr std::string_view RoutineName("CalcPondGroundHeatExchanger");
469 :
470 122895 : Real64 PondMass = this->Depth * this->Area *
471 368685 : FluidProperties::GetDensityGlycol(
472 245790 : state, fluidNameWater, max(this->PondTemp, DataPrecisionGlobals::constant_zero), this->WaterIndex, RoutineName);
473 :
474 245790 : Real64 SpecificHeat = FluidProperties::GetSpecificHeatGlycol(
475 122895 : state, fluidNameWater, max(this->PondTemp, DataPrecisionGlobals::constant_zero), this->WaterIndex, RoutineName);
476 :
477 122895 : Real64 Flux = this->CalcTotalFLux(state, this->PondTemp);
478 : Real64 PondTempStar =
479 122895 : this->PastBulkTemperature + 0.5 * DataGlobalConstants::SecInHour * state.dataHVACGlobal->TimeStepSys * Flux / (SpecificHeat * PondMass);
480 :
481 122895 : Real64 FluxStar = this->CalcTotalFLux(state, PondTempStar);
482 : Real64 PondTempStarStar =
483 122895 : this->PastBulkTemperature + 0.5 * DataGlobalConstants::SecInHour * state.dataHVACGlobal->TimeStepSys * FluxStar / (SpecificHeat * PondMass);
484 :
485 122895 : Real64 FluxStarStar = this->CalcTotalFLux(state, PondTempStarStar);
486 : Real64 PondTempStarStarStar =
487 122895 : this->PastBulkTemperature + DataGlobalConstants::SecInHour * state.dataHVACGlobal->TimeStepSys * FluxStarStar / (SpecificHeat * PondMass);
488 :
489 368685 : this->PondTemp = this->PastBulkTemperature + DataGlobalConstants::SecInHour * state.dataHVACGlobal->TimeStepSys *
490 245790 : (Flux + 2.0 * FluxStar + 2.0 * FluxStarStar + this->CalcTotalFLux(state, PondTempStarStarStar)) /
491 122895 : (6.0 * SpecificHeat * PondMass);
492 122895 : }
493 :
494 491580 : Real64 PondGroundHeatExchangerData::CalcTotalFLux(EnergyPlusData &state, Real64 const PondBulkTemp // pond temp for this flux calculation
495 : )
496 : {
497 : // AUTHOR Simon Rees
498 : // DATE WRITTEN August 2002
499 : // MODIFIED na
500 : // RE-ENGINEERED na
501 :
502 : // PURPOSE OF THIS FUNCTION:
503 : // This calculates the summation of the heat fluxes on the pond for a
504 : // given pond temperature. The following heat fluxes are calculated:
505 : // convection,
506 : // long-wave radiation,
507 : // solar gain,
508 : // evaporation,
509 : // ground conduction,
510 : // along with heat exchange with the fluid
511 :
512 : // METHODOLOGY EMPLOYED:
513 : // Convection is calculated with the ASHRAE simple convection coefficients.
514 : // Evaporation is calculated assuming a fixed Lewis number - not as in
515 : // Chaisson model. Heat transfer with the fluid is calculated using a heat
516 : // exchanger Effectiveness-NTU method, where the pond is seen as a static
517 : // fluid - this is also different from Chaisson's original model (assumed
518 : // pond at average of inlet and outlet temps).
519 :
520 : // REFERENCES:
521 : // Chiasson, A. Advances in Modeling of Ground-Source Heat Pump Systems.
522 : // M.S. Thesis, Oklahoma State University, December 1999.
523 : // Chiasson, A.D., J.D. Spitler, S.J. Rees, M.D. Smith. 2000. A Model For
524 : // Simulating The Performance Of A Shallow Pond As A Supplemental Heat
525 : // Rejecter With Closed-Loop Ground-Source Heat Pump Systems.
526 : // ASHRAE Transactions. 106(2):107-121.
527 : // Hull, J.R., K.V. Liu, W.T. Sha, J. Kamal, and C.E. Nielsen, 1984.
528 : // Dependence of Ground Heat Losses Upon Solar Pond Size and Perimeter
529 : // Insulation Calculated and Experimental Results. Solar Energy,33(1):25-33.
530 :
531 : Real64 CalcTotalFLux; // function return variable
532 :
533 491580 : Real64 constexpr PrandtlAir(0.71); // Prandtl number for air - assumed constant
534 491580 : Real64 constexpr SchmidtAir(0.6); // Schmidt number for air - assumed constant
535 491580 : Real64 constexpr PondHeight(0.0); // for now
536 :
537 : static constexpr std::string_view RoutineName("PondGroundHeatExchanger:CalcTotalFlux");
538 :
539 : // make a surface heat balance and solve for temperature
540 491580 : Real64 ThermalAbs = 0.9; // thermal absorptivity
541 :
542 : // set appropriate external temp
543 : // use height dependency -- if there was a height for this unit, it could be inserted.
544 : // parameter PondHeight=0.0 is used.
545 491580 : Real64 OutDryBulb = DataEnvironment::OutDryBulbTempAt(state, PondHeight);
546 491580 : Real64 OutWetBulb = DataEnvironment::OutWetBulbTempAt(state, PondHeight);
547 :
548 : Real64 ExternalTemp; // external environmental temp - drybulb or wetbulb
549 491580 : if (state.dataEnvrn->IsSnow || state.dataEnvrn->IsRain) {
550 0 : ExternalTemp = OutWetBulb;
551 : } else { // normal dry conditions
552 491580 : ExternalTemp = OutDryBulb;
553 : }
554 :
555 : // absolute temperatures
556 491580 : Real64 SurfTempAbs = PondBulkTemp + DataGlobalConstants::KelvinConv; // absolute value of surface temp
557 491580 : Real64 SkyTempAbs = state.dataEnvrn->SkyTemp + DataGlobalConstants::KelvinConv; // absolute value of sky temp
558 :
559 : // ASHRAE simple convection coefficient model for external surfaces.
560 491580 : Real64 ConvCoef = ConvectionCoefficients::CalcASHRAESimpExtConvectCoeff(DataSurfaces::SurfaceRoughness::VeryRough,
561 491580 : DataEnvironment::WindSpeedAt(state, PondHeight));
562 :
563 : // convective flux
564 491580 : Real64 FluxConvect = ConvCoef * (PondBulkTemp - ExternalTemp);
565 :
566 : // long-wave radiation between pond and sky.
567 491580 : Real64 FluxLongwave = StefBoltzmann * ThermalAbs * (pow_4(SurfTempAbs) - pow_4(SkyTempAbs));
568 :
569 : // total absorbed solar using function - no ground solar
570 491580 : Real64 FluxSolAbsorbed = CalcSolarFlux(state);
571 :
572 : // specific heat from fluid prop routines
573 983160 : Real64 SpecHeat = FluidProperties::GetSpecificHeatGlycol(state,
574 491580 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
575 : max(this->InletTemp, 0.0),
576 491580 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
577 491580 : RoutineName);
578 : // heat transfer with fluid - heat exchanger analogy.
579 :
580 : // convective flux
581 491580 : Real64 effectiveness = this->CalcEffectiveness(state, this->InletTemp, PondBulkTemp, this->MassFlowRate);
582 491580 : Real64 Qfluid = this->MassFlowRate * SpecHeat * effectiveness * (this->InletTemp - PondBulkTemp);
583 :
584 : // evaporation flux
585 : // get air properties
586 491580 : Real64 HumRatioAir = Psychrometrics::PsyWFnTdbTwbPb(state, OutDryBulb, OutWetBulb, state.dataEnvrn->OutBaroPress);
587 :
588 : // humidity ratio at pond surface/film temperature
589 491580 : Real64 HumRatioFilm = Psychrometrics::PsyWFnTdbTwbPb(state, PondBulkTemp, PondBulkTemp, state.dataEnvrn->OutBaroPress);
590 491580 : Real64 SpecHeatAir = Psychrometrics::PsyCpAirFnW(HumRatioAir);
591 491580 : Real64 LatentHeatAir = Psychrometrics::PsyHfgAirFnWTdb(HumRatioAir, OutDryBulb);
592 :
593 : // evaporative heat flux
594 491580 : Real64 FluxEvap = pow_2(PrandtlAir / SchmidtAir) / 3.0 * ConvCoef / SpecHeatAir * (HumRatioFilm - HumRatioAir) * LatentHeatAir;
595 :
596 : // ground heat transfer flux
597 491580 : Real64 Perimeter = 4.0 * std::sqrt(this->Area); // pond perimeter -- square assumption
598 :
599 : // ground heat transfer coefficient
600 491580 : Real64 UvalueGround = 0.999 * (this->GrndConductivity / this->Depth) + 1.37 * (this->GrndConductivity * Perimeter / this->Area);
601 :
602 : // ground heat transfer flux
603 491580 : Real64 FluxGround = UvalueGround * (PondBulkTemp - state.dataEnvrn->GroundTemp_Deep);
604 :
605 491580 : CalcTotalFLux = Qfluid + this->Area * (FluxSolAbsorbed - FluxConvect - FluxLongwave - FluxEvap - FluxGround);
606 :
607 491580 : return CalcTotalFLux;
608 : }
609 :
610 491580 : Real64 PondGroundHeatExchangerData::CalcSolarFlux(EnergyPlusData &state) const
611 : {
612 :
613 : // FUNCTION INFORMATION:
614 : // AUTHOR Simon Rees
615 : // DATE WRITTEN August 2002
616 : // MODIFIED na
617 : // RE-ENGINEERED na
618 :
619 : // PURPOSE OF THIS SUBROUTINE:
620 : // This is used to calculate the net solar flux absorbed by the pond.
621 :
622 : // METHODOLOGY EMPLOYED:
623 : // This is calculated from basic optical formula using the extinction
624 : // coefficient of the pond as the main parameter. This can be in a
625 : // wide range: 0.13 - 7.5 in the literature depending on algae, suspended
626 : // solids etc. ??
627 :
628 : // REFERENCES:
629 : // Duffie, J.A. and W.A. Beckman, 1991. Solar Engineering of Thermal
630 : // Processes, 2 nd Edition. John Wiley and Sons.
631 : // Chiasson, A. Advances in Modeling of Ground-Source Heat Pump Systems.
632 : // M.S. Thesis, Oklahoma State University, December 1999.
633 : // Chiasson, A.D., J.D. Spitler, S.J. Rees, M.D. Smith. 2000. A Model For
634 : // Simulating The Performance Of A Shallow Pond As A Supplemental Heat
635 : // Rejecter With Closed-Loop Ground-Source Heat Pump Systems.
636 : // ASHRAE Transactions. 106(2):107-121.
637 :
638 : Real64 CalcSolarFlux; // Function return variable
639 :
640 491580 : Real64 constexpr WaterRefIndex(1.33); // refractive index of water
641 491580 : Real64 constexpr AirRefIndex(1.0003); // refractive index of air
642 491580 : Real64 constexpr PondExtCoef(0.3); // extinction coefficient of water
643 :
644 : // check for sun up.
645 491580 : if (!state.dataEnvrn->SunIsUp) {
646 244876 : CalcSolarFlux = 0.0;
647 244876 : return CalcSolarFlux;
648 : }
649 :
650 : // get the incidence and reflection angles
651 246704 : Real64 IncidAngle = std::acos(state.dataEnvrn->SOLCOS(3));
652 246704 : Real64 RefractAngle = std::asin(std::sin(IncidAngle) * AirRefIndex / WaterRefIndex);
653 :
654 : // absorbed component: Tau_a
655 246704 : Real64 Absorbtance = std::exp(-PondExtCoef * this->Depth / std::cos(RefractAngle));
656 :
657 : // parallel and perpendicular components
658 246704 : Real64 ParallelRad = pow_2(std::tan(RefractAngle - IncidAngle)) / pow_2(std::tan(RefractAngle + IncidAngle));
659 246704 : Real64 PerpendRad = pow_2(std::sin(RefractAngle - IncidAngle)) / pow_2(std::sin(RefractAngle + IncidAngle));
660 :
661 : // transmittance: Tau
662 246704 : Real64 Transmitance = 0.5 * Absorbtance * ((1.0 - ParallelRad) / (1.0 + ParallelRad) + (1.0 - PerpendRad) / (1.0 + PerpendRad));
663 :
664 : // reflectance: Tau_a - Tau
665 246704 : Real64 Reflectance = Absorbtance - Transmitance;
666 :
667 : // apply reflectance to beam and diffuse solar to find flux
668 246704 : CalcSolarFlux = (1.0 - Reflectance) * (state.dataEnvrn->SOLCOS(3) * state.dataEnvrn->BeamSolarRad + state.dataEnvrn->DifSolarRad);
669 :
670 246704 : return CalcSolarFlux;
671 : }
672 :
673 614475 : Real64 PondGroundHeatExchangerData::CalcEffectiveness(EnergyPlusData &state,
674 : Real64 const InsideTemperature, // Temperature of fluid in pipe circuit, in C
675 : Real64 const PondTemperature, // Temperature of pond water (i.e. outside the pipe), in C
676 : Real64 const massFlowRate // Mass flow rate, in kg/s
677 : )
678 : {
679 :
680 : // FUNCTION INFORMATION:
681 : // AUTHOR Simon Rees
682 : // DATE WRITTEN August 2002
683 : // MODIFIED na
684 : // RE-ENGINEERED na
685 :
686 : // PURPOSE OF THIS SUBROUTINE:
687 : // This subroutine calculates the "heat exchanger" effectiveness.
688 : // This routine is adapted from that in the low temp radiant pond model.
689 :
690 : // METHODOLOGY EMPLOYED:
691 : // The heat transfer coefficient is calculated at the pipe and
692 : // consists of inside and outside convection coefficients and conduction
693 : // through the pipe. The other assumptions are that the tube inside
694 : // surface temperature is equal to the "source location temperature"
695 : // and that it is a CONSTANT throughout the pond. External convection is
696 : // natural mode using Churchill and Chu correlation. Inside convection
697 : // calculated using the Dittus-Boelter equation.
698 :
699 : // REFERENCES:
700 : // Incropera, F.P. and D.P. DeWitt, 1996. Introduction to Heat Transfer,
701 : // 3 rd Edition. John Wiley & Sons.
702 : // Churchill, S.W. and H.H.S. Chu. 1975. Correlating Equations for
703 : // Laminar and Turbulent Free Convection from a Horizontal Cylinder.
704 : // International Journal of Heat and Mass Transfer, 18: 1049-1053.
705 : // See also RadiantSystemLowTemp module.
706 :
707 : Real64 CalcEffectiveness; // Function return variable
708 :
709 614475 : Real64 constexpr MaxLaminarRe(2300.0); // Maximum Reynolds number for laminar flow
710 614475 : Real64 constexpr GravConst(9.81); // gravitational constant - should be fixed!
711 : static constexpr std::string_view CalledFrom("PondGroundHeatExchanger:CalcEffectiveness");
712 :
713 : // evaluate properties at pipe fluid temperature for given pipe fluid
714 :
715 1228950 : Real64 SpecificHeat = FluidProperties::GetSpecificHeatGlycol(state,
716 614475 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
717 : InsideTemperature,
718 614475 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
719 614475 : CalledFrom);
720 1228950 : Real64 Conductivity = FluidProperties::GetConductivityGlycol(state,
721 614475 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
722 : InsideTemperature,
723 614475 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
724 614475 : CalledFrom);
725 1228950 : Real64 Viscosity = FluidProperties::GetViscosityGlycol(state,
726 614475 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
727 : InsideTemperature,
728 614475 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
729 614475 : CalledFrom);
730 :
731 : // Calculate the Reynold's number from RE=(4*Mdot)/(Pi*Mu*Diameter)
732 614475 : Real64 ReynoldsNum = 4.0 * massFlowRate / (DataGlobalConstants::Pi * Viscosity * this->TubeInDiameter * this->NumCircuits);
733 :
734 614475 : Real64 PrantlNum = Viscosity * SpecificHeat / Conductivity;
735 :
736 : Real64 NusseltNum; // Nusselt number (dimensionless)
737 :
738 : // Calculate the Nusselt number based on what flow regime one is in. h = (k)(Nu)/D
739 614475 : if (ReynoldsNum >= MaxLaminarRe) { // Turbulent flow --> use Dittus-Boelter equation
740 494080 : NusseltNum = 0.023 * std::pow(ReynoldsNum, 0.8) * std::pow(PrantlNum, 0.3);
741 : } else { // Laminar flow --> use constant surface temperature relation
742 120395 : NusseltNum = 3.66;
743 : }
744 :
745 : // inside convection resistance, from Nu
746 614475 : Real64 ConvCoefIn = Conductivity * NusseltNum / this->TubeInDiameter;
747 :
748 : // now find properties of pond water - always assume pond fluid is water
749 614475 : Real64 WaterSpecHeat = FluidProperties::GetSpecificHeatGlycol(state, fluidNameWater, max(PondTemperature, 0.0), this->WaterIndex, CalledFrom);
750 614475 : Real64 WaterConductivity = FluidProperties::GetConductivityGlycol(state, fluidNameWater, max(PondTemperature, 0.0), this->WaterIndex, CalledFrom);
751 614475 : Real64 WaterViscosity = FluidProperties::GetViscosityGlycol(state, fluidNameWater, max(PondTemperature, 0.0), this->WaterIndex, CalledFrom);
752 614475 : Real64 WaterDensity = FluidProperties::GetDensityGlycol(state, fluidNameWater, max(PondTemperature, 0.0), this->WaterIndex, CalledFrom);
753 :
754 : // derived properties for natural convection coefficient
755 : // expansion coef (Beta) = -1/Rho. dRho/dT
756 : // The following code includes some slight modifications from Simon's original code.
757 : // It guarantees that the delta T is 10C and also avoids the problems associated with
758 : // water hitting a maximum density at around 4C. (RKS)
759 : Real64 ExpansionCoef =
760 1843425 : -(FluidProperties::GetDensityGlycol(state, fluidNameWater, max(PondTemperature, 10.0) + 5.0, this->WaterIndex, CalledFrom) -
761 1228950 : FluidProperties::GetDensityGlycol(state, fluidNameWater, max(PondTemperature, 10.0) - 5.0, this->WaterIndex, CalledFrom)) /
762 614475 : (10.0 * WaterDensity);
763 :
764 614475 : Real64 ThermDiff = WaterConductivity / (WaterDensity * WaterSpecHeat);
765 614475 : PrantlNum = WaterViscosity * WaterSpecHeat / WaterConductivity;
766 :
767 614475 : Real64 RayleighNum = WaterDensity * GravConst * ExpansionCoef * std::abs(InsideTemperature - PondTemperature) * pow_3(TubeOutDiameter) /
768 614475 : (WaterViscosity * ThermDiff);
769 :
770 : // Calculate the Nusselt number for natural convection at outside of pipe
771 614475 : NusseltNum = pow_2(0.6 + (0.387 * std::pow(RayleighNum, 1.0 / 6.0) / (std::pow(1.0 + 0.559 / std::pow(PrantlNum, 9.0 / 16.0), 8.0 / 27.0))));
772 :
773 : // outside convection resistance, from Nu
774 614475 : Real64 ConvCoefOut = WaterConductivity * NusseltNum / this->TubeOutDiameter;
775 :
776 : // conduction resistance of pipe
777 614475 : Real64 PipeResistance = this->TubeInDiameter / this->TubeConductivity * std::log(this->TubeOutDiameter / this->TubeInDiameter);
778 :
779 : // total pipe thermal resistance - conduction and convection
780 614475 : Real64 TotalResistance = PipeResistance + 1.0 / ConvCoefIn + this->TubeInDiameter / (this->TubeOutDiameter * ConvCoefOut);
781 :
782 : // Calculate the NTU parameter
783 : // NTU = UA/[(Mdot*Cp)min] = A/[Rtot*(Mdot*Cp)min]
784 : // where: Rtot = Ri,convection + Rconduction + Ro,conveciton
785 : // A = Pi*D*TubeLength
786 :
787 : Real64 NTU; // Number of transfer units, non-dimensional
788 :
789 614475 : if (massFlowRate == 0.0) {
790 55955 : CalcEffectiveness = 1.0;
791 : } else {
792 558520 : NTU = DataGlobalConstants::Pi * TubeInDiameter * this->CircuitLength * this->NumCircuits / (TotalResistance * massFlowRate * SpecificHeat);
793 : // Calculate effectiveness - formula for static fluid
794 558520 : CalcEffectiveness = (1.0 - std::exp(-NTU));
795 : }
796 :
797 : // Check for frozen pond
798 614475 : if (PondTemperature < 0.0) {
799 0 : ++this->ConsecutiveFrozen;
800 0 : if (this->FrozenErrIndex == 0) {
801 0 : ShowWarningMessage(state,
802 0 : format("GroundHeatExchanger:Pond=\"{}\", is frozen; Pond model not valid. Calculated Pond Temperature=[{:.2R}] C",
803 : this->Name,
804 0 : PondTemperature));
805 0 : ShowContinueErrorTimeStamp(state, "");
806 : }
807 0 : ShowRecurringWarningErrorAtEnd(state,
808 0 : "GroundHeatExchanger:Pond=\"" + this->Name + "\", is frozen",
809 : this->FrozenErrIndex,
810 : PondTemperature,
811 : PondTemperature,
812 : _,
813 : "[C]",
814 : "[C]");
815 0 : if (this->ConsecutiveFrozen >= state.dataGlobal->NumOfTimeStepInHour * 30) {
816 0 : ShowFatalError(state, "GroundHeatExchanger:Pond=\"" + this->Name + "\" has been frozen for 30 consecutive hours. Program terminates.");
817 : }
818 : } else {
819 614475 : this->ConsecutiveFrozen = 0;
820 : }
821 :
822 614475 : return CalcEffectiveness;
823 : }
824 :
825 122895 : void PondGroundHeatExchangerData::UpdatePondGroundHeatExchanger(EnergyPlusData &state)
826 : {
827 :
828 : // SUBROUTINE INFORMATION:
829 : // AUTHOR Simon Rees
830 : // DATE WRITTEN August 2002
831 : // MODIFIED na
832 : // RE-ENGINEERED na
833 :
834 : // PURPOSE OF THIS SUBROUTINE:
835 : // This subroutine does any updating that needs to be done for pond
836 : // ground heat exchangers. This routine must also set the outlet water
837 : // conditions.
838 :
839 : static constexpr std::string_view RoutineName("PondGroundHeatExchanger:Update");
840 :
841 : // Calculate the water side outlet conditions and set the
842 : // appropriate conditions on the correct HVAC node.
843 245790 : Real64 CpFluid = FluidProperties::GetSpecificHeatGlycol(state,
844 122895 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
845 : this->InletTemp,
846 122895 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
847 122895 : RoutineName);
848 :
849 122895 : PlantUtilities::SafeCopyPlantNode(state, InletNodeNum, OutletNodeNum);
850 :
851 : // update outlet temp
852 122895 : if ((CpFluid > 0.0) && (this->MassFlowRate > 0.0)) {
853 111704 : this->OutletTemp = this->InletTemp - this->HeatTransferRate / (this->MassFlowRate * CpFluid);
854 : } else {
855 11191 : this->OutletTemp = this->InletTemp;
856 : }
857 :
858 : // update node
859 122895 : state.dataLoopNodes->Node(this->OutletNodeNum).Temp = this->OutletTemp;
860 122895 : state.dataLoopNodes->Node(this->OutletNodeNum).MassFlowRate = this->MassFlowRate;
861 :
862 : // update heat transfer rate
863 : // compute pond heat transfer
864 122895 : Real64 effectiveness = this->CalcEffectiveness(state, this->InletTemp, this->PondTemp, this->MassFlowRate);
865 122895 : this->HeatTransferRate = this->MassFlowRate * CpFluid * effectiveness * (this->InletTemp - this->PondTemp);
866 122895 : this->Energy = this->HeatTransferRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
867 :
868 : // keep track of the bulk temperature
869 122895 : this->BulkTemperature = this->PondTemp;
870 122895 : }
871 122910 : void PondGroundHeatExchangerData::oneTimeInit(EnergyPlusData &state)
872 : {
873 122910 : Real64 constexpr DesignVelocity(0.5); // Hypothetical design max pipe velocity [m/s]
874 122910 : Real64 constexpr PondHeight(0.0); // for now
875 :
876 122910 : static std::string const RoutineName("InitPondGroundHeatExchanger");
877 :
878 122910 : if (this->setupOutputVarsFlag) {
879 3 : this->setupOutputVars(state);
880 3 : this->setupOutputVarsFlag = false;
881 : }
882 :
883 122910 : if (this->OneTimeFlag || state.dataGlobal->WarmupFlag) {
884 : // initialize pond temps to mean of drybulb and ground temps.
885 105622 : this->BulkTemperature = this->PastBulkTemperature =
886 105622 : 0.5 * (DataEnvironment::OutDryBulbTempAt(state, PondHeight) + state.dataEnvrn->GroundTemp_Deep);
887 105622 : this->OneTimeFlag = false;
888 : }
889 :
890 : // Init more variables
891 122910 : if (this->MyFlag) {
892 : // Locate the hx on the plant loops for later usage
893 3 : bool errFlag = false;
894 3 : PlantUtilities::ScanPlantLoopsForObject(
895 : state, this->Name, DataPlant::PlantEquipmentType::GrndHtExchgPond, this->plantLoc, errFlag, _, _, _, _, _);
896 3 : if (errFlag) {
897 0 : ShowFatalError(state, "InitPondGroundHeatExchanger: Program terminated due to previous condition(s).");
898 : }
899 9 : Real64 rho = FluidProperties::GetDensityGlycol(state,
900 3 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
901 : DataPrecisionGlobals::constant_zero,
902 3 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
903 3 : RoutineName);
904 9 : Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state,
905 3 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
906 : DataPrecisionGlobals::constant_zero,
907 3 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
908 3 : RoutineName);
909 3 : this->DesignMassFlowRate = DataGlobalConstants::Pi / 4.0 * pow_2(this->TubeInDiameter) * DesignVelocity * rho * this->NumCircuits;
910 3 : this->DesignCapacity = this->DesignMassFlowRate * Cp * 10.0; // assume 10C delta T?
911 3 : PlantUtilities::InitComponentNodes(state, 0.0, this->DesignMassFlowRate, this->InletNodeNum, this->OutletNodeNum);
912 3 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->InletNodeNum, this->DesignMassFlowRate / rho);
913 :
914 3 : this->MyFlag = false;
915 : }
916 122910 : }
917 :
918 2313 : } // namespace EnergyPlus::PondGroundHeatExchanger
|