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) {
191 47 : state.dataMixerComponent->MixerCond.allocate(state.dataMixerComponent->NumMixers);
192 : }
193 48 : state.dataMixerComponent->CheckEquipName.dimension(state.dataMixerComponent->NumMixers, true);
194 :
195 48 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
196 48 : AlphArray.allocate(NumAlphas);
197 48 : cAlphaFields.allocate(NumAlphas);
198 48 : lAlphaBlanks.dimension(NumAlphas, true);
199 48 : cNumericFields.allocate(NumNums);
200 48 : lNumericBlanks.dimension(NumNums, true);
201 48 : NumArray.dimension(NumNums, 0.0);
202 :
203 104 : for (MixerNum = 1; MixerNum <= state.dataMixerComponent->NumMixers; ++MixerNum) {
204 56 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
205 : CurrentModuleObject,
206 : MixerNum,
207 : AlphArray,
208 : NumAlphas,
209 : NumArray,
210 : NumNums,
211 : IOStat,
212 : lNumericBlanks,
213 : lAlphaBlanks,
214 : cAlphaFields,
215 : cNumericFields);
216 56 : Util::IsNameEmpty(state, AlphArray(1), CurrentModuleObject, ErrorsFound);
217 :
218 56 : state.dataMixerComponent->MixerCond(MixerNum).MixerName = AlphArray(1);
219 :
220 112 : state.dataMixerComponent->MixerCond(MixerNum).OutletNode = GetOnlySingleNode(state,
221 56 : AlphArray(2),
222 : ErrorsFound,
223 : DataLoopNode::ConnectionObjectType::AirLoopHVACZoneMixer,
224 56 : AlphArray(1),
225 : DataLoopNode::NodeFluidType::Air,
226 : DataLoopNode::ConnectionType::Outlet,
227 : NodeInputManager::CompFluidStream::Primary,
228 : ObjectIsNotParent);
229 56 : state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes = NumAlphas - 2;
230 :
231 130 : for (auto &e : state.dataMixerComponent->MixerCond) {
232 74 : e.InitFlag = true;
233 56 : }
234 :
235 56 : state.dataMixerComponent->MixerCond(MixerNum).InletNode.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
236 56 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
237 56 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMaxAvail.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
238 56 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMinAvail.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
239 56 : state.dataMixerComponent->MixerCond(MixerNum).InletTemp.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
240 56 : state.dataMixerComponent->MixerCond(MixerNum).InletHumRat.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
241 56 : state.dataMixerComponent->MixerCond(MixerNum).InletEnthalpy.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
242 56 : state.dataMixerComponent->MixerCond(MixerNum).InletPressure.allocate(state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes);
243 :
244 56 : state.dataMixerComponent->MixerCond(MixerNum).InletNode = 0;
245 56 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate = 0.0;
246 56 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMaxAvail = 0.0;
247 56 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMinAvail = 0.0;
248 56 : state.dataMixerComponent->MixerCond(MixerNum).InletTemp = 0.0;
249 56 : state.dataMixerComponent->MixerCond(MixerNum).InletHumRat = 0.0;
250 56 : state.dataMixerComponent->MixerCond(MixerNum).InletEnthalpy = 0.0;
251 56 : state.dataMixerComponent->MixerCond(MixerNum).InletPressure = 0.0;
252 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate = 0.0;
253 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMaxAvail = 0.0;
254 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMinAvail = 0.0;
255 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletTemp = 0.0;
256 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletHumRat = 0.0;
257 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletEnthalpy = 0.0;
258 56 : state.dataMixerComponent->MixerCond(MixerNum).OutletPressure = 0.0;
259 :
260 148 : for (NodeNum = 1; NodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++NodeNum) {
261 :
262 92 : state.dataMixerComponent->MixerCond(MixerNum).InletNode(NodeNum) =
263 184 : GetOnlySingleNode(state,
264 92 : AlphArray(2 + NodeNum),
265 : ErrorsFound,
266 : DataLoopNode::ConnectionObjectType::AirLoopHVACZoneMixer,
267 92 : AlphArray(1),
268 : DataLoopNode::NodeFluidType::Air,
269 : DataLoopNode::ConnectionType::Inlet,
270 : NodeInputManager::CompFluidStream::Primary,
271 : ObjectIsNotParent);
272 92 : if (lAlphaBlanks(2 + NodeNum)) {
273 0 : ShowSevereError(state, format("{} is Blank, {} = {}", cAlphaFields(2 + NodeNum), CurrentModuleObject, AlphArray(1)));
274 0 : ErrorsFound = true;
275 : }
276 : }
277 :
278 : } // end Number of Mixer Loop
279 :
280 : // Check for duplicate names specified in Zone Mixer
281 104 : for (MixerNum = 1; MixerNum <= state.dataMixerComponent->NumMixers; ++MixerNum) {
282 56 : NodeNum = state.dataMixerComponent->MixerCond(MixerNum).OutletNode;
283 148 : for (InNodeNum1 = 1; InNodeNum1 <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InNodeNum1) {
284 92 : if (NodeNum != state.dataMixerComponent->MixerCond(MixerNum).InletNode(InNodeNum1)) {
285 92 : continue;
286 : }
287 0 : ShowSevereError(state,
288 0 : format("{} = {} specifies an inlet node name the same as the outlet node.",
289 : CurrentModuleObject,
290 0 : state.dataMixerComponent->MixerCond(MixerNum).MixerName));
291 0 : ShowContinueError(state, format("..{} = {}", cAlphaFields(2), state.dataLoopNodes->NodeID(NodeNum)));
292 0 : ShowContinueError(state, format("..Inlet Node #{} is duplicate.", InNodeNum1));
293 0 : ErrorsFound = true;
294 : }
295 148 : for (InNodeNum1 = 1; InNodeNum1 <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InNodeNum1) {
296 134 : for (InNodeNum2 = InNodeNum1 + 1; InNodeNum2 <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InNodeNum2) {
297 42 : if (state.dataMixerComponent->MixerCond(MixerNum).InletNode(InNodeNum1) !=
298 42 : state.dataMixerComponent->MixerCond(MixerNum).InletNode(InNodeNum2)) {
299 42 : continue;
300 : }
301 0 : ShowSevereError(state,
302 0 : format("{} = {} specifies duplicate inlet nodes in its inlet node list.",
303 : CurrentModuleObject,
304 0 : state.dataMixerComponent->MixerCond(MixerNum).MixerName));
305 0 : ShowContinueError(state, format("..Inlet Node #{} Name={}", InNodeNum1, state.dataLoopNodes->NodeID(InNodeNum1)));
306 0 : ShowContinueError(state, format("..Inlet Node #{} is duplicate.", InNodeNum2));
307 0 : ErrorsFound = true;
308 : }
309 : }
310 : }
311 :
312 48 : AlphArray.deallocate();
313 48 : NumArray.deallocate();
314 48 : cAlphaFields.deallocate();
315 48 : lAlphaBlanks.deallocate();
316 48 : cNumericFields.deallocate();
317 48 : lNumericBlanks.deallocate();
318 :
319 48 : if (ErrorsFound) {
320 0 : ShowFatalError(state, format("{}Errors found in getting input.", RoutineName));
321 : }
322 48 : }
323 :
324 : // End of Get Input subroutines for the HB Module
325 : //******************************************************************************
326 :
327 : // Beginning Initialization Section of the Module
328 : //******************************************************************************
329 :
330 90946 : void InitAirMixer(EnergyPlusData &state, int const MixerNum)
331 : {
332 :
333 : // SUBROUTINE INFORMATION:
334 : // AUTHOR Richard J. Liesen
335 : // DATE WRITTEN March 2000
336 : // MODIFIED na
337 : // RE-ENGINEERED na
338 :
339 : // PURPOSE OF THIS SUBROUTINE:
340 : // This subroutine is for initializations of the Mixer Components.
341 :
342 : // METHODOLOGY EMPLOYED:
343 : // Uses the status flags to trigger events.
344 :
345 : // REFERENCES:
346 : // na
347 :
348 : // USE STATEMENTS:
349 : // na
350 :
351 : // Locals
352 : // SUBROUTINE ARGUMENT DEFINITIONS:
353 :
354 : // SUBROUTINE PARAMETER DEFINITIONS:
355 : // na
356 :
357 : // INTERFACE BLOCK SPECIFICATIONS
358 : // na
359 :
360 : // DERIVED TYPE DEFINITIONS
361 : // na
362 :
363 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
364 : int NodeNum;
365 :
366 : // Do the following initializations (every time step): This should be the info from
367 : // the previous components outlets or the node data in this section.
368 :
369 : // Transfer the node data to MixerCond data structure
370 249756 : for (NodeNum = 1; NodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++NodeNum) {
371 :
372 158810 : int InletNode = state.dataMixerComponent->MixerCond(MixerNum).InletNode(NodeNum);
373 : // Set all of the inlet mass flow variables from the nodes
374 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(NodeNum) = state.dataLoopNodes->Node(InletNode).MassFlowRate;
375 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMaxAvail(NodeNum) = state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail;
376 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMinAvail(NodeNum) = state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail;
377 : // Set all of the inlet state variables from the inlet nodes
378 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletTemp(NodeNum) = state.dataLoopNodes->Node(InletNode).Temp;
379 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletHumRat(NodeNum) = state.dataLoopNodes->Node(InletNode).HumRat;
380 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletEnthalpy(NodeNum) = state.dataLoopNodes->Node(InletNode).Enthalpy;
381 158810 : state.dataMixerComponent->MixerCond(MixerNum).InletPressure(NodeNum) = state.dataLoopNodes->Node(InletNode).Press;
382 : }
383 90946 : }
384 :
385 : // End Initialization Section of the Module
386 : //******************************************************************************
387 :
388 : // Begin Algorithm Section of the Module
389 : //******************************************************************************
390 :
391 90942 : void CalcAirMixer(EnergyPlusData &state, int &MixerNum)
392 : {
393 :
394 : // SUBROUTINE INFORMATION:
395 : // AUTHOR Richard J. Liesen
396 : // DATE WRITTEN March 2000
397 : // MODIFIED na
398 : // RE-ENGINEERED na
399 :
400 : // PURPOSE OF THIS SUBROUTINE:
401 : // This subroutine needs a description.
402 :
403 : // METHODOLOGY EMPLOYED:
404 : // Needs description, as appropriate.
405 :
406 : // REFERENCES:
407 : // na
408 :
409 : // Using/Aliasing
410 : using Psychrometrics::PsyTdbFnHW;
411 :
412 : // Locals
413 : // SUBROUTINE ARGUMENT DEFINITIONS:
414 :
415 : // SUBROUTINE PARAMETER DEFINITIONS:
416 : // na
417 :
418 : // INTERFACE BLOCK SPECIFICATIONS
419 : // na
420 :
421 : // DERIVED TYPE DEFINITIONS
422 : // na
423 :
424 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
425 : int InletNodeNum;
426 :
427 : // Reset the totals to zero before they are summed.
428 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate = 0.0;
429 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMaxAvail = 0.0;
430 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMinAvail = 0.0;
431 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletTemp = 0.0;
432 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletHumRat = 0.0;
433 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletPressure = 0.0;
434 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletEnthalpy = 0.0;
435 :
436 249744 : for (InletNodeNum = 1; InletNodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InletNodeNum) {
437 158802 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate +=
438 158802 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(InletNodeNum);
439 158802 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMaxAvail +=
440 158802 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMaxAvail(InletNodeNum);
441 158802 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMinAvail +=
442 158802 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRateMinAvail(InletNodeNum);
443 : }
444 :
445 90942 : if (state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate > 0.0) {
446 :
447 : // Mass balance on moisture to get outlet air humidity ratio
448 :
449 223688 : for (InletNodeNum = 1; InletNodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InletNodeNum) {
450 143740 : state.dataMixerComponent->MixerCond(MixerNum).OutletHumRat +=
451 143740 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(InletNodeNum) *
452 143740 : state.dataMixerComponent->MixerCond(MixerNum).InletHumRat(InletNodeNum) /
453 143740 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate;
454 : }
455 :
456 : // "Momentum balance" to get outlet air pressure
457 :
458 223688 : for (InletNodeNum = 1; InletNodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InletNodeNum) {
459 143740 : state.dataMixerComponent->MixerCond(MixerNum).OutletPressure +=
460 143740 : state.dataMixerComponent->MixerCond(MixerNum).InletPressure(InletNodeNum) *
461 143740 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(InletNodeNum) /
462 143740 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate;
463 : }
464 :
465 : // Energy balance to get outlet air enthalpy
466 :
467 223688 : for (InletNodeNum = 1; InletNodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InletNodeNum) {
468 143740 : state.dataMixerComponent->MixerCond(MixerNum).OutletEnthalpy +=
469 143740 : state.dataMixerComponent->MixerCond(MixerNum).InletEnthalpy(InletNodeNum) *
470 143740 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(InletNodeNum) /
471 143740 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate;
472 : }
473 :
474 : // Use Enthalpy and humidity ratio to get outlet temperature from psych chart
475 :
476 79948 : state.dataMixerComponent->MixerCond(MixerNum).OutletTemp =
477 79948 : PsyTdbFnHW(state.dataMixerComponent->MixerCond(MixerNum).OutletEnthalpy, state.dataMixerComponent->MixerCond(MixerNum).OutletHumRat);
478 :
479 : } else {
480 : // Mass Flow in air loop is zero and loop is not operating.
481 : // Arbitrarily set the output to the first inlet leg
482 10994 : state.dataMixerComponent->MixerCond(MixerNum).OutletHumRat = state.dataMixerComponent->MixerCond(MixerNum).InletHumRat(1);
483 10994 : state.dataMixerComponent->MixerCond(MixerNum).OutletPressure = state.dataMixerComponent->MixerCond(MixerNum).InletPressure(1);
484 10994 : state.dataMixerComponent->MixerCond(MixerNum).OutletEnthalpy = state.dataMixerComponent->MixerCond(MixerNum).InletEnthalpy(1);
485 10994 : state.dataMixerComponent->MixerCond(MixerNum).OutletTemp = state.dataMixerComponent->MixerCond(MixerNum).InletTemp(1);
486 : }
487 :
488 : // make sure MassFlowRateMaxAvail is >= MassFlowRate
489 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMaxAvail = max(
490 90942 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMaxAvail, state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate);
491 90942 : }
492 :
493 : // End Algorithm Section of the Module
494 : // *****************************************************************************
495 :
496 : // Beginning of Update subroutines for the Mixer Module
497 : // *****************************************************************************
498 :
499 90942 : void UpdateAirMixer(EnergyPlusData &state, int const MixerNum)
500 : {
501 :
502 : // SUBROUTINE INFORMATION:
503 : // AUTHOR Richard J. Liesen
504 : // DATE WRITTEN March 2000
505 : // MODIFIED na
506 : // RE-ENGINEERED na
507 :
508 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
509 : int OutletNode;
510 : int InletNode;
511 : int InletNodeNum;
512 :
513 90942 : OutletNode = state.dataMixerComponent->MixerCond(MixerNum).OutletNode;
514 90942 : InletNode = state.dataMixerComponent->MixerCond(MixerNum).InletNode(1); // For now use first inlet node
515 :
516 : // Set the outlet air nodes of the Mixer
517 90942 : state.dataLoopNodes->Node(OutletNode).MassFlowRate = state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate;
518 90942 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMaxAvail;
519 90942 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRateMinAvail;
520 90942 : state.dataLoopNodes->Node(OutletNode).Temp = state.dataMixerComponent->MixerCond(MixerNum).OutletTemp;
521 90942 : state.dataLoopNodes->Node(OutletNode).HumRat = state.dataMixerComponent->MixerCond(MixerNum).OutletHumRat;
522 90942 : state.dataLoopNodes->Node(OutletNode).Enthalpy = state.dataMixerComponent->MixerCond(MixerNum).OutletEnthalpy;
523 90942 : state.dataLoopNodes->Node(OutletNode).Press = state.dataMixerComponent->MixerCond(MixerNum).OutletPressure;
524 : // Set the outlet nodes for properties that just pass through & not used
525 90942 : state.dataLoopNodes->Node(OutletNode).Quality = state.dataLoopNodes->Node(InletNode).Quality;
526 :
527 90942 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
528 0 : if (state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate > 0.0) {
529 : // CO2 balance to get outlet air CO2
530 0 : state.dataLoopNodes->Node(OutletNode).CO2 = 0.0;
531 0 : for (InletNodeNum = 1; InletNodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InletNodeNum) {
532 0 : state.dataLoopNodes->Node(OutletNode).CO2 +=
533 0 : state.dataLoopNodes->Node(state.dataMixerComponent->MixerCond(MixerNum).InletNode(InletNodeNum)).CO2 *
534 0 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(InletNodeNum) /
535 0 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate;
536 : }
537 : } else {
538 0 : state.dataLoopNodes->Node(OutletNode).CO2 = state.dataLoopNodes->Node(InletNode).CO2;
539 : }
540 : }
541 :
542 90942 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
543 0 : if (state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate > 0.0) {
544 : // Generic contaminant balance to get outlet air CO2
545 0 : state.dataLoopNodes->Node(OutletNode).GenContam = 0.0;
546 0 : for (InletNodeNum = 1; InletNodeNum <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InletNodeNum) {
547 0 : state.dataLoopNodes->Node(OutletNode).GenContam +=
548 0 : state.dataLoopNodes->Node(state.dataMixerComponent->MixerCond(MixerNum).InletNode(InletNodeNum)).GenContam *
549 0 : state.dataMixerComponent->MixerCond(MixerNum).InletMassFlowRate(InletNodeNum) /
550 0 : state.dataMixerComponent->MixerCond(MixerNum).OutletMassFlowRate;
551 : }
552 : } else {
553 0 : state.dataLoopNodes->Node(OutletNode).GenContam = state.dataLoopNodes->Node(InletNode).GenContam;
554 : }
555 : }
556 90942 : }
557 :
558 : // End of Update subroutines for the Mixer Module
559 : // *****************************************************************************
560 :
561 : // Beginning of Reporting subroutines for the Mixer Module
562 : // *****************************************************************************
563 :
564 90942 : void ReportMixer([[maybe_unused]] int const MixerNum)
565 : {
566 :
567 : // SUBROUTINE INFORMATION:
568 : // AUTHOR Richard J. Liesen
569 : // DATE WRITTEN March 2000
570 : // MODIFIED na
571 : // RE-ENGINEERED na
572 :
573 : // PURPOSE OF THIS SUBROUTINE:
574 : // This subroutine needs a description.
575 :
576 : // METHODOLOGY EMPLOYED:
577 : // Needs description, as appropriate.
578 :
579 : // REFERENCES:
580 : // na
581 :
582 : // USE STATEMENTS:
583 : // na
584 :
585 : // Locals
586 : // SUBROUTINE ARGUMENT DEFINITIONS:
587 :
588 : // SUBROUTINE PARAMETER DEFINITIONS:
589 : // na
590 :
591 : // INTERFACE BLOCK SPECIFICATIONS
592 : // na
593 :
594 : // DERIVED TYPE DEFINITIONS
595 : // na
596 :
597 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
598 : // na
599 :
600 : // Write(*,*)=MixerCond(MixerNum)%MixerPower Still needs to report the Mixer power from this component
601 90942 : }
602 :
603 : // End of Reporting subroutines for the Mixer Module
604 :
605 : // Beginning of Utility subroutines for the Mixer Component
606 : // *****************************************************************************
607 :
608 7 : void GetZoneMixerIndex(EnergyPlusData &state, std::string const &MixerName, int &MixerIndex, bool &ErrorsFound, std::string const &ThisObjectType)
609 : {
610 :
611 : // SUBROUTINE INFORMATION:
612 : // AUTHOR Fred Buhl
613 : // DATE WRITTEN March 2015
614 : // MODIFIED na
615 : // RE-ENGINEERED na
616 :
617 : // PURPOSE OF THIS SUBROUTINE:
618 : // This subroutine sets an index for a given zone mixer -- issues error message if that mixer
619 : // is not legal mixer.
620 :
621 7 : if (state.dataMixerComponent->GetZoneMixerIndexInputFlag) { // First time subroutine has been entered
622 4 : GetMixerInput(state);
623 4 : state.dataMixerComponent->GetZoneMixerIndexInputFlag = false;
624 : }
625 :
626 7 : MixerIndex = Util::FindItemInList(MixerName, state.dataMixerComponent->MixerCond, &MixerConditions::MixerName);
627 7 : if (MixerIndex == 0) {
628 1 : if (!ThisObjectType.empty()) {
629 1 : ShowSevereError(state, format("{}, GetZoneMixerIndex: Zone Mixer not found={}", ThisObjectType, MixerName));
630 : } else {
631 0 : ShowSevereError(state, format("GetZoneMixerIndex: Zone Mixer not found={}", MixerName));
632 : }
633 1 : ErrorsFound = true;
634 : }
635 7 : }
636 :
637 2 : int getZoneMixerIndexFromInletNode(EnergyPlusData &state, int const InNodeNum)
638 : {
639 :
640 2 : if (state.dataMixerComponent->GetZoneMixerIndexInputFlag) { // First time subroutine has been entered
641 2 : GetMixerInput(state);
642 2 : state.dataMixerComponent->GetZoneMixerIndexInputFlag = false;
643 : }
644 :
645 2 : if (state.dataMixerComponent->NumMixers > 0) {
646 4 : for (int MixerNum = 1; MixerNum <= state.dataMixerComponent->NumMixers; ++MixerNum) {
647 4 : for (int InNodeCtr = 1; InNodeCtr <= state.dataMixerComponent->MixerCond(MixerNum).NumInletNodes; ++InNodeCtr) {
648 2 : if (InNodeNum == state.dataMixerComponent->MixerCond(MixerNum).InletNode(InNodeCtr)) {
649 0 : return MixerNum;
650 : }
651 : }
652 : }
653 : }
654 :
655 2 : return 0;
656 : }
657 :
658 : // End of Utility subroutines for the Mixer Component
659 : // *****************************************************************************
660 :
661 : } // namespace EnergyPlus::MixerComponent
|