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