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 : // ObjexxFCL Headers
49 : #include <ObjexxFCL/Fmath.hh>
50 :
51 : // EnergyPlus Headers
52 : #include <EnergyPlus/CurveManager.hh>
53 : #include <EnergyPlus/Data/EnergyPlusData.hh>
54 : #include <EnergyPlus/DataContaminantBalance.hh>
55 : #include <EnergyPlus/DataEnvironment.hh>
56 : #include <EnergyPlus/DataLoopNode.hh>
57 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
58 : #include <EnergyPlus/NodeInputManager.hh>
59 : #include <EnergyPlus/OutAirNodeManager.hh>
60 : #include <EnergyPlus/Psychrometrics.hh>
61 : #include <EnergyPlus/ScheduleManager.hh>
62 : #include <EnergyPlus/UtilityRoutines.hh>
63 :
64 : namespace EnergyPlus {
65 :
66 : namespace OutAirNodeManager {
67 : // Module containing the routines that deal with the outside air nodes
68 :
69 : // MODULE INFORMATION:
70 : // AUTHOR Fred Buhl
71 : // DATE WRITTEN September 1998
72 : // MODIFIED na
73 : // RE-ENGINEERED na
74 :
75 : // PURPOSE OF THIS MODULE:
76 : // To encapsulate the data and update the conditions for all the outside
77 : // air nodes in the problem.
78 :
79 : // METHODOLOGY EMPLOYED:
80 : // Outside air nodes provide the connection to outside conditions for the
81 : // EnergyPlus HVAC simulation. The list of air nodes specified in the input
82 : // file will be read in. Each air node will be updated to the outside environmental
83 : // conditions at the start of each EnergyPlus main time step.
84 :
85 : // REFERENCES:
86 :
87 : // OTHER NOTES:
88 :
89 : // USE STATEMENTS:
90 : // Use statements for data only modules
91 : // Using/Aliasing
92 : using namespace DataLoopNode;
93 : using namespace DataEnvironment;
94 :
95 248744 : void SetOutAirNodes(EnergyPlusData &state)
96 : {
97 :
98 : // SUBROUTINE INFORMATION:
99 : // AUTHOR Fred Buhl
100 : // DATE WRITTEN September 1998
101 : // MODIFIED na
102 : // RE-ENGINEERED na
103 :
104 : // PURPOSE OF THIS SUBROUTINE:
105 : // Make sure the outside air nodes are prepared for the HVAC simulation
106 :
107 : // METHODOLOGY EMPLOYED:
108 : // Use appropriate flag to check for needed action
109 :
110 248744 : if (state.dataOutAirNodeMgr->GetOutAirNodesInputFlag) { // First time subroutine has been entered
111 137 : GetOutAirNodesInput(state); // Get OutAir Nodes data
112 137 : state.dataOutAirNodeMgr->GetOutAirNodesInputFlag = false;
113 : }
114 248744 : InitOutAirNodes(state);
115 248744 : }
116 :
117 251 : void GetOutAirNodesInput(EnergyPlusData &state)
118 : {
119 :
120 : // SUBROUTINE INFORMATION:
121 : // AUTHOR Fred Buhl
122 : // DATE WRITTEN September 1998
123 : // MODIFIED na
124 : // RE-ENGINEERED na
125 :
126 : // PURPOSE OF THIS SUBROUTINE
127 : // Read in the list of outside air nodes & store in array OutAirInletNodeList
128 :
129 : // METHODOLOGY EMPLOYED:
130 : // Use the Get routines from the InputProcessor module.
131 :
132 : // Using/Aliasing
133 : using namespace NodeInputManager;
134 :
135 : // Locals
136 : // SUBROUTINE PARAMETER DEFINITIONS:
137 : static constexpr std::string_view RoutineName("GetOutAirNodesInput: "); // include trailing blank space
138 : static constexpr std::string_view routineName = "GetOutAirNodesInput";
139 :
140 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
141 : int NumOutAirInletNodeLists;
142 : int NumOutsideAirNodeSingles;
143 : int NumNums; // Number of REAL(r64) numbers returned by GetObjectItem
144 : int NumAlphas; // Number of alphanumerics returned by GetObjectItem
145 : int NumParams;
146 251 : Array1D_int NodeNums;
147 : int NumNodes;
148 : int IOStat; // Status flag from GetObjectItem
149 : int NodeNum; // index into NodeNums
150 : // INTEGER :: OutAirNodeNum ! index into OutAirInletNodeList
151 : int OutAirInletNodeListNum; // OUTSIDE AIR INLET NODE LIST index
152 : int OutsideAirNodeSingleNum; // OUTSIDE AIR NODE index
153 : int AlphaNum; // index into Alphas
154 : std::size_t ListSize; // size of OutAirInletNodeList
155 : // LOGICAL :: AlreadyInList ! flag used for checking for duplicate input
156 : bool ErrorsFound;
157 : bool ErrInList;
158 : std::size_t CurSize;
159 : int NextFluidStreamNum; // Fluid stream index (all outside air inlet nodes need a unique fluid stream number)
160 251 : Array1D_int TmpNums;
161 251 : std::string CurrentModuleObject; // Object type for getting and error messages
162 251 : Array1D_string Alphas; // Alpha input items for object
163 251 : Array1D_string cAlphaFields; // Alpha field names
164 251 : Array1D_string cNumericFields; // Numeric field names
165 251 : Array1D<Real64> Numbers; // Numeric input items for object
166 251 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
167 251 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
168 251 : int MaxNums(0); // Maximum number of numeric input fields
169 251 : int MaxAlphas(0); // Maximum number of alpha input fields
170 251 : int TotalArgs(0); // Total number of alpha and numeric arguments (max) for a
171 :
172 251 : NumOutAirInletNodeLists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "OutdoorAir:NodeList");
173 251 : NumOutsideAirNodeSingles = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "OutdoorAir:Node");
174 251 : state.dataOutAirNodeMgr->NumOutsideAirNodes = 0;
175 251 : ErrorsFound = false;
176 251 : NextFluidStreamNum = 1;
177 :
178 251 : ListSize = 0;
179 251 : CurSize = 100;
180 251 : TmpNums.dimension(CurSize, 0);
181 :
182 251 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "NodeList", NumParams, NumAlphas, NumNums);
183 251 : NodeNums.dimension(NumParams, 0);
184 :
185 251 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "OutdoorAir:NodeList", TotalArgs, NumAlphas, NumNums);
186 251 : MaxNums = max(MaxNums, NumNums);
187 251 : MaxAlphas = max(MaxAlphas, NumAlphas);
188 251 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "OutdoorAir:Node", TotalArgs, NumAlphas, NumNums);
189 251 : MaxNums = max(MaxNums, NumNums);
190 251 : MaxAlphas = max(MaxAlphas, NumAlphas);
191 :
192 251 : Alphas.allocate(MaxAlphas);
193 251 : cAlphaFields.allocate(MaxAlphas);
194 251 : cNumericFields.allocate(MaxNums);
195 251 : Numbers.dimension(MaxNums, 0.0);
196 251 : lAlphaBlanks.dimension(MaxAlphas, true);
197 251 : lNumericBlanks.dimension(MaxNums, true);
198 :
199 251 : if (NumOutAirInletNodeLists > 0) {
200 : // Loop over all outside air inlet nodes in the input and count them
201 76 : CurrentModuleObject = "OutdoorAir:NodeList";
202 197 : for (OutAirInletNodeListNum = 1; OutAirInletNodeListNum <= NumOutAirInletNodeLists; ++OutAirInletNodeListNum) {
203 121 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
204 : CurrentModuleObject,
205 : OutAirInletNodeListNum,
206 : Alphas,
207 : NumAlphas,
208 : Numbers,
209 : NumNums,
210 : IOStat,
211 : lNumericBlanks,
212 : lAlphaBlanks,
213 : cAlphaFields,
214 : cNumericFields);
215 :
216 254 : for (AlphaNum = 1; AlphaNum <= NumAlphas; ++AlphaNum) {
217 133 : ErrInList = false;
218 : // To support HVAC diagram, every outside inlet node must have a unique fluid stream number
219 : // GetNodeNums will increment the value across a node list, the starting value must be incremented
220 : // here across lists and across objects
221 266 : GetNodeNums(state,
222 133 : Alphas(AlphaNum),
223 : NumNodes,
224 : NodeNums,
225 : ErrInList,
226 : DataLoopNode::NodeFluidType::Air,
227 : DataLoopNode::ConnectionObjectType::OutdoorAirNodeList,
228 : CurrentModuleObject,
229 : DataLoopNode::ConnectionType::OutsideAir,
230 : static_cast<NodeInputManager::CompFluidStream>(NextFluidStreamNum),
231 : ObjectIsNotParent,
232 : IncrementFluidStreamYes,
233 133 : cAlphaFields(AlphaNum));
234 133 : NextFluidStreamNum += NumNodes;
235 133 : if (ErrInList) {
236 0 : ShowContinueError(state, format("Occurred in {}, {} = {}", CurrentModuleObject, cAlphaFields(AlphaNum), Alphas(AlphaNum)));
237 0 : ErrorsFound = true;
238 : }
239 284 : for (NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
240 : // Duplicates here are not a problem, just ignore
241 151 : if (!any_eq(TmpNums, NodeNums(NodeNum))) {
242 151 : ++ListSize;
243 151 : if (ListSize > CurSize) {
244 0 : TmpNums.redimension(CurSize += 100, 0);
245 : }
246 151 : TmpNums(ListSize) = NodeNums(NodeNum);
247 : }
248 : }
249 : }
250 : }
251 :
252 76 : if (ErrorsFound) {
253 0 : ShowFatalError(state, format("{}Errors found in getting {} input.", RoutineName, CurrentModuleObject));
254 : }
255 : }
256 :
257 251 : if (NumOutsideAirNodeSingles > 0) {
258 : // Loop over all single outside air nodes in the input
259 79 : CurrentModuleObject = "OutdoorAir:Node";
260 187 : for (OutsideAirNodeSingleNum = 1; OutsideAirNodeSingleNum <= NumOutsideAirNodeSingles; ++OutsideAirNodeSingleNum) {
261 108 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
262 : CurrentModuleObject,
263 : OutsideAirNodeSingleNum,
264 : Alphas,
265 : NumAlphas,
266 : Numbers,
267 : NumNums,
268 : IOStat,
269 : lNumericBlanks,
270 : lAlphaBlanks,
271 : cAlphaFields,
272 : cNumericFields);
273 :
274 108 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
275 :
276 108 : ErrInList = false;
277 : // To support HVAC diagram, every outside inlet node must have a unique fluid stream number
278 : // GetNodeNums will increment the value across a node list, the starting value must be incremented
279 : // here across lists and across objects
280 216 : GetNodeNums(state,
281 108 : Alphas(1),
282 : NumNodes,
283 : NodeNums,
284 : ErrInList,
285 : DataLoopNode::NodeFluidType::Air,
286 : DataLoopNode::ConnectionObjectType::OutdoorAirNode,
287 : CurrentModuleObject,
288 : DataLoopNode::ConnectionType::OutsideAir,
289 : static_cast<NodeInputManager::CompFluidStream>(NextFluidStreamNum),
290 : ObjectIsNotParent,
291 : IncrementFluidStreamYes,
292 108 : cAlphaFields(1));
293 108 : NextFluidStreamNum += NumNodes;
294 108 : if (ErrInList) {
295 0 : ShowContinueError(state, format("Occurred in {}, {} = {}", CurrentModuleObject, cAlphaFields(1), Alphas(1)));
296 0 : ErrorsFound = true;
297 : }
298 :
299 108 : if (NumNodes > 1) {
300 0 : ShowSevereError(state, format("{}, {} = {}", CurrentModuleObject, cAlphaFields(1), Alphas(1)));
301 0 : ShowContinueError(state, "...appears to point to a node list, not a single node.");
302 0 : ErrorsFound = true;
303 0 : continue;
304 : }
305 :
306 108 : if (!any_eq(TmpNums, NodeNums(1))) {
307 108 : ++ListSize;
308 108 : if (ListSize > CurSize) {
309 0 : TmpNums.redimension(CurSize += 100, 0);
310 : }
311 108 : TmpNums(ListSize) = NodeNums(1);
312 : } else { // Duplicates are a problem
313 0 : ShowSevereError(state, format("{}, duplicate {} = {}", CurrentModuleObject, cAlphaFields(1), Alphas(1)));
314 0 : ShowContinueError(state, format("Duplicate {} might be found in an OutdoorAir:NodeList.", cAlphaFields(1)));
315 0 : ErrorsFound = true;
316 0 : continue;
317 : }
318 :
319 : // Set additional node properties
320 108 : if (NumNums > 0) {
321 40 : state.dataLoopNodes->Node(NodeNums(1)).Height = Numbers(1);
322 : }
323 :
324 108 : if (NumAlphas > 1) {
325 4 : state.dataGlobal->AnyLocalEnvironmentsInModel = true;
326 : }
327 :
328 108 : if (NumAlphas <= 1 || lAlphaBlanks(2)) {
329 3 : } else if ((state.dataLoopNodes->Node(NodeNums(1)).outAirDryBulbSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
330 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
331 0 : ErrorsFound = true;
332 : }
333 :
334 108 : if (NumAlphas <= 2 || lAlphaBlanks(3)) {
335 3 : } else if ((state.dataLoopNodes->Node(NodeNums(1)).outAirWetBulbSched = Sched::GetSchedule(state, Alphas(3))) == nullptr) {
336 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(3), Alphas(3));
337 0 : ErrorsFound = true;
338 : }
339 :
340 108 : if (NumAlphas <= 3 || lAlphaBlanks(4)) {
341 3 : } else if ((state.dataLoopNodes->Node(NodeNums(1)).outAirWindSpeedSched = Sched::GetSchedule(state, Alphas(4))) == nullptr) {
342 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(4), Alphas(4));
343 0 : ErrorsFound = true;
344 : }
345 :
346 108 : if (NumAlphas <= 4 || lAlphaBlanks(5)) {
347 3 : } else if ((state.dataLoopNodes->Node(NodeNums(1)).outAirWindDirSched = Sched::GetSchedule(state, Alphas(5))) == nullptr) {
348 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(5), Alphas(5));
349 0 : ErrorsFound = true;
350 : }
351 :
352 108 : if (NumAlphas > 8) {
353 0 : ShowSevereError(state, format("{}, {} = {}", CurrentModuleObject, cAlphaFields(1), Alphas(1)));
354 0 : ShowContinueError(state, "Object Definition indicates more than 7 Alpha Objects.");
355 0 : ErrorsFound = true;
356 0 : continue;
357 : }
358 213 : if (state.dataLoopNodes->Node(NodeNums(1)).outAirDryBulbSched != nullptr ||
359 105 : state.dataLoopNodes->Node(NodeNums(1)).outAirWetBulbSched != nullptr) {
360 3 : state.dataLoopNodes->Node(NodeNums(1)).IsLocalNode = true;
361 : }
362 : }
363 79 : if (ErrorsFound) {
364 0 : ShowFatalError(state, format("{}Errors found in getting {} input.", RoutineName, CurrentModuleObject));
365 : }
366 : }
367 :
368 251 : if (ListSize > 0) {
369 130 : state.dataOutAirNodeMgr->NumOutsideAirNodes = ListSize;
370 130 : state.dataOutAirNodeMgr->OutsideAirNodeList = TmpNums({1, static_cast<int>(ListSize)});
371 : }
372 251 : }
373 :
374 248747 : void InitOutAirNodes(EnergyPlusData &state)
375 : {
376 : // SUBROUTINE INFORMATION:
377 : // AUTHOR Fred Buhl
378 : // DATE WRITTEN Sept 1998
379 : // MODIFIED B. Griffith, added EMS override
380 : // RE-ENGINEERED na
381 :
382 : // PURPOSE OF THIS SUBROUTINE:
383 : // Initialize the outside air node data data. In Particular,
384 : // set the outside air nodes to the outside conditions at the
385 : // start of every heat balance time step.
386 :
387 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
388 : int OutsideAirNodeNum;
389 : int NodeNum;
390 :
391 : // Do the begin time step initialization
392 471895 : for (OutsideAirNodeNum = 1; OutsideAirNodeNum <= state.dataOutAirNodeMgr->NumOutsideAirNodes; ++OutsideAirNodeNum) {
393 223148 : NodeNum = state.dataOutAirNodeMgr->OutsideAirNodeList(OutsideAirNodeNum);
394 223148 : SetOANodeValues(state, NodeNum, true);
395 : }
396 248747 : }
397 :
398 230 : bool CheckOutAirNodeNumber(EnergyPlusData &state, int const NodeNumber) // Number of node to check to see if in Outside Air list
399 : {
400 :
401 : // FUNCTION INFORMATION:
402 : // AUTHOR Linda Lawrie
403 : // DATE WRITTEN Feb 2007
404 : // MODIFIED na
405 : // RE-ENGINEERED na
406 :
407 : // PURPOSE OF THIS FUNCTION:
408 : // Provide an entry into the OutAirNode List for checking from other routines.
409 :
410 : // METHODOLOGY EMPLOYED:
411 : // na
412 :
413 : // REFERENCES:
414 : // na
415 :
416 : // USE STATEMENTS:
417 : // na
418 :
419 : // Return value
420 : bool Okay; // True if found, false if not
421 :
422 : // Locals
423 : // FUNCTION ARGUMENT DEFINITIONS:
424 :
425 : // FUNCTION PARAMETER DEFINITIONS:
426 : // na
427 :
428 : // INTERFACE BLOCK SPECIFICATIONS:
429 : // na
430 :
431 : // DERIVED TYPE DEFINITIONS:
432 : // na
433 :
434 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
435 : // na
436 :
437 230 : if (state.dataOutAirNodeMgr->GetOutAirNodesInputFlag) { // First time subroutine has been entered
438 98 : GetOutAirNodesInput(state); // Get Out Air Nodes data
439 98 : state.dataOutAirNodeMgr->GetOutAirNodesInputFlag = false;
440 98 : SetOutAirNodes(state);
441 : }
442 :
443 230 : if (any_eq(state.dataOutAirNodeMgr->OutsideAirNodeList, NodeNumber)) {
444 117 : Okay = true;
445 : } else {
446 113 : Okay = false;
447 : }
448 :
449 230 : return Okay;
450 : }
451 :
452 21 : void CheckAndAddAirNodeNumber(EnergyPlusData &state,
453 : int const NodeNumber, // Number of node to check to see if in Outside Air list
454 : bool &Okay // True if found, false if not
455 : )
456 : {
457 :
458 : // SUBROUTINE INFORMATION:
459 : // AUTHOR Linda Lawrie
460 : // DATE WRITTEN March 2007
461 : // MODIFIED na
462 : // RE-ENGINEERED na
463 :
464 : // PURPOSE OF THIS SUBROUTINE:
465 : // At the time of writing, some items (namely Chillers) have "made up" node
466 : // names for nodes that are "outside air nodes". Rather than fatal out, add
467 : // this subroutine which will check and then add a outside air node, if necessary.
468 :
469 : // METHODOLOGY EMPLOYED:
470 : // na
471 :
472 : // REFERENCES:
473 : // na
474 :
475 : // Using/Aliasing
476 : using namespace NodeInputManager;
477 :
478 : // Locals
479 : // SUBROUTINE ARGUMENT DEFINITIONS:
480 :
481 : // SUBROUTINE PARAMETER DEFINITIONS:
482 : // na
483 :
484 : // INTERFACE BLOCK SPECIFICATIONS:
485 : // na
486 :
487 : // DERIVED TYPE DEFINITIONS:
488 : // na
489 :
490 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
491 21 : Array1D_int TmpNums;
492 : int DummyNumber;
493 :
494 21 : if (state.dataOutAirNodeMgr->GetOutAirNodesInputFlag) { // First time subroutine has been entered
495 14 : GetOutAirNodesInput(state); // Get Out Air Nodes data
496 14 : state.dataOutAirNodeMgr->GetOutAirNodesInputFlag = false;
497 14 : SetOutAirNodes(state);
498 : }
499 :
500 21 : Okay = false;
501 :
502 21 : if (state.dataOutAirNodeMgr->NumOutsideAirNodes > 0) {
503 13 : if (any_eq(state.dataOutAirNodeMgr->OutsideAirNodeList, NodeNumber)) {
504 12 : Okay = true;
505 : } else {
506 1 : Okay = false;
507 : }
508 : } else {
509 8 : Okay = false;
510 : }
511 :
512 21 : if (NodeNumber > 0) {
513 21 : if (!Okay) { // Add new outside air node to list
514 9 : state.dataOutAirNodeMgr->OutsideAirNodeList.redimension(++state.dataOutAirNodeMgr->NumOutsideAirNodes);
515 9 : state.dataOutAirNodeMgr->OutsideAirNodeList(state.dataOutAirNodeMgr->NumOutsideAirNodes) = NodeNumber;
516 9 : TmpNums = state.dataOutAirNodeMgr->OutsideAirNodeList;
517 9 : bool errFlag(false);
518 : // register new node..
519 27 : GetNodeNums(state,
520 9 : state.dataLoopNodes->NodeID(NodeNumber),
521 : DummyNumber,
522 : TmpNums,
523 : errFlag,
524 : DataLoopNode::NodeFluidType::Air,
525 : DataLoopNode::ConnectionObjectType::OutdoorAirNode,
526 : "OutdoorAir:Node",
527 : DataLoopNode::ConnectionType::OutsideAir,
528 9 : static_cast<NodeInputManager::CompFluidStream>(state.dataOutAirNodeMgr->NumOutsideAirNodes),
529 : ObjectIsNotParent,
530 : IncrementFluidStreamYes);
531 9 : SetOANodeValues(state, NodeNumber, false);
532 : }
533 : }
534 21 : }
535 :
536 223157 : void SetOANodeValues(EnergyPlusData &state,
537 : int const NodeNum, // Number of node to check to see if in Outside Air list
538 : bool InitCall // True if Init calls, false if CheckAndAddAirNodeNumber calls
539 : )
540 : {
541 : // SUBROUTINE INFORMATION:
542 : // AUTHOR L. Gu
543 : // DATE WRITTEN July 2018
544 :
545 : // PURPOSE OF THIS SUBROUTINE:
546 : // Consolidate a block from both CheckAndAddAirNodeNumber and InitOutAirNodes to set
547 : // up outdoor node values
548 :
549 : using Psychrometrics::PsyHFnTdbW;
550 : using Psychrometrics::PsyTwbFnTdbWPb;
551 : using Psychrometrics::PsyWFnTdbTwbPb;
552 :
553 : // Set node data to global values
554 223157 : if (state.dataLoopNodes->Node(NodeNum).Height < 0.0) {
555 : // Note -- this setting is different than the DataEnvironment "AT" settings.
556 223151 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb = state.dataEnvrn->OutDryBulbTemp;
557 223151 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = state.dataEnvrn->OutWetBulbTemp;
558 223151 : if (InitCall) {
559 223142 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = state.dataEnvrn->WindSpeed;
560 : }
561 : } else {
562 6 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb = OutDryBulbTempAt(state, state.dataLoopNodes->Node(NodeNum).Height);
563 6 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = OutWetBulbTempAt(state, state.dataLoopNodes->Node(NodeNum).Height);
564 6 : if (InitCall) {
565 6 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = DataEnvironment::WindSpeedAt(state, state.dataLoopNodes->Node(NodeNum).Height);
566 : }
567 : }
568 223157 : if (!InitCall) {
569 9 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = state.dataEnvrn->WindSpeed;
570 : }
571 223157 : state.dataLoopNodes->Node(NodeNum).OutAirWindDir = state.dataEnvrn->WindDir;
572 :
573 223157 : if (InitCall) {
574 : // Set node data to local air node values if defined
575 223148 : if (state.dataLoopNodes->Node(NodeNum).outAirDryBulbSched != nullptr) {
576 4 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb = state.dataLoopNodes->Node(NodeNum).outAirDryBulbSched->getCurrentVal();
577 : }
578 223148 : if (state.dataLoopNodes->Node(NodeNum).outAirWetBulbSched != nullptr) {
579 3 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = state.dataLoopNodes->Node(NodeNum).outAirWetBulbSched->getCurrentVal();
580 : }
581 223148 : if (state.dataLoopNodes->Node(NodeNum).outAirWindSpeedSched != nullptr) {
582 3 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = state.dataLoopNodes->Node(NodeNum).outAirWindSpeedSched->getCurrentVal();
583 : }
584 223148 : if (state.dataLoopNodes->Node(NodeNum).outAirWindDirSched != nullptr) {
585 3 : state.dataLoopNodes->Node(NodeNum).OutAirWindDir = state.dataLoopNodes->Node(NodeNum).outAirWindDirSched->getCurrentVal();
586 : }
587 :
588 : // Set node data to EMS overwritten values if defined
589 223148 : if (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirDryBulb) {
590 1 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb = state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirDryBulb;
591 : }
592 223148 : if (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWetBulb) {
593 1 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWetBulb;
594 : }
595 223148 : if (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWindSpeed) {
596 0 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWindSpeed;
597 : }
598 223148 : if (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWindDir) {
599 0 : state.dataLoopNodes->Node(NodeNum).OutAirWindDir = state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWindDir;
600 : }
601 : }
602 :
603 223157 : state.dataLoopNodes->Node(NodeNum).Temp = state.dataLoopNodes->Node(NodeNum).OutAirDryBulb;
604 223157 : if (state.dataLoopNodes->Node(NodeNum).IsLocalNode) {
605 6 : if (InitCall) {
606 6 : if (state.dataLoopNodes->Node(NodeNum).OutAirWetBulb > state.dataLoopNodes->Node(NodeNum).OutAirDryBulb) {
607 0 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = state.dataLoopNodes->Node(NodeNum).OutAirDryBulb;
608 : }
609 6 : if (state.dataLoopNodes->Node(NodeNum).outAirWetBulbSched == nullptr &&
610 8 : !state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWetBulb &&
611 2 : (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirDryBulb ||
612 2 : state.dataLoopNodes->Node(NodeNum).outAirDryBulbSched != nullptr)) {
613 1 : state.dataLoopNodes->Node(NodeNum).HumRat = state.dataEnvrn->OutHumRat;
614 2 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = PsyTwbFnTdbWPb(
615 1 : state, state.dataLoopNodes->Node(NodeNum).OutAirDryBulb, state.dataEnvrn->OutHumRat, state.dataEnvrn->OutBaroPress);
616 : } else {
617 10 : state.dataLoopNodes->Node(NodeNum).HumRat = PsyWFnTdbTwbPb(state,
618 5 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb,
619 5 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb,
620 5 : state.dataEnvrn->OutBaroPress);
621 : }
622 : } else {
623 0 : state.dataLoopNodes->Node(NodeNum).HumRat = PsyWFnTdbTwbPb(state,
624 0 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb,
625 0 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb,
626 0 : state.dataEnvrn->OutBaroPress);
627 : }
628 : } else {
629 223151 : state.dataLoopNodes->Node(NodeNum).HumRat = state.dataEnvrn->OutHumRat;
630 : }
631 223157 : state.dataLoopNodes->Node(NodeNum).Enthalpy =
632 223157 : PsyHFnTdbW(state.dataLoopNodes->Node(NodeNum).OutAirDryBulb, state.dataLoopNodes->Node(NodeNum).HumRat);
633 223157 : state.dataLoopNodes->Node(NodeNum).Press = state.dataEnvrn->OutBaroPress;
634 223157 : state.dataLoopNodes->Node(NodeNum).Quality = 0.0;
635 : // Add contaminants
636 223157 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
637 3 : state.dataLoopNodes->Node(NodeNum).CO2 = state.dataContaminantBalance->OutdoorCO2;
638 : }
639 223157 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
640 0 : state.dataLoopNodes->Node(NodeNum).GenContam = state.dataContaminantBalance->OutdoorGC;
641 : }
642 223157 : }
643 :
644 : } // namespace OutAirNodeManager
645 :
646 : } // namespace EnergyPlus
|