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 <algorithm>
50 : #include <cmath>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Data/EnergyPlusData.hh>
57 : #include <EnergyPlus/DataContaminantBalance.hh>
58 : #include <EnergyPlus/DataEnvironment.hh>
59 : #include <EnergyPlus/DataHeatBalance.hh>
60 : #include <EnergyPlus/DataLoopNode.hh>
61 : #include <EnergyPlus/DataZoneEquipment.hh>
62 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
63 : #include <EnergyPlus/NodeInputManager.hh>
64 : #include <EnergyPlus/PoweredInductionUnits.hh>
65 : #include <EnergyPlus/Psychrometrics.hh>
66 : #include <EnergyPlus/PurchasedAirManager.hh>
67 : #include <EnergyPlus/UtilityRoutines.hh>
68 : #include <EnergyPlus/ZonePlenum.hh>
69 :
70 : namespace EnergyPlus::ZonePlenum {
71 : // Module containing simulation routines for both zone return and zone supply plenums
72 :
73 : // MODULE INFORMATION:
74 : // AUTHOR Peter Graham Ellis
75 : // DATE WRITTEN November 2000
76 : // MODIFIED na
77 : // RE-ENGINEERED na
78 :
79 : // PURPOSE OF THIS MODULE:
80 : // To encapsulate the data and algorithms required to
81 : // manage Air Path Zone Return Plenum Components
82 :
83 : // METHODOLOGY EMPLOYED:
84 : // The Zone Plenum
85 :
86 : // Using/Aliasing
87 : using namespace DataLoopNode;
88 : using Psychrometrics::PsyHFnTdbW;
89 : using Psychrometrics::PsyTdbFnHW;
90 :
91 : // Functions
92 :
93 2687292 : void SimAirZonePlenum(EnergyPlusData &state,
94 : std::string_view CompName,
95 : DataZoneEquipment::AirLoopHVACZone const iCompType,
96 : int &CompIndex,
97 : ObjexxFCL::Optional_bool_const FirstHVACIteration, // Autodesk:OPTIONAL Used without PRESENT check
98 : ObjexxFCL::Optional_bool_const FirstCall, // Autodesk:OPTIONAL Used without PRESENT check
99 : ObjexxFCL::Optional_bool PlenumInletChanged // Autodesk:OPTIONAL Used without PRESENT check
100 : )
101 : {
102 :
103 : // SUBROUTINE INFORMATION:
104 : // AUTHOR Peter Graham Ellis
105 : // DATE WRITTEN November 2000
106 : // MODIFIED March 2000
107 : // RE-ENGINEERED na
108 :
109 : // PURPOSE OF THIS SUBROUTINE:
110 : // This subroutine manages the ZonePlenum component simulation for both
111 : // return and supply plenums.
112 : // It is called from the SimAirLoopComponent at the system time step.
113 :
114 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
115 : int ZonePlenumNum; // The ZonePlenum that you are currently loading input into
116 :
117 : // Obtains and Allocates ZonePlenum related parameters from input file
118 2687292 : if (state.dataZonePlenum->GetInputFlag) { // First time subroutine has been entered
119 192 : GetZonePlenumInput(state);
120 192 : state.dataZonePlenum->GetInputFlag = false;
121 : }
122 :
123 2687292 : if (iCompType == DataZoneEquipment::AirLoopHVACZone::ReturnPlenum) { // 'AirLoopHVAC:ReturnPlenum'
124 : // Find the correct ZonePlenumNumber
125 2609056 : if (CompIndex == 0) {
126 283 : ZonePlenumNum = Util::FindItemInList(CompName, state.dataZonePlenum->ZoneRetPlenCond, &ZoneReturnPlenumConditions::ZonePlenumName);
127 283 : if (ZonePlenumNum == 0) {
128 0 : ShowFatalError(state, format("SimAirZonePlenum: AirLoopHVAC:ReturnPlenum not found={}", CompName));
129 : }
130 283 : CompIndex = ZonePlenumNum;
131 : } else {
132 2608773 : ZonePlenumNum = CompIndex;
133 2608773 : if (ZonePlenumNum > state.dataZonePlenum->NumZoneReturnPlenums || ZonePlenumNum < 1) {
134 0 : ShowFatalError(
135 : state,
136 0 : format("SimAirZonePlenum: Invalid CompIndex passed={}, Number of AirLoopHVAC:ReturnPlenum={}, AirLoopHVAC:ReturnPlenum name={}",
137 : ZonePlenumNum,
138 0 : state.dataZonePlenum->NumZoneReturnPlenums,
139 : CompName));
140 : }
141 2608773 : if (state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).checkEquipName) {
142 284 : if (CompName != state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZonePlenumName) {
143 0 : ShowFatalError(state,
144 0 : format("SimAirZonePlenum: Invalid CompIndex passed={}, AirLoopHVAC:ReturnPlenum name={}, stored "
145 : "AirLoopHVAC:ReturnPlenum Name for that index={}",
146 : ZonePlenumNum,
147 : CompName,
148 0 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZonePlenumName));
149 : }
150 284 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).checkEquipName = false;
151 : }
152 : }
153 :
154 2609056 : InitAirZoneReturnPlenum(state, ZonePlenumNum); // Initialize all ZonePlenum related parameters
155 :
156 2609056 : CalcAirZoneReturnPlenum(state, ZonePlenumNum);
157 :
158 2609056 : UpdateAirZoneReturnPlenum(state, ZonePlenumNum); // Update the current ZonePlenum to the outlet nodes
159 :
160 78236 : } else if (iCompType == DataZoneEquipment::AirLoopHVACZone::SupplyPlenum) { // 'AirLoopHVAC:SupplyPlenum'
161 : // Find the correct ZonePlenumNumber
162 78236 : if (CompIndex == 0) {
163 8 : ZonePlenumNum = Util::FindItemInList(CompName, state.dataZonePlenum->ZoneSupPlenCond, &ZoneSupplyPlenumConditions::ZonePlenumName);
164 8 : if (ZonePlenumNum == 0) {
165 0 : ShowFatalError(state, format("SimAirZonePlenum: AirLoopHVAC:SupplyPlenum not found={}", CompName));
166 : }
167 8 : CompIndex = ZonePlenumNum;
168 : } else {
169 78228 : ZonePlenumNum = CompIndex;
170 78228 : if (ZonePlenumNum > state.dataZonePlenum->NumZoneSupplyPlenums || ZonePlenumNum < 1) {
171 0 : ShowFatalError(
172 : state,
173 0 : format("SimAirZonePlenum: Invalid CompIndex passed={}, Number of AirLoopHVAC:SupplyPlenum={}, AirLoopHVAC:SupplyPlenum name={}",
174 : ZonePlenumNum,
175 0 : state.dataZonePlenum->NumZoneReturnPlenums,
176 : CompName));
177 : }
178 78228 : if (state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).checkEquipName) {
179 8 : if (CompName != state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZonePlenumName) {
180 0 : ShowFatalError(state,
181 0 : format("SimAirZonePlenum: Invalid CompIndex passed={}, AirLoopHVAC:SupplyPlenum name={}, stored "
182 : "AirLoopHVAC:SupplyPlenum Name for that index={}",
183 : ZonePlenumNum,
184 : CompName,
185 0 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZonePlenumName));
186 : }
187 8 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).checkEquipName = false;
188 : }
189 : }
190 :
191 78236 : InitAirZoneSupplyPlenum(state, ZonePlenumNum, FirstHVACIteration, FirstCall); // Initialize all ZonePlenum related parameters
192 :
193 78236 : CalcAirZoneSupplyPlenum(state, ZonePlenumNum, FirstCall);
194 : // Update the current ZonePlenum to the outlet nodes
195 78236 : UpdateAirZoneSupplyPlenum(state, ZonePlenumNum, PlenumInletChanged, FirstCall);
196 :
197 : } else {
198 0 : ShowSevereError(state, format("SimAirZonePlenum: Errors in Plenum={}", CompName));
199 0 : ShowContinueError(state, format("ZonePlenum: Unhandled plenum type found:{}", iCompType));
200 0 : ShowFatalError(state, "Preceding conditions cause termination.");
201 : }
202 2687292 : }
203 :
204 198 : void GetZonePlenumInput(EnergyPlusData &state)
205 : {
206 :
207 : // SUBROUTINE INFORMATION:
208 : // AUTHOR Peter Graham Ellis
209 : // DATE WRITTEN November 2000
210 : // MODIFIED August 2003, FCW: For each zone with a return air plenum put the ZoneRetPlenCond
211 : // number for the return air plenum in the ZoneEquipConfig array for the zone
212 : // for later access to the zone's return air plenum conditions.
213 : // RE-ENGINEERED na
214 :
215 : // PURPOSE OF THIS SUBROUTINE:
216 : // This subroutine is the main routine to call other input routines and Get routines
217 :
218 : // METHODOLOGY EMPLOYED:
219 : // Uses the status flags to trigger events.
220 :
221 : // Using/Aliasing
222 : using DataZoneEquipment::EquipConfiguration;
223 : using NodeInputManager::CheckUniqueNodeNumbers;
224 : using NodeInputManager::EndUniqueNodeCheck;
225 : using NodeInputManager::GetNodeNums;
226 : using NodeInputManager::GetOnlySingleNode;
227 : using NodeInputManager::InitUniqueNodeCheck;
228 : using PoweredInductionUnits::PIUInducesPlenumAir;
229 : using PurchasedAirManager::CheckPurchasedAirForReturnPlenum;
230 :
231 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
232 : int ZoneEquipConfigLoop;
233 : int NumAlphas;
234 : int NumNums;
235 : int NumArgs;
236 : int NumNodes;
237 198 : Array1D_int NodeNums;
238 : int MaxNums;
239 : int MaxAlphas;
240 : int NodeNum;
241 : int IOStat;
242 198 : Array1D<Real64> NumArray; // Numeric input items for object
243 198 : std::string CurrentModuleObject; // for ease in getting objects
244 198 : Array1D_string AlphArray; // Alpha input items for object
245 198 : Array1D_string cAlphaFields; // Alpha field names
246 198 : Array1D_string cNumericFields; // Numeric field names
247 198 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
248 198 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
249 198 : bool ErrorsFound(false);
250 : bool NodeListError; // Flag for node list error
251 : bool UniqueNodeError;
252 : static constexpr std::string_view RoutineName("GetZonePlenumInput: "); // include trailing blank space
253 198 : std::string InducedNodeListName;
254 :
255 198 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "AirLoopHVAC:ReturnPlenum", NumArgs, NumAlphas, NumNums);
256 198 : MaxNums = NumNums;
257 198 : MaxAlphas = NumAlphas;
258 198 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "AirLoopHVAC:SupplyPlenum", NumArgs, NumAlphas, NumNums);
259 198 : MaxNums = max(NumNums, MaxNums);
260 198 : MaxAlphas = max(NumAlphas, MaxAlphas);
261 198 : AlphArray.allocate(MaxAlphas);
262 198 : cAlphaFields.allocate(MaxAlphas);
263 198 : cNumericFields.allocate(MaxNums);
264 198 : NumArray.dimension(MaxNums, 0.0);
265 198 : lAlphaBlanks.dimension(MaxAlphas, true);
266 198 : lNumericBlanks.dimension(MaxNums, true);
267 198 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "NodeList", NumArgs, NumAlphas, NumNums);
268 198 : NodeNums.dimension(NumArgs, 0);
269 :
270 198 : InducedNodeListName = "";
271 :
272 198 : state.dataZonePlenum->NumZoneReturnPlenums = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirLoopHVAC:ReturnPlenum");
273 198 : state.dataZonePlenum->NumZoneSupplyPlenums = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirLoopHVAC:SupplyPlenum");
274 :
275 198 : if (state.dataZonePlenum->NumZoneReturnPlenums > 0) {
276 190 : state.dataZonePlenum->ZoneRetPlenCond.allocate(state.dataZonePlenum->NumZoneReturnPlenums);
277 : }
278 198 : if (state.dataZonePlenum->NumZoneSupplyPlenums > 0) {
279 6 : state.dataZonePlenum->ZoneSupPlenCond.allocate(state.dataZonePlenum->NumZoneSupplyPlenums);
280 : }
281 :
282 198 : InitUniqueNodeCheck(state, "AirLoopHVAC:ReturnPlenum");
283 482 : for (int ZonePlenumNum = 1; ZonePlenumNum <= state.dataZonePlenum->NumZoneReturnPlenums; ++ZonePlenumNum) {
284 :
285 284 : CurrentModuleObject = "AirLoopHVAC:ReturnPlenum";
286 :
287 284 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
288 : CurrentModuleObject,
289 : ZonePlenumNum,
290 : AlphArray,
291 : NumAlphas,
292 : NumArray,
293 : NumNums,
294 : IOStat,
295 : lNumericBlanks,
296 : lAlphaBlanks,
297 : cAlphaFields,
298 : cNumericFields);
299 284 : Util::IsNameEmpty(state, AlphArray(1), CurrentModuleObject, ErrorsFound);
300 :
301 284 : auto &thisRetPlenum = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum);
302 284 : thisRetPlenum.ZonePlenumName = AlphArray(1);
303 :
304 : // Check if this zone is also used in another return plenum
305 284 : IOStat = Util::FindItemInList(AlphArray(2), state.dataZonePlenum->ZoneRetPlenCond, &ZoneReturnPlenumConditions::ZoneName, ZonePlenumNum - 1);
306 284 : if (IOStat != 0) {
307 0 : ShowSevereError(state,
308 0 : format("{}{} \"{}\" is used more than once as a {}.", RoutineName, cAlphaFields(2), AlphArray(2), CurrentModuleObject));
309 0 : ShowContinueError(state, format("..Only one {} object may be connected to a given zone.", CurrentModuleObject));
310 0 : ShowContinueError(state, format("..occurs in {} = {}", CurrentModuleObject, AlphArray(1)));
311 0 : ErrorsFound = true;
312 : }
313 284 : thisRetPlenum.ZoneName = AlphArray(2);
314 : // put the X-Ref to the zone heat balance data structure
315 284 : thisRetPlenum.ActualZoneNum = Util::FindItemInList(AlphArray(2), state.dataHeatBal->Zone);
316 284 : if (thisRetPlenum.ActualZoneNum == 0) {
317 0 : ShowSevereError(state, format("For {} = {}, {} = {} not found.", CurrentModuleObject, AlphArray(1), cAlphaFields(2), AlphArray(2)));
318 0 : ErrorsFound = true;
319 0 : continue;
320 : } else {
321 284 : state.dataHeatBal->Zone(thisRetPlenum.ActualZoneNum).IsReturnPlenum = true;
322 284 : state.dataHeatBal->Zone(thisRetPlenum.ActualZoneNum).PlenumCondNum = ZonePlenumNum;
323 : }
324 : // Check if this zone is used as a controlled zone
325 284 : ZoneEquipConfigLoop = Util::FindItemInList(AlphArray(2), state.dataZoneEquip->ZoneEquipConfig, &EquipConfiguration::ZoneName);
326 284 : if (ZoneEquipConfigLoop != 0) {
327 0 : ShowSevereError(
328 : state,
329 0 : format(
330 : "{}{} \"{}\" is a controlled zone. It cannot be used as a {}", RoutineName, cAlphaFields(2), AlphArray(2), CurrentModuleObject));
331 0 : ShowContinueError(state, format("..occurs in {} = {}", CurrentModuleObject, AlphArray(1)));
332 0 : ErrorsFound = true;
333 : }
334 :
335 284 : thisRetPlenum.ZoneNodeName = AlphArray(3);
336 284 : thisRetPlenum.ZoneNodeNum = GetOnlySingleNode(state,
337 284 : AlphArray(3),
338 : ErrorsFound,
339 : DataLoopNode::ConnectionObjectType::AirLoopHVACReturnPlenum,
340 284 : AlphArray(1),
341 : DataLoopNode::NodeFluidType::Air,
342 : DataLoopNode::ConnectionType::ZoneNode,
343 : NodeInputManager::CompFluidStream::Primary,
344 : ObjectIsNotParent);
345 : // Insert the Plenum Zone Number into the Zone Heat Balance data structure for later reference
346 284 : state.dataHeatBal->Zone(thisRetPlenum.ActualZoneNum).SystemZoneNodeNumber = thisRetPlenum.ZoneNodeNum;
347 : // SpaceHB TODO: For now, assign the same system node to the spaces in the zone
348 568 : for (int spaceNum : state.dataHeatBal->Zone(thisRetPlenum.ActualZoneNum).spaceIndexes) {
349 284 : state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber = thisRetPlenum.ZoneNodeNum;
350 284 : }
351 :
352 284 : thisRetPlenum.OutletNode = GetOnlySingleNode(state,
353 284 : AlphArray(4),
354 : ErrorsFound,
355 : DataLoopNode::ConnectionObjectType::AirLoopHVACReturnPlenum,
356 284 : AlphArray(1),
357 : DataLoopNode::NodeFluidType::Air,
358 : DataLoopNode::ConnectionType::Outlet,
359 : NodeInputManager::CompFluidStream::Primary,
360 : ObjectIsNotParent);
361 :
362 284 : InducedNodeListName = AlphArray(5);
363 284 : NodeListError = false;
364 568 : GetNodeNums(state,
365 : InducedNodeListName,
366 : NumNodes,
367 : NodeNums,
368 : NodeListError,
369 : DataLoopNode::NodeFluidType::Air,
370 : DataLoopNode::ConnectionObjectType::AirLoopHVACReturnPlenum,
371 284 : thisRetPlenum.ZonePlenumName,
372 : DataLoopNode::ConnectionType::InducedAir,
373 : NodeInputManager::CompFluidStream::Primary,
374 : ObjectIsNotParent,
375 : false,
376 284 : cAlphaFields(5));
377 :
378 284 : if (!NodeListError) {
379 284 : thisRetPlenum.NumInducedNodes = NumNodes;
380 284 : thisRetPlenum.InducedNode.allocate(thisRetPlenum.NumInducedNodes);
381 284 : thisRetPlenum.InducedMassFlowRate.allocate(thisRetPlenum.NumInducedNodes);
382 284 : thisRetPlenum.InducedMassFlowRateMaxAvail.allocate(thisRetPlenum.NumInducedNodes);
383 284 : thisRetPlenum.InducedMassFlowRateMinAvail.allocate(thisRetPlenum.NumInducedNodes);
384 284 : thisRetPlenum.InducedTemp.allocate(thisRetPlenum.NumInducedNodes);
385 284 : thisRetPlenum.InducedHumRat.allocate(thisRetPlenum.NumInducedNodes);
386 284 : thisRetPlenum.InducedEnthalpy.allocate(thisRetPlenum.NumInducedNodes);
387 284 : thisRetPlenum.InducedPressure.allocate(thisRetPlenum.NumInducedNodes);
388 284 : thisRetPlenum.InducedCO2.allocate(thisRetPlenum.NumInducedNodes);
389 284 : thisRetPlenum.InducedGenContam.allocate(thisRetPlenum.NumInducedNodes);
390 284 : thisRetPlenum.InducedMassFlowRate = 0.0;
391 284 : thisRetPlenum.InducedMassFlowRateMaxAvail = 0.0;
392 284 : thisRetPlenum.InducedMassFlowRateMinAvail = 0.0;
393 284 : thisRetPlenum.InducedTemp = 0.0;
394 284 : thisRetPlenum.InducedHumRat = 0.0;
395 284 : thisRetPlenum.InducedEnthalpy = 0.0;
396 284 : thisRetPlenum.InducedPressure = 0.0;
397 284 : thisRetPlenum.InducedCO2 = 0.0;
398 284 : thisRetPlenum.InducedGenContam = 0.0;
399 310 : for (NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
400 26 : thisRetPlenum.InducedNode(NodeNum) = NodeNums(NodeNum);
401 26 : UniqueNodeError = false;
402 26 : if (!CheckPurchasedAirForReturnPlenum(state, ZonePlenumNum)) {
403 26 : CheckUniqueNodeNumbers(state, "Return Plenum Induced Air Nodes", UniqueNodeError, NodeNums(NodeNum), CurrentModuleObject);
404 26 : if (UniqueNodeError) {
405 0 : ShowContinueError(state, format("Occurs for ReturnPlenum = {}", AlphArray(1)));
406 0 : ErrorsFound = true;
407 : }
408 26 : PIUInducesPlenumAir(state, thisRetPlenum.InducedNode(NodeNum), ZonePlenumNum);
409 : }
410 : }
411 : } else {
412 0 : ShowContinueError(
413 : state,
414 0 : format("Invalid Induced Air Outlet Node or NodeList name in AirLoopHVAC:ReturnPlenum object = {}", thisRetPlenum.ZonePlenumName));
415 0 : ErrorsFound = true;
416 : }
417 :
418 284 : thisRetPlenum.NumInletNodes = NumAlphas - 5;
419 :
420 974 : for (auto &e : state.dataZonePlenum->ZoneRetPlenCond) {
421 690 : e.InitFlag = true;
422 284 : }
423 :
424 284 : thisRetPlenum.InletNode.allocate(thisRetPlenum.NumInletNodes);
425 284 : thisRetPlenum.InletMassFlowRate.allocate(thisRetPlenum.NumInletNodes);
426 284 : thisRetPlenum.InletMassFlowRateMaxAvail.allocate(thisRetPlenum.NumInletNodes);
427 284 : thisRetPlenum.InletMassFlowRateMinAvail.allocate(thisRetPlenum.NumInletNodes);
428 284 : thisRetPlenum.InletTemp.allocate(thisRetPlenum.NumInletNodes);
429 284 : thisRetPlenum.InletHumRat.allocate(thisRetPlenum.NumInletNodes);
430 284 : thisRetPlenum.InletEnthalpy.allocate(thisRetPlenum.NumInletNodes);
431 284 : thisRetPlenum.InletPressure.allocate(thisRetPlenum.NumInletNodes);
432 284 : thisRetPlenum.ZoneEqNum.allocate(thisRetPlenum.NumInletNodes);
433 :
434 284 : thisRetPlenum.InletNode = 0;
435 284 : thisRetPlenum.InletMassFlowRate = 0.0;
436 284 : thisRetPlenum.InletMassFlowRateMaxAvail = 0.0;
437 284 : thisRetPlenum.InletMassFlowRateMinAvail = 0.0;
438 284 : thisRetPlenum.InletTemp = 0.0;
439 284 : thisRetPlenum.InletHumRat = 0.0;
440 284 : thisRetPlenum.InletEnthalpy = 0.0;
441 284 : thisRetPlenum.InletPressure = 0.0;
442 284 : thisRetPlenum.OutletMassFlowRate = 0.0;
443 284 : thisRetPlenum.OutletMassFlowRateMaxAvail = 0.0;
444 284 : thisRetPlenum.OutletMassFlowRateMinAvail = 0.0;
445 284 : thisRetPlenum.OutletTemp = 0.0;
446 284 : thisRetPlenum.OutletHumRat = 0.0;
447 284 : thisRetPlenum.OutletEnthalpy = 0.0;
448 284 : thisRetPlenum.OutletPressure = 0.0;
449 284 : thisRetPlenum.ZoneTemp = 0.0;
450 284 : thisRetPlenum.ZoneHumRat = 0.0;
451 284 : thisRetPlenum.ZoneEnthalpy = 0.0;
452 :
453 1599 : for (NodeNum = 1; NodeNum <= thisRetPlenum.NumInletNodes; ++NodeNum) {
454 :
455 2630 : thisRetPlenum.InletNode(NodeNum) = GetOnlySingleNode(state,
456 1315 : AlphArray(5 + NodeNum),
457 : ErrorsFound,
458 : DataLoopNode::ConnectionObjectType::AirLoopHVACReturnPlenum,
459 1315 : AlphArray(1),
460 : DataLoopNode::NodeFluidType::Air,
461 : DataLoopNode::ConnectionType::Inlet,
462 : NodeInputManager::CompFluidStream::Primary,
463 : ObjectIsNotParent);
464 : }
465 :
466 : } // end AirLoopHVAC:ReturnPlenum Loop
467 198 : EndUniqueNodeCheck(state, "AirLoopHVAC:ReturnPlenum");
468 :
469 206 : for (int ZonePlenumNum = 1; ZonePlenumNum <= state.dataZonePlenum->NumZoneSupplyPlenums; ++ZonePlenumNum) {
470 8 : CurrentModuleObject = "AirLoopHVAC:SupplyPlenum";
471 :
472 8 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
473 : CurrentModuleObject,
474 : ZonePlenumNum,
475 : AlphArray,
476 : NumAlphas,
477 : NumArray,
478 : NumNums,
479 : IOStat,
480 : lNumericBlanks,
481 : lAlphaBlanks,
482 : cAlphaFields,
483 : cNumericFields);
484 8 : Util::IsNameEmpty(state, AlphArray(1), CurrentModuleObject, ErrorsFound);
485 :
486 8 : auto &thisSupPlenum = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum);
487 8 : thisSupPlenum.ZonePlenumName = AlphArray(1);
488 :
489 : // Check if this zone is also used in another plenum
490 8 : IOStat = Util::FindItemInList(AlphArray(2), state.dataZonePlenum->ZoneSupPlenCond, &ZoneSupplyPlenumConditions::ZoneName, ZonePlenumNum - 1);
491 8 : if (IOStat != 0) {
492 0 : ShowSevereError(state,
493 0 : format("{}{} \"{}\" is used more than once as a {}.", RoutineName, cAlphaFields(2), AlphArray(2), CurrentModuleObject));
494 0 : ShowContinueError(state, format("..Only one {} object may be connected to a given zone.", CurrentModuleObject));
495 0 : ShowContinueError(state, format("..occurs in {} = {}", CurrentModuleObject, AlphArray(1)));
496 0 : ErrorsFound = true;
497 : }
498 8 : if (state.dataZonePlenum->NumZoneReturnPlenums > 0) { // Check if this zone is also used in another plenum
499 2 : IOStat = Util::FindItemInList(AlphArray(2), state.dataZonePlenum->ZoneRetPlenCond, &ZoneReturnPlenumConditions::ZoneName);
500 2 : if (IOStat != 0) {
501 0 : ShowSevereError(state,
502 0 : format("{}{} \"{}\" is used more than once as a {} or AirLoopHVAC:ReturnPlenum.",
503 : RoutineName,
504 : cAlphaFields(2),
505 : AlphArray(2),
506 : CurrentModuleObject));
507 0 : ShowContinueError(state,
508 0 : format("..Only one {} or AirLoopHVAC:ReturnPlenum object may be connected to a given zone.", CurrentModuleObject));
509 0 : ShowContinueError(state, format("..occurs in {} = {}", CurrentModuleObject, AlphArray(1)));
510 0 : ErrorsFound = true;
511 : }
512 : }
513 8 : thisSupPlenum.ZoneName = AlphArray(2);
514 : // put the X-Ref to the zone heat balance data structure
515 8 : thisSupPlenum.ActualZoneNum = Util::FindItemInList(AlphArray(2), state.dataHeatBal->Zone);
516 8 : if (thisSupPlenum.ActualZoneNum == 0) {
517 0 : ShowSevereError(state, format("For {} = {}, {} = {} not found.", CurrentModuleObject, AlphArray(1), cAlphaFields(2), AlphArray(2)));
518 0 : ErrorsFound = true;
519 0 : continue;
520 : } else {
521 8 : state.dataHeatBal->Zone(thisSupPlenum.ActualZoneNum).IsSupplyPlenum = true;
522 8 : state.dataHeatBal->Zone(thisSupPlenum.ActualZoneNum).PlenumCondNum = ZonePlenumNum;
523 : }
524 : // Check if this zone is used as a controlled zone
525 8 : if (std::any_of(state.dataZoneEquip->ZoneEquipConfig.begin(), state.dataZoneEquip->ZoneEquipConfig.end(), [](EquipConfiguration const &e) {
526 10 : return e.IsControlled;
527 : })) {
528 8 : ZoneEquipConfigLoop = Util::FindItemInList(AlphArray(2), state.dataZoneEquip->ZoneEquipConfig, &EquipConfiguration::ZoneName);
529 8 : if (ZoneEquipConfigLoop != 0) {
530 0 : ShowSevereError(state,
531 0 : format("{}{} \"{}\" is a controlled zone. It cannot be used as a {} or AirLoopHVAC:ReturnPlenum.",
532 : RoutineName,
533 : cAlphaFields(2),
534 : AlphArray(2),
535 : CurrentModuleObject));
536 0 : ShowContinueError(state, format("..occurs in {} = {}", CurrentModuleObject, AlphArray(1)));
537 0 : ErrorsFound = true;
538 : }
539 : }
540 : // Check if this is also used as a return plenum
541 : // *** This next IF loop looks wrong. Sent e-mail to Peter/Brent 8/14/08 for clarification ****
542 : // IF (NumZoneReturnPlenums > 0) THEN
543 : // IOSTAT=Util::FindItemInList(AlphArray(1),ZoneRetPlenCond%ZoneName,NumZoneReturnPlenums)
544 : // IF (IOStat /= 0) THEN
545 : // CALL ShowSevereError(state, RoutineName//'Plenum "'//TRIM(AlphArray(2))// &
546 : // '" is a controlled zone. It cannot be used as a '// &
547 : // 'SUPPLY PLENUM or RETURN PLENUM.')
548 : // CALL ShowContinueError(state, '..occurs in '//TRIM(CurrentModuleObject)//' = '//TRIM(AlphArray(1)))
549 : // ErrorsFound=.TRUE.
550 : // ENDIF
551 : // ENDIF
552 :
553 8 : thisSupPlenum.ZoneNodeName = AlphArray(3);
554 8 : thisSupPlenum.ZoneNodeNum = GetOnlySingleNode(state,
555 8 : AlphArray(3),
556 : ErrorsFound,
557 : DataLoopNode::ConnectionObjectType::AirLoopHVACSupplyPlenum,
558 8 : AlphArray(1),
559 : DataLoopNode::NodeFluidType::Air,
560 : DataLoopNode::ConnectionType::ZoneNode,
561 : NodeInputManager::CompFluidStream::Primary,
562 : ObjectIsNotParent);
563 : // Insert the Plenum Zone Number into the Zone Heat Balance data structure for later reference
564 8 : state.dataHeatBal->Zone(thisSupPlenum.ActualZoneNum).SystemZoneNodeNumber = thisSupPlenum.ZoneNodeNum;
565 : // SpaceHB TODO: For now, assign the same system node to the spaces in the zone
566 16 : for (int spaceNum : state.dataHeatBal->Zone(thisSupPlenum.ActualZoneNum).spaceIndexes) {
567 8 : state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber = thisSupPlenum.ZoneNodeNum;
568 8 : }
569 :
570 8 : thisSupPlenum.InletNode = GetOnlySingleNode(state,
571 8 : AlphArray(4),
572 : ErrorsFound,
573 : DataLoopNode::ConnectionObjectType::AirLoopHVACSupplyPlenum,
574 8 : AlphArray(1),
575 : DataLoopNode::NodeFluidType::Air,
576 : DataLoopNode::ConnectionType::Inlet,
577 : NodeInputManager::CompFluidStream::Primary,
578 : ObjectIsNotParent);
579 :
580 8 : thisSupPlenum.NumOutletNodes = NumAlphas - 4;
581 :
582 20 : for (auto &e : state.dataZonePlenum->ZoneSupPlenCond) {
583 12 : e.InitFlag = true;
584 8 : }
585 :
586 8 : thisSupPlenum.OutletNode.allocate(thisSupPlenum.NumOutletNodes);
587 8 : thisSupPlenum.OutletMassFlowRate.allocate(thisSupPlenum.NumOutletNodes);
588 8 : thisSupPlenum.OutletMassFlowRateMaxAvail.allocate(thisSupPlenum.NumOutletNodes);
589 8 : thisSupPlenum.OutletMassFlowRateMinAvail.allocate(thisSupPlenum.NumOutletNodes);
590 8 : thisSupPlenum.OutletTemp.allocate(thisSupPlenum.NumOutletNodes);
591 8 : thisSupPlenum.OutletHumRat.allocate(thisSupPlenum.NumOutletNodes);
592 8 : thisSupPlenum.OutletEnthalpy.allocate(thisSupPlenum.NumOutletNodes);
593 8 : thisSupPlenum.OutletPressure.allocate(thisSupPlenum.NumOutletNodes);
594 :
595 8 : thisSupPlenum.OutletNode = 0;
596 8 : thisSupPlenum.OutletMassFlowRate = 0.0;
597 8 : thisSupPlenum.OutletMassFlowRateMaxAvail = 0.0;
598 8 : thisSupPlenum.OutletMassFlowRateMinAvail = 0.0;
599 8 : thisSupPlenum.OutletTemp = 0.0;
600 8 : thisSupPlenum.OutletHumRat = 0.0;
601 8 : thisSupPlenum.OutletEnthalpy = 0.0;
602 8 : thisSupPlenum.OutletPressure = 0.0;
603 8 : thisSupPlenum.InletMassFlowRate = 0.0;
604 8 : thisSupPlenum.InletMassFlowRateMaxAvail = 0.0;
605 8 : thisSupPlenum.InletMassFlowRateMinAvail = 0.0;
606 8 : thisSupPlenum.InletTemp = 0.0;
607 8 : thisSupPlenum.InletHumRat = 0.0;
608 8 : thisSupPlenum.InletEnthalpy = 0.0;
609 8 : thisSupPlenum.InletPressure = 0.0;
610 8 : thisSupPlenum.ZoneTemp = 0.0;
611 8 : thisSupPlenum.ZoneHumRat = 0.0;
612 8 : thisSupPlenum.ZoneEnthalpy = 0.0;
613 :
614 20 : for (NodeNum = 1; NodeNum <= thisSupPlenum.NumOutletNodes; ++NodeNum) {
615 :
616 24 : thisSupPlenum.OutletNode(NodeNum) = GetOnlySingleNode(state,
617 12 : AlphArray(4 + NodeNum),
618 : ErrorsFound,
619 : DataLoopNode::ConnectionObjectType::AirLoopHVACSupplyPlenum,
620 12 : AlphArray(1),
621 : DataLoopNode::NodeFluidType::Air,
622 : DataLoopNode::ConnectionType::Outlet,
623 : NodeInputManager::CompFluidStream::Primary,
624 : ObjectIsNotParent);
625 : }
626 :
627 : } // end AirLoopHVAC:SupplyPlenum Loop
628 :
629 198 : AlphArray.deallocate();
630 198 : NumArray.deallocate();
631 198 : cAlphaFields.deallocate();
632 198 : cNumericFields.deallocate();
633 198 : lAlphaBlanks.deallocate();
634 198 : lNumericBlanks.deallocate();
635 198 : NodeNums.deallocate();
636 :
637 198 : if (ErrorsFound) {
638 0 : ShowFatalError(state, format("{}Errors found in input. Preceding condition(s) cause termination.", RoutineName));
639 : }
640 198 : }
641 :
642 2609056 : void InitAirZoneReturnPlenum(EnergyPlusData &state, int const ZonePlenumNum)
643 : {
644 :
645 : // SUBROUTINE INFORMATION:
646 : // AUTHOR Peter Graham Ellis
647 : // DATE WRITTEN November 2000
648 : // MODIFIED na
649 : // RE-ENGINEERED na
650 :
651 : // PURPOSE OF THIS SUBROUTINE:
652 : // This subroutine is for initializations of the ZonePlenum components.
653 :
654 : // METHODOLOGY EMPLOYED:
655 : // Uses the status flags to trigger events.
656 :
657 : // Using/Aliasing
658 :
659 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
660 : int InletNode;
661 2609056 : int InducedNode(0);
662 : int InletNodeLoop;
663 : int ZoneNodeNum;
664 : int NodeNum;
665 : int ZonePlenumLoop;
666 : int PlenumZoneNum;
667 : int ZoneEquipConfigLoop; // Loop number of ZoneEquipConfig derived type
668 : int ADUNum; // air distribution unit index
669 : int NumADUsToPlen; // number of ADUs that might leak to this plenum
670 : int ADUsToPlenIndex; // index of an ADU that might leak to this plenum in the plenum ADU list
671 :
672 : // Do the one time initializations
673 2609056 : if (state.dataZonePlenum->InitAirZoneReturnPlenumOneTimeFlag) {
674 :
675 : // For each zone with a return air plenum put the ZoneRetPlenCond number for the return air plenum
676 : // in the ZoneEquipConfig array for the zone. This allows direct access of the zone's return air
677 : // plenum conditions, such as plenum temperature and air flow. Also establish and save connections
678 : // to the Air Distribution Units. This is needed for the simple duct leakage calculation.
679 :
680 474 : for (ZonePlenumLoop = 1; ZonePlenumLoop <= state.dataZonePlenum->NumZoneReturnPlenums; ++ZonePlenumLoop) {
681 284 : ADUsToPlenIndex = 0;
682 284 : NumADUsToPlen = 0;
683 284 : if (state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).NumInletNodes > 0) {
684 1599 : for (InletNodeLoop = 1; InletNodeLoop <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).NumInletNodes; ++InletNodeLoop) {
685 1315 : InletNode = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).InletNode(InletNodeLoop);
686 : // Loop through ZoneEquipConfig's and look for return air node value = InletNode
687 16780 : for (ZoneEquipConfigLoop = 1; ZoneEquipConfigLoop <= state.dataGlobal->NumOfZones; ++ZoneEquipConfigLoop) {
688 15465 : if (!state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigLoop).IsControlled) continue;
689 25682 : for (int retNode = 1; retNode <= state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigLoop).NumReturnNodes; ++retNode) {
690 12841 : if (state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigLoop).ReturnNode(retNode) == InletNode) {
691 1310 : state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigLoop).ReturnNodePlenumNum = ZonePlenumLoop;
692 1310 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).ZoneEqNum(InletNodeLoop) = ZoneEquipConfigLoop;
693 : }
694 : }
695 : }
696 : // count the ADUs that can leak to this plenum
697 14206 : for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
698 12891 : if (state.dataDefineEquipment->AirDistUnit(ADUNum).ZoneEqNum ==
699 12891 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).ZoneEqNum(InletNodeLoop)) {
700 1325 : state.dataDefineEquipment->AirDistUnit(ADUNum).RetPlenumNum = ZonePlenumLoop;
701 1325 : ++NumADUsToPlen;
702 : }
703 : }
704 : }
705 : }
706 284 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).ADUIndex.allocate(NumADUsToPlen);
707 284 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).NumADUs = NumADUsToPlen;
708 : // fill the list of air distribution units that can leak to this plenum
709 284 : if (NumADUsToPlen > 0) {
710 3037 : for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
711 2754 : if (state.dataDefineEquipment->AirDistUnit(ADUNum).RetPlenumNum == ZonePlenumLoop) {
712 1325 : ++ADUsToPlenIndex;
713 1325 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).ADUIndex(ADUsToPlenIndex) = ADUNum;
714 : }
715 : }
716 : }
717 : }
718 :
719 : // Check that all ADUs with leakage found a return plenum
720 1562 : for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
721 1372 : auto &thisADU(state.dataDefineEquipment->AirDistUnit(ADUNum));
722 : // TODO: the first half of this IF condition was a duplicated OR, if issues around this code, might want to check the history of this line
723 1372 : if (thisADU.DownStreamLeak && (thisADU.RetPlenumNum == 0)) {
724 0 : ShowWarningError(state,
725 0 : format("No return plenum found for simple duct leakage for ZoneHVAC:AirDistributionUnit={} in Zone={}",
726 0 : thisADU.Name,
727 0 : state.dataZoneEquip->ZoneEquipConfig(thisADU.ZoneEqNum).ZoneName));
728 0 : ShowContinueError(state, "Leakage will be ignored for this ADU.");
729 0 : thisADU.UpStreamLeak = false;
730 0 : thisADU.DownStreamLeak = false;
731 0 : thisADU.UpStreamLeakFrac = 0.0;
732 0 : thisADU.DownStreamLeakFrac = 0.0;
733 : }
734 : }
735 :
736 190 : state.dataZonePlenum->InitAirZoneReturnPlenumOneTimeFlag = false;
737 : }
738 :
739 : // Do the Begin Environment initializations
740 2609056 : if (state.dataZonePlenum->InitAirZoneReturnPlenumEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
741 :
742 3050 : for (PlenumZoneNum = 1; PlenumZoneNum <= state.dataZonePlenum->NumZoneReturnPlenums; ++PlenumZoneNum) {
743 :
744 1861 : ZoneNodeNum = state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).ZoneNodeNum;
745 1861 : state.dataLoopNodes->Node(ZoneNodeNum).Temp = 20.0;
746 1861 : state.dataLoopNodes->Node(ZoneNodeNum).MassFlowRate = 0.0;
747 1861 : state.dataLoopNodes->Node(ZoneNodeNum).Quality = 1.0;
748 1861 : state.dataLoopNodes->Node(ZoneNodeNum).Press = state.dataEnvrn->OutBaroPress;
749 1861 : state.dataLoopNodes->Node(ZoneNodeNum).HumRat = state.dataEnvrn->OutHumRat;
750 1861 : state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy =
751 1861 : PsyHFnTdbW(state.dataLoopNodes->Node(ZoneNodeNum).Temp, state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
752 :
753 1861 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).ZoneTemp = 20.0;
754 1861 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).ZoneHumRat = 0.0;
755 1861 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).ZoneEnthalpy = 0.0;
756 1861 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletTemp = 0.0;
757 1861 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletHumRat = 0.0;
758 1861 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletEnthalpy = 0.0;
759 1861 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletPressure = 0.0;
760 1861 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletMassFlowRate = 0.0;
761 1861 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletMassFlowRateMaxAvail = 0.0;
762 1861 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletMassFlowRateMinAvail = 0.0;
763 : }
764 :
765 1189 : state.dataZonePlenum->InitAirZoneReturnPlenumEnvrnFlag = false;
766 : }
767 :
768 2609056 : if (!state.dataGlobal->BeginEnvrnFlag) {
769 2594528 : state.dataZonePlenum->InitAirZoneReturnPlenumEnvrnFlag = true;
770 : }
771 :
772 : // Transfer the node data to ZoneRetPlenCond data structure
773 15208538 : for (NodeNum = 1; NodeNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInletNodes; ++NodeNum) {
774 :
775 12599482 : InletNode = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletNode(NodeNum);
776 : // Set all of the inlet mass flow variables from the nodes
777 12599482 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRate(NodeNum) = state.dataLoopNodes->Node(InletNode).MassFlowRate;
778 12599482 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRateMaxAvail(NodeNum) =
779 12599482 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail;
780 12599482 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRateMinAvail(NodeNum) =
781 12599482 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail;
782 : // ! Set all of the inlet state variables from the inlet nodes
783 : // ZoneRetPlenCond(ZonePlenumNum)%InletTemp(NodeNum) = Node(InletNode)%Temp
784 : // ZoneRetPlenCond(ZonePlenumNum)%InletHumRat(NodeNum) = Node(InletNode)%HumRat
785 : // ZoneRetPlenCond(ZonePlenumNum)%InletEnthalpy(NodeNum) = Node(InletNode)%Enthalpy
786 12599482 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletPressure(NodeNum) = state.dataLoopNodes->Node(InletNode).Press;
787 : }
788 :
789 2609056 : ZoneNodeNum = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneNodeNum;
790 : // Set the induced air flow rates and conditions
791 2805427 : for (NodeNum = 1; NodeNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInducedNodes; ++NodeNum) {
792 196371 : InducedNode = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedNode(NodeNum);
793 196371 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedMassFlowRate(NodeNum) = state.dataLoopNodes->Node(InducedNode).MassFlowRate;
794 196371 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedMassFlowRateMaxAvail(NodeNum) =
795 196371 : state.dataLoopNodes->Node(InducedNode).MassFlowRateMaxAvail;
796 196371 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedMassFlowRateMinAvail(NodeNum) =
797 196371 : state.dataLoopNodes->Node(InducedNode).MassFlowRateMinAvail;
798 :
799 196371 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedTemp(NodeNum) = state.dataLoopNodes->Node(ZoneNodeNum).Temp;
800 196371 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedHumRat(NodeNum) = state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
801 196371 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedEnthalpy(NodeNum) = state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy;
802 196371 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedPressure(NodeNum) = state.dataLoopNodes->Node(ZoneNodeNum).Press;
803 196371 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
804 0 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedCO2(NodeNum) = state.dataLoopNodes->Node(ZoneNodeNum).CO2;
805 : }
806 196371 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
807 0 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedGenContam(NodeNum) = state.dataLoopNodes->Node(ZoneNodeNum).GenContam;
808 : }
809 : }
810 :
811 : // Add stuff to calculate conduction inputs to the zone plenum
812 : // Now load the zone conditions
813 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneTemp = state.dataLoopNodes->Node(ZoneNodeNum).Temp;
814 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneHumRat = state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
815 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneEnthalpy = state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy;
816 2609056 : }
817 :
818 78236 : void InitAirZoneSupplyPlenum(EnergyPlusData &state, int const ZonePlenumNum, bool const FirstHVACIteration, bool const FirstCall)
819 : {
820 :
821 : // SUBROUTINE INFORMATION:
822 : // AUTHOR Peter Graham Ellis
823 : // DATE WRITTEN March 2000
824 : // MODIFIED na
825 : // RE-ENGINEERED na
826 :
827 : // PURPOSE OF THIS SUBROUTINE:
828 : // This subroutine is for initializations of the ZonePlenum components.
829 :
830 : // METHODOLOGY EMPLOYED:
831 : // Similar to the Zone Splitter component but with interactions to the plenum zone.
832 :
833 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
834 : int InletNode;
835 : int OutletNode;
836 : int ZoneNodeNum;
837 : int PlenumZoneNum;
838 : int NodeIndex;
839 :
840 78236 : auto &Node(state.dataLoopNodes->Node);
841 :
842 : // Do the Begin Environment initializations
843 78236 : if (state.dataZonePlenum->MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
844 :
845 92 : for (PlenumZoneNum = 1; PlenumZoneNum <= state.dataZonePlenum->NumZoneSupplyPlenums; ++PlenumZoneNum) {
846 :
847 54 : ZoneNodeNum = state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).ZoneNodeNum;
848 54 : Node(ZoneNodeNum).Temp = 20.0;
849 54 : Node(ZoneNodeNum).MassFlowRate = 0.0;
850 54 : Node(ZoneNodeNum).Quality = 1.0;
851 54 : Node(ZoneNodeNum).Press = state.dataEnvrn->OutBaroPress;
852 54 : Node(ZoneNodeNum).HumRat = state.dataEnvrn->OutHumRat;
853 54 : Node(ZoneNodeNum).Enthalpy = PsyHFnTdbW(Node(ZoneNodeNum).Temp, Node(ZoneNodeNum).HumRat);
854 :
855 54 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).ZoneTemp = 20.0;
856 54 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).ZoneHumRat = 0.0;
857 54 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).ZoneEnthalpy = 0.0;
858 54 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletTemp = 0.0;
859 54 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletHumRat = 0.0;
860 54 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletEnthalpy = 0.0;
861 54 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletPressure = 0.0;
862 54 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletMassFlowRate = 0.0;
863 54 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletMassFlowRateMaxAvail = 0.0;
864 54 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletMassFlowRateMinAvail = 0.0;
865 : }
866 :
867 38 : state.dataZonePlenum->MyEnvrnFlag = false;
868 : }
869 :
870 78236 : if (!state.dataGlobal->BeginEnvrnFlag) {
871 77380 : state.dataZonePlenum->MyEnvrnFlag = true;
872 : }
873 :
874 : // Do the following initializations (every time step): This should be the info from
875 : // the previous components outlets or the node data in this section.
876 :
877 78236 : InletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletNode;
878 78236 : ZoneNodeNum = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneNodeNum;
879 :
880 78236 : if (FirstHVACIteration && FirstCall) {
881 19592 : if (Node(InletNode).MassFlowRate > 0.0) {
882 14453 : Node(ZoneNodeNum).MassFlowRate = Node(InletNode).MassFlowRate;
883 36258 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
884 21805 : OutletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletNode(NodeIndex);
885 21805 : Node(OutletNode).MassFlowRate = Node(InletNode).MassFlowRate / state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes;
886 : }
887 : }
888 19592 : if (Node(InletNode).MassFlowRateMaxAvail > 0.0) {
889 14453 : Node(ZoneNodeNum).MassFlowRateMaxAvail = Node(InletNode).MassFlowRateMaxAvail;
890 36258 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
891 21805 : OutletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletNode(NodeIndex);
892 21805 : Node(OutletNode).MassFlowRateMaxAvail =
893 21805 : Node(InletNode).MassFlowRateMaxAvail / state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes;
894 : }
895 : }
896 :
897 : } // For FirstHVACIteration and FirstCall
898 :
899 78236 : if (FirstCall) {
900 :
901 39118 : if (Node(InletNode).MassFlowRateMaxAvail == 0.0) { // For Node inlet Max Avail = 0.0
902 :
903 20522 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
904 10283 : OutletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletNode(NodeIndex);
905 10283 : Node(OutletNode).MassFlowRate = 0.0;
906 10283 : Node(OutletNode).MassFlowRateMaxAvail = 0.0;
907 10283 : Node(OutletNode).MassFlowRateMinAvail = 0.0;
908 : }
909 :
910 10239 : Node(ZoneNodeNum).MassFlowRate = 0.0;
911 10239 : Node(ZoneNodeNum).MassFlowRateMaxAvail = 0.0;
912 10239 : Node(ZoneNodeNum).MassFlowRateMinAvail = 0.0;
913 :
914 : } // For Node inlet Max Avail = 0.0
915 :
916 : // Add stuff to calculate conduction inputs to the zone plenum
917 : // Now load the zone conditions
918 39118 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneTemp = Node(ZoneNodeNum).Temp;
919 39118 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneHumRat = Node(ZoneNodeNum).HumRat;
920 39118 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneEnthalpy = Node(ZoneNodeNum).Enthalpy;
921 :
922 92972 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
923 53854 : OutletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletNode(NodeIndex);
924 53854 : Node(OutletNode).Press = Node(InletNode).Press;
925 53854 : Node(OutletNode).Quality = Node(InletNode).Quality;
926 : }
927 :
928 39118 : Node(ZoneNodeNum).Press = Node(InletNode).Press;
929 39118 : Node(ZoneNodeNum).Quality = Node(InletNode).Quality;
930 :
931 : } else { // On the second call from the ZoneEquipManager this is where the flows are passed back to
932 : // the supply plenum inlet.
933 92972 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
934 53854 : OutletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletNode(NodeIndex);
935 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletMassFlowRate(NodeIndex) = Node(OutletNode).MassFlowRate;
936 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail(NodeIndex) = Node(OutletNode).MassFlowRateMaxAvail;
937 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletMassFlowRateMinAvail(NodeIndex) = Node(OutletNode).MassFlowRateMinAvail;
938 : }
939 :
940 : } // For FirstCall
941 78236 : }
942 :
943 2609056 : void CalcAirZoneReturnPlenum(EnergyPlusData &state, int const ZonePlenumNum)
944 : {
945 :
946 : // SUBROUTINE INFORMATION:
947 : // AUTHOR Peter Graham Ellis
948 : // DATE WRITTEN November 2000
949 : // MODIFIED na
950 : // RE-ENGINEERED na
951 :
952 : // Using/Aliasing
953 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
954 2609056 : int InletNodeNum(0); // inlet node number
955 2609056 : int IndNum(0); // induced air index
956 2609056 : int ADUNum(0); // air distribution unit number
957 2609056 : int ADUListIndex(0); // air distribution unit index in zone return plenum data structure
958 2609056 : Real64 TotIndMassFlowRate(0.0); // total induced air mass flow rate [kg/s]
959 :
960 : // Reset the totals to zero before they are summed.
961 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate = 0.0;
962 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail = 0.0;
963 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMinAvail = 0.0;
964 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletTemp = 0.0;
965 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletHumRat = 0.0;
966 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletPressure = 0.0;
967 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletEnthalpy = 0.0;
968 2609056 : TotIndMassFlowRate = 0.0;
969 :
970 15208538 : for (InletNodeNum = 1; InletNodeNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInletNodes; ++InletNodeNum) {
971 12599482 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate +=
972 12599482 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRate(InletNodeNum);
973 12599482 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail +=
974 12599482 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRateMaxAvail(InletNodeNum);
975 12599482 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMinAvail +=
976 12599482 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRateMinAvail(InletNodeNum);
977 : }
978 :
979 2609056 : if (state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate > 0.0) {
980 :
981 : // "Momentum balance" to get outlet air pressure
982 12361606 : for (InletNodeNum = 1; InletNodeNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInletNodes; ++InletNodeNum) {
983 :
984 10230250 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletPressure +=
985 10230250 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletPressure(InletNodeNum) *
986 10230250 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRate(InletNodeNum) /
987 10230250 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate;
988 : }
989 :
990 : } else {
991 : // Mass Flow in air loop is zero and loop is not operating.
992 : // Arbitrarily set the output to the first inlet leg
993 477700 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletPressure = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletPressure(1);
994 : }
995 :
996 : // add in the leak flow rate, if any. Don't alter the pressure calc (it is not used anyway)
997 15249108 : for (ADUListIndex = 1; ADUListIndex <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumADUs; ++ADUListIndex) {
998 12640052 : ADUNum = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ADUIndex(ADUListIndex);
999 12640052 : if (state.dataDefineEquipment->AirDistUnit(ADUNum).UpStreamLeak || state.dataDefineEquipment->AirDistUnit(ADUNum).DownStreamLeak) {
1000 253875 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate +=
1001 253875 : state.dataDefineEquipment->AirDistUnit(ADUNum).MassFlowRateUpStrLk +
1002 253875 : state.dataDefineEquipment->AirDistUnit(ADUNum).MassFlowRateDnStrLk;
1003 253875 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail +=
1004 253875 : state.dataDefineEquipment->AirDistUnit(ADUNum).MaxAvailDelta;
1005 253875 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMinAvail +=
1006 253875 : state.dataDefineEquipment->AirDistUnit(ADUNum).MinAvailDelta;
1007 : }
1008 : }
1009 : // Sum up induced air flow rate
1010 2805427 : for (IndNum = 1; IndNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInducedNodes; ++IndNum) {
1011 196371 : TotIndMassFlowRate += state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedMassFlowRate(IndNum);
1012 : }
1013 :
1014 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate -= TotIndMassFlowRate;
1015 :
1016 : // Set the Plenum Outlet to the Zone Node conditions
1017 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletHumRat = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneHumRat;
1018 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletEnthalpy = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneEnthalpy;
1019 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletTemp = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneTemp;
1020 : // make sure the MassFlowMaxAvail >= MassFlowRate
1021 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail =
1022 2609056 : max(state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail,
1023 2609056 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate);
1024 2609056 : }
1025 :
1026 78236 : void CalcAirZoneSupplyPlenum(EnergyPlusData &state, int const ZonePlenumNum, bool const FirstCall)
1027 : {
1028 :
1029 : // SUBROUTINE INFORMATION:
1030 : // AUTHOR Peter Graham Ellis
1031 : // DATE WRITTEN March 2000
1032 : // MODIFIED na
1033 : // RE-ENGINEERED na
1034 :
1035 : // METHODOLOGY EMPLOYED:
1036 : // Similar to the Zone Splitter component but with interactions to the plenum zone.
1037 :
1038 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1039 : int NodeIndex;
1040 :
1041 : // The first time through the State properties are passed through
1042 78236 : if (FirstCall) {
1043 : // Moisture balance to get outlet air humidity ratio
1044 92972 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
1045 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletHumRat(NodeIndex) =
1046 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneHumRat;
1047 : }
1048 :
1049 : // Energy balance to get outlet air enthalpy
1050 92972 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
1051 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletEnthalpy(NodeIndex) =
1052 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneEnthalpy;
1053 : }
1054 :
1055 : // Set outlet temperatures equal to inlet temperature
1056 92972 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
1057 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletTemp(NodeIndex) =
1058 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneTemp;
1059 : }
1060 :
1061 : } else {
1062 : // This is the second time through and this is where the mass flows from the outlets are
1063 : // summed and then assigned upstream to the inlet node.
1064 39118 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRate = 0.0;
1065 39118 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRateMaxAvail = 0.0;
1066 39118 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRateMinAvail = 0.0;
1067 92972 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
1068 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRate +=
1069 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletMassFlowRate(NodeIndex);
1070 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRateMaxAvail +=
1071 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail(NodeIndex);
1072 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRateMinAvail +=
1073 53854 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletMassFlowRateMinAvail(NodeIndex);
1074 : }
1075 : }
1076 78236 : }
1077 :
1078 : // End Algorithm Section of the Module
1079 : // *****************************************************************************
1080 :
1081 : // Beginning of Update subroutines for the ZonePlenum Module
1082 : // *****************************************************************************
1083 :
1084 2609056 : void UpdateAirZoneReturnPlenum(EnergyPlusData &state, int const ZonePlenumNum)
1085 : {
1086 :
1087 : // SUBROUTINE INFORMATION:
1088 : // AUTHOR Peter Graham Ellis
1089 : // DATE WRITTEN November 2000
1090 : // MODIFIED na
1091 : // RE-ENGINEERED na
1092 :
1093 : // Using/Aliasing
1094 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1095 : int OutletNode;
1096 : int InletNode;
1097 : int ZoneNode;
1098 : int InletNodeNum;
1099 : int InducedNode; // the node number of an induced air outlet node
1100 : int IndNum; // the induced air outlet index in ZoneRetPlenCond
1101 :
1102 2609056 : auto &Node(state.dataLoopNodes->Node);
1103 :
1104 2609056 : OutletNode = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletNode;
1105 2609056 : InletNode = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletNode(1);
1106 2609056 : ZoneNode = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneNodeNum;
1107 :
1108 : // Set the outlet air nodes of the ZonePlenum
1109 2609056 : Node(OutletNode).MassFlowRate = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate;
1110 2609056 : Node(OutletNode).MassFlowRateMaxAvail = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail;
1111 2609056 : Node(OutletNode).MassFlowRateMinAvail = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMinAvail;
1112 :
1113 2609056 : Node(ZoneNode).MassFlowRate = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate;
1114 2609056 : Node(ZoneNode).MassFlowRateMaxAvail = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail;
1115 2609056 : Node(ZoneNode).MassFlowRateMinAvail = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMinAvail;
1116 2609056 : Node(ZoneNode).Press = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletPressure;
1117 :
1118 2609056 : Node(OutletNode).Temp = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletTemp;
1119 2609056 : Node(OutletNode).HumRat = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletHumRat;
1120 2609056 : Node(OutletNode).Enthalpy = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletEnthalpy;
1121 2609056 : Node(OutletNode).Press = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletPressure;
1122 2805427 : for (IndNum = 1; IndNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInducedNodes; ++IndNum) {
1123 196371 : InducedNode = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedNode(IndNum);
1124 196371 : Node(InducedNode).Temp = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedTemp(IndNum);
1125 196371 : Node(InducedNode).HumRat = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedHumRat(IndNum);
1126 196371 : Node(InducedNode).Enthalpy = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedEnthalpy(IndNum);
1127 196371 : Node(InducedNode).Press = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedPressure(IndNum);
1128 196371 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1129 0 : Node(InducedNode).CO2 = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedCO2(IndNum);
1130 : }
1131 196371 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1132 0 : Node(InducedNode).GenContam = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedGenContam(IndNum);
1133 : }
1134 196371 : Node(InducedNode).Quality = Node(InletNode).Quality;
1135 : }
1136 :
1137 : // Set the outlet nodes for properties that are just pass through and not used
1138 2609056 : Node(OutletNode).Quality = Node(InletNode).Quality;
1139 2609056 : Node(ZoneNode).Quality = Node(InletNode).Quality;
1140 :
1141 : // Set the outlet node contaminant properties if needed. The zone contaminant conditions are calculated in ZoneContaminantPredictorCorrector
1142 2609056 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1143 0 : if (state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate > 0.0) {
1144 : // CO2 balance to get outlet air CO2
1145 0 : Node(OutletNode).CO2 = 0.0;
1146 0 : for (InletNodeNum = 1; InletNodeNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInletNodes; ++InletNodeNum) {
1147 0 : Node(OutletNode).CO2 += Node(state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletNode(InletNodeNum)).CO2 *
1148 0 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRate(InletNodeNum) /
1149 0 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate;
1150 : }
1151 0 : Node(ZoneNode).CO2 = Node(OutletNode).CO2;
1152 : } else {
1153 0 : Node(OutletNode).CO2 = Node(ZoneNode).CO2;
1154 : }
1155 : }
1156 2609056 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1157 0 : if (state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate > 0.0) {
1158 : // GenContam balance to get outlet air GenContam
1159 0 : Node(OutletNode).GenContam = 0.0;
1160 0 : for (InletNodeNum = 1; InletNodeNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInletNodes; ++InletNodeNum) {
1161 0 : Node(OutletNode).GenContam += Node(state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletNode(InletNodeNum)).GenContam *
1162 0 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRate(InletNodeNum) /
1163 0 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate;
1164 : }
1165 0 : Node(ZoneNode).GenContam = Node(OutletNode).GenContam;
1166 : } else {
1167 0 : Node(OutletNode).GenContam = Node(ZoneNode).GenContam;
1168 : }
1169 : }
1170 2609056 : }
1171 :
1172 78236 : void UpdateAirZoneSupplyPlenum(EnergyPlusData &state, int const ZonePlenumNum, bool &PlenumInletChanged, bool const FirstCall)
1173 : {
1174 :
1175 : // SUBROUTINE INFORMATION:
1176 : // AUTHOR Peter Graham Ellis
1177 : // DATE WRITTEN March 2000
1178 : // MODIFIED na
1179 : // RE-ENGINEERED na
1180 :
1181 : // METHODOLOGY EMPLOYED:
1182 : // Similar to the Zone Splitter component but with interactions to the plenum zone.
1183 :
1184 : // Using/Aliasing
1185 : // SUBROUTINE PARAMETER DEFINITIONS:
1186 78236 : Real64 constexpr FlowRateToler(0.01); // Tolerance for mass flow rate convergence (in kg/s)
1187 :
1188 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1189 : int OutletNode;
1190 : int InletNode;
1191 : int ZoneNode;
1192 : int NodeIndex;
1193 :
1194 78236 : auto &Node(state.dataLoopNodes->Node);
1195 :
1196 78236 : OutletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletNode(1);
1197 78236 : InletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletNode;
1198 78236 : ZoneNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneNodeNum;
1199 :
1200 : // On the FirstCall the State properties are passed through and the mass flows are not dealt with
1201 78236 : if (FirstCall) {
1202 : // Set the outlet nodes for properties that just pass through and not used
1203 92972 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
1204 53854 : OutletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletNode(NodeIndex);
1205 53854 : Node(OutletNode).Temp = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletTemp(NodeIndex);
1206 53854 : Node(OutletNode).HumRat = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletHumRat(NodeIndex);
1207 53854 : Node(OutletNode).Enthalpy = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletEnthalpy(NodeIndex);
1208 53854 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1209 0 : Node(OutletNode).CO2 = Node(InletNode).CO2;
1210 : }
1211 53854 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1212 0 : Node(OutletNode).GenContam = Node(InletNode).GenContam;
1213 : }
1214 : }
1215 :
1216 39118 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1217 0 : Node(ZoneNode).CO2 = Node(InletNode).CO2;
1218 : }
1219 39118 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1220 0 : Node(ZoneNode).GenContam = Node(InletNode).GenContam;
1221 : }
1222 :
1223 : } else {
1224 : // The second time through just updates the mass flow conditions back upstream
1225 : // to the inlet.
1226 :
1227 39118 : if (std::abs(Node(InletNode).MassFlowRate - state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRate) > FlowRateToler) {
1228 10027 : PlenumInletChanged = true;
1229 : }
1230 :
1231 39118 : Node(InletNode).MassFlowRate = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRate;
1232 39118 : Node(InletNode).MassFlowRateMaxAvail = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRateMaxAvail;
1233 39118 : Node(InletNode).MassFlowRateMinAvail = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRateMinAvail;
1234 :
1235 39118 : Node(ZoneNode).MassFlowRate = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRate;
1236 39118 : Node(ZoneNode).MassFlowRateMaxAvail = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRateMaxAvail;
1237 39118 : Node(ZoneNode).MassFlowRateMinAvail = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRateMinAvail;
1238 :
1239 : } // For FirstCall
1240 78236 : }
1241 :
1242 5 : int GetReturnPlenumIndex(EnergyPlusData &state, int const ExNodeNum)
1243 : {
1244 :
1245 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1246 : int PlenumNum; // loop counter
1247 : int InducedNodeNum; // loop counter
1248 : int WhichPlenum; // index to return plenum
1249 :
1250 : // Obtains and Allocates ZonePlenum related parameters from input file
1251 5 : if (state.dataZonePlenum->GetInputFlag) { // First time subroutine has been entered
1252 1 : GetZonePlenumInput(state);
1253 1 : state.dataZonePlenum->GetInputFlag = false;
1254 : }
1255 :
1256 5 : WhichPlenum = 0;
1257 5 : if (state.dataZonePlenum->NumZoneReturnPlenums > 0) {
1258 9 : for (PlenumNum = 1; PlenumNum <= state.dataZonePlenum->NumZoneReturnPlenums; ++PlenumNum) {
1259 5 : if (ExNodeNum != state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).OutletNode) continue;
1260 1 : WhichPlenum = PlenumNum;
1261 1 : break;
1262 : }
1263 5 : if (WhichPlenum == 0) {
1264 4 : for (PlenumNum = 1; PlenumNum <= state.dataZonePlenum->NumZoneReturnPlenums; ++PlenumNum) {
1265 10 : for (InducedNodeNum = 1; InducedNodeNum <= state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).NumInducedNodes; ++InducedNodeNum) {
1266 10 : if (ExNodeNum != state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).InducedNode(InducedNodeNum)) continue;
1267 4 : WhichPlenum = PlenumNum;
1268 4 : break;
1269 : }
1270 4 : if (WhichPlenum > 0) break;
1271 : }
1272 : }
1273 : }
1274 :
1275 5 : return WhichPlenum;
1276 : }
1277 :
1278 5 : void GetReturnPlenumName(EnergyPlusData &state, int const ReturnPlenumIndex, std::string &ReturnPlenumName)
1279 : {
1280 :
1281 : // Obtains and Allocates ZonePlenum related parameters from input file
1282 5 : if (state.dataZonePlenum->GetInputFlag) { // First time subroutine has been entered
1283 0 : GetZonePlenumInput(state);
1284 0 : state.dataZonePlenum->GetInputFlag = false;
1285 : }
1286 :
1287 5 : ReturnPlenumName = " ";
1288 5 : if (state.dataZonePlenum->NumZoneReturnPlenums > 0) {
1289 5 : ReturnPlenumName = state.dataZonePlenum->ZoneRetPlenCond(ReturnPlenumIndex).ZonePlenumName;
1290 : }
1291 5 : }
1292 :
1293 4 : int getReturnPlenumIndexFromInletNode(EnergyPlusData &state, int const InNodeNum)
1294 : {
1295 :
1296 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1297 : int PlenumNum; // loop counter
1298 : int InNodeCtr; // loop counter
1299 : int thisPlenum;
1300 :
1301 : // Obtains and Allocates ZonePlenum related parameters from input file
1302 4 : if (state.dataZonePlenum->GetInputFlag) { // First time subroutine has been entered
1303 4 : GetZonePlenumInput(state);
1304 4 : state.dataZonePlenum->GetInputFlag = false;
1305 : }
1306 :
1307 4 : thisPlenum = 0;
1308 4 : if (state.dataZonePlenum->NumZoneReturnPlenums > 0) {
1309 0 : for (PlenumNum = 1; PlenumNum <= state.dataZonePlenum->NumZoneReturnPlenums; ++PlenumNum) {
1310 0 : for (InNodeCtr = 1; InNodeCtr <= state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).NumInletNodes; ++InNodeCtr) {
1311 0 : if (InNodeNum != state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).InletNode(InNodeCtr)) continue;
1312 0 : thisPlenum = PlenumNum;
1313 0 : break;
1314 : }
1315 0 : if (thisPlenum > 0) break;
1316 : }
1317 : }
1318 :
1319 4 : return thisPlenum;
1320 : }
1321 :
1322 3 : bool ValidateInducedNode(EnergyPlusData &state, int const InduceNodeNum, int const NumReturnNodes, Array1D<int> const &ReturnNode)
1323 : {
1324 : // Ensure induced node is used as inlet node of zoe equipment
1325 : int PlenumNum; // loop counter
1326 : int InNodeCtr; // loop counter
1327 : int InduceNodeCtr; // loop counter
1328 3 : bool Nodefound = false;
1329 :
1330 : // Obtains and Allocates ZonePlenum related parameters from input file
1331 3 : if (state.dataZonePlenum->GetInputFlag) { // First time subroutine has been entered
1332 1 : GetZonePlenumInput(state);
1333 1 : state.dataZonePlenum->GetInputFlag = false;
1334 : }
1335 :
1336 3 : if (state.dataZonePlenum->NumZoneReturnPlenums > 0) {
1337 3 : for (PlenumNum = 1; PlenumNum <= state.dataZonePlenum->NumZoneReturnPlenums; ++PlenumNum) {
1338 6 : for (InduceNodeCtr = 1; InduceNodeCtr <= state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).NumInducedNodes; ++InduceNodeCtr) {
1339 6 : if (InduceNodeNum == state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).InducedNode(InduceNodeCtr)) {
1340 10 : for (InNodeCtr = 1; InNodeCtr <= state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).NumInletNodes; ++InNodeCtr) {
1341 17 : for (int ReturnNodeNum = 1; ReturnNodeNum <= NumReturnNodes; ++ReturnNodeNum) {
1342 10 : if (ReturnNode(ReturnNodeNum) != state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).InletNode(InNodeCtr)) continue;
1343 3 : Nodefound = true;
1344 3 : break;
1345 : }
1346 10 : if (Nodefound) break;
1347 : }
1348 : }
1349 6 : if (Nodefound) break;
1350 : }
1351 3 : if (Nodefound) break;
1352 : }
1353 : }
1354 :
1355 3 : return Nodefound;
1356 : }
1357 :
1358 : } // namespace EnergyPlus::ZonePlenum
|