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 : // C++ Headers
49 : #include <cmath>
50 :
51 : // EnergyPlus Headers
52 : #include <EnergyPlus/Data/EnergyPlusData.hh>
53 : #include <EnergyPlus/DataContaminantBalance.hh>
54 : #include <EnergyPlus/DataEnvironment.hh>
55 : #include <EnergyPlus/DataLoopNode.hh>
56 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
57 : #include <EnergyPlus/NodeInputManager.hh>
58 : #include <EnergyPlus/Psychrometrics.hh>
59 : #include <EnergyPlus/SplitterComponent.hh>
60 : #include <EnergyPlus/UtilityRoutines.hh>
61 :
62 : namespace EnergyPlus {
63 :
64 : namespace SplitterComponent {
65 : // Module containing the Splitter simulation routines
66 :
67 : // MODULE INFORMATION:
68 : // AUTHOR Richard J. Liesen
69 : // DATE WRITTEN March 2000
70 : // MODIFIED na
71 : // RE-ENGINEERED na
72 :
73 : // PURPOSE OF THIS MODULE:
74 : // To encapsulate the data and algorithms required to
75 : // manage Air Path Splitter Components
76 :
77 : using namespace DataLoopNode;
78 :
79 22905644 : void SimAirLoopSplitter(EnergyPlusData &state,
80 : std::string_view CompName,
81 : bool const FirstHVACIteration,
82 : bool const FirstCall,
83 : bool &SplitterInletChanged,
84 : int &CompIndex)
85 : {
86 :
87 : // SUBROUTINE INFORMATION:
88 : // AUTHOR Richard Liesen
89 : // DATE WRITTEN March 2000
90 : // MODIFIED na
91 : // RE-ENGINEERED na
92 :
93 : // PURPOSE OF THIS SUBROUTINE:
94 : // This subroutine manages Splitter component simulation.
95 : // It is called from the SimAirLoopComponent
96 : // at the system time step.
97 :
98 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
99 : int SplitterNum; // The Splitter that you are currently loading input for
100 :
101 : // Obtains and Allocates Splitter related parameters from input file
102 22905644 : if (state.dataSplitterComponent->GetSplitterInputFlag) { // First time subroutine has been entered
103 540 : GetSplitterInput(state);
104 : }
105 :
106 : // Find the correct SplitterNumber
107 22905644 : if (CompIndex == 0) {
108 1215 : SplitterNum = Util::FindItemInList(CompName, state.dataSplitterComponent->SplitterCond, &SplitterConditions::SplitterName);
109 1215 : if (SplitterNum == 0) {
110 0 : ShowFatalError(state, format("SimAirLoopSplitter: Splitter not found={}", CompName));
111 : }
112 1215 : CompIndex = SplitterNum;
113 : } else {
114 22904429 : SplitterNum = CompIndex;
115 22904429 : if (SplitterNum > state.dataSplitterComponent->NumSplitters || SplitterNum < 1) {
116 0 : ShowFatalError(state,
117 0 : format("SimAirLoopSplitter: Invalid CompIndex passed={}, Number of Splitters={}, Splitter name={}",
118 : SplitterNum,
119 0 : state.dataSplitterComponent->NumSplitters,
120 : CompName));
121 : }
122 22904429 : if (state.dataSplitterComponent->CheckEquipName(SplitterNum)) {
123 1215 : if (CompName != state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName) {
124 0 : ShowFatalError(state,
125 0 : format("SimAirLoopSplitter: Invalid CompIndex passed={}, Splitter name={}, stored Splitter Name for that index={}",
126 : SplitterNum,
127 : CompName,
128 0 : state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName));
129 : }
130 1215 : state.dataSplitterComponent->CheckEquipName(SplitterNum) = false;
131 : }
132 : }
133 :
134 22905644 : InitAirLoopSplitter(state, SplitterNum, FirstHVACIteration, FirstCall); // Initialize all Splitter related parameters
135 :
136 22905644 : CalcAirLoopSplitter(state, SplitterNum, FirstCall);
137 :
138 : // Update the current Splitter to the outlet nodes
139 22905644 : UpdateSplitter(state, SplitterNum, SplitterInletChanged, FirstCall);
140 :
141 : // Report the current Splitter
142 22905644 : ReportSplitter(SplitterNum);
143 22905644 : }
144 :
145 : //*******************************
146 :
147 : // Get Input Section of the Module
148 : //******************************************************************************
149 :
150 540 : void GetSplitterInput(EnergyPlusData &state)
151 : {
152 :
153 : // SUBROUTINE INFORMATION:
154 : // AUTHOR Richard J. Liesen
155 : // DATE WRITTEN March 2000
156 : // MODIFIED na
157 : // RE-ENGINEERED na
158 :
159 : // PURPOSE OF THIS SUBROUTINE:
160 : // This subroutine is the main routine to call other input routines and
161 : // Get routines. The Splitter only gets node connection data and not mass
162 : // flow rates.
163 :
164 : // METHODOLOGY EMPLOYED:
165 : // Uses the status flags to trigger events.
166 :
167 : // Using/Aliasing
168 : using NodeInputManager::GetOnlySingleNode;
169 :
170 : // SUBROUTINE PARAMETER DEFINITIONS:
171 : static constexpr std::string_view RoutineName("GetSplitterInput: "); // include trailing blank space
172 :
173 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
174 : int SplitterNum; // The Splitter that you are currently loading input into
175 : int NumAlphas;
176 : int NumNums;
177 : int NodeNum;
178 : int IOStat;
179 540 : bool ErrorsFound(false);
180 : int NumParams;
181 : int OutNodeNum1;
182 : int OutNodeNum2;
183 540 : std::string CurrentModuleObject; // for ease in getting objects
184 540 : Array1D_string AlphArray; // Alpha input items for object
185 540 : Array1D_string cAlphaFields; // Alpha field names
186 540 : Array1D_string cNumericFields; // Numeric field names
187 540 : Array1D<Real64> NumArray; // Numeric input items for object
188 540 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
189 540 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
190 :
191 : // RESET THE GETINPUT FLAG
192 540 : state.dataSplitterComponent->GetSplitterInputFlag = false;
193 :
194 540 : CurrentModuleObject = "AirLoopHVAC:ZoneSplitter";
195 540 : state.dataSplitterComponent->NumSplitters = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
196 :
197 540 : if (state.dataSplitterComponent->NumSplitters > 0)
198 540 : state.dataSplitterComponent->SplitterCond.allocate(state.dataSplitterComponent->NumSplitters);
199 540 : state.dataSplitterComponent->CheckEquipName.dimension(state.dataSplitterComponent->NumSplitters, true);
200 :
201 540 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
202 540 : AlphArray.allocate(NumAlphas);
203 540 : cAlphaFields.allocate(NumAlphas);
204 540 : lAlphaBlanks.dimension(NumAlphas, true);
205 540 : cNumericFields.allocate(NumNums);
206 540 : lNumericBlanks.dimension(NumNums, true);
207 540 : NumArray.dimension(NumNums, 0.0);
208 :
209 1755 : for (SplitterNum = 1; SplitterNum <= state.dataSplitterComponent->NumSplitters; ++SplitterNum) {
210 1215 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
211 : CurrentModuleObject,
212 : SplitterNum,
213 : AlphArray,
214 : NumAlphas,
215 : NumArray,
216 : NumNums,
217 : IOStat,
218 : lNumericBlanks,
219 : lAlphaBlanks,
220 : cAlphaFields,
221 : cNumericFields);
222 1215 : Util::IsNameEmpty(state, AlphArray(1), CurrentModuleObject, ErrorsFound);
223 :
224 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName = AlphArray(1);
225 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode =
226 2430 : GetOnlySingleNode(state,
227 1215 : AlphArray(2),
228 : ErrorsFound,
229 : DataLoopNode::ConnectionObjectType::AirLoopHVACZoneSplitter,
230 1215 : AlphArray(1),
231 : DataLoopNode::NodeFluidType::Air,
232 : DataLoopNode::ConnectionType::Inlet,
233 : NodeInputManager::CompFluidStream::Primary,
234 : ObjectIsNotParent);
235 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes = NumAlphas - 2;
236 :
237 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum)
238 1215 : .OutletNode.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
239 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum)
240 1215 : .OutletMassFlowRate.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
241 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum)
242 1215 : .OutletMassFlowRateMaxAvail.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
243 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum)
244 1215 : .OutletMassFlowRateMinAvail.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
245 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum)
246 1215 : .OutletTemp.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
247 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum)
248 1215 : .OutletHumRat.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
249 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum)
250 1215 : .OutletEnthalpy.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
251 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum)
252 1215 : .OutletPressure.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
253 :
254 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate = 0.0;
255 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMaxAvail = 0.0;
256 1215 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMinAvail = 0.0;
257 :
258 4899 : for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
259 :
260 3684 : state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum) =
261 7368 : GetOnlySingleNode(state,
262 3684 : AlphArray(2 + NodeNum),
263 : ErrorsFound,
264 : DataLoopNode::ConnectionObjectType::AirLoopHVACZoneSplitter,
265 3684 : AlphArray(1),
266 : DataLoopNode::NodeFluidType::Air,
267 : DataLoopNode::ConnectionType::Outlet,
268 : NodeInputManager::CompFluidStream::Primary,
269 : ObjectIsNotParent);
270 3684 : if (lAlphaBlanks(2 + NodeNum)) {
271 0 : ShowSevereError(state, format("{} is Blank, {} = {}", cAlphaFields(2 + NodeNum), CurrentModuleObject, AlphArray(1)));
272 0 : ErrorsFound = true;
273 : }
274 : }
275 :
276 : } // end Number of Splitter Loop
277 :
278 : // Check for duplicate names specified in Zone Splitter
279 1755 : for (SplitterNum = 1; SplitterNum <= state.dataSplitterComponent->NumSplitters; ++SplitterNum) {
280 1215 : NodeNum = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
281 4899 : for (OutNodeNum1 = 1; OutNodeNum1 <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutNodeNum1) {
282 3684 : if (NodeNum != state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(OutNodeNum1)) continue;
283 0 : ShowSevereError(state,
284 0 : format("{} = {} specifies an outlet node name the same as the inlet node.",
285 : CurrentModuleObject,
286 0 : state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName));
287 0 : ShowContinueError(state, format("..{}={}", cAlphaFields(2), state.dataLoopNodes->NodeID(NodeNum)));
288 0 : ShowContinueError(state, format("..Outlet Node #{} is duplicate.", OutNodeNum1));
289 0 : ErrorsFound = true;
290 : }
291 4899 : for (OutNodeNum1 = 1; OutNodeNum1 <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutNodeNum1) {
292 19841 : for (OutNodeNum2 = OutNodeNum1 + 1; OutNodeNum2 <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes;
293 : ++OutNodeNum2) {
294 16157 : if (state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(OutNodeNum1) !=
295 16157 : state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(OutNodeNum2))
296 16157 : continue;
297 0 : ShowSevereError(state,
298 0 : format("{} = {} specifies duplicate outlet nodes in its outlet node list.",
299 : CurrentModuleObject,
300 0 : state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName));
301 0 : ShowContinueError(state, format("..Outlet Node #{} Name={}", OutNodeNum1, state.dataLoopNodes->NodeID(OutNodeNum1)));
302 0 : ShowContinueError(state, format("..Outlet Node #{} is duplicate.", OutNodeNum2));
303 0 : ErrorsFound = true;
304 : }
305 : }
306 : }
307 :
308 540 : AlphArray.deallocate();
309 540 : NumArray.deallocate();
310 540 : cAlphaFields.deallocate();
311 540 : lAlphaBlanks.deallocate();
312 540 : cNumericFields.deallocate();
313 540 : lNumericBlanks.deallocate();
314 :
315 540 : if (ErrorsFound) {
316 0 : ShowFatalError(state, format("{}Errors found in getting input.", RoutineName));
317 : }
318 540 : }
319 :
320 22905644 : void InitAirLoopSplitter(EnergyPlusData &state, int const SplitterNum, bool const FirstHVACIteration, bool const FirstCall)
321 : {
322 :
323 : // SUBROUTINE INFORMATION:
324 : // AUTHOR Richard J. Liesen
325 : // DATE WRITTEN March 2000
326 : // MODIFIED na
327 : // RE-ENGINEERED na
328 :
329 : // PURPOSE OF THIS SUBROUTINE:
330 : // This subroutine is for initialisations of the Splitter Components.
331 :
332 : // METHODOLOGY EMPLOYED:
333 : // Uses the status flags to trigger events.
334 :
335 : using Psychrometrics::PsyHFnTdbW;
336 :
337 : int InletNode;
338 : int OutletNode;
339 : int NodeNum;
340 : Real64 AirEnthalpy; // [J/kg]
341 :
342 : // Do the Begin Environment initializations
343 22905644 : if (state.dataGlobal->BeginEnvrnFlag && state.dataSplitterComponent->MyEnvrnFlag) {
344 :
345 : // Calculate the air density and enthalpy for standard conditions...
346 3218 : AirEnthalpy = PsyHFnTdbW(20.0, state.dataEnvrn->OutHumRat);
347 :
348 : // Initialize the inlet node to s standard set of conditions so that the
349 : // flows match around the loop & do not cause convergence problems.
350 3218 : InletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
351 3218 : state.dataLoopNodes->Node(InletNode).Temp = 20.0;
352 3218 : state.dataLoopNodes->Node(InletNode).HumRat = state.dataEnvrn->OutHumRat;
353 3218 : state.dataLoopNodes->Node(InletNode).Enthalpy = AirEnthalpy;
354 3218 : state.dataLoopNodes->Node(InletNode).Press = state.dataEnvrn->OutBaroPress;
355 3218 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
356 43 : state.dataLoopNodes->Node(InletNode).CO2 = state.dataContaminantBalance->OutdoorCO2;
357 : }
358 3218 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
359 11 : state.dataLoopNodes->Node(InletNode).GenContam = state.dataContaminantBalance->OutdoorGC;
360 : }
361 :
362 3218 : state.dataSplitterComponent->MyEnvrnFlag = false;
363 : }
364 :
365 22905644 : if (!state.dataGlobal->BeginEnvrnFlag) {
366 22798434 : state.dataSplitterComponent->MyEnvrnFlag = true;
367 : }
368 :
369 : // Set the inlet node for the Splitter
370 22905644 : InletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
371 :
372 : // Do the following initializations (every time step): This should be the info from
373 : // the previous components outlets or the node data in this section.
374 : // Load the node data in this section for the component simulation
375 :
376 : // This section is very important to understand. The system off condition is important
377 : // transfer around the loop even if the splitter does not have enough information to
378 : // calculate the correct flow rates since the dampers are downstream and there is no pressure
379 : // simulation. What happens in this section is the flow from upstream is not zero is
380 : // arbitrarily split by the number of inlet nodes. This is by no way meant to determine the
381 : // correct split flow! Just to give each outlet a non-zero flow so that the Air Distribution
382 : // Unit(ADU) downstream knows that the system is operating or has flow. This is only done the first
383 : // iteration through and the splitter first pass. After the first iteration the ADU sets the
384 : // correct flow and that is used and passed back upstream.
385 22905644 : if (FirstHVACIteration && FirstCall) {
386 4285863 : if (state.dataLoopNodes->Node(InletNode).MassFlowRate > 0.0) {
387 14216341 : for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
388 10967183 : OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
389 10967183 : state.dataLoopNodes->Node(OutletNode).MassFlowRate =
390 10967183 : state.dataLoopNodes->Node(InletNode).MassFlowRate / state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes;
391 : }
392 : }
393 4285863 : if (state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail > 0.0) {
394 14225249 : for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
395 10973880 : OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
396 10973880 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail =
397 10973880 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail /
398 10973880 : state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes;
399 : }
400 : }
401 :
402 : } // For FirstHVACIteration and FirstCall
403 :
404 22905644 : if (FirstCall) {
405 : // There is one exception to the rule stated above and that is if the system shuts OFF
406 : // for some operational or algorithm dependency. This IF block should catch that condition
407 : // and then pass the NO flow condition downstream to the waiting ADU's. Most of the time
408 : // this IF is jumped over.
409 11452822 : if (state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail == 0.0) {
410 :
411 8013856 : for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
412 :
413 5810473 : OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
414 5810473 : state.dataLoopNodes->Node(OutletNode).MassFlowRate = 0.0;
415 5810473 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = 0.0;
416 5810473 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = 0.0;
417 : }
418 : } // For Node inlet Max Avail = 0.0
419 :
420 : // Pass the State Properties through every time. This is what mainly happens each time
421 : // through the splitter,
422 11452822 : InletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
423 11452822 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletTemp = state.dataLoopNodes->Node(InletNode).Temp;
424 11452822 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletHumRat = state.dataLoopNodes->Node(InletNode).HumRat;
425 11452822 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletEnthalpy = state.dataLoopNodes->Node(InletNode).Enthalpy;
426 11452822 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletPressure = state.dataLoopNodes->Node(InletNode).Press;
427 :
428 : } else { // On the second call from the ZoneEquipManager this is where the flows are passed back to
429 : // the splitter inlet.
430 46830125 : for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
431 :
432 35377303 : OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
433 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRate(NodeNum) =
434 35377303 : state.dataLoopNodes->Node(OutletNode).MassFlowRate;
435 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRateMaxAvail(NodeNum) =
436 35377303 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail;
437 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRateMinAvail(NodeNum) =
438 35377303 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail;
439 : }
440 :
441 : } // For FirstCall
442 22905644 : }
443 :
444 22905644 : void CalcAirLoopSplitter(EnergyPlusData &state, int const SplitterNum, bool const FirstCall)
445 : {
446 :
447 : // SUBROUTINE INFORMATION:
448 : // AUTHOR Richard J. Liesen
449 : // DATE WRITTEN March 2000
450 : // MODIFIED na
451 : // RE-ENGINEERED na
452 :
453 : // PURPOSE OF THIS SUBROUTINE:
454 : // This subroutine needs a description.
455 :
456 : // METHODOLOGY EMPLOYED:
457 : // Needs description, as appropriate.
458 :
459 : int OutletNodeNum;
460 :
461 : // The first time through the State properties are split and passed through
462 22905644 : if (FirstCall) {
463 : // Moisture balance to get outlet air humidity ratio
464 46830125 : for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
465 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).OutletHumRat(OutletNodeNum) =
466 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletHumRat;
467 : }
468 :
469 : // "Momentum balance" to get outlet air pressure
470 46830125 : for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
471 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).OutletPressure(OutletNodeNum) =
472 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletPressure;
473 : }
474 :
475 : // Energy balance to get outlet air enthalpy
476 46830125 : for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
477 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).OutletEnthalpy(OutletNodeNum) =
478 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletEnthalpy;
479 : }
480 :
481 : // Set outlet temperatures equal to inlet temperature
482 46830125 : for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
483 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).OutletTemp(OutletNodeNum) =
484 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletTemp;
485 : }
486 :
487 : } else {
488 : // This is the second time through and this is where the mass flows from each outlet are
489 : // summed and then assigned upstream to the inlet node.
490 : // Overall Mass Continuity Equation to get inlet mass flow rates
491 : // Zero the inlet Totals before the Inlets are summed
492 11452822 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate = 0.0;
493 11452822 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMaxAvail = 0.0;
494 11452822 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMinAvail = 0.0;
495 :
496 46830125 : for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
497 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate +=
498 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRate(OutletNodeNum);
499 :
500 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMaxAvail +=
501 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRateMaxAvail(OutletNodeNum);
502 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMinAvail +=
503 35377303 : state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRateMinAvail(OutletNodeNum);
504 : }
505 :
506 : // What happens if Splitter inlet mass flow rate is greater than max available
507 : }
508 22905644 : }
509 :
510 : // End Algorithm Section of the Module
511 : // *****************************************************************************
512 :
513 : // Beginning of Update subroutines for the Splitter Module
514 : // *****************************************************************************
515 :
516 22905644 : void UpdateSplitter(EnergyPlusData &state, int const SplitterNum, bool &SplitterInletChanged, bool const FirstCall)
517 : {
518 : // SUBROUTINE INFORMATION:
519 : // AUTHOR Richard J. Liesen
520 : // DATE WRITTEN March 2000
521 : // MODIFIED na
522 : // RE-ENGINEERED na
523 :
524 22905644 : Real64 constexpr FlowRateToler(0.01); // Tolerance for mass flow rate convergence (in kg/s)
525 :
526 : int InletNode;
527 : int OutletNode;
528 : int NodeNum;
529 :
530 : // Set the inlet node for this splitter to be used throughout subroutine for either case
531 22905644 : InletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
532 :
533 : // On the FirstCall the State properties are passed through and the mass flows are not dealt with
534 : // except for NO flow conditions
535 22905644 : if (FirstCall) {
536 : // Set the outlet nodes for properties that just pass through & not used
537 46830125 : for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
538 35377303 : OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
539 35377303 : state.dataLoopNodes->Node(OutletNode).Temp = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletTemp(NodeNum);
540 35377303 : state.dataLoopNodes->Node(OutletNode).HumRat = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletHumRat(NodeNum);
541 35377303 : state.dataLoopNodes->Node(OutletNode).Enthalpy = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletEnthalpy(NodeNum);
542 35377303 : state.dataLoopNodes->Node(OutletNode).Quality = state.dataLoopNodes->Node(InletNode).Quality;
543 35377303 : state.dataLoopNodes->Node(OutletNode).Press = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletPressure(NodeNum);
544 35377303 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
545 130471 : state.dataLoopNodes->Node(OutletNode).CO2 = state.dataLoopNodes->Node(InletNode).CO2;
546 : }
547 35377303 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
548 28713 : state.dataLoopNodes->Node(OutletNode).GenContam = state.dataLoopNodes->Node(InletNode).GenContam;
549 : }
550 : }
551 :
552 : } else {
553 : // The second time through just updates the mass flow conditions back upstream
554 : // to the inlet. Before it sets the inlet it checks to see that the flow rate has not
555 : // changed or not. The tolerance has been relaxed some now that the splitter has been
556 : // re-written
557 :
558 : // Set the outlet air nodes of the Splitter if the splitter results have changed
559 : // beyond the tolerance.
560 11452822 : if (std::abs(state.dataLoopNodes->Node(InletNode).MassFlowRate -
561 11452822 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate) > FlowRateToler) {
562 2159217 : SplitterInletChanged = true;
563 : }
564 11452822 : state.dataLoopNodes->Node(InletNode).MassFlowRate = state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate;
565 11452822 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail =
566 11452822 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMaxAvail;
567 11452822 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail =
568 11452822 : state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMinAvail;
569 :
570 : } // The FirstCall END IF
571 22905644 : }
572 :
573 22905644 : void ReportSplitter([[maybe_unused]] int const SplitterNum)
574 : {
575 :
576 : // SUBROUTINE INFORMATION:
577 : // AUTHOR Richard J. Liesen
578 : // DATE WRITTEN March 2000
579 : // MODIFIED na
580 : // RE-ENGINEERED na
581 :
582 : // Write(*,*)=SplitterCond(SplitterNum)%SplitterPower Still needs to report the Splitter power from this component
583 22905644 : }
584 :
585 24 : int GetSplitterOutletNumber(EnergyPlusData &state,
586 : std::string const &SplitterName, // must match Splitter names for the Splitter type
587 : int const SplitterNum, // Index of Splitters
588 : bool &ErrorsFound // set to true if problem
589 : )
590 : {
591 :
592 : // FUNCTION INFORMATION:
593 : // AUTHOR Lixing Gu
594 : // DATE WRITTEN Feb 2013
595 : // MODIFIED na
596 : // RE-ENGINEERED na
597 :
598 : // PURPOSE OF THIS FUNCTION:
599 : // This function looks up the given AirLoopHVAC:ZoneSplitter and returns the number of outlet nodes. If
600 : // incorrect AirLoopHVAC:ZoneSplitter name is given, ErrorsFound is returned as true
601 : // as zero.
602 :
603 : // Return value
604 : int SplitterOutletNumber;
605 :
606 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
607 : int WhichSplitter;
608 :
609 : // Obtains and Allocates AirLoopHVAC:ZoneSplitter related parameters from input file
610 24 : if (state.dataSplitterComponent->GetSplitterInputFlag) { // First time subroutine has been entered
611 0 : GetSplitterInput(state);
612 0 : state.dataSplitterComponent->GetSplitterInputFlag = false;
613 : }
614 :
615 24 : if (SplitterNum == 0) {
616 0 : WhichSplitter = Util::FindItemInList(SplitterName, state.dataSplitterComponent->SplitterCond, &SplitterConditions::SplitterName);
617 : } else {
618 24 : WhichSplitter = SplitterNum;
619 : }
620 :
621 24 : if (WhichSplitter != 0) {
622 24 : SplitterOutletNumber = state.dataSplitterComponent->SplitterCond(WhichSplitter).NumOutletNodes;
623 : }
624 :
625 24 : if (WhichSplitter == 0) {
626 0 : ShowSevereError(state, format("GetSplitterOuletNumber: Could not find Splitter = \"{}\"", SplitterName));
627 0 : ErrorsFound = true;
628 0 : SplitterOutletNumber = 0;
629 : }
630 :
631 24 : return SplitterOutletNumber;
632 : }
633 :
634 24 : Array1D_int GetSplitterNodeNumbers(EnergyPlusData &state,
635 : std::string const &SplitterName, // must match Splitter names for the Splitter type
636 : int const SplitterNum, // Index of Splitters
637 : bool &ErrorsFound // set to true if problem
638 : )
639 : {
640 :
641 : // FUNCTION INFORMATION:
642 : // AUTHOR Lixing Gu
643 : // DATE WRITTEN Feb 2013
644 : // MODIFIED na
645 : // RE-ENGINEERED na
646 :
647 : // PURPOSE OF THIS FUNCTION:
648 : // This function looks up the given AirLoopHVAC:ZoneSplitter and returns the node numbers. If
649 : // incorrect AirLoopHVAC:ZoneSplitter name is given, ErrorsFound is returned as true
650 : // as zero.
651 :
652 : // Return value
653 24 : Array1D_int SplitterNodeNumbers;
654 :
655 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
656 : int WhichSplitter;
657 : int i;
658 :
659 : // Obtains and Allocates AirLoopHVAC:ZoneSplitter related parameters from input file
660 24 : if (state.dataSplitterComponent->GetSplitterInputFlag) { // First time subroutine has been entered
661 0 : GetSplitterInput(state);
662 0 : state.dataSplitterComponent->GetSplitterInputFlag = false;
663 : }
664 :
665 24 : if (SplitterNum == 0) {
666 0 : WhichSplitter = Util::FindItemInList(SplitterName, state.dataSplitterComponent->SplitterCond, &SplitterConditions::SplitterName);
667 : } else {
668 24 : WhichSplitter = SplitterNum;
669 : }
670 :
671 24 : if (WhichSplitter != 0) {
672 24 : SplitterNodeNumbers.allocate(state.dataSplitterComponent->SplitterCond(WhichSplitter).NumOutletNodes + 2);
673 24 : SplitterNodeNumbers(1) = state.dataSplitterComponent->SplitterCond(WhichSplitter).InletNode;
674 24 : SplitterNodeNumbers(2) = state.dataSplitterComponent->SplitterCond(WhichSplitter).NumOutletNodes;
675 74 : for (i = 1; i <= SplitterNodeNumbers(2); ++i) {
676 50 : SplitterNodeNumbers(i + 2) = state.dataSplitterComponent->SplitterCond(WhichSplitter).OutletNode(i);
677 : }
678 : }
679 :
680 24 : if (WhichSplitter == 0) {
681 0 : ShowSevereError(state, format("GetSplitterNodeNumbers: Could not find Splitter = \"{}\"", SplitterName));
682 0 : ErrorsFound = true;
683 : }
684 :
685 24 : return SplitterNodeNumbers;
686 0 : }
687 :
688 : } // namespace SplitterComponent
689 :
690 : } // namespace EnergyPlus
|