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 8 : }
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 8 : }
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 1 : }
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 1 : }
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) {
677 20 : continue;
678 : }
679 102 : for (int retNode = 1; retNode <= state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigLoop).NumReturnNodes; ++retNode) {
680 51 : if (state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigLoop).ReturnNode(retNode) == InletNode) {
681 14 : state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigLoop).ReturnNodePlenumNum = ZonePlenumLoop;
682 14 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).ZoneEqNum(InletNodeLoop) = ZoneEquipConfigLoop;
683 : }
684 : }
685 : }
686 : // count the ADUs that can leak to this plenum
687 65 : for (int ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
688 50 : if (state.dataDefineEquipment->AirDistUnit(ADUNum).ZoneEqNum ==
689 50 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).ZoneEqNum(InletNodeLoop)) {
690 14 : state.dataDefineEquipment->AirDistUnit(ADUNum).RetPlenumNum = ZonePlenumLoop;
691 14 : ++NumADUsToPlen;
692 : }
693 : }
694 : }
695 : }
696 7 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).ADUIndex.allocate(NumADUsToPlen);
697 7 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).NumADUs = NumADUsToPlen;
698 : // fill the list of air distribution units that can leak to this plenum
699 7 : if (NumADUsToPlen > 0) {
700 5 : int ADUsToPlenIndex = 0;
701 19 : for (int ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
702 14 : if (state.dataDefineEquipment->AirDistUnit(ADUNum).RetPlenumNum == ZonePlenumLoop) {
703 14 : ++ADUsToPlenIndex;
704 14 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumLoop).ADUIndex(ADUsToPlenIndex) = ADUNum;
705 : }
706 : }
707 : }
708 : }
709 :
710 : // Check that all ADUs with leakage found a return plenum
711 21 : for (int ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
712 14 : auto &thisADU(state.dataDefineEquipment->AirDistUnit(ADUNum));
713 : // 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
714 14 : if (thisADU.DownStreamLeak && (thisADU.RetPlenumNum == 0)) {
715 0 : ShowWarningError(state,
716 0 : format("No return plenum found for simple duct leakage for ZoneHVAC:AirDistributionUnit={} in Zone={}",
717 0 : thisADU.Name,
718 0 : state.dataZoneEquip->ZoneEquipConfig(thisADU.ZoneEqNum).ZoneName));
719 0 : ShowContinueError(state, "Leakage will be ignored for this ADU.");
720 0 : thisADU.UpStreamLeak = false;
721 0 : thisADU.DownStreamLeak = false;
722 0 : thisADU.UpStreamLeakFrac = 0.0;
723 0 : thisADU.DownStreamLeakFrac = 0.0;
724 : }
725 : }
726 :
727 7 : state.dataZonePlenum->InitAirZoneReturnPlenumOneTimeFlag = false;
728 : }
729 :
730 : // Do the Begin Environment initializations
731 9 : if (state.dataZonePlenum->InitAirZoneReturnPlenumEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
732 :
733 2 : for (int PlenumZoneNum = 1; PlenumZoneNum <= state.dataZonePlenum->NumZoneReturnPlenums; ++PlenumZoneNum) {
734 :
735 1 : ZoneNodeNum = state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).ZoneNodeNum;
736 1 : state.dataLoopNodes->Node(ZoneNodeNum).Temp = 20.0;
737 1 : state.dataLoopNodes->Node(ZoneNodeNum).MassFlowRate = 0.0;
738 1 : state.dataLoopNodes->Node(ZoneNodeNum).Quality = 1.0;
739 1 : state.dataLoopNodes->Node(ZoneNodeNum).Press = state.dataEnvrn->OutBaroPress;
740 1 : state.dataLoopNodes->Node(ZoneNodeNum).HumRat = state.dataEnvrn->OutHumRat;
741 1 : state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy =
742 1 : PsyHFnTdbW(state.dataLoopNodes->Node(ZoneNodeNum).Temp, state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
743 :
744 1 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).ZoneTemp = 20.0;
745 1 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).ZoneHumRat = 0.0;
746 1 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).ZoneEnthalpy = 0.0;
747 1 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletTemp = 0.0;
748 1 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletHumRat = 0.0;
749 1 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletEnthalpy = 0.0;
750 1 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletPressure = 0.0;
751 1 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletMassFlowRate = 0.0;
752 1 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletMassFlowRateMaxAvail = 0.0;
753 1 : state.dataZonePlenum->ZoneRetPlenCond(PlenumZoneNum).InletMassFlowRateMinAvail = 0.0;
754 : }
755 :
756 1 : state.dataZonePlenum->InitAirZoneReturnPlenumEnvrnFlag = false;
757 : }
758 :
759 9 : if (!state.dataGlobal->BeginEnvrnFlag) {
760 7 : state.dataZonePlenum->InitAirZoneReturnPlenumEnvrnFlag = true;
761 : }
762 :
763 : // Transfer the node data to ZoneRetPlenCond data structure
764 34 : for (NodeNum = 1; NodeNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInletNodes; ++NodeNum) {
765 :
766 25 : InletNode = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletNode(NodeNum);
767 : // Set all of the inlet mass flow variables from the nodes
768 25 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRate(NodeNum) = state.dataLoopNodes->Node(InletNode).MassFlowRate;
769 25 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRateMaxAvail(NodeNum) =
770 25 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail;
771 25 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRateMinAvail(NodeNum) =
772 25 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail;
773 : // ! Set all of the inlet state variables from the inlet nodes
774 : // ZoneRetPlenCond(ZonePlenumNum)%InletTemp(NodeNum) = Node(InletNode)%Temp
775 : // ZoneRetPlenCond(ZonePlenumNum)%InletHumRat(NodeNum) = Node(InletNode)%HumRat
776 : // ZoneRetPlenCond(ZonePlenumNum)%InletEnthalpy(NodeNum) = Node(InletNode)%Enthalpy
777 25 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletPressure(NodeNum) = state.dataLoopNodes->Node(InletNode).Press;
778 : }
779 :
780 9 : ZoneNodeNum = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneNodeNum;
781 : // Set the induced air flow rates and conditions
782 21 : for (NodeNum = 1; NodeNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInducedNodes; ++NodeNum) {
783 12 : int InducedNode = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedNode(NodeNum);
784 12 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedMassFlowRate(NodeNum) = state.dataLoopNodes->Node(InducedNode).MassFlowRate;
785 12 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedMassFlowRateMaxAvail(NodeNum) =
786 12 : state.dataLoopNodes->Node(InducedNode).MassFlowRateMaxAvail;
787 12 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedMassFlowRateMinAvail(NodeNum) =
788 12 : state.dataLoopNodes->Node(InducedNode).MassFlowRateMinAvail;
789 :
790 12 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedTemp(NodeNum) = state.dataLoopNodes->Node(ZoneNodeNum).Temp;
791 12 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedHumRat(NodeNum) = state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
792 12 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedEnthalpy(NodeNum) = state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy;
793 12 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedPressure(NodeNum) = state.dataLoopNodes->Node(ZoneNodeNum).Press;
794 12 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
795 2 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedCO2(NodeNum) = state.dataLoopNodes->Node(ZoneNodeNum).CO2;
796 : }
797 12 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
798 2 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedGenContam(NodeNum) = state.dataLoopNodes->Node(ZoneNodeNum).GenContam;
799 : }
800 : }
801 :
802 : // Add stuff to calculate conduction inputs to the zone plenum
803 : // Now load the zone conditions
804 9 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneTemp = state.dataLoopNodes->Node(ZoneNodeNum).Temp;
805 9 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneHumRat = state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
806 9 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneEnthalpy = state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy;
807 9 : }
808 :
809 2 : void InitAirZoneSupplyPlenum(EnergyPlusData &state, int const ZonePlenumNum, bool const FirstHVACIteration, bool const FirstCall)
810 : {
811 :
812 : // SUBROUTINE INFORMATION:
813 : // AUTHOR Peter Graham Ellis
814 : // DATE WRITTEN March 2000
815 : // MODIFIED na
816 : // RE-ENGINEERED na
817 :
818 : // PURPOSE OF THIS SUBROUTINE:
819 : // This subroutine is for initializations of the ZonePlenum components.
820 :
821 : // METHODOLOGY EMPLOYED:
822 : // Similar to the Zone Splitter component but with interactions to the plenum zone.
823 :
824 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
825 : int InletNode;
826 : int OutletNode;
827 : int ZoneNodeNum;
828 : int NodeIndex;
829 :
830 : // Do the Begin Environment initializations
831 2 : if (state.dataZonePlenum->MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
832 :
833 0 : for (int PlenumZoneNum = 1; PlenumZoneNum <= state.dataZonePlenum->NumZoneSupplyPlenums; ++PlenumZoneNum) {
834 :
835 0 : ZoneNodeNum = state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).ZoneNodeNum;
836 0 : auto &node = state.dataLoopNodes->Node(ZoneNodeNum);
837 0 : node.Temp = 20.0;
838 0 : node.MassFlowRate = 0.0;
839 0 : node.Quality = 1.0;
840 0 : node.Press = state.dataEnvrn->OutBaroPress;
841 0 : node.HumRat = state.dataEnvrn->OutHumRat;
842 0 : node.Enthalpy = PsyHFnTdbW(node.Temp, node.HumRat);
843 :
844 0 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).ZoneTemp = 20.0;
845 0 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).ZoneHumRat = 0.0;
846 0 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).ZoneEnthalpy = 0.0;
847 0 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletTemp = 0.0;
848 0 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletHumRat = 0.0;
849 0 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletEnthalpy = 0.0;
850 0 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletPressure = 0.0;
851 0 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletMassFlowRate = 0.0;
852 0 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletMassFlowRateMaxAvail = 0.0;
853 0 : state.dataZonePlenum->ZoneSupPlenCond(PlenumZoneNum).InletMassFlowRateMinAvail = 0.0;
854 : }
855 :
856 0 : state.dataZonePlenum->MyEnvrnFlag = false;
857 : }
858 :
859 2 : if (!state.dataGlobal->BeginEnvrnFlag) {
860 2 : state.dataZonePlenum->MyEnvrnFlag = true;
861 : }
862 :
863 : // Do the following initializations (every time step): This should be the info from
864 : // the previous components outlets or the node data in this section.
865 :
866 2 : InletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletNode;
867 2 : auto const &inletNode = state.dataLoopNodes->Node(InletNode);
868 2 : ZoneNodeNum = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneNodeNum;
869 2 : auto &zoneNode = state.dataLoopNodes->Node(ZoneNodeNum);
870 :
871 2 : if (FirstHVACIteration && FirstCall) {
872 1 : if (inletNode.MassFlowRate > 0.0) {
873 0 : zoneNode.MassFlowRate = inletNode.MassFlowRate;
874 0 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
875 0 : OutletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletNode(NodeIndex);
876 0 : state.dataLoopNodes->Node(OutletNode).MassFlowRate =
877 0 : inletNode.MassFlowRate / state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes;
878 : }
879 : }
880 1 : if (inletNode.MassFlowRateMaxAvail > 0.0) {
881 0 : zoneNode.MassFlowRateMaxAvail = inletNode.MassFlowRateMaxAvail;
882 0 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
883 0 : OutletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletNode(NodeIndex);
884 0 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail =
885 0 : inletNode.MassFlowRateMaxAvail / state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes;
886 : }
887 : }
888 :
889 : } // For FirstHVACIteration and FirstCall
890 :
891 2 : if (FirstCall) {
892 :
893 1 : if (inletNode.MassFlowRateMaxAvail == 0.0) { // For Node inlet Max Avail = 0.0
894 :
895 2 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
896 1 : OutletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletNode(NodeIndex);
897 1 : auto &outletNode = state.dataLoopNodes->Node(OutletNode);
898 1 : outletNode.MassFlowRate = 0.0;
899 1 : outletNode.MassFlowRateMaxAvail = 0.0;
900 1 : outletNode.MassFlowRateMinAvail = 0.0;
901 : }
902 :
903 1 : zoneNode.MassFlowRate = 0.0;
904 1 : zoneNode.MassFlowRateMaxAvail = 0.0;
905 1 : zoneNode.MassFlowRateMinAvail = 0.0;
906 :
907 : } // For Node inlet Max Avail = 0.0
908 :
909 : // Add stuff to calculate conduction inputs to the zone plenum
910 : // Now load the zone conditions
911 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneTemp = zoneNode.Temp;
912 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneHumRat = zoneNode.HumRat;
913 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneEnthalpy = zoneNode.Enthalpy;
914 :
915 2 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
916 1 : OutletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletNode(NodeIndex);
917 1 : auto &outletNode = state.dataLoopNodes->Node(OutletNode);
918 1 : outletNode.Press = inletNode.Press;
919 1 : outletNode.Quality = inletNode.Quality;
920 : }
921 :
922 1 : zoneNode.Press = inletNode.Press;
923 1 : zoneNode.Quality = inletNode.Quality;
924 :
925 : } else { // On the second call from the ZoneEquipManager this is where the flows are passed back to
926 : // the supply plenum inlet.
927 2 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
928 1 : OutletNode = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletNode(NodeIndex);
929 1 : auto const &outletNode = state.dataLoopNodes->Node(OutletNode);
930 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletMassFlowRate(NodeIndex) = outletNode.MassFlowRate;
931 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail(NodeIndex) = outletNode.MassFlowRateMaxAvail;
932 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletMassFlowRateMinAvail(NodeIndex) = outletNode.MassFlowRateMinAvail;
933 : }
934 :
935 : } // For FirstCall
936 2 : }
937 :
938 8 : void CalcAirZoneReturnPlenum(EnergyPlusData &state, int const ZonePlenumNum)
939 : {
940 :
941 : // SUBROUTINE INFORMATION:
942 : // AUTHOR Peter Graham Ellis
943 : // DATE WRITTEN November 2000
944 : // MODIFIED na
945 : // RE-ENGINEERED na
946 :
947 : // Using/Aliasing
948 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
949 8 : int InletNodeNum(0); // inlet node number
950 8 : int IndNum(0); // induced air index
951 8 : int ADUListIndex(0); // air distribution unit index in zone return plenum data structure
952 8 : Real64 TotIndMassFlowRate(0.0); // total induced air mass flow rate [kg/s]
953 :
954 : // Reset the totals to zero before they are summed.
955 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate = 0.0;
956 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail = 0.0;
957 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMinAvail = 0.0;
958 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletTemp = 0.0;
959 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletHumRat = 0.0;
960 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletPressure = 0.0;
961 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletEnthalpy = 0.0;
962 8 : TotIndMassFlowRate = 0.0;
963 :
964 33 : for (InletNodeNum = 1; InletNodeNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInletNodes; ++InletNodeNum) {
965 25 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate +=
966 25 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRate(InletNodeNum);
967 25 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail +=
968 25 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRateMaxAvail(InletNodeNum);
969 25 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMinAvail +=
970 25 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRateMinAvail(InletNodeNum);
971 : }
972 :
973 8 : if (state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate > 0.0) {
974 :
975 : // "Momentum balance" to get outlet air pressure
976 20 : for (InletNodeNum = 1; InletNodeNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInletNodes; ++InletNodeNum) {
977 :
978 16 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletPressure +=
979 16 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletPressure(InletNodeNum) *
980 16 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletMassFlowRate(InletNodeNum) /
981 16 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate;
982 : }
983 :
984 : } else {
985 : // Mass Flow in air loop is zero and loop is not operating.
986 : // Arbitrarily set the output to the first inlet leg
987 4 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletPressure = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InletPressure(1);
988 : }
989 :
990 : // add in the leak flow rate, if any. Don't alter the pressure calc (it is not used anyway)
991 32 : for (ADUListIndex = 1; ADUListIndex <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumADUs; ++ADUListIndex) {
992 24 : int ADUNum = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ADUIndex(ADUListIndex);
993 24 : if (state.dataDefineEquipment->AirDistUnit(ADUNum).UpStreamLeak || state.dataDefineEquipment->AirDistUnit(ADUNum).DownStreamLeak) {
994 0 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate +=
995 0 : state.dataDefineEquipment->AirDistUnit(ADUNum).MassFlowRateUpStrLk +
996 0 : state.dataDefineEquipment->AirDistUnit(ADUNum).MassFlowRateDnStrLk;
997 0 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail +=
998 0 : state.dataDefineEquipment->AirDistUnit(ADUNum).MaxAvailDelta;
999 0 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMinAvail +=
1000 0 : state.dataDefineEquipment->AirDistUnit(ADUNum).MinAvailDelta;
1001 : }
1002 : }
1003 : // Sum up induced air flow rate
1004 18 : for (IndNum = 1; IndNum <= state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).NumInducedNodes; ++IndNum) {
1005 10 : TotIndMassFlowRate += state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).InducedMassFlowRate(IndNum);
1006 : }
1007 :
1008 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate -= TotIndMassFlowRate;
1009 :
1010 : // Set the Plenum Outlet to the Zone Node conditions
1011 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletHumRat = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneHumRat;
1012 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletEnthalpy = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneEnthalpy;
1013 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletTemp = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).ZoneTemp;
1014 : // make sure the MassFlowMaxAvail >= MassFlowRate
1015 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail =
1016 8 : max(state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail,
1017 8 : state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum).OutletMassFlowRate);
1018 8 : }
1019 :
1020 2 : void CalcAirZoneSupplyPlenum(EnergyPlusData &state, int const ZonePlenumNum, bool const FirstCall)
1021 : {
1022 :
1023 : // SUBROUTINE INFORMATION:
1024 : // AUTHOR Peter Graham Ellis
1025 : // DATE WRITTEN March 2000
1026 : // MODIFIED na
1027 : // RE-ENGINEERED na
1028 :
1029 : // METHODOLOGY EMPLOYED:
1030 : // Similar to the Zone Splitter component but with interactions to the plenum zone.
1031 :
1032 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1033 : int NodeIndex;
1034 :
1035 : // The first time through the State properties are passed through
1036 2 : if (FirstCall) {
1037 : // Moisture balance to get outlet air humidity ratio
1038 2 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
1039 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletHumRat(NodeIndex) =
1040 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneHumRat;
1041 : }
1042 :
1043 : // Energy balance to get outlet air enthalpy
1044 2 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
1045 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletEnthalpy(NodeIndex) =
1046 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneEnthalpy;
1047 : }
1048 :
1049 : // Set outlet temperatures equal to inlet temperature
1050 2 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
1051 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletTemp(NodeIndex) =
1052 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).ZoneTemp;
1053 : }
1054 :
1055 : } else {
1056 : // This is the second time through and this is where the mass flows from the outlets are
1057 : // summed and then assigned upstream to the inlet node.
1058 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRate = 0.0;
1059 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRateMaxAvail = 0.0;
1060 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRateMinAvail = 0.0;
1061 2 : for (NodeIndex = 1; NodeIndex <= state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).NumOutletNodes; ++NodeIndex) {
1062 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRate +=
1063 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletMassFlowRate(NodeIndex);
1064 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRateMaxAvail +=
1065 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletMassFlowRateMaxAvail(NodeIndex);
1066 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).InletMassFlowRateMinAvail +=
1067 1 : state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum).OutletMassFlowRateMinAvail(NodeIndex);
1068 : }
1069 : }
1070 2 : }
1071 :
1072 : // End Algorithm Section of the Module
1073 : // *****************************************************************************
1074 :
1075 : // Beginning of Update subroutines for the ZonePlenum Module
1076 : // *****************************************************************************
1077 :
1078 9 : void UpdateAirZoneReturnPlenum(EnergyPlusData &state, int const ZonePlenumNum)
1079 : {
1080 :
1081 : // SUBROUTINE INFORMATION:
1082 : // AUTHOR Peter Graham Ellis
1083 : // DATE WRITTEN November 2000
1084 :
1085 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1086 9 : auto const &zoneRetPlenCond = state.dataZonePlenum->ZoneRetPlenCond(ZonePlenumNum);
1087 9 : auto &outletNode = state.dataLoopNodes->Node(zoneRetPlenCond.OutletNode);
1088 9 : auto const &inletNode = state.dataLoopNodes->Node(zoneRetPlenCond.InletNode(1));
1089 9 : auto &zoneNode = state.dataLoopNodes->Node(zoneRetPlenCond.ZoneNodeNum);
1090 :
1091 : // Set the outlet air nodes of the ZonePlenum
1092 9 : outletNode.MassFlowRate = zoneRetPlenCond.OutletMassFlowRate;
1093 9 : outletNode.MassFlowRateMaxAvail = zoneRetPlenCond.OutletMassFlowRateMaxAvail;
1094 9 : outletNode.MassFlowRateMinAvail = zoneRetPlenCond.OutletMassFlowRateMinAvail;
1095 :
1096 9 : zoneNode.MassFlowRate = zoneRetPlenCond.OutletMassFlowRate;
1097 9 : zoneNode.MassFlowRateMaxAvail = zoneRetPlenCond.OutletMassFlowRateMaxAvail;
1098 9 : zoneNode.MassFlowRateMinAvail = zoneRetPlenCond.OutletMassFlowRateMinAvail;
1099 9 : zoneNode.Press = zoneRetPlenCond.OutletPressure;
1100 :
1101 9 : outletNode.Temp = zoneRetPlenCond.OutletTemp;
1102 9 : outletNode.HumRat = zoneRetPlenCond.OutletHumRat;
1103 9 : outletNode.Enthalpy = zoneRetPlenCond.OutletEnthalpy;
1104 9 : outletNode.Press = zoneRetPlenCond.OutletPressure;
1105 21 : for (int IndNum = 1; IndNum <= zoneRetPlenCond.NumInducedNodes; ++IndNum) {
1106 12 : int InducedNode = zoneRetPlenCond.InducedNode(IndNum);
1107 12 : auto &inducedNode = state.dataLoopNodes->Node(InducedNode);
1108 12 : inducedNode.Temp = zoneRetPlenCond.InducedTemp(IndNum);
1109 12 : inducedNode.HumRat = zoneRetPlenCond.InducedHumRat(IndNum);
1110 12 : inducedNode.Enthalpy = zoneRetPlenCond.InducedEnthalpy(IndNum);
1111 12 : inducedNode.Press = zoneRetPlenCond.InducedPressure(IndNum);
1112 12 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1113 2 : inducedNode.CO2 = zoneRetPlenCond.InducedCO2(IndNum);
1114 : }
1115 12 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1116 2 : inducedNode.GenContam = zoneRetPlenCond.InducedGenContam(IndNum);
1117 : }
1118 12 : inducedNode.Quality = inletNode.Quality;
1119 : }
1120 :
1121 : // Set the outlet nodes for properties that are just pass through and not used
1122 9 : outletNode.Quality = inletNode.Quality;
1123 9 : zoneNode.Quality = inletNode.Quality;
1124 :
1125 : // Set the outlet node contaminant properties if needed. The zone contaminant conditions are calculated in ZoneContaminantPredictorCorrector
1126 9 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1127 1 : if (zoneRetPlenCond.OutletMassFlowRate > 0.0) {
1128 : // CO2 balance to get outlet air CO2
1129 0 : outletNode.CO2 = 0.0;
1130 0 : for (int InletNodeNum = 1; InletNodeNum <= zoneRetPlenCond.NumInletNodes; ++InletNodeNum) {
1131 0 : outletNode.CO2 += state.dataLoopNodes->Node(zoneRetPlenCond.InletNode(InletNodeNum)).CO2 *
1132 0 : zoneRetPlenCond.InletMassFlowRate(InletNodeNum) / zoneRetPlenCond.OutletMassFlowRate;
1133 : }
1134 0 : zoneNode.CO2 = outletNode.CO2;
1135 : } else {
1136 1 : outletNode.CO2 = zoneNode.CO2;
1137 : }
1138 : }
1139 9 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1140 1 : if (zoneRetPlenCond.OutletMassFlowRate > 0.0) {
1141 : // GenContam balance to get outlet air GenContam
1142 0 : outletNode.GenContam = 0.0;
1143 0 : for (int InletNodeNum = 1; InletNodeNum <= zoneRetPlenCond.NumInletNodes; ++InletNodeNum) {
1144 0 : outletNode.GenContam += state.dataLoopNodes->Node(zoneRetPlenCond.InletNode(InletNodeNum)).GenContam *
1145 0 : zoneRetPlenCond.InletMassFlowRate(InletNodeNum) / zoneRetPlenCond.OutletMassFlowRate;
1146 : }
1147 0 : zoneNode.GenContam = outletNode.GenContam;
1148 : } else {
1149 1 : outletNode.GenContam = zoneNode.GenContam;
1150 : }
1151 : }
1152 9 : }
1153 :
1154 2 : void UpdateAirZoneSupplyPlenum(EnergyPlusData &state, int const ZonePlenumNum, bool &PlenumInletChanged, bool const FirstCall)
1155 : {
1156 :
1157 : // SUBROUTINE INFORMATION:
1158 : // AUTHOR Peter Graham Ellis
1159 : // DATE WRITTEN March 2000
1160 :
1161 : // METHODOLOGY EMPLOYED:
1162 : // Similar to the Zone Splitter component but with interactions to the plenum zone.
1163 :
1164 : // SUBROUTINE PARAMETER DEFINITIONS:
1165 2 : Real64 constexpr FlowRateToler = 0.01; // Tolerance for mass flow rate convergence (in kg/s)
1166 :
1167 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1168 2 : auto const &zoneSupPlenCon = state.dataZonePlenum->ZoneSupPlenCond(ZonePlenumNum);
1169 2 : auto &inletNode = state.dataLoopNodes->Node(zoneSupPlenCon.InletNode);
1170 2 : auto &zoneNode = state.dataLoopNodes->Node(zoneSupPlenCon.ZoneNodeNum);
1171 :
1172 : // On the FirstCall the State properties are passed through and the mass flows are not dealt with
1173 2 : if (FirstCall) {
1174 : // Set the outlet nodes for properties that just pass through and not used
1175 2 : for (int NodeIndex = 1; NodeIndex <= zoneSupPlenCon.NumOutletNodes; ++NodeIndex) {
1176 1 : int OutletNode = zoneSupPlenCon.OutletNode(NodeIndex);
1177 1 : auto &outletNode = state.dataLoopNodes->Node(OutletNode);
1178 1 : outletNode.Temp = zoneSupPlenCon.OutletTemp(NodeIndex);
1179 1 : outletNode.HumRat = zoneSupPlenCon.OutletHumRat(NodeIndex);
1180 1 : outletNode.Enthalpy = zoneSupPlenCon.OutletEnthalpy(NodeIndex);
1181 1 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1182 0 : outletNode.CO2 = inletNode.CO2;
1183 : }
1184 1 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1185 0 : outletNode.GenContam = inletNode.GenContam;
1186 : }
1187 : }
1188 :
1189 1 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1190 0 : zoneNode.CO2 = inletNode.CO2;
1191 : }
1192 1 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1193 0 : zoneNode.GenContam = inletNode.GenContam;
1194 : }
1195 :
1196 : } else {
1197 : // The second time through just updates the mass flow conditions back upstream to the inlet.
1198 1 : if (std::abs(inletNode.MassFlowRate - zoneSupPlenCon.InletMassFlowRate) > FlowRateToler) {
1199 0 : PlenumInletChanged = true;
1200 : }
1201 :
1202 1 : inletNode.MassFlowRate = zoneSupPlenCon.InletMassFlowRate;
1203 1 : inletNode.MassFlowRateMaxAvail = zoneSupPlenCon.InletMassFlowRateMaxAvail;
1204 1 : inletNode.MassFlowRateMinAvail = zoneSupPlenCon.InletMassFlowRateMinAvail;
1205 :
1206 1 : zoneNode.MassFlowRate = zoneSupPlenCon.InletMassFlowRate;
1207 1 : zoneNode.MassFlowRateMaxAvail = zoneSupPlenCon.InletMassFlowRateMaxAvail;
1208 1 : zoneNode.MassFlowRateMinAvail = zoneSupPlenCon.InletMassFlowRateMinAvail;
1209 :
1210 : } // For FirstCall
1211 2 : }
1212 :
1213 1 : int GetReturnPlenumIndex(EnergyPlusData &state, int const ExNodeNum)
1214 : {
1215 :
1216 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1217 : int WhichPlenum; // index to return plenum
1218 :
1219 : // Obtains and Allocates ZonePlenum related parameters from input file
1220 1 : if (state.dataZonePlenum->GetInputFlag) { // First time subroutine has been entered
1221 1 : GetZonePlenumInput(state);
1222 1 : state.dataZonePlenum->GetInputFlag = false;
1223 : }
1224 :
1225 1 : WhichPlenum = 0;
1226 1 : if (state.dataZonePlenum->NumZoneReturnPlenums > 0) {
1227 1 : for (int PlenumNum = 1; PlenumNum <= state.dataZonePlenum->NumZoneReturnPlenums; ++PlenumNum) {
1228 1 : if (ExNodeNum != state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).OutletNode) {
1229 0 : continue;
1230 : }
1231 1 : WhichPlenum = PlenumNum;
1232 1 : break;
1233 : }
1234 1 : if (WhichPlenum == 0) {
1235 0 : for (int PlenumNum = 1; PlenumNum <= state.dataZonePlenum->NumZoneReturnPlenums; ++PlenumNum) {
1236 0 : for (int InducedNodeNum = 1; InducedNodeNum <= state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).NumInducedNodes; ++InducedNodeNum) {
1237 0 : if (ExNodeNum != state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).InducedNode(InducedNodeNum)) {
1238 0 : continue;
1239 : }
1240 0 : WhichPlenum = PlenumNum;
1241 0 : break;
1242 : }
1243 0 : if (WhichPlenum > 0) {
1244 0 : break;
1245 : }
1246 : }
1247 : }
1248 : }
1249 :
1250 1 : return WhichPlenum;
1251 : }
1252 :
1253 1 : void GetReturnPlenumName(EnergyPlusData &state, int const ReturnPlenumIndex, std::string &ReturnPlenumName)
1254 : {
1255 :
1256 : // Obtains and Allocates ZonePlenum related parameters from input file
1257 1 : if (state.dataZonePlenum->GetInputFlag) { // First time subroutine has been entered
1258 0 : GetZonePlenumInput(state);
1259 0 : state.dataZonePlenum->GetInputFlag = false;
1260 : }
1261 :
1262 1 : ReturnPlenumName = " ";
1263 1 : if (state.dataZonePlenum->NumZoneReturnPlenums > 0) {
1264 1 : ReturnPlenumName = state.dataZonePlenum->ZoneRetPlenCond(ReturnPlenumIndex).ZonePlenumName;
1265 : }
1266 1 : }
1267 :
1268 2 : int getReturnPlenumIndexFromInletNode(EnergyPlusData &state, int const InNodeNum)
1269 : {
1270 :
1271 : // Obtains and Allocates ZonePlenum related parameters from input file
1272 2 : if (state.dataZonePlenum->GetInputFlag) { // First time subroutine has been entered
1273 2 : GetZonePlenumInput(state);
1274 2 : state.dataZonePlenum->GetInputFlag = false;
1275 : }
1276 :
1277 2 : int thisPlenum = 0;
1278 2 : if (state.dataZonePlenum->NumZoneReturnPlenums > 0) {
1279 0 : for (int PlenumNum = 1; PlenumNum <= state.dataZonePlenum->NumZoneReturnPlenums; ++PlenumNum) {
1280 0 : for (int InNodeCtr = 1; InNodeCtr <= state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).NumInletNodes; ++InNodeCtr) {
1281 0 : if (InNodeNum != state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).InletNode(InNodeCtr)) {
1282 0 : continue;
1283 : }
1284 0 : thisPlenum = PlenumNum;
1285 0 : break;
1286 : }
1287 0 : if (thisPlenum > 0) {
1288 0 : break;
1289 : }
1290 : }
1291 : }
1292 :
1293 2 : return thisPlenum;
1294 : }
1295 :
1296 5 : bool ValidateInducedNode(EnergyPlusData &state, int const InduceNodeNum, int const NumReturnNodes, Array1D<int> const &ReturnNode)
1297 : {
1298 : // Ensure induced node is used as inlet node of zoe equipment
1299 5 : bool Nodefound = false;
1300 :
1301 : // Obtains and Allocates ZonePlenum related parameters from input file
1302 5 : if (state.dataZonePlenum->GetInputFlag) { // First time subroutine has been entered
1303 2 : GetZonePlenumInput(state);
1304 2 : state.dataZonePlenum->GetInputFlag = false;
1305 : }
1306 :
1307 5 : if (state.dataZonePlenum->NumZoneReturnPlenums > 0) {
1308 6 : for (int PlenumNum = 1; PlenumNum <= state.dataZonePlenum->NumZoneReturnPlenums; ++PlenumNum) {
1309 9 : for (int InduceNodeCtr = 1; InduceNodeCtr <= state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).NumInducedNodes; ++InduceNodeCtr) {
1310 8 : if (InduceNodeNum == state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).InducedNode(InduceNodeCtr)) {
1311 12 : for (int InNodeCtr = 1; InNodeCtr <= state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).NumInletNodes; ++InNodeCtr) {
1312 20 : for (int ReturnNodeNum = 1; ReturnNodeNum <= NumReturnNodes; ++ReturnNodeNum) {
1313 12 : if (ReturnNode(ReturnNodeNum) != state.dataZonePlenum->ZoneRetPlenCond(PlenumNum).InletNode(InNodeCtr)) {
1314 8 : continue;
1315 : }
1316 4 : Nodefound = true;
1317 4 : break;
1318 : }
1319 12 : if (Nodefound) {
1320 4 : break;
1321 : }
1322 : }
1323 : }
1324 8 : if (Nodefound) {
1325 4 : break;
1326 : }
1327 : }
1328 5 : if (Nodefound) {
1329 4 : break;
1330 : }
1331 : }
1332 : }
1333 :
1334 5 : return Nodefound;
1335 : }
1336 :
1337 : } // namespace EnergyPlus::ZonePlenum
|