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