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 <string>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/string.functions.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/BranchNodeConnections.hh>
57 : #include <EnergyPlus/Data/EnergyPlusData.hh>
58 : #include <EnergyPlus/DataContaminantBalance.hh>
59 : #include <EnergyPlus/DataEnvironment.hh>
60 : #include <EnergyPlus/DataErrorTracking.hh>
61 : #include <EnergyPlus/EMSManager.hh>
62 : #include <EnergyPlus/FluidProperties.hh>
63 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
64 : #include <EnergyPlus/NodeInputManager.hh>
65 : #include <EnergyPlus/OutputProcessor.hh>
66 : #include <EnergyPlus/Psychrometrics.hh>
67 : #include <EnergyPlus/ScheduleManager.hh>
68 : #include <EnergyPlus/UtilityRoutines.hh>
69 :
70 : namespace EnergyPlus::NodeInputManager {
71 :
72 : // MODULE INFORMATION:
73 : // AUTHOR Linda K. Lawrie
74 : // DATE WRITTEN September 1999
75 :
76 : // PURPOSE OF THIS MODULE:
77 : // To provide utilities for reading and assigning indices for the
78 : // nodes in the HVAC loops.
79 :
80 : using namespace DataLoopNode;
81 : using namespace BranchNodeConnections;
82 :
83 10724 : void GetNodeNums(EnergyPlusData &state,
84 : std::string const &Name, // Name for which to obtain information
85 : int &NumNodes, // Number of nodes accompanying this Name
86 : Array1D_int &NodeNumbers, // Node Numbers accompanying this Name
87 : bool &ErrorsFound, // True when errors are found...
88 : DataLoopNode::NodeFluidType nodeFluidType, // Fluidtype for checking/setting node FluidType
89 : DataLoopNode::ConnectionObjectType const NodeObjectType, // Node Object Type (i.e. "Chiller:Electric")
90 : std::string const &NodeObjectName, // Node Object Name (i.e. "MyChiller")
91 : DataLoopNode::ConnectionType const nodeConnectionType, // Node Connection Type (see DataLoopNode)
92 : CompFluidStream const NodeFluidStream, // Which Fluid Stream (1,2,3,...)
93 : bool const ObjectIsParent, // True/False
94 : bool const IncrementFluidStream, // True/False
95 : std::string_view const InputFieldName // Input Field Name
96 : )
97 : {
98 :
99 : // SUBROUTINE INFORMATION:
100 : // AUTHOR Linda K. Lawrie
101 : // DATE WRITTEN September 1999
102 : // MODIFIED February 2004, Fluid Type checking/setting
103 :
104 : // PURPOSE OF THIS SUBROUTINE:
105 : // This subroutine calls the Node Manager to determine if the
106 : // entered name has already been assigned and if it is a list
107 : // or if it is a single node. If it has not been assigned, then
108 : // it is a single node and will need to be entered in the Node
109 : // data structure.
110 :
111 : // SUBROUTINE PARAMETER DEFINITIONS:
112 : static constexpr std::string_view RoutineName("GetNodeNums: ");
113 :
114 10724 : std::string_view const objTypeStr = BranchNodeConnections::ConnectionObjectTypeNames[static_cast<int>(NodeObjectType)];
115 :
116 10724 : if (state.dataNodeInputMgr->GetNodeInputFlag) {
117 456 : GetNodeListsInput(state, ErrorsFound);
118 456 : state.dataNodeInputMgr->GetNodeInputFlag = false;
119 : }
120 :
121 10724 : if (nodeFluidType != DataLoopNode::NodeFluidType::Air && nodeFluidType != DataLoopNode::NodeFluidType::Water &&
122 1704 : nodeFluidType != DataLoopNode::NodeFluidType::Electric && nodeFluidType != DataLoopNode::NodeFluidType::Steam &&
123 1678 : nodeFluidType != DataLoopNode::NodeFluidType::Blank) {
124 0 : ShowSevereError(state, format("{}{}=\"{}=\", invalid fluid type.", RoutineName, objTypeStr, NodeObjectName));
125 0 : ShowContinueError(state, format("..Invalid FluidType={}", nodeFluidType));
126 0 : ErrorsFound = true;
127 0 : ShowFatalError(state, "Preceding issue causes termination.");
128 : }
129 :
130 10724 : if (!Name.empty()) {
131 10108 : int ThisOne = Util::FindItemInList(Name, state.dataNodeInputMgr->NodeLists);
132 10108 : if (ThisOne != 0) {
133 362 : NumNodes = state.dataNodeInputMgr->NodeLists(ThisOne).NumOfNodesInList;
134 362 : NodeNumbers({1, NumNodes}) = state.dataNodeInputMgr->NodeLists(ThisOne).NodeNumbers({1, NumNodes});
135 847 : for (int Loop = 1; Loop <= NumNodes; ++Loop) {
136 869 : if (nodeFluidType != DataLoopNode::NodeFluidType::Blank &&
137 384 : state.dataLoopNodes->Node(NodeNumbers(Loop)).FluidType != DataLoopNode::NodeFluidType::Blank) {
138 54 : if (state.dataLoopNodes->Node(NodeNumbers(Loop)).FluidType != nodeFluidType) {
139 0 : ShowSevereError(state, format("{}{}=\"{}=\", invalid data.", RoutineName, objTypeStr, NodeObjectName));
140 0 : if (!InputFieldName.empty()) {
141 0 : ShowContinueError(state, fmt::format("...Ref field={}", InputFieldName));
142 : }
143 0 : ShowContinueError(
144 : state,
145 0 : format("Existing Fluid type for node, incorrect for request. Node={}", state.dataLoopNodes->NodeID(NodeNumbers(Loop))));
146 0 : ShowContinueError(
147 : state,
148 0 : format("Existing Fluid type={}, Requested Fluid Type={}",
149 0 : format("{}",
150 0 : DataLoopNode::NodeFluidTypeNames[static_cast<int>(state.dataLoopNodes->Node(NodeNumbers(Loop)).FluidType)]),
151 0 : format("{}", DataLoopNode::NodeFluidTypeNames[static_cast<int>(nodeFluidType)])));
152 0 : ErrorsFound = true;
153 : }
154 : }
155 485 : if (state.dataLoopNodes->Node(NodeNumbers(Loop)).FluidType == DataLoopNode::NodeFluidType::Blank) {
156 400 : state.dataLoopNodes->Node(NodeNumbers(Loop)).FluidType = nodeFluidType;
157 : }
158 485 : ++state.dataNodeInputMgr->NodeRef(NodeNumbers(Loop));
159 : }
160 : } else {
161 9746 : ThisOne = AssignNodeNumber(state, Name, nodeFluidType, ErrorsFound);
162 9746 : NumNodes = 1;
163 9746 : NodeNumbers(1) = ThisOne;
164 : }
165 : } else {
166 616 : NumNodes = 0;
167 616 : NodeNumbers(1) = 0;
168 : }
169 :
170 : // Most calls to this routine use a fixed fluid stream number for all nodes, this is the default
171 10724 : NodeInputManager::CompFluidStream FluidStreamNum = NodeFluidStream;
172 20955 : for (int Loop = 1; Loop <= NumNodes; ++Loop) {
173 : // If requested, assign NodeFluidStream to the first node and increment the fluid stream number
174 : // for each remaining node in the list
175 10231 : if (IncrementFluidStream) {
176 268 : FluidStreamNum = static_cast<NodeInputManager::CompFluidStream>(static_cast<int>(NodeFluidStream) + (Loop - 1));
177 : }
178 :
179 10231 : RegisterNodeConnection(state,
180 10231 : NodeNumbers(Loop),
181 10231 : state.dataLoopNodes->NodeID(NodeNumbers(Loop)),
182 : NodeObjectType,
183 : NodeObjectName,
184 : nodeConnectionType,
185 : FluidStreamNum,
186 : ObjectIsParent,
187 : ErrorsFound,
188 : InputFieldName);
189 : }
190 10724 : }
191 :
192 75 : void SetupNodeVarsForReporting(EnergyPlusData &state)
193 : {
194 :
195 : // SUBROUTINE INFORMATION:
196 : // AUTHOR Linda K. Lawrie
197 : // DATE WRITTEN September
198 :
199 : // PURPOSE OF THIS SUBROUTINE:
200 : // This subroutine is called when the indicated number of
201 : // Nodes have been found (TOTAL NODE NUMBER) or when HVAC warmup is
202 : // complete, whichever condition is reached first.
203 :
204 75 : if (!state.dataNodeInputMgr->NodeVarsSetup) {
205 75 : if (!state.dataErrTracking->AbortProcessing) {
206 75 : state.dataLoopNodes->MoreNodeInfo.allocate(state.dataNodeInputMgr->NumOfUniqueNodeNames);
207 866 : for (int NumNode = 1; NumNode <= state.dataNodeInputMgr->NumOfUniqueNodeNames; ++NumNode) {
208 791 : auto &Node = state.dataLoopNodes->Node(NumNode);
209 791 : auto &NodeID = state.dataLoopNodes->NodeID(NumNode);
210 :
211 : // Setup Report variables for the Nodes for HVAC Reporting, CurrentModuleObject='Node Name'
212 1582 : SetupOutputVariable(state,
213 : "System Node Temperature",
214 : Constant::Units::C,
215 791 : Node.Temp,
216 : OutputProcessor::TimeStepType::System,
217 : OutputProcessor::StoreType::Average,
218 : NodeID);
219 1582 : SetupOutputVariable(state,
220 : "System Node Mass Flow Rate",
221 : Constant::Units::kg_s,
222 791 : Node.MassFlowRate,
223 : OutputProcessor::TimeStepType::System,
224 : OutputProcessor::StoreType::Average,
225 : NodeID);
226 1582 : SetupOutputVariable(state,
227 : "System Node Humidity Ratio",
228 : Constant::Units::kgWater_kgDryAir,
229 791 : Node.HumRat,
230 : OutputProcessor::TimeStepType::System,
231 : OutputProcessor::StoreType::Average,
232 : NodeID);
233 1582 : SetupOutputVariable(state,
234 : "System Node Setpoint Temperature",
235 : Constant::Units::C,
236 791 : Node.TempSetPoint,
237 : OutputProcessor::TimeStepType::System,
238 : OutputProcessor::StoreType::Average,
239 : NodeID);
240 1582 : SetupOutputVariable(state,
241 : "System Node Setpoint High Temperature",
242 : Constant::Units::C,
243 791 : Node.TempSetPointHi,
244 : OutputProcessor::TimeStepType::System,
245 : OutputProcessor::StoreType::Average,
246 : NodeID);
247 1582 : SetupOutputVariable(state,
248 : "System Node Setpoint Low Temperature",
249 : Constant::Units::C,
250 791 : Node.TempSetPointLo,
251 : OutputProcessor::TimeStepType::System,
252 : OutputProcessor::StoreType::Average,
253 : NodeID);
254 1582 : SetupOutputVariable(state,
255 : "System Node Setpoint Humidity Ratio",
256 : Constant::Units::kgWater_kgDryAir,
257 791 : Node.HumRatSetPoint,
258 : OutputProcessor::TimeStepType::System,
259 : OutputProcessor::StoreType::Average,
260 : NodeID);
261 1582 : SetupOutputVariable(state,
262 : "System Node Setpoint Minimum Humidity Ratio",
263 : Constant::Units::kgWater_kgDryAir,
264 791 : Node.HumRatMin,
265 : OutputProcessor::TimeStepType::System,
266 : OutputProcessor::StoreType::Average,
267 : NodeID);
268 1582 : SetupOutputVariable(state,
269 : "System Node Setpoint Maximum Humidity Ratio",
270 : Constant::Units::kgWater_kgDryAir,
271 791 : Node.HumRatMax,
272 : OutputProcessor::TimeStepType::System,
273 : OutputProcessor::StoreType::Average,
274 : NodeID);
275 1582 : SetupOutputVariable(state,
276 : "System Node Relative Humidity",
277 : Constant::Units::Perc,
278 791 : state.dataLoopNodes->MoreNodeInfo(NumNode).RelHumidity,
279 : OutputProcessor::TimeStepType::System,
280 : OutputProcessor::StoreType::Average,
281 : NodeID);
282 1582 : SetupOutputVariable(state,
283 : "System Node Pressure",
284 : Constant::Units::Pa,
285 791 : Node.Press,
286 : OutputProcessor::TimeStepType::System,
287 : OutputProcessor::StoreType::Average,
288 : NodeID);
289 1582 : SetupOutputVariable(state,
290 : "System Node Standard Density Volume Flow Rate",
291 : Constant::Units::m3_s,
292 791 : state.dataLoopNodes->MoreNodeInfo(NumNode).VolFlowRateStdRho,
293 : OutputProcessor::TimeStepType::System,
294 : OutputProcessor::StoreType::Average,
295 : NodeID);
296 791 : if (Node.FluidType == DataLoopNode::NodeFluidType::Air ||
297 236 : Node.FluidType == DataLoopNode::NodeFluidType::Water) { // setup volume flow rate report for actual/current density
298 1582 : SetupOutputVariable(state,
299 : "System Node Current Density Volume Flow Rate",
300 : Constant::Units::m3_s,
301 791 : state.dataLoopNodes->MoreNodeInfo(NumNode).VolFlowRateCrntRho,
302 : OutputProcessor::TimeStepType::System,
303 : OutputProcessor::StoreType::Average,
304 : NodeID);
305 1582 : SetupOutputVariable(state,
306 : "System Node Current Density",
307 : Constant::Units::kg_m3,
308 791 : state.dataLoopNodes->MoreNodeInfo(NumNode).Density,
309 : OutputProcessor::TimeStepType::System,
310 : OutputProcessor::StoreType::Average,
311 : NodeID);
312 1582 : SetupOutputVariable(state,
313 : "System Node Specific Heat",
314 : Constant::Units::J_kgK,
315 791 : state.dataLoopNodes->MoreNodeInfo(NumNode).SpecificHeat,
316 : OutputProcessor::TimeStepType::System,
317 : OutputProcessor::StoreType::Average,
318 : NodeID);
319 : }
320 :
321 1582 : SetupOutputVariable(state,
322 : "System Node Enthalpy",
323 : Constant::Units::J_kg,
324 791 : state.dataLoopNodes->MoreNodeInfo(NumNode).ReportEnthalpy,
325 : OutputProcessor::TimeStepType::System,
326 : OutputProcessor::StoreType::Average,
327 : NodeID);
328 1582 : SetupOutputVariable(state,
329 : "System Node Wetbulb Temperature",
330 : Constant::Units::C,
331 791 : state.dataLoopNodes->MoreNodeInfo(NumNode).WetBulbTemp,
332 : OutputProcessor::TimeStepType::System,
333 : OutputProcessor::StoreType::Average,
334 : NodeID);
335 1582 : SetupOutputVariable(state,
336 : "System Node Dewpoint Temperature",
337 : Constant::Units::C,
338 791 : state.dataLoopNodes->MoreNodeInfo(NumNode).AirDewPointTemp,
339 : OutputProcessor::TimeStepType::System,
340 : OutputProcessor::StoreType::Average,
341 : NodeID);
342 1582 : SetupOutputVariable(state,
343 : "System Node Wind Speed",
344 : Constant::Units::m_s,
345 791 : Node.OutAirWindSpeed,
346 : OutputProcessor::TimeStepType::System,
347 : OutputProcessor::StoreType::Average,
348 : NodeID);
349 1582 : SetupOutputVariable(state,
350 : "System Node Wind Direction",
351 : Constant::Units::deg,
352 791 : Node.OutAirWindDir,
353 : OutputProcessor::TimeStepType::System,
354 : OutputProcessor::StoreType::Average,
355 : NodeID);
356 1582 : SetupOutputVariable(state,
357 : "System Node Quality",
358 : Constant::Units::None,
359 791 : Node.Quality,
360 : OutputProcessor::TimeStepType::System,
361 : OutputProcessor::StoreType::Average,
362 : NodeID);
363 1582 : SetupOutputVariable(state,
364 : "System Node Height",
365 : Constant::Units::m,
366 791 : Node.Height,
367 : OutputProcessor::TimeStepType::System,
368 : OutputProcessor::StoreType::Average,
369 : NodeID);
370 791 : if (state.dataGlobal->DisplayAdvancedReportVariables) {
371 0 : SetupOutputVariable(state,
372 : "System Node Minimum Temperature",
373 : Constant::Units::C,
374 0 : Node.TempMin,
375 : OutputProcessor::TimeStepType::System,
376 : OutputProcessor::StoreType::Average,
377 : NodeID);
378 0 : SetupOutputVariable(state,
379 : "System Node Maximum Temperature",
380 : Constant::Units::C,
381 0 : Node.TempMax,
382 : OutputProcessor::TimeStepType::System,
383 : OutputProcessor::StoreType::Average,
384 : NodeID);
385 0 : SetupOutputVariable(state,
386 : "System Node Minimum Limit Mass Flow Rate",
387 : Constant::Units::kg_s,
388 0 : Node.MassFlowRateMin,
389 : OutputProcessor::TimeStepType::System,
390 : OutputProcessor::StoreType::Average,
391 : NodeID);
392 0 : SetupOutputVariable(state,
393 : "System Node Maximum Limit Mass Flow Rate",
394 : Constant::Units::kg_s,
395 0 : Node.MassFlowRateMax,
396 : OutputProcessor::TimeStepType::System,
397 : OutputProcessor::StoreType::Average,
398 : NodeID);
399 0 : SetupOutputVariable(state,
400 : "System Node Minimum Available Mass Flow Rate",
401 : Constant::Units::kg_s,
402 0 : Node.MassFlowRateMinAvail,
403 : OutputProcessor::TimeStepType::System,
404 : OutputProcessor::StoreType::Average,
405 : NodeID);
406 0 : SetupOutputVariable(state,
407 : "System Node Maximum Available Mass Flow Rate",
408 : Constant::Units::kg_s,
409 0 : Node.MassFlowRateMaxAvail,
410 : OutputProcessor::TimeStepType::System,
411 : OutputProcessor::StoreType::Average,
412 : NodeID);
413 0 : SetupOutputVariable(state,
414 : "System Node Setpoint Mass Flow Rate",
415 : Constant::Units::kg_s,
416 0 : Node.MassFlowRateSetPoint,
417 : OutputProcessor::TimeStepType::System,
418 : OutputProcessor::StoreType::Average,
419 : NodeID);
420 0 : SetupOutputVariable(state,
421 : "System Node Requested Mass Flow Rate",
422 : Constant::Units::kg_s,
423 0 : Node.MassFlowRateRequest,
424 : OutputProcessor::TimeStepType::System,
425 : OutputProcessor::StoreType::Average,
426 : NodeID);
427 0 : SetupOutputVariable(state,
428 : "System Node Last Timestep Temperature",
429 : Constant::Units::C,
430 0 : Node.TempLastTimestep,
431 : OutputProcessor::TimeStepType::System,
432 : OutputProcessor::StoreType::Average,
433 : NodeID);
434 0 : SetupOutputVariable(state,
435 : "System Node Last Timestep Enthalpy",
436 : Constant::Units::J_kg,
437 0 : Node.EnthalpyLastTimestep,
438 : OutputProcessor::TimeStepType::System,
439 : OutputProcessor::StoreType::Average,
440 : NodeID);
441 : }
442 791 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
443 0 : SetupOutputVariable(state,
444 : "System Node CO2 Concentration",
445 : Constant::Units::ppm,
446 0 : Node.CO2,
447 : OutputProcessor::TimeStepType::System,
448 : OutputProcessor::StoreType::Average,
449 : NodeID);
450 : }
451 791 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
452 0 : SetupOutputVariable(state,
453 : "System Node Generic Air Contaminant Concentration",
454 : Constant::Units::ppm,
455 0 : Node.GenContam,
456 : OutputProcessor::TimeStepType::System,
457 : OutputProcessor::StoreType::Average,
458 : NodeID);
459 : }
460 : }
461 : }
462 75 : state.dataNodeInputMgr->NodeVarsSetup = true;
463 :
464 75 : print(state.files.bnd, "{}\n", "! This file shows details about the branches, nodes, and other");
465 75 : print(state.files.bnd, "{}\n", "! elements of the flow connections.");
466 75 : print(state.files.bnd, "{}\n", "! This file is intended for use in \"debugging\" potential problems");
467 75 : print(state.files.bnd, "{}\n", "! that may also be detected by the program, but may be more easily");
468 75 : print(state.files.bnd, "{}\n", "! identified by \"eye\".");
469 75 : print(state.files.bnd, "{}\n", "! This file is also intended to support software which draws a");
470 75 : print(state.files.bnd, "{}\n", "! schematic diagram of the HVAC system.");
471 75 : print(state.files.bnd, "{}\n", "! ===============================================================");
472 : // Show the node names on the Branch-Node Details file
473 : static constexpr std::string_view Format_700("! #Nodes,<Number of Unique Nodes>");
474 75 : print(state.files.bnd, "{}\n", Format_700);
475 75 : print(state.files.bnd, " #Nodes,{}\n", state.dataNodeInputMgr->NumOfUniqueNodeNames);
476 75 : if (state.dataNodeInputMgr->NumOfUniqueNodeNames > 0) {
477 : static constexpr std::string_view Format_702(
478 : "! <Node>,<NodeNumber>,<Node Name>,<Node Fluid Type>,<# Times Node Referenced After Definition>");
479 39 : print(state.files.bnd, "{}\n", Format_702);
480 : }
481 75 : int Count0 = 0;
482 866 : for (int NumNode = 1; NumNode <= state.dataNodeInputMgr->NumOfUniqueNodeNames; ++NumNode) {
483 791 : auto &Node = state.dataLoopNodes->Node(NumNode);
484 791 : auto &NodeID = state.dataLoopNodes->NodeID(NumNode);
485 1582 : print(state.files.bnd,
486 : " Node,{},{},{},{}\n",
487 : NumNode,
488 : NodeID,
489 791 : DataLoopNode::NodeFluidTypeNames[static_cast<int>(Node.FluidType)],
490 791 : state.dataNodeInputMgr->NodeRef(NumNode));
491 791 : if (state.dataNodeInputMgr->NodeRef(NumNode) == 0) {
492 123 : ++Count0;
493 : }
494 : }
495 : // Show suspicious node names on the Branch-Node Details file
496 75 : if (Count0 > 0) {
497 37 : print(state.files.bnd, "{}\n", "! ===============================================================");
498 37 : print(state.files.bnd, "{}\n", "! Suspicious nodes have 0 references. It is normal for some nodes, however.");
499 37 : print(state.files.bnd, "{}\n", "! Listing nodes with 0 references (culled from previous list):");
500 : static constexpr std::string_view Format_703(
501 : "! <Suspicious Node>,<NodeNumber>,<Node Name>,<Node Fluid Type>,<# Times Node Referenced After Definition>");
502 37 : print(state.files.bnd, "{}\n", Format_703);
503 772 : for (int NumNode = 1; NumNode <= state.dataNodeInputMgr->NumOfUniqueNodeNames; ++NumNode) {
504 735 : auto &Node = state.dataLoopNodes->Node(NumNode);
505 735 : auto &NodeID = state.dataLoopNodes->NodeID(NumNode);
506 735 : if (state.dataNodeInputMgr->NodeRef(NumNode) > 0) {
507 612 : continue;
508 : }
509 246 : print(state.files.bnd,
510 : " Suspicious Node,{},{},{},{}\n",
511 : NumNode,
512 : NodeID,
513 123 : DataLoopNode::NodeFluidTypeNames[static_cast<int>(Node.FluidType)],
514 123 : state.dataNodeInputMgr->NodeRef(NumNode));
515 : }
516 : }
517 : }
518 75 : }
519 :
520 772 : void GetNodeListsInput(EnergyPlusData &state, bool &ErrorsFound) // Set to true when requested Node List not found, unchanged otherwise
521 : {
522 :
523 : // SUBROUTINE INFORMATION:
524 : // AUTHOR Linda K. Lawrie
525 : // DATE WRITTEN September 1999
526 : // MODIFIED na
527 : // RE-ENGINEERED na
528 :
529 : // PURPOSE OF THIS SUBROUTINE:
530 : // This subroutine gets the Node Lists from the IDF and fills the
531 : // Node List Data Structure.
532 :
533 : // SUBROUTINE PARAMETER DEFINITIONS:
534 : static constexpr std::string_view RoutineName("GetNodeListsInput: ");
535 2298 : static std::string const CurrentModuleObject("NodeList");
536 :
537 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
538 : int NumAlphas; // Number of alphas in IDF item
539 : int NumNumbers; // Number of numerics in IDF item
540 : int IOStatus; // IOStatus for IDF item (not checked)
541 : int NCount; // Actual number of node lists
542 : bool flagError; // true when error node list name should be output
543 772 : Array1D_string cAlphas;
544 772 : Array1D<Real64> rNumbers;
545 :
546 772 : bool localErrorsFound(false);
547 772 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NCount, NumAlphas, NumNumbers);
548 772 : cAlphas.allocate(NumAlphas);
549 772 : rNumbers.allocate(NumNumbers);
550 772 : state.dataNodeInputMgr->NumOfNodeLists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
551 772 : state.dataNodeInputMgr->NodeLists.allocate(state.dataNodeInputMgr->NumOfNodeLists);
552 1171 : for (int i = 1; i <= state.dataNodeInputMgr->NumOfNodeLists; ++i) {
553 399 : state.dataNodeInputMgr->NodeLists(i).Name.clear();
554 399 : state.dataNodeInputMgr->NodeLists(i).NumOfNodesInList = 0;
555 : }
556 :
557 772 : NCount = 0;
558 1171 : for (int Loop = 1; Loop <= state.dataNodeInputMgr->NumOfNodeLists; ++Loop) {
559 399 : state.dataInputProcessing->inputProcessor->getObjectItem(
560 : state, CurrentModuleObject, Loop, cAlphas, NumAlphas, rNumbers, NumNumbers, IOStatus);
561 399 : if (Util::IsNameEmpty(state, cAlphas(1), CurrentModuleObject, localErrorsFound)) {
562 0 : continue;
563 : }
564 :
565 399 : ++NCount;
566 399 : state.dataNodeInputMgr->NodeLists(NCount).Name = cAlphas(1);
567 399 : state.dataNodeInputMgr->NodeLists(NCount).NodeNames.allocate(NumAlphas - 1);
568 399 : state.dataNodeInputMgr->NodeLists(NCount).NodeNames = "";
569 399 : state.dataNodeInputMgr->NodeLists(NCount).NodeNumbers.allocate(NumAlphas - 1);
570 399 : state.dataNodeInputMgr->NodeLists(NCount).NodeNumbers = 0;
571 399 : state.dataNodeInputMgr->NodeLists(NCount).NumOfNodesInList = NumAlphas - 1;
572 399 : if (NumAlphas <= 1) {
573 0 : if (NumAlphas == 1) {
574 0 : ShowSevereError(state, format("{}{}=\"{}\" does not have any nodes.", RoutineName, CurrentModuleObject, cAlphas(1)));
575 : } else {
576 0 : ShowSevereError(state, format("{}{}=<blank> does not have any nodes or nodelist name.", RoutineName, CurrentModuleObject));
577 : }
578 0 : localErrorsFound = true;
579 0 : continue;
580 : }
581 : // Put all in, then determine unique
582 944 : for (int Loop1 = 1; Loop1 <= NumAlphas - 1; ++Loop1) {
583 545 : state.dataNodeInputMgr->NodeLists(NCount).NodeNames(Loop1) = cAlphas(Loop1 + 1);
584 545 : if (cAlphas(Loop1 + 1).empty()) {
585 0 : ShowWarningError(state, format("{}{}=\"{}\", blank node name in list.", RoutineName, CurrentModuleObject, cAlphas(1)));
586 0 : --state.dataNodeInputMgr->NodeLists(NCount).NumOfNodesInList;
587 0 : if (state.dataNodeInputMgr->NodeLists(NCount).NumOfNodesInList <= 0) {
588 0 : ShowSevereError(state, format("{}{}=\"{}\" does not have any nodes.", RoutineName, CurrentModuleObject, cAlphas(1)));
589 0 : localErrorsFound = true;
590 0 : break;
591 : }
592 0 : continue;
593 : }
594 545 : state.dataNodeInputMgr->NodeLists(NCount).NodeNumbers(Loop1) = AssignNodeNumber(
595 545 : state, state.dataNodeInputMgr->NodeLists(NCount).NodeNames(Loop1), DataLoopNode::NodeFluidType::Blank, localErrorsFound);
596 545 : if (Util::SameString(state.dataNodeInputMgr->NodeLists(NCount).NodeNames(Loop1), state.dataNodeInputMgr->NodeLists(NCount).Name)) {
597 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid node name in list.", RoutineName, CurrentModuleObject, cAlphas(1)));
598 0 : ShowContinueError(state, format("... Node {} Name=\"{}\", duplicates NodeList Name.", Loop1, cAlphas(Loop1 + 1)));
599 0 : localErrorsFound = true;
600 : }
601 : }
602 : // Error on any duplicates
603 399 : flagError = true;
604 944 : for (int Loop1 = 1; Loop1 <= state.dataNodeInputMgr->NodeLists(NCount).NumOfNodesInList; ++Loop1) {
605 728 : for (int Loop2 = Loop1 + 1; Loop2 <= state.dataNodeInputMgr->NodeLists(NCount).NumOfNodesInList; ++Loop2) {
606 183 : if (state.dataNodeInputMgr->NodeLists(NCount).NodeNumbers(Loop1) != state.dataNodeInputMgr->NodeLists(NCount).NodeNumbers(Loop2)) {
607 183 : continue;
608 : }
609 0 : if (flagError) { // only list nodelist name once
610 0 : ShowSevereError(state, format("{}{}=\"{}\" has duplicate nodes:", RoutineName, CurrentModuleObject, cAlphas(1)));
611 0 : flagError = false;
612 : }
613 0 : ShowContinueError(state,
614 0 : format("...list item={}, \"{}\", duplicate list item={}, \"{}\".",
615 : Loop1,
616 0 : state.dataLoopNodes->NodeID(state.dataNodeInputMgr->NodeLists(NCount).NodeNumbers(Loop1)),
617 : Loop2,
618 0 : state.dataLoopNodes->NodeID(state.dataNodeInputMgr->NodeLists(NCount).NodeNumbers(Loop2))));
619 0 : localErrorsFound = true;
620 : }
621 : }
622 : }
623 :
624 1171 : for (int Loop = 1; Loop <= state.dataNodeInputMgr->NumOfNodeLists; ++Loop) {
625 944 : for (int Loop2 = 1; Loop2 <= state.dataNodeInputMgr->NodeLists(Loop).NumOfNodesInList; ++Loop2) {
626 2559 : for (int Loop1 = 1; Loop1 <= state.dataNodeInputMgr->NumOfNodeLists; ++Loop1) {
627 2014 : if (Loop == Loop1) {
628 545 : continue; // within a nodelist have already checked to see if node name duplicates nodelist name
629 : }
630 1469 : if (!Util::SameString(state.dataNodeInputMgr->NodeLists(Loop).NodeNames(Loop2), state.dataNodeInputMgr->NodeLists(Loop1).Name)) {
631 1469 : continue;
632 : }
633 0 : ShowSevereError(
634 : state,
635 0 : format(
636 0 : "{}{}=\"{}\", invalid node name in list.", RoutineName, CurrentModuleObject, state.dataNodeInputMgr->NodeLists(Loop1).Name));
637 0 : ShowContinueError(
638 : state,
639 0 : format("... Node {} Name=\"{}\", duplicates NodeList Name.", Loop2, state.dataNodeInputMgr->NodeLists(Loop).NodeNames(Loop2)));
640 0 : ShowContinueError(state, format("... NodeList=\"{}\", is duplicated.", state.dataNodeInputMgr->NodeLists(Loop1).Name));
641 0 : ShowContinueError(state, "... Items in NodeLists must not be the name of another NodeList.");
642 0 : localErrorsFound = true;
643 : }
644 : }
645 : }
646 :
647 772 : cAlphas.deallocate();
648 772 : rNumbers.deallocate();
649 :
650 772 : if (localErrorsFound) {
651 0 : ShowFatalError(state, format("{}{}: Error getting input - causes termination.", RoutineName, CurrentModuleObject));
652 0 : ErrorsFound = true;
653 : }
654 772 : }
655 :
656 10291 : int AssignNodeNumber(EnergyPlusData &state,
657 : std::string const &Name, // Name for assignment
658 : DataLoopNode::NodeFluidType const nodeFluidType, // must be valid
659 : bool &ErrorsFound)
660 : {
661 :
662 : // FUNCTION INFORMATION:
663 : // AUTHOR Linda K. Lawrie
664 : // DATE WRITTEN September 1999
665 : // MODIFIED na
666 : // RE-ENGINEERED na
667 :
668 : // PURPOSE OF THIS FUNCTION:
669 : // This function assigns a node number to this name.
670 :
671 : // METHODOLOGY EMPLOYED:
672 : // Look to see if a name has already been entered. Use the index of
673 : // the array as the node number, if there.
674 :
675 : // Return value
676 : int AssignNodeNumber;
677 :
678 10291 : if (nodeFluidType != DataLoopNode::NodeFluidType::Air && nodeFluidType != DataLoopNode::NodeFluidType::Water &&
679 2186 : nodeFluidType != DataLoopNode::NodeFluidType::Electric && nodeFluidType != DataLoopNode::NodeFluidType::Steam &&
680 2160 : nodeFluidType != DataLoopNode::NodeFluidType::Blank) {
681 0 : ShowSevereError(state, format("AssignNodeNumber: Invalid FluidType={}", nodeFluidType));
682 0 : ErrorsFound = true;
683 0 : ShowFatalError(state, "AssignNodeNumber: Preceding issue causes termination.");
684 : }
685 :
686 10291 : if (state.dataNodeInputMgr->NumOfUniqueNodeNames > 0) {
687 9628 : int NumNode = Util::FindItemInList(
688 19256 : Name, state.dataLoopNodes->NodeID({1, state.dataNodeInputMgr->NumOfUniqueNodeNames}), state.dataNodeInputMgr->NumOfUniqueNodeNames);
689 9628 : if (NumNode > 0) {
690 4942 : AssignNodeNumber = NumNode;
691 4942 : ++state.dataNodeInputMgr->NodeRef(NumNode);
692 4942 : if (nodeFluidType != DataLoopNode::NodeFluidType::Blank) {
693 5564 : if (state.dataLoopNodes->Node(NumNode).FluidType != nodeFluidType &&
694 1132 : state.dataLoopNodes->Node(NumNode).FluidType != DataLoopNode::NodeFluidType::Blank) {
695 0 : ShowSevereError(state,
696 0 : format("Existing Fluid type for node, incorrect for request. Node={}", state.dataLoopNodes->NodeID(NumNode)));
697 0 : ShowContinueError(
698 : state,
699 0 : format("Existing Fluid type={}, Requested Fluid Type={}",
700 0 : format("{}", DataLoopNode::NodeFluidTypeNames[static_cast<int>(state.dataLoopNodes->Node(NumNode).FluidType)]),
701 0 : format("{}", DataLoopNode::NodeFluidTypeNames[static_cast<int>(nodeFluidType)])));
702 0 : ErrorsFound = true;
703 : }
704 : }
705 4942 : if (state.dataLoopNodes->Node(NumNode).FluidType == DataLoopNode::NodeFluidType::Blank) {
706 1440 : state.dataLoopNodes->Node(NumNode).FluidType = nodeFluidType;
707 : }
708 : } else {
709 4686 : ++state.dataNodeInputMgr->NumOfUniqueNodeNames;
710 4686 : state.dataLoopNodes->NumOfNodes = state.dataNodeInputMgr->NumOfUniqueNodeNames;
711 :
712 4686 : state.dataLoopNodes->Node.redimension(state.dataLoopNodes->NumOfNodes);
713 4686 : state.dataLoopNodes->NodeID.redimension({0, state.dataLoopNodes->NumOfNodes});
714 4686 : state.dataNodeInputMgr->NodeRef.redimension(state.dataLoopNodes->NumOfNodes);
715 4686 : state.dataLoopNodes->MarkedNode.redimension(state.dataLoopNodes->NumOfNodes);
716 4686 : state.dataLoopNodes->NodeSetpointCheck.redimension(state.dataLoopNodes->NumOfNodes);
717 : // Set new item in Node
718 4686 : state.dataLoopNodes->Node(state.dataLoopNodes->NumOfNodes).FluidType = nodeFluidType;
719 4686 : state.dataNodeInputMgr->NodeRef(state.dataLoopNodes->NumOfNodes) = 0;
720 4686 : state.dataLoopNodes->NodeID(state.dataNodeInputMgr->NumOfUniqueNodeNames) = Name;
721 :
722 4686 : AssignNodeNumber = state.dataNodeInputMgr->NumOfUniqueNodeNames;
723 : }
724 : } else {
725 663 : state.dataLoopNodes->Node.allocate(1);
726 663 : state.dataLoopNodes->Node(1).FluidType = nodeFluidType;
727 : // Allocate takes care of defining
728 663 : state.dataLoopNodes->NumOfNodes = 1;
729 663 : state.dataLoopNodes->NodeID.allocate({0, 1});
730 663 : state.dataNodeInputMgr->NodeRef.allocate(1);
731 663 : state.dataLoopNodes->MarkedNode.allocate(1);
732 663 : state.dataLoopNodes->NodeSetpointCheck.allocate(1);
733 :
734 663 : state.dataNodeInputMgr->NumOfUniqueNodeNames = 1;
735 663 : state.dataLoopNodes->NodeID(0) = "Undefined";
736 663 : state.dataLoopNodes->NodeID(state.dataNodeInputMgr->NumOfUniqueNodeNames) = Name;
737 663 : AssignNodeNumber = 1;
738 663 : state.dataNodeInputMgr->NodeRef(1) = 0;
739 : }
740 :
741 10291 : return AssignNodeNumber;
742 : }
743 :
744 7509 : int GetOnlySingleNode(EnergyPlusData &state,
745 : std::string const &NodeName,
746 : bool &errFlag,
747 : DataLoopNode::ConnectionObjectType const NodeObjectType, // Node Object Type (i.e. "Chiller:Electric")
748 : std::string const &NodeObjectName, // Node Object Name (i.e. "MyChiller")
749 : DataLoopNode::NodeFluidType const nodeFluidType, // Fluidtype for checking/setting node FluidType
750 : DataLoopNode::ConnectionType const nodeConnectionType, // Node Connection Type (see DataLoopNode)
751 : CompFluidStream const NodeFluidStream, // Which Fluid Stream
752 : bool const ObjectIsParent, // True/False
753 : std::string_view const InputFieldName // Input Field Name
754 : )
755 : {
756 :
757 : // FUNCTION INFORMATION:
758 : // AUTHOR Linda K. Lawrie; adapted from GasAbsorptionChiller;Jason Glazer
759 : // DATE WRITTEN December 2001
760 :
761 : // PURPOSE OF THIS FUNCTION:
762 : // This function gets a single node (or error message results) using the
763 : // node id from the input file.
764 :
765 : static constexpr std::string_view RoutineName("GetOnlySingleNode: ");
766 :
767 : int NumNodes;
768 :
769 7509 : std::string_view const objTypeStr = BranchNodeConnections::ConnectionObjectTypeNames[static_cast<int>(NodeObjectType)];
770 :
771 7509 : if (state.dataNodeInputMgr->GetOnlySingleNodeFirstTime) {
772 : int NumParams;
773 : int NumAlphas;
774 : int NumNums;
775 649 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "NodeList", NumParams, NumAlphas, NumNums);
776 649 : state.dataNodeInputMgr->GetOnlySingleNodeNodeNums.dimension(NumParams, 0);
777 649 : state.dataNodeInputMgr->GetOnlySingleNodeFirstTime = false;
778 : }
779 :
780 15018 : GetNodeNums(state,
781 : NodeName,
782 : NumNodes,
783 7509 : state.dataNodeInputMgr->GetOnlySingleNodeNodeNums,
784 : errFlag,
785 : nodeFluidType,
786 : NodeObjectType,
787 : NodeObjectName,
788 : nodeConnectionType,
789 : NodeFluidStream,
790 : ObjectIsParent,
791 : false,
792 : InputFieldName);
793 :
794 7509 : if (NumNodes > 1) {
795 0 : ShowSevereError(state, format("{}{}=\"{}=\", invalid data.", RoutineName, objTypeStr, NodeObjectName));
796 0 : if (!InputFieldName.empty()) {
797 0 : ShowContinueError(state, fmt::format("...Ref field={}", InputFieldName));
798 : }
799 0 : ShowContinueError(state, format("Only 1st Node used from NodeList=\"{}\".", NodeName));
800 0 : ShowContinueError(state, "...a Nodelist may not be valid in this context.");
801 0 : errFlag = true;
802 7509 : } else if (NumNodes == 0) {
803 157 : state.dataNodeInputMgr->GetOnlySingleNodeNodeNums(1) = 0;
804 : }
805 :
806 15018 : return state.dataNodeInputMgr->GetOnlySingleNodeNodeNums(1);
807 : }
808 :
809 385 : void InitUniqueNodeCheck(EnergyPlusData &state, std::string const &ContextName)
810 : {
811 :
812 : // SUBROUTINE INFORMATION:
813 : // AUTHOR Linda Lawrie
814 : // DATE WRITTEN November 2002
815 : // MODIFIED na
816 : // RE-ENGINEERED na
817 :
818 : // PURPOSE OF THIS SUBROUTINE:
819 : // This subroutine begins a process of checking for unique node names
820 : // in a sequence of nodes.
821 :
822 : // Begin set up of Uniqueness context
823 :
824 385 : if (state.dataNodeInputMgr->GetNodeInputFlag) {
825 316 : bool errFlag(false);
826 316 : GetNodeListsInput(state, errFlag);
827 316 : state.dataNodeInputMgr->GetNodeInputFlag = false;
828 : }
829 :
830 385 : if (!state.dataNodeInputMgr->CurCheckContextName.empty()) {
831 0 : ShowFatalError(state,
832 0 : format("Init Uniqueness called for \"{}, but checks for \"{}\" was already in progress.",
833 : ContextName,
834 0 : state.dataNodeInputMgr->CurCheckContextName));
835 : }
836 385 : if (ContextName.empty()) {
837 0 : ShowFatalError(state, "Init Uniqueness called with Blank Context Name");
838 : }
839 385 : if (allocated(state.dataNodeInputMgr->UniqueNodeNames)) {
840 0 : state.dataNodeInputMgr->UniqueNodeNames.deallocate();
841 : }
842 :
843 385 : state.dataNodeInputMgr->NumCheckNodes = 0;
844 385 : state.dataNodeInputMgr->MaxCheckNodes = 100;
845 385 : state.dataNodeInputMgr->UniqueNodeNames.allocate(state.dataNodeInputMgr->MaxCheckNodes);
846 385 : state.dataNodeInputMgr->CurCheckContextName = ContextName;
847 385 : }
848 :
849 331 : void CheckUniqueNodeNames(
850 : EnergyPlusData &state, std::string const &NodeTypes, bool &ErrorsFound, std::string const &CheckName, std::string const &ObjectName)
851 : {
852 :
853 : // SUBROUTINE INFORMATION:
854 : // AUTHOR Linda Lawrie
855 : // DATE WRITTEN November 2002
856 : // MODIFIED na
857 : // RE-ENGINEERED na
858 :
859 : // PURPOSE OF THIS SUBROUTINE:
860 : // This subroutine checks the appropriate input argument for uniqueness.
861 : // Call CheckUniqueNodes(NodeTypes,CheckType,ErrorsFound,CheckName,CheckNumber)
862 : // NodeTypes - used in error message (if any produced)
863 : // ErrorsFound - true if error found by routine
864 : // CheckName - NodeName entered
865 : // ObjectName - "Name" field of object (i.e., CurCheckContextName)
866 :
867 : // METHODOLOGY EMPLOYED:
868 : // checks the current list of items for this (again)
869 :
870 331 : if (!CheckName.empty()) {
871 331 : int Found = Util::FindItemInList(CheckName, state.dataNodeInputMgr->UniqueNodeNames, state.dataNodeInputMgr->NumCheckNodes);
872 331 : if (Found != 0) {
873 1 : ShowSevereError(state, format("{}=\"{}\", duplicate node names found.", state.dataNodeInputMgr->CurCheckContextName, ObjectName));
874 1 : ShowContinueError(state, format("...for Node Type(s)={}, duplicate node name=\"{}\".", NodeTypes, CheckName));
875 2 : ShowContinueError(state, "...Nodes must be unique across instances of this object.");
876 : // CALL ShowSevereError(state, 'Node Types='//TRIM(NodeTypes)//', Non Unique Name found='//TRIM(CheckName))
877 : // CALL ShowContinueError(state, 'Context='//TRIM(CurCheckContextName))
878 1 : ErrorsFound = true;
879 : } else {
880 330 : ++state.dataNodeInputMgr->NumCheckNodes;
881 330 : if (state.dataNodeInputMgr->NumCheckNodes > state.dataNodeInputMgr->MaxCheckNodes) {
882 0 : state.dataNodeInputMgr->UniqueNodeNames.redimension(state.dataNodeInputMgr->MaxCheckNodes += 100);
883 : }
884 330 : state.dataNodeInputMgr->UniqueNodeNames(state.dataNodeInputMgr->NumCheckNodes) = CheckName;
885 : }
886 : }
887 331 : }
888 :
889 829 : void CheckUniqueNodeNumbers(
890 : EnergyPlusData &state, std::string const &NodeTypes, bool &ErrorsFound, int const CheckNumber, std::string const &ObjectName)
891 : {
892 :
893 : // SUBROUTINE INFORMATION:
894 : // AUTHOR Linda Lawrie
895 : // DATE WRITTEN November 2002
896 : // MODIFIED na
897 : // RE-ENGINEERED na
898 :
899 : // PURPOSE OF THIS SUBROUTINE:
900 : // This subroutine checks the appropriate input argument for uniqueness.
901 : // Call CheckUniqueNodes(NodeTypes,CheckType,ErrorsFound,CheckName,CheckNumber)
902 : // NodeTypes - used in error message (if any produced)
903 : // ErrorsFound - true if error found by routine
904 : // CheckNumber - Node Number entered
905 : // ObjectName - "Name" field of object (i.e., CurCheckContextName)
906 :
907 : // METHODOLOGY EMPLOYED:
908 : // checks the current list of items for this (again)
909 :
910 829 : if (CheckNumber != 0) {
911 829 : int Found = Util::FindItemInList(
912 829 : state.dataLoopNodes->NodeID(CheckNumber), state.dataNodeInputMgr->UniqueNodeNames, state.dataNodeInputMgr->NumCheckNodes);
913 829 : if (Found != 0) {
914 0 : ShowSevereError(state, format("{}=\"{}\", duplicate node names found.", state.dataNodeInputMgr->CurCheckContextName, ObjectName));
915 0 : ShowContinueError(state,
916 0 : format("...for Node Type(s)={}, duplicate node name=\"{}\".", NodeTypes, state.dataLoopNodes->NodeID(CheckNumber)));
917 0 : ShowContinueError(state, "...Nodes must be unique across instances of this object.");
918 0 : ErrorsFound = true;
919 : } else {
920 829 : ++state.dataNodeInputMgr->NumCheckNodes;
921 829 : if (state.dataNodeInputMgr->NumCheckNodes > state.dataNodeInputMgr->MaxCheckNodes) {
922 0 : state.dataNodeInputMgr->UniqueNodeNames.redimension(state.dataNodeInputMgr->MaxCheckNodes += 100);
923 : }
924 829 : state.dataNodeInputMgr->UniqueNodeNames(state.dataNodeInputMgr->NumCheckNodes) = state.dataLoopNodes->NodeID(CheckNumber);
925 : }
926 : }
927 829 : }
928 :
929 385 : void EndUniqueNodeCheck(EnergyPlusData &state, std::string const &ContextName)
930 : {
931 :
932 : // SUBROUTINE INFORMATION:
933 : // AUTHOR Linda Lawrie
934 : // DATE WRITTEN November 2002
935 : // MODIFIED na
936 : // RE-ENGINEERED na
937 :
938 : // PURPOSE OF THIS SUBROUTINE:
939 : // This subroutine marks the end of a unique node check.
940 :
941 385 : if (state.dataNodeInputMgr->CurCheckContextName != ContextName) {
942 0 : ShowFatalError(state,
943 0 : format("End Uniqueness called for \"{}, but checks for \"{}\" was in progress.",
944 : ContextName,
945 0 : state.dataNodeInputMgr->CurCheckContextName));
946 : }
947 385 : if (ContextName.empty()) {
948 0 : ShowFatalError(state, "End Uniqueness called with Blank Context Name");
949 : }
950 385 : state.dataNodeInputMgr->CurCheckContextName = std::string();
951 385 : if (allocated(state.dataNodeInputMgr->UniqueNodeNames)) {
952 385 : state.dataNodeInputMgr->UniqueNodeNames.deallocate();
953 : }
954 385 : }
955 :
956 36340 : void CalcMoreNodeInfo(EnergyPlusData &state)
957 : {
958 :
959 : // SUBROUTINE INFORMATION:
960 : // AUTHOR Fred Buhl
961 : // DATE WRITTEN January 2004
962 : // MODIFIED na
963 : // RE-ENGINEERED na
964 :
965 : // PURPOSE OF THIS SUBROUTINE:
966 : // Calculate additional node information for reporting
967 :
968 : // METHODOLOGY EMPLOYED:
969 : // Input is the existing node data plus environment variables. Output is
970 : // stored in MoreNodeInfo.
971 :
972 : // Using/Aliasing
973 : using Psychrometrics::CPCW;
974 : using Psychrometrics::PsyCpAirFnW;
975 : using Psychrometrics::PsyHFnTdbW;
976 : using Psychrometrics::PsyRhFnTdbWPb;
977 : using Psychrometrics::PsyRhoAirFnPbTdbW;
978 : using Psychrometrics::PsyTdpFnWPb;
979 : using Psychrometrics::PsyTwbFnTdbWPb;
980 : using Psychrometrics::RhoH2O;
981 :
982 : // SUBROUTINE PARAMETER DEFINITIONS:
983 : static constexpr std::string_view RoutineName("CalcMoreNodeInfo");
984 36456 : static std::string const NodeReportingCalc("NodeReportingCalc:");
985 :
986 36340 : auto &RhoAirStdInit = state.dataNodeInputMgr->RhoAirStdInit;
987 36340 : auto &RhoWaterStdInit = state.dataNodeInputMgr->RhoWaterStdInit;
988 36340 : auto &NodeWetBulbScheds = state.dataNodeInputMgr->NodeWetBulbScheds;
989 36340 : auto &NodeRelHumidityRepReq = state.dataNodeInputMgr->NodeRelHumidityRepReq;
990 36340 : auto &NodeRelHumidityScheds = state.dataNodeInputMgr->NodeRelHumidityScheds;
991 36340 : auto &NodeDewPointRepReq = state.dataNodeInputMgr->NodeDewPointRepReq;
992 36340 : auto &NodeDewPointScheds = state.dataNodeInputMgr->NodeDewPointScheds;
993 36340 : auto &NodeSpecificHeatRepReq = state.dataNodeInputMgr->NodeSpecificHeatRepReq;
994 36340 : auto &NodeSpecificHeatScheds = state.dataNodeInputMgr->NodeSpecificHeatScheds;
995 36340 : auto &nodeReportingStrings = state.dataNodeInputMgr->nodeReportingStrings;
996 36340 : auto &nodeFluids = state.dataNodeInputMgr->nodeFluids;
997 : Real64 SteamDensity;
998 : Real64 EnthSteamInDry;
999 : Real64 RhoAirCurrent; // temporary value for current air density f(baro, db , W)
1000 : Real64 rho;
1001 : Real64 Cp;
1002 : Real64 rhoStd;
1003 :
1004 36340 : if (state.dataNodeInputMgr->CalcMoreNodeInfoMyOneTimeFlag) {
1005 66 : RhoAirStdInit = state.dataEnvrn->StdRhoAir;
1006 66 : RhoWaterStdInit = RhoH2O(Constant::InitConvTemp);
1007 66 : state.dataNodeInputMgr->NodeWetBulbRepReq.allocate(state.dataLoopNodes->NumOfNodes);
1008 66 : NodeWetBulbScheds.allocate(state.dataLoopNodes->NumOfNodes);
1009 66 : NodeRelHumidityRepReq.allocate(state.dataLoopNodes->NumOfNodes);
1010 66 : NodeRelHumidityScheds.allocate(state.dataLoopNodes->NumOfNodes);
1011 66 : NodeDewPointRepReq.allocate(state.dataLoopNodes->NumOfNodes);
1012 66 : NodeDewPointScheds.allocate(state.dataLoopNodes->NumOfNodes);
1013 66 : NodeSpecificHeatRepReq.allocate(state.dataLoopNodes->NumOfNodes);
1014 66 : NodeSpecificHeatScheds.allocate(state.dataLoopNodes->NumOfNodes);
1015 66 : nodeReportingStrings.reserve(state.dataLoopNodes->NumOfNodes);
1016 66 : nodeFluids.reserve(state.dataLoopNodes->NumOfNodes);
1017 66 : state.dataNodeInputMgr->NodeWetBulbRepReq = false;
1018 66 : NodeWetBulbScheds = nullptr;
1019 66 : NodeRelHumidityRepReq = false;
1020 66 : NodeRelHumidityScheds = nullptr;
1021 66 : NodeDewPointRepReq = false;
1022 66 : NodeDewPointScheds = nullptr;
1023 66 : NodeSpecificHeatRepReq = false;
1024 66 : NodeSpecificHeatScheds = nullptr;
1025 :
1026 839 : for (int iNode = 1; iNode <= state.dataLoopNodes->NumOfNodes; ++iNode) {
1027 773 : nodeReportingStrings.push_back(std::string(NodeReportingCalc + state.dataLoopNodes->NodeID(iNode)));
1028 773 : nodeFluids.push_back(
1029 773 : (state.dataLoopNodes->Node(iNode).FluidIndex == 0) ? nullptr : state.dataFluid->glycols(state.dataLoopNodes->Node(iNode).FluidIndex));
1030 :
1031 1926 : for (auto const *reqVar : state.dataOutputProcessor->reqVars) {
1032 1153 : if (Util::SameString(reqVar->key, state.dataLoopNodes->NodeID(iNode)) || reqVar->key.empty()) {
1033 411 : if (Util::SameString(reqVar->name, "System Node Wetbulb Temperature")) {
1034 0 : state.dataNodeInputMgr->NodeWetBulbRepReq(iNode) = true;
1035 0 : NodeWetBulbScheds(iNode) = reqVar->sched;
1036 411 : } else if (Util::SameString(reqVar->name, "System Node Relative Humidity")) {
1037 0 : NodeRelHumidityRepReq(iNode) = true;
1038 0 : NodeRelHumidityScheds(iNode) = reqVar->sched;
1039 411 : } else if (Util::SameString(reqVar->name, "System Node Dewpoint Temperature")) {
1040 0 : NodeDewPointRepReq(iNode) = true;
1041 0 : NodeDewPointScheds(iNode) = reqVar->sched;
1042 411 : } else if (Util::SameString(reqVar->name, "System Node Specific Heat")) {
1043 0 : NodeSpecificHeatRepReq(iNode) = true;
1044 0 : NodeSpecificHeatScheds(iNode) = reqVar->sched;
1045 : }
1046 : }
1047 773 : }
1048 1546 : if (EMSManager::CheckIfNodeMoreInfoSensedByEMS(state, iNode, "System Node Wetbulb Temperature")) {
1049 1 : state.dataNodeInputMgr->NodeWetBulbRepReq(iNode) = true;
1050 1 : NodeWetBulbScheds(iNode) = nullptr;
1051 : }
1052 1546 : if (EMSManager::CheckIfNodeMoreInfoSensedByEMS(state, iNode, "System Node Relative Humidity")) {
1053 1 : NodeRelHumidityRepReq(iNode) = true;
1054 1 : NodeRelHumidityScheds(iNode) = nullptr;
1055 : }
1056 1546 : if (EMSManager::CheckIfNodeMoreInfoSensedByEMS(state, iNode, "System Node Dewpoint Temperature")) {
1057 1 : NodeDewPointRepReq(iNode) = true;
1058 1 : NodeDewPointScheds(iNode) = nullptr;
1059 : }
1060 1546 : if (EMSManager::CheckIfNodeMoreInfoSensedByEMS(state, iNode, "System Node Specific Heat")) {
1061 1 : NodeSpecificHeatRepReq(iNode) = true;
1062 1 : NodeSpecificHeatScheds(iNode) = nullptr;
1063 : }
1064 : }
1065 66 : state.dataNodeInputMgr->CalcMoreNodeInfoMyOneTimeFlag = false;
1066 : }
1067 :
1068 343807 : for (int iNode = 1; iNode <= state.dataLoopNodes->NumOfNodes; ++iNode) {
1069 307467 : bool ReportWetBulb = false;
1070 307467 : bool ReportRelHumidity = false;
1071 307467 : bool ReportDewPoint = false;
1072 307467 : bool ReportSpecificHeat = false;
1073 307467 : if (state.dataNodeInputMgr->NodeWetBulbRepReq(iNode) && NodeWetBulbScheds(iNode) != nullptr) {
1074 0 : ReportWetBulb = (NodeWetBulbScheds(iNode)->getCurrentVal() > 0.0);
1075 307467 : } else if (state.dataNodeInputMgr->NodeWetBulbRepReq(iNode) && NodeWetBulbScheds(iNode) == nullptr) {
1076 1 : ReportWetBulb = true;
1077 307466 : } else if (state.dataLoopNodes->Node(iNode).SPMNodeWetBulbRepReq) {
1078 0 : ReportWetBulb = true;
1079 : }
1080 307467 : if (NodeRelHumidityRepReq(iNode) && NodeRelHumidityScheds(iNode) != nullptr) {
1081 0 : ReportRelHumidity = (NodeRelHumidityScheds(iNode)->getCurrentVal() > 0.0);
1082 307467 : } else if (NodeRelHumidityRepReq(iNode) && NodeRelHumidityScheds(iNode) == nullptr) {
1083 1 : ReportRelHumidity = true;
1084 : }
1085 307467 : if (NodeDewPointRepReq(iNode) && NodeDewPointScheds(iNode) != nullptr) {
1086 0 : ReportDewPoint = (NodeDewPointScheds(iNode)->getCurrentVal() > 0.0);
1087 307467 : } else if (NodeDewPointRepReq(iNode) && NodeDewPointScheds(iNode) == nullptr) {
1088 1 : ReportDewPoint = true;
1089 : }
1090 307467 : if (NodeSpecificHeatRepReq(iNode) && NodeSpecificHeatScheds(iNode) != nullptr) {
1091 0 : ReportSpecificHeat = (NodeSpecificHeatScheds(iNode)->getCurrentVal() > 0.0);
1092 307467 : } else if (NodeSpecificHeatRepReq(iNode) && NodeSpecificHeatScheds(iNode) == nullptr) {
1093 1 : ReportSpecificHeat = true;
1094 : }
1095 : // calculate the volume flow rate
1096 307467 : if (state.dataLoopNodes->Node(iNode).FluidType == DataLoopNode::NodeFluidType::Air) {
1097 218399 : state.dataLoopNodes->MoreNodeInfo(iNode).VolFlowRateStdRho = state.dataLoopNodes->Node(iNode).MassFlowRate / RhoAirStdInit;
1098 : // if Node%Press was reliable could be used here.
1099 436798 : RhoAirCurrent = PsyRhoAirFnPbTdbW(
1100 218399 : state, state.dataEnvrn->OutBaroPress, state.dataLoopNodes->Node(iNode).Temp, state.dataLoopNodes->Node(iNode).HumRat);
1101 218399 : state.dataLoopNodes->MoreNodeInfo(iNode).Density = RhoAirCurrent;
1102 218399 : if (RhoAirCurrent != 0.0) {
1103 218399 : state.dataLoopNodes->MoreNodeInfo(iNode).VolFlowRateCrntRho = state.dataLoopNodes->Node(iNode).MassFlowRate / RhoAirCurrent;
1104 : }
1105 218399 : state.dataLoopNodes->MoreNodeInfo(iNode).ReportEnthalpy =
1106 218399 : PsyHFnTdbW(state.dataLoopNodes->Node(iNode).Temp, state.dataLoopNodes->Node(iNode).HumRat);
1107 218399 : if (ReportWetBulb) {
1108 : // if Node%Press was reliable could be used here.
1109 2 : state.dataLoopNodes->MoreNodeInfo(iNode).WetBulbTemp = PsyTwbFnTdbWPb(state,
1110 1 : state.dataLoopNodes->Node(iNode).Temp,
1111 1 : state.dataLoopNodes->Node(iNode).HumRat,
1112 1 : state.dataEnvrn->OutBaroPress,
1113 1 : nodeReportingStrings[iNode - 1]);
1114 : } else {
1115 218398 : state.dataLoopNodes->MoreNodeInfo(iNode).WetBulbTemp = 0.0;
1116 : }
1117 218399 : if (ReportDewPoint) {
1118 1 : state.dataLoopNodes->MoreNodeInfo(iNode).AirDewPointTemp =
1119 2 : PsyTdpFnWPb(state, state.dataLoopNodes->Node(iNode).HumRat, state.dataEnvrn->OutBaroPress);
1120 : } else {
1121 218398 : state.dataLoopNodes->MoreNodeInfo(iNode).AirDewPointTemp = 0.0;
1122 : }
1123 218399 : if (ReportRelHumidity) {
1124 : // if Node%Press was reliable could be used here.
1125 : // following routines don't issue psych errors and may be more reliable.
1126 2 : state.dataLoopNodes->MoreNodeInfo(iNode).RelHumidity = 100.0 * PsyRhFnTdbWPb(state,
1127 1 : state.dataLoopNodes->Node(iNode).Temp,
1128 1 : state.dataLoopNodes->Node(iNode).HumRat,
1129 1 : state.dataEnvrn->OutBaroPress,
1130 1 : nodeReportingStrings[iNode - 1]);
1131 : } else {
1132 218398 : state.dataLoopNodes->MoreNodeInfo(iNode).RelHumidity = 0.0;
1133 : }
1134 218399 : if (ReportSpecificHeat) { // only call psych routine if needed.
1135 1 : state.dataLoopNodes->MoreNodeInfo(iNode).SpecificHeat = PsyCpAirFnW(state.dataLoopNodes->Node(iNode).HumRat);
1136 : } else {
1137 218398 : state.dataLoopNodes->MoreNodeInfo(iNode).SpecificHeat = 0.0;
1138 : }
1139 89068 : } else if (state.dataLoopNodes->Node(iNode).FluidType == DataLoopNode::NodeFluidType::Water) {
1140 :
1141 176984 : if (!((state.dataLoopNodes->Node(iNode).FluidIndex > 0) &&
1142 88492 : (state.dataLoopNodes->Node(iNode).FluidIndex <= state.dataFluid->glycols.isize()))) {
1143 0 : rho = RhoWaterStdInit;
1144 0 : rhoStd = RhoWaterStdInit;
1145 0 : Cp = CPCW(state.dataLoopNodes->Node(iNode).Temp);
1146 : } else {
1147 88492 : Cp = nodeFluids[iNode - 1]->getSpecificHeat(state, state.dataLoopNodes->Node(iNode).Temp, nodeReportingStrings[iNode - 1]);
1148 88492 : rhoStd = nodeFluids[iNode - 1]->getDensity(state, Constant::InitConvTemp, nodeReportingStrings[iNode - 1]);
1149 88492 : rho = nodeFluids[iNode - 1]->getDensity(state, state.dataLoopNodes->Node(iNode).Temp, nodeReportingStrings[iNode - 1]);
1150 : }
1151 :
1152 88492 : state.dataLoopNodes->MoreNodeInfo(iNode).VolFlowRateStdRho = state.dataLoopNodes->Node(iNode).MassFlowRate / rhoStd;
1153 88492 : state.dataLoopNodes->MoreNodeInfo(iNode).VolFlowRateCrntRho = state.dataLoopNodes->Node(iNode).MassFlowRate / rho;
1154 88492 : state.dataLoopNodes->MoreNodeInfo(iNode).Density = rho;
1155 88492 : state.dataLoopNodes->MoreNodeInfo(iNode).ReportEnthalpy = Cp * state.dataLoopNodes->Node(iNode).Temp;
1156 88492 : state.dataLoopNodes->MoreNodeInfo(iNode).SpecificHeat = Cp; // always fill since cp already always being calculated anyway
1157 88492 : state.dataLoopNodes->MoreNodeInfo(iNode).WetBulbTemp = 0.0;
1158 88492 : state.dataLoopNodes->MoreNodeInfo(iNode).RelHumidity = 100.0;
1159 576 : } else if (state.dataLoopNodes->Node(iNode).FluidType == DataLoopNode::NodeFluidType::Steam) {
1160 0 : if (state.dataLoopNodes->Node(iNode).Quality == 1.0) {
1161 0 : auto *steam = Fluid::GetSteam(state);
1162 : SteamDensity =
1163 0 : steam->getSatDensity(state, state.dataLoopNodes->Node(iNode).Temp, state.dataLoopNodes->Node(iNode).Quality, RoutineName);
1164 : EnthSteamInDry =
1165 0 : steam->getSatEnthalpy(state, state.dataLoopNodes->Node(iNode).Temp, state.dataLoopNodes->Node(iNode).Quality, RoutineName);
1166 0 : state.dataLoopNodes->MoreNodeInfo(iNode).VolFlowRateStdRho = state.dataLoopNodes->Node(iNode).MassFlowRate / SteamDensity;
1167 0 : state.dataLoopNodes->MoreNodeInfo(iNode).ReportEnthalpy = EnthSteamInDry;
1168 0 : state.dataLoopNodes->MoreNodeInfo(iNode).WetBulbTemp = 0.0;
1169 0 : state.dataLoopNodes->MoreNodeInfo(iNode).RelHumidity = 0.0;
1170 0 : } else if (state.dataLoopNodes->Node(iNode).Quality == 0.0) { // The node has condensate water through it
1171 0 : state.dataLoopNodes->MoreNodeInfo(iNode).VolFlowRateStdRho = state.dataLoopNodes->Node(iNode).MassFlowRate / RhoWaterStdInit;
1172 0 : state.dataLoopNodes->MoreNodeInfo(iNode).ReportEnthalpy =
1173 0 : CPCW(state.dataLoopNodes->Node(iNode).Temp) * state.dataLoopNodes->Node(iNode).Temp;
1174 0 : state.dataLoopNodes->MoreNodeInfo(iNode).WetBulbTemp = 0.0;
1175 0 : state.dataLoopNodes->MoreNodeInfo(iNode).RelHumidity = 0.0;
1176 : }
1177 576 : } else if (state.dataLoopNodes->Node(iNode).FluidType == DataLoopNode::NodeFluidType::Electric) {
1178 0 : state.dataLoopNodes->MoreNodeInfo(iNode).VolFlowRateStdRho = 0.0;
1179 0 : state.dataLoopNodes->MoreNodeInfo(iNode).ReportEnthalpy = 0.0;
1180 0 : state.dataLoopNodes->MoreNodeInfo(iNode).WetBulbTemp = 0.0;
1181 0 : state.dataLoopNodes->MoreNodeInfo(iNode).RelHumidity = 0.0;
1182 0 : state.dataLoopNodes->MoreNodeInfo(iNode).SpecificHeat = 0.0;
1183 : } else {
1184 576 : state.dataLoopNodes->MoreNodeInfo(iNode).VolFlowRateStdRho = state.dataLoopNodes->Node(iNode).MassFlowRate / RhoAirStdInit;
1185 576 : if (state.dataLoopNodes->Node(iNode).HumRat > 0.0) {
1186 0 : state.dataLoopNodes->MoreNodeInfo(iNode).ReportEnthalpy =
1187 0 : PsyHFnTdbW(state.dataLoopNodes->Node(iNode).Temp, state.dataLoopNodes->Node(iNode).HumRat);
1188 0 : if (ReportWetBulb) {
1189 0 : state.dataLoopNodes->MoreNodeInfo(iNode).WetBulbTemp = PsyTwbFnTdbWPb(
1190 0 : state, state.dataLoopNodes->Node(iNode).Temp, state.dataLoopNodes->Node(iNode).HumRat, state.dataEnvrn->StdBaroPress);
1191 : } else {
1192 0 : state.dataLoopNodes->MoreNodeInfo(iNode).WetBulbTemp = 0.0;
1193 : }
1194 0 : if (ReportSpecificHeat) {
1195 0 : state.dataLoopNodes->MoreNodeInfo(iNode).SpecificHeat = PsyCpAirFnW(state.dataLoopNodes->Node(iNode).HumRat);
1196 : } else {
1197 0 : state.dataLoopNodes->MoreNodeInfo(iNode).SpecificHeat = 0.0;
1198 : }
1199 : } else {
1200 576 : state.dataLoopNodes->MoreNodeInfo(iNode).ReportEnthalpy =
1201 576 : CPCW(state.dataLoopNodes->Node(iNode).Temp) * state.dataLoopNodes->Node(iNode).Temp;
1202 576 : state.dataLoopNodes->MoreNodeInfo(iNode).WetBulbTemp = 0.0;
1203 576 : state.dataLoopNodes->MoreNodeInfo(iNode).SpecificHeat = 0.0;
1204 : }
1205 : }
1206 : }
1207 36340 : }
1208 :
1209 1 : void MarkNode(EnergyPlusData &state,
1210 : int const NodeNumber, // Node Number to be marked
1211 : DataLoopNode::ConnectionObjectType const ObjectType,
1212 : std::string const &ObjectName,
1213 : std::string const &FieldName)
1214 : {
1215 :
1216 : // SUBROUTINE INFORMATION:
1217 : // AUTHOR Linda Lawrie
1218 : // DATE WRITTEN March 2004
1219 : // MODIFIED na
1220 : // RE-ENGINEERED na
1221 :
1222 : // PURPOSE OF THIS SUBROUTINE:
1223 : // This subroutine marks a node -- this node needs to exist in more than one object.
1224 :
1225 1 : state.dataLoopNodes->MarkedNode(NodeNumber).IsMarked = true;
1226 1 : state.dataLoopNodes->MarkedNode(NodeNumber).ObjectType = ObjectType;
1227 1 : state.dataLoopNodes->MarkedNode(NodeNumber).ObjectName = ObjectName;
1228 1 : state.dataLoopNodes->MarkedNode(NodeNumber).FieldName = FieldName;
1229 1 : }
1230 :
1231 73 : void CheckMarkedNodes(EnergyPlusData &state, bool &ErrorsFound)
1232 : {
1233 :
1234 : // SUBROUTINE INFORMATION:
1235 : // AUTHOR Linda Lawrie
1236 : // DATE WRITTEN March 2004
1237 : // MODIFIED na
1238 : // RE-ENGINEERED na
1239 :
1240 : // PURPOSE OF THIS SUBROUTINE:
1241 : // This subroutine checks "marked" nodes.
1242 :
1243 862 : for (int NodeNum = 1; NodeNum <= state.dataLoopNodes->NumOfNodes; ++NodeNum) {
1244 789 : if (state.dataLoopNodes->MarkedNode(NodeNum).IsMarked) {
1245 1 : if (state.dataNodeInputMgr->NodeRef(NodeNum) == 0) {
1246 : std::string_view objType =
1247 0 : BranchNodeConnections::ConnectionObjectTypeNames[static_cast<int>(state.dataLoopNodes->MarkedNode(NodeNum).ObjectType)];
1248 0 : ShowSevereError(state, format("Node=\"{}\" did not find reference by another object.", state.dataLoopNodes->NodeID(NodeNum)));
1249 0 : ShowContinueError(state,
1250 0 : format(R"(Object="{}", Name="{}", Field=[{}])",
1251 : objType,
1252 0 : state.dataLoopNodes->MarkedNode(NodeNum).ObjectName,
1253 0 : state.dataLoopNodes->MarkedNode(NodeNum).FieldName));
1254 0 : ErrorsFound = true;
1255 : }
1256 : }
1257 : }
1258 73 : }
1259 :
1260 : } // namespace EnergyPlus::NodeInputManager
|