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 2835728 : 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 2835728 : if (state.dataOutAirNodeMgr->GetOutAirNodesInputFlag) { // First time subroutine has been entered
111 756 : GetOutAirNodesInput(state); // Get OutAir Nodes data
112 756 : state.dataOutAirNodeMgr->GetOutAirNodesInputFlag = false;
113 : }
114 2835728 : InitOutAirNodes(state);
115 2835728 : }
116 :
117 801 : 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 801 : 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 801 : Array1D_int TmpNums;
161 801 : std::string CurrentModuleObject; // Object type for getting and error messages
162 801 : Array1D_string Alphas; // Alpha input items for object
163 801 : Array1D_string cAlphaFields; // Alpha field names
164 801 : Array1D_string cNumericFields; // Numeric field names
165 801 : Array1D<Real64> Numbers; // Numeric input items for object
166 801 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
167 801 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
168 801 : int MaxNums(0); // Maximum number of numeric input fields
169 801 : int MaxAlphas(0); // Maximum number of alpha input fields
170 801 : int TotalArgs(0); // Total number of alpha and numeric arguments (max) for a
171 :
172 801 : NumOutAirInletNodeLists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "OutdoorAir:NodeList");
173 801 : NumOutsideAirNodeSingles = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "OutdoorAir:Node");
174 801 : state.dataOutAirNodeMgr->NumOutsideAirNodes = 0;
175 801 : ErrorsFound = false;
176 801 : NextFluidStreamNum = 1;
177 :
178 801 : ListSize = 0;
179 801 : CurSize = 100;
180 801 : TmpNums.dimension(CurSize, 0);
181 :
182 801 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "NodeList", NumParams, NumAlphas, NumNums);
183 801 : NodeNums.dimension(NumParams, 0);
184 :
185 801 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "OutdoorAir:NodeList", TotalArgs, NumAlphas, NumNums);
186 801 : MaxNums = max(MaxNums, NumNums);
187 801 : MaxAlphas = max(MaxAlphas, NumAlphas);
188 801 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "OutdoorAir:Node", TotalArgs, NumAlphas, NumNums);
189 801 : MaxNums = max(MaxNums, NumNums);
190 801 : MaxAlphas = max(MaxAlphas, NumAlphas);
191 :
192 801 : Alphas.allocate(MaxAlphas);
193 801 : cAlphaFields.allocate(MaxAlphas);
194 801 : cNumericFields.allocate(MaxNums);
195 801 : Numbers.dimension(MaxNums, 0.0);
196 801 : lAlphaBlanks.dimension(MaxAlphas, true);
197 801 : lNumericBlanks.dimension(MaxNums, true);
198 :
199 801 : if (NumOutAirInletNodeLists > 0) {
200 : // Loop over all outside air inlet nodes in the input and count them
201 448 : CurrentModuleObject = "OutdoorAir:NodeList";
202 1496 : for (OutAirInletNodeListNum = 1; OutAirInletNodeListNum <= NumOutAirInletNodeLists; ++OutAirInletNodeListNum) {
203 1048 : 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 2098 : for (AlphaNum = 1; AlphaNum <= NumAlphas; ++AlphaNum) {
217 1050 : 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 2100 : GetNodeNums(state,
222 1050 : 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 1050 : cAlphaFields(AlphaNum));
234 1050 : NextFluidStreamNum += NumNodes;
235 1050 : if (ErrInList) {
236 0 : ShowContinueError(state, format("Occurred in {}, {} = {}", CurrentModuleObject, cAlphaFields(AlphaNum), Alphas(AlphaNum)));
237 0 : ErrorsFound = true;
238 : }
239 2249 : for (NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
240 : // Duplicates here are not a problem, just ignore
241 1199 : if (!any_eq(TmpNums, NodeNums(NodeNum))) {
242 1198 : ++ListSize;
243 1198 : if (ListSize > CurSize) {
244 0 : TmpNums.redimension(CurSize += 100, 0);
245 : }
246 1198 : TmpNums(ListSize) = NodeNums(NodeNum);
247 : }
248 : }
249 : }
250 : }
251 :
252 448 : if (ErrorsFound) {
253 0 : ShowFatalError(state, format("{}Errors found in getting {} input.", RoutineName, CurrentModuleObject));
254 : }
255 : }
256 :
257 801 : if (NumOutsideAirNodeSingles > 0) {
258 : // Loop over all single outside air nodes in the input
259 304 : CurrentModuleObject = "OutdoorAir:Node";
260 1661 : for (OutsideAirNodeSingleNum = 1; OutsideAirNodeSingleNum <= NumOutsideAirNodeSingles; ++OutsideAirNodeSingleNum) {
261 1357 : 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 1357 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
275 :
276 1357 : 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 2714 : GetNodeNums(state,
281 1357 : 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 1357 : cAlphaFields(1));
293 1357 : NextFluidStreamNum += NumNodes;
294 1357 : if (ErrInList) {
295 0 : ShowContinueError(state, format("Occurred in {}, {} = {}", CurrentModuleObject, cAlphaFields(1), Alphas(1)));
296 0 : ErrorsFound = true;
297 : }
298 :
299 1357 : 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 1357 : if (!any_eq(TmpNums, NodeNums(1))) {
307 1357 : ++ListSize;
308 1357 : if (ListSize > CurSize) {
309 2 : TmpNums.redimension(CurSize += 100, 0);
310 : }
311 1357 : 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 1357 : if (NumNums > 0) {
321 429 : state.dataLoopNodes->Node(NodeNums(1)).Height = Numbers(1);
322 : }
323 :
324 1357 : if (NumAlphas > 1) {
325 2 : state.dataGlobal->AnyLocalEnvironmentsInModel = true;
326 : }
327 :
328 1357 : if (NumAlphas <= 1 || lAlphaBlanks(2)) {
329 2 : } 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 1357 : if (NumAlphas <= 2 || lAlphaBlanks(3)) {
335 1 : } 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 1357 : if (NumAlphas <= 3 || lAlphaBlanks(4)) {
341 1 : } 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 1357 : if (NumAlphas <= 4 || lAlphaBlanks(5)) {
347 1 : } 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 1357 : 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 2712 : if (state.dataLoopNodes->Node(NodeNums(1)).outAirDryBulbSched != nullptr ||
359 1355 : state.dataLoopNodes->Node(NodeNums(1)).outAirWetBulbSched != nullptr) {
360 2 : state.dataLoopNodes->Node(NodeNums(1)).IsLocalNode = true;
361 : }
362 : }
363 304 : if (ErrorsFound) {
364 0 : ShowFatalError(state, format("{}Errors found in getting {} input.", RoutineName, CurrentModuleObject));
365 : }
366 : }
367 :
368 801 : if (ListSize > 0) {
369 515 : state.dataOutAirNodeMgr->NumOutsideAirNodes = ListSize;
370 515 : state.dataOutAirNodeMgr->OutsideAirNodeList = TmpNums({1, static_cast<int>(ListSize)});
371 : }
372 801 : }
373 :
374 2835728 : 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 12298672 : for (OutsideAirNodeNum = 1; OutsideAirNodeNum <= state.dataOutAirNodeMgr->NumOutsideAirNodes; ++OutsideAirNodeNum) {
393 9462944 : NodeNum = state.dataOutAirNodeMgr->OutsideAirNodeList(OutsideAirNodeNum);
394 9462944 : SetOANodeValues(state, NodeNum, true);
395 : }
396 2835728 : }
397 :
398 2903 : 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 2903 : if (state.dataOutAirNodeMgr->GetOutAirNodesInputFlag) { // First time subroutine has been entered
438 45 : GetOutAirNodesInput(state); // Get Out Air Nodes data
439 45 : state.dataOutAirNodeMgr->GetOutAirNodesInputFlag = false;
440 45 : SetOutAirNodes(state);
441 : }
442 :
443 2903 : if (any_eq(state.dataOutAirNodeMgr->OutsideAirNodeList, NodeNumber)) {
444 1635 : Okay = true;
445 : } else {
446 1268 : Okay = false;
447 : }
448 :
449 2903 : return Okay;
450 : }
451 :
452 121 : 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 121 : Array1D_int TmpNums;
492 : int DummyNumber;
493 :
494 121 : if (state.dataOutAirNodeMgr->GetOutAirNodesInputFlag) { // First time subroutine has been entered
495 0 : GetOutAirNodesInput(state); // Get Out Air Nodes data
496 0 : state.dataOutAirNodeMgr->GetOutAirNodesInputFlag = false;
497 0 : SetOutAirNodes(state);
498 : }
499 :
500 121 : Okay = false;
501 :
502 121 : if (state.dataOutAirNodeMgr->NumOutsideAirNodes > 0) {
503 120 : if (any_eq(state.dataOutAirNodeMgr->OutsideAirNodeList, NodeNumber)) {
504 117 : Okay = true;
505 : } else {
506 3 : Okay = false;
507 : }
508 : } else {
509 1 : Okay = false;
510 : }
511 :
512 121 : if (NodeNumber > 0) {
513 121 : if (!Okay) { // Add new outside air node to list
514 4 : state.dataOutAirNodeMgr->OutsideAirNodeList.redimension(++state.dataOutAirNodeMgr->NumOutsideAirNodes);
515 4 : state.dataOutAirNodeMgr->OutsideAirNodeList(state.dataOutAirNodeMgr->NumOutsideAirNodes) = NodeNumber;
516 4 : TmpNums = state.dataOutAirNodeMgr->OutsideAirNodeList;
517 4 : bool errFlag(false);
518 : // register new node..
519 12 : GetNodeNums(state,
520 4 : 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 4 : static_cast<NodeInputManager::CompFluidStream>(state.dataOutAirNodeMgr->NumOutsideAirNodes),
529 : ObjectIsNotParent,
530 : IncrementFluidStreamYes);
531 4 : SetOANodeValues(state, NodeNumber, false);
532 : }
533 : }
534 121 : }
535 :
536 9462948 : 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 9462948 : if (state.dataLoopNodes->Node(NodeNum).Height < 0.0) {
555 : // Note -- this setting is different than the DataEnvironment "AT" settings.
556 9206643 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb = state.dataEnvrn->OutDryBulbTemp;
557 9206643 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = state.dataEnvrn->OutWetBulbTemp;
558 9206643 : if (InitCall) {
559 9206639 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = state.dataEnvrn->WindSpeed;
560 : }
561 : } else {
562 256305 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb = OutDryBulbTempAt(state, state.dataLoopNodes->Node(NodeNum).Height);
563 256305 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = OutWetBulbTempAt(state, state.dataLoopNodes->Node(NodeNum).Height);
564 256305 : if (InitCall) {
565 256305 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = DataEnvironment::WindSpeedAt(state, state.dataLoopNodes->Node(NodeNum).Height);
566 : }
567 : }
568 9462948 : if (!InitCall) {
569 4 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = state.dataEnvrn->WindSpeed;
570 : }
571 9462948 : state.dataLoopNodes->Node(NodeNum).OutAirWindDir = state.dataEnvrn->WindDir;
572 :
573 9462948 : if (InitCall) {
574 : // Set node data to local air node values if defined
575 9462944 : if (state.dataLoopNodes->Node(NodeNum).outAirDryBulbSched != nullptr) {
576 6756 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb = state.dataLoopNodes->Node(NodeNum).outAirDryBulbSched->getCurrentVal();
577 : }
578 9462944 : if (state.dataLoopNodes->Node(NodeNum).outAirWetBulbSched != nullptr) {
579 2706 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = state.dataLoopNodes->Node(NodeNum).outAirWetBulbSched->getCurrentVal();
580 : }
581 9462944 : if (state.dataLoopNodes->Node(NodeNum).outAirWindSpeedSched != nullptr) {
582 2706 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = state.dataLoopNodes->Node(NodeNum).outAirWindSpeedSched->getCurrentVal();
583 : }
584 9462944 : if (state.dataLoopNodes->Node(NodeNum).outAirWindDirSched != nullptr) {
585 2706 : state.dataLoopNodes->Node(NodeNum).OutAirWindDir = state.dataLoopNodes->Node(NodeNum).outAirWindDirSched->getCurrentVal();
586 : }
587 :
588 : // Set node data to EMS overwritten values if defined
589 9462944 : if (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirDryBulb) {
590 16128 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb = state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirDryBulb;
591 : }
592 9462944 : if (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWetBulb) {
593 16128 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWetBulb;
594 : }
595 9462944 : if (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWindSpeed) {
596 0 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWindSpeed;
597 : }
598 9462944 : if (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWindDir) {
599 0 : state.dataLoopNodes->Node(NodeNum).OutAirWindDir = state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWindDir;
600 : }
601 : }
602 :
603 9462948 : state.dataLoopNodes->Node(NodeNum).Temp = state.dataLoopNodes->Node(NodeNum).OutAirDryBulb;
604 9462948 : if (state.dataLoopNodes->Node(NodeNum).IsLocalNode) {
605 22884 : if (InitCall) {
606 22884 : 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 22884 : if (state.dataLoopNodes->Node(NodeNum).outAirWetBulbSched == nullptr &&
610 26934 : !state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWetBulb &&
611 4050 : (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirDryBulb ||
612 4050 : state.dataLoopNodes->Node(NodeNum).outAirDryBulbSched != nullptr)) {
613 4050 : state.dataLoopNodes->Node(NodeNum).HumRat = state.dataEnvrn->OutHumRat;
614 8100 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = PsyTwbFnTdbWPb(
615 4050 : state, state.dataLoopNodes->Node(NodeNum).OutAirDryBulb, state.dataEnvrn->OutHumRat, state.dataEnvrn->OutBaroPress);
616 : } else {
617 37668 : state.dataLoopNodes->Node(NodeNum).HumRat = PsyWFnTdbTwbPb(state,
618 18834 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb,
619 18834 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb,
620 18834 : 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 9440064 : state.dataLoopNodes->Node(NodeNum).HumRat = state.dataEnvrn->OutHumRat;
630 : }
631 9462948 : state.dataLoopNodes->Node(NodeNum).Enthalpy =
632 9462948 : PsyHFnTdbW(state.dataLoopNodes->Node(NodeNum).OutAirDryBulb, state.dataLoopNodes->Node(NodeNum).HumRat);
633 9462948 : state.dataLoopNodes->Node(NodeNum).Press = state.dataEnvrn->OutBaroPress;
634 9462948 : state.dataLoopNodes->Node(NodeNum).Quality = 0.0;
635 : // Add contaminants
636 9462948 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
637 20603 : state.dataLoopNodes->Node(NodeNum).CO2 = state.dataContaminantBalance->OutdoorCO2;
638 : }
639 9462948 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
640 7091 : state.dataLoopNodes->Node(NodeNum).GenContam = state.dataContaminantBalance->OutdoorGC;
641 : }
642 9462948 : }
643 :
644 : } // namespace OutAirNodeManager
645 :
646 : } // namespace EnergyPlus
|