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/Construction.hh>
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataConversions.hh>
60 : #include <EnergyPlus/DataEnvironment.hh>
61 : #include <EnergyPlus/DataHVACGlobals.hh>
62 : #include <EnergyPlus/DataHeatBalFanSys.hh>
63 : #include <EnergyPlus/DataHeatBalSurface.hh>
64 : #include <EnergyPlus/DataHeatBalance.hh>
65 : #include <EnergyPlus/DataLoopNode.hh>
66 : #include <EnergyPlus/DataSizing.hh>
67 : #include <EnergyPlus/DataSurfaceLists.hh>
68 : #include <EnergyPlus/DataSurfaces.hh>
69 : #include <EnergyPlus/FluidProperties.hh>
70 : #include <EnergyPlus/General.hh>
71 : #include <EnergyPlus/GeneralRoutines.hh>
72 : #include <EnergyPlus/HeatBalanceSurfaceManager.hh>
73 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
74 : #include <EnergyPlus/NodeInputManager.hh>
75 : #include <EnergyPlus/OutputProcessor.hh>
76 : #include <EnergyPlus/Plant/DataPlant.hh>
77 : #include <EnergyPlus/Plant/PlantLocation.hh>
78 : #include <EnergyPlus/PlantUtilities.hh>
79 : #include <EnergyPlus/Psychrometrics.hh>
80 : #include <EnergyPlus/ScheduleManager.hh>
81 : #include <EnergyPlus/SwimmingPool.hh>
82 : #include <EnergyPlus/UtilityRoutines.hh>
83 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
84 :
85 : namespace EnergyPlus::SwimmingPool {
86 :
87 : // MODULE INFORMATION:
88 : // AUTHOR Rick Strand, Ho-Sung Kim
89 : // DATE WRITTEN June 2012 (F90) and October 2014 (C++)
90 :
91 : // PURPOSE OF THIS MODULE:
92 : // The purpose of this module is to encapsulate the data and algorithms required
93 : // to manage the SwimmingPool System Component.
94 :
95 : // METHODOLOGY EMPLOYED:
96 : // The swimming pool acts as a surface within the heat balance and then connects
97 : // to the plant via a water loop.
98 :
99 : // REFERENCES:
100 : // 1. ASHRAE (2011). 2011 ASHRAE Handbook - HVAC Applications. Atlanta: American Society of Heating,
101 : // Refrigerating and Air-Conditioning Engineers, Inc., p.5.6-5.9.
102 : // 2. Janis, R. and W. Tao (2005). Mechanical and Electrical Systems in Buildings. 3rd ed. Upper
103 : // Saddle River, NJ: Pearson Education, Inc., p.246.
104 : // 3. Kittler, R. (1989). Indoor Natatorium Design and Energy Recycling. ASHRAE Transactions 95(1), p.521-526.
105 : // 4. Smith, C., R. Jones, and G. Lof (1993). Energy Requirements and Potential Savings for Heated
106 : // Indoor Swimming Pools. ASHRAE Transactions 99(2), p.864-874.
107 :
108 6050562 : void SimSwimmingPool(EnergyPlusData &state, bool FirstHVACIteration)
109 : {
110 : // Process the input data if it hasn't been done already
111 6050562 : if (state.dataSwimmingPools->getSwimmingPoolInput) {
112 770 : GetSwimmingPool(state);
113 770 : state.dataSwimmingPools->getSwimmingPoolInput = false;
114 : }
115 :
116 : // System wide (for all pools) inits
117 6050562 : state.dataHeatBalFanSys->SumConvPool = 0.0;
118 6050562 : state.dataHeatBalFanSys->SumLatentPool = 0.0;
119 :
120 6050562 : PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
121 6050562 : Real64 CurLoad = 0.0;
122 6050562 : bool RunFlag = true;
123 :
124 6056100 : for (auto &thisPool : state.dataSwimmingPools->Pool) {
125 5538 : thisPool.simulate(state, A, FirstHVACIteration, CurLoad, RunFlag);
126 : }
127 :
128 6050562 : if (state.dataSwimmingPools->NumSwimmingPools > 0) HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state);
129 :
130 6050562 : ReportSwimmingPool(state);
131 6050562 : }
132 :
133 5538 : void SwimmingPoolData::simulate(EnergyPlusData &state,
134 : [[maybe_unused]] const PlantLocation &calledFromLocation,
135 : bool FirstHVACIteration,
136 : [[maybe_unused]] Real64 &CurLoad,
137 : [[maybe_unused]] bool RunFlag)
138 : {
139 5538 : this->initialize(state, FirstHVACIteration);
140 :
141 5538 : this->calculate(state);
142 :
143 5538 : this->update(state);
144 5538 : }
145 :
146 770 : void GetSwimmingPool(EnergyPlusData &state)
147 : {
148 : // SUBROUTINE INFORMATION:
149 : // AUTHOR Rick Strand, Ho-Sung Kim
150 : // DATE WRITTEN October 2014
151 :
152 : // PURPOSE OF THIS SUBROUTINE:
153 : // This subroutine reads the input for all swimming pools present in
154 : // the user input file. This will contain all of the information needed
155 : // to simulate a swimming pool.
156 :
157 : // SUBROUTINE PARAMETER DEFINITIONS:
158 : static constexpr std::string_view RoutineName("GetSwimmingPool: "); // include trailing blank space
159 770 : Real64 constexpr MinCoverFactor(0.0); // minimum value for cover factors
160 770 : Real64 constexpr MaxCoverFactor(1.0); // maximum value for cover factors
161 770 : Real64 constexpr MinDepth(0.05); // minimum average pool depth (to avoid obvious input errors)
162 770 : Real64 constexpr MaxDepth(10.0); // maximum average pool depth (to avoid obvious input errors)
163 770 : Real64 constexpr MinPowerFactor(0.0); // minimum power factor for miscellaneous equipment
164 :
165 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
166 770 : bool ErrorsFound(false); // Set to true if something goes wrong
167 1540 : std::string CurrentModuleObject; // for ease in getting objects
168 1540 : Array1D_string Alphas; // Alpha items for object
169 1540 : Array1D_string cAlphaFields; // Alpha field names
170 1540 : Array1D_string cNumericFields; // Numeric field names
171 770 : int IOStatus = 0; // Used in GetObjectItem
172 1540 : Array1D<Real64> Numbers; // Numeric items for object
173 770 : int NumAlphas = 0; // Number of Alphas for each GetObjectItem call
174 770 : int NumArgs = 0; // Unused variable that is part of a subroutine call
175 770 : int NumNumbers = 0; // Number of Numbers for each GetObjectItem call
176 1540 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
177 1540 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
178 :
179 : // Initializations and allocations
180 770 : int MaxAlphas = 0; // Maximum number of alphas for these input keywords
181 770 : int MaxNumbers = 0; // Maximum number of numbers for these input keywords
182 :
183 770 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "SwimmingPool:Indoor", NumArgs, NumAlphas, NumNumbers);
184 770 : MaxAlphas = max(MaxAlphas, NumAlphas);
185 770 : MaxNumbers = max(MaxNumbers, NumNumbers);
186 :
187 770 : Alphas.allocate(MaxAlphas);
188 770 : Alphas = "";
189 770 : Numbers.allocate(MaxNumbers);
190 770 : Numbers = 0.0;
191 770 : cAlphaFields.allocate(MaxAlphas);
192 770 : cAlphaFields = "";
193 770 : cNumericFields.allocate(MaxNumbers);
194 770 : cNumericFields = "";
195 770 : lAlphaBlanks.allocate(MaxAlphas);
196 770 : lAlphaBlanks = true;
197 770 : lNumericBlanks.allocate(MaxNumbers);
198 770 : lNumericBlanks = true;
199 :
200 770 : state.dataSwimmingPools->NumSwimmingPools = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SwimmingPool:Indoor");
201 770 : state.dataSwimmingPools->CheckEquipName.allocate(state.dataSwimmingPools->NumSwimmingPools);
202 770 : state.dataSwimmingPools->CheckEquipName = true;
203 :
204 770 : state.dataSwimmingPools->Pool.allocate(state.dataSwimmingPools->NumSwimmingPools);
205 :
206 : // Obtain all of the user data related to indoor swimming pools...
207 770 : CurrentModuleObject = "SwimmingPool:Indoor";
208 772 : for (int Item = 1; Item <= state.dataSwimmingPools->NumSwimmingPools; ++Item) {
209 :
210 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
211 : CurrentModuleObject,
212 : Item,
213 : Alphas,
214 : NumAlphas,
215 : Numbers,
216 : NumNumbers,
217 : IOStatus,
218 : lNumericBlanks,
219 : lAlphaBlanks,
220 : cAlphaFields,
221 : cNumericFields);
222 2 : UtilityRoutines::IsNameEmpty(state, Alphas(1), CurrentModuleObject, ErrorsFound);
223 2 : state.dataSwimmingPools->Pool(Item).Name = Alphas(1);
224 :
225 2 : state.dataSwimmingPools->Pool(Item).SurfaceName = Alphas(2);
226 2 : state.dataSwimmingPools->Pool(Item).SurfacePtr = 0;
227 38 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
228 38 : if (UtilityRoutines::SameString(state.dataSurface->Surface(SurfNum).Name, state.dataSwimmingPools->Pool(Item).SurfaceName)) {
229 2 : state.dataSwimmingPools->Pool(Item).SurfacePtr = SurfNum;
230 2 : break;
231 : }
232 : }
233 :
234 2 : state.dataSwimmingPools->Pool(Item).ErrorCheckSetupPoolSurface(state, Alphas(1), Alphas(2), cAlphaFields(2), ErrorsFound);
235 :
236 2 : state.dataSwimmingPools->Pool(Item).AvgDepth = Numbers(1);
237 2 : if (state.dataSwimmingPools->Pool(Item).AvgDepth < MinDepth) {
238 0 : ShowWarningError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has an average depth that is too small.");
239 0 : ShowContinueError(state, "The pool average depth has been reset to the minimum allowed depth.");
240 2 : } else if (state.dataSwimmingPools->Pool(Item).AvgDepth > MaxDepth) {
241 0 : ShowSevereError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has an average depth that is too large.");
242 0 : ShowContinueError(state, "The pool depth must be less than the maximum average depth of 10 meters.");
243 0 : ErrorsFound = true;
244 : }
245 :
246 2 : state.dataSwimmingPools->Pool(Item).ActivityFactorSchedName = Alphas(3);
247 2 : state.dataSwimmingPools->Pool(Item).ActivityFactorSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(3));
248 2 : if ((state.dataSwimmingPools->Pool(Item).ActivityFactorSchedPtr == 0) && (!lAlphaBlanks(3))) {
249 0 : ShowSevereError(state, cAlphaFields(3) + " not found: " + Alphas(3));
250 0 : ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
251 0 : ErrorsFound = true;
252 : }
253 :
254 2 : state.dataSwimmingPools->Pool(Item).MakeupWaterSupplySchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(4));
255 2 : if ((state.dataSwimmingPools->Pool(Item).MakeupWaterSupplySchedPtr == 0) && (!lAlphaBlanks(4))) {
256 0 : ShowSevereError(state, cAlphaFields(4) + " not found: " + Alphas(4));
257 0 : ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
258 0 : ErrorsFound = true;
259 : }
260 :
261 2 : state.dataSwimmingPools->Pool(Item).CoverSchedName = Alphas(5);
262 2 : state.dataSwimmingPools->Pool(Item).CoverSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(5));
263 2 : if ((state.dataSwimmingPools->Pool(Item).CoverSchedPtr == 0) && (!lAlphaBlanks(5))) {
264 0 : ShowSevereError(state, cAlphaFields(5) + " not found: " + Alphas(5));
265 0 : ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
266 0 : ErrorsFound = true;
267 : }
268 :
269 2 : state.dataSwimmingPools->Pool(Item).CoverEvapFactor = Numbers(2);
270 2 : if (state.dataSwimmingPools->Pool(Item).CoverEvapFactor < MinCoverFactor) {
271 0 : ShowWarningError(state,
272 0 : std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has an evaporation cover factor less than zero.");
273 0 : ShowContinueError(state, "The evaporation cover factor has been reset to zero.");
274 0 : state.dataSwimmingPools->Pool(Item).CoverEvapFactor = MinCoverFactor;
275 2 : } else if (state.dataSwimmingPools->Pool(Item).CoverEvapFactor > MaxCoverFactor) {
276 0 : ShowWarningError(
277 0 : state, std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has an evaporation cover factor greater than one.");
278 0 : ShowContinueError(state, "The evaporation cover factor has been reset to one.");
279 0 : state.dataSwimmingPools->Pool(Item).CoverEvapFactor = MaxCoverFactor;
280 : }
281 :
282 2 : state.dataSwimmingPools->Pool(Item).CoverConvFactor = Numbers(3);
283 2 : if (state.dataSwimmingPools->Pool(Item).CoverConvFactor < MinCoverFactor) {
284 0 : ShowWarningError(state,
285 0 : std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has a convection cover factor less than zero.");
286 0 : ShowContinueError(state, "The convection cover factor has been reset to zero.");
287 0 : state.dataSwimmingPools->Pool(Item).CoverConvFactor = MinCoverFactor;
288 2 : } else if (state.dataSwimmingPools->Pool(Item).CoverConvFactor > MaxCoverFactor) {
289 0 : ShowWarningError(state,
290 0 : std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has a convection cover factor greater than one.");
291 0 : ShowContinueError(state, "The convection cover factor has been reset to one.");
292 0 : state.dataSwimmingPools->Pool(Item).CoverConvFactor = MaxCoverFactor;
293 : }
294 :
295 2 : state.dataSwimmingPools->Pool(Item).CoverSWRadFactor = Numbers(4);
296 2 : if (state.dataSwimmingPools->Pool(Item).CoverSWRadFactor < MinCoverFactor) {
297 0 : ShowWarningError(state,
298 0 : std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) +
299 : " has a short-wavelength radiation cover factor less than zero.");
300 0 : ShowContinueError(state, "The short-wavelength radiation cover factor has been reset to zero.");
301 0 : state.dataSwimmingPools->Pool(Item).CoverSWRadFactor = MinCoverFactor;
302 2 : } else if (state.dataSwimmingPools->Pool(Item).CoverSWRadFactor > MaxCoverFactor) {
303 0 : ShowWarningError(state,
304 0 : std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) +
305 : " has a short-wavelength radiation cover factor greater than one.");
306 0 : ShowContinueError(state, "The short-wavelength radiation cover factor has been reset to one.");
307 0 : state.dataSwimmingPools->Pool(Item).CoverSWRadFactor = MaxCoverFactor;
308 : }
309 :
310 2 : state.dataSwimmingPools->Pool(Item).CoverLWRadFactor = Numbers(5);
311 2 : if (state.dataSwimmingPools->Pool(Item).CoverLWRadFactor < MinCoverFactor) {
312 0 : ShowWarningError(state,
313 0 : std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) +
314 : " has a long-wavelength radiation cover factor less than zero.");
315 0 : ShowContinueError(state, "The long-wavelength radiation cover factor has been reset to zero.");
316 0 : state.dataSwimmingPools->Pool(Item).CoverLWRadFactor = MinCoverFactor;
317 2 : } else if (state.dataSwimmingPools->Pool(Item).CoverLWRadFactor > MaxCoverFactor) {
318 0 : ShowWarningError(state,
319 0 : std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) +
320 : " has a long-wavelength radiation cover factor greater than one.");
321 0 : ShowContinueError(state, "The long-wavelength radiation cover factor has been reset to one.");
322 0 : state.dataSwimmingPools->Pool(Item).CoverLWRadFactor = MaxCoverFactor;
323 : }
324 :
325 2 : state.dataSwimmingPools->Pool(Item).WaterInletNodeName = Alphas(6);
326 2 : state.dataSwimmingPools->Pool(Item).WaterOutletNodeName = Alphas(7);
327 2 : state.dataSwimmingPools->Pool(Item).WaterInletNode =
328 4 : NodeInputManager::GetOnlySingleNode(state,
329 2 : Alphas(6),
330 : ErrorsFound,
331 : DataLoopNode::ConnectionObjectType::SwimmingPoolIndoor,
332 2 : Alphas(1),
333 : DataLoopNode::NodeFluidType::Water,
334 : DataLoopNode::ConnectionType::Inlet,
335 : NodeInputManager::CompFluidStream::Primary,
336 2 : DataLoopNode::ObjectIsNotParent);
337 2 : state.dataSwimmingPools->Pool(Item).WaterOutletNode =
338 4 : NodeInputManager::GetOnlySingleNode(state,
339 2 : Alphas(7),
340 : ErrorsFound,
341 : DataLoopNode::ConnectionObjectType::SwimmingPoolIndoor,
342 2 : Alphas(1),
343 : DataLoopNode::NodeFluidType::Water,
344 : DataLoopNode::ConnectionType::Outlet,
345 : NodeInputManager::CompFluidStream::Primary,
346 2 : DataLoopNode::ObjectIsNotParent);
347 2 : if ((!lAlphaBlanks(6)) || (!lAlphaBlanks(7))) {
348 2 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(6), Alphas(7), "Hot Water Nodes");
349 : }
350 2 : state.dataSwimmingPools->Pool(Item).WaterVolFlowMax = Numbers(6);
351 2 : state.dataSwimmingPools->Pool(Item).MiscPowerFactor = Numbers(7);
352 2 : if (state.dataSwimmingPools->Pool(Item).MiscPowerFactor < MinPowerFactor) {
353 0 : ShowWarningError(
354 0 : state, std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + " has a miscellaneous power factor less than zero.");
355 0 : ShowContinueError(state, "The miscellaneous power factor has been reset to zero.");
356 0 : state.dataSwimmingPools->Pool(Item).MiscPowerFactor = MinPowerFactor;
357 : }
358 :
359 2 : state.dataSwimmingPools->Pool(Item).SetPtTempSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(8));
360 2 : if ((state.dataSwimmingPools->Pool(Item).SetPtTempSchedPtr == 0) && (!lAlphaBlanks(8))) {
361 0 : ShowSevereError(state, cAlphaFields(8) + " not found: " + Alphas(8));
362 0 : ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
363 0 : ErrorsFound = true;
364 : }
365 2 : if (lAlphaBlanks(8)) {
366 0 : ShowSevereError(state, cAlphaFields(8) + " left blank. This is NOT allowed as there must be a pool water setpoint temperature.");
367 0 : ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
368 0 : ErrorsFound = true;
369 : }
370 :
371 2 : state.dataSwimmingPools->Pool(Item).MaxNumOfPeople = Numbers(8);
372 2 : if (state.dataSwimmingPools->Pool(Item).MaxNumOfPeople < 0.0) {
373 0 : ShowWarningError(state,
374 0 : std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) +
375 : " was entered with negative people. This is not allowed.");
376 0 : ShowContinueError(state, "The number of people has been reset to zero.");
377 0 : state.dataSwimmingPools->Pool(Item).MaxNumOfPeople = 0.0;
378 : }
379 :
380 2 : state.dataSwimmingPools->Pool(Item).PeopleSchedName = Alphas(9);
381 2 : state.dataSwimmingPools->Pool(Item).PeopleSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(9));
382 2 : if ((state.dataSwimmingPools->Pool(Item).PeopleSchedPtr == 0) && (!lAlphaBlanks(9))) {
383 0 : ShowSevereError(state, cAlphaFields(9) + " not found: " + Alphas(9));
384 0 : ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
385 0 : ErrorsFound = true;
386 : }
387 :
388 2 : state.dataSwimmingPools->Pool(Item).PeopleHeatGainSchedName = Alphas(10);
389 2 : state.dataSwimmingPools->Pool(Item).PeopleHeatGainSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(10));
390 2 : if ((state.dataSwimmingPools->Pool(Item).PeopleHeatGainSchedPtr == 0) && (!lAlphaBlanks(10))) {
391 0 : ShowSevereError(state, cAlphaFields(10) + " not found: " + Alphas(10));
392 0 : ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + Alphas(1));
393 0 : ErrorsFound = true;
394 : }
395 : }
396 :
397 770 : Alphas.deallocate();
398 770 : Numbers.deallocate();
399 770 : cAlphaFields.deallocate();
400 770 : cNumericFields.deallocate();
401 770 : lAlphaBlanks.deallocate();
402 770 : lNumericBlanks.deallocate();
403 :
404 770 : if (ErrorsFound) {
405 0 : ShowFatalError(state, std::string{RoutineName} + "Errors found in swimming pool input. Preceding conditions cause termination.");
406 : }
407 770 : }
408 :
409 2 : void SwimmingPoolData::ErrorCheckSetupPoolSurface(
410 : EnergyPlusData &state, std::string_view Alpha1, std::string_view Alpha2, std::string_view cAlphaField2, bool &ErrorsFound)
411 : {
412 :
413 : static constexpr std::string_view RoutineName("ErrorCheckSetupPoolSurface: "); // include trailing blank space
414 : static constexpr std::string_view CurrentModuleObject("SwimmingPool:Indoor");
415 :
416 2 : if (this->SurfacePtr <= 0) {
417 0 : ShowSevereError(state, std::string{RoutineName} + "Invalid " + std::string{cAlphaField2} + " = " + std::string{Alpha2});
418 0 : ShowContinueError(state, "Occurs in " + std::string{CurrentModuleObject} + " = " + std::string{Alpha1});
419 0 : ErrorsFound = true;
420 2 : } else if (state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(this->SurfacePtr)) {
421 0 : ShowSevereError(state, std::string{RoutineName} + std::string{CurrentModuleObject} + "=\"" + std::string{Alpha1} + "\", Invalid Surface");
422 0 : ShowContinueError(
423 0 : state, std::string{cAlphaField2} + "=\"" + std::string{Alpha2} + "\" has been used in another radiant system, ventilated slab, or pool.");
424 0 : ShowContinueError(state,
425 : "A single surface can only be a radiant system, a ventilated slab, or a pool. It CANNOT be more than one of these.");
426 0 : ErrorsFound = true;
427 : // Something present that is not allowed for a swimming pool (non-CTF algorithm, movable insulation, or radiant source/sink
428 2 : } else if (state.dataSurface->Surface(this->SurfacePtr).HeatTransferAlgorithm != DataSurfaces::HeatTransferModel::CTF) {
429 0 : ShowSevereError(state,
430 0 : state.dataSurface->Surface(this->SurfacePtr).Name +
431 : " is a pool and is attempting to use a non-CTF solution algorithm. This is "
432 : "not allowed. Use the CTF solution algorithm for this surface.");
433 0 : ErrorsFound = true;
434 :
435 2 : } else if (state.dataSurface->Surface(this->SurfacePtr).Class == DataSurfaces::SurfaceClass::Window) {
436 0 : ShowSevereError(state,
437 0 : state.dataSurface->Surface(this->SurfacePtr).Name +
438 : " is a pool and is defined as a window. This is not allowed. A pool must be a floor that is NOT a window.");
439 0 : ErrorsFound = true;
440 2 : } else if (state.dataSurface->SurfMaterialMovInsulInt(this->SurfacePtr) > 0) {
441 0 : ShowSevereError(state,
442 0 : state.dataSurface->Surface(this->SurfacePtr).Name +
443 : " is a pool and has movable insulation. This is not allowed. Remove the movable insulation for this surface.");
444 0 : ErrorsFound = true;
445 2 : } else if (state.dataConstruction->Construct(state.dataSurface->Surface(this->SurfacePtr).Construction).SourceSinkPresent) {
446 0 : ShowSevereError(
447 : state,
448 0 : state.dataSurface->Surface(this->SurfacePtr).Name +
449 : " is a pool and uses a construction with a source/sink. This is not allowed. Use a standard construction for this surface.");
450 0 : ErrorsFound = true;
451 : } else { // ( Pool( Item ).SurfacePtr > 0 )
452 2 : state.dataSurface->SurfIsRadSurfOrVentSlabOrPool(this->SurfacePtr) = true;
453 2 : state.dataSurface->SurfIsPool(this->SurfacePtr) = true;
454 2 : this->ZonePtr = state.dataSurface->Surface(this->SurfacePtr).Zone;
455 : // Check to make sure pool surface is a floor
456 2 : if (state.dataSurface->Surface(this->SurfacePtr).Class != DataSurfaces::SurfaceClass::Floor) {
457 0 : ShowSevereError(state,
458 0 : std::string{RoutineName} + std::string{CurrentModuleObject} + "=\"" + std::string{Alpha1} +
459 : " contains a surface name that is NOT a floor.");
460 0 : ShowContinueError(
461 : state, "A swimming pool must be associated with a surface that is a FLOOR. Association with other surface types is not permitted.");
462 0 : ErrorsFound = true;
463 : }
464 : }
465 2 : }
466 :
467 5538 : void SwimmingPoolData::initialize(EnergyPlusData &state, bool const FirstHVACIteration // true during the first HVAC iteration
468 : )
469 : {
470 : // SUBROUTINE INFORMATION:
471 : // AUTHOR Rick Strand, Ho-Sung Kim
472 : // DATE WRITTEN October 2014
473 :
474 : // PURPOSE OF THIS SUBROUTINE:
475 : // This subroutine initializes variables relating to indoor swimming pools.
476 :
477 : // SUBROUTINE PARAMETER DEFINITIONS:
478 : static constexpr std::string_view RoutineName("InitSwimmingPool");
479 5538 : Real64 constexpr MinActivityFactor = 0.0; // Minimum value for activity factor
480 5538 : Real64 constexpr MaxActivityFactor = 10.0; // Maximum value for activity factor (realistically)
481 :
482 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
483 5538 : Real64 HeatGainPerPerson = ScheduleManager::GetCurrentScheduleValue(state, this->PeopleHeatGainSchedPtr);
484 5538 : Real64 PeopleModifier = ScheduleManager::GetCurrentScheduleValue(state, this->PeopleSchedPtr);
485 :
486 5538 : if (this->MyOneTimeFlag) {
487 2 : this->setupOutputVars(state); // Set up the output variables once here
488 2 : this->ZeroSourceSumHATsurf.allocate(state.dataGlobal->NumOfZones);
489 2 : this->ZeroSourceSumHATsurf = 0.0;
490 2 : this->QPoolSrcAvg.allocate(state.dataSurface->TotSurfaces);
491 2 : this->QPoolSrcAvg = 0.0;
492 2 : this->HeatTransCoefsAvg.allocate(state.dataSurface->TotSurfaces);
493 2 : this->HeatTransCoefsAvg = 0.0;
494 2 : this->LastQPoolSrc.allocate(state.dataSurface->TotSurfaces);
495 2 : this->LastQPoolSrc = 0.0;
496 2 : this->LastHeatTransCoefs.allocate(state.dataSurface->TotSurfaces);
497 2 : this->LastHeatTransCoefs = 0.0;
498 2 : this->LastSysTimeElapsed.allocate(state.dataSurface->TotSurfaces);
499 2 : this->LastSysTimeElapsed = 0.0;
500 2 : this->LastTimeStepSys.allocate(state.dataSurface->TotSurfaces);
501 2 : this->LastTimeStepSys = 0.0;
502 2 : this->MyOneTimeFlag = false;
503 : }
504 :
505 5538 : SwimmingPoolData::initSwimmingPoolPlantLoopIndex(state);
506 :
507 5538 : if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlagGeneral) {
508 10 : this->ZeroSourceSumHATsurf = 0.0;
509 10 : this->QPoolSrcAvg = 0.0;
510 10 : this->HeatTransCoefsAvg = 0.0;
511 10 : this->LastQPoolSrc = 0.0;
512 10 : this->LastHeatTransCoefs = 0.0;
513 10 : this->LastSysTimeElapsed = 0.0;
514 10 : this->LastTimeStepSys = 0.0;
515 10 : this->MyEnvrnFlagGeneral = false;
516 : }
517 :
518 5538 : if (!state.dataGlobal->BeginEnvrnFlag) this->MyEnvrnFlagGeneral = true;
519 :
520 5538 : if (state.dataGlobal->BeginEnvrnFlag) {
521 32 : this->PoolWaterTemp = 23.0;
522 32 : this->HeatPower = 0.0;
523 32 : this->HeatEnergy = 0.0;
524 32 : this->MiscEquipPower = 0.0;
525 32 : this->MiscEquipEnergy = 0.0;
526 32 : this->WaterInletTemp = 0.0;
527 32 : this->WaterOutletTemp = 0.0;
528 32 : this->WaterMassFlowRate = 0.0;
529 32 : this->PeopleHeatGain = 0.0;
530 32 : Real64 Density = FluidProperties::GetDensityGlycol(state, "WATER", this->PoolWaterTemp, this->GlycolIndex, RoutineName);
531 32 : this->WaterMass = state.dataSurface->Surface(this->SurfacePtr).Area * this->AvgDepth * Density;
532 32 : this->WaterMassFlowRateMax = this->WaterVolFlowMax * Density;
533 32 : this->initSwimmingPoolPlantNodeFlow(state);
534 : }
535 :
536 5538 : if (state.dataGlobal->BeginTimeStepFlag && FirstHVACIteration) { // This is the first pass through in a particular time step
537 :
538 2706 : int ZoneNum = this->ZonePtr;
539 2706 : this->ZeroSourceSumHATsurf(ZoneNum) =
540 2706 : state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state); // Set this to figure what part of the load the radiant system meets
541 2706 : int SurfNum = this->SurfacePtr;
542 2706 : this->QPoolSrcAvg(SurfNum) = 0.0; // Initialize this variable to zero (pool parameters "off")
543 2706 : this->HeatTransCoefsAvg(SurfNum) = 0.0; // Initialize this variable to zero (pool parameters "off")
544 2706 : this->LastQPoolSrc(SurfNum) = 0.0; // At the start of a time step, reset to zero so average calculation can begin again
545 2706 : this->LastSysTimeElapsed(SurfNum) = 0.0; // At the start of a time step, reset to zero so average calculation can begin again
546 2706 : this->LastTimeStepSys(SurfNum) = 0.0; // At the start of a time step, reset to zero so average calculation can begin again
547 : }
548 :
549 : // initialize the flow rate for the component on the plant side (this follows standard procedure for other components like low temperature
550 : // radiant systems)
551 5538 : Real64 mdot = 0.0;
552 5538 : PlantUtilities::SetComponentFlowRate(state, mdot, this->WaterInletNode, this->WaterOutletNode, this->HWplantLoc);
553 5538 : this->WaterInletTemp = state.dataLoopNodes->Node(this->WaterInletNode).Temp;
554 :
555 : // get the schedule values for different scheduled parameters
556 5538 : if (this->ActivityFactorSchedPtr > 0) {
557 5538 : this->CurActivityFactor = ScheduleManager::GetCurrentScheduleValue(state, this->ActivityFactorSchedPtr);
558 5538 : if (this->CurActivityFactor < MinActivityFactor) {
559 0 : this->CurActivityFactor = MinActivityFactor;
560 0 : ShowWarningError(state,
561 0 : std::string{RoutineName} + ": Swimming Pool =\"" + this->Name + " Activity Factor Schedule =\"" +
562 0 : this->ActivityFactorSchedName + " has a negative value. This is not allowed.");
563 0 : ShowContinueError(state, "The activity factor has been reset to zero.");
564 : }
565 5538 : if (this->CurActivityFactor > MaxActivityFactor) {
566 0 : this->CurActivityFactor = 1.0;
567 0 : ShowWarningError(state,
568 0 : std::string{RoutineName} + ": Swimming Pool =\"" + this->Name + " Activity Factor Schedule =\"" +
569 0 : this->ActivityFactorSchedName + " has a value larger than 10. This is not allowed.");
570 0 : ShowContinueError(state, "The activity factor has been reset to unity.");
571 : }
572 : } else {
573 : // default is activity factor of 1.0
574 0 : this->CurActivityFactor = 1.0;
575 : }
576 :
577 5538 : this->CurSetPtTemp = ScheduleManager::GetCurrentScheduleValue(state, this->SetPtTempSchedPtr);
578 :
579 5538 : if (this->MakeupWaterSupplySchedPtr > 0) {
580 5538 : this->CurMakeupWaterTemp = ScheduleManager::GetCurrentScheduleValue(state, this->MakeupWaterSupplySchedPtr);
581 : } else {
582 : // use water main temperaure if no schedule present in input
583 0 : this->CurMakeupWaterTemp = state.dataEnvrn->WaterMainsTemp;
584 : }
585 :
586 : // determine the current heat gain from people
587 5538 : if (this->PeopleHeatGainSchedPtr > 0) {
588 5538 : if (HeatGainPerPerson < 0.0) {
589 0 : ShowWarningError(state,
590 0 : std::string{RoutineName} + ": Swimming Pool =\"" + this->Name + " Heat Gain Schedule =\"" +
591 0 : this->PeopleHeatGainSchedName + " has a negative value. This is not allowed.");
592 0 : ShowContinueError(state, "The heat gain per person has been reset to zero.");
593 0 : HeatGainPerPerson = 0.0;
594 : }
595 5538 : if (this->PeopleSchedPtr > 0) {
596 5538 : if (PeopleModifier < 0.0) {
597 0 : ShowWarningError(state,
598 0 : std::string{RoutineName} + ": Swimming Pool =\"" + this->Name + " People Schedule =\"" + this->PeopleSchedName +
599 : " has a negative value. This is not allowed.");
600 0 : ShowContinueError(state, "The number of people has been reset to zero.");
601 0 : PeopleModifier = 0.0;
602 : }
603 : } else { // no people schedule entered--assume that full number always present
604 0 : PeopleModifier = 1.0;
605 : }
606 : } else { // no heat gain schedule added--assume a zero value for Heat Gain per Person and no people present
607 0 : HeatGainPerPerson = 0.0;
608 0 : PeopleModifier = 0.0;
609 : }
610 5538 : this->PeopleHeatGain = PeopleModifier * HeatGainPerPerson * this->MaxNumOfPeople;
611 :
612 : // once cover schedule value is established, define the current values of the cover heat transfer factors
613 5538 : if (this->CoverSchedPtr > 0) {
614 5538 : this->CurCoverSchedVal = ScheduleManager::GetCurrentScheduleValue(state, this->CoverSchedPtr);
615 5538 : if (this->CurCoverSchedVal > 1.0) {
616 0 : ShowWarningError(state,
617 0 : std::string{RoutineName} + ": Swimming Pool =\"" + this->Name + " Cover Schedule =\"" + this->CoverSchedName +
618 : " has a value greater than 1.0 (100%). This is not allowed.");
619 0 : ShowContinueError(state, "The cover has been reset to one or fully covered.");
620 0 : this->CurCoverSchedVal = 1.0;
621 5538 : } else if (this->CurCoverSchedVal < 0.0) {
622 0 : ShowWarningError(state,
623 0 : std::string{RoutineName} + ": Swimming Pool =\"" + this->Name + " Cover Schedule =\"" + this->CoverSchedName +
624 : " has a negative value. This is not allowed.");
625 0 : ShowContinueError(state, "The cover has been reset to zero or uncovered.");
626 0 : this->CurCoverSchedVal = 0.0;
627 : }
628 : } else {
629 : // default is NO pool cover
630 0 : this->CurCoverSchedVal = 0.0;
631 : }
632 : // for the current cover factors, a value of 1.0 means that the pool is open (not covered)
633 : // the user input values determine the amount the pool cover degrades one of the factors
634 : // for example, if the cover reduces convection by 50% and the pool is half covered, then
635 : // the reduction factor for convection is 25% or 75% of the normal value. this establishes
636 : // the following relationships and how they are used in other parts of the code.
637 : // note that for the radiation factors, the reduction in absorption of radiation caused by
638 : // the cover will result in a net imbalance if this energy which is no longer accounted for
639 : // in the surface heat balance is not accounted for elsewhere. thus, these terms will dump
640 : // any reduced radiation into the air heat balance as an additional convective gain to avoid
641 : // any loss of energy in the overall heat balance.
642 5538 : this->CurCoverEvapFac = 1.0 - (this->CurCoverSchedVal * this->CoverEvapFactor);
643 5538 : this->CurCoverConvFac = 1.0 - (this->CurCoverSchedVal * this->CoverConvFactor);
644 5538 : this->CurCoverSWRadFac = 1.0 - (this->CurCoverSchedVal * this->CoverSWRadFactor);
645 5538 : this->CurCoverLWRadFac = 1.0 - (this->CurCoverSchedVal * this->CoverLWRadFactor);
646 5538 : }
647 :
648 2 : void SwimmingPoolData::setupOutputVars(EnergyPlusData &state)
649 : {
650 4 : SetupOutputVariable(state,
651 : "Indoor Pool Makeup Water Rate",
652 : OutputProcessor::Unit::m3_s,
653 : this->MakeUpWaterVolFlowRate,
654 : OutputProcessor::SOVTimeStepType::System,
655 : OutputProcessor::SOVStoreType::Average,
656 2 : this->Name);
657 4 : SetupOutputVariable(state,
658 : "Indoor Pool Makeup Water Volume",
659 : OutputProcessor::Unit::m3,
660 : this->MakeUpWaterVol,
661 : OutputProcessor::SOVTimeStepType::System,
662 : OutputProcessor::SOVStoreType::Summed,
663 : this->Name,
664 : _,
665 : "MainsWater",
666 : "Heating",
667 : _,
668 2 : "System");
669 4 : SetupOutputVariable(state,
670 : "Indoor Pool Makeup Water Temperature",
671 : OutputProcessor::Unit::C,
672 : this->CurMakeupWaterTemp,
673 : OutputProcessor::SOVTimeStepType::System,
674 : OutputProcessor::SOVStoreType::Average,
675 2 : this->Name);
676 4 : SetupOutputVariable(state,
677 : "Indoor Pool Water Temperature",
678 : OutputProcessor::Unit::C,
679 : this->PoolWaterTemp,
680 : OutputProcessor::SOVTimeStepType::System,
681 : OutputProcessor::SOVStoreType::Average,
682 2 : this->Name);
683 4 : SetupOutputVariable(state,
684 : "Indoor Pool Inlet Water Temperature",
685 : OutputProcessor::Unit::C,
686 : this->WaterInletTemp,
687 : OutputProcessor::SOVTimeStepType::System,
688 : OutputProcessor::SOVStoreType::Average,
689 2 : this->Name);
690 4 : SetupOutputVariable(state,
691 : "Indoor Pool Inlet Water Mass Flow Rate",
692 : OutputProcessor::Unit::kg_s,
693 : this->WaterMassFlowRate,
694 : OutputProcessor::SOVTimeStepType::System,
695 : OutputProcessor::SOVStoreType::Average,
696 2 : this->Name);
697 4 : SetupOutputVariable(state,
698 : "Indoor Pool Miscellaneous Equipment Power",
699 : OutputProcessor::Unit::W,
700 : this->MiscEquipPower,
701 : OutputProcessor::SOVTimeStepType::System,
702 : OutputProcessor::SOVStoreType::Average,
703 2 : this->Name);
704 4 : SetupOutputVariable(state,
705 : "Indoor Pool Miscellaneous Equipment Energy",
706 : OutputProcessor::Unit::J,
707 : this->MiscEquipEnergy,
708 : OutputProcessor::SOVTimeStepType::System,
709 : OutputProcessor::SOVStoreType::Summed,
710 2 : this->Name);
711 4 : SetupOutputVariable(state,
712 : "Indoor Pool Water Heating Rate",
713 : OutputProcessor::Unit::W,
714 : this->HeatPower,
715 : OutputProcessor::SOVTimeStepType::System,
716 : OutputProcessor::SOVStoreType::Average,
717 2 : this->Name);
718 4 : SetupOutputVariable(state,
719 : "Indoor Pool Water Heating Energy",
720 : OutputProcessor::Unit::J,
721 : this->HeatEnergy,
722 : OutputProcessor::SOVTimeStepType::System,
723 : OutputProcessor::SOVStoreType::Summed,
724 : this->Name,
725 : _,
726 : "ENERGYTRANSFER",
727 : "HEATINGCOILS",
728 : _,
729 2 : "System");
730 4 : SetupOutputVariable(state,
731 : "Indoor Pool Radiant to Convection by Cover",
732 : OutputProcessor::Unit::W,
733 : this->RadConvertToConvect,
734 : OutputProcessor::SOVTimeStepType::System,
735 : OutputProcessor::SOVStoreType::Average,
736 2 : this->Name);
737 4 : SetupOutputVariable(state,
738 : "Indoor Pool People Heat Gain",
739 : OutputProcessor::Unit::W,
740 : this->PeopleHeatGain,
741 : OutputProcessor::SOVTimeStepType::System,
742 : OutputProcessor::SOVStoreType::Average,
743 2 : this->Name);
744 4 : SetupOutputVariable(state,
745 : "Indoor Pool Current Activity Factor",
746 : OutputProcessor::Unit::None,
747 : this->CurActivityFactor,
748 : OutputProcessor::SOVTimeStepType::System,
749 : OutputProcessor::SOVStoreType::Average,
750 2 : this->Name);
751 4 : SetupOutputVariable(state,
752 : "Indoor Pool Current Cover Factor",
753 : OutputProcessor::Unit::None,
754 : this->CurCoverSchedVal,
755 : OutputProcessor::SOVTimeStepType::System,
756 : OutputProcessor::SOVStoreType::Average,
757 2 : this->Name);
758 4 : SetupOutputVariable(state,
759 : "Indoor Pool Evaporative Heat Loss Rate",
760 : OutputProcessor::Unit::W,
761 : this->EvapHeatLossRate,
762 : OutputProcessor::SOVTimeStepType::System,
763 : OutputProcessor::SOVStoreType::Average,
764 2 : this->Name);
765 4 : SetupOutputVariable(state,
766 : "Indoor Pool Evaporative Heat Loss Energy",
767 : OutputProcessor::Unit::J,
768 : this->EvapEnergyLoss,
769 : OutputProcessor::SOVTimeStepType::System,
770 : OutputProcessor::SOVStoreType::Summed,
771 2 : this->Name);
772 4 : SetupOutputVariable(state,
773 : "Indoor Pool Saturation Pressure at Pool Temperature",
774 : OutputProcessor::Unit::Pa,
775 : this->SatPressPoolWaterTemp,
776 : OutputProcessor::SOVTimeStepType::System,
777 : OutputProcessor::SOVStoreType::Average,
778 2 : this->Name);
779 4 : SetupOutputVariable(state,
780 : "Indoor Pool Partial Pressure of Water Vapor in Air",
781 : OutputProcessor::Unit::Pa,
782 : this->PartPressZoneAirTemp,
783 : OutputProcessor::SOVTimeStepType::System,
784 : OutputProcessor::SOVStoreType::Average,
785 2 : this->Name);
786 4 : SetupOutputVariable(state,
787 : "Indoor Pool Current Cover Evaporation Factor",
788 : OutputProcessor::Unit::None,
789 : this->CurCoverEvapFac,
790 : OutputProcessor::SOVTimeStepType::System,
791 : OutputProcessor::SOVStoreType::Average,
792 2 : this->Name);
793 4 : SetupOutputVariable(state,
794 : "Indoor Pool Current Cover Convective Factor",
795 : OutputProcessor::Unit::None,
796 : this->CurCoverConvFac,
797 : OutputProcessor::SOVTimeStepType::System,
798 : OutputProcessor::SOVStoreType::Average,
799 2 : this->Name);
800 4 : SetupOutputVariable(state,
801 : "Indoor Pool Current Cover SW Radiation Factor",
802 : OutputProcessor::Unit::None,
803 : this->CurCoverSWRadFac,
804 : OutputProcessor::SOVTimeStepType::System,
805 : OutputProcessor::SOVStoreType::Average,
806 2 : this->Name);
807 4 : SetupOutputVariable(state,
808 : "Indoor Pool Current Cover LW Radiation Factor",
809 : OutputProcessor::Unit::None,
810 : this->CurCoverLWRadFac,
811 : OutputProcessor::SOVTimeStepType::System,
812 : OutputProcessor::SOVStoreType::Average,
813 2 : this->Name);
814 2 : }
815 :
816 5538 : void SwimmingPoolData::initSwimmingPoolPlantLoopIndex(EnergyPlusData &state)
817 : {
818 : // SUBROUTINE INFORMATION:
819 : // AUTHOR Rick Strand
820 : // DATE WRITTEN June 2017
821 :
822 : static constexpr std::string_view RoutineName("InitSwimmingPoolPlantLoopIndex");
823 :
824 5538 : if (this->MyPlantScanFlagPool && allocated(state.dataPlnt->PlantLoop)) {
825 2 : bool errFlag = false;
826 2 : if (this->WaterInletNode > 0) {
827 2 : PlantUtilities::ScanPlantLoopsForObject(
828 : state, this->Name, DataPlant::PlantEquipmentType::SwimmingPool_Indoor, this->HWplantLoc, errFlag, _, _, _, this->WaterInletNode, _);
829 2 : if (errFlag) {
830 0 : ShowFatalError(state, std::string{RoutineName} + ": Program terminated due to previous condition(s).");
831 : }
832 : }
833 2 : this->MyPlantScanFlagPool = false;
834 5536 : } else if (this->MyPlantScanFlagPool && !state.dataGlobal->AnyPlantInModel) {
835 0 : this->MyPlantScanFlagPool = false;
836 : }
837 5538 : }
838 :
839 32 : void SwimmingPoolData::initSwimmingPoolPlantNodeFlow(EnergyPlusData &state) const
840 : {
841 :
842 32 : if (!this->MyPlantScanFlagPool) {
843 32 : if (this->WaterInletNode > 0) {
844 32 : PlantUtilities::InitComponentNodes(state, 0.0, this->WaterMassFlowRateMax, this->WaterInletNode, this->WaterOutletNode);
845 32 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->WaterInletNode, this->WaterVolFlowMax);
846 : }
847 : }
848 32 : }
849 :
850 5538 : void SwimmingPoolData::calculate(EnergyPlusData &state)
851 : {
852 : // SUBROUTINE INFORMATION:
853 : // AUTHOR Rick Strand, Ho-Sung Kim
854 : // DATE WRITTEN October 2014
855 :
856 : // PURPOSE OF THIS SUBROUTINE:
857 : // This subroutine simulates the components making up the Indoor Swimming Pool model.
858 :
859 : // METHODOLOGY EMPLOYED:
860 : // The swimming pool is modeled as a SURFACE to get access to all of the existing
861 : // surface related algorithms. This subroutine mainly models the components of the
862 : // swimming pool so that information can be used in a standard surface heat balance.
863 : // The pool is assumed to be located at the inside surface face with a possible cover
864 : // affecting the heat balance. The pool model takes the form of an equation solving
865 : // for the inside surface temperature which is assumed to be the same as the pool
866 : // water temperature.
867 : // Standard Heat Balance Equation:
868 : // SurfTempInTmp( SurfNum ) = ( SurfCTFConstInPart( SurfNum ) + SurfQRadThermInAbs( SurfNum ) + SurfOpaqQRadSWInAbs( SurfNum ) + HConvIn(
869 : // SurfNum
870 : //)
871 : //* RefAirTemp( SurfNum ) + SurfNetLWRadToSurf( SurfNum ) + Construct( ConstrNum ).CTFSourceIn( 0 ) * SurfQsrcHist( 1, SurfNum ) +
872 : // SurfQdotRadHVACInPerArea( SurfNum ) + IterDampConst * SurfTempInsOld(
873 : // SurfNum ) + Construct( ConstrNum ).CTFCross( 0 ) * TH11 ) / ( Construct( ConstrNum ).CTFInside( 0 ) + HConvIn( SurfNum ) + IterDampConst );
874 : //// Constant part of conduction eq (history terms) | LW radiation from internal sources | SW radiation from internal sources | Convection
875 : // from surface to zone air | Net radiant exchange with other zone surfaces | Heat source/sink term for radiant systems | (if there is one
876 : // present) | Radiant flux from high temp radiant heater | Radiant flux from a hot water baseboard heater | Radiant flux from a steam
877 : // baseboard heater | Radiant flux from an electric baseboard heater | Iterative damping term (for stability) | Current conduction from | the
878 : // outside surface | Coefficient for conduction (current time) | Convection and damping term
879 : // That equation is modified to include pool specific terms and removes the IterDampConst
880 : // term which is for iterations within the inside surface heat balance. Then, the resulting
881 : // equation is solved for the plant loop mass flow rate. It also assigns the appropriate
882 : // terms for use in the actual heat balance routine.
883 :
884 : // REFERENCES:
885 : // 1. ASHRAE (2011). 2011 ASHRAE Handbook - HVAC Applications. Atlanta: American Society of Heating,
886 : // Refrigerating and Air-Conditioning Engineers, Inc., p.5.6-5.9.
887 : // 2. Janis, R. and W. Tao (2005). Mechanical and Electrical Systems in Buildings. 3rd ed. Upper
888 : // Saddle River, NJ: Pearson Education, Inc., p.246.
889 : // 3. Kittler, R. (1989). Indoor Natatorium Design and Energy Recycling. ASHRAE Transactions 95(1), p.521-526.
890 : // 4. Smith, C., R. Jones, and G. Lof (1993). Energy Requirements and Potential Savings for Heated
891 : // Indoor Swimming Pools. ASHRAE Transactions 99(2), p.864-874.
892 :
893 : // SUBROUTINE PARAMETER DEFINITIONS:
894 : static constexpr std::string_view RoutineName("CalcSwimmingPool");
895 :
896 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
897 5538 : Real64 EvapRate = 0.0; // evaporation rate for pool in kg/s
898 :
899 : // initialize local variables
900 5538 : int SurfNum = this->SurfacePtr; // surface number of floor that is the pool
901 5538 : int ZoneNum = state.dataSurface->Surface(SurfNum).Zone; // index to zone array
902 5538 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
903 :
904 : // Convection coefficient calculation
905 : Real64 HConvIn =
906 5538 : 0.22 * std::pow(std::abs(this->PoolWaterTemp - thisZoneHB.MAT), 1.0 / 3.0) * this->CurCoverConvFac; // convection coefficient for pool
907 5538 : calcSwimmingPoolEvap(state, EvapRate, SurfNum, thisZoneHB.MAT, thisZoneHB.ZoneAirHumRat);
908 5538 : this->MakeUpWaterMassFlowRate = EvapRate;
909 11076 : Real64 EvapEnergyLossPerArea = -EvapRate *
910 5538 : Psychrometrics::PsyHfgAirFnWTdb(thisZoneHB.ZoneAirHumRat,
911 : thisZoneHB.MAT) /
912 5538 : state.dataSurface->Surface(SurfNum).Area; // energy effect of evaporation rate per unit area in W/m2
913 5538 : this->EvapHeatLossRate = EvapEnergyLossPerArea * state.dataSurface->Surface(SurfNum).Area;
914 : // LW and SW radiation term modification: any "excess" radiation blocked by the cover gets convected
915 : // to the air directly and added to the zone air heat balance
916 5538 : Real64 LWsum = (state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNum) + state.dataHeatBalSurf->SurfQdotRadNetLWInPerArea(SurfNum) +
917 5538 : state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNum)); // summation of all long-wavelenth radiation going to surface
918 5538 : Real64 LWtotal = this->CurCoverLWRadFac * LWsum; // total flux from long-wavelength radiation to surface
919 : Real64 SWtotal =
920 5538 : this->CurCoverSWRadFac * state.dataHeatBalSurf->SurfOpaqQRadSWInAbs(SurfNum); // total flux from short-wavelength radiation to surface
921 5538 : this->RadConvertToConvect =
922 5538 : ((1.0 - this->CurCoverLWRadFac) * LWsum) + ((1.0 - this->CurCoverSWRadFac) * state.dataHeatBalSurf->SurfOpaqQRadSWInAbs(SurfNum));
923 :
924 : // Heat gain from people (assumed to be all convective to pool water)
925 : Real64 PeopleGain =
926 5538 : this->PeopleHeatGain / state.dataSurface->Surface(SurfNum).Area; // heat gain from people in pool (assumed to be all convective)
927 :
928 : // Get an estimate of the pool water specific heat
929 : Real64 Cp =
930 5538 : FluidProperties::GetSpecificHeatGlycol(state, "WATER", this->PoolWaterTemp, this->GlycolIndex, RoutineName); // specific heat of pool water
931 :
932 5538 : Real64 TH22 = state.dataHeatBalSurf->SurfInsideTempHist(2)(
933 5538 : SurfNum); // inside surface temperature at the previous time step equals the old pool water temperature
934 5538 : Real64 TInSurf =
935 : this->CurSetPtTemp; // Setpoint temperature for pool which is also the goal temperature and also the inside surface face temperature
936 5538 : Real64 Tmuw = this->CurMakeupWaterTemp; // Inlet makeup water temperature
937 5538 : Real64 TLoopInletTemp = state.dataLoopNodes->Node(this->WaterInletNode).Temp; // Inlet water temperature from the plant loop
938 5538 : this->WaterInletTemp = TLoopInletTemp;
939 :
940 : // Now calculate the requested mass flow rate from the plant loop to achieve the proper pool temperature
941 : // old equation using surface heat balance form: MassFlowRate = CpDeltaTi * ( CondTerms + ConvTerm + SWtotal + LWtotal + PeopleGain +
942 : // PoolMassTerm + MUWTerm + EvapEnergyLossPerArea );
943 11076 : Real64 MassFlowRate = (this->WaterMass / (state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour)) *
944 11076 : ((TInSurf - TH22) / (TLoopInletTemp - TInSurf)); // Target mass flow rate to achieve the proper setpoint temperature
945 5538 : if (MassFlowRate > this->WaterMassFlowRateMax) {
946 0 : MassFlowRate = this->WaterMassFlowRateMax;
947 5538 : } else if (MassFlowRate < 0.0) {
948 2 : MassFlowRate = 0.0;
949 : }
950 5538 : PlantUtilities::SetComponentFlowRate(state, MassFlowRate, this->WaterInletNode, this->WaterOutletNode, this->HWplantLoc);
951 5538 : this->WaterMassFlowRate = MassFlowRate;
952 :
953 : // We now have a flow rate so we can assemble the terms needed for the surface heat balance that is solved for the inside face temperature
954 5538 : state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum) =
955 11076 : SWtotal + LWtotal + PeopleGain + EvapEnergyLossPerArea + HConvIn * thisZoneHB.MAT +
956 11076 : (EvapRate * Tmuw + MassFlowRate * TLoopInletTemp + (this->WaterMass * TH22 / state.dataGlobal->TimeStepZoneSec)) * Cp /
957 5538 : state.dataSurface->Surface(SurfNum).Area;
958 5538 : state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum) =
959 5538 : HConvIn + (EvapRate + MassFlowRate + (this->WaterMass / state.dataGlobal->TimeStepZoneSec)) * Cp / state.dataSurface->Surface(SurfNum).Area;
960 :
961 : // Finally take care of the latent and convective gains resulting from the pool
962 5538 : state.dataHeatBalFanSys->SumConvPool(ZoneNum) += this->RadConvertToConvect;
963 5538 : state.dataHeatBalFanSys->SumLatentPool(ZoneNum) += EvapRate * Psychrometrics::PsyHfgAirFnWTdb(thisZoneHB.ZoneAirHumRat, thisZoneHB.MAT);
964 5538 : }
965 :
966 5538 : void SwimmingPoolData::calcSwimmingPoolEvap(EnergyPlusData &state,
967 : Real64 &EvapRate, // evaporation rate of pool
968 : int const SurfNum, // surface index
969 : Real64 const MAT, // mean air temperature
970 : Real64 const HumRat // zone air humidity ratio
971 : )
972 : {
973 : static constexpr std::string_view RoutineName("CalcSwimmingPoolEvap");
974 5538 : Real64 constexpr CFinHg(0.00029613); // Multiple pressure in Pa by this constant to get inches of Hg
975 :
976 : // Evaporation calculation:
977 : // Evaporation Rate (lb/h) = 0.1 * Area (ft2) * Activity Factor * (Psat,pool - Ppar,air) (in Hg)
978 : // So evaporation rate, area, and pressures have to be converted to standard E+ units (kg/s, m2, and Pa, respectively)
979 : // Evaporation Rate per Area = Evaporation Rate * Heat of Vaporization / Area of Surface
980 :
981 5538 : Real64 PSatPool = Psychrometrics::PsyPsatFnTemp(state, this->PoolWaterTemp, RoutineName);
982 : Real64 PParAir =
983 5538 : Psychrometrics::PsyPsatFnTemp(state, MAT, RoutineName) * Psychrometrics::PsyRhFnTdbWPb(state, MAT, HumRat, state.dataEnvrn->OutBaroPress);
984 5538 : if (PSatPool < PParAir) PSatPool = PParAir;
985 5538 : this->SatPressPoolWaterTemp = PSatPool;
986 5538 : this->PartPressZoneAirTemp = PParAir;
987 11076 : EvapRate = (0.1 * (state.dataSurface->Surface(SurfNum).Area / DataConversions::CFA) * this->CurActivityFactor * ((PSatPool - PParAir) * CFinHg)) *
988 5538 : DataConversions::CFMF * this->CurCoverEvapFac;
989 5538 : }
990 :
991 5538 : void SwimmingPoolData::update(EnergyPlusData &state)
992 : {
993 : // SUBROUTINE INFORMATION:
994 : // AUTHOR Rick Strand, Ho-Sung Kim
995 : // DATE WRITTEN October 2014
996 :
997 : // PURPOSE OF THIS SUBROUTINE:
998 : // This subroutine does any updating that needs to be done for the swimming pool model.
999 :
1000 5538 : int SurfNum = this->SurfacePtr; // surface number/pointer
1001 :
1002 5538 : if (this->LastSysTimeElapsed(SurfNum) == state.dataHVACGlobal->SysTimeElapsed) {
1003 : // Still iterating or reducing system time step, so subtract old values which were
1004 : // not valid
1005 5534 : this->QPoolSrcAvg(SurfNum) -= this->LastQPoolSrc(SurfNum) * this->LastTimeStepSys(SurfNum) / state.dataGlobal->TimeStepZone;
1006 5534 : this->HeatTransCoefsAvg(SurfNum) -= this->LastHeatTransCoefs(SurfNum) * this->LastTimeStepSys(SurfNum) / state.dataGlobal->TimeStepZone;
1007 : }
1008 :
1009 : // Update the running average and the "last" values with the current values of the appropriate variables
1010 5538 : this->QPoolSrcAvg(SurfNum) +=
1011 5538 : state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum) * state.dataHVACGlobal->TimeStepSys / state.dataGlobal->TimeStepZone;
1012 5538 : this->HeatTransCoefsAvg(SurfNum) +=
1013 5538 : state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum) * state.dataHVACGlobal->TimeStepSys / state.dataGlobal->TimeStepZone;
1014 :
1015 5538 : this->LastQPoolSrc(SurfNum) = state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum);
1016 5538 : this->LastHeatTransCoefs(SurfNum) = state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum);
1017 5538 : this->LastSysTimeElapsed(SurfNum) = state.dataHVACGlobal->SysTimeElapsed;
1018 5538 : this->LastTimeStepSys(SurfNum) = state.dataHVACGlobal->TimeStepSys;
1019 :
1020 5538 : PlantUtilities::SafeCopyPlantNode(state, this->WaterInletNode, this->WaterOutletNode);
1021 :
1022 5538 : Real64 WaterMassFlow = state.dataLoopNodes->Node(this->WaterInletNode).MassFlowRate; // water mass flow rate
1023 5538 : if (WaterMassFlow > 0.0) state.dataLoopNodes->Node(this->WaterOutletNode).Temp = this->PoolWaterTemp;
1024 5538 : }
1025 0 : void SwimmingPoolData::oneTimeInit_new([[maybe_unused]] EnergyPlusData &state)
1026 : {
1027 0 : }
1028 0 : void SwimmingPoolData::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
1029 : {
1030 0 : }
1031 :
1032 2568313 : void UpdatePoolSourceValAvg(EnergyPlusData &state, bool &SwimmingPoolOn) // .TRUE. if the swimming pool "runs" this zone time step
1033 : {
1034 : // SUBROUTINE INFORMATION:
1035 : // AUTHOR Rick Strand
1036 : // DATE WRITTEN October 2014
1037 :
1038 : // PURPOSE OF THIS SUBROUTINE:
1039 : // To transfer the average value of the pool heat balance term over the entire zone time step back to the heat balance routines so that the
1040 : // heat balance algorithms can simulate one last time with the average source to maintain some reasonable amount of continuity and energy
1041 : // balance in the temperature and flux histories.
1042 :
1043 : // METHODOLOGY EMPLOYED:
1044 : // All of the record keeping for the average term is done in the Update routine so the only other thing that this subroutine does is check to
1045 : // see if the system was even on. If any average term is non-zero, then one or more of the swimming pools was running. Method borrowed from
1046 : // radiant systems.
1047 :
1048 : // SUBROUTINE PARAMETER DEFINITIONS:
1049 2568313 : Real64 constexpr CloseEnough(0.01); // Some arbitrarily small value to avoid zeros and numbers that are almost the same
1050 :
1051 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1052 2568313 : SwimmingPoolOn = false;
1053 :
1054 : // If this was never allocated, then there are no radiant systems in this input file (just RETURN)
1055 2571019 : for (int PoolNum = 1; PoolNum <= state.dataSwimmingPools->NumSwimmingPools; ++PoolNum) {
1056 2706 : if (!allocated(state.dataSwimmingPools->Pool(PoolNum).QPoolSrcAvg)) return;
1057 :
1058 : // If it was allocated, then we have to check to see if this was running at all
1059 51414 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1060 51414 : if (state.dataSwimmingPools->Pool(PoolNum).QPoolSrcAvg(SurfNum) != 0.0) {
1061 2706 : SwimmingPoolOn = true;
1062 2706 : break; // DO loop
1063 : }
1064 : }
1065 :
1066 2706 : state.dataHeatBalFanSys->QPoolSurfNumerator = state.dataSwimmingPools->Pool(PoolNum).QPoolSrcAvg;
1067 2706 : state.dataHeatBalFanSys->PoolHeatTransCoefs = state.dataSwimmingPools->Pool(PoolNum).HeatTransCoefsAvg;
1068 : }
1069 :
1070 : // For interzone surfaces, modQPoolSrcAvg was only updated for the "active" side. The active side
1071 : // would have a non-zero value at this point. If the numbers differ, then we have to manually update.
1072 166705567 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1073 164137254 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0 && state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) {
1074 184307730 : if (std::abs(state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum) -
1075 122871820 : state.dataHeatBalFanSys->QPoolSurfNumerator(state.dataSurface->Surface(SurfNum).ExtBoundCond)) >
1076 : CloseEnough) { // numbers differ
1077 0 : if (std::abs(state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum)) >
1078 0 : std::abs(state.dataHeatBalFanSys->QPoolSurfNumerator(state.dataSurface->Surface(SurfNum).ExtBoundCond))) {
1079 0 : state.dataHeatBalFanSys->QPoolSurfNumerator(state.dataSurface->Surface(SurfNum).ExtBoundCond) =
1080 0 : state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum);
1081 : } else {
1082 0 : state.dataHeatBalFanSys->QPoolSurfNumerator(SurfNum) =
1083 0 : state.dataHeatBalFanSys->QPoolSurfNumerator(state.dataSurface->Surface(SurfNum).ExtBoundCond);
1084 : }
1085 : }
1086 : }
1087 : }
1088 : // For interzone surfaces, PoolHeatTransCoefs was only updated for the "active" side. The active side
1089 : // would have a non-zero value at this point. If the numbers differ, then we have to manually update.
1090 166705567 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1091 164137254 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond > 0 && state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) {
1092 184307730 : if (std::abs(state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum) -
1093 122871820 : state.dataHeatBalFanSys->PoolHeatTransCoefs(state.dataSurface->Surface(SurfNum).ExtBoundCond)) >
1094 : CloseEnough) { // numbers differ
1095 0 : if (std::abs(state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum)) >
1096 0 : std::abs(state.dataHeatBalFanSys->PoolHeatTransCoefs(state.dataSurface->Surface(SurfNum).ExtBoundCond))) {
1097 0 : state.dataHeatBalFanSys->PoolHeatTransCoefs(state.dataSurface->Surface(SurfNum).ExtBoundCond) =
1098 0 : state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum);
1099 : } else {
1100 0 : state.dataHeatBalFanSys->PoolHeatTransCoefs(SurfNum) =
1101 0 : state.dataHeatBalFanSys->PoolHeatTransCoefs(state.dataSurface->Surface(SurfNum).ExtBoundCond);
1102 : }
1103 : }
1104 : }
1105 : }
1106 : }
1107 :
1108 6050562 : void ReportSwimmingPool(EnergyPlusData &state)
1109 : {
1110 : // SUBROUTINE INFORMATION:
1111 : // AUTHOR Rick Strand, Ho-Sung Kim
1112 : // DATE WRITTEN October 2014
1113 :
1114 : // PURPOSE OF THIS SUBROUTINE:
1115 : // This subroutine simply produces output for the swimming pool model.
1116 :
1117 : // SUBROUTINE PARAMETER DEFINITIONS:
1118 : static constexpr std::string_view RoutineName("ReportSwimmingPool");
1119 6050562 : Real64 constexpr MinDensity = 1.0; // to avoid a divide by zero
1120 :
1121 6056100 : for (int PoolNum = 1; PoolNum <= state.dataSwimmingPools->NumSwimmingPools; ++PoolNum) {
1122 :
1123 5538 : int SurfNum = state.dataSwimmingPools->Pool(PoolNum).SurfacePtr; // surface number index
1124 :
1125 : // First transfer the surface inside temperature data to the current pool water temperature
1126 5538 : state.dataSwimmingPools->Pool(PoolNum).PoolWaterTemp = state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfNum);
1127 :
1128 : // Next calculate the amount of heating done by the plant loop
1129 16614 : Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state,
1130 : "WATER",
1131 5538 : state.dataSwimmingPools->Pool(PoolNum).PoolWaterTemp,
1132 5538 : state.dataSwimmingPools->Pool(PoolNum).GlycolIndex,
1133 5538 : RoutineName); // specific heat of water
1134 5538 : state.dataSwimmingPools->Pool(PoolNum).HeatPower =
1135 11076 : state.dataSwimmingPools->Pool(PoolNum).WaterMassFlowRate * Cp *
1136 5538 : (state.dataSwimmingPools->Pool(PoolNum).WaterInletTemp - state.dataSwimmingPools->Pool(PoolNum).PoolWaterTemp);
1137 :
1138 : // Now the power consumption of miscellaneous equipment
1139 16614 : Real64 Density = FluidProperties::GetDensityGlycol(state,
1140 : "WATER",
1141 5538 : state.dataSwimmingPools->Pool(PoolNum).PoolWaterTemp,
1142 5538 : state.dataSwimmingPools->Pool(PoolNum).GlycolIndex,
1143 5538 : RoutineName); // density of water
1144 5538 : if (Density > MinDensity) {
1145 5538 : state.dataSwimmingPools->Pool(PoolNum).MiscEquipPower =
1146 5538 : state.dataSwimmingPools->Pool(PoolNum).MiscPowerFactor * state.dataSwimmingPools->Pool(PoolNum).WaterMassFlowRate / Density;
1147 : } else {
1148 0 : state.dataSwimmingPools->Pool(PoolNum).MiscEquipPower = 0.0;
1149 : }
1150 :
1151 : // Also the radiant exchange converted to convection by the pool cover
1152 5538 : state.dataSwimmingPools->Pool(PoolNum).RadConvertToConvectRep =
1153 5538 : state.dataSwimmingPools->Pool(PoolNum).RadConvertToConvect * state.dataSurface->Surface(SurfNum).Area;
1154 :
1155 : // Finally calculate the summed up report variables
1156 5538 : state.dataSwimmingPools->Pool(PoolNum).MiscEquipEnergy =
1157 5538 : state.dataSwimmingPools->Pool(PoolNum).MiscEquipPower * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
1158 5538 : state.dataSwimmingPools->Pool(PoolNum).HeatEnergy =
1159 5538 : state.dataSwimmingPools->Pool(PoolNum).HeatPower * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
1160 5538 : state.dataSwimmingPools->Pool(PoolNum).MakeUpWaterMass =
1161 5538 : state.dataSwimmingPools->Pool(PoolNum).MakeUpWaterMassFlowRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
1162 5538 : state.dataSwimmingPools->Pool(PoolNum).EvapEnergyLoss =
1163 5538 : state.dataSwimmingPools->Pool(PoolNum).EvapHeatLossRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
1164 :
1165 5538 : state.dataSwimmingPools->Pool(PoolNum).MakeUpWaterVolFlowRate =
1166 5538 : MakeUpWaterVolFlowFunct(state.dataSwimmingPools->Pool(PoolNum).MakeUpWaterMassFlowRate, Density);
1167 5538 : state.dataSwimmingPools->Pool(PoolNum).MakeUpWaterVol = MakeUpWaterVolFunct(state.dataSwimmingPools->Pool(PoolNum).MakeUpWaterMass, Density);
1168 : }
1169 6050562 : }
1170 :
1171 5538 : Real64 MakeUpWaterVolFlowFunct(Real64 MakeUpWaterMassFlowRate, Real64 Density)
1172 : {
1173 5538 : return MakeUpWaterMassFlowRate / Density;
1174 : }
1175 :
1176 5538 : Real64 MakeUpWaterVolFunct(Real64 MakeUpWaterMass, Real64 Density)
1177 : {
1178 5538 : return MakeUpWaterMass / Density;
1179 : }
1180 :
1181 2313 : } // namespace EnergyPlus::SwimmingPool
|