Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // 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 2811996 : 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 2811996 : if (state.dataOutAirNodeMgr->GetOutAirNodesInputFlag) { // First time subroutine has been entered
111 753 : GetOutAirNodesInput(state); // Get OutAir Nodes data
112 753 : state.dataOutAirNodeMgr->GetOutAirNodesInputFlag = false;
113 : }
114 2811996 : InitOutAirNodes(state);
115 2811996 : }
116 :
117 796 : 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 : using ScheduleManager::GetScheduleIndex;
135 :
136 : // Locals
137 : // SUBROUTINE PARAMETER DEFINITIONS:
138 : static constexpr std::string_view RoutineName("GetOutAirNodesInput: "); // include trailing blank space
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 796 : 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 796 : Array1D_int TmpNums;
161 796 : std::string CurrentModuleObject; // Object type for getting and error messages
162 796 : Array1D_string Alphas; // Alpha input items for object
163 796 : Array1D_string cAlphaFields; // Alpha field names
164 796 : Array1D_string cNumericFields; // Numeric field names
165 796 : Array1D<Real64> Numbers; // Numeric input items for object
166 796 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
167 796 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
168 796 : int MaxNums(0); // Maximum number of numeric input fields
169 796 : int MaxAlphas(0); // Maximum number of alpha input fields
170 796 : int TotalArgs(0); // Total number of alpha and numeric arguments (max) for a
171 :
172 796 : NumOutAirInletNodeLists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "OutdoorAir:NodeList");
173 796 : NumOutsideAirNodeSingles = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "OutdoorAir:Node");
174 796 : state.dataOutAirNodeMgr->NumOutsideAirNodes = 0;
175 796 : ErrorsFound = false;
176 796 : NextFluidStreamNum = 1;
177 :
178 796 : ListSize = 0;
179 796 : CurSize = 100;
180 796 : TmpNums.dimension(CurSize, 0);
181 :
182 796 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "NodeList", NumParams, NumAlphas, NumNums);
183 796 : NodeNums.dimension(NumParams, 0);
184 :
185 796 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "OutdoorAir:NodeList", TotalArgs, NumAlphas, NumNums);
186 796 : MaxNums = max(MaxNums, NumNums);
187 796 : MaxAlphas = max(MaxAlphas, NumAlphas);
188 796 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "OutdoorAir:Node", TotalArgs, NumAlphas, NumNums);
189 796 : MaxNums = max(MaxNums, NumNums);
190 796 : MaxAlphas = max(MaxAlphas, NumAlphas);
191 :
192 796 : Alphas.allocate(MaxAlphas);
193 796 : cAlphaFields.allocate(MaxAlphas);
194 796 : cNumericFields.allocate(MaxNums);
195 796 : Numbers.dimension(MaxNums, 0.0);
196 796 : lAlphaBlanks.dimension(MaxAlphas, true);
197 796 : lNumericBlanks.dimension(MaxNums, true);
198 :
199 796 : if (NumOutAirInletNodeLists > 0) {
200 : // Loop over all outside air inlet nodes in the input and count them
201 445 : CurrentModuleObject = "OutdoorAir:NodeList";
202 1481 : for (OutAirInletNodeListNum = 1; OutAirInletNodeListNum <= NumOutAirInletNodeLists; ++OutAirInletNodeListNum) {
203 1036 : 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 2074 : for (AlphaNum = 1; AlphaNum <= NumAlphas; ++AlphaNum) {
217 1038 : 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 2076 : GetNodeNums(state,
222 1038 : 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 1038 : cAlphaFields(AlphaNum));
234 1038 : NextFluidStreamNum += NumNodes;
235 1038 : if (ErrInList) {
236 0 : ShowContinueError(state, format("Occurred in {}, {} = {}", CurrentModuleObject, cAlphaFields(AlphaNum), Alphas(AlphaNum)));
237 0 : ErrorsFound = true;
238 : }
239 2225 : for (NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
240 : // Duplicates here are not a problem, just ignore
241 1187 : if (!any_eq(TmpNums, NodeNums(NodeNum))) {
242 1186 : ++ListSize;
243 1186 : if (ListSize > CurSize) {
244 0 : TmpNums.redimension(CurSize += 100, 0);
245 : }
246 1186 : TmpNums(ListSize) = NodeNums(NodeNum);
247 : }
248 : }
249 : }
250 : }
251 :
252 445 : if (ErrorsFound) {
253 0 : ShowFatalError(state, format("{}Errors found in getting {} input.", RoutineName, CurrentModuleObject));
254 : }
255 : }
256 :
257 796 : if (NumOutsideAirNodeSingles > 0) {
258 : // Loop over all single outside air nodes in the input
259 299 : CurrentModuleObject = "OutdoorAir:Node";
260 1506 : for (OutsideAirNodeSingleNum = 1; OutsideAirNodeSingleNum <= NumOutsideAirNodeSingles; ++OutsideAirNodeSingleNum) {
261 1207 : 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 1207 : ErrInList = false;
275 : // To support HVAC diagram, every outside inlet node must have a unique fluid stream number
276 : // GetNodeNums will increment the value across a node list, the starting value must be incremented
277 : // here across lists and across objects
278 2414 : GetNodeNums(state,
279 1207 : Alphas(1),
280 : NumNodes,
281 : NodeNums,
282 : ErrInList,
283 : DataLoopNode::NodeFluidType::Air,
284 : DataLoopNode::ConnectionObjectType::OutdoorAirNode,
285 : CurrentModuleObject,
286 : DataLoopNode::ConnectionType::OutsideAir,
287 : static_cast<NodeInputManager::CompFluidStream>(NextFluidStreamNum),
288 : ObjectIsNotParent,
289 : IncrementFluidStreamYes,
290 1207 : cAlphaFields(1));
291 1207 : NextFluidStreamNum += NumNodes;
292 1207 : if (ErrInList) {
293 0 : ShowContinueError(state, format("Occurred in {}, {} = {}", CurrentModuleObject, cAlphaFields(1), Alphas(1)));
294 0 : ErrorsFound = true;
295 : }
296 :
297 1207 : if (NumNodes > 1) {
298 0 : ShowSevereError(state, format("{}, {} = {}", CurrentModuleObject, cAlphaFields(1), Alphas(1)));
299 0 : ShowContinueError(state, "...appears to point to a node list, not a single node.");
300 0 : ErrorsFound = true;
301 0 : continue;
302 : }
303 :
304 1207 : if (!any_eq(TmpNums, NodeNums(1))) {
305 1207 : ++ListSize;
306 1207 : if (ListSize > CurSize) {
307 1 : TmpNums.redimension(CurSize += 100, 0);
308 : }
309 1207 : TmpNums(ListSize) = NodeNums(1);
310 : } else { // Duplicates are a problem
311 0 : ShowSevereError(state, format("{}, duplicate {} = {}", CurrentModuleObject, cAlphaFields(1), Alphas(1)));
312 0 : ShowContinueError(state, format("Duplicate {} might be found in an OutdoorAir:NodeList.", cAlphaFields(1)));
313 0 : ErrorsFound = true;
314 0 : continue;
315 : }
316 :
317 : // Set additional node properties
318 1207 : if (NumNums > 0) state.dataLoopNodes->Node(NodeNums(1)).Height = Numbers(1);
319 :
320 1207 : if (NumAlphas > 1) {
321 2 : state.dataGlobal->AnyLocalEnvironmentsInModel = true;
322 : }
323 :
324 1207 : if (NumAlphas > 1 && !lAlphaBlanks(2)) {
325 2 : state.dataLoopNodes->Node(NodeNums(1)).OutAirDryBulbSchedNum = GetScheduleIndex(state, Alphas(2));
326 2 : if (state.dataLoopNodes->Node(NodeNums(1)).OutAirDryBulbSchedNum == 0) {
327 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid schedule.", RoutineName, CurrentModuleObject, cAlphaFields(2)));
328 0 : ShowContinueError(state, format("Dry Bulb Temperature Schedule not found=\"{}\".", Alphas(2)));
329 0 : ErrorsFound = true;
330 : }
331 : }
332 :
333 1207 : if (NumAlphas > 2 && !lAlphaBlanks(3)) {
334 1 : state.dataLoopNodes->Node(NodeNums(1)).OutAirWetBulbSchedNum = GetScheduleIndex(state, Alphas(3));
335 1 : if (state.dataLoopNodes->Node(NodeNums(1)).OutAirWetBulbSchedNum == 0) {
336 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid schedule.", RoutineName, CurrentModuleObject, cAlphaFields(3)));
337 0 : ShowContinueError(state, format("Wet Bulb Temperature Schedule not found=\"{}\".", Alphas(3)));
338 0 : ErrorsFound = true;
339 : }
340 : }
341 :
342 1207 : if (NumAlphas > 3 && !lAlphaBlanks(4)) {
343 1 : state.dataLoopNodes->Node(NodeNums(1)).OutAirWindSpeedSchedNum = GetScheduleIndex(state, Alphas(4));
344 1 : if (state.dataLoopNodes->Node(NodeNums(1)).OutAirWindSpeedSchedNum == 0) {
345 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid schedule.", RoutineName, CurrentModuleObject, cAlphaFields(4)));
346 0 : ShowContinueError(state, format("Wind Speed Schedule not found=\"{}\".", Alphas(4)));
347 0 : ErrorsFound = true;
348 : }
349 : }
350 :
351 1207 : if (NumAlphas > 4 && !lAlphaBlanks(5)) {
352 1 : state.dataLoopNodes->Node(NodeNums(1)).OutAirWindDirSchedNum = GetScheduleIndex(state, Alphas(5));
353 1 : if (state.dataLoopNodes->Node(NodeNums(1)).OutAirWindDirSchedNum == 0) {
354 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid schedule.", RoutineName, CurrentModuleObject, cAlphaFields(5)));
355 0 : ShowContinueError(state, format("Wind Direction Schedule not found=\"{}\".", Alphas(5)));
356 0 : ErrorsFound = true;
357 : }
358 : }
359 :
360 1207 : if (NumAlphas > 8) {
361 0 : ShowSevereError(state, format("{}, {} = {}", CurrentModuleObject, cAlphaFields(1), Alphas(1)));
362 0 : ShowContinueError(state, "Object Definition indicates more than 7 Alpha Objects.");
363 0 : ErrorsFound = true;
364 0 : continue;
365 : }
366 2412 : if (state.dataLoopNodes->Node(NodeNums(1)).OutAirDryBulbSchedNum > 0 ||
367 1205 : state.dataLoopNodes->Node(NodeNums(1)).OutAirWetBulbSchedNum > 0) {
368 2 : state.dataLoopNodes->Node(NodeNums(1)).IsLocalNode = true;
369 : }
370 : }
371 299 : if (ErrorsFound) {
372 0 : ShowFatalError(state, format("{}Errors found in getting {} input.", RoutineName, CurrentModuleObject));
373 : }
374 : }
375 :
376 796 : if (ListSize > 0) {
377 510 : state.dataOutAirNodeMgr->NumOutsideAirNodes = ListSize;
378 510 : state.dataOutAirNodeMgr->OutsideAirNodeList = TmpNums({1, static_cast<int>(ListSize)});
379 : }
380 796 : }
381 :
382 2811996 : void InitOutAirNodes(EnergyPlusData &state)
383 : {
384 : // SUBROUTINE INFORMATION:
385 : // AUTHOR Fred Buhl
386 : // DATE WRITTEN Sept 1998
387 : // MODIFIED B. Griffith, added EMS override
388 : // RE-ENGINEERED na
389 :
390 : // PURPOSE OF THIS SUBROUTINE:
391 : // Initialize the outside air node data data. In Particular,
392 : // set the outside air nodes to the outside conditions at the
393 : // start of every heat balance time step.
394 :
395 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
396 : int OutsideAirNodeNum;
397 : int NodeNum;
398 :
399 : // Do the begin time step initialization
400 11590790 : for (OutsideAirNodeNum = 1; OutsideAirNodeNum <= state.dataOutAirNodeMgr->NumOutsideAirNodes; ++OutsideAirNodeNum) {
401 8778794 : NodeNum = state.dataOutAirNodeMgr->OutsideAirNodeList(OutsideAirNodeNum);
402 8778794 : SetOANodeValues(state, NodeNum, true);
403 : }
404 2811996 : }
405 :
406 2867 : bool CheckOutAirNodeNumber(EnergyPlusData &state, int const NodeNumber) // Number of node to check to see if in Outside Air list
407 : {
408 :
409 : // FUNCTION INFORMATION:
410 : // AUTHOR Linda Lawrie
411 : // DATE WRITTEN Feb 2007
412 : // MODIFIED na
413 : // RE-ENGINEERED na
414 :
415 : // PURPOSE OF THIS FUNCTION:
416 : // Provide an entry into the OutAirNode List for checking from other routines.
417 :
418 : // METHODOLOGY EMPLOYED:
419 : // na
420 :
421 : // REFERENCES:
422 : // na
423 :
424 : // USE STATEMENTS:
425 : // na
426 :
427 : // Return value
428 : bool Okay; // True if found, false if not
429 :
430 : // Locals
431 : // FUNCTION ARGUMENT DEFINITIONS:
432 :
433 : // FUNCTION PARAMETER DEFINITIONS:
434 : // na
435 :
436 : // INTERFACE BLOCK SPECIFICATIONS:
437 : // na
438 :
439 : // DERIVED TYPE DEFINITIONS:
440 : // na
441 :
442 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
443 : // na
444 :
445 2867 : if (state.dataOutAirNodeMgr->GetOutAirNodesInputFlag) { // First time subroutine has been entered
446 43 : GetOutAirNodesInput(state); // Get Out Air Nodes data
447 43 : state.dataOutAirNodeMgr->GetOutAirNodesInputFlag = false;
448 43 : SetOutAirNodes(state);
449 : }
450 :
451 2867 : if (any_eq(state.dataOutAirNodeMgr->OutsideAirNodeList, NodeNumber)) {
452 1613 : Okay = true;
453 : } else {
454 1254 : Okay = false;
455 : }
456 :
457 2867 : return Okay;
458 : }
459 :
460 121 : void CheckAndAddAirNodeNumber(EnergyPlusData &state,
461 : int const NodeNumber, // Number of node to check to see if in Outside Air list
462 : bool &Okay // True if found, false if not
463 : )
464 : {
465 :
466 : // SUBROUTINE INFORMATION:
467 : // AUTHOR Linda Lawrie
468 : // DATE WRITTEN March 2007
469 : // MODIFIED na
470 : // RE-ENGINEERED na
471 :
472 : // PURPOSE OF THIS SUBROUTINE:
473 : // At the time of writing, some items (namely Chillers) have "made up" node
474 : // names for nodes that are "outside air nodes". Rather than fatal out, add
475 : // this subroutine which will check and then add a outside air node, if necessary.
476 :
477 : // METHODOLOGY EMPLOYED:
478 : // na
479 :
480 : // REFERENCES:
481 : // na
482 :
483 : // Using/Aliasing
484 : using namespace NodeInputManager;
485 :
486 : // Locals
487 : // SUBROUTINE ARGUMENT DEFINITIONS:
488 :
489 : // SUBROUTINE PARAMETER DEFINITIONS:
490 : // na
491 :
492 : // INTERFACE BLOCK SPECIFICATIONS:
493 : // na
494 :
495 : // DERIVED TYPE DEFINITIONS:
496 : // na
497 :
498 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
499 121 : Array1D_int TmpNums;
500 : int DummyNumber;
501 :
502 121 : if (state.dataOutAirNodeMgr->GetOutAirNodesInputFlag) { // First time subroutine has been entered
503 0 : GetOutAirNodesInput(state); // Get Out Air Nodes data
504 0 : state.dataOutAirNodeMgr->GetOutAirNodesInputFlag = false;
505 0 : SetOutAirNodes(state);
506 : }
507 :
508 121 : Okay = false;
509 :
510 121 : if (state.dataOutAirNodeMgr->NumOutsideAirNodes > 0) {
511 120 : if (any_eq(state.dataOutAirNodeMgr->OutsideAirNodeList, NodeNumber)) {
512 117 : Okay = true;
513 : } else {
514 3 : Okay = false;
515 : }
516 : } else {
517 1 : Okay = false;
518 : }
519 :
520 121 : if (NodeNumber > 0) {
521 121 : if (!Okay) { // Add new outside air node to list
522 4 : state.dataOutAirNodeMgr->OutsideAirNodeList.redimension(++state.dataOutAirNodeMgr->NumOutsideAirNodes);
523 4 : state.dataOutAirNodeMgr->OutsideAirNodeList(state.dataOutAirNodeMgr->NumOutsideAirNodes) = NodeNumber;
524 4 : TmpNums = state.dataOutAirNodeMgr->OutsideAirNodeList;
525 4 : bool errFlag(false);
526 : // register new node..
527 12 : GetNodeNums(state,
528 4 : state.dataLoopNodes->NodeID(NodeNumber),
529 : DummyNumber,
530 : TmpNums,
531 : errFlag,
532 : DataLoopNode::NodeFluidType::Air,
533 : DataLoopNode::ConnectionObjectType::OutdoorAirNode,
534 : "OutdoorAir:Node",
535 : DataLoopNode::ConnectionType::OutsideAir,
536 4 : static_cast<NodeInputManager::CompFluidStream>(state.dataOutAirNodeMgr->NumOutsideAirNodes),
537 : ObjectIsNotParent,
538 : IncrementFluidStreamYes);
539 4 : SetOANodeValues(state, NodeNumber, false);
540 : }
541 : }
542 121 : }
543 :
544 8778798 : void SetOANodeValues(EnergyPlusData &state,
545 : int const NodeNum, // Number of node to check to see if in Outside Air list
546 : bool InitCall // True if Init calls, false if CheckAndAddAirNodeNumber calls
547 : )
548 : {
549 : // SUBROUTINE INFORMATION:
550 : // AUTHOR L. Gu
551 : // DATE WRITTEN July 2018
552 :
553 : // PURPOSE OF THIS SUBROUTINE:
554 : // Consolidate a block from both CheckAndAddAirNodeNumber and InitOutAirNodes to set
555 : // up outdoor node values
556 :
557 : using Psychrometrics::PsyHFnTdbW;
558 : using Psychrometrics::PsyTwbFnTdbWPb;
559 : using Psychrometrics::PsyWFnTdbTwbPb;
560 : using ScheduleManager::GetCurrentScheduleValue;
561 :
562 : // Set node data to global values
563 8778798 : if (state.dataLoopNodes->Node(NodeNum).Height < 0.0) {
564 : // Note -- this setting is different than the DataEnvironment "AT" settings.
565 8522493 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb = state.dataEnvrn->OutDryBulbTemp;
566 8522493 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = state.dataEnvrn->OutWetBulbTemp;
567 8522493 : if (InitCall) state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = state.dataEnvrn->WindSpeed;
568 : } else {
569 256305 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb = OutDryBulbTempAt(state, state.dataLoopNodes->Node(NodeNum).Height);
570 256305 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = OutWetBulbTempAt(state, state.dataLoopNodes->Node(NodeNum).Height);
571 256305 : if (InitCall)
572 256305 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = DataEnvironment::WindSpeedAt(state, state.dataLoopNodes->Node(NodeNum).Height);
573 : }
574 8778798 : if (!InitCall) state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = state.dataEnvrn->WindSpeed;
575 8778798 : state.dataLoopNodes->Node(NodeNum).OutAirWindDir = state.dataEnvrn->WindDir;
576 :
577 8778798 : if (InitCall) {
578 : // Set node data to local air node values if defined
579 8778794 : if (state.dataLoopNodes->Node(NodeNum).OutAirDryBulbSchedNum != 0) {
580 6756 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb =
581 6756 : GetCurrentScheduleValue(state, state.dataLoopNodes->Node(NodeNum).OutAirDryBulbSchedNum);
582 : }
583 8778794 : if (state.dataLoopNodes->Node(NodeNum).OutAirWetBulbSchedNum != 0) {
584 2706 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb =
585 2706 : GetCurrentScheduleValue(state, state.dataLoopNodes->Node(NodeNum).OutAirWetBulbSchedNum);
586 : }
587 8778794 : if (state.dataLoopNodes->Node(NodeNum).OutAirWindSpeedSchedNum != 0) {
588 2706 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed =
589 2706 : GetCurrentScheduleValue(state, state.dataLoopNodes->Node(NodeNum).OutAirWindSpeedSchedNum);
590 : }
591 8778794 : if (state.dataLoopNodes->Node(NodeNum).OutAirWindDirSchedNum != 0) {
592 2706 : state.dataLoopNodes->Node(NodeNum).OutAirWindDir =
593 2706 : GetCurrentScheduleValue(state, state.dataLoopNodes->Node(NodeNum).OutAirWindDirSchedNum);
594 : }
595 :
596 : // Set node data to EMS overwritten values if defined
597 8778794 : if (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirDryBulb)
598 16128 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb = state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirDryBulb;
599 8778794 : if (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWetBulb)
600 16128 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWetBulb;
601 8778794 : if (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWindSpeed)
602 0 : state.dataLoopNodes->Node(NodeNum).OutAirWindSpeed = state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWindSpeed;
603 8778794 : if (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWindDir)
604 0 : state.dataLoopNodes->Node(NodeNum).OutAirWindDir = state.dataLoopNodes->Node(NodeNum).EMSValueForOutAirWindDir;
605 : }
606 :
607 8778798 : state.dataLoopNodes->Node(NodeNum).Temp = state.dataLoopNodes->Node(NodeNum).OutAirDryBulb;
608 8778798 : if (state.dataLoopNodes->Node(NodeNum).IsLocalNode) {
609 22884 : if (InitCall) {
610 22884 : if (state.dataLoopNodes->Node(NodeNum).OutAirWetBulb > state.dataLoopNodes->Node(NodeNum).OutAirDryBulb) {
611 0 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = state.dataLoopNodes->Node(NodeNum).OutAirDryBulb;
612 : }
613 26934 : if (state.dataLoopNodes->Node(NodeNum).OutAirWetBulbSchedNum == 0 && !state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirWetBulb &&
614 4050 : (state.dataLoopNodes->Node(NodeNum).EMSOverrideOutAirDryBulb || state.dataLoopNodes->Node(NodeNum).OutAirDryBulbSchedNum != 0)) {
615 4050 : state.dataLoopNodes->Node(NodeNum).HumRat = state.dataEnvrn->OutHumRat;
616 8100 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb = PsyTwbFnTdbWPb(
617 4050 : state, state.dataLoopNodes->Node(NodeNum).OutAirDryBulb, state.dataEnvrn->OutHumRat, state.dataEnvrn->OutBaroPress);
618 : } else {
619 37668 : state.dataLoopNodes->Node(NodeNum).HumRat = PsyWFnTdbTwbPb(state,
620 18834 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb,
621 18834 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb,
622 18834 : state.dataEnvrn->OutBaroPress);
623 : }
624 : } else {
625 0 : state.dataLoopNodes->Node(NodeNum).HumRat = PsyWFnTdbTwbPb(state,
626 0 : state.dataLoopNodes->Node(NodeNum).OutAirDryBulb,
627 0 : state.dataLoopNodes->Node(NodeNum).OutAirWetBulb,
628 0 : state.dataEnvrn->OutBaroPress);
629 : }
630 : } else {
631 8755914 : state.dataLoopNodes->Node(NodeNum).HumRat = state.dataEnvrn->OutHumRat;
632 : }
633 8778798 : state.dataLoopNodes->Node(NodeNum).Enthalpy =
634 8778798 : PsyHFnTdbW(state.dataLoopNodes->Node(NodeNum).OutAirDryBulb, state.dataLoopNodes->Node(NodeNum).HumRat);
635 8778798 : state.dataLoopNodes->Node(NodeNum).Press = state.dataEnvrn->OutBaroPress;
636 8778798 : state.dataLoopNodes->Node(NodeNum).Quality = 0.0;
637 : // Add contaminants
638 8778798 : if (state.dataContaminantBalance->Contaminant.CO2Simulation)
639 20603 : state.dataLoopNodes->Node(NodeNum).CO2 = state.dataContaminantBalance->OutdoorCO2;
640 8778798 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation)
641 7091 : state.dataLoopNodes->Node(NodeNum).GenContam = state.dataContaminantBalance->OutdoorGC;
642 8778798 : }
643 :
644 : } // namespace OutAirNodeManager
645 :
646 : } // namespace EnergyPlus
|