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