Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, 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 :
54 : // EnergyPlus Headers
55 : #include <EnergyPlus/BranchNodeConnections.hh>
56 : #include <EnergyPlus/Data/EnergyPlusData.hh>
57 : #include <EnergyPlus/DataEnvironment.hh>
58 : #include <EnergyPlus/DataHVACGlobals.hh>
59 : #include <EnergyPlus/DataHeatBalance.hh>
60 : #include <EnergyPlus/DataIPShortCuts.hh>
61 : #include <EnergyPlus/DataLoopNode.hh>
62 : #include <EnergyPlus/DataWater.hh>
63 : #include <EnergyPlus/FluidProperties.hh>
64 : #include <EnergyPlus/HeatBalanceInternalHeatGains.hh>
65 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
66 : #include <EnergyPlus/NodeInputManager.hh>
67 : #include <EnergyPlus/OutputProcessor.hh>
68 : #include <EnergyPlus/Plant/DataPlant.hh>
69 : #include <EnergyPlus/PlantUtilities.hh>
70 : #include <EnergyPlus/Psychrometrics.hh>
71 : #include <EnergyPlus/ScheduleManager.hh>
72 : #include <EnergyPlus/UtilityRoutines.hh>
73 : #include <EnergyPlus/WaterManager.hh>
74 : #include <EnergyPlus/WaterUse.hh>
75 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
76 :
77 : namespace EnergyPlus {
78 :
79 : namespace WaterUse {
80 :
81 : // MODULE INFORMATION:
82 : // AUTHOR Peter Graham Ellis
83 : // DATE WRITTEN August 2006
84 : // MODIFIED Brent Griffith, plant upgrade
85 :
86 505706 : void SimulateWaterUse(EnergyPlusData &state, bool FirstHVACIteration)
87 : {
88 :
89 : // SUBROUTINE INFORMATION:
90 : // AUTHOR Peter Graham Ellis
91 : // DATE WRITTEN August 2006
92 : // MODIFIED Brent Griffith, March 2010, separated plant connected to different sim routine
93 :
94 : // PURPOSE OF THIS SUBROUTINE:
95 : // This routine is called from non zone equipment manager and serves to call
96 : // water use and connections that are not connected to a full plant loop
97 :
98 505706 : int constexpr MaxIterations(100);
99 505706 : Real64 constexpr Tolerance(0.1); // Make input?
100 :
101 505706 : if (state.dataWaterUse->getWaterUseInputFlag) {
102 101 : GetWaterUseInput(state);
103 101 : state.dataWaterUse->getWaterUseInputFlag = false;
104 : }
105 :
106 505706 : if (state.dataGlobal->BeginEnvrnFlag && state.dataWaterUse->MyEnvrnFlagLocal) {
107 477 : if (state.dataWaterUse->numWaterEquipment > 0) {
108 4 : for (auto &e : state.dataWaterUse->WaterEquipment) {
109 2 : e.SensibleRate = 0.0;
110 2 : e.SensibleEnergy = 0.0;
111 2 : e.LatentRate = 0.0;
112 2 : e.LatentEnergy = 0.0;
113 2 : e.MixedTemp = 0.0;
114 2 : e.TotalMassFlowRate = 0.0;
115 2 : e.DrainTemp = 0.0;
116 2 : }
117 : }
118 :
119 477 : if (state.dataWaterUse->numWaterConnections > 0) {
120 4 : for (auto &e : state.dataWaterUse->WaterConnections) {
121 2 : e.TotalMassFlowRate = 0.0;
122 2 : }
123 : }
124 :
125 477 : state.dataWaterUse->MyEnvrnFlagLocal = false;
126 : }
127 :
128 505706 : if (!state.dataGlobal->BeginEnvrnFlag) {
129 503793 : state.dataWaterUse->MyEnvrnFlagLocal = true;
130 : }
131 :
132 : // Simulate all unconnected WATER USE EQUIPMENT objects
133 507196 : for (auto &waterEquipment : state.dataWaterUse->WaterEquipment) {
134 1490 : if (waterEquipment.Connections == 0) {
135 0 : waterEquipment.CalcEquipmentFlowRates(state);
136 0 : waterEquipment.CalcEquipmentDrainTemp(state);
137 : }
138 505706 : } // WaterEquipNum
139 :
140 505706 : ReportStandAloneWaterUse(state);
141 :
142 : // Simulate WATER USE CONNECTIONS objects and connected WATER USE EQUIPMENT objects
143 507196 : for (auto &waterConnection : state.dataWaterUse->WaterConnections) {
144 :
145 1490 : if (!waterConnection.StandAlone) {
146 1490 : continue; // only model non plant connections here
147 : }
148 :
149 0 : waterConnection.InitConnections(state);
150 :
151 0 : int NumIteration = 0;
152 :
153 : while (true) {
154 0 : ++NumIteration;
155 :
156 0 : waterConnection.CalcConnectionsFlowRates(state, FirstHVACIteration);
157 0 : waterConnection.CalcConnectionsDrainTemp(state);
158 0 : waterConnection.CalcConnectionsHeatRecovery(state);
159 :
160 0 : if (waterConnection.TempError < Tolerance) {
161 0 : break;
162 0 : } else if (NumIteration > MaxIterations) {
163 0 : if (!state.dataGlobal->WarmupFlag) {
164 0 : if (waterConnection.MaxIterationsErrorIndex == 0) {
165 0 : ShowWarningError(state,
166 0 : format("WaterUse:Connections = {}: Heat recovery temperature did not converge", waterConnection.Name));
167 0 : ShowContinueErrorTimeStamp(state, "");
168 : }
169 0 : ShowRecurringWarningErrorAtEnd(state,
170 0 : "WaterUse:Connections = " + waterConnection.Name +
171 : ": Heat recovery temperature did not converge",
172 0 : waterConnection.MaxIterationsErrorIndex);
173 : }
174 0 : break;
175 : }
176 :
177 : } // WHILE
178 :
179 0 : waterConnection.UpdateWaterConnections(state);
180 0 : waterConnection.ReportWaterUse(state);
181 :
182 505706 : } // WaterConnNum
183 505706 : }
184 :
185 1 : PlantComponent *WaterConnectionsType::factory(EnergyPlusData &state, std::string const &objectName)
186 : {
187 : // Process the input data
188 1 : if (state.dataWaterUse->getWaterUseInputFlag) {
189 1 : GetWaterUseInput(state);
190 1 : state.dataWaterUse->getWaterUseInputFlag = false;
191 : }
192 :
193 : // Now look for this particular object in the list
194 1 : for (auto &thisWC : state.dataWaterUse->WaterConnections) {
195 1 : if (thisWC.Name == objectName) {
196 1 : return &thisWC;
197 : }
198 2 : }
199 : // If we didn't find it, fatal
200 : ShowFatalError(state, format("LocalWaterUseConnectionFactory: Error getting inputs for object named: {}", objectName)); // LCOV_EXCL_LINE
201 : // Shut up the compiler
202 : return nullptr; // LCOV_EXCL_LINE
203 : }
204 :
205 5965 : void WaterConnectionsType::simulate(EnergyPlusData &state,
206 : [[maybe_unused]] const PlantLocation &calledFromLocation,
207 : bool FirstHVACIteration,
208 : [[maybe_unused]] Real64 &CurLoad,
209 : [[maybe_unused]] bool RunFlag)
210 : {
211 :
212 : // SUBROUTINE INFORMATION:
213 : // AUTHOR Brent Griffith March 2010, Demand Side Update
214 : // DATE WRITTEN August 2006
215 :
216 : // PURPOSE OF THIS SUBROUTINE:
217 : // Plant sim call for plant loop connected water use and connections
218 :
219 5965 : int constexpr MaxIterations(100);
220 5965 : Real64 constexpr Tolerance(0.1); // Make input?
221 :
222 5965 : if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
223 2 : if (state.dataWaterUse->numWaterEquipment > 0) {
224 4 : for (auto &waterEquipment : state.dataWaterUse->WaterEquipment) {
225 2 : waterEquipment.reset();
226 2 : if (waterEquipment.setupMyOutputVars) {
227 1 : waterEquipment.setupOutputVars(state);
228 1 : waterEquipment.setupMyOutputVars = false;
229 : }
230 2 : }
231 : }
232 :
233 2 : if (state.dataWaterUse->numWaterConnections > 0) {
234 4 : for (auto &waterConnections : state.dataWaterUse->WaterConnections) {
235 2 : waterConnections.TotalMassFlowRate = 0.0;
236 2 : }
237 : }
238 :
239 2 : this->MyEnvrnFlag = false;
240 : }
241 :
242 5965 : if (!state.dataGlobal->BeginEnvrnFlag) {
243 5944 : this->MyEnvrnFlag = true;
244 : }
245 :
246 5965 : this->InitConnections(state);
247 :
248 5965 : int NumIteration = 0;
249 :
250 : while (true) {
251 5965 : ++NumIteration;
252 :
253 5965 : this->CalcConnectionsFlowRates(state, FirstHVACIteration);
254 5965 : this->CalcConnectionsDrainTemp(state);
255 5965 : this->CalcConnectionsHeatRecovery(state);
256 :
257 5965 : if (this->TempError < Tolerance) {
258 5965 : break;
259 0 : } else if (NumIteration > MaxIterations) {
260 0 : if (!state.dataGlobal->WarmupFlag) {
261 0 : if (this->MaxIterationsErrorIndex == 0) {
262 0 : ShowWarningError(state, format("WaterUse:Connections = {}: Heat recovery temperature did not converge", this->Name));
263 0 : ShowContinueErrorTimeStamp(state, "");
264 : }
265 0 : ShowRecurringWarningErrorAtEnd(state,
266 0 : "WaterUse:Connections = " + this->Name + ": Heat recovery temperature did not converge",
267 0 : this->MaxIterationsErrorIndex);
268 : }
269 0 : break;
270 : }
271 : } // WHILE
272 :
273 5965 : this->UpdateWaterConnections(state);
274 5965 : this->ReportWaterUse(state);
275 5965 : }
276 :
277 105 : void GetWaterUseInput(EnergyPlusData &state)
278 : {
279 :
280 : // SUBROUTINE INFORMATION:
281 : // AUTHOR Peter Graham Ellis
282 : // DATE WRITTEN August 2006
283 :
284 : static constexpr std::string_view routineName = "GetWaterUseInput";
285 :
286 105 : bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
287 : int IOStatus; // Used in GetObjectItem
288 : int NumAlphas; // Number of Alphas for each GetObjectItem call
289 : int NumNumbers; // Number of Numbers for each GetObjectItem call
290 :
291 105 : constexpr std::array<std::string_view, static_cast<int>(HeatRecovHX::Num)> HeatRecoverHXNamesUC{"IDEAL", "COUNTERFLOW", "CROSSFLOW"};
292 :
293 105 : constexpr std::array<std::string_view, static_cast<int>(HeatRecovConfig::Num)> HeatRecoveryConfigNamesUC{
294 : "PLANT", "EQUIPMENT", "PLANTANDEQUIPMENT"};
295 :
296 105 : state.dataIPShortCut->cCurrentModuleObject = "WaterUse:Equipment";
297 210 : state.dataWaterUse->numWaterEquipment =
298 105 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
299 :
300 105 : if (state.dataWaterUse->numWaterEquipment > 0) {
301 4 : state.dataWaterUse->WaterEquipment.allocate(state.dataWaterUse->numWaterEquipment);
302 :
303 8 : for (int WaterEquipNum = 1; WaterEquipNum <= state.dataWaterUse->numWaterEquipment; ++WaterEquipNum) {
304 4 : auto &thisWEq = state.dataWaterUse->WaterEquipment(WaterEquipNum);
305 12 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
306 4 : state.dataIPShortCut->cCurrentModuleObject,
307 : WaterEquipNum,
308 4 : state.dataIPShortCut->cAlphaArgs,
309 : NumAlphas,
310 4 : state.dataIPShortCut->rNumericArgs,
311 : NumNumbers,
312 : IOStatus,
313 : _,
314 4 : state.dataIPShortCut->lAlphaFieldBlanks,
315 4 : state.dataIPShortCut->cAlphaFieldNames,
316 4 : state.dataIPShortCut->cNumericFieldNames);
317 :
318 4 : ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
319 4 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
320 4 : thisWEq.Name = state.dataIPShortCut->cAlphaArgs(1);
321 :
322 4 : thisWEq.EndUseSubcatName = state.dataIPShortCut->cAlphaArgs(2);
323 :
324 4 : thisWEq.PeakVolFlowRate = state.dataIPShortCut->rNumericArgs(1);
325 :
326 4 : if ((NumAlphas <= 2) || (state.dataIPShortCut->lAlphaFieldBlanks(3))) {
327 1 : } else if ((thisWEq.flowRateFracSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(3))) == nullptr) {
328 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), state.dataIPShortCut->cAlphaArgs(3));
329 0 : ErrorsFound = true;
330 : }
331 :
332 4 : if ((NumAlphas <= 3) || (state.dataIPShortCut->lAlphaFieldBlanks(4))) {
333 2 : } else if ((thisWEq.targetTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(4))) == nullptr) {
334 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4), state.dataIPShortCut->cAlphaArgs(4));
335 0 : ErrorsFound = true;
336 : }
337 :
338 4 : if ((NumAlphas <= 4) || (state.dataIPShortCut->lAlphaFieldBlanks(5))) {
339 0 : } else if ((thisWEq.hotTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(5))) == nullptr) {
340 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5));
341 0 : ErrorsFound = true;
342 : }
343 :
344 4 : if ((NumAlphas <= 5) || (state.dataIPShortCut->lAlphaFieldBlanks(6))) {
345 0 : } else if ((thisWEq.coldTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(6))) == nullptr) {
346 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6));
347 0 : ErrorsFound = true;
348 : }
349 :
350 4 : if ((NumAlphas <= 6) || (state.dataIPShortCut->lAlphaFieldBlanks(7))) {
351 3 : } else if ((thisWEq.Zone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(7), state.dataHeatBal->Zone)) == 0) {
352 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7));
353 0 : ErrorsFound = true;
354 : }
355 :
356 4 : if ((NumAlphas <= 7) || (state.dataIPShortCut->lAlphaFieldBlanks(8))) {
357 3 : } else if ((thisWEq.sensibleFracSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(8))) == nullptr) {
358 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8));
359 0 : ErrorsFound = true;
360 : }
361 :
362 4 : if ((NumAlphas <= 8) || (state.dataIPShortCut->lAlphaFieldBlanks(9))) {
363 3 : } else if ((thisWEq.latentFracSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(9))) == nullptr) {
364 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9));
365 0 : ErrorsFound = true;
366 : }
367 :
368 : } // WaterEquipNum
369 :
370 4 : if (ErrorsFound) {
371 0 : ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
372 : }
373 : }
374 :
375 105 : state.dataIPShortCut->cCurrentModuleObject = "WaterUse:Connections";
376 210 : state.dataWaterUse->numWaterConnections =
377 105 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
378 :
379 105 : if (state.dataWaterUse->numWaterConnections > 0) {
380 3 : state.dataWaterUse->WaterConnections.allocate(state.dataWaterUse->numWaterConnections);
381 :
382 6 : for (int WaterConnNum = 1; WaterConnNum <= state.dataWaterUse->numWaterConnections; ++WaterConnNum) {
383 9 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
384 3 : state.dataIPShortCut->cCurrentModuleObject,
385 : WaterConnNum,
386 3 : state.dataIPShortCut->cAlphaArgs,
387 : NumAlphas,
388 3 : state.dataIPShortCut->rNumericArgs,
389 : NumNumbers,
390 : IOStatus,
391 : _,
392 3 : state.dataIPShortCut->lAlphaFieldBlanks,
393 3 : state.dataIPShortCut->cAlphaFieldNames,
394 3 : state.dataIPShortCut->cNumericFieldNames);
395 :
396 3 : ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
397 :
398 3 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
399 3 : auto &waterConnection = state.dataWaterUse->WaterConnections(WaterConnNum);
400 3 : waterConnection.Name = state.dataIPShortCut->cAlphaArgs(1);
401 :
402 3 : if ((!state.dataIPShortCut->lAlphaFieldBlanks(2)) || (!state.dataIPShortCut->lAlphaFieldBlanks(3))) {
403 3 : waterConnection.InletNode = NodeInputManager::GetOnlySingleNode(state,
404 3 : state.dataIPShortCut->cAlphaArgs(2),
405 : ErrorsFound,
406 : DataLoopNode::ConnectionObjectType::WaterUseConnections,
407 3 : waterConnection.Name,
408 : DataLoopNode::NodeFluidType::Water,
409 : DataLoopNode::ConnectionType::Inlet,
410 : NodeInputManager::CompFluidStream::Primary,
411 : DataLoopNode::ObjectIsNotParent);
412 6 : waterConnection.OutletNode = NodeInputManager::GetOnlySingleNode(state,
413 3 : state.dataIPShortCut->cAlphaArgs(3),
414 : ErrorsFound,
415 : DataLoopNode::ConnectionObjectType::WaterUseConnections,
416 3 : waterConnection.Name,
417 : DataLoopNode::NodeFluidType::Water,
418 : DataLoopNode::ConnectionType::Outlet,
419 : NodeInputManager::CompFluidStream::Primary,
420 : DataLoopNode::ObjectIsNotParent);
421 :
422 : // Check plant connections
423 9 : BranchNodeConnections::TestCompSet(state,
424 3 : state.dataIPShortCut->cCurrentModuleObject,
425 : waterConnection.Name,
426 3 : state.dataIPShortCut->cAlphaArgs(2),
427 3 : state.dataIPShortCut->cAlphaArgs(3),
428 : "DHW Nodes");
429 : } else {
430 : // If no plant nodes are connected, simulate in stand-alone mode.
431 0 : waterConnection.StandAlone = true;
432 : }
433 :
434 3 : if (!state.dataIPShortCut->lAlphaFieldBlanks(4)) {
435 0 : WaterManager::SetupTankDemandComponent(state,
436 : waterConnection.Name,
437 0 : state.dataIPShortCut->cCurrentModuleObject,
438 0 : state.dataIPShortCut->cAlphaArgs(4),
439 : ErrorsFound,
440 0 : waterConnection.SupplyTankNum,
441 0 : waterConnection.TankDemandID);
442 : }
443 :
444 3 : if (!state.dataIPShortCut->lAlphaFieldBlanks(5)) {
445 0 : WaterManager::SetupTankSupplyComponent(state,
446 : waterConnection.Name,
447 0 : state.dataIPShortCut->cCurrentModuleObject,
448 0 : state.dataIPShortCut->cAlphaArgs(5),
449 : ErrorsFound,
450 0 : waterConnection.RecoveryTankNum,
451 0 : waterConnection.TankSupplyID);
452 : }
453 :
454 3 : if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
455 0 : } else if ((waterConnection.hotTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(6))) == nullptr) {
456 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6));
457 0 : ErrorsFound = true;
458 : }
459 :
460 3 : if (state.dataIPShortCut->lAlphaFieldBlanks(7)) {
461 0 : } else if ((waterConnection.coldTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(7))) == nullptr) {
462 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7));
463 0 : ErrorsFound = true;
464 : }
465 :
466 3 : if ((!state.dataIPShortCut->lAlphaFieldBlanks(8)) && (state.dataIPShortCut->cAlphaArgs(8) != "NONE")) {
467 0 : waterConnection.HeatRecovery = true;
468 0 : waterConnection.HeatRecoveryHX =
469 0 : static_cast<HeatRecovHX>(getEnumValue(HeatRecoverHXNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8))));
470 0 : if (waterConnection.HeatRecoveryHX == HeatRecovHX::Invalid) {
471 0 : ShowSevereError(state,
472 0 : format("Invalid {} = {}", state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8)));
473 0 : ShowContinueError(state, format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, waterConnection.Name));
474 0 : ErrorsFound = true;
475 : }
476 :
477 0 : waterConnection.HeatRecoveryConfig =
478 0 : static_cast<HeatRecovConfig>(getEnumValue(HeatRecoveryConfigNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(9))));
479 0 : if (waterConnection.HeatRecoveryConfig == HeatRecovConfig::Invalid) {
480 0 : ShowSevereError(state,
481 0 : format("Invalid {} = {}", state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9)));
482 0 : ShowContinueError(state, format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, waterConnection.Name));
483 0 : ErrorsFound = true;
484 : }
485 : }
486 :
487 3 : waterConnection.HXUA = state.dataIPShortCut->rNumericArgs(1);
488 :
489 3 : waterConnection.myWaterEquipArr.allocate(NumAlphas - 9);
490 :
491 6 : for (int AlphaNum = 10; AlphaNum <= NumAlphas; ++AlphaNum) {
492 3 : int WaterEquipNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(AlphaNum), state.dataWaterUse->WaterEquipment);
493 :
494 3 : if (WaterEquipNum == 0) {
495 0 : ShowSevereError(
496 : state,
497 0 : format("Invalid {} = {}", state.dataIPShortCut->cAlphaFieldNames(AlphaNum), state.dataIPShortCut->cAlphaArgs(AlphaNum)));
498 0 : ShowContinueError(state, format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, waterConnection.Name));
499 0 : ErrorsFound = true;
500 : } else {
501 3 : if (state.dataWaterUse->WaterEquipment(WaterEquipNum).Connections > 0) {
502 0 : ShowSevereError(state,
503 0 : format("{} = {}: WaterUse:Equipment = {} is already referenced by another object.",
504 0 : state.dataIPShortCut->cCurrentModuleObject,
505 0 : waterConnection.Name,
506 0 : state.dataIPShortCut->cAlphaArgs(AlphaNum)));
507 0 : ErrorsFound = true;
508 : } else {
509 3 : state.dataWaterUse->WaterEquipment(WaterEquipNum).Connections = WaterConnNum;
510 :
511 3 : ++waterConnection.NumWaterEquipment;
512 3 : waterConnection.myWaterEquipArr(waterConnection.NumWaterEquipment) = WaterEquipNum;
513 :
514 3 : waterConnection.PeakVolFlowRate +=
515 3 : state.dataWaterUse->WaterEquipment(WaterEquipNum).PeakVolFlowRate; // this does not include possible multipliers
516 : }
517 : }
518 : }
519 :
520 : } // WaterConnNum
521 :
522 3 : if (ErrorsFound) {
523 0 : ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
524 : }
525 :
526 3 : if (state.dataWaterUse->numWaterConnections > 0) {
527 3 : state.dataWaterUse->CheckEquipName.allocate(state.dataWaterUse->numWaterConnections);
528 3 : state.dataWaterUse->CheckEquipName = true;
529 : }
530 : }
531 :
532 : // determine connection's peak mass flow rates.
533 105 : if (state.dataWaterUse->numWaterConnections > 0) {
534 6 : for (int WaterConnNum = 1; WaterConnNum <= state.dataWaterUse->numWaterConnections; ++WaterConnNum) {
535 3 : auto &waterConnection = state.dataWaterUse->WaterConnections(WaterConnNum);
536 3 : waterConnection.PeakMassFlowRate = 0.0;
537 6 : for (int WaterEquipNum = 1; WaterEquipNum <= waterConnection.NumWaterEquipment; ++WaterEquipNum) {
538 3 : auto &thisWEq = state.dataWaterUse->WaterEquipment(waterConnection.myWaterEquipArr(WaterEquipNum));
539 3 : if (thisWEq.Zone > 0) {
540 2 : waterConnection.PeakMassFlowRate += thisWEq.PeakVolFlowRate * calcH2ODensity(state) *
541 2 : state.dataHeatBal->Zone(thisWEq.Zone).Multiplier *
542 2 : state.dataHeatBal->Zone(thisWEq.Zone).ListMultiplier;
543 : } else { // can't have multipliers
544 1 : waterConnection.PeakMassFlowRate += thisWEq.PeakVolFlowRate * calcH2ODensity(state);
545 : }
546 : }
547 3 : PlantUtilities::RegisterPlantCompDesignFlow(
548 3 : state, waterConnection.InletNode, waterConnection.PeakMassFlowRate / calcH2ODensity(state));
549 : }
550 : }
551 : // need a good place to set a bool to calculate WaterUse hot and cold flow rates in CalcEquipmentFlowRates
552 : // WaterUse can be used with or without WaterUse:Connections, with or without WaterUse:Equipment hot temp schedule
553 109 : for (auto &waterEquipment : state.dataWaterUse->WaterEquipment) {
554 : // set logical if either hot water temp or target temp schedule are missing (will use cold water otherwise)
555 : // if a connections object is used then don't need to hot temp schedule
556 4 : waterEquipment.allowHotControl =
557 4 : (waterEquipment.targetTempSched != nullptr && waterEquipment.hotTempSched != nullptr) || waterEquipment.Connections;
558 105 : }
559 105 : }
560 :
561 4 : void WaterEquipmentType::setupOutputVars(EnergyPlusData &state)
562 : {
563 8 : SetupOutputVariable(state,
564 : "Water Use Equipment Hot Water Mass Flow Rate",
565 : Constant::Units::kg_s,
566 4 : this->HotMassFlowRate,
567 : OutputProcessor::TimeStepType::System,
568 : OutputProcessor::StoreType::Average,
569 4 : this->Name);
570 :
571 8 : SetupOutputVariable(state,
572 : "Water Use Equipment Cold Water Mass Flow Rate",
573 : Constant::Units::kg_s,
574 4 : this->ColdMassFlowRate,
575 : OutputProcessor::TimeStepType::System,
576 : OutputProcessor::StoreType::Average,
577 4 : this->Name);
578 :
579 8 : SetupOutputVariable(state,
580 : "Water Use Equipment Total Mass Flow Rate",
581 : Constant::Units::kg_s,
582 4 : this->TotalMassFlowRate,
583 : OutputProcessor::TimeStepType::System,
584 : OutputProcessor::StoreType::Average,
585 4 : this->Name);
586 :
587 8 : SetupOutputVariable(state,
588 : "Water Use Equipment Hot Water Volume Flow Rate",
589 : Constant::Units::m3_s,
590 4 : this->HotVolFlowRate,
591 : OutputProcessor::TimeStepType::System,
592 : OutputProcessor::StoreType::Average,
593 4 : this->Name);
594 :
595 8 : SetupOutputVariable(state,
596 : "Water Use Equipment Cold Water Volume Flow Rate",
597 : Constant::Units::m3_s,
598 4 : this->ColdVolFlowRate,
599 : OutputProcessor::TimeStepType::System,
600 : OutputProcessor::StoreType::Average,
601 4 : this->Name);
602 :
603 8 : SetupOutputVariable(state,
604 : "Water Use Equipment Total Volume Flow Rate",
605 : Constant::Units::m3_s,
606 4 : this->TotalVolFlowRate,
607 : OutputProcessor::TimeStepType::System,
608 : OutputProcessor::StoreType::Average,
609 4 : this->Name);
610 :
611 8 : SetupOutputVariable(state,
612 : "Water Use Equipment Hot Water Volume",
613 : Constant::Units::m3,
614 4 : this->HotVolume,
615 : OutputProcessor::TimeStepType::System,
616 : OutputProcessor::StoreType::Sum,
617 4 : this->Name);
618 :
619 8 : SetupOutputVariable(state,
620 : "Water Use Equipment Cold Water Volume",
621 : Constant::Units::m3,
622 4 : this->ColdVolume,
623 : OutputProcessor::TimeStepType::System,
624 : OutputProcessor::StoreType::Sum,
625 4 : this->Name);
626 :
627 8 : SetupOutputVariable(state,
628 : "Water Use Equipment Total Volume",
629 : Constant::Units::m3,
630 4 : this->TotalVolume,
631 : OutputProcessor::TimeStepType::System,
632 : OutputProcessor::StoreType::Sum,
633 4 : this->Name,
634 : Constant::eResource::Water,
635 : OutputProcessor::Group::Plant,
636 : OutputProcessor::EndUseCat::WaterSystem,
637 : this->EndUseSubcatName);
638 8 : SetupOutputVariable(state,
639 : "Water Use Equipment Mains Water Volume",
640 : Constant::Units::m3,
641 4 : this->TotalVolume,
642 : OutputProcessor::TimeStepType::System,
643 : OutputProcessor::StoreType::Sum,
644 4 : this->Name,
645 : Constant::eResource::MainsWater,
646 : OutputProcessor::Group::Plant,
647 : OutputProcessor::EndUseCat::WaterSystem,
648 : this->EndUseSubcatName);
649 :
650 8 : SetupOutputVariable(state,
651 : "Water Use Equipment Hot Water Temperature",
652 : Constant::Units::C,
653 4 : this->HotTemp,
654 : OutputProcessor::TimeStepType::System,
655 : OutputProcessor::StoreType::Average,
656 4 : this->Name);
657 :
658 8 : SetupOutputVariable(state,
659 : "Water Use Equipment Cold Water Temperature",
660 : Constant::Units::C,
661 4 : this->ColdTemp,
662 : OutputProcessor::TimeStepType::System,
663 : OutputProcessor::StoreType::Average,
664 4 : this->Name);
665 :
666 8 : SetupOutputVariable(state,
667 : "Water Use Equipment Target Water Temperature",
668 : Constant::Units::C,
669 4 : this->TargetTemp,
670 : OutputProcessor::TimeStepType::System,
671 : OutputProcessor::StoreType::Average,
672 4 : this->Name);
673 :
674 8 : SetupOutputVariable(state,
675 : "Water Use Equipment Mixed Water Temperature",
676 : Constant::Units::C,
677 4 : this->MixedTemp,
678 : OutputProcessor::TimeStepType::System,
679 : OutputProcessor::StoreType::Average,
680 4 : this->Name);
681 :
682 8 : SetupOutputVariable(state,
683 : "Water Use Equipment Drain Water Temperature",
684 : Constant::Units::C,
685 4 : this->DrainTemp,
686 : OutputProcessor::TimeStepType::System,
687 : OutputProcessor::StoreType::Average,
688 4 : this->Name);
689 :
690 8 : SetupOutputVariable(state,
691 : "Water Use Equipment Heating Rate",
692 : Constant::Units::W,
693 4 : this->Power,
694 : OutputProcessor::TimeStepType::System,
695 : OutputProcessor::StoreType::Average,
696 4 : this->Name);
697 :
698 4 : if (this->Connections == 0) {
699 2 : SetupOutputVariable(state,
700 : "Water Use Equipment Heating Energy",
701 : Constant::Units::J,
702 1 : this->Energy,
703 : OutputProcessor::TimeStepType::System,
704 : OutputProcessor::StoreType::Sum,
705 1 : this->Name,
706 : Constant::eResource::DistrictHeatingWater,
707 : OutputProcessor::Group::Plant,
708 : OutputProcessor::EndUseCat::WaterSystem,
709 : this->EndUseSubcatName);
710 :
711 3 : } else if (state.dataWaterUse->WaterConnections(this->Connections).StandAlone) {
712 0 : SetupOutputVariable(state,
713 : "Water Use Equipment Heating Energy",
714 : Constant::Units::J,
715 0 : this->Energy,
716 : OutputProcessor::TimeStepType::System,
717 : OutputProcessor::StoreType::Sum,
718 0 : this->Name,
719 : Constant::eResource::DistrictHeatingWater,
720 : OutputProcessor::Group::Plant,
721 : OutputProcessor::EndUseCat::WaterSystem,
722 : this->EndUseSubcatName);
723 :
724 : } else { // The EQUIPMENT is coupled to a plant loop via a CONNECTIONS object
725 6 : SetupOutputVariable(state,
726 : "Water Use Equipment Heating Energy",
727 : Constant::Units::J,
728 3 : this->Energy,
729 : OutputProcessor::TimeStepType::System,
730 : OutputProcessor::StoreType::Sum,
731 3 : this->Name,
732 : Constant::eResource::EnergyTransfer,
733 : OutputProcessor::Group::Plant,
734 : OutputProcessor::EndUseCat::WaterSystem,
735 : this->EndUseSubcatName);
736 : }
737 :
738 4 : if (this->Zone > 0) {
739 6 : SetupOutputVariable(state,
740 : "Water Use Equipment Zone Sensible Heat Gain Rate",
741 : Constant::Units::W,
742 3 : this->SensibleRate,
743 : OutputProcessor::TimeStepType::System,
744 : OutputProcessor::StoreType::Average,
745 3 : this->Name);
746 6 : SetupOutputVariable(state,
747 : "Water Use Equipment Zone Sensible Heat Gain Energy",
748 : Constant::Units::J,
749 3 : this->SensibleEnergy,
750 : OutputProcessor::TimeStepType::System,
751 : OutputProcessor::StoreType::Sum,
752 3 : this->Name);
753 :
754 6 : SetupOutputVariable(state,
755 : "Water Use Equipment Zone Latent Gain Rate",
756 : Constant::Units::W,
757 3 : this->LatentRate,
758 : OutputProcessor::TimeStepType::System,
759 : OutputProcessor::StoreType::Average,
760 3 : this->Name);
761 6 : SetupOutputVariable(state,
762 : "Water Use Equipment Zone Latent Gain Energy",
763 : Constant::Units::J,
764 3 : this->LatentEnergy,
765 : OutputProcessor::TimeStepType::System,
766 : OutputProcessor::StoreType::Sum,
767 3 : this->Name);
768 :
769 6 : SetupOutputVariable(state,
770 : "Water Use Equipment Zone Moisture Gain Mass Flow Rate",
771 : Constant::Units::kg_s,
772 3 : this->MoistureRate,
773 : OutputProcessor::TimeStepType::System,
774 : OutputProcessor::StoreType::Average,
775 3 : this->Name);
776 6 : SetupOutputVariable(state,
777 : "Water Use Equipment Zone Moisture Gain Mass",
778 : Constant::Units::kg,
779 3 : this->MoistureMass,
780 : OutputProcessor::TimeStepType::System,
781 : OutputProcessor::StoreType::Sum,
782 3 : this->Name);
783 :
784 3 : SetupZoneInternalGain(state,
785 : this->Zone,
786 : this->Name,
787 : DataHeatBalance::IntGainType::WaterUseEquipment,
788 : &this->SensibleRateNoMultiplier,
789 : nullptr,
790 : nullptr,
791 : &this->LatentRateNoMultiplier);
792 : }
793 4 : }
794 :
795 1 : void WaterConnectionsType::setupOutputVars(EnergyPlusData &state)
796 : {
797 2 : SetupOutputVariable(state,
798 : "Water Use Connections Hot Water Mass Flow Rate",
799 : Constant::Units::kg_s,
800 1 : this->HotMassFlowRate,
801 : OutputProcessor::TimeStepType::System,
802 : OutputProcessor::StoreType::Average,
803 1 : this->Name);
804 :
805 2 : SetupOutputVariable(state,
806 : "Water Use Connections Cold Water Mass Flow Rate",
807 : Constant::Units::kg_s,
808 1 : this->ColdMassFlowRate,
809 : OutputProcessor::TimeStepType::System,
810 : OutputProcessor::StoreType::Average,
811 1 : this->Name);
812 :
813 2 : SetupOutputVariable(state,
814 : "Water Use Connections Total Mass Flow Rate",
815 : Constant::Units::kg_s,
816 1 : this->TotalMassFlowRate,
817 : OutputProcessor::TimeStepType::System,
818 : OutputProcessor::StoreType::Average,
819 1 : this->Name);
820 :
821 2 : SetupOutputVariable(state,
822 : "Water Use Connections Drain Water Mass Flow Rate",
823 : Constant::Units::kg_s,
824 1 : this->DrainMassFlowRate,
825 : OutputProcessor::TimeStepType::System,
826 : OutputProcessor::StoreType::Average,
827 1 : this->Name);
828 :
829 2 : SetupOutputVariable(state,
830 : "Water Use Connections Heat Recovery Mass Flow Rate",
831 : Constant::Units::kg_s,
832 1 : this->RecoveryMassFlowRate,
833 : OutputProcessor::TimeStepType::System,
834 : OutputProcessor::StoreType::Average,
835 1 : this->Name);
836 :
837 2 : SetupOutputVariable(state,
838 : "Water Use Connections Hot Water Volume Flow Rate",
839 : Constant::Units::m3_s,
840 1 : this->HotVolFlowRate,
841 : OutputProcessor::TimeStepType::System,
842 : OutputProcessor::StoreType::Average,
843 1 : this->Name);
844 :
845 2 : SetupOutputVariable(state,
846 : "Water Use Connections Cold Water Volume Flow Rate",
847 : Constant::Units::m3_s,
848 1 : this->ColdVolFlowRate,
849 : OutputProcessor::TimeStepType::System,
850 : OutputProcessor::StoreType::Average,
851 1 : this->Name);
852 :
853 2 : SetupOutputVariable(state,
854 : "Water Use Connections Total Volume Flow Rate",
855 : Constant::Units::m3_s,
856 1 : this->TotalVolFlowRate,
857 : OutputProcessor::TimeStepType::System,
858 : OutputProcessor::StoreType::Average,
859 1 : this->Name);
860 :
861 2 : SetupOutputVariable(state,
862 : "Water Use Connections Hot Water Volume",
863 : Constant::Units::m3,
864 1 : this->HotVolume,
865 : OutputProcessor::TimeStepType::System,
866 : OutputProcessor::StoreType::Sum,
867 1 : this->Name);
868 :
869 2 : SetupOutputVariable(state,
870 : "Water Use Connections Cold Water Volume",
871 : Constant::Units::m3,
872 1 : this->ColdVolume,
873 : OutputProcessor::TimeStepType::System,
874 : OutputProcessor::StoreType::Sum,
875 1 : this->Name);
876 :
877 2 : SetupOutputVariable(state,
878 : "Water Use Connections Total Volume",
879 : Constant::Units::m3,
880 1 : this->TotalVolume,
881 : OutputProcessor::TimeStepType::System,
882 : OutputProcessor::StoreType::Sum,
883 1 : this->Name); //, &
884 : // ResourceTypeKey='Water', EndUseKey='DHW', EndUseSubKey=EndUseSubcategoryName, GroupKey='Plant')
885 : // tHIS WAS double counting
886 :
887 2 : SetupOutputVariable(state,
888 : "Water Use Connections Hot Water Temperature",
889 : Constant::Units::C,
890 1 : this->HotTemp,
891 : OutputProcessor::TimeStepType::System,
892 : OutputProcessor::StoreType::Average,
893 1 : this->Name);
894 :
895 2 : SetupOutputVariable(state,
896 : "Water Use Connections Cold Water Temperature",
897 : Constant::Units::C,
898 1 : this->ColdTemp,
899 : OutputProcessor::TimeStepType::System,
900 : OutputProcessor::StoreType::Average,
901 1 : this->Name);
902 :
903 2 : SetupOutputVariable(state,
904 : "Water Use Connections Drain Water Temperature",
905 : Constant::Units::C,
906 1 : this->DrainTemp,
907 : OutputProcessor::TimeStepType::System,
908 : OutputProcessor::StoreType::Average,
909 1 : this->Name);
910 :
911 2 : SetupOutputVariable(state,
912 : "Water Use Connections Return Water Temperature",
913 : Constant::Units::C,
914 1 : this->ReturnTemp,
915 : OutputProcessor::TimeStepType::System,
916 : OutputProcessor::StoreType::Average,
917 1 : this->Name);
918 :
919 2 : SetupOutputVariable(state,
920 : "Water Use Connections Waste Water Temperature",
921 : Constant::Units::C,
922 1 : this->WasteTemp,
923 : OutputProcessor::TimeStepType::System,
924 : OutputProcessor::StoreType::Average,
925 1 : this->Name);
926 :
927 2 : SetupOutputVariable(state,
928 : "Water Use Connections Heat Recovery Water Temperature",
929 : Constant::Units::C,
930 1 : this->RecoveryTemp,
931 : OutputProcessor::TimeStepType::System,
932 : OutputProcessor::StoreType::Average,
933 1 : this->Name);
934 :
935 2 : SetupOutputVariable(state,
936 : "Water Use Connections Heat Recovery Effectiveness",
937 : Constant::Units::None,
938 1 : this->Effectiveness,
939 : OutputProcessor::TimeStepType::System,
940 : OutputProcessor::StoreType::Average,
941 1 : this->Name);
942 :
943 2 : SetupOutputVariable(state,
944 : "Water Use Connections Heat Recovery Rate",
945 : Constant::Units::W,
946 1 : this->RecoveryRate,
947 : OutputProcessor::TimeStepType::System,
948 : OutputProcessor::StoreType::Average,
949 1 : this->Name);
950 2 : SetupOutputVariable(state,
951 : "Water Use Connections Heat Recovery Energy",
952 : Constant::Units::J,
953 1 : this->RecoveryEnergy,
954 : OutputProcessor::TimeStepType::System,
955 : OutputProcessor::StoreType::Sum,
956 1 : this->Name);
957 : // Does this go on a meter?
958 :
959 : // To do: Add report variable for starved flow when tank can't deliver?
960 :
961 1 : if (!this->StandAlone) {
962 2 : SetupOutputVariable(state,
963 : "Water Use Connections Plant Hot Water Energy",
964 : Constant::Units::J,
965 1 : this->Energy,
966 : OutputProcessor::TimeStepType::System,
967 : OutputProcessor::StoreType::Sum,
968 1 : this->Name,
969 : Constant::eResource::PlantLoopHeatingDemand,
970 : OutputProcessor::Group::Plant,
971 : OutputProcessor::EndUseCat::WaterSystem);
972 : }
973 1 : }
974 :
975 5970 : void WaterEquipmentType::CalcEquipmentFlowRates(EnergyPlusData &state)
976 : {
977 :
978 : // SUBROUTINE INFORMATION:
979 : // AUTHOR Peter Graham Ellis
980 : // DATE WRITTEN August 2006
981 :
982 : // PURPOSE OF THIS SUBROUTINE:
983 : // Calculate desired hot and cold water flow rates
984 :
985 : Real64 TempDiff;
986 5970 : Real64 constexpr EPSILON(1.e-3);
987 :
988 5970 : if (this->setupMyOutputVars) {
989 3 : this->setupOutputVars(state);
990 3 : this->setupMyOutputVars = false;
991 : }
992 :
993 5970 : if (this->Connections > 0) {
994 : // Get water temperature conditions from the CONNECTIONS object
995 5969 : this->ColdTemp = state.dataWaterUse->WaterConnections(this->Connections).ColdTemp;
996 5969 : this->HotTemp = state.dataWaterUse->WaterConnections(this->Connections).HotTemp;
997 :
998 : } else {
999 : // Get water temperature conditions from the WATER USE EQUIPMENT schedules
1000 1 : this->ColdTemp = (this->coldTempSched != nullptr) ? this->coldTempSched->getCurrentVal() : state.dataEnvrn->WaterMainsTemp;
1001 1 : this->HotTemp = (this->hotTempSched != nullptr) ? this->hotTempSched->getCurrentVal() : this->ColdTemp;
1002 : }
1003 :
1004 5970 : if (this->targetTempSched != nullptr) {
1005 5968 : this->TargetTemp = this->targetTempSched->getCurrentVal();
1006 2 : } else if (this->allowHotControl) { // If no TargetTempSchedule, but allowHotControl is set, use all hot water if applicable
1007 1 : this->TargetTemp = this->HotTemp;
1008 : } else { // If no TargetTempSchedule, use all cold water
1009 1 : this->TargetTemp = this->ColdTemp;
1010 : }
1011 :
1012 : // Get the requested total flow rate
1013 5970 : this->TotalVolFlowRate = this->PeakVolFlowRate;
1014 5970 : if (this->Zone > 0) {
1015 5 : this->TotalVolFlowRate *= state.dataHeatBal->Zone(this->Zone).Multiplier * state.dataHeatBal->Zone(this->Zone).ListMultiplier;
1016 : }
1017 5970 : if (this->flowRateFracSched != nullptr) {
1018 5965 : this->TotalVolFlowRate *= this->flowRateFracSched->getCurrentVal();
1019 : }
1020 :
1021 5970 : this->TotalMassFlowRate = this->TotalVolFlowRate * calcH2ODensity(state);
1022 :
1023 : // Calculate hot and cold water mixing at the tap
1024 5970 : if (this->TotalMassFlowRate > 0.0 && this->allowHotControl) {
1025 : // Calculate the flow rates needed to meet the target temperature
1026 5969 : if (this->TargetTemp <= this->ColdTemp + EPSILON) {
1027 : // don't need to mix (use cold) or hot water flow would be very small if within EPSILON above cold temp (use cold)
1028 1 : this->HotMassFlowRate = 0.0;
1029 1 : if (!state.dataGlobal->WarmupFlag && this->TargetTemp < this->ColdTemp) {
1030 : // print error for variables of target water temperature
1031 1 : ++this->TargetCWTempErrorCount;
1032 1 : TempDiff = this->ColdTemp - this->TargetTemp;
1033 1 : if (this->TargetCWTempErrorCount < 2) {
1034 2 : ShowWarningError(
1035 : state,
1036 2 : format("CalcEquipmentFlowRates: \"{}\" - Target water temperature is less than the cold water temperature by ({:.2R} C)",
1037 1 : this->Name,
1038 : TempDiff));
1039 2 : ShowContinueErrorTimeStamp(state, "");
1040 1 : ShowContinueError(state, format("...target water temperature = {:.2R} C", this->TargetTemp));
1041 1 : ShowContinueError(state, format("...cold water temperature = {:.2R} C", this->ColdTemp));
1042 3 : ShowContinueError(state,
1043 : "...Target water temperature should be greater than or equal to the cold water temperature. "
1044 : "Verify temperature setpoints and schedules.");
1045 : } else {
1046 0 : ShowRecurringWarningErrorAtEnd(
1047 : state,
1048 0 : format(
1049 : "\"{}\" - Target water temperature should be greater than or equal to the cold water temperature error continues...",
1050 0 : this->Name),
1051 0 : this->TargetCWTempErrIndex,
1052 : TempDiff,
1053 : TempDiff);
1054 : }
1055 : }
1056 5968 : } else if (this->TargetTemp >= this->HotTemp) {
1057 : // don't need to mix (use hot), or need to purge stagnant hot water temps (use hot)
1058 48 : this->HotMassFlowRate = this->TotalMassFlowRate;
1059 48 : if (!state.dataGlobal->WarmupFlag) {
1060 : // print error for variables of target water temperature
1061 3 : if (this->ColdTemp > (this->HotTemp + EPSILON)) {
1062 : // print error for variables of hot water temperature
1063 1 : ++this->CWHWTempErrorCount;
1064 1 : TempDiff = this->ColdTemp - this->HotTemp;
1065 1 : if (this->CWHWTempErrorCount < 2) {
1066 2 : ShowWarningError(
1067 : state,
1068 2 : format("CalcEquipmentFlowRates: \"{}\" - Hot water temperature is less than the cold water temperature by ({:.2R} C)",
1069 1 : this->Name,
1070 : TempDiff));
1071 2 : ShowContinueErrorTimeStamp(state, "");
1072 1 : ShowContinueError(state, format("...hot water temperature = {:.2R} C", this->HotTemp));
1073 1 : ShowContinueError(state, format("...cold water temperature = {:.2R} C", this->ColdTemp));
1074 3 : ShowContinueError(state,
1075 : "...Hot water temperature should be greater than or equal to the cold water temperature. "
1076 : "Verify temperature setpoints and schedules.");
1077 : } else {
1078 0 : ShowRecurringWarningErrorAtEnd(
1079 : state,
1080 0 : format("\"{}\" - Hot water temperature should be greater than the cold water temperature error continues... ",
1081 0 : this->Name),
1082 0 : this->CWHWTempErrIndex,
1083 : TempDiff,
1084 : TempDiff);
1085 : }
1086 2 : } else if (this->TargetTemp > this->HotTemp) {
1087 1 : TempDiff = this->TargetTemp - this->HotTemp;
1088 1 : ++this->TargetHWTempErrorCount;
1089 1 : if (this->TargetHWTempErrorCount < 2) {
1090 2 : ShowWarningError(state,
1091 2 : format("CalcEquipmentFlowRates: \"{}\" - Target water temperature is greater than the hot water "
1092 : "temperature by ({:.2R} C)",
1093 1 : this->Name,
1094 : TempDiff));
1095 2 : ShowContinueErrorTimeStamp(state, "");
1096 1 : ShowContinueError(state, format("...target water temperature = {:.2R} C", this->TargetTemp));
1097 1 : ShowContinueError(state, format("...hot water temperature = {:.2R} C", this->HotTemp));
1098 3 : ShowContinueError(state,
1099 : "...Target water temperature should be less than or equal to the hot water temperature. "
1100 : "Verify temperature setpoints and schedules.");
1101 : } else {
1102 0 : ShowRecurringWarningErrorAtEnd(state,
1103 0 : format("\"{}\" - Target water temperature should be less than or equal to the hot "
1104 : "water temperature error continues...",
1105 0 : this->Name),
1106 0 : this->TargetHWTempErrIndex,
1107 : TempDiff,
1108 : TempDiff);
1109 : }
1110 : }
1111 : }
1112 : } else {
1113 : // Check hot less than cold temp, else calculate hot flow.
1114 5920 : if (this->HotTemp <= this->ColdTemp + EPSILON) {
1115 : // will need to avoid divide by 0 and stagnant region. Target temp is greater than ColdTemp so use hot water
1116 : // continue using hot water until hot water temp is EPSILON C above cold water temp (i.e., avoid very small denominator)
1117 0 : this->HotMassFlowRate = this->TotalMassFlowRate;
1118 0 : if (!state.dataGlobal->WarmupFlag && this->HotTemp < this->ColdTemp) {
1119 : // print error for variables of hot water temperature
1120 0 : ++this->CWHWTempErrorCount;
1121 0 : TempDiff = this->ColdTemp - this->HotTemp;
1122 0 : if (this->CWHWTempErrorCount < 2) {
1123 0 : ShowWarningError(state,
1124 0 : format("CalcEquipmentFlowRates: \"{}\" - Hot water temperature is less than the cold water "
1125 : "temperature by ({:.2R} C)",
1126 0 : this->Name,
1127 : TempDiff));
1128 0 : ShowContinueErrorTimeStamp(state, "");
1129 0 : ShowContinueError(state, format("...hot water temperature = {:.2R} C", this->HotTemp));
1130 0 : ShowContinueError(state, format("...cold water temperature = {:.2R} C", this->ColdTemp));
1131 0 : ShowContinueError(state,
1132 : "...Hot water temperature should be greater than or equal to the cold water temperature. "
1133 : "Verify temperature setpoints and schedules.");
1134 : } else {
1135 0 : ShowRecurringWarningErrorAtEnd(
1136 : state,
1137 0 : format("\"{}\" - Hot water temperature should be greater than the cold water temperature error continues... ",
1138 0 : this->Name),
1139 0 : this->CWHWTempErrIndex,
1140 : TempDiff,
1141 : TempDiff);
1142 : }
1143 : }
1144 : } else {
1145 : // HotMassFlowRate should always be between 0 and TotalMassFlowRate
1146 5920 : this->HotMassFlowRate = this->TotalMassFlowRate * (this->TargetTemp - this->ColdTemp) / (this->HotTemp - this->ColdTemp);
1147 : }
1148 : }
1149 :
1150 5969 : this->ColdMassFlowRate = this->TotalMassFlowRate - this->HotMassFlowRate;
1151 5969 : this->MixedTemp = (this->ColdMassFlowRate * this->ColdTemp + this->HotMassFlowRate * this->HotTemp) / this->TotalMassFlowRate;
1152 : // there should be no out of bounds results
1153 5969 : assert(this->ColdMassFlowRate >= 0.0 && this->ColdMassFlowRate <= this->TotalMassFlowRate);
1154 5969 : assert(this->HotMassFlowRate >= 0.0 && this->HotMassFlowRate <= this->TotalMassFlowRate);
1155 5969 : assert(std::abs(this->HotMassFlowRate + this->ColdMassFlowRate - this->TotalMassFlowRate) < EPSILON);
1156 : } else {
1157 1 : this->HotMassFlowRate = 0.0;
1158 1 : this->ColdMassFlowRate = this->TotalMassFlowRate;
1159 1 : this->MixedTemp = this->TargetTemp;
1160 : }
1161 5970 : }
1162 :
1163 5965 : void WaterEquipmentType::CalcEquipmentDrainTemp(EnergyPlusData &state)
1164 : {
1165 :
1166 : // SUBROUTINE INFORMATION:
1167 : // AUTHOR Peter Graham Ellis
1168 : // DATE WRITTEN August 2006
1169 :
1170 : // PURPOSE OF THIS SUBROUTINE:
1171 : // Calculate drainwater temperature and heat and moisture gains to zone.
1172 :
1173 : static constexpr std::string_view RoutineName("CalcEquipmentDrainTemp");
1174 :
1175 5965 : this->SensibleRate = 0.0;
1176 5965 : this->SensibleEnergy = 0.0;
1177 5965 : this->LatentRate = 0.0;
1178 5965 : this->LatentEnergy = 0.0;
1179 :
1180 5965 : if ((this->Zone == 0) || (this->TotalMassFlowRate == 0.0)) {
1181 5965 : this->DrainTemp = this->MixedTemp;
1182 5965 : this->DrainMassFlowRate = this->TotalMassFlowRate;
1183 :
1184 : } else {
1185 0 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->Zone);
1186 :
1187 0 : if (this->sensibleFracSched == nullptr) {
1188 0 : this->SensibleRate = 0.0;
1189 0 : this->SensibleEnergy = 0.0;
1190 : } else {
1191 0 : this->SensibleRate = this->sensibleFracSched->getCurrentVal() * this->TotalMassFlowRate *
1192 0 : Psychrometrics::CPHW(Constant::InitConvTemp) * (this->MixedTemp - thisZoneHB.MAT);
1193 0 : this->SensibleEnergy = this->SensibleRate * state.dataHVACGlobal->TimeStepSysSec;
1194 : }
1195 :
1196 0 : if (this->latentFracSched == nullptr) {
1197 0 : this->LatentRate = 0.0;
1198 0 : this->LatentEnergy = 0.0;
1199 : } else {
1200 0 : Real64 ZoneHumRat = thisZoneHB.airHumRat;
1201 0 : Real64 ZoneHumRatSat = Psychrometrics::PsyWFnTdbRhPb(state,
1202 : thisZoneHB.MAT,
1203 : 1.0,
1204 0 : state.dataEnvrn->OutBaroPress,
1205 : RoutineName); // Humidratio at 100% relative humidity
1206 0 : Real64 RhoAirDry = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisZoneHB.MAT, 0.0);
1207 : Real64 ZoneMassMax =
1208 0 : (ZoneHumRatSat - ZoneHumRat) * RhoAirDry * state.dataHeatBal->Zone(this->Zone).Volume; // Max water that can be evaporated to zone
1209 0 : Real64 FlowMassMax = this->TotalMassFlowRate * state.dataHVACGlobal->TimeStepSysSec; // Max water in flow
1210 0 : Real64 MoistureMassMax = min(ZoneMassMax, FlowMassMax);
1211 :
1212 0 : this->MoistureMass = this->latentFracSched->getCurrentVal() * MoistureMassMax;
1213 0 : this->MoistureRate = this->MoistureMass / (state.dataHVACGlobal->TimeStepSysSec);
1214 :
1215 0 : this->LatentRate = this->MoistureRate * Psychrometrics::PsyHfgAirFnWTdb(ZoneHumRat, thisZoneHB.MAT);
1216 0 : this->LatentEnergy = this->LatentRate * state.dataHVACGlobal->TimeStepSysSec;
1217 : }
1218 :
1219 0 : this->DrainMassFlowRate = this->TotalMassFlowRate - this->MoistureRate;
1220 :
1221 0 : if (this->DrainMassFlowRate == 0.0) {
1222 0 : this->DrainTemp = this->MixedTemp;
1223 : } else {
1224 0 : this->DrainTemp = (this->TotalMassFlowRate * Psychrometrics::CPHW(Constant::InitConvTemp) * this->MixedTemp - this->SensibleRate -
1225 0 : this->LatentRate) /
1226 0 : (this->DrainMassFlowRate * Psychrometrics::CPHW(Constant::InitConvTemp));
1227 : }
1228 : }
1229 5965 : }
1230 :
1231 5968 : void WaterConnectionsType::InitConnections(EnergyPlusData &state)
1232 : {
1233 :
1234 : // SUBROUTINE INFORMATION:
1235 : // AUTHOR Peter Graham Ellis
1236 : // DATE WRITTEN August 2006
1237 : // MODIFIED Brent Griffith 2010, demand side update
1238 :
1239 : // Set the cold water temperature
1240 5968 : if (this->SupplyTankNum > 0) {
1241 0 : this->ColdSupplyTemp = state.dataWaterData->WaterStorage(this->SupplyTankNum).Twater;
1242 :
1243 5968 : } else if (this->coldTempSched != nullptr) {
1244 0 : this->ColdSupplyTemp = this->coldTempSched->getCurrentVal();
1245 :
1246 : } else {
1247 5968 : this->ColdSupplyTemp = state.dataEnvrn->WaterMainsTemp;
1248 : }
1249 :
1250 : // Initially set ColdTemp to the ColdSupplyTemp; with heat recovery, ColdTemp will change during iteration
1251 5968 : this->ColdTemp = this->ColdSupplyTemp;
1252 :
1253 : // Set the hot water temperature
1254 5968 : if (this->StandAlone) {
1255 0 : this->HotTemp = (this->hotTempSched != nullptr) ? this->hotTempSched->getCurrentVal() : this->ColdTemp;
1256 : } else {
1257 :
1258 5968 : if (state.dataGlobal->BeginEnvrnFlag && this->Init) {
1259 : // Clear node initial conditions
1260 4 : if (this->InletNode > 0 && this->OutletNode > 0) {
1261 4 : PlantUtilities::InitComponentNodes(state, 0.0, this->PeakMassFlowRate, this->InletNode, this->OutletNode);
1262 :
1263 4 : this->ReturnTemp = state.dataLoopNodes->Node(this->InletNode).Temp;
1264 : }
1265 :
1266 4 : this->Init = false;
1267 : }
1268 :
1269 5968 : if (!state.dataGlobal->BeginEnvrnFlag) {
1270 5944 : this->Init = true;
1271 : }
1272 :
1273 5968 : if (this->InletNode > 0) {
1274 5968 : if (!state.dataGlobal->DoingSizing) {
1275 5968 : this->HotTemp = state.dataLoopNodes->Node(this->InletNode).Temp;
1276 : } else {
1277 : // plant loop will not be running so need a value here.
1278 : // should change to use tank setpoint but water use connections don't have knowledge of the tank they are fed by
1279 0 : this->HotTemp = 60.0;
1280 : }
1281 : }
1282 : }
1283 5968 : }
1284 :
1285 5965 : void WaterConnectionsType::CalcConnectionsFlowRates(EnergyPlusData &state, bool FirstHVACIteration)
1286 : {
1287 :
1288 : // SUBROUTINE INFORMATION:
1289 : // AUTHOR Peter Graham Ellis
1290 : // DATE WRITTEN August 2006
1291 :
1292 : // PURPOSE OF THIS SUBROUTINE:
1293 : // Calculate summed values for WATER USE CONNECTIONS (to prepare to request flow from plant, and for reporting).
1294 :
1295 5965 : this->ColdMassFlowRate = 0.0;
1296 5965 : this->HotMassFlowRate = 0.0;
1297 :
1298 11930 : for (int Loop = 1; Loop <= this->NumWaterEquipment; ++Loop) {
1299 5965 : auto &thisWEq = state.dataWaterUse->WaterEquipment(this->myWaterEquipArr(Loop));
1300 :
1301 5965 : thisWEq.CalcEquipmentFlowRates(state);
1302 :
1303 5965 : this->ColdMassFlowRate += thisWEq.ColdMassFlowRate;
1304 5965 : this->HotMassFlowRate += thisWEq.HotMassFlowRate;
1305 : } // Loop
1306 :
1307 5965 : this->TotalMassFlowRate = this->ColdMassFlowRate + this->HotMassFlowRate;
1308 :
1309 5965 : if (!this->StandAlone) { // Interact with the plant loop
1310 5965 : if (this->InletNode > 0) {
1311 5965 : if (FirstHVACIteration) {
1312 : // Request the mass flow rate from the demand side manager
1313 2985 : PlantUtilities::SetComponentFlowRate(state, this->HotMassFlowRate, this->InletNode, this->OutletNode, this->plantLoc);
1314 :
1315 : } else {
1316 2980 : Real64 DesiredHotWaterMassFlow = this->HotMassFlowRate;
1317 2980 : PlantUtilities::SetComponentFlowRate(state, DesiredHotWaterMassFlow, this->InletNode, this->OutletNode, this->plantLoc);
1318 : // readjust if more than actual available mass flow rate determined by the demand side manager
1319 2980 : if ((this->HotMassFlowRate != DesiredHotWaterMassFlow) && (this->HotMassFlowRate > 0.0)) { // plant didn't give what was asked for
1320 :
1321 2980 : Real64 AvailableFraction = DesiredHotWaterMassFlow / this->HotMassFlowRate;
1322 :
1323 2980 : this->ColdMassFlowRate = this->TotalMassFlowRate - this->HotMassFlowRate; // Preserve the total mass flow rate
1324 :
1325 : // Proportionally reduce hot water and increase cold water for all WATER USE EQUIPMENT
1326 5960 : for (int Loop = 1; Loop <= this->NumWaterEquipment; ++Loop) {
1327 2980 : auto &thisWEq = state.dataWaterUse->WaterEquipment(this->myWaterEquipArr(Loop));
1328 :
1329 : // Recalculate flow rates for water equipment within connection
1330 2980 : thisWEq.HotMassFlowRate *= AvailableFraction;
1331 2980 : thisWEq.ColdMassFlowRate = thisWEq.TotalMassFlowRate - thisWEq.HotMassFlowRate;
1332 :
1333 : // Recalculate mixed water temperature
1334 2980 : if (thisWEq.TotalMassFlowRate > 0.0) {
1335 2980 : thisWEq.MixedTemp = (thisWEq.ColdMassFlowRate * thisWEq.ColdTemp + thisWEq.HotMassFlowRate * thisWEq.HotTemp) /
1336 2980 : thisWEq.TotalMassFlowRate;
1337 : } else {
1338 0 : thisWEq.MixedTemp = thisWEq.TargetTemp;
1339 : }
1340 : } // Loop
1341 : }
1342 : }
1343 : }
1344 : }
1345 :
1346 5965 : if (this->SupplyTankNum > 0) {
1347 : // Set the demand request for supply water from water storage tank
1348 0 : this->ColdVolFlowRate = this->ColdMassFlowRate / calcH2ODensity(state);
1349 0 : state.dataWaterData->WaterStorage(this->SupplyTankNum).VdotRequestDemand(this->TankDemandID) = this->ColdVolFlowRate;
1350 :
1351 : // Check if cold flow rate should be starved by restricted flow from tank
1352 : // Currently, the tank flow is not really starved--water continues to flow at the tank water temperature
1353 : // But the user can see the error by comparing report variables for TankVolFlowRate < ColdVolFlowRate
1354 0 : this->TankVolFlowRate = state.dataWaterData->WaterStorage(this->SupplyTankNum).VdotAvailDemand(this->TankDemandID);
1355 0 : this->TankMassFlowRate = this->TankVolFlowRate * calcH2ODensity(state);
1356 : }
1357 5965 : }
1358 :
1359 5965 : void WaterConnectionsType::CalcConnectionsDrainTemp(EnergyPlusData &state)
1360 : {
1361 :
1362 : // SUBROUTINE INFORMATION:
1363 : // AUTHOR Peter Graham Ellis
1364 : // DATE WRITTEN August 2006
1365 :
1366 5965 : Real64 MassFlowTempSum = 0.0;
1367 5965 : this->DrainMassFlowRate = 0.0;
1368 :
1369 11930 : for (int Loop = 1; Loop <= this->NumWaterEquipment; ++Loop) {
1370 5965 : auto &thisWEq = state.dataWaterUse->WaterEquipment(this->myWaterEquipArr(Loop));
1371 :
1372 5965 : thisWEq.CalcEquipmentDrainTemp(state);
1373 :
1374 5965 : this->DrainMassFlowRate += thisWEq.DrainMassFlowRate;
1375 5965 : MassFlowTempSum += thisWEq.DrainMassFlowRate * thisWEq.DrainTemp;
1376 : } // Loop
1377 :
1378 5965 : if (this->DrainMassFlowRate > 0.0) {
1379 5965 : this->DrainTemp = MassFlowTempSum / this->DrainMassFlowRate;
1380 : } else {
1381 0 : this->DrainTemp = this->HotTemp;
1382 : }
1383 :
1384 5965 : this->DrainVolFlowRate = this->DrainMassFlowRate * calcH2ODensity(state);
1385 5965 : }
1386 :
1387 5965 : void WaterConnectionsType::CalcConnectionsHeatRecovery(EnergyPlusData &state)
1388 : {
1389 :
1390 : // SUBROUTINE INFORMATION:
1391 : // AUTHOR Peter Graham Ellis
1392 : // DATE WRITTEN August 2006
1393 :
1394 : // PURPOSE OF THIS SUBROUTINE:
1395 : // Calculate drainwater heat recovery
1396 :
1397 5965 : if (!this->HeatRecovery) {
1398 5965 : this->RecoveryTemp = this->ColdSupplyTemp;
1399 5965 : this->ReturnTemp = this->ColdSupplyTemp;
1400 5965 : this->WasteTemp = this->DrainTemp;
1401 :
1402 0 : } else if (this->TotalMassFlowRate == 0.0) {
1403 0 : this->Effectiveness = 0.0;
1404 0 : this->RecoveryRate = 0.0;
1405 0 : this->RecoveryTemp = this->ColdSupplyTemp;
1406 0 : this->ReturnTemp = this->ColdSupplyTemp;
1407 0 : this->WasteTemp = this->DrainTemp;
1408 :
1409 : } else { // WaterConnections(WaterConnNum)%TotalMassFlowRate > 0.0
1410 :
1411 0 : switch (this->HeatRecoveryConfig) {
1412 0 : case HeatRecovConfig::Plant: {
1413 0 : this->RecoveryMassFlowRate = this->HotMassFlowRate;
1414 0 : } break;
1415 0 : case HeatRecovConfig::Equipment: {
1416 0 : this->RecoveryMassFlowRate = this->ColdMassFlowRate;
1417 0 : } break;
1418 0 : case HeatRecovConfig::PlantAndEquip: {
1419 0 : this->RecoveryMassFlowRate = this->TotalMassFlowRate;
1420 0 : } break;
1421 0 : default:
1422 0 : break;
1423 : }
1424 :
1425 0 : Real64 HXCapacityRate = Psychrometrics::CPHW(Constant::InitConvTemp) * this->RecoveryMassFlowRate;
1426 0 : Real64 DrainCapacityRate = Psychrometrics::CPHW(Constant::InitConvTemp) * this->DrainMassFlowRate;
1427 0 : Real64 MinCapacityRate = min(DrainCapacityRate, HXCapacityRate);
1428 :
1429 0 : switch (this->HeatRecoveryHX) {
1430 0 : case HeatRecovHX::Ideal: {
1431 0 : this->Effectiveness = 1.0;
1432 0 : } break;
1433 0 : case HeatRecovHX::CounterFlow: { // Unmixed
1434 0 : Real64 CapacityRatio = MinCapacityRate / max(DrainCapacityRate, HXCapacityRate);
1435 0 : Real64 NTU = this->HXUA / MinCapacityRate;
1436 0 : if (CapacityRatio == 1.0) {
1437 0 : this->Effectiveness = NTU / (1.0 + NTU);
1438 : } else {
1439 0 : Real64 ExpVal = std::exp(-NTU * (1.0 - CapacityRatio));
1440 0 : this->Effectiveness = (1.0 - ExpVal) / (1.0 - CapacityRatio * ExpVal);
1441 : }
1442 0 : } break;
1443 0 : case HeatRecovHX::CrossFlow: { // Unmixed
1444 0 : Real64 CapacityRatio = MinCapacityRate / max(DrainCapacityRate, HXCapacityRate);
1445 0 : Real64 NTU = this->HXUA / MinCapacityRate;
1446 0 : this->Effectiveness = 1.0 - std::exp((std::pow(NTU, 0.22) / CapacityRatio) * (std::exp(-CapacityRatio * std::pow(NTU, 0.78)) - 1.0));
1447 0 : } break;
1448 0 : default:
1449 0 : break;
1450 : }
1451 :
1452 0 : this->RecoveryRate = this->Effectiveness * MinCapacityRate * (this->DrainTemp - this->ColdSupplyTemp);
1453 0 : this->RecoveryTemp = this->ColdSupplyTemp + this->RecoveryRate / (Psychrometrics::CPHW(Constant::InitConvTemp) * this->TotalMassFlowRate);
1454 0 : this->WasteTemp = this->DrainTemp - this->RecoveryRate / (Psychrometrics::CPHW(Constant::InitConvTemp) * this->TotalMassFlowRate);
1455 :
1456 0 : if (this->RecoveryTankNum > 0) {
1457 0 : state.dataWaterData->WaterStorage(this->RecoveryTankNum).VdotAvailSupply(this->TankSupplyID) = this->DrainVolFlowRate;
1458 0 : state.dataWaterData->WaterStorage(this->RecoveryTankNum).TwaterSupply(this->TankSupplyID) = this->WasteTemp;
1459 : }
1460 :
1461 0 : switch (this->HeatRecoveryConfig) {
1462 0 : case HeatRecovConfig::Plant: {
1463 0 : this->TempError = 0.0; // No feedback back to the cold supply
1464 0 : this->ReturnTemp = this->RecoveryTemp;
1465 0 : } break;
1466 0 : case HeatRecovConfig::Equipment: {
1467 0 : this->TempError = std::abs(this->ColdTemp - this->RecoveryTemp);
1468 :
1469 0 : this->ColdTemp = this->RecoveryTemp;
1470 0 : this->ReturnTemp = this->ColdSupplyTemp;
1471 0 : } break;
1472 0 : case HeatRecovConfig::PlantAndEquip: {
1473 0 : this->TempError = std::abs(this->ColdTemp - this->RecoveryTemp);
1474 :
1475 0 : this->ColdTemp = this->RecoveryTemp;
1476 0 : this->ReturnTemp = this->RecoveryTemp;
1477 0 : } break;
1478 0 : default:
1479 0 : break;
1480 : }
1481 : }
1482 5965 : }
1483 :
1484 5965 : void WaterConnectionsType::UpdateWaterConnections(EnergyPlusData &state)
1485 : {
1486 :
1487 : // SUBROUTINE INFORMATION:
1488 : // AUTHOR Peter Graham Ellis
1489 : // DATE WRITTEN August 2006
1490 :
1491 : // PURPOSE OF THIS SUBROUTINE:
1492 : // Updates the node variables with local variables.
1493 :
1494 5965 : if (this->InletNode > 0 && this->OutletNode > 0) {
1495 : // Pass all variables from inlet to outlet node
1496 5965 : PlantUtilities::SafeCopyPlantNode(state, this->InletNode, this->OutletNode, this->plantLoc.loopNum);
1497 :
1498 : // Set outlet node variables that are possibly changed
1499 5965 : state.dataLoopNodes->Node(this->OutletNode).Temp = this->ReturnTemp;
1500 : // should add enthalpy update to return?
1501 : }
1502 5965 : }
1503 :
1504 505706 : void ReportStandAloneWaterUse(EnergyPlusData &state)
1505 : {
1506 :
1507 : // SUBROUTINE INFORMATION:
1508 : // AUTHOR B. Griffith, Peter Graham Ellis
1509 : // DATE WRITTEN Nov. 2011
1510 : // MODIFIED Brent Griffith, March 2010 added argument
1511 :
1512 : // PURPOSE OF THIS SUBROUTINE:
1513 : // Calculates report variables for stand alone water use
1514 :
1515 507196 : for (int WaterEquipNum = 1; WaterEquipNum <= state.dataWaterUse->numWaterEquipment; ++WaterEquipNum) {
1516 1490 : auto &thisWEq = state.dataWaterUse->WaterEquipment(WaterEquipNum);
1517 1490 : thisWEq.ColdVolFlowRate = thisWEq.ColdMassFlowRate / calcH2ODensity(state);
1518 1490 : thisWEq.HotVolFlowRate = thisWEq.HotMassFlowRate / calcH2ODensity(state);
1519 1490 : thisWEq.TotalVolFlowRate = thisWEq.ColdVolFlowRate + thisWEq.HotVolFlowRate;
1520 :
1521 1490 : thisWEq.ColdVolume = thisWEq.ColdVolFlowRate * state.dataHVACGlobal->TimeStepSysSec;
1522 1490 : thisWEq.HotVolume = thisWEq.HotVolFlowRate * state.dataHVACGlobal->TimeStepSysSec;
1523 1490 : thisWEq.TotalVolume = thisWEq.TotalVolFlowRate * state.dataHVACGlobal->TimeStepSysSec;
1524 :
1525 1490 : if (thisWEq.Connections == 0) {
1526 0 : thisWEq.Power = thisWEq.HotMassFlowRate * Psychrometrics::CPHW(Constant::InitConvTemp) * (thisWEq.HotTemp - thisWEq.ColdTemp);
1527 : } else {
1528 1490 : thisWEq.Power = thisWEq.HotMassFlowRate * Psychrometrics::CPHW(Constant::InitConvTemp) *
1529 1490 : (thisWEq.HotTemp - state.dataWaterUse->WaterConnections(thisWEq.Connections).ReturnTemp);
1530 : }
1531 :
1532 1490 : thisWEq.Energy = thisWEq.Power * state.dataHVACGlobal->TimeStepSysSec;
1533 : }
1534 505706 : }
1535 :
1536 5965 : void WaterConnectionsType::ReportWaterUse(EnergyPlusData &state)
1537 : {
1538 :
1539 : // SUBROUTINE INFORMATION:
1540 : // AUTHOR Peter Graham Ellis
1541 : // DATE WRITTEN August 2006
1542 : // MODIFIED Brent Griffith, March 2010 added argument
1543 :
1544 : // PURPOSE OF THIS SUBROUTINE:
1545 : // Calculates report variables.
1546 :
1547 11930 : for (int Loop = 1; Loop <= this->NumWaterEquipment; ++Loop) {
1548 :
1549 5965 : auto &thisWEq = state.dataWaterUse->WaterEquipment(this->myWaterEquipArr(Loop));
1550 :
1551 5965 : thisWEq.ColdVolFlowRate = thisWEq.ColdMassFlowRate / calcH2ODensity(state);
1552 5965 : thisWEq.HotVolFlowRate = thisWEq.HotMassFlowRate / calcH2ODensity(state);
1553 5965 : thisWEq.TotalVolFlowRate = thisWEq.ColdVolFlowRate + thisWEq.HotVolFlowRate;
1554 5965 : thisWEq.ColdVolume = thisWEq.ColdVolFlowRate * state.dataHVACGlobal->TimeStepSysSec;
1555 5965 : thisWEq.HotVolume = thisWEq.HotVolFlowRate * state.dataHVACGlobal->TimeStepSysSec;
1556 5965 : thisWEq.TotalVolume = thisWEq.TotalVolFlowRate * state.dataHVACGlobal->TimeStepSysSec;
1557 :
1558 5965 : if (thisWEq.Connections == 0) {
1559 0 : thisWEq.Power = thisWEq.HotMassFlowRate * Psychrometrics::CPHW(Constant::InitConvTemp) * (thisWEq.HotTemp - thisWEq.ColdTemp);
1560 : } else {
1561 5965 : thisWEq.Power = thisWEq.HotMassFlowRate * Psychrometrics::CPHW(Constant::InitConvTemp) *
1562 5965 : (thisWEq.HotTemp - state.dataWaterUse->WaterConnections(thisWEq.Connections).ReturnTemp);
1563 : }
1564 :
1565 5965 : thisWEq.Energy = thisWEq.Power * state.dataHVACGlobal->TimeStepSysSec;
1566 : }
1567 :
1568 5965 : this->ColdVolFlowRate = this->ColdMassFlowRate / calcH2ODensity(state);
1569 5965 : this->HotVolFlowRate = this->HotMassFlowRate / calcH2ODensity(state);
1570 5965 : this->TotalVolFlowRate = this->ColdVolFlowRate + this->HotVolFlowRate;
1571 5965 : this->ColdVolume = this->ColdVolFlowRate * state.dataHVACGlobal->TimeStepSysSec;
1572 5965 : this->HotVolume = this->HotVolFlowRate * state.dataHVACGlobal->TimeStepSysSec;
1573 5965 : this->TotalVolume = this->TotalVolFlowRate * state.dataHVACGlobal->TimeStepSysSec;
1574 5965 : this->Power = this->HotMassFlowRate * Psychrometrics::CPHW(Constant::InitConvTemp) * (this->HotTemp - this->ReturnTemp);
1575 5965 : this->Energy = this->Power * state.dataHVACGlobal->TimeStepSysSec;
1576 5965 : this->RecoveryEnergy = this->RecoveryRate * state.dataHVACGlobal->TimeStepSysSec;
1577 5965 : }
1578 1 : void WaterConnectionsType::oneTimeInit_new(EnergyPlusData &state)
1579 : {
1580 :
1581 1 : this->setupOutputVars(state);
1582 :
1583 1 : if (allocated(state.dataPlnt->PlantLoop) && !this->StandAlone) {
1584 1 : bool errFlag = false;
1585 2 : PlantUtilities::ScanPlantLoopsForObject(
1586 1 : state, this->Name, DataPlant::PlantEquipmentType::WaterUseConnection, this->plantLoc, errFlag, _, _, _, _, _);
1587 1 : if (errFlag) {
1588 0 : ShowFatalError(state, "InitConnections: Program terminated due to previous condition(s).");
1589 : }
1590 : }
1591 1 : }
1592 0 : void WaterConnectionsType::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
1593 : {
1594 0 : }
1595 :
1596 249958 : void CalcWaterUseZoneGains(EnergyPlusData &state)
1597 : {
1598 :
1599 : // SUBROUTINE INFORMATION:
1600 : // AUTHOR Peter Graham Ellis
1601 : // DATE WRITTEN August 2006
1602 :
1603 : // PURPOSE OF THIS SUBROUTINE:
1604 : // Calculates the zone internal gains due to water use sensible and latent loads.
1605 :
1606 : static bool MyEnvrnFlagLocal = true;
1607 :
1608 249958 : if (state.dataWaterUse->numWaterEquipment == 0) {
1609 249284 : return;
1610 : }
1611 :
1612 674 : if (state.dataGlobal->BeginEnvrnFlag && MyEnvrnFlagLocal) {
1613 2 : for (auto &e : state.dataWaterUse->WaterEquipment) {
1614 1 : e.SensibleRate = 0.0;
1615 1 : e.SensibleEnergy = 0.0;
1616 1 : e.SensibleRateNoMultiplier = 0.0;
1617 1 : e.LatentRate = 0.0;
1618 1 : e.LatentEnergy = 0.0;
1619 1 : e.LatentRateNoMultiplier = 0.0;
1620 1 : e.MixedTemp = 0.0;
1621 1 : e.TotalMassFlowRate = 0.0;
1622 1 : e.DrainTemp = 0.0;
1623 1 : e.ColdVolFlowRate = 0.0;
1624 1 : e.HotVolFlowRate = 0.0;
1625 1 : e.TotalVolFlowRate = 0.0;
1626 1 : e.ColdMassFlowRate = 0.0;
1627 1 : e.HotMassFlowRate = 0.0;
1628 1 : }
1629 1 : MyEnvrnFlagLocal = false;
1630 : }
1631 :
1632 674 : if (!state.dataGlobal->BeginEnvrnFlag) {
1633 673 : MyEnvrnFlagLocal = true;
1634 : }
1635 :
1636 1348 : for (int WaterEquipNum = 1; WaterEquipNum <= state.dataWaterUse->numWaterEquipment; ++WaterEquipNum) {
1637 674 : if (state.dataWaterUse->WaterEquipment(WaterEquipNum).Zone == 0) {
1638 674 : continue;
1639 : }
1640 0 : int ZoneNum = state.dataWaterUse->WaterEquipment(WaterEquipNum).Zone;
1641 0 : state.dataWaterUse->WaterEquipment(WaterEquipNum).SensibleRateNoMultiplier =
1642 0 : state.dataWaterUse->WaterEquipment(WaterEquipNum).SensibleRate /
1643 0 : (state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier);
1644 0 : state.dataWaterUse->WaterEquipment(WaterEquipNum).LatentRateNoMultiplier =
1645 0 : state.dataWaterUse->WaterEquipment(WaterEquipNum).LatentRate /
1646 0 : (state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier);
1647 : }
1648 : }
1649 :
1650 38784 : Real64 calcH2ODensity(EnergyPlusData &state)
1651 : {
1652 : static constexpr std::string_view RoutineName{"calcH2ODensity"};
1653 :
1654 38784 : if (state.dataWaterUse->calcRhoH2O) {
1655 5 : state.dataWaterUse->rhoH2OStd = Fluid::GetWater(state)->getDensity(state, Constant::InitConvTemp, RoutineName);
1656 5 : state.dataWaterUse->calcRhoH2O = false;
1657 : }
1658 38784 : return state.dataWaterUse->rhoH2OStd;
1659 : }
1660 :
1661 : } // namespace WaterUse
1662 : } // namespace EnergyPlus
|