Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // ObjexxFCL Headers
49 : #include <ObjexxFCL/Fmath.hh>
50 :
51 : // EnergyPlus Headers
52 : #include <EnergyPlus/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/MixerComponent.hh>
58 : #include <EnergyPlus/NodeInputManager.hh>
59 : #include <EnergyPlus/Psychrometrics.hh>
60 : #include <EnergyPlus/UtilityRoutines.hh>
61 :
62 : namespace EnergyPlus::MixerComponent {
63 :
64 : // MODULE INFORMATION:
65 : // AUTHOR Richard J. Liesen
66 : // DATE WRITTEN March 2000
67 : // MODIFIED na
68 : // RE-ENGINEERED na
69 :
70 : // PURPOSE OF THIS MODULE:
71 : // To encapsulate the data and algorithms required to
72 : // manage Air Path Mixer Components
73 :
74 : // METHODOLOGY EMPLOYED:
75 : // This Mixer is very simple. It just takes the inlets and sums them
76 : // and sets that to the outlet conditions. For the State Properties
77 : // it just takes the flow weighted averages of them.
78 :
79 : // Using/Aliasing
80 : using namespace DataLoopNode;
81 :
82 90942 : void SimAirMixer(EnergyPlusData &state, std::string_view CompName, int &CompIndex)
83 : {
84 :
85 : // SUBROUTINE INFORMATION:
86 : // AUTHOR Richard Liesen
87 : // DATE WRITTEN February 1998
88 : // MODIFIED na
89 : // RE-ENGINEERED na
90 :
91 : // PURPOSE OF THIS SUBROUTINE:
92 : // This subroutine manages Mixer component simulation.
93 : // It is called from the SimAirLoopComponent
94 : // at the system time step.
95 :
96 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
97 : int MixerNum; // The Mixer that you are currently loading input into
98 :
99 : // Obtains and Allocates Mixer related parameters from input file
100 90942 : if (state.dataMixerComponent->SimAirMixerInputFlag) { // First time subroutine has been entered
101 39 : GetMixerInput(state);
102 39 : state.dataMixerComponent->SimAirMixerInputFlag = false;
103 : }
104 :
105 : // Find the correct MixerNumber
106 90942 : if (CompIndex == 0) {
107 46 : MixerNum = Util::FindItemInList(CompName, state.dataMixerComponent->MixerCond, &MixerConditions::MixerName);
108 46 : if (MixerNum == 0) {
109 0 : ShowFatalError(state, format("SimAirLoopMixer: Mixer not found={}", CompName));
110 : }
111 46 : CompIndex = MixerNum;
112 : } else {
113 90896 : MixerNum = CompIndex;
114 90896 : if (MixerNum > state.dataMixerComponent->NumMixers || MixerNum < 1) {
115 0 : ShowFatalError(state,
116 0 : format("SimAirLoopMixer: Invalid CompIndex passed={}, Number of Mixers={}, Mixer name={}",
117 : MixerNum,
118 0 : state.dataMixerComponent->NumMixers,
119 : CompName));
120 : }
121 90896 : if (state.dataMixerComponent->CheckEquipName(MixerNum)) {
122 38 : if (CompName != state.dataMixerComponent->MixerCond(MixerNum).MixerName) {
123 0 : ShowFatalError(state,
124 0 : format("SimAirLoopMixer: Invalid CompIndex passed={}, Mixer name={}, stored Mixer Name for that index={}",
125 : MixerNum,
126 : CompName,
127 0 : state.dataMixerComponent->MixerCond(MixerNum).MixerName));
128 : }
129 38 : state.dataMixerComponent->CheckEquipName(MixerNum) = false;
130 : }
131 : }
132 :
133 : // With the correct MixerNum Initialize
134 90942 : InitAirMixer(state, MixerNum); // Initialize all Mixer related parameters
135 :
136 90942 : CalcAirMixer(state, MixerNum);
137 :
138 : // Update the current Mixer to the outlet nodes
139 90942 : UpdateAirMixer(state, MixerNum);
140 :
141 : // Report the current Mixer
142 90942 : ReportMixer(MixerNum);
143 90942 : }
144 :
145 : // Get Input Section of the Module
146 : //******************************************************************************
147 :
148 48 : void GetMixerInput(EnergyPlusData &state)
149 : {
150 :
151 : // SUBROUTINE INFORMATION:
152 : // AUTHOR Richard J. Liesen
153 : // DATE WRITTEN March 2000
154 : // MODIFIED na
155 : // RE-ENGINEERED na
156 :
157 : // PURPOSE OF THIS SUBROUTINE:
158 : // This subroutine is the main routine to call other input routines and Get routines
159 :
160 : // METHODOLOGY EMPLOYED:
161 : // Uses the status flags to trigger events.
162 :
163 : // Using/Aliasing
164 : using NodeInputManager::GetOnlySingleNode;
165 :
166 : // SUBROUTINE PARAMETER DEFINITIONS:
167 : static constexpr std::string_view RoutineName("GetMixerInput: "); // include trailing blank space
168 :
169 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
170 : int MixerNum; // The Mixer that you are currently loading input into
171 : int NumAlphas;
172 : int NumNums;
173 : int NodeNum;
174 : int IOStat;
175 48 : bool ErrorsFound(false);
176 : int NumParams;
177 : int InNodeNum1;
178 : int InNodeNum2;
179 48 : std::string CurrentModuleObject; // for ease in getting objects
180 48 : Array1D_string AlphArray; // Alpha input items for object
181 48 : Array1D_string cAlphaFields; // Alpha field names
182 48 : Array1D_string cNumericFields; // Numeric field names
183 48 : Array1D<Real64> NumArray; // Numeric input items for object
184 48 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
185 48 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
186 :
187 48 : CurrentModuleObject = "AirLoopHVAC:ZoneMixer";
188 48 : state.dataMixerComponent->NumMixers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
189 :
190 48 : if (state.dataMixerComponent->NumMixers > 0) state.dataMixerComponent->MixerCond.allocate(state.dataMixerComponent->NumMixers);
191 48 : state.dataMixerComponent->CheckEquipName.dimension(state.dataMixerComponent->NumMixers, true);
192 :
193 48 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
194 48 : AlphArray.allocate(NumAlphas);
195 48 : cAlphaFields.allocate(NumAlphas);
196 48 : lAlphaBlanks.dimension(NumAlphas, true);
197 48 : cNumericFields.allocate(NumNums);
198 48 : lNumericBlanks.dimension(NumNums, true);
199 48 : NumArray.dimension(NumNums, 0.0);
200 :
201 104 : for (MixerNum = 1; MixerNum <= state.dataMixerComponent->NumMixers; ++MixerNum) {
202 56 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
203 : CurrentModuleObject,
204 : MixerNum,
205 : AlphArray,
206 : NumAlphas,
207 : NumArray,
208 : NumNums,
209 : IOStat,
210 : lNumericBlanks,
211 : lAlphaBlanks,
212 : cAlphaFields,
213 : cNumericFields);
214 56 : Util::IsNameEmpty(state, AlphArray(1), CurrentModuleObject, ErrorsFound);
215 :
216 56 : state.dataMixerComponent->MixerCond(MixerNum).MixerName = AlphArray(1);
217 :
218 112 : state.dataMixerComponent->MixerCond(MixerNum).OutletNode = GetOnlySingleNode(state,
219 56 : AlphArray(2),
220 : ErrorsFound,
221 : DataLoopNode::ConnectionObjectType::AirLoopHVACZoneMixer,
222 56 : AlphArray(1),
223 : DataLoopNode::NodeFluidType::Air,
224 : DataLoopNode::ConnectionType::Outlet,
225 : NodeInputManager::CompFluidStream::Primary,
226 : ObjectIsNotParent);
227 56 : state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes = NumAlphas - 2;
228 :
229 130 : for (auto &e : state.dataMixerComponent->MixerCond)
230 74 : e.InitFlag = true;
231 :
232 56 : state.dataMixerComponent->MixerCond(MixerNum).InletNode.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
233 56 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
234 56 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMaxAvail.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
235 56 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMinAvail.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
236 56 : state.dataMixerComponent->MixerCond(MixerNum).InletTemp.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
237 56 : state.dataMixerComponent->MixerCond(MixerNum).InletHumRat.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
238 56 : state.dataMixerComponent->MixerCond(MixerNum).InletEnthalpy.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
239 56 : state.dataMixerComponent->MixerCond(MixerNum).InletPressure.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
240 :
241 56 : state.dataMixerComponent->MixerCond(MixerNum).InletNode = 0;
242 56 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate = 0.0;
243 56 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMaxAvail = 0.0;
244 56 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMinAvail = 0.0;
245 56 : state.dataMixerComponent->MixerCond(MixerNum).InletTemp = 0.0;
246 56 : state.dataMixerComponent->MixerCond(MixerNum).InletHumRat = 0.0;
247 56 : state.dataMixerComponent->MixerCond(MixerNum).InletEnthalpy = 0.0;
248 56 : state.dataMixerComponent->MixerCond(MixerNum).InletPressure = 0.0;
249 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate = 0.0;
250 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMaxAvail = 0.0;
251 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMinAvail = 0.0;
252 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletTemp = 0.0;
253 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletHumRat = 0.0;
254 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletEnthalpy = 0.0;
255 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletPressure = 0.0;
256 :
257 148 : for (NodeNum = 1; NodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++NodeNum) {
258 :
259 92 : state.dataMixerComponent->MixerCond(MixerNum).InletNode(NodeNum) =
260 184 : GetOnlySingleNode(state,
261 92 : AlphArray(2 + NodeNum),
262 : ErrorsFound,
263 : DataLoopNode::ConnectionObjectType::AirLoopHVACZoneMixer,
264 92 : AlphArray(1),
265 : DataLoopNode::NodeFluidType::Air,
266 : DataLoopNode::ConnectionType::Inlet,
267 : NodeInputManager::CompFluidStream::Primary,
268 : ObjectIsNotParent);
269 92 : if (lAlphaBlanks(2 + NodeNum)) {
270 0 : ShowSevereError(state, format("{} is Blank, {} = {}", cAlphaFields(2 + NodeNum), CurrentModuleObject, AlphArray(1)));
271 0 : ErrorsFound = true;
272 : }
273 : }
274 :
275 : } // end Number of Mixer Loop
276 :
277 : // Check for duplicate names specified in Zone Mixer
278 104 : for (MixerNum = 1; MixerNum <= state.dataMixerComponent->NumMixers; ++MixerNum) {
279 56 : NodeNum = state.dataMixerComponent->MixerCond(MixerNum).OutletNode;
280 148 : for (InNodeNum1 = 1; InNodeNum1 <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InNodeNum1) {
281 92 : if (NodeNum != state.dataMixerComponent->MixerCond(MixerNum).InletNode(InNodeNum1)) continue;
282 0 : ShowSevereError(state,
283 0 : format("{} = {} specifies an inlet node name the same as the outlet node.",
284 : CurrentModuleObject,
285 0 : state.dataMixerComponent->MixerCond(MixerNum).MixerName));
286 0 : ShowContinueError(state, format("..{} = {}", cAlphaFields(2), state.dataLoopNodes->NodeID(NodeNum)));
287 0 : ShowContinueError(state, format("..Inlet Node #{} is duplicate.", InNodeNum1));
288 0 : ErrorsFound = true;
289 : }
290 148 : for (InNodeNum1 = 1; InNodeNum1 <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InNodeNum1) {
291 134 : for (InNodeNum2 = InNodeNum1 + 1; InNodeNum2 <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InNodeNum2) {
292 42 : if (state.dataMixerComponent->MixerCond(MixerNum).InletNode(InNodeNum1) !=
293 42 : state.dataMixerComponent->MixerCond(MixerNum).InletNode(InNodeNum2))
294 42 : continue;
295 0 : ShowSevereError(state,
296 0 : format("{} = {} specifies duplicate inlet nodes in its inlet node list.",
297 : CurrentModuleObject,
298 0 : state.dataMixerComponent->MixerCond(MixerNum).MixerName));
299 0 : ShowContinueError(state, format("..Inlet Node #{} Name={}", InNodeNum1, state.dataLoopNodes->NodeID(InNodeNum1)));
300 0 : ShowContinueError(state, format("..Inlet Node #{} is duplicate.", InNodeNum2));
301 0 : ErrorsFound = true;
302 : }
303 : }
304 : }
305 :
306 48 : AlphArray.deallocate();
307 48 : NumArray.deallocate();
308 48 : cAlphaFields.deallocate();
309 48 : lAlphaBlanks.deallocate();
310 48 : cNumericFields.deallocate();
311 48 : lNumericBlanks.deallocate();
312 :
313 48 : if (ErrorsFound) {
314 0 : ShowFatalError(state, format("{}Errors found in getting input.", RoutineName));
315 : }
316 48 : }
317 :
318 : // End of Get Input subroutines for the HB Module
319 : //******************************************************************************
320 :
321 : // Beginning Initialization Section of the Module
322 : //******************************************************************************
323 :
324 90946 : void InitAirMixer(EnergyPlusData &state, int const MixerNum)
325 : {
326 :
327 : // SUBROUTINE INFORMATION:
328 : // AUTHOR Richard J. Liesen
329 : // DATE WRITTEN March 2000
330 : // MODIFIED na
331 : // RE-ENGINEERED na
332 :
333 : // PURPOSE OF THIS SUBROUTINE:
334 : // This subroutine is for initializations of the Mixer Components.
335 :
336 : // METHODOLOGY EMPLOYED:
337 : // Uses the status flags to trigger events.
338 :
339 : // REFERENCES:
340 : // na
341 :
342 : // USE STATEMENTS:
343 : // na
344 :
345 : // Locals
346 : // SUBROUTINE ARGUMENT DEFINITIONS:
347 :
348 : // SUBROUTINE PARAMETER DEFINITIONS:
349 : // na
350 :
351 : // INTERFACE BLOCK SPECIFICATIONS
352 : // na
353 :
354 : // DERIVED TYPE DEFINITIONS
355 : // na
356 :
357 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
358 : int NodeNum;
359 :
360 : // Do the following initializations (every time step): This should be the info from
361 : // the previous components outlets or the node data in this section.
362 :
363 : // Transfer the node data to MixerCond data structure
364 249756 : for (NodeNum = 1; NodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++NodeNum) {
365 :
366 158810 : int InletNode = state.dataMixerComponent->MixerCond(MixerNum).InletNode(NodeNum);
367 : // Set all of the inlet mass flow variables from the nodes
368 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(NodeNum) = state.dataLoopNodes->Node(InletNode).MassFlowRate;
369 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMaxAvail(NodeNum) = state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail;
370 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMinAvail(NodeNum) = state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail;
371 : // Set all of the inlet state variables from the inlet nodes
372 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletTemp(NodeNum) = state.dataLoopNodes->Node(InletNode).Temp;
373 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletHumRat(NodeNum) = state.dataLoopNodes->Node(InletNode).HumRat;
374 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletEnthalpy(NodeNum) = state.dataLoopNodes->Node(InletNode).Enthalpy;
375 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletPressure(NodeNum) = state.dataLoopNodes->Node(InletNode).Press;
376 : }
377 90946 : }
378 :
379 : // End Initialization Section of the Module
380 : //******************************************************************************
381 :
382 : // Begin Algorithm Section of the Module
383 : //******************************************************************************
384 :
385 90942 : void CalcAirMixer(EnergyPlusData &state, int &MixerNum)
386 : {
387 :
388 : // SUBROUTINE INFORMATION:
389 : // AUTHOR Richard J. Liesen
390 : // DATE WRITTEN March 2000
391 : // MODIFIED na
392 : // RE-ENGINEERED na
393 :
394 : // PURPOSE OF THIS SUBROUTINE:
395 : // This subroutine needs a description.
396 :
397 : // METHODOLOGY EMPLOYED:
398 : // Needs description, as appropriate.
399 :
400 : // REFERENCES:
401 : // na
402 :
403 : // Using/Aliasing
404 : using Psychrometrics::PsyTdbFnHW;
405 :
406 : // Locals
407 : // SUBROUTINE ARGUMENT DEFINITIONS:
408 :
409 : // SUBROUTINE PARAMETER DEFINITIONS:
410 : // na
411 :
412 : // INTERFACE BLOCK SPECIFICATIONS
413 : // na
414 :
415 : // DERIVED TYPE DEFINITIONS
416 : // na
417 :
418 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
419 : int InletNodeNum;
420 :
421 : // Reset the totals to zero before they are summed.
422 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate = 0.0;
423 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMaxAvail = 0.0;
424 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMinAvail = 0.0;
425 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletTemp = 0.0;
426 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletHumRat = 0.0;
427 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletPressure = 0.0;
428 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletEnthalpy = 0.0;
429 :
430 249744 : for (InletNodeNum = 1; InletNodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InletNodeNum) {
431 158802 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate +=
432 158802 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(InletNodeNum);
433 158802 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMaxAvail +=
434 158802 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMaxAvail(InletNodeNum);
435 158802 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMinAvail +=
436 158802 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMinAvail(InletNodeNum);
437 : }
438 :
439 90942 : if (state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate > 0.0) {
440 :
441 : // Mass balance on moisture to get outlet air humidity ratio
442 :
443 223688 : for (InletNodeNum = 1; InletNodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InletNodeNum) {
444 143740 : state.dataMixerComponent->MixerCond(MixerNum).OutletHumRat +=
445 143740 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(InletNodeNum) *
446 143740 : state.dataMixerComponent->MixerCond(MixerNum).InletHumRat(InletNodeNum) /
447 143740 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate;
448 : }
449 :
450 : // "Momentum balance" to get outlet air pressure
451 :
452 223688 : for (InletNodeNum = 1; InletNodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InletNodeNum) {
453 143740 : state.dataMixerComponent->MixerCond(MixerNum).OutletPressure +=
454 143740 : state.dataMixerComponent->MixerCond(MixerNum).InletPressure(InletNodeNum) *
455 143740 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(InletNodeNum) /
456 143740 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate;
457 : }
458 :
459 : // Energy balance to get outlet air enthalpy
460 :
461 223688 : for (InletNodeNum = 1; InletNodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InletNodeNum) {
462 143740 : state.dataMixerComponent->MixerCond(MixerNum).OutletEnthalpy +=
463 143740 : state.dataMixerComponent->MixerCond(MixerNum).InletEnthalpy(InletNodeNum) *
464 143740 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(InletNodeNum) /
465 143740 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate;
466 : }
467 :
468 : // Use Enthalpy and humidity ratio to get outlet temperature from psych chart
469 :
470 79948 : state.dataMixerComponent->MixerCond(MixerNum).OutletTemp =
471 79948 : PsyTdbFnHW(state.dataMixerComponent->MixerCond(MixerNum).OutletEnthalpy, state.dataMixerComponent->MixerCond(MixerNum).OutletHumRat);
472 :
473 : } else {
474 : // Mass Flow in air loop is zero and loop is not operating.
475 : // Arbitrarily set the output to the first inlet leg
476 10994 : state.dataMixerComponent->MixerCond(MixerNum).OutletHumRat = state.dataMixerComponent->MixerCond(MixerNum).InletHumRat(1);
477 10994 : state.dataMixerComponent->MixerCond(MixerNum).OutletPressure = state.dataMixerComponent->MixerCond(MixerNum).InletPressure(1);
478 10994 : state.dataMixerComponent->MixerCond(MixerNum).OutletEnthalpy = state.dataMixerComponent->MixerCond(MixerNum).InletEnthalpy(1);
479 10994 : state.dataMixerComponent->MixerCond(MixerNum).OutletTemp = state.dataMixerComponent->MixerCond(MixerNum).InletTemp(1);
480 : }
481 :
482 : // make sure MassFlowRateMaxAvail is >= MassFlowRate
483 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMaxAvail = max(
484 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMaxAvail, state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate);
485 90942 : }
486 :
487 : // End Algorithm Section of the Module
488 : // *****************************************************************************
489 :
490 : // Beginning of Update subroutines for the Mixer Module
491 : // *****************************************************************************
492 :
493 90942 : void UpdateAirMixer(EnergyPlusData &state, int const MixerNum)
494 : {
495 :
496 : // SUBROUTINE INFORMATION:
497 : // AUTHOR Richard J. Liesen
498 : // DATE WRITTEN March 2000
499 : // MODIFIED na
500 : // RE-ENGINEERED na
501 :
502 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
503 : int OutletNode;
504 : int InletNode;
505 : int InletNodeNum;
506 :
507 90942 : OutletNode = state.dataMixerComponent->MixerCond(MixerNum).OutletNode;
508 90942 : InletNode = state.dataMixerComponent->MixerCond(MixerNum).InletNode(1); // For now use first inlet node
509 :
510 : // Set the outlet air nodes of the Mixer
511 90942 : state.dataLoopNodes->Node(OutletNode).MassFlowRate = state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate;
512 90942 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMaxAvail;
513 90942 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMinAvail;
514 90942 : state.dataLoopNodes->Node(OutletNode).Temp = state.dataMixerComponent->MixerCond(MixerNum).OutletTemp;
515 90942 : state.dataLoopNodes->Node(OutletNode).HumRat = state.dataMixerComponent->MixerCond(MixerNum).OutletHumRat;
516 90942 : state.dataLoopNodes->Node(OutletNode).Enthalpy = state.dataMixerComponent->MixerCond(MixerNum).OutletEnthalpy;
517 90942 : state.dataLoopNodes->Node(OutletNode).Press = state.dataMixerComponent->MixerCond(MixerNum).OutletPressure;
518 : // Set the outlet nodes for properties that just pass through & not used
519 90942 : state.dataLoopNodes->Node(OutletNode).Quality = state.dataLoopNodes->Node(InletNode).Quality;
520 :
521 90942 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
522 0 : if (state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate > 0.0) {
523 : // CO2 balance to get outlet air CO2
524 0 : state.dataLoopNodes->Node(OutletNode).CO2 = 0.0;
525 0 : for (InletNodeNum = 1; InletNodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InletNodeNum) {
526 0 : state.dataLoopNodes->Node(OutletNode).CO2 +=
527 0 : state.dataLoopNodes->Node(state.dataMixerComponent->MixerCond(MixerNum).InletNode(InletNodeNum)).CO2 *
528 0 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(InletNodeNum) /
529 0 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate;
530 : }
531 : } else {
532 0 : state.dataLoopNodes->Node(OutletNode).CO2 = state.dataLoopNodes->Node(InletNode).CO2;
533 : }
534 : }
535 :
536 90942 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
537 0 : if (state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate > 0.0) {
538 : // Generic contaminant balance to get outlet air CO2
539 0 : state.dataLoopNodes->Node(OutletNode).GenContam = 0.0;
540 0 : for (InletNodeNum = 1; InletNodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InletNodeNum) {
541 0 : state.dataLoopNodes->Node(OutletNode).GenContam +=
542 0 : state.dataLoopNodes->Node(state.dataMixerComponent->MixerCond(MixerNum).InletNode(InletNodeNum)).GenContam *
543 0 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(InletNodeNum) /
544 0 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate;
545 : }
546 : } else {
547 0 : state.dataLoopNodes->Node(OutletNode).GenContam = state.dataLoopNodes->Node(InletNode).GenContam;
548 : }
549 : }
550 90942 : }
551 :
552 : // End of Update subroutines for the Mixer Module
553 : // *****************************************************************************
554 :
555 : // Beginning of Reporting subroutines for the Mixer Module
556 : // *****************************************************************************
557 :
558 90942 : void ReportMixer([[maybe_unused]] int const MixerNum)
559 : {
560 :
561 : // SUBROUTINE INFORMATION:
562 : // AUTHOR Richard J. Liesen
563 : // DATE WRITTEN March 2000
564 : // MODIFIED na
565 : // RE-ENGINEERED na
566 :
567 : // PURPOSE OF THIS SUBROUTINE:
568 : // This subroutine needs a description.
569 :
570 : // METHODOLOGY EMPLOYED:
571 : // Needs description, as appropriate.
572 :
573 : // REFERENCES:
574 : // na
575 :
576 : // USE STATEMENTS:
577 : // na
578 :
579 : // Locals
580 : // SUBROUTINE ARGUMENT DEFINITIONS:
581 :
582 : // SUBROUTINE PARAMETER DEFINITIONS:
583 : // na
584 :
585 : // INTERFACE BLOCK SPECIFICATIONS
586 : // na
587 :
588 : // DERIVED TYPE DEFINITIONS
589 : // na
590 :
591 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
592 : // na
593 :
594 : // Write(*,*)=MixerCond(MixerNum)%MixerPower Still needs to report the Mixer power from this component
595 90942 : }
596 :
597 : // End of Reporting subroutines for the Mixer Module
598 :
599 : // Beginning of Utility subroutines for the Mixer Component
600 : // *****************************************************************************
601 :
602 7 : void GetZoneMixerIndex(EnergyPlusData &state, std::string const &MixerName, int &MixerIndex, bool &ErrorsFound, std::string const &ThisObjectType)
603 : {
604 :
605 : // SUBROUTINE INFORMATION:
606 : // AUTHOR Fred Buhl
607 : // DATE WRITTEN March 2015
608 : // MODIFIED na
609 : // RE-ENGINEERED na
610 :
611 : // PURPOSE OF THIS SUBROUTINE:
612 : // This subroutine sets an index for a given zone mixer -- issues error message if that mixer
613 : // is not legal mixer.
614 :
615 7 : if (state.dataMixerComponent->GetZoneMixerIndexInputFlag) { // First time subroutine has been entered
616 4 : GetMixerInput(state);
617 4 : state.dataMixerComponent->GetZoneMixerIndexInputFlag = false;
618 : }
619 :
620 7 : MixerIndex = Util::FindItemInList(MixerName, state.dataMixerComponent->MixerCond, &MixerConditions::MixerName);
621 7 : if (MixerIndex == 0) {
622 1 : if (!ThisObjectType.empty()) {
623 1 : ShowSevereError(state, format("{}, GetZoneMixerIndex: Zone Mixer not found={}", ThisObjectType, MixerName));
624 : } else {
625 0 : ShowSevereError(state, format("GetZoneMixerIndex: Zone Mixer not found={}", MixerName));
626 : }
627 1 : ErrorsFound = true;
628 : }
629 7 : }
630 :
631 2 : int getZoneMixerIndexFromInletNode(EnergyPlusData &state, int const InNodeNum)
632 : {
633 :
634 2 : if (state.dataMixerComponent->GetZoneMixerIndexInputFlag) { // First time subroutine has been entered
635 2 : GetMixerInput(state);
636 2 : state.dataMixerComponent->GetZoneMixerIndexInputFlag = false;
637 : }
638 :
639 2 : if (state.dataMixerComponent->NumMixers > 0) {
640 4 : for (int MixerNum = 1; MixerNum <= state.dataMixerComponent->NumMixers; ++MixerNum) {
641 4 : for (int InNodeCtr = 1; InNodeCtr <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InNodeCtr) {
642 2 : if (InNodeNum == state.dataMixerComponent->MixerCond(MixerNum).InletNode(InNodeCtr)) {
643 0 : return MixerNum;
644 : }
645 : }
646 : }
647 : }
648 :
649 2 : return 0;
650 : }
651 :
652 : // End of Utility subroutines for the Mixer Component
653 : // *****************************************************************************
654 :
655 : } // namespace EnergyPlus::MixerComponent
|