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