Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2023, 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 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Fmath.hh>
53 :
54 : // EnergyPlus Headers
55 : #include <AirflowNetwork/Solver.hpp>
56 : #include <EnergyPlus/Autosizing/SystemAirFlowSizing.hh>
57 : #include <EnergyPlus/BranchNodeConnections.hh>
58 : #include <EnergyPlus/CurveManager.hh>
59 : #include <EnergyPlus/Data/EnergyPlusData.hh>
60 : #include <EnergyPlus/DataContaminantBalance.hh>
61 : #include <EnergyPlus/DataEnvironment.hh>
62 : #include <EnergyPlus/DataHeatBalance.hh>
63 : #include <EnergyPlus/DataIPShortCuts.hh>
64 : #include <EnergyPlus/DataLoopNode.hh>
65 : #include <EnergyPlus/DataPrecisionGlobals.hh>
66 : #include <EnergyPlus/DataSizing.hh>
67 : #include <EnergyPlus/DataZoneEquipment.hh>
68 : #include <EnergyPlus/EMSManager.hh>
69 : #include <EnergyPlus/Fans.hh>
70 : #include <EnergyPlus/FaultsManager.hh>
71 : #include <EnergyPlus/GlobalNames.hh>
72 : #include <EnergyPlus/HVACFan.hh>
73 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
74 : #include <EnergyPlus/NodeInputManager.hh>
75 : #include <EnergyPlus/OutputProcessor.hh>
76 : #include <EnergyPlus/OutputReportPredefined.hh>
77 : #include <EnergyPlus/Psychrometrics.hh>
78 : #include <EnergyPlus/ScheduleManager.hh>
79 : #include <EnergyPlus/UtilityRoutines.hh>
80 :
81 : namespace EnergyPlus::Fans {
82 : // Module containing the fan simulation routines
83 :
84 : // MODULE INFORMATION:
85 : // AUTHOR Richard J. Liesen
86 : // DATE WRITTEN April 1998
87 : // MODIFIED Shirey, May 2001
88 : // Griffith, May 2009, EMS changes
89 : // Craig Wray 22Aug2010 Added Fan Component Model
90 : // RE-ENGINEERED na
91 :
92 : // PURPOSE OF THIS MODULE:
93 : // To encapsulate the data and algorithms required to
94 : // manage the Fan System Component
95 :
96 : // Using/Aliasing
97 : using namespace DataLoopNode;
98 : using DataHVACGlobals::cFanTypes;
99 : using DataHVACGlobals::FanType_ComponentModel;
100 : using DataHVACGlobals::FanType_SimpleConstVolume;
101 : using DataHVACGlobals::FanType_SimpleOnOff;
102 : using DataHVACGlobals::FanType_SimpleVAV;
103 : using DataHVACGlobals::FanType_ZoneExhaust;
104 : using DataHVACGlobals::FixedMin;
105 : using DataHVACGlobals::MinFrac;
106 : using DataHVACGlobals::SmallAirVolFlow;
107 : using EMSManager::ManageEMS;
108 : using Psychrometrics::PsyCpAirFnW;
109 : using Psychrometrics::PsyRhoAirFnPbTdbW;
110 : using Psychrometrics::PsyTdbFnHW;
111 : using namespace ScheduleManager;
112 :
113 : constexpr std::array<std::string_view, static_cast<int>(AvailabilityManagerCoupling::Num)> couplingsUC = {"COUPLED", "DECOUPLED"};
114 :
115 138406141 : void SimulateFanComponents(EnergyPlusData &state,
116 : std::string_view const CompName,
117 : bool const FirstHVACIteration,
118 : int &CompIndex,
119 : Optional<Real64 const> SpeedRatio,
120 : Optional_bool_const ZoneCompTurnFansOn, // Turn fans ON signal from ZoneHVAC component
121 : Optional_bool_const ZoneCompTurnFansOff, // Turn Fans OFF signal from ZoneHVAC component
122 : Optional<Real64 const> PressureRise // Pressure difference to use for DeltaPress
123 : )
124 : {
125 :
126 : // SUBROUTINE INFORMATION:
127 : // AUTHOR Richard Liesen
128 : // DATE WRITTEN February 1998
129 : // MODIFIED Chandan Sharma, March 2011 - FSEC: Added logic for ZoneHVAC sys avail managers
130 : // RE-ENGINEERED na
131 :
132 : // PURPOSE OF THIS SUBROUTINE:
133 : // This subroutine manages Fan component simulation.
134 :
135 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
136 : int FanNum; // current fan number
137 :
138 138406141 : auto &Fan(state.dataFans->Fan);
139 :
140 : // Obtains and Allocates fan related parameters from input file
141 138406141 : if (state.dataFans->GetFanInputFlag) { // First time subroutine has been entered
142 28 : GetFanInput(state);
143 28 : state.dataFans->GetFanInputFlag = false;
144 : }
145 :
146 138406141 : if (CompIndex == 0) {
147 951 : FanNum = UtilityRoutines::FindItemInList(CompName, Fan, &FanEquipConditions::FanName);
148 951 : if (FanNum == 0) {
149 0 : ShowFatalError(state, "SimulateFanComponents: Fan not found=" + std::string{CompName});
150 : }
151 951 : CompIndex = FanNum;
152 : } else {
153 138405190 : FanNum = CompIndex;
154 138405190 : if (FanNum > state.dataFans->NumFans || FanNum < 1) {
155 0 : ShowFatalError(
156 : state,
157 0 : format(
158 0 : "SimulateFanComponents: Invalid CompIndex passed={}, Number of Fans={}, Fan name={}", FanNum, state.dataFans->NumFans, CompName));
159 : }
160 138405190 : if (state.dataFans->CheckEquipName(FanNum)) {
161 1943 : if (!CompName.empty() && CompName != Fan(FanNum).FanName) {
162 0 : ShowFatalError(state,
163 0 : format("SimulateFanComponents: Invalid CompIndex passed={}, Fan name={}, stored Fan Name for that index={}",
164 : FanNum,
165 : CompName,
166 0 : Fan(FanNum).FanName));
167 : }
168 1943 : state.dataFans->CheckEquipName(FanNum) = false;
169 : }
170 : }
171 :
172 138406141 : state.dataFans->LocalTurnFansOn = false;
173 138406141 : state.dataFans->LocalTurnFansOff = false;
174 : // With the correct FanNum Initialize
175 138406141 : InitFan(state, FanNum, FirstHVACIteration); // Initialize all fan related parameters
176 :
177 138406141 : if (present(ZoneCompTurnFansOn) && present(ZoneCompTurnFansOff)) {
178 : // Set module-level logic flags equal to ZoneCompTurnFansOn and ZoneCompTurnFansOff values passed into this routine
179 : // for ZoneHVAC components with system availability managers defined.
180 : // The module-level flags get used in the other subroutines (e.g., SimSimpleFan,SimVariableVolumeFan and SimOnOffFan)
181 18797476 : state.dataFans->LocalTurnFansOn = ZoneCompTurnFansOn;
182 18797476 : state.dataFans->LocalTurnFansOff = ZoneCompTurnFansOff;
183 : } else {
184 : // Set module-level logic flags equal to the global LocalTurnFansOn and LocalTurnFansOff variables for all other cases.
185 119608665 : state.dataFans->LocalTurnFansOn = state.dataHVACGlobal->TurnFansOn;
186 119608665 : state.dataFans->LocalTurnFansOff = state.dataHVACGlobal->TurnFansOff;
187 : }
188 :
189 : // Calculate the Correct Fan Model with the current FanNum
190 138406141 : if (Fan(FanNum).FanType_Num == FanType_SimpleConstVolume) {
191 11873687 : SimSimpleFan(state, FanNum);
192 126532454 : } else if (Fan(FanNum).FanType_Num == FanType_SimpleVAV) {
193 17080494 : if (present(PressureRise)) {
194 28596 : SimVariableVolumeFan(state, FanNum, PressureRise);
195 : } else {
196 17051898 : SimVariableVolumeFan(state, FanNum);
197 : }
198 109451960 : } else if (Fan(FanNum).FanType_Num == FanType_SimpleOnOff) {
199 107762510 : SimOnOffFan(state, FanNum, SpeedRatio);
200 1689450 : } else if (Fan(FanNum).FanType_Num == FanType_ZoneExhaust) {
201 1632157 : SimZoneExhaustFan(state, FanNum);
202 57293 : } else if (Fan(FanNum).FanType_Num == FanType_ComponentModel) {
203 57293 : SimComponentModelFan(state, FanNum);
204 : }
205 :
206 : // Update the current fan to the outlet nodes
207 138406141 : UpdateFan(state, FanNum);
208 :
209 : // Report the current fan
210 138406141 : ReportFan(state, FanNum);
211 138406141 : }
212 :
213 : // Get Input Section of the Module
214 : //******************************************************************************
215 :
216 546 : void GetFanInput(EnergyPlusData &state)
217 : {
218 :
219 : // SUBROUTINE INFORMATION:
220 : // AUTHOR Richard Liesen
221 : // DATE WRITTEN April 1998
222 : // MODIFIED Shirey, May 2001
223 : // RE-ENGINEERED na
224 :
225 : // PURPOSE OF THIS SUBROUTINE:
226 : // Obtains input data for fans and stores it in fan data structures
227 :
228 : // Using/Aliasing
229 : using BranchNodeConnections::TestCompSet;
230 : using Curve::GetCurveIndex;
231 : using NodeInputManager::GetOnlySingleNode;
232 :
233 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
234 : int FanNum; // The fan that you are currently loading input into
235 : int NumSimpFan; // The number of Simple Const Vol Fans
236 : int NumVarVolFan; // The number of Simple Variable Vol Fans
237 : int NumOnOff; // The number of Simple on-off Fans
238 : int NumZoneExhFan;
239 : int SimpFanNum;
240 : int OnOffFanNum;
241 : int VarVolFanNum;
242 : int ExhFanNum;
243 : int NVPerfNum;
244 : bool NVPerfFanFound;
245 : int NumCompModelFan;
246 : int CompModelFanNum;
247 : int NumAlphas;
248 : int NumNums;
249 : int checkNum;
250 : int IOStat;
251 546 : bool ErrorsFound(false); // If errors detected in input
252 : static constexpr std::string_view RoutineName("GetFanInput: "); // include trailing blank space
253 1092 : Array1D_string cAlphaFieldNames;
254 1092 : Array1D_string cNumericFieldNames;
255 1092 : Array1D_bool lNumericFieldBlanks;
256 1092 : Array1D_bool lAlphaFieldBlanks;
257 1092 : Array1D_string cAlphaArgs;
258 1092 : Array1D<Real64> rNumericArgs;
259 1092 : std::string cCurrentModuleObject;
260 : int NumParams;
261 : int MaxAlphas;
262 : int MaxNumbers;
263 :
264 546 : auto &Fan(state.dataFans->Fan);
265 546 : auto &FanNumericFields(state.dataFans->FanNumericFields);
266 546 : auto &UniqueFanNames(state.dataFans->UniqueFanNames);
267 546 : auto &NightVentPerf(state.dataFans->NightVentPerf);
268 :
269 546 : state.dataFans->GetFanInputFlag = false;
270 :
271 546 : MaxAlphas = 0;
272 546 : MaxNumbers = 0;
273 546 : NumSimpFan = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Fan:ConstantVolume");
274 546 : if (NumSimpFan > 0) {
275 200 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Fan:ConstantVolume", NumParams, NumAlphas, NumNums);
276 200 : MaxAlphas = max(MaxAlphas, NumAlphas);
277 200 : MaxNumbers = max(MaxNumbers, NumNums);
278 : }
279 546 : NumVarVolFan = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Fan:VariableVolume");
280 546 : if (NumVarVolFan > 0) {
281 250 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Fan:VariableVolume", NumParams, NumAlphas, NumNums);
282 250 : MaxAlphas = max(MaxAlphas, NumAlphas);
283 250 : MaxNumbers = max(MaxNumbers, NumNums);
284 : }
285 546 : NumOnOff = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Fan:OnOff");
286 546 : if (NumOnOff > 0) {
287 167 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Fan:OnOff", NumParams, NumAlphas, NumNums);
288 167 : MaxAlphas = max(MaxAlphas, NumAlphas);
289 167 : MaxNumbers = max(MaxNumbers, NumNums);
290 : }
291 546 : NumZoneExhFan = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Fan:ZoneExhaust");
292 546 : if (NumZoneExhFan > 0) {
293 43 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Fan:ZoneExhaust", NumParams, NumAlphas, NumNums);
294 43 : MaxAlphas = max(MaxAlphas, NumAlphas);
295 43 : MaxNumbers = max(MaxNumbers, NumNums);
296 : }
297 546 : state.dataFans->NumNightVentPerf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "FanPerformance:NightVentilation");
298 546 : if (state.dataFans->NumNightVentPerf > 0) {
299 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "FanPerformance:NightVentilation", NumParams, NumAlphas, NumNums);
300 0 : MaxAlphas = max(MaxAlphas, NumAlphas);
301 0 : MaxNumbers = max(MaxNumbers, NumNums);
302 : }
303 :
304 546 : NumCompModelFan = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Fan:ComponentModel");
305 546 : if (NumCompModelFan > 0) {
306 4 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Fan:ComponentModel", NumParams, NumAlphas, NumNums);
307 4 : MaxAlphas = max(MaxAlphas, NumAlphas);
308 4 : MaxNumbers = max(MaxNumbers, NumNums);
309 : }
310 :
311 546 : cAlphaArgs.allocate(MaxAlphas);
312 546 : cAlphaFieldNames.allocate(MaxAlphas);
313 546 : lAlphaFieldBlanks.dimension(MaxAlphas, false);
314 546 : cNumericFieldNames.allocate(MaxNumbers);
315 546 : lNumericFieldBlanks.dimension(MaxNumbers, false);
316 546 : rNumericArgs.dimension(MaxNumbers, 0.0);
317 :
318 546 : state.dataFans->NumFans = NumSimpFan + NumVarVolFan + NumZoneExhFan + NumOnOff + NumCompModelFan;
319 546 : if (state.dataFans->NumFans > 0) {
320 546 : Fan.allocate(state.dataFans->NumFans);
321 546 : FanNumericFields.allocate(state.dataFans->NumFans);
322 546 : UniqueFanNames.reserve(state.dataFans->NumFans);
323 : }
324 546 : state.dataFans->CheckEquipName.dimension(state.dataFans->NumFans, true);
325 :
326 1050 : for (SimpFanNum = 1; SimpFanNum <= NumSimpFan; ++SimpFanNum) {
327 504 : FanNum = SimpFanNum;
328 504 : cCurrentModuleObject = "Fan:ConstantVolume";
329 504 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
330 : cCurrentModuleObject,
331 : SimpFanNum,
332 : cAlphaArgs,
333 : NumAlphas,
334 : rNumericArgs,
335 : NumNums,
336 : IOStat,
337 : lNumericFieldBlanks,
338 : lAlphaFieldBlanks,
339 : cAlphaFieldNames,
340 : cNumericFieldNames);
341 :
342 504 : FanNumericFields(FanNum).FieldNames.allocate(MaxNumbers);
343 504 : FanNumericFields(FanNum).FieldNames = "";
344 504 : FanNumericFields(FanNum).FieldNames = cNumericFieldNames;
345 :
346 504 : GlobalNames::VerifyUniqueInterObjectName(state, UniqueFanNames, cAlphaArgs(1), cCurrentModuleObject, cAlphaFieldNames(1), ErrorsFound);
347 504 : Fan(FanNum).FanName = cAlphaArgs(1);
348 504 : Fan(FanNum).FanType = cCurrentModuleObject;
349 504 : Fan(FanNum).AvailSchedName = cAlphaArgs(2);
350 504 : if (lAlphaFieldBlanks(2)) {
351 0 : Fan(FanNum).AvailSchedPtrNum = DataGlobalConstants::ScheduleAlwaysOn;
352 : } else {
353 504 : Fan(FanNum).AvailSchedPtrNum = GetScheduleIndex(state, cAlphaArgs(2));
354 504 : if (Fan(FanNum).AvailSchedPtrNum == 0) {
355 0 : ShowSevereError(state,
356 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(2) + " entered =" + cAlphaArgs(2) +
357 0 : " for " + cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
358 0 : ErrorsFound = true;
359 : }
360 : }
361 504 : Fan(FanNum).FanType_Num = FanType_SimpleConstVolume;
362 :
363 504 : Fan(FanNum).FanEff = rNumericArgs(1);
364 504 : Fan(FanNum).DeltaPress = rNumericArgs(2);
365 504 : Fan(FanNum).MaxAirFlowRate = rNumericArgs(3);
366 504 : if (Fan(FanNum).MaxAirFlowRate == 0.0) {
367 0 : ShowWarningError(state,
368 0 : cCurrentModuleObject + "=\"" + Fan(FanNum).FanName +
369 : "\" has specified 0.0 max air flow rate. It will not be used in the simulation.");
370 : }
371 504 : Fan(FanNum).MaxAirFlowRateIsAutosizable = true;
372 504 : Fan(FanNum).MotEff = rNumericArgs(4);
373 504 : Fan(FanNum).MotInAirFrac = rNumericArgs(5);
374 504 : Fan(FanNum).MinAirFlowRate = 0.0;
375 :
376 504 : Fan(FanNum).InletNodeNum = GetOnlySingleNode(state,
377 504 : cAlphaArgs(3),
378 : ErrorsFound,
379 : DataLoopNode::ConnectionObjectType::FanConstantVolume,
380 504 : cAlphaArgs(1),
381 : DataLoopNode::NodeFluidType::Air,
382 : DataLoopNode::ConnectionType::Inlet,
383 : NodeInputManager::CompFluidStream::Primary,
384 504 : ObjectIsNotParent);
385 504 : Fan(FanNum).OutletNodeNum = GetOnlySingleNode(state,
386 504 : cAlphaArgs(4),
387 : ErrorsFound,
388 : DataLoopNode::ConnectionObjectType::FanConstantVolume,
389 504 : cAlphaArgs(1),
390 : DataLoopNode::NodeFluidType::Air,
391 : DataLoopNode::ConnectionType::Outlet,
392 : NodeInputManager::CompFluidStream::Primary,
393 504 : ObjectIsNotParent);
394 :
395 504 : if (NumAlphas > 4) {
396 182 : Fan(FanNum).EndUseSubcategoryName = cAlphaArgs(5);
397 : } else {
398 322 : Fan(FanNum).EndUseSubcategoryName = "General";
399 : }
400 :
401 504 : TestCompSet(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(3), cAlphaArgs(4), "Air Nodes");
402 :
403 : } // end Number of Simple FAN Loop
404 :
405 968 : for (VarVolFanNum = 1; VarVolFanNum <= NumVarVolFan; ++VarVolFanNum) {
406 422 : FanNum = NumSimpFan + VarVolFanNum;
407 422 : cCurrentModuleObject = "Fan:VariableVolume";
408 422 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
409 : cCurrentModuleObject,
410 : VarVolFanNum,
411 : cAlphaArgs,
412 : NumAlphas,
413 : rNumericArgs,
414 : NumNums,
415 : IOStat,
416 : lNumericFieldBlanks,
417 : lAlphaFieldBlanks,
418 : cAlphaFieldNames,
419 : cNumericFieldNames);
420 :
421 422 : FanNumericFields(FanNum).FieldNames.allocate(MaxNumbers);
422 422 : FanNumericFields(FanNum).FieldNames = "";
423 422 : FanNumericFields(FanNum).FieldNames = cNumericFieldNames;
424 :
425 422 : GlobalNames::VerifyUniqueInterObjectName(state, UniqueFanNames, cAlphaArgs(1), cCurrentModuleObject, cAlphaFieldNames(1), ErrorsFound);
426 422 : Fan(FanNum).FanName = cAlphaArgs(1);
427 422 : Fan(FanNum).FanType = cCurrentModuleObject;
428 422 : Fan(FanNum).AvailSchedName = cAlphaArgs(2);
429 422 : if (lAlphaFieldBlanks(2)) {
430 0 : Fan(FanNum).AvailSchedPtrNum = DataGlobalConstants::ScheduleAlwaysOn;
431 : } else {
432 422 : Fan(FanNum).AvailSchedPtrNum = GetScheduleIndex(state, cAlphaArgs(2));
433 422 : if (Fan(FanNum).AvailSchedPtrNum == 0) {
434 0 : ShowSevereError(state,
435 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(2) + " entered =" + cAlphaArgs(2) +
436 0 : " for " + cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
437 0 : ErrorsFound = true;
438 : }
439 : }
440 422 : Fan(FanNum).FanType_Num = FanType_SimpleVAV;
441 :
442 422 : Fan(FanNum).FanEff = rNumericArgs(1);
443 422 : Fan(FanNum).DeltaPress = rNumericArgs(2);
444 422 : Fan(FanNum).MaxAirFlowRate = rNumericArgs(3);
445 422 : if (Fan(FanNum).MaxAirFlowRate == 0.0) {
446 0 : ShowWarningError(state,
447 0 : cCurrentModuleObject + "=\"" + Fan(FanNum).FanName +
448 : "\" has specified 0.0 max air flow rate. It will not be used in the simulation.");
449 : }
450 422 : Fan(FanNum).MaxAirFlowRateIsAutosizable = true;
451 422 : if (UtilityRoutines::SameString(cAlphaArgs(3), "Fraction")) {
452 254 : Fan(FanNum).FanMinAirFracMethod = MinFrac;
453 168 : } else if (UtilityRoutines::SameString(cAlphaArgs(3), "FixedFlowRate")) {
454 168 : Fan(FanNum).FanMinAirFracMethod = FixedMin;
455 : } else {
456 0 : ShowSevereError(state, cAlphaFieldNames(3) + " should be either Fraction or FixedFlowRate.");
457 0 : ShowContinueError(state, "Occurs in " + Fan(FanNum).FanName + " object.");
458 0 : ErrorsFound = true;
459 : }
460 : // Fan(FanNum)%MinAirFlowRate= rNumericArgs(4)
461 422 : Fan(FanNum).FanMinFrac = rNumericArgs(4);
462 422 : Fan(FanNum).FanFixedMin = rNumericArgs(5);
463 422 : Fan(FanNum).MotEff = rNumericArgs(6);
464 422 : Fan(FanNum).MotInAirFrac = rNumericArgs(7);
465 422 : Fan(FanNum).FanCoeff(1) = rNumericArgs(8);
466 422 : Fan(FanNum).FanCoeff(2) = rNumericArgs(9);
467 422 : Fan(FanNum).FanCoeff(3) = rNumericArgs(10);
468 422 : Fan(FanNum).FanCoeff(4) = rNumericArgs(11);
469 422 : Fan(FanNum).FanCoeff(5) = rNumericArgs(12);
470 422 : if (Fan(FanNum).FanCoeff(1) == 0.0 && Fan(FanNum).FanCoeff(2) == 0.0 && Fan(FanNum).FanCoeff(3) == 0.0 && Fan(FanNum).FanCoeff(4) == 0.0 &&
471 0 : Fan(FanNum).FanCoeff(5) == 0.0) {
472 0 : ShowWarningError(state, "Fan Coefficients are all zero. No Fan power will be reported.");
473 0 : ShowContinueError(state, "For " + cCurrentModuleObject + ", Fan=" + cAlphaArgs(1));
474 : }
475 422 : Fan(FanNum).InletNodeNum = GetOnlySingleNode(state,
476 422 : cAlphaArgs(4),
477 : ErrorsFound,
478 : DataLoopNode::ConnectionObjectType::FanVariableVolume,
479 422 : cAlphaArgs(1),
480 : DataLoopNode::NodeFluidType::Air,
481 : DataLoopNode::ConnectionType::Inlet,
482 : NodeInputManager::CompFluidStream::Primary,
483 422 : ObjectIsNotParent);
484 422 : Fan(FanNum).OutletNodeNum = GetOnlySingleNode(state,
485 422 : cAlphaArgs(5),
486 : ErrorsFound,
487 : DataLoopNode::ConnectionObjectType::FanVariableVolume,
488 422 : cAlphaArgs(1),
489 : DataLoopNode::NodeFluidType::Air,
490 : DataLoopNode::ConnectionType::Outlet,
491 : NodeInputManager::CompFluidStream::Primary,
492 422 : ObjectIsNotParent);
493 :
494 422 : if (NumAlphas > 5) {
495 180 : Fan(FanNum).EndUseSubcategoryName = cAlphaArgs(6);
496 : } else {
497 242 : Fan(FanNum).EndUseSubcategoryName = "General";
498 : }
499 :
500 422 : TestCompSet(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(4), cAlphaArgs(5), "Air Nodes");
501 :
502 : } // end Number of Variable Volume FAN Loop
503 :
504 687 : for (ExhFanNum = 1; ExhFanNum <= NumZoneExhFan; ++ExhFanNum) {
505 141 : FanNum = NumSimpFan + NumVarVolFan + ExhFanNum;
506 141 : cCurrentModuleObject = "Fan:ZoneExhaust";
507 141 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
508 : cCurrentModuleObject,
509 : ExhFanNum,
510 : cAlphaArgs,
511 : NumAlphas,
512 : rNumericArgs,
513 : NumNums,
514 : IOStat,
515 : lNumericFieldBlanks,
516 : lAlphaFieldBlanks,
517 : cAlphaFieldNames,
518 : cNumericFieldNames);
519 :
520 141 : FanNumericFields(FanNum).FieldNames.allocate(MaxNumbers);
521 141 : FanNumericFields(FanNum).FieldNames = "";
522 141 : FanNumericFields(FanNum).FieldNames = cNumericFieldNames;
523 :
524 141 : GlobalNames::VerifyUniqueInterObjectName(state, UniqueFanNames, cAlphaArgs(1), cCurrentModuleObject, cAlphaFieldNames(1), ErrorsFound);
525 141 : Fan(FanNum).FanName = cAlphaArgs(1);
526 141 : Fan(FanNum).FanType = cCurrentModuleObject;
527 141 : Fan(FanNum).AvailSchedName = cAlphaArgs(2);
528 141 : if (lAlphaFieldBlanks(2)) {
529 0 : Fan(FanNum).AvailSchedPtrNum = DataGlobalConstants::ScheduleAlwaysOn;
530 : } else {
531 141 : Fan(FanNum).AvailSchedPtrNum = GetScheduleIndex(state, cAlphaArgs(2));
532 141 : if (Fan(FanNum).AvailSchedPtrNum == 0) {
533 0 : ShowSevereError(state,
534 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(2) + " entered =" + cAlphaArgs(2) +
535 0 : " for " + cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
536 0 : ErrorsFound = true;
537 : } else {
538 141 : if (HasFractionalScheduleValue(state, Fan(FanNum).AvailSchedPtrNum)) {
539 0 : ShowWarningError(state,
540 0 : cCurrentModuleObject + "=\"" + Fan(FanNum).FanName + "\" has fractional values in Schedule=" + cAlphaArgs(2) +
541 : ". Only 0.0 in the schedule value turns the fan off.");
542 : }
543 : }
544 : }
545 141 : Fan(FanNum).FanType_Num = FanType_ZoneExhaust;
546 :
547 141 : Fan(FanNum).FanEff = rNumericArgs(1);
548 141 : Fan(FanNum).DeltaPress = rNumericArgs(2);
549 141 : Fan(FanNum).MaxAirFlowRate = rNumericArgs(3);
550 141 : Fan(FanNum).MaxAirFlowRateIsAutosizable = false;
551 141 : Fan(FanNum).MotEff = 1.0;
552 141 : Fan(FanNum).MotInAirFrac = 1.0;
553 141 : Fan(FanNum).MinAirFlowRate = 0.0;
554 141 : Fan(FanNum).RhoAirStdInit = state.dataEnvrn->StdRhoAir;
555 141 : Fan(FanNum).MaxAirMassFlowRate = Fan(FanNum).MaxAirFlowRate * Fan(FanNum).RhoAirStdInit;
556 :
557 141 : if (Fan(FanNum).MaxAirFlowRate == 0.0) {
558 0 : ShowWarningError(state,
559 0 : cCurrentModuleObject + "=\"" + Fan(FanNum).FanName +
560 : "\" has specified 0.0 max air flow rate. It will not be used in the simulation.");
561 : }
562 :
563 141 : Fan(FanNum).InletNodeNum = GetOnlySingleNode(state,
564 141 : cAlphaArgs(3),
565 : ErrorsFound,
566 : DataLoopNode::ConnectionObjectType::FanZoneExhaust,
567 141 : cAlphaArgs(1),
568 : DataLoopNode::NodeFluidType::Air,
569 : DataLoopNode::ConnectionType::Inlet,
570 : NodeInputManager::CompFluidStream::Primary,
571 141 : ObjectIsNotParent);
572 141 : Fan(FanNum).OutletNodeNum = GetOnlySingleNode(state,
573 141 : cAlphaArgs(4),
574 : ErrorsFound,
575 : DataLoopNode::ConnectionObjectType::FanZoneExhaust,
576 141 : cAlphaArgs(1),
577 : DataLoopNode::NodeFluidType::Air,
578 : DataLoopNode::ConnectionType::Outlet,
579 : NodeInputManager::CompFluidStream::Primary,
580 141 : ObjectIsNotParent);
581 :
582 141 : if (NumAlphas > 4 && !lAlphaFieldBlanks(5)) {
583 137 : Fan(FanNum).EndUseSubcategoryName = cAlphaArgs(5);
584 : } else {
585 4 : Fan(FanNum).EndUseSubcategoryName = "General";
586 : }
587 :
588 141 : if (NumAlphas > 5 && !lAlphaFieldBlanks(6)) {
589 0 : Fan(FanNum).FlowFractSchedNum = GetScheduleIndex(state, cAlphaArgs(6));
590 0 : if (Fan(FanNum).FlowFractSchedNum == 0) {
591 0 : ShowSevereError(state,
592 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(6) + " entered =" + cAlphaArgs(6) +
593 0 : " for " + cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
594 0 : ErrorsFound = true;
595 0 : } else if (Fan(FanNum).FlowFractSchedNum > 0) {
596 0 : if (!CheckScheduleValueMinMax(state, Fan(FanNum).FlowFractSchedNum, ">=", 0.0, "<=", 1.0)) {
597 0 : ShowSevereError(state,
598 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(6) + " for " +
599 0 : cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
600 0 : ShowContinueError(state, "Error found in " + cAlphaFieldNames(6) + " = " + cAlphaArgs(6));
601 0 : ShowContinueError(state, "Schedule values must be (>=0., <=1.)");
602 0 : ErrorsFound = true;
603 : }
604 : }
605 : } else {
606 141 : Fan(FanNum).FlowFractSchedNum = DataGlobalConstants::ScheduleAlwaysOn;
607 : }
608 :
609 141 : if (NumAlphas > 6 && !lAlphaFieldBlanks(7)) {
610 6 : Fan(FanNum).AvailManagerMode = static_cast<AvailabilityManagerCoupling>(getEnumerationValue(couplingsUC, cAlphaArgs(7)));
611 6 : if (Fan(FanNum).AvailManagerMode == AvailabilityManagerCoupling::Invalid) {
612 0 : ShowSevereError(state,
613 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(7) + " entered =" + cAlphaArgs(7) +
614 0 : " for " + cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
615 0 : ErrorsFound = true;
616 : }
617 : } else {
618 135 : Fan(FanNum).AvailManagerMode = AvailabilityManagerCoupling::Coupled;
619 : }
620 :
621 141 : if (NumAlphas > 7 && !lAlphaFieldBlanks(8)) {
622 0 : Fan(FanNum).MinTempLimitSchedNum = GetScheduleIndex(state, cAlphaArgs(8));
623 0 : if (Fan(FanNum).MinTempLimitSchedNum == 0) {
624 0 : ShowSevereError(state,
625 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(8) + " entered =" + cAlphaArgs(8) +
626 0 : " for " + cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
627 0 : ErrorsFound = true;
628 : }
629 : } else {
630 141 : Fan(FanNum).MinTempLimitSchedNum = 0;
631 : }
632 :
633 141 : if (NumAlphas > 8 && !lAlphaFieldBlanks(9)) {
634 :
635 32 : if (state.dataHeatBal->ZoneAirMassFlow.ZoneFlowAdjustment != DataHeatBalance::AdjustmentType::NoAdjustReturnAndMixing) {
636 : // do not include adjusted for "balanced" exhaust flow in the zone total return calculation
637 0 : ShowWarningError(state,
638 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(9) + " = " + cAlphaArgs(9) +
639 0 : " for " + cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
640 0 : ShowContinueError(state, "When zone air mass flow balance is enforced, this input field should be left blank.");
641 0 : ShowContinueError(state, "This schedule will be ignored in the simulation.");
642 0 : Fan(FanNum).BalancedFractSchedNum = 0;
643 : } else {
644 32 : Fan(FanNum).BalancedFractSchedNum = GetScheduleIndex(state, cAlphaArgs(9));
645 32 : if (Fan(FanNum).BalancedFractSchedNum == 0) {
646 0 : ShowSevereError(state,
647 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(9) +
648 0 : " entered =" + cAlphaArgs(9) + " for " + cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
649 0 : ErrorsFound = true;
650 32 : } else if (Fan(FanNum).BalancedFractSchedNum > 0) {
651 32 : if (!CheckScheduleValueMinMax(state, Fan(FanNum).BalancedFractSchedNum, ">=", 0.0, "<=", 1.0)) {
652 0 : ShowSevereError(state,
653 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(9) + " for " +
654 0 : cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
655 0 : ShowContinueError(state, "Error found in " + cAlphaFieldNames(9) + " = " + cAlphaArgs(9));
656 0 : ShowContinueError(state, "Schedule values must be (>=0., <=1.)");
657 0 : ErrorsFound = true;
658 : }
659 : }
660 : }
661 : } else {
662 109 : Fan(FanNum).BalancedFractSchedNum = 0;
663 : }
664 :
665 : } // end of Zone Exhaust Fan loop
666 :
667 1418 : for (OnOffFanNum = 1; OnOffFanNum <= NumOnOff; ++OnOffFanNum) {
668 872 : FanNum = NumSimpFan + NumVarVolFan + NumZoneExhFan + OnOffFanNum;
669 872 : cCurrentModuleObject = "Fan:OnOff";
670 872 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
671 : cCurrentModuleObject,
672 : OnOffFanNum,
673 : cAlphaArgs,
674 : NumAlphas,
675 : rNumericArgs,
676 : NumNums,
677 : IOStat,
678 : lNumericFieldBlanks,
679 : lAlphaFieldBlanks,
680 : cAlphaFieldNames,
681 : cNumericFieldNames);
682 :
683 872 : FanNumericFields(FanNum).FieldNames.allocate(MaxNumbers);
684 872 : FanNumericFields(FanNum).FieldNames = "";
685 872 : FanNumericFields(FanNum).FieldNames = cNumericFieldNames;
686 :
687 872 : GlobalNames::VerifyUniqueInterObjectName(state, UniqueFanNames, cAlphaArgs(1), cCurrentModuleObject, cAlphaFieldNames(1), ErrorsFound);
688 872 : Fan(FanNum).FanName = cAlphaArgs(1);
689 872 : Fan(FanNum).FanType = cCurrentModuleObject;
690 872 : Fan(FanNum).AvailSchedName = cAlphaArgs(2);
691 872 : if (lAlphaFieldBlanks(2)) {
692 0 : Fan(FanNum).AvailSchedPtrNum = DataGlobalConstants::ScheduleAlwaysOn;
693 : } else {
694 872 : Fan(FanNum).AvailSchedPtrNum = GetScheduleIndex(state, cAlphaArgs(2));
695 872 : if (Fan(FanNum).AvailSchedPtrNum == 0) {
696 0 : ShowSevereError(state,
697 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(2) + " entered =" + cAlphaArgs(2) +
698 0 : " for " + cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
699 0 : ErrorsFound = true;
700 : }
701 : }
702 872 : Fan(FanNum).FanType_Num = FanType_SimpleOnOff;
703 :
704 872 : Fan(FanNum).FanEff = rNumericArgs(1);
705 872 : Fan(FanNum).DeltaPress = rNumericArgs(2);
706 872 : Fan(FanNum).MaxAirFlowRate = rNumericArgs(3);
707 872 : if (Fan(FanNum).MaxAirFlowRate == 0.0) {
708 0 : ShowWarningError(state,
709 0 : cCurrentModuleObject + "=\"" + Fan(FanNum).FanName +
710 : "\" has specified 0.0 max air flow rate. It will not be used in the simulation.");
711 : }
712 872 : Fan(FanNum).MaxAirFlowRateIsAutosizable = true;
713 : // the following two structure variables are set here, as well as in InitFan, for the Heat Pump:Water Heater object
714 : // (Standard Rating procedure may be called before BeginEnvirFlag is set to TRUE, if so MaxAirMassFlowRate = 0)
715 872 : Fan(FanNum).RhoAirStdInit = state.dataEnvrn->StdRhoAir;
716 872 : Fan(FanNum).MaxAirMassFlowRate = Fan(FanNum).MaxAirFlowRate * Fan(FanNum).RhoAirStdInit;
717 :
718 872 : Fan(FanNum).MotEff = rNumericArgs(4);
719 872 : Fan(FanNum).MotInAirFrac = rNumericArgs(5);
720 872 : Fan(FanNum).MinAirFlowRate = 0.0;
721 :
722 872 : Fan(FanNum).InletNodeNum = GetOnlySingleNode(state,
723 872 : cAlphaArgs(3),
724 : ErrorsFound,
725 : DataLoopNode::ConnectionObjectType::FanOnOff,
726 872 : cAlphaArgs(1),
727 : DataLoopNode::NodeFluidType::Air,
728 : DataLoopNode::ConnectionType::Inlet,
729 : NodeInputManager::CompFluidStream::Primary,
730 872 : ObjectIsNotParent);
731 872 : Fan(FanNum).OutletNodeNum = GetOnlySingleNode(state,
732 872 : cAlphaArgs(4),
733 : ErrorsFound,
734 : DataLoopNode::ConnectionObjectType::FanOnOff,
735 872 : cAlphaArgs(1),
736 : DataLoopNode::NodeFluidType::Air,
737 : DataLoopNode::ConnectionType::Outlet,
738 : NodeInputManager::CompFluidStream::Primary,
739 872 : ObjectIsNotParent);
740 :
741 872 : if (NumAlphas > 4 && !lAlphaFieldBlanks(5)) {
742 25 : Fan(FanNum).FanPowerRatAtSpeedRatCurveIndex = GetCurveIndex(state, cAlphaArgs(5));
743 : }
744 :
745 872 : if (NumAlphas > 5 && !lAlphaFieldBlanks(6)) {
746 10 : Fan(FanNum).FanEffRatioCurveIndex = GetCurveIndex(state, cAlphaArgs(6));
747 : }
748 :
749 872 : if (NumAlphas > 6 && !lAlphaFieldBlanks(7)) {
750 383 : Fan(FanNum).EndUseSubcategoryName = cAlphaArgs(7);
751 : } else {
752 489 : Fan(FanNum).EndUseSubcategoryName = "General";
753 : }
754 :
755 872 : TestCompSet(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(3), cAlphaArgs(4), "Air Nodes");
756 :
757 : } // end Number of Simple ON-OFF FAN Loop
758 :
759 546 : cCurrentModuleObject = "FanPerformance:NightVentilation";
760 546 : state.dataFans->NumNightVentPerf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
761 :
762 546 : if (state.dataFans->NumNightVentPerf > 0) {
763 0 : NightVentPerf.allocate(state.dataFans->NumNightVentPerf);
764 0 : for (auto &e : NightVentPerf) {
765 0 : e.FanName.clear();
766 0 : e.FanEff = 0.0;
767 0 : e.DeltaPress = 0.0;
768 0 : e.MaxAirFlowRate = 0.0;
769 0 : e.MotEff = 0.0;
770 0 : e.MotInAirFrac = 0.0;
771 0 : e.MaxAirMassFlowRate = 0.0;
772 : }
773 : }
774 : // input the night ventilation performance objects
775 546 : for (NVPerfNum = 1; NVPerfNum <= state.dataFans->NumNightVentPerf; ++NVPerfNum) {
776 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
777 : cCurrentModuleObject,
778 : NVPerfNum,
779 : cAlphaArgs,
780 : NumAlphas,
781 : rNumericArgs,
782 : NumNums,
783 : IOStat,
784 : lNumericFieldBlanks,
785 : lAlphaFieldBlanks,
786 : cAlphaFieldNames,
787 : cNumericFieldNames);
788 0 : UtilityRoutines::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
789 0 : NightVentPerf(NVPerfNum).FanName = cAlphaArgs(1);
790 0 : NightVentPerf(NVPerfNum).FanEff = rNumericArgs(1);
791 0 : NightVentPerf(NVPerfNum).DeltaPress = rNumericArgs(2);
792 0 : NightVentPerf(NVPerfNum).MaxAirFlowRate = rNumericArgs(3);
793 0 : NightVentPerf(NVPerfNum).MotEff = rNumericArgs(4);
794 0 : NightVentPerf(NVPerfNum).MotInAirFrac = rNumericArgs(5);
795 : // find the corresponding fan
796 0 : NVPerfFanFound = false;
797 0 : for (FanNum = 1; FanNum <= state.dataFans->NumFans; ++FanNum) {
798 0 : if (NightVentPerf(NVPerfNum).FanName == Fan(FanNum).FanName) {
799 0 : NVPerfFanFound = true;
800 0 : Fan(FanNum).NVPerfNum = NVPerfNum;
801 0 : break;
802 : }
803 : }
804 0 : if (!NVPerfFanFound) {
805 0 : ShowSevereError(state, cCurrentModuleObject + ", fan name not found=" + cAlphaArgs(1));
806 0 : ErrorsFound = true;
807 : }
808 : }
809 :
810 550 : for (CompModelFanNum = 1; CompModelFanNum <= NumCompModelFan; ++CompModelFanNum) {
811 4 : FanNum = NumSimpFan + NumVarVolFan + NumZoneExhFan + NumOnOff + CompModelFanNum;
812 :
813 4 : cCurrentModuleObject = "Fan:ComponentModel";
814 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
815 : cCurrentModuleObject,
816 : CompModelFanNum,
817 : cAlphaArgs,
818 : NumAlphas,
819 : rNumericArgs,
820 : NumNums,
821 : IOStat,
822 : lNumericFieldBlanks,
823 : lAlphaFieldBlanks,
824 : cAlphaFieldNames,
825 : cNumericFieldNames);
826 :
827 4 : FanNumericFields(FanNum).FieldNames.allocate(MaxNumbers);
828 4 : FanNumericFields(FanNum).FieldNames = "";
829 4 : FanNumericFields(FanNum).FieldNames = cNumericFieldNames;
830 :
831 4 : GlobalNames::VerifyUniqueInterObjectName(state, UniqueFanNames, cAlphaArgs(1), cCurrentModuleObject, cAlphaFieldNames(1), ErrorsFound);
832 4 : Fan(FanNum).FanName = cAlphaArgs(1); // Fan name
833 4 : Fan(FanNum).FanType = cCurrentModuleObject;
834 :
835 4 : Fan(FanNum).InletNodeNum = GetOnlySingleNode(state,
836 4 : cAlphaArgs(2),
837 : ErrorsFound,
838 : DataLoopNode::ConnectionObjectType::FanComponentModel,
839 4 : cAlphaArgs(1),
840 : DataLoopNode::NodeFluidType::Air,
841 : DataLoopNode::ConnectionType::Inlet,
842 : NodeInputManager::CompFluidStream::Primary,
843 4 : ObjectIsNotParent); // Air inlet node name
844 4 : Fan(FanNum).OutletNodeNum = GetOnlySingleNode(state,
845 4 : cAlphaArgs(3),
846 : ErrorsFound,
847 : DataLoopNode::ConnectionObjectType::FanComponentModel,
848 4 : cAlphaArgs(1),
849 : DataLoopNode::NodeFluidType::Air,
850 : DataLoopNode::ConnectionType::Outlet,
851 : NodeInputManager::CompFluidStream::Primary,
852 4 : ObjectIsNotParent); // Air outlet node name
853 :
854 4 : TestCompSet(state, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(2), cAlphaArgs(3), "Air Nodes");
855 :
856 4 : Fan(FanNum).AvailSchedName = cAlphaArgs(4); // Availability schedule name
857 4 : if (lAlphaFieldBlanks(4)) {
858 0 : Fan(FanNum).AvailSchedPtrNum = 0;
859 : } else {
860 4 : Fan(FanNum).AvailSchedPtrNum = GetScheduleIndex(state, cAlphaArgs(4));
861 4 : if (Fan(FanNum).AvailSchedPtrNum == 0) {
862 0 : ShowSevereError(state,
863 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(4) + " entered =" + cAlphaArgs(4) +
864 0 : " for " + cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
865 0 : ErrorsFound = true;
866 : }
867 : }
868 :
869 4 : Fan(FanNum).FanType_Num = FanType_ComponentModel;
870 :
871 4 : Fan(FanNum).MaxAirFlowRate = rNumericArgs(1);
872 4 : if (Fan(FanNum).MaxAirFlowRate == 0.0) {
873 0 : ShowWarningError(state,
874 0 : cCurrentModuleObject + "=\"" + Fan(FanNum).FanName +
875 : "\" has specified 0.0 max air flow rate. It will not be used in the simulation.");
876 : }
877 4 : Fan(FanNum).MaxAirFlowRateIsAutosizable = true;
878 4 : Fan(FanNum).MinAirFlowRate = rNumericArgs(2);
879 :
880 4 : Fan(FanNum).FanSizingFactor = rNumericArgs(3); // Fan max airflow sizing factor [-]
881 4 : Fan(FanNum).FanWheelDia = rNumericArgs(4); // Fan wheel outer diameter [m]
882 4 : Fan(FanNum).FanOutletArea = rNumericArgs(5); // Fan outlet area [m2]
883 4 : Fan(FanNum).FanMaxEff = rNumericArgs(6); // Fan maximum static efficiency [-]
884 4 : Fan(FanNum).EuMaxEff = rNumericArgs(7); // Euler number at Fan maximum static efficiency [-]
885 4 : Fan(FanNum).FanMaxDimFlow = rNumericArgs(8); // Fan maximum dimensionless airflow [-]
886 4 : Fan(FanNum).PulleyDiaRatio = rNumericArgs(9); // Motor/fan pulley diameter ratio [-]
887 4 : Fan(FanNum).BeltMaxTorque = rNumericArgs(10); // Belt maximum torque [N-m, autosizable]
888 4 : Fan(FanNum).BeltSizingFactor = rNumericArgs(11); // Belt sizing factor [-]
889 4 : Fan(FanNum).BeltTorqueTrans = rNumericArgs(12); // Belt fractional torque transition Region 1-2 [-]
890 4 : Fan(FanNum).MotorMaxSpd = rNumericArgs(13); // Motor maximum speed [rpm]
891 4 : Fan(FanNum).MotorMaxOutPwr = rNumericArgs(14); // Motor maximum output power [W, autosizable]
892 4 : Fan(FanNum).MotorSizingFactor = rNumericArgs(15); // Motor sizing factor [-]
893 4 : Fan(FanNum).MotInAirFrac = rNumericArgs(16); // Fraction of fan and motor losses to airstream [-]
894 4 : Fan(FanNum).VFDEffType = cAlphaArgs(5); // VFD efficiency type [Speed or Power]
895 4 : Fan(FanNum).VFDMaxOutPwr = rNumericArgs(17); // VFD maximum output power [W, autosizable]
896 4 : Fan(FanNum).VFDSizingFactor = rNumericArgs(18); // VFD sizing factor [-]
897 4 : Fan(FanNum).PressRiseCurveIndex = GetCurveIndex(state, cAlphaArgs(6)); // Fan pressure rise curve
898 4 : Fan(FanNum).PressResetCurveIndex = GetCurveIndex(state, cAlphaArgs(7)); // Duct static pressure reset curve
899 4 : Fan(FanNum).PLFanEffNormCurveIndex = GetCurveIndex(state, cAlphaArgs(8)); // Fan part-load eff (normal) curve
900 4 : Fan(FanNum).PLFanEffStallCurveIndex = GetCurveIndex(state, cAlphaArgs(9)); // Fan part-load eff (stall) curve
901 4 : Fan(FanNum).DimFlowNormCurveIndex = GetCurveIndex(state, cAlphaArgs(10)); // Fan dim airflow (normal) curve
902 4 : Fan(FanNum).DimFlowStallCurveIndex = GetCurveIndex(state, cAlphaArgs(11)); // Fan dim airflow (stall) curve
903 4 : Fan(FanNum).BeltMaxEffCurveIndex = GetCurveIndex(state, cAlphaArgs(12)); // Belt max eff curve
904 4 : Fan(FanNum).PLBeltEffReg1CurveIndex = GetCurveIndex(state, cAlphaArgs(13)); // Belt part-load eff Region 1 curve
905 4 : Fan(FanNum).PLBeltEffReg2CurveIndex = GetCurveIndex(state, cAlphaArgs(14)); // Belt part-load eff Region 2 curve
906 4 : Fan(FanNum).PLBeltEffReg3CurveIndex = GetCurveIndex(state, cAlphaArgs(15)); // Belt part-load eff Region 3 curve
907 4 : Fan(FanNum).MotorMaxEffCurveIndex = GetCurveIndex(state, cAlphaArgs(16)); // Motor max eff curve
908 4 : Fan(FanNum).PLMotorEffCurveIndex = GetCurveIndex(state, cAlphaArgs(17)); // Motor part-load eff curve
909 4 : Fan(FanNum).VFDEffCurveIndex = GetCurveIndex(state, cAlphaArgs(18)); // VFD eff curve
910 :
911 4 : if (NumAlphas > 18) {
912 0 : Fan(FanNum).EndUseSubcategoryName = cAlphaArgs(19);
913 : } else {
914 4 : Fan(FanNum).EndUseSubcategoryName = "General";
915 : }
916 :
917 : } // end Number of Component Model FAN Loop
918 :
919 546 : cAlphaArgs.deallocate();
920 546 : cAlphaFieldNames.deallocate();
921 546 : lAlphaFieldBlanks.deallocate();
922 546 : cNumericFieldNames.deallocate();
923 546 : lNumericFieldBlanks.deallocate();
924 546 : rNumericArgs.deallocate();
925 :
926 : // Check Fans
927 2489 : for (FanNum = 1; FanNum <= state.dataFans->NumFans; ++FanNum) {
928 41375 : for (checkNum = FanNum + 1; checkNum <= state.dataFans->NumFans; ++checkNum) {
929 39432 : if (Fan(FanNum).InletNodeNum == Fan(checkNum).InletNodeNum) {
930 0 : ErrorsFound = true;
931 0 : ShowSevereError(state, "GetFanInput, duplicate fan inlet node names, must be unique for fans.");
932 0 : ShowContinueError(state,
933 0 : "Fan=" + Fan(FanNum).FanType + ':' + Fan(FanNum).FanName + " and Fan=" + Fan(checkNum).FanType + ':' +
934 0 : Fan(checkNum).FanName + '.');
935 0 : ShowContinueError(state, "Inlet Node Name=\"" + state.dataLoopNodes->NodeID(Fan(FanNum).InletNodeNum) + "\".");
936 : }
937 39432 : if (Fan(FanNum).OutletNodeNum == Fan(checkNum).OutletNodeNum) {
938 0 : ErrorsFound = true;
939 0 : ShowSevereError(state, "GetFanInput, duplicate fan outlet node names, must be unique for fans.");
940 0 : ShowContinueError(state,
941 0 : "Fan=" + Fan(FanNum).FanType + ':' + Fan(FanNum).FanName + " and Fan=" + Fan(checkNum).FanType + ':' +
942 0 : Fan(checkNum).FanName + '.');
943 0 : ShowContinueError(state, "Outlet Node Name=\"" + state.dataLoopNodes->NodeID(Fan(FanNum).OutletNodeNum) + "\".");
944 : }
945 : }
946 : }
947 :
948 546 : if (ErrorsFound) {
949 0 : ShowFatalError(state, std::string{RoutineName} + "Errors found in input. Program terminates.");
950 : }
951 :
952 2489 : for (FanNum = 1; FanNum <= state.dataFans->NumFans; ++FanNum) {
953 : // Setup Report variables for the Fans CurrentModuleObject='Fans'
954 7772 : SetupOutputVariable(state,
955 : "Fan Electricity Rate",
956 : OutputProcessor::Unit::W,
957 1943 : Fan(FanNum).FanPower,
958 : OutputProcessor::SOVTimeStepType::System,
959 : OutputProcessor::SOVStoreType::Average,
960 3886 : Fan(FanNum).FanName);
961 7772 : SetupOutputVariable(state,
962 : "Fan Rise in Air Temperature",
963 : OutputProcessor::Unit::deltaC,
964 1943 : Fan(FanNum).DeltaTemp,
965 : OutputProcessor::SOVTimeStepType::System,
966 : OutputProcessor::SOVStoreType::Average,
967 3886 : Fan(FanNum).FanName);
968 7772 : SetupOutputVariable(state,
969 : "Fan Heat Gain to Air",
970 : OutputProcessor::Unit::W,
971 1943 : Fan(FanNum).PowerLossToAir,
972 : OutputProcessor::SOVTimeStepType::System,
973 : OutputProcessor::SOVStoreType::Average,
974 3886 : Fan(FanNum).FanName);
975 9715 : SetupOutputVariable(state,
976 : "Fan Electricity Energy",
977 : OutputProcessor::Unit::J,
978 1943 : Fan(FanNum).FanEnergy,
979 : OutputProcessor::SOVTimeStepType::System,
980 : OutputProcessor::SOVStoreType::Summed,
981 1943 : Fan(FanNum).FanName,
982 : _,
983 : "Electricity",
984 : "Fans",
985 1943 : Fan(FanNum).EndUseSubcategoryName,
986 1943 : "System");
987 7772 : SetupOutputVariable(state,
988 : "Fan Air Mass Flow Rate",
989 : OutputProcessor::Unit::kg_s,
990 1943 : Fan(FanNum).OutletAirMassFlowRate,
991 : OutputProcessor::SOVTimeStepType::System,
992 : OutputProcessor::SOVStoreType::Average,
993 3886 : Fan(FanNum).FanName);
994 1943 : if ((Fan(FanNum).FanType_Num == FanType_ZoneExhaust) && (Fan(FanNum).BalancedFractSchedNum > 0)) {
995 128 : SetupOutputVariable(state,
996 : "Fan Unbalanced Air Mass Flow Rate",
997 : OutputProcessor::Unit::kg_s,
998 32 : Fan(FanNum).UnbalancedOutletMassFlowRate,
999 : OutputProcessor::SOVTimeStepType::System,
1000 : OutputProcessor::SOVStoreType::Average,
1001 64 : Fan(FanNum).FanName);
1002 128 : SetupOutputVariable(state,
1003 : "Fan Balanced Air Mass Flow Rate",
1004 : OutputProcessor::Unit::kg_s,
1005 32 : Fan(FanNum).BalancedOutletMassFlowRate,
1006 : OutputProcessor::SOVTimeStepType::System,
1007 : OutputProcessor::SOVStoreType::Average,
1008 64 : Fan(FanNum).FanName);
1009 : }
1010 :
1011 1943 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
1012 :
1013 638 : SetupEMSInternalVariable(state, "Fan Maximum Mass Flow Rate", Fan(FanNum).FanName, "[kg/s]", Fan(FanNum).MaxAirMassFlowRate);
1014 2552 : SetupEMSActuator(state,
1015 : "Fan",
1016 638 : Fan(FanNum).FanName,
1017 : "Fan Air Mass Flow Rate",
1018 : "[kg/s]",
1019 638 : Fan(FanNum).EMSMaxMassFlowOverrideOn,
1020 1914 : Fan(FanNum).EMSAirMassFlowValue);
1021 638 : SetupEMSInternalVariable(state, "Fan Nominal Pressure Rise", Fan(FanNum).FanName, "[Pa]", Fan(FanNum).DeltaPress);
1022 2552 : SetupEMSActuator(state,
1023 : "Fan",
1024 638 : Fan(FanNum).FanName,
1025 : "Fan Pressure Rise",
1026 : "[Pa]",
1027 638 : Fan(FanNum).EMSFanPressureOverrideOn,
1028 1914 : Fan(FanNum).EMSFanPressureValue);
1029 638 : SetupEMSInternalVariable(state, "Fan Nominal Total Efficiency", Fan(FanNum).FanName, "[fraction]", Fan(FanNum).FanEff);
1030 2552 : SetupEMSActuator(
1031 2552 : state, "Fan", Fan(FanNum).FanName, "Fan Total Efficiency", "[fraction]", Fan(FanNum).EMSFanEffOverrideOn, Fan(FanNum).EMSFanEffValue);
1032 :
1033 2552 : SetupEMSActuator(state,
1034 : "Fan",
1035 638 : Fan(FanNum).FanName,
1036 : "Fan Autosized Air Flow Rate",
1037 : "[m3/s]",
1038 638 : Fan(FanNum).MaxAirFlowRateEMSOverrideOn,
1039 1914 : Fan(FanNum).MaxAirFlowRateEMSOverrideValue);
1040 : }
1041 : }
1042 :
1043 1418 : for (OnOffFanNum = 1; OnOffFanNum <= NumOnOff; ++OnOffFanNum) {
1044 872 : FanNum = NumSimpFan + NumVarVolFan + NumZoneExhFan + OnOffFanNum;
1045 3488 : SetupOutputVariable(state,
1046 : "Fan Runtime Fraction",
1047 : OutputProcessor::Unit::None,
1048 872 : Fan(FanNum).FanRuntimeFraction,
1049 : OutputProcessor::SOVTimeStepType::System,
1050 : OutputProcessor::SOVStoreType::Average,
1051 1744 : Fan(FanNum).FanName);
1052 : }
1053 :
1054 : bool anyRan;
1055 546 : ManageEMS(state, EMSManager::EMSCallFrom::ComponentGetInput, anyRan, ObjexxFCL::Optional_int_const());
1056 546 : state.dataFans->MySizeFlag.dimension(state.dataFans->NumFans, true);
1057 546 : }
1058 :
1059 : // End of Get Input subroutines for the HB Module
1060 : //******************************************************************************
1061 :
1062 : // Beginning Initialization Section of the Module
1063 : //******************************************************************************
1064 :
1065 138406141 : void InitFan(EnergyPlusData &state,
1066 : int const FanNum,
1067 : [[maybe_unused]] bool const FirstHVACIteration // unused1208
1068 : )
1069 : {
1070 :
1071 : // SUBROUTINE INFORMATION:
1072 : // AUTHOR Richard J. Liesen
1073 : // DATE WRITTEN February 1998
1074 : // MODIFIED na
1075 : // RE-ENGINEERED na
1076 :
1077 : // PURPOSE OF THIS SUBROUTINE:
1078 : // This subroutine is for initializations of the Fan Components.
1079 :
1080 : // METHODOLOGY EMPLOYED:
1081 : // Uses the status flags to trigger initializations.
1082 :
1083 : // Using/Aliasing
1084 : using DataZoneEquipment::CheckZoneEquipmentList;
1085 :
1086 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1087 : int InletNode;
1088 : int OutletNode;
1089 : int OutNode;
1090 : int Loop;
1091 :
1092 138406141 : auto &Fan(state.dataFans->Fan);
1093 138406141 : auto &NightVentPerf(state.dataFans->NightVentPerf);
1094 :
1095 138406141 : if (state.dataFans->MyOneTimeFlag) {
1096 :
1097 546 : state.dataFans->MyEnvrnFlag.dimension(state.dataFans->NumFans, true);
1098 :
1099 546 : state.dataFans->MyOneTimeFlag = false;
1100 : }
1101 :
1102 : // need to check all fans to see if they are on Zone Equipment List or issue warning
1103 138406141 : if (!state.dataFans->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
1104 546 : state.dataFans->ZoneEquipmentListChecked = true;
1105 2489 : for (Loop = 1; Loop <= state.dataFans->NumFans; ++Loop) {
1106 1943 : if (!UtilityRoutines::SameString(Fan(Loop).FanType, "Fan:ZoneExhaust")) continue;
1107 141 : if (CheckZoneEquipmentList(state, Fan(Loop).FanType, Fan(Loop).FanName)) continue;
1108 0 : ShowSevereError(state,
1109 0 : "InitFans: Fan=[" + Fan(Loop).FanType + ',' + Fan(Loop).FanName +
1110 : "] is not on any ZoneHVAC:EquipmentList. It will not be simulated.");
1111 : }
1112 : }
1113 :
1114 138406141 : if (!state.dataGlobal->SysSizingCalc && state.dataFans->MySizeFlag(FanNum)) {
1115 :
1116 1942 : SizeFan(state, FanNum);
1117 : // Set the loop cycling flag
1118 1942 : if (Fan(FanNum).FanType_Num == FanType_SimpleOnOff) {
1119 872 : if (state.dataSize->CurSysNum > 0) {
1120 404 : state.dataAirLoop->AirLoopControlInfo(state.dataSize->CurSysNum).CyclingFan = true;
1121 : }
1122 : }
1123 :
1124 1942 : state.dataFans->MySizeFlag(FanNum) = false;
1125 : }
1126 :
1127 : // Do the Begin Environment initializations
1128 138406141 : if (state.dataGlobal->BeginEnvrnFlag && state.dataFans->MyEnvrnFlag(FanNum)) {
1129 :
1130 : // For all Fan inlet nodes convert the Volume flow to a mass flow
1131 : // unused0909 InNode = Fan(FanNum)%InletNodeNum
1132 12132 : OutNode = Fan(FanNum).OutletNodeNum;
1133 12132 : Fan(FanNum).RhoAirStdInit = state.dataEnvrn->StdRhoAir;
1134 :
1135 : // Change the Volume Flow Rates to Mass Flow Rates
1136 :
1137 12132 : Fan(FanNum).MaxAirMassFlowRate = Fan(FanNum).MaxAirFlowRate * Fan(FanNum).RhoAirStdInit;
1138 12132 : if (Fan(FanNum).FanMinAirFracMethod == MinFrac) {
1139 10854 : Fan(FanNum).MinAirFlowRate = Fan(FanNum).MaxAirFlowRate * Fan(FanNum).FanMinFrac;
1140 10854 : Fan(FanNum).MinAirMassFlowRate = Fan(FanNum).MinAirFlowRate * Fan(FanNum).RhoAirStdInit;
1141 1278 : } else if (Fan(FanNum).FanMinAirFracMethod == FixedMin) {
1142 1278 : Fan(FanNum).MinAirFlowRate = Fan(FanNum).FanFixedMin;
1143 1278 : Fan(FanNum).MinAirMassFlowRate = Fan(FanNum).MinAirFlowRate * Fan(FanNum).RhoAirStdInit;
1144 : }
1145 12132 : if (Fan(FanNum).NVPerfNum > 0) {
1146 0 : NightVentPerf(Fan(FanNum).NVPerfNum).MaxAirMassFlowRate = NightVentPerf(Fan(FanNum).NVPerfNum).MaxAirFlowRate * Fan(FanNum).RhoAirStdInit;
1147 : }
1148 :
1149 : // Init the Node Control variables
1150 12132 : state.dataLoopNodes->Node(OutNode).MassFlowRateMax = Fan(FanNum).MaxAirMassFlowRate;
1151 : // According to the IO Ref guide:
1152 : // "Note that this field is only used to calculate the fan power.
1153 : // This field does not enforce the system air flow rate during simulation"
1154 : // Node(OutNode).MassFlowRateMin = Fan(FanNum).MinAirMassFlowRate;
1155 :
1156 : // Initialize all report variables to a known state at beginning of simulation
1157 12132 : Fan(FanNum).FanPower = 0.0;
1158 12132 : Fan(FanNum).DeltaTemp = 0.0;
1159 12132 : Fan(FanNum).PowerLossToAir = 0.0;
1160 12132 : Fan(FanNum).FanEnergy = 0.0;
1161 :
1162 12132 : state.dataFans->MyEnvrnFlag(FanNum) = false;
1163 : }
1164 :
1165 138406141 : if (!state.dataGlobal->BeginEnvrnFlag) {
1166 138081715 : state.dataFans->MyEnvrnFlag(FanNum) = true;
1167 : }
1168 :
1169 : // Do the Begin Day initializations
1170 : // none
1171 :
1172 : // Do the begin HVAC time step initializations
1173 : // none
1174 :
1175 : // Do the following initializations (every time step): This should be the info from
1176 : // the previous components outlets or the node data in this section.
1177 :
1178 : // Do a check and make sure that the max and min available(control) flow is
1179 : // between the physical max and min for the Fan while operating.
1180 :
1181 138406141 : InletNode = Fan(FanNum).InletNodeNum;
1182 138406141 : OutletNode = Fan(FanNum).OutletNodeNum;
1183 :
1184 138406141 : Fan(FanNum).MassFlowRateMaxAvail =
1185 138406141 : min(state.dataLoopNodes->Node(OutletNode).MassFlowRateMax, state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail);
1186 138406141 : Fan(FanNum).MassFlowRateMinAvail =
1187 138406141 : min(max(state.dataLoopNodes->Node(OutletNode).MassFlowRateMin, state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail),
1188 138406141 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail);
1189 :
1190 : // Load the node data in this section for the component simulation
1191 : // First need to make sure that the MassFlowRate is between the max and min avail.
1192 138406141 : if (Fan(FanNum).FanType_Num != FanType_ZoneExhaust) {
1193 136773984 : Fan(FanNum).InletAirMassFlowRate = min(state.dataLoopNodes->Node(InletNode).MassFlowRate, Fan(FanNum).MassFlowRateMaxAvail);
1194 136773984 : Fan(FanNum).InletAirMassFlowRate = max(Fan(FanNum).InletAirMassFlowRate, Fan(FanNum).MassFlowRateMinAvail);
1195 : } else { // zone exhaust fans
1196 1632157 : Fan(FanNum).MassFlowRateMaxAvail = Fan(FanNum).MaxAirMassFlowRate;
1197 1632157 : Fan(FanNum).MassFlowRateMinAvail = 0.0;
1198 1632157 : if (Fan(FanNum).FlowFractSchedNum > 0) { // modulate flow
1199 0 : Fan(FanNum).InletAirMassFlowRate = Fan(FanNum).MassFlowRateMaxAvail * GetCurrentScheduleValue(state, Fan(FanNum).FlowFractSchedNum);
1200 0 : Fan(FanNum).InletAirMassFlowRate = max(0.0, Fan(FanNum).InletAirMassFlowRate);
1201 : } else { // always run at max
1202 1632157 : Fan(FanNum).InletAirMassFlowRate = Fan(FanNum).MassFlowRateMaxAvail;
1203 : }
1204 1632157 : if (Fan(FanNum).EMSMaxMassFlowOverrideOn)
1205 0 : Fan(FanNum).InletAirMassFlowRate = min(Fan(FanNum).EMSAirMassFlowValue, Fan(FanNum).MassFlowRateMaxAvail);
1206 : }
1207 :
1208 : // Then set the other conditions
1209 138406141 : Fan(FanNum).InletAirTemp = state.dataLoopNodes->Node(InletNode).Temp;
1210 138406141 : Fan(FanNum).InletAirHumRat = state.dataLoopNodes->Node(InletNode).HumRat;
1211 138406141 : Fan(FanNum).InletAirEnthalpy = state.dataLoopNodes->Node(InletNode).Enthalpy;
1212 138406141 : }
1213 :
1214 1943 : void SizeFan(EnergyPlusData &state, int const FanNum)
1215 : {
1216 :
1217 : // SUBROUTINE INFORMATION:
1218 : // AUTHOR Fred Buhl
1219 : // DATE WRITTEN September 2001
1220 : // MODIFIED Craig Wray August 2010 - added fan, belt, motor, and VFD component sizing
1221 : // August 2013 Daeho Kang, add component sizing table entries
1222 : // RE-ENGINEERED na
1223 :
1224 : // PURPOSE OF THIS SUBROUTINE:
1225 : // This subroutine is for sizing fans for which flow rates have not been
1226 : // specified in the input, or when fan component sizes have not been specified
1227 :
1228 : // METHODOLOGY EMPLOYED:
1229 : // Obtains flow rates from the zone or system sizing arrays.
1230 :
1231 : // Using/Aliasing
1232 : using namespace DataSizing;
1233 : using namespace OutputReportPredefined;
1234 : using Curve::CurveValue;
1235 : using Curve::GetCurveIndex;
1236 :
1237 : // SUBROUTINE PARAMETER DEFINITIONS:
1238 : static constexpr std::string_view RoutineName("SizeFan: "); // include trailing blank space
1239 :
1240 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1241 : int NVPerfNum; // Index to night ventialation performance object
1242 3886 : std::string equipName; // Equipment name
1243 : Real64 RatedPower; // Rated fan power [W]
1244 : Real64 RhoAir; // Air density [kg/m3]
1245 : Real64 FanVolFlow; // Fan volumetric airflow [m3/s]
1246 : Real64 DuctStaticPress; // Duct static pressure setpoint [Pa]
1247 : Real64 DeltaPressTot; // Total pressure rise across fan [N/m2 = Pa]
1248 : Real64 FanOutletVelPress; // Fan outlet velocity pressure [Pa]
1249 : Real64 EulerNum; // Fan Euler number [-]
1250 : Real64 NormalizedEulerNum; // Normalized Fan Euler number [-]
1251 : Real64 FanDimFlow; // Fan dimensionless airflow [-]
1252 : Real64 FanSpdRadS; // Fan shaft rotational speed [rad/s]
1253 : Real64 MotorSpeed; // Motor shaft rotational speed [rpm]
1254 : Real64 XbeltMax; // Factor for belt max eff curve [ln hp]
1255 : Real64 FanTrqRatio; // Ratio of fan torque to max fan torque [-]
1256 : Real64 BeltPLEff; // Belt normalized (part-load) efficiency [-]
1257 : Real64 XmotorMax; // Factor for motor max eff curve [ln hp]
1258 : Real64 MotorOutPwrRatio; // Ratio of motor output power to max motor output power [-]
1259 : Real64 MotorPLEff; // Motor normalized (part-load) efficiency [-]
1260 1943 : Real64 VFDSpdRatio(0.0); // Ratio of motor speed to motor max speed [-]
1261 1943 : Real64 VFDOutPwrRatio(0.0); // Ratio of VFD output power to max VFD output power [-]
1262 3886 : std::string CompName; // component name
1263 3886 : std::string CompType; // component type
1264 3886 : std::string SizingString; // input field sizing description (e.g., Nominal Capacity)
1265 1943 : bool bPRINT = true; // TRUE if sizing is reported to output (eio)
1266 : Real64 TempFlow; // autosized flow rate of fan [m3/s]
1267 1943 : int FieldNum = 2; // IDD numeric field number where input field description is found
1268 1943 : int NumFansSized = 0; // counter used to deallocate temporary string array after all fans have been sized
1269 :
1270 1943 : auto &Fan(state.dataFans->Fan);
1271 1943 : auto &FanNumericFields(state.dataFans->FanNumericFields);
1272 1943 : auto &NightVentPerf(state.dataFans->NightVentPerf);
1273 :
1274 1943 : if (Fan(FanNum).FanType_Num == FanType_ComponentModel) {
1275 4 : FieldNum = 1;
1276 : } else {
1277 1939 : FieldNum = 3;
1278 : }
1279 1943 : SizingString = FanNumericFields(FanNum).FieldNames(FieldNum) + " [m3/s]";
1280 :
1281 1943 : TempFlow = Fan(FanNum).MaxAirFlowRate;
1282 1943 : state.dataSize->DataAutosizable = Fan(FanNum).MaxAirFlowRateIsAutosizable;
1283 1943 : CompType = Fan(FanNum).FanType;
1284 1943 : CompName = Fan(FanNum).FanName;
1285 1943 : state.dataSize->DataEMSOverrideON = Fan(FanNum).MaxAirFlowRateEMSOverrideOn;
1286 1943 : state.dataSize->DataEMSOverride = Fan(FanNum).MaxAirFlowRateEMSOverrideValue;
1287 :
1288 1943 : bool errorsFound = false;
1289 3886 : SystemAirFlowSizer sizerSystemAirFlow;
1290 1943 : sizerSystemAirFlow.overrideSizingString(SizingString);
1291 1943 : sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
1292 1943 : Fan(FanNum).MaxAirFlowRate = sizerSystemAirFlow.size(state, TempFlow, errorsFound);
1293 :
1294 1943 : state.dataSize->DataAutosizable = true;
1295 1943 : state.dataSize->DataEMSOverrideON = false;
1296 1943 : state.dataSize->DataEMSOverride = 0.0;
1297 :
1298 1943 : FanVolFlow = Fan(FanNum).MaxAirFlowRate; // Maximum volumetric airflow through fan [m3/s at standard conditions]
1299 1943 : if (Fan(FanNum).FanType_Num == FanType_ComponentModel) {
1300 : // Get air density at standard conditions and get mass airflow through fan
1301 : // From WeatherManager:
1302 : // StdBaroPress=(101.325d0*(1.0d0-2.25577d-05*WeatherFileElevation)**5.2559d0)*1000.d0
1303 : // StdRhoAir=PsyRhoAirFnPbTdbW(StdBaroPress,20,0)
1304 : // From PsychRoutines:
1305 : // w=MAX(dw,1.0d-5)
1306 : // rhoair = pb/(287.d0*(tdb+DataGlobalConstants::KelvinConv())*(1.0d0+1.6077687d0*w))
1307 4 : RhoAir = state.dataEnvrn->StdRhoAir;
1308 :
1309 : // Adjust max fan volumetric airflow using fan sizing factor
1310 4 : FanVolFlow *= Fan(FanNum).FanSizingFactor; //[m3/s at standard conditions]
1311 :
1312 : // Calculate max fan static pressure rise using max fan volumetric flow, std air density, air-handling system characteristics,
1313 : // and Sherman-Wray system curve model (assumes static pressure surrounding air distribution system is zero)
1314 4 : DuctStaticPress = CurveValue(state, Fan(FanNum).PressResetCurveIndex, FanVolFlow); // Duct static pressure setpoint [Pa]
1315 4 : DeltaPressTot = CurveValue(state, Fan(FanNum).PressRiseCurveIndex, FanVolFlow, DuctStaticPress); // Max fan total pressure rise [Pa]
1316 4 : FanOutletVelPress = 0.5 * RhoAir * pow_2(FanVolFlow / Fan(FanNum).FanOutletArea); // Max fan outlet velocity pressure [Pa]
1317 : // Outlet velocity pressure cannot exceed total pressure rise
1318 4 : FanOutletVelPress = min(FanOutletVelPress, DeltaPressTot);
1319 4 : Fan(FanNum).DeltaPress = DeltaPressTot - FanOutletVelPress; // Max fan static pressure rise [Pa]
1320 :
1321 : // Calculate max fan air power using volumetric flow abd corresponding fan static pressure rise
1322 4 : Fan(FanNum).FanAirPower = FanVolFlow * Fan(FanNum).DeltaPress; //[W]
1323 :
1324 : // Calculate fan wheel efficiency at max fan volumetric flow and corresponding fan static pressure rise,
1325 : // using fan characteristics and Wray dimensionless fan static efficiency model
1326 4 : EulerNum = (Fan(FanNum).DeltaPress * pow_4(Fan(FanNum).FanWheelDia)) / (RhoAir * pow_2(FanVolFlow)); //[-]
1327 4 : NormalizedEulerNum = std::log10(EulerNum / Fan(FanNum).EuMaxEff);
1328 4 : if (NormalizedEulerNum <= 0.0) {
1329 3 : Fan(FanNum).FanWheelEff = CurveValue(state, Fan(FanNum).PLFanEffNormCurveIndex, NormalizedEulerNum);
1330 : } else {
1331 1 : Fan(FanNum).FanWheelEff = CurveValue(state, Fan(FanNum).PLFanEffStallCurveIndex, NormalizedEulerNum);
1332 : }
1333 4 : Fan(FanNum).FanWheelEff *= Fan(FanNum).FanMaxEff; // [-]
1334 4 : Fan(FanNum).FanWheelEff = max(Fan(FanNum).FanWheelEff, 0.01); // Minimum efficiency is 1% to avoid numerical errors
1335 :
1336 : // Calculate max fan shaft power using fan air power and fan efficiency
1337 : // at max fan static pressure rise and max fan volumetric flow
1338 4 : Fan(FanNum).FanShaftPower = (Fan(FanNum).FanAirPower / Fan(FanNum).FanWheelEff); //[W]
1339 4 : Fan(FanNum).FanShaftPwrMax = Fan(FanNum).FanShaftPower; //[W]
1340 :
1341 : // Calculate fan shaft speed, motor speed, and fan torque using Wray dimensionless fan airflow model
1342 4 : if (NormalizedEulerNum <= 0.0) {
1343 3 : FanDimFlow = CurveValue(state, Fan(FanNum).DimFlowNormCurveIndex, NormalizedEulerNum); //[-]
1344 : } else {
1345 1 : FanDimFlow = CurveValue(state, Fan(FanNum).DimFlowStallCurveIndex, NormalizedEulerNum); //[-]
1346 : }
1347 4 : FanSpdRadS = FanVolFlow / (FanDimFlow * Fan(FanNum).FanMaxDimFlow * pow_3(Fan(FanNum).FanWheelDia)); //[rad/s]
1348 4 : Fan(FanNum).FanSpd = FanSpdRadS * 9.549296586; //[rpm, conversion factor is 30/PI]
1349 :
1350 4 : if (Fan(FanNum).PulleyDiaRatio == AutoSize) {
1351 : // WRITE(*,*) 'Autosizing pulley drive ratio'
1352 4 : Fan(FanNum).PulleyDiaRatio = Fan(FanNum).FanSpd / Fan(FanNum).MotorMaxSpd; //[-]
1353 : }
1354 :
1355 : // For direct-drive, should have PulleyDiaRatio = 1
1356 4 : MotorSpeed = Fan(FanNum).FanSpd / Fan(FanNum).PulleyDiaRatio; //[rpm]
1357 :
1358 : // Check for inconsistent drive ratio and motor speed, and report design fan speed with warning
1359 4 : if (MotorSpeed > (Fan(FanNum).MotorMaxSpd + 1.e-5)) {
1360 0 : ShowWarningError(state,
1361 0 : "Drive ratio for " + Fan(FanNum).FanType + ": " + Fan(FanNum).FanName +
1362 : " is too low at design conditions -- check motor speed and drive ratio inputs");
1363 0 : ShowContinueError(state, format("...Design fan speed [rev/min]: {:.2R}", Fan(FanNum).FanSpd));
1364 : }
1365 :
1366 4 : Fan(FanNum).FanTrq = Fan(FanNum).FanShaftPower / FanSpdRadS; //[N-m]
1367 :
1368 4 : if (Fan(FanNum).BeltMaxTorque == AutoSize) {
1369 : // WRITE(*,*) 'Autosizing fan belt'
1370 4 : Fan(FanNum).BeltMaxTorque = Fan(FanNum).FanTrq; //[N-m]
1371 : }
1372 : // Adjust max belt torque using belt sizing factor
1373 4 : Fan(FanNum).BeltMaxTorque *= Fan(FanNum).BeltSizingFactor; //[N-m]
1374 :
1375 : // Check for undersized belt and report design size with warning
1376 4 : if (Fan(FanNum).FanTrq > (Fan(FanNum).BeltMaxTorque + 1.e-5)) {
1377 0 : ShowWarningError(
1378 0 : state, "Belt for " + Fan(FanNum).FanType + ": " + Fan(FanNum).FanName + " is undersized at design conditions -- check belt inputs");
1379 0 : ShowContinueError(state, format("...Design belt output torque (without oversizing) [Nm]: {:.2R}", Fan(FanNum).FanTrq));
1380 : }
1381 :
1382 : // Calculate belt max efficiency using correlations and coefficients based on AMCA data
1383 : // Direct-drive is represented using curve coefficients such that "belt" max eff and PL eff = 1.0
1384 4 : XbeltMax = std::log(Fan(FanNum).FanShaftPwrMax / 746.0); // Natural log of belt output power in hp
1385 4 : if (Fan(FanNum).BeltMaxEffCurveIndex != 0) {
1386 4 : Fan(FanNum).BeltMaxEff = std::exp(CurveValue(state, Fan(FanNum).BeltMaxEffCurveIndex, XbeltMax)); //[-]
1387 : } else {
1388 0 : Fan(FanNum).BeltMaxEff = 1.0; // No curve specified - use constant efficiency
1389 : }
1390 :
1391 : // Calculate belt part-load drive efficiency and input power using correlations and coefficients based on ACEEE data
1392 4 : FanTrqRatio = Fan(FanNum).FanTrq / Fan(FanNum).BeltMaxTorque; //[-]
1393 4 : if ((FanTrqRatio <= Fan(FanNum).BeltTorqueTrans) && (Fan(FanNum).PLBeltEffReg1CurveIndex != 0)) {
1394 0 : BeltPLEff = CurveValue(state, Fan(FanNum).PLBeltEffReg1CurveIndex, FanTrqRatio); //[-]
1395 : } else {
1396 4 : if ((FanTrqRatio > Fan(FanNum).BeltTorqueTrans) && (FanTrqRatio <= 1.0) && (Fan(FanNum).PLBeltEffReg2CurveIndex != 0)) {
1397 4 : BeltPLEff = CurveValue(state, Fan(FanNum).PLBeltEffReg2CurveIndex, FanTrqRatio); //[-]
1398 : } else {
1399 0 : if ((FanTrqRatio > 1.0) && (Fan(FanNum).PLBeltEffReg3CurveIndex != 0)) {
1400 0 : BeltPLEff = CurveValue(state, Fan(FanNum).PLBeltEffReg3CurveIndex, FanTrqRatio); //[-]
1401 : } else {
1402 0 : BeltPLEff = 1.0; // Direct drive or no curve specified - use constant efficiency
1403 : }
1404 : }
1405 : }
1406 4 : Fan(FanNum).BeltEff = Fan(FanNum).BeltMaxEff * BeltPLEff; //[-]
1407 4 : Fan(FanNum).BeltEff = max(Fan(FanNum).BeltEff, 0.01); // Minimum efficiency is 1% to avoid numerical errors
1408 4 : Fan(FanNum).BeltInputPower = Fan(FanNum).FanShaftPower / Fan(FanNum).BeltEff; //[W]
1409 :
1410 4 : if (Fan(FanNum).MotorMaxOutPwr == AutoSize) {
1411 : // WRITE(*,*) 'Autosizing fan motor'
1412 4 : Fan(FanNum).MotorMaxOutPwr = Fan(FanNum).BeltInputPower;
1413 : }
1414 : // Adjust max motor output power using motor sizing factor
1415 4 : Fan(FanNum).MotorMaxOutPwr *= Fan(FanNum).MotorSizingFactor; //[W]
1416 :
1417 : // Check for undersized motor and report design size with warning
1418 4 : if (Fan(FanNum).BeltInputPower > (Fan(FanNum).MotorMaxOutPwr + 1.e-5)) {
1419 0 : ShowWarningError(
1420 0 : state, "Motor for " + Fan(FanNum).FanType + ": " + Fan(FanNum).FanName + " is undersized at design conditions -- check motor inputs");
1421 0 : ShowContinueError(state, format("...Design motor output power (without oversizing) [W]: {:.2R}", Fan(FanNum).BeltInputPower));
1422 : }
1423 :
1424 : // Calculate motor max efficiency using correlations and coefficients based on MotorMaster+ data
1425 4 : XmotorMax = std::log(Fan(FanNum).MotorMaxOutPwr / 746.0); // Natural log of motor output power in hp
1426 4 : if (Fan(FanNum).MotorMaxEffCurveIndex != 0) {
1427 4 : Fan(FanNum).MotorMaxEff = CurveValue(state, Fan(FanNum).MotorMaxEffCurveIndex, XmotorMax); //[-]
1428 : } else {
1429 0 : Fan(FanNum).MotorMaxEff = 1.0; // No curve specified - use constant efficiency
1430 : }
1431 :
1432 : // Calculate motor part-load efficiency and input power using correlations and coefficients based on MotorMaster+ data
1433 4 : MotorOutPwrRatio = Fan(FanNum).BeltInputPower / Fan(FanNum).MotorMaxOutPwr; //[-]
1434 4 : if (Fan(FanNum).PLMotorEffCurveIndex != 0) {
1435 4 : MotorPLEff = CurveValue(state, Fan(FanNum).PLMotorEffCurveIndex, MotorOutPwrRatio); //[-]
1436 : } else {
1437 0 : MotorPLEff = 1.0; // No curve specified - use constant efficiency
1438 : }
1439 4 : Fan(FanNum).MotEff = Fan(FanNum).MotorMaxEff * MotorPLEff; //[-]
1440 4 : Fan(FanNum).MotEff = max(Fan(FanNum).MotEff, 0.01); // Minimum efficiency is 1% to avoid numerical errors
1441 :
1442 : // Calculate motor input power using belt input power and motor efficiency
1443 4 : Fan(FanNum).MotorInputPower = Fan(FanNum).BeltInputPower / Fan(FanNum).MotEff; //[W]
1444 :
1445 : // Calculate max VFD efficiency and input power using correlations and coefficients based on VFD type
1446 4 : if ((Fan(FanNum).VFDEffType == "SPEED") && (Fan(FanNum).VFDEffCurveIndex != 0)) {
1447 0 : VFDSpdRatio = MotorSpeed / Fan(FanNum).MotorMaxSpd; //[-]
1448 0 : Fan(FanNum).VFDEff = CurveValue(state, Fan(FanNum).VFDEffCurveIndex, VFDSpdRatio); //[-]
1449 : } else {
1450 4 : if ((Fan(FanNum).VFDEffType == "POWER") && (Fan(FanNum).VFDEffCurveIndex != 0)) {
1451 4 : if (Fan(FanNum).VFDMaxOutPwr == AutoSize) {
1452 : // WRITE(*,*) 'Autosizing fan VFD'
1453 4 : Fan(FanNum).VFDMaxOutPwr = Fan(FanNum).MotorInputPower;
1454 : }
1455 : // Adjust max VFD output power using VFD sizing factor
1456 4 : Fan(FanNum).VFDMaxOutPwr *= Fan(FanNum).VFDSizingFactor; //[W]
1457 :
1458 : // Check for undersized VFD and report design size with warning
1459 4 : if (Fan(FanNum).MotorInputPower > (Fan(FanNum).VFDMaxOutPwr + 1.e-5)) {
1460 0 : ShowWarningError(state,
1461 0 : "VFD for " + Fan(FanNum).FanType + ": " + Fan(FanNum).FanName +
1462 : " is undersized at design conditions -- check VFD inputs");
1463 0 : ShowContinueError(state, format("...Design VFD output power (without oversizing) [W]: {:.2R}", Fan(FanNum).MotorInputPower));
1464 : }
1465 :
1466 4 : VFDOutPwrRatio = Fan(FanNum).MotorInputPower / Fan(FanNum).VFDMaxOutPwr; //[-]
1467 4 : Fan(FanNum).VFDEff = CurveValue(state, Fan(FanNum).VFDEffCurveIndex, VFDOutPwrRatio); //[-]
1468 : } else {
1469 : // No curve specified - use constant efficiency
1470 0 : Fan(FanNum).VFDMaxOutPwr = 0.0;
1471 0 : Fan(FanNum).VFDEff = 0.97;
1472 : }
1473 : }
1474 4 : Fan(FanNum).VFDEff = max(Fan(FanNum).VFDEff, 0.01); // Minimum efficiency is 1% to avoid numerical errors
1475 :
1476 : // Calculate VFD "rated" input power using motor input power and VFD efficiency
1477 4 : RatedPower = Fan(FanNum).MotorInputPower / Fan(FanNum).VFDEff; //[W]
1478 :
1479 : // Calculate combined fan system efficiency: includes fan, belt, motor, and VFD
1480 : // Equivalent to Fan(FanNum)%FanAirPower / Fan(FanNum)%FanPower
1481 4 : Fan(FanNum).FanEff = Fan(FanNum).FanWheelEff * Fan(FanNum).BeltEff * Fan(FanNum).MotEff * Fan(FanNum).VFDEff;
1482 :
1483 : // Report fan, belt, motor, and VFD characteristics at design condition to .eio file
1484 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Design Fan Airflow [m3/s]", FanVolFlow);
1485 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Design Fan Static Pressure Rise [Pa]", Fan(FanNum).DeltaPress);
1486 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Design Fan Shaft Power [W]", Fan(FanNum).FanShaftPower);
1487 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Design Motor Output Power [W]", Fan(FanNum).MotorMaxOutPwr);
1488 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Design VFD Output Power [W]", Fan(FanNum).VFDMaxOutPwr);
1489 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Rated Power [W]", RatedPower);
1490 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Drive Ratio []", Fan(FanNum).PulleyDiaRatio);
1491 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Design Belt Output Torque [Nm]", Fan(FanNum).BeltMaxTorque);
1492 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Design Fan Efficiency []", Fan(FanNum).FanWheelEff);
1493 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Maximum Belt Efficiency []", Fan(FanNum).BeltMaxEff);
1494 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Design Belt Efficiency []", Fan(FanNum).BeltEff);
1495 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Maximum Motor Efficiency []", Fan(FanNum).MotorMaxEff);
1496 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Design Motor Efficiency []", Fan(FanNum).MotEff);
1497 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Design VFD Efficiency []", Fan(FanNum).VFDEff);
1498 4 : BaseSizer::reportSizerOutput(state, Fan(FanNum).FanType, Fan(FanNum).FanName, "Design Combined Efficiency []", Fan(FanNum).FanEff);
1499 : } // End fan component sizing
1500 :
1501 1943 : equipName = Fan(FanNum).FanName;
1502 :
1503 : // Rearrange order to match table and use FanVolFlow to calculate RatedPower
1504 : // ALSO generates values if Component Model fan, for which DeltaPress and FanEff vary with flow
1505 1943 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchFanType, equipName, Fan(FanNum).FanType);
1506 1943 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchFanTotEff, equipName, Fan(FanNum).FanEff);
1507 1943 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchFanDeltaP, equipName, Fan(FanNum).DeltaPress);
1508 1943 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchFanVolFlow, equipName, FanVolFlow);
1509 1943 : RatedPower = FanVolFlow * Fan(FanNum).DeltaPress / Fan(FanNum).FanEff; // total fan power
1510 1943 : if (Fan(FanNum).FanType_Num != FanType_ComponentModel) {
1511 1939 : Fan(FanNum).DesignPointFEI =
1512 1939 : HVACFan::FanSystem::report_fei(state, FanVolFlow, RatedPower, Fan(FanNum).DeltaPress, state.dataEnvrn->StdRhoAir);
1513 : }
1514 1943 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchFanPwr, equipName, RatedPower);
1515 1943 : if (FanVolFlow != 0.0) {
1516 1934 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchFanPwrPerFlow, equipName, RatedPower / FanVolFlow);
1517 : }
1518 1943 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchFanMotorIn, equipName, Fan(FanNum).MotInAirFrac);
1519 1943 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchFanEndUse, equipName, Fan(FanNum).EndUseSubcategoryName);
1520 1943 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchFanEnergyIndex, equipName, Fan(FanNum).DesignPointFEI);
1521 :
1522 1943 : NVPerfNum = Fan(FanNum).NVPerfNum;
1523 1943 : if (NVPerfNum > 0) {
1524 0 : if (NightVentPerf(NVPerfNum).MaxAirFlowRate == AutoSize) {
1525 0 : NightVentPerf(NVPerfNum).MaxAirFlowRate = Fan(FanNum).MaxAirFlowRate;
1526 : }
1527 : }
1528 :
1529 : // Now that sizing is done, do check if the design point of fan is covered in the fault Fan Curve
1530 1943 : if (Fan(FanNum).FaultyFilterFlag) {
1531 1 : int jFault_AirFilter = Fan(FanNum).FaultyFilterIndex;
1532 :
1533 : // Check fault availability schedules
1534 1 : if (!state.dataFaultsMgr->FaultsFouledAirFilters(jFault_AirFilter).CheckFaultyAirFilterFanCurve(state)) {
1535 0 : ShowSevereError(state, "FaultModel:Fouling:AirFilter = \"" + state.dataFaultsMgr->FaultsFouledAirFilters(jFault_AirFilter).Name + "\"");
1536 0 : ShowContinueError(state,
1537 0 : "Invalid Fan Curve Name = \"" + state.dataFaultsMgr->FaultsFouledAirFilters(jFault_AirFilter).FaultyAirFilterFanCurve +
1538 : "\" does not cover ");
1539 0 : ShowContinueError(state, "the operational point of Fan " + Fan(FanNum).FanName);
1540 0 : ShowFatalError(state,
1541 0 : "SizeFan: Invalid FaultModel:Fouling:AirFilter=" + state.dataFaultsMgr->FaultsFouledAirFilters(jFault_AirFilter).Name);
1542 : }
1543 : }
1544 :
1545 1943 : if (++NumFansSized == state.dataFans->NumFans) FanNumericFields.deallocate(); // remove temporary array for field names at end of sizing
1546 1943 : }
1547 :
1548 11873687 : void SimSimpleFan(EnergyPlusData &state, int const FanNum)
1549 : {
1550 :
1551 : // SUBROUTINE INFORMATION:
1552 : // AUTHOR Unknown
1553 : // DATE WRITTEN Unknown
1554 : // MODIFIED Brent Griffith, May 2009, added EMS override
1555 : // Chandan Sharma, March 2011, FSEC: Added LocalTurnFansOn and LocalTurnFansOff
1556 : // Rongpeng Zhang, April 2015, added faulty fan operations due to fouling air filters
1557 : // RE-ENGINEERED na
1558 :
1559 : // PURPOSE OF THIS SUBROUTINE:
1560 : // This subroutine simulates the simple constant volume fan.
1561 :
1562 : // METHODOLOGY EMPLOYED:
1563 : // Converts design pressure rise and efficiency into fan power and temperature rise
1564 : // Constant fan pressure rise is assumed.
1565 :
1566 : // REFERENCES:
1567 : // ASHRAE HVAC 2 Toolkit, page 2-3 (FANSIM)
1568 :
1569 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1570 : Real64 RhoAir;
1571 : Real64 DeltaPress; // [N/m2]
1572 : Real64 FanEff;
1573 : Real64 MotInAirFrac;
1574 : Real64 MotEff;
1575 : Real64 MassFlow; // [kg/sec]
1576 : Real64 FanShaftPower; // power delivered to fan shaft
1577 :
1578 : int NVPerfNum;
1579 :
1580 11873687 : auto &Fan(state.dataFans->Fan);
1581 11873687 : auto &NightVentPerf(state.dataFans->NightVentPerf);
1582 :
1583 11873687 : NVPerfNum = Fan(FanNum).NVPerfNum;
1584 :
1585 11873687 : if (state.dataHVACGlobal->NightVentOn && NVPerfNum > 0) {
1586 0 : DeltaPress = NightVentPerf(NVPerfNum).DeltaPress;
1587 0 : FanEff = NightVentPerf(NVPerfNum).FanEff;
1588 0 : MotEff = NightVentPerf(NVPerfNum).MotEff;
1589 0 : MotInAirFrac = NightVentPerf(NVPerfNum).MotInAirFrac;
1590 : } else {
1591 11873687 : DeltaPress = Fan(FanNum).DeltaPress;
1592 11873687 : FanEff = Fan(FanNum).FanEff;
1593 11873687 : MotEff = Fan(FanNum).MotEff;
1594 11873687 : MotInAirFrac = Fan(FanNum).MotInAirFrac;
1595 : }
1596 :
1597 : // For a Constant Volume Simple Fan the Max Flow Rate is the Flow Rate for the fan
1598 : // unused0909 Tin = Fan(FanNum)%InletAirTemp
1599 : // unused0909 Win = Fan(FanNum)%InletAirHumRat
1600 11873687 : RhoAir = Fan(FanNum).RhoAirStdInit;
1601 11873687 : MassFlow = Fan(FanNum).InletAirMassFlowRate;
1602 :
1603 : // Faulty fan operations
1604 : // Update MassFlow & DeltaPress if there are fouling air filters corresponding to the fan
1605 11873687 : if (Fan(FanNum).FaultyFilterFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
1606 0 : (!state.dataGlobal->KickOffSimulation)) {
1607 :
1608 0 : int iFault = Fan(FanNum).FaultyFilterIndex;
1609 :
1610 : // Check fault availability schedules
1611 0 : if (GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsFouledAirFilters(iFault).AvaiSchedPtr) > 0.0) {
1612 0 : Real64 FanDesignFlowRateDec = 0; // Decrease of the Fan Design Volume Flow Rate [m3/sec]
1613 :
1614 0 : FanDesignFlowRateDec = CalFaultyFanAirFlowReduction(
1615 : state,
1616 0 : Fan(FanNum).FanName,
1617 0 : Fan(FanNum).MaxAirFlowRate,
1618 0 : Fan(FanNum).DeltaPress,
1619 0 : (GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsFouledAirFilters(iFault).FaultyAirFilterPressFracSchePtr) - 1) *
1620 0 : Fan(FanNum).DeltaPress,
1621 0 : state.dataFaultsMgr->FaultsFouledAirFilters(iFault).FaultyAirFilterFanCurvePtr);
1622 :
1623 : // Update MassFlow & DeltaPress of the fan
1624 0 : MassFlow = min(MassFlow, Fan(FanNum).MaxAirMassFlowRate - FanDesignFlowRateDec * RhoAir);
1625 0 : DeltaPress = GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsFouledAirFilters(iFault).FaultyAirFilterPressFracSchePtr) *
1626 0 : Fan(FanNum).DeltaPress;
1627 : }
1628 : }
1629 :
1630 : // EMS overwrite MassFlow, DeltaPress, and FanEff
1631 11873687 : if (Fan(FanNum).EMSMaxMassFlowOverrideOn) MassFlow = Fan(FanNum).EMSAirMassFlowValue;
1632 11873687 : if (Fan(FanNum).EMSFanPressureOverrideOn) DeltaPress = Fan(FanNum).EMSFanPressureValue;
1633 11873687 : if (Fan(FanNum).EMSFanEffOverrideOn) FanEff = Fan(FanNum).EMSFanEffValue;
1634 :
1635 11873687 : MassFlow = min(MassFlow, Fan(FanNum).MaxAirMassFlowRate);
1636 11873687 : MassFlow = max(MassFlow, Fan(FanNum).MinAirMassFlowRate);
1637 :
1638 : // Determine the Fan Schedule for the Time step
1639 36148354 : if ((GetCurrentScheduleValue(state, Fan(FanNum).AvailSchedPtrNum) > 0.0 || state.dataFans->LocalTurnFansOn) &&
1640 32484307 : !state.dataFans->LocalTurnFansOff && MassFlow > 0.0) {
1641 : // Fan is operating
1642 9870914 : Fan(FanNum).FanPower = max(0.0, MassFlow * DeltaPress / (FanEff * RhoAir)); // total fan power
1643 9870914 : FanShaftPower = MotEff * Fan(FanNum).FanPower; // power delivered to shaft
1644 9870914 : Fan(FanNum).PowerLossToAir = FanShaftPower + (Fan(FanNum).FanPower - FanShaftPower) * MotInAirFrac;
1645 9870914 : Fan(FanNum).OutletAirEnthalpy = Fan(FanNum).InletAirEnthalpy + Fan(FanNum).PowerLossToAir / MassFlow;
1646 : // This fan does not change the moisture or Mass Flow across the component
1647 9870914 : Fan(FanNum).OutletAirHumRat = Fan(FanNum).InletAirHumRat;
1648 9870914 : Fan(FanNum).OutletAirMassFlowRate = MassFlow;
1649 9870914 : Fan(FanNum).OutletAirTemp = PsyTdbFnHW(Fan(FanNum).OutletAirEnthalpy, Fan(FanNum).OutletAirHumRat);
1650 :
1651 : } else {
1652 : // Fan is off and not operating no power consumed and mass flow rate.
1653 2002773 : Fan(FanNum).FanPower = 0.0;
1654 2002773 : FanShaftPower = 0.0;
1655 2002773 : Fan(FanNum).PowerLossToAir = 0.0;
1656 2002773 : Fan(FanNum).OutletAirMassFlowRate = 0.0;
1657 2002773 : Fan(FanNum).OutletAirHumRat = Fan(FanNum).InletAirHumRat;
1658 2002773 : Fan(FanNum).OutletAirEnthalpy = Fan(FanNum).InletAirEnthalpy;
1659 2002773 : Fan(FanNum).OutletAirTemp = Fan(FanNum).InletAirTemp;
1660 : // Set the Control Flow variables to 0.0 flow when OFF.
1661 2002773 : Fan(FanNum).MassFlowRateMaxAvail = 0.0;
1662 2002773 : Fan(FanNum).MassFlowRateMinAvail = 0.0;
1663 : }
1664 11873687 : }
1665 :
1666 17080494 : void SimVariableVolumeFan(EnergyPlusData &state, int const FanNum, Optional<Real64 const> PressureRise)
1667 : {
1668 :
1669 : // SUBROUTINE INFORMATION:
1670 : // AUTHOR Unknown
1671 : // DATE WRITTEN Unknown
1672 : // MODIFIED Phil Haves
1673 : // Brent Griffith, May 2009 for EMS
1674 : // Chandan Sharma, March 2011, FSEC: Added LocalTurnFansOn and LocalTurnFansOff
1675 : // Rongpeng Zhang, April 2015, added faulty fan operations due to fouling air filters
1676 : // RE-ENGINEERED na
1677 :
1678 : // PURPOSE OF THIS SUBROUTINE:
1679 : // This subroutine simulates the simple variable volume fan.
1680 :
1681 : // METHODOLOGY EMPLOYED:
1682 : // Converts design pressure rise and efficiency into fan power and temperature rise
1683 : // Constant fan pressure rise is assumed.
1684 : // Uses curves of fan power fraction vs. fan part load to determine fan power at
1685 : // off design conditions.
1686 :
1687 : // REFERENCES:
1688 : // ASHRAE HVAC 2 Toolkit, page 2-3 (FANSIM)
1689 :
1690 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1691 : Real64 RhoAir;
1692 : Real64 DeltaPress; // [N/m2 = Pa]
1693 : Real64 FanEff; // Total fan efficiency - combined efficiency of fan, drive train,
1694 : // motor and variable speed controller (if any)
1695 : Real64 MaxAirFlowRate;
1696 : Real64 MaxAirMassFlowRate;
1697 : Real64 MotInAirFrac;
1698 : Real64 MotEff;
1699 : Real64 MassFlow; // [kg/sec]
1700 : Real64 PartLoadFrac;
1701 : Real64 MinFlowFrac; // Variable Volume Fan Min Flow Fraction [-]
1702 17080494 : Real64 FlowFracForPower(0.0); // Variable Volume Fan Flow Fraction for power calcs[-]
1703 17080494 : Real64 FlowFracActual(0.0); // actual VAV fan flow fraction
1704 : Real64 FanShaftPower; // power delivered to fan shaft
1705 : int NVPerfNum;
1706 :
1707 : // added to address the fan heat issue during low air flow conditions
1708 : Real64 MinFlowFracLimitFanHeat; // Minimum Fan Flow Fraction Limit for Fan Heat at Low Airflow [-]
1709 : Real64 FanPoweratLowMinimum; // Fan Power at Low Minimum Airflow [W]
1710 : Real64 PartLoadFracatLowMin;
1711 : Real64 DeltaTAcrossFan; // Air temperature rise across the fan due to fan heat [C]
1712 :
1713 : // Simple Variable Volume Fan - default values from DOE-2
1714 : // Type of Fan Coeff1 Coeff2 Coeff3 Coeff4 Coeff5
1715 : // INLET VANE DAMPERS 0.35071223 0.30850535 -0.54137364 0.87198823 0.000
1716 : // DISCHARGE DAMPERS 0.37073425 0.97250253 -0.34240761 0.000 0.000
1717 : // VARIABLE SPEED MOTOR 0.0015302446 0.0052080574 1.1086242 -0.11635563 0.000
1718 :
1719 17080494 : auto &Fan(state.dataFans->Fan);
1720 17080494 : auto &NightVentPerf(state.dataFans->NightVentPerf);
1721 :
1722 17080494 : NVPerfNum = Fan(FanNum).NVPerfNum;
1723 17080494 : MaxAirFlowRate = Fan(FanNum).MaxAirFlowRate;
1724 :
1725 17080494 : if (state.dataHVACGlobal->NightVentOn && NVPerfNum > 0) {
1726 0 : DeltaPress = NightVentPerf(NVPerfNum).DeltaPress;
1727 0 : FanEff = NightVentPerf(NVPerfNum).FanEff;
1728 0 : MotEff = NightVentPerf(NVPerfNum).MotEff;
1729 0 : MotInAirFrac = NightVentPerf(NVPerfNum).MotInAirFrac;
1730 0 : MaxAirMassFlowRate = NightVentPerf(NVPerfNum).MaxAirMassFlowRate;
1731 : } else {
1732 17080494 : if (present(PressureRise)) {
1733 28596 : DeltaPress = PressureRise;
1734 : } else {
1735 17051898 : DeltaPress = Fan(FanNum).DeltaPress;
1736 : }
1737 17080494 : FanEff = Fan(FanNum).FanEff;
1738 17080494 : MotEff = Fan(FanNum).MotEff;
1739 17080494 : MotInAirFrac = Fan(FanNum).MotInAirFrac;
1740 17080494 : MaxAirMassFlowRate = Fan(FanNum).MaxAirMassFlowRate;
1741 : }
1742 :
1743 : // unused0909 Tin = Fan(FanNum)%InletAirTemp
1744 : // unused0909 Win = Fan(FanNum)%InletAirHumRat
1745 17080494 : RhoAir = Fan(FanNum).RhoAirStdInit;
1746 17080494 : MassFlow = Fan(FanNum).InletAirMassFlowRate;
1747 :
1748 : // Faulty fan operations
1749 : // Update MassFlow & DeltaPress if there are fouling air filters corresponding to the fan
1750 34181765 : if (Fan(FanNum).FaultyFilterFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
1751 17085630 : (!state.dataGlobal->KickOffSimulation) && (!Fan(FanNum).EMSMaxMassFlowOverrideOn)) {
1752 :
1753 2568 : int iFault = Fan(FanNum).FaultyFilterIndex;
1754 :
1755 : // Check fault availability schedules
1756 2568 : if (GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsFouledAirFilters(iFault).AvaiSchedPtr) > 0.0) {
1757 2568 : Real64 FanDesignFlowRateDec = 0; // Decrease of the Fan Design Volume Flow Rate [m3/sec]
1758 :
1759 12840 : FanDesignFlowRateDec = CalFaultyFanAirFlowReduction(
1760 : state,
1761 2568 : Fan(FanNum).FanName,
1762 2568 : Fan(FanNum).MaxAirFlowRate,
1763 2568 : Fan(FanNum).DeltaPress,
1764 2568 : (GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsFouledAirFilters(iFault).FaultyAirFilterPressFracSchePtr) - 1) *
1765 2568 : Fan(FanNum).DeltaPress,
1766 2568 : state.dataFaultsMgr->FaultsFouledAirFilters(iFault).FaultyAirFilterFanCurvePtr);
1767 :
1768 : // Update MassFlow & DeltaPress of the fan
1769 2568 : MaxAirFlowRate = Fan(FanNum).MaxAirFlowRate - FanDesignFlowRateDec;
1770 2568 : MaxAirMassFlowRate = Fan(FanNum).MaxAirMassFlowRate - FanDesignFlowRateDec * RhoAir;
1771 5136 : DeltaPress = GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsFouledAirFilters(iFault).FaultyAirFilterPressFracSchePtr) *
1772 2568 : Fan(FanNum).DeltaPress;
1773 : }
1774 : }
1775 :
1776 : // EMS overwrite MassFlow, DeltaPress, and FanEff
1777 17080494 : if (Fan(FanNum).EMSFanPressureOverrideOn) DeltaPress = Fan(FanNum).EMSFanPressureValue;
1778 17080494 : if (Fan(FanNum).EMSFanEffOverrideOn) FanEff = Fan(FanNum).EMSFanEffValue;
1779 17080494 : if (Fan(FanNum).EMSMaxMassFlowOverrideOn) MassFlow = Fan(FanNum).EMSAirMassFlowValue;
1780 :
1781 17080494 : MassFlow = min(MassFlow, MaxAirMassFlowRate);
1782 :
1783 : // Determine the Fan Schedule for the Time step
1784 53478978 : if ((GetCurrentScheduleValue(state, Fan(FanNum).AvailSchedPtrNum) > 0.0 || state.dataFans->LocalTurnFansOn) &&
1785 47984538 : !state.dataFans->LocalTurnFansOff && MassFlow > 0.0) {
1786 : // Fan is operating - calculate power loss and enthalpy rise
1787 : // Fan(FanNum)%FanPower = PartLoadFrac*FullMassFlow*DeltaPress/(FanEff*RhoAir) ! total fan power
1788 : // Calculate and check limits on fraction of system flow
1789 : // unused0909 MaxFlowFrac = 1.0
1790 : // MinFlowFrac is calculated from the ration of the volume flows and is non-dimensional
1791 15326563 : MinFlowFrac = Fan(FanNum).MinAirFlowRate / MaxAirFlowRate;
1792 : // The actual flow fraction is calculated from MassFlow and the MaxVolumeFlow * AirDensity
1793 15326563 : FlowFracActual = MassFlow / MaxAirMassFlowRate;
1794 :
1795 : // Calculate the part Load Fraction (PH 7/13/03)
1796 :
1797 15326563 : FlowFracForPower = max(MinFlowFrac, min(FlowFracActual, 1.0)); // limit flow fraction to allowed range
1798 15326563 : if (state.dataHVACGlobal->NightVentOn && NVPerfNum > 0) {
1799 0 : PartLoadFrac = 1.0;
1800 : } else {
1801 45979689 : PartLoadFrac = Fan(FanNum).FanCoeff(1) + Fan(FanNum).FanCoeff(2) * FlowFracForPower + Fan(FanNum).FanCoeff(3) * pow_2(FlowFracForPower) +
1802 30653126 : Fan(FanNum).FanCoeff(4) * pow_3(FlowFracForPower) + Fan(FanNum).FanCoeff(5) * pow_4(FlowFracForPower);
1803 : }
1804 :
1805 15326563 : Fan(FanNum).FanPower = max(0.0, PartLoadFrac * MaxAirMassFlowRate * DeltaPress / (FanEff * RhoAir)); // total fan power (PH 7/13/03)
1806 :
1807 15326563 : FanShaftPower = MotEff * Fan(FanNum).FanPower; // power delivered to shaft
1808 15326563 : Fan(FanNum).PowerLossToAir = FanShaftPower + (Fan(FanNum).FanPower - FanShaftPower) * MotInAirFrac;
1809 15326563 : Fan(FanNum).OutletAirEnthalpy = Fan(FanNum).InletAirEnthalpy + Fan(FanNum).PowerLossToAir / MassFlow;
1810 : // This fan does not change the moisture or Mass Flow across the component
1811 15326563 : Fan(FanNum).OutletAirHumRat = Fan(FanNum).InletAirHumRat;
1812 15326563 : Fan(FanNum).OutletAirMassFlowRate = MassFlow;
1813 15326563 : Fan(FanNum).OutletAirTemp = PsyTdbFnHW(Fan(FanNum).OutletAirEnthalpy, Fan(FanNum).OutletAirHumRat);
1814 :
1815 : // KHL/FB, 2/10/2011. NFP implemented as CR 8338.
1816 : // When fan air flow is less than 10%, the fan power curve is linearized between the 10% to 0% to
1817 : // avoid the unrealistic high temperature rise across the fan.
1818 : // TH, 2/15/2011
1819 : // This change caused diffs for VAV systems when fan runs at less than 10% flow conditions.
1820 : // A potential way to improve is to check the temperature rise across the fan first,
1821 : // if it is too high (say > 20C) then applies the code.
1822 15326563 : DeltaTAcrossFan = Fan(FanNum).OutletAirTemp - Fan(FanNum).InletAirTemp;
1823 15326563 : if (DeltaTAcrossFan > 20.0) {
1824 0 : MinFlowFracLimitFanHeat = 0.10;
1825 0 : if (FlowFracForPower < MinFlowFracLimitFanHeat) {
1826 0 : PartLoadFracatLowMin = Fan(FanNum).FanCoeff(1) + Fan(FanNum).FanCoeff(2) * MinFlowFracLimitFanHeat +
1827 0 : Fan(FanNum).FanCoeff(3) * pow_2(MinFlowFracLimitFanHeat) +
1828 0 : Fan(FanNum).FanCoeff(4) * pow_3(MinFlowFracLimitFanHeat) +
1829 0 : Fan(FanNum).FanCoeff(5) * pow_4(MinFlowFracLimitFanHeat);
1830 0 : FanPoweratLowMinimum = PartLoadFracatLowMin * MaxAirMassFlowRate * DeltaPress / (FanEff * RhoAir);
1831 0 : Fan(FanNum).FanPower = max(0.0, FlowFracForPower * FanPoweratLowMinimum / MinFlowFracLimitFanHeat);
1832 0 : } else if (FlowFracActual < MinFlowFracLimitFanHeat) {
1833 0 : PartLoadFracatLowMin = Fan(FanNum).FanCoeff(1) + Fan(FanNum).FanCoeff(2) * MinFlowFracLimitFanHeat +
1834 0 : Fan(FanNum).FanCoeff(3) * pow_2(MinFlowFracLimitFanHeat) +
1835 0 : Fan(FanNum).FanCoeff(4) * pow_3(MinFlowFracLimitFanHeat) +
1836 0 : Fan(FanNum).FanCoeff(5) * pow_4(MinFlowFracLimitFanHeat);
1837 0 : FanPoweratLowMinimum = PartLoadFracatLowMin * MaxAirMassFlowRate * DeltaPress / (FanEff * RhoAir);
1838 0 : Fan(FanNum).FanPower = max(0.0, FlowFracActual * FanPoweratLowMinimum / MinFlowFracLimitFanHeat);
1839 : }
1840 0 : FanShaftPower = MotEff * Fan(FanNum).FanPower; // power delivered to shaft
1841 0 : Fan(FanNum).PowerLossToAir = FanShaftPower + (Fan(FanNum).FanPower - FanShaftPower) * MotInAirFrac;
1842 0 : Fan(FanNum).OutletAirEnthalpy = Fan(FanNum).InletAirEnthalpy + Fan(FanNum).PowerLossToAir / MassFlow;
1843 : // This fan does not change the moisture or Mass Flow across the component
1844 0 : Fan(FanNum).OutletAirHumRat = Fan(FanNum).InletAirHumRat;
1845 0 : Fan(FanNum).OutletAirMassFlowRate = MassFlow;
1846 0 : Fan(FanNum).OutletAirTemp = PsyTdbFnHW(Fan(FanNum).OutletAirEnthalpy, Fan(FanNum).OutletAirHumRat);
1847 : }
1848 :
1849 : } else {
1850 : // Fan is off and not operating no power consumed and mass flow rate.
1851 1753931 : Fan(FanNum).FanPower = 0.0;
1852 1753931 : FanShaftPower = 0.0;
1853 1753931 : Fan(FanNum).PowerLossToAir = 0.0;
1854 1753931 : Fan(FanNum).OutletAirMassFlowRate = 0.0;
1855 1753931 : Fan(FanNum).OutletAirHumRat = Fan(FanNum).InletAirHumRat;
1856 1753931 : Fan(FanNum).OutletAirEnthalpy = Fan(FanNum).InletAirEnthalpy;
1857 1753931 : Fan(FanNum).OutletAirTemp = Fan(FanNum).InletAirTemp;
1858 : // Set the Control Flow variables to 0.0 flow when OFF.
1859 1753931 : Fan(FanNum).MassFlowRateMaxAvail = 0.0;
1860 1753931 : Fan(FanNum).MassFlowRateMinAvail = 0.0;
1861 : }
1862 17080494 : }
1863 :
1864 107762510 : void SimOnOffFan(EnergyPlusData &state, int const FanNum, Optional<Real64 const> SpeedRatio)
1865 : {
1866 :
1867 : // SUBROUTINE INFORMATION:
1868 : // AUTHOR Unknown
1869 : // DATE WRITTEN Unknown
1870 : // MODIFIED Shirey, May 2001
1871 : // R. Raustad - FSEC, Jan 2009 - added SpeedRatio for multi-speed fans
1872 : // Brent Griffith, May 2009 for EMS
1873 : // Chandan Sharma, March 2011, FSEC: Added LocalTurnFansOn and LocalTurnFansOff
1874 : // Rongpeng Zhang, April 2015, added faulty fan operations due to fouling air filters
1875 : // RE-ENGINEERED na
1876 :
1877 : // PURPOSE OF THIS SUBROUTINE:
1878 : // This subroutine simulates the simple on/off fan.
1879 :
1880 : // METHODOLOGY EMPLOYED:
1881 : // Converts design pressure rise and efficiency into fan power and temperature rise
1882 : // Constant fan pressure rise is assumed.
1883 : // Uses curves of fan power fraction vs. fan part load to determine fan power at
1884 : // off design conditions.
1885 : // Same as simple (constant volume) fan, except added part-load curve input
1886 :
1887 : // REFERENCES:
1888 : // ASHRAE HVAC 2 Toolkit, page 2-3 (FANSIM)
1889 :
1890 : // Using/Aliasing
1891 : using Curve::CurveValue;
1892 :
1893 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1894 : Real64 RhoAir;
1895 : Real64 DeltaPress; // [N/m2]
1896 : Real64 FanEff;
1897 : Real64 MassFlow; // [kg/sec]
1898 : Real64 MaxAirMassFlowRate; // [kg/sec]
1899 : Real64 PartLoadRatio; // Ratio of actual mass flow rate to max mass flow rate
1900 : Real64 FlowFrac; // Actual Fan Flow Fraction = actual mass flow rate / max air mass flow rate
1901 : Real64 FanShaftPower; // power delivered to fan shaft
1902 : Real64 SpeedRaisedToPower; // Result of the speed ratio raised to the power of n (Curve object)
1903 : Real64 EffRatioAtSpeedRatio; // Efficiency ratio at current speed ratio (Curve object)
1904 :
1905 107762510 : auto &Fan(state.dataFans->Fan);
1906 :
1907 107762510 : MassFlow = Fan(FanNum).InletAirMassFlowRate;
1908 107762510 : MaxAirMassFlowRate = Fan(FanNum).MaxAirMassFlowRate;
1909 107762510 : DeltaPress = Fan(FanNum).DeltaPress;
1910 107762510 : FanEff = Fan(FanNum).FanEff;
1911 107762510 : RhoAir = Fan(FanNum).RhoAirStdInit;
1912 :
1913 : // Faulty fan operations
1914 : // Update MassFlow & DeltaPress if there are fouling air filters corresponding to the fan
1915 215525020 : if (Fan(FanNum).FaultyFilterFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
1916 107762510 : (!state.dataGlobal->KickOffSimulation) && (!Fan(FanNum).EMSMaxMassFlowOverrideOn)) {
1917 :
1918 0 : int iFault = Fan(FanNum).FaultyFilterIndex;
1919 :
1920 : // Check fault availability schedules
1921 0 : if (GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsFouledAirFilters(iFault).AvaiSchedPtr) > 0.0) {
1922 0 : Real64 FanDesignFlowRateDec = 0; // Decrease of the Fan Design Volume Flow Rate [m3/sec]
1923 :
1924 0 : FanDesignFlowRateDec = CalFaultyFanAirFlowReduction(
1925 : state,
1926 0 : Fan(FanNum).FanName,
1927 0 : Fan(FanNum).MaxAirFlowRate,
1928 0 : Fan(FanNum).DeltaPress,
1929 0 : (GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsFouledAirFilters(iFault).FaultyAirFilterPressFracSchePtr) - 1) *
1930 0 : Fan(FanNum).DeltaPress,
1931 0 : state.dataFaultsMgr->FaultsFouledAirFilters(iFault).FaultyAirFilterFanCurvePtr);
1932 :
1933 : // Update MassFlow & DeltaPress of the fan
1934 0 : MaxAirMassFlowRate = Fan(FanNum).MaxAirMassFlowRate - FanDesignFlowRateDec * RhoAir;
1935 0 : DeltaPress = GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsFouledAirFilters(iFault).FaultyAirFilterPressFracSchePtr) *
1936 0 : Fan(FanNum).DeltaPress;
1937 : }
1938 : }
1939 :
1940 : // EMS overwrite MassFlow, DeltaPress, and FanEff
1941 107762510 : if (Fan(FanNum).EMSMaxMassFlowOverrideOn) MassFlow = Fan(FanNum).EMSAirMassFlowValue;
1942 107762510 : if (Fan(FanNum).EMSFanPressureOverrideOn) DeltaPress = Fan(FanNum).EMSFanPressureValue;
1943 107762510 : if (Fan(FanNum).EMSFanEffOverrideOn) FanEff = Fan(FanNum).EMSFanEffValue;
1944 :
1945 107762510 : MassFlow = min(MassFlow, MaxAirMassFlowRate);
1946 107762510 : MassFlow = max(MassFlow, Fan(FanNum).MinAirMassFlowRate);
1947 107762510 : Fan(FanNum).FanRuntimeFraction = 0.0;
1948 :
1949 : // Determine the Fan Schedule for the Time step
1950 324304035 : if ((GetCurrentScheduleValue(state, Fan(FanNum).AvailSchedPtrNum) > 0.0 || state.dataFans->LocalTurnFansOn) &&
1951 321398136 : !state.dataFans->LocalTurnFansOff && MassFlow > 0.0 && Fan(FanNum).MaxAirMassFlowRate > 0.0) {
1952 : // The actual flow fraction is calculated from MassFlow and the MaxVolumeFlow * AirDensity
1953 91027777 : FlowFrac = MassFlow / MaxAirMassFlowRate;
1954 :
1955 : // Calculate the part load ratio, can't be greater than 1
1956 91027777 : PartLoadRatio = min(1.0, FlowFrac);
1957 : // Fan is operating
1958 91027777 : if (state.dataHVACGlobal->OnOffFanPartLoadFraction <= 0.0) {
1959 0 : ShowRecurringWarningErrorAtEnd(state, "Fan:OnOff, OnOffFanPartLoadFraction <= 0.0, Reset to 1.0", state.dataFans->ErrCount);
1960 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // avoid divide by zero or negative PLF
1961 : }
1962 :
1963 91027777 : if (state.dataHVACGlobal->OnOffFanPartLoadFraction < 0.7) {
1964 56758 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 0.7; // a warning message is already issued from the DX coils or gas heating coil
1965 : }
1966 :
1967 : // Keep fan runtime fraction between 0.0 and 1.0, and RTF >= PLR
1968 91027777 : if (state.dataHVACGlobal->OnOffFanPartLoadFraction >= 1.0) {
1969 85363482 : Fan(FanNum).FanRuntimeFraction = PartLoadRatio;
1970 : } else {
1971 5664295 : Fan(FanNum).FanRuntimeFraction = max(0.0, min(1.0, PartLoadRatio / state.dataHVACGlobal->OnOffFanPartLoadFraction));
1972 : }
1973 : // The fan speed ratio (passed from parent) determines the fan power according to fan laws
1974 91027777 : if (present(SpeedRatio)) {
1975 : // Fan(FanNum)%FanPower = MassFlow*DeltaPress/(FanEff*RhoAir*OnOffFanPartLoadFraction)! total fan power
1976 89063771 : Fan(FanNum).FanPower = max(0.0, MaxAirMassFlowRate * Fan(FanNum).FanRuntimeFraction * DeltaPress / (FanEff * RhoAir));
1977 :
1978 : // Do not modify fan power calculation unless fan power vs speed ratio curve is used.
1979 89063771 : if (Fan(FanNum).FanPowerRatAtSpeedRatCurveIndex > 0) {
1980 :
1981 : // adjust RTF to be in line with speed ratio (i.e., MaxAirMassFlowRate is not MAX when SpeedRatio /= 1)
1982 : // PLR = Mdot/MAXFlow => Mdot/(MAXFlow * SpeedRatio), RTF = PLR/PLF => PLR/SpeedRatio/PLF = RTF / SpeedRatio
1983 201002 : if (SpeedRatio > 0.0) Fan(FanNum).FanRuntimeFraction = min(1.0, Fan(FanNum).FanRuntimeFraction / SpeedRatio);
1984 :
1985 201002 : SpeedRaisedToPower = CurveValue(state, Fan(FanNum).FanPowerRatAtSpeedRatCurveIndex, SpeedRatio);
1986 201002 : if (SpeedRaisedToPower < 0.0) {
1987 0 : if (Fan(FanNum).OneTimePowerRatioCheck && !state.dataGlobal->WarmupFlag) {
1988 0 : ShowSevereError(state, cFanTypes(Fan(FanNum).FanType_Num) + " = " + Fan(FanNum).FanName + "\"");
1989 0 : ShowContinueError(state, "Error in Fan Power Ratio curve. Curve output less than 0.0.");
1990 0 : ShowContinueError(state, format("Curve output = {:.5T}, fan speed ratio = {:.5T}", SpeedRaisedToPower, SpeedRatio));
1991 0 : ShowContinueError(state, "Check curve coefficients to ensure proper power ratio as a function of fan speed ratio.");
1992 0 : ShowContinueError(state, "Resetting Fan Power Ratio curve output to 0.0 and the simulation continues.");
1993 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
1994 0 : Fan(FanNum).OneTimePowerRatioCheck = false;
1995 : }
1996 0 : SpeedRaisedToPower = 0.0;
1997 : }
1998 201002 : if (Fan(FanNum).FanEffRatioCurveIndex > 0 && !state.dataGlobal->WarmupFlag) {
1999 30543 : EffRatioAtSpeedRatio = CurveValue(state, Fan(FanNum).FanEffRatioCurveIndex, SpeedRatio);
2000 30543 : if (EffRatioAtSpeedRatio < 0.01) {
2001 0 : if (Fan(FanNum).OneTimeEffRatioCheck && !state.dataGlobal->WarmupFlag) {
2002 0 : ShowSevereError(state, cFanTypes(Fan(FanNum).FanType_Num) + " = " + Fan(FanNum).FanName + "\"");
2003 0 : ShowContinueError(state, "Error in Fan Efficiency Ratio curve. Curve output less than 0.01.");
2004 0 : ShowContinueError(state, format("Curve output = {:.5T}, fan speed ratio = {:.5T}", EffRatioAtSpeedRatio, SpeedRatio));
2005 0 : ShowContinueError(state, "Check curve coefficients to ensure proper efficiency ratio as a function of fan speed ratio.");
2006 0 : ShowContinueError(state, "Resetting Fan Efficiency Ratio curve output to 0.01 and the simulation continues.");
2007 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
2008 0 : Fan(FanNum).OneTimeEffRatioCheck = false;
2009 : }
2010 0 : EffRatioAtSpeedRatio = 0.01;
2011 : }
2012 : } else {
2013 170459 : EffRatioAtSpeedRatio = 1.0;
2014 : }
2015 201002 : Fan(FanNum).FanPower *= SpeedRaisedToPower / EffRatioAtSpeedRatio;
2016 : }
2017 : } else {
2018 1964006 : Fan(FanNum).FanPower = max(0.0, MaxAirMassFlowRate * Fan(FanNum).FanRuntimeFraction * DeltaPress / (FanEff * RhoAir)); // total fan power
2019 : }
2020 :
2021 : // OnOffFanPartLoadFraction is passed via DataHVACGlobals from the cooling or heating coil that is
2022 : // requesting the fan to operate in cycling fan/cycling coil mode
2023 91027777 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // reset to 1 in case other on/off fan is called without a part load curve
2024 91027777 : FanShaftPower = Fan(FanNum).MotEff * Fan(FanNum).FanPower; // power delivered to shaft
2025 91027777 : Fan(FanNum).PowerLossToAir = FanShaftPower + (Fan(FanNum).FanPower - FanShaftPower) * Fan(FanNum).MotInAirFrac;
2026 91027777 : Fan(FanNum).OutletAirEnthalpy = Fan(FanNum).InletAirEnthalpy + Fan(FanNum).PowerLossToAir / MassFlow;
2027 : // This fan does not change the moisture or Mass Flow across the component
2028 91027777 : Fan(FanNum).OutletAirHumRat = Fan(FanNum).InletAirHumRat;
2029 91027777 : Fan(FanNum).OutletAirMassFlowRate = MassFlow;
2030 : // Fan(FanNum)%OutletAirTemp = Tin + PowerLossToAir/(MassFlow*PsyCpAirFnW(Win,Tin))
2031 91027777 : Fan(FanNum).OutletAirTemp = PsyTdbFnHW(Fan(FanNum).OutletAirEnthalpy, Fan(FanNum).OutletAirHumRat);
2032 : } else {
2033 : // Fan is off and not operating no power consumed and mass flow rate.
2034 16734733 : Fan(FanNum).FanPower = 0.0;
2035 16734733 : FanShaftPower = 0.0;
2036 16734733 : Fan(FanNum).PowerLossToAir = 0.0;
2037 16734733 : Fan(FanNum).OutletAirMassFlowRate = 0.0;
2038 16734733 : Fan(FanNum).OutletAirHumRat = Fan(FanNum).InletAirHumRat;
2039 16734733 : Fan(FanNum).OutletAirEnthalpy = Fan(FanNum).InletAirEnthalpy;
2040 16734733 : Fan(FanNum).OutletAirTemp = Fan(FanNum).InletAirTemp;
2041 : // Set the Control Flow variables to 0.0 flow when OFF.
2042 16734733 : Fan(FanNum).MassFlowRateMaxAvail = 0.0;
2043 16734733 : Fan(FanNum).MassFlowRateMinAvail = 0.0;
2044 : }
2045 107762510 : }
2046 :
2047 1632157 : void SimZoneExhaustFan(EnergyPlusData &state, int const FanNum)
2048 : {
2049 :
2050 : // SUBROUTINE INFORMATION:
2051 : // AUTHOR Fred Buhl
2052 : // DATE WRITTEN Jan 2000
2053 : // MODIFIED Brent Griffith, May 2009 for EMS
2054 : // Brent Griffith, Feb 2013 controls upgrade
2055 : // RE-ENGINEERED na
2056 :
2057 : // PURPOSE OF THIS SUBROUTINE:
2058 : // This subroutine simulates the Zone Exhaust Fan
2059 :
2060 : // METHODOLOGY EMPLOYED:
2061 : // Converts design pressure rise and efficiency into fan power and temperature rise
2062 : // Constant fan pressure rise is assumed.
2063 :
2064 : // REFERENCES:
2065 : // ASHRAE HVAC 2 Toolkit, page 2-3 (FANSIM)
2066 :
2067 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2068 : Real64 RhoAir;
2069 : Real64 DeltaPress; // [N/m2]
2070 : Real64 FanEff;
2071 : Real64 MassFlow; // [kg/sec]
2072 : Real64 Tin; // [C]
2073 1632157 : bool FanIsRunning = false; // There seems to be a missing else case below unless false is assumed
2074 :
2075 1632157 : auto &Fan(state.dataFans->Fan);
2076 :
2077 1632157 : DeltaPress = Fan(FanNum).DeltaPress;
2078 1632157 : if (Fan(FanNum).EMSFanPressureOverrideOn) DeltaPress = Fan(FanNum).EMSFanPressureValue;
2079 :
2080 1632157 : FanEff = Fan(FanNum).FanEff;
2081 1632157 : if (Fan(FanNum).EMSFanEffOverrideOn) FanEff = Fan(FanNum).EMSFanEffValue;
2082 :
2083 : // For a Constant Volume Simple Fan the Max Flow Rate is the Flow Rate for the fan
2084 1632157 : Tin = Fan(FanNum).InletAirTemp;
2085 1632157 : RhoAir = Fan(FanNum).RhoAirStdInit;
2086 1632157 : MassFlow = Fan(FanNum).InletAirMassFlowRate;
2087 :
2088 : // When the AvailManagerMode == ExhaustFanCoupledToAvailManagers then the
2089 : // Exhaust Fan is interlocked with air loop availability via global TurnFansOn and TurnFansOff variables.
2090 : // There is now the option to control if user wants to decouple air loop operation and exhaust fan operation
2091 : // (zone air mass balance issues). If in the future want to allow for zone level local availability manager
2092 : // then the optional arguments ZoneCompTurnFansOn and ZoneCompTurnFansOff will need
2093 : // to be passed to SimulateFanComponents, and TurnFansOn must be changed to LocalTurnFansOn
2094 : // and TurnFansOff to LocalTurnFansOff in the IF statement below.
2095 :
2096 : // apply controls to determine if operating
2097 1632157 : if (Fan(FanNum).AvailManagerMode == AvailabilityManagerCoupling::Coupled) {
2098 4467422 : if (((GetCurrentScheduleValue(state, Fan(FanNum).AvailSchedPtrNum) > 0.0) || state.dataHVACGlobal->TurnFansOn) &&
2099 3790784 : !state.dataHVACGlobal->TurnFansOff && MassFlow > 0.0) { // available
2100 1180089 : if (Fan(FanNum).MinTempLimitSchedNum > 0) {
2101 0 : if (Tin >= GetCurrentScheduleValue(state, Fan(FanNum).MinTempLimitSchedNum)) {
2102 0 : FanIsRunning = true;
2103 : } else {
2104 0 : FanIsRunning = false;
2105 : }
2106 : } else {
2107 1180089 : FanIsRunning = true;
2108 : }
2109 : } else {
2110 243527 : FanIsRunning = false;
2111 : }
2112 :
2113 208541 : } else if (Fan(FanNum).AvailManagerMode == AvailabilityManagerCoupling::Decoupled) {
2114 208541 : if (GetCurrentScheduleValue(state, Fan(FanNum).AvailSchedPtrNum) > 0.0 && MassFlow > 0.0) {
2115 204497 : if (Fan(FanNum).MinTempLimitSchedNum > 0) {
2116 0 : if (Tin >= GetCurrentScheduleValue(state, Fan(FanNum).MinTempLimitSchedNum)) {
2117 0 : FanIsRunning = true;
2118 : } else {
2119 0 : FanIsRunning = false;
2120 : }
2121 : } else {
2122 204497 : FanIsRunning = true;
2123 : }
2124 : } else {
2125 4044 : FanIsRunning = false;
2126 : }
2127 : }
2128 :
2129 1632157 : if (FanIsRunning) {
2130 : // Fan is operating
2131 1384586 : Fan(FanNum).FanPower = max(0.0, MassFlow * DeltaPress / (FanEff * RhoAir)); // total fan power
2132 1384586 : Fan(FanNum).PowerLossToAir = Fan(FanNum).FanPower;
2133 1384586 : Fan(FanNum).OutletAirEnthalpy = Fan(FanNum).InletAirEnthalpy + Fan(FanNum).PowerLossToAir / MassFlow;
2134 : // This fan does not change the moisture or Mass Flow across the component
2135 1384586 : Fan(FanNum).OutletAirHumRat = Fan(FanNum).InletAirHumRat;
2136 1384586 : Fan(FanNum).OutletAirMassFlowRate = MassFlow;
2137 1384586 : Fan(FanNum).OutletAirTemp = PsyTdbFnHW(Fan(FanNum).OutletAirEnthalpy, Fan(FanNum).OutletAirHumRat);
2138 :
2139 : } else {
2140 : // Fan is off and not operating no power consumed and mass flow rate.
2141 247571 : Fan(FanNum).FanPower = 0.0;
2142 247571 : Fan(FanNum).PowerLossToAir = 0.0;
2143 247571 : Fan(FanNum).OutletAirMassFlowRate = 0.0;
2144 247571 : Fan(FanNum).OutletAirHumRat = Fan(FanNum).InletAirHumRat;
2145 247571 : Fan(FanNum).OutletAirEnthalpy = Fan(FanNum).InletAirEnthalpy;
2146 247571 : Fan(FanNum).OutletAirTemp = Fan(FanNum).InletAirTemp;
2147 : // Set the Control Flow variables to 0.0 flow when OFF.
2148 247571 : Fan(FanNum).MassFlowRateMaxAvail = 0.0;
2149 247571 : Fan(FanNum).MassFlowRateMinAvail = 0.0;
2150 247571 : Fan(FanNum).InletAirMassFlowRate = 0.0;
2151 : }
2152 1632157 : }
2153 :
2154 57293 : void SimComponentModelFan(EnergyPlusData &state, int const FanNum)
2155 : {
2156 :
2157 : // SUBROUTINE INFORMATION:
2158 : // AUTHOR Craig Wray, LBNL
2159 : // DATE WRITTEN Feb 2010
2160 : // MODIFIED Chandan Sharma, March 2011, FSEC: Added LocalTurnFansOn and LocalTurnFansOff
2161 : // RE-ENGINEERED na
2162 :
2163 : // PURPOSE OF THIS SUBROUTINE:
2164 : // This subroutine simulates the component model fan.
2165 :
2166 : // METHODOLOGY EMPLOYED:
2167 : // Calculate fan volumetric flow and corresponding fan static pressure rise,
2168 : // using air-handling system characteristics and Sherman-Wray system curve model
2169 : // Calculate fan air power using volumetric flow and fan static pressure rise
2170 : // Calculate fan wheel efficiency using fan volumetric flow, fan static pressure rise,
2171 : // fan characteristics, and Wray dimensionless fan static efficiency model
2172 : // Calculate fan shaft power using fan air power and fan static efficiency
2173 : // Calculate fan shaft speed and torque using Wray dimensionless fan airflow model
2174 : // Calculate belt part-load efficiency using correlations and coefficients based on ACEEE data
2175 : // Calculate belt input power using fan shaft power and belt efficiency
2176 : // Calculate motor part-load efficiency using correlations and coefficients based on MotorMaster+ data
2177 : // Calculate motor input power using belt input power and motor efficiency
2178 : // Calculate VFD efficiency using correlations and coefficients based on DOE data
2179 : // Calculate VFD input power using motor input power and VFD efficiency
2180 : // Calculate combined efficiency of fan, belt, motor, and VFD
2181 : // Calculate air temperature rise due to fan (and belt+motor if in airstream) power entering air-handler airflow
2182 : // Calculate output node conditions
2183 :
2184 : // Using/Aliasing
2185 : using Curve::CurveValue;
2186 : using Curve::GetCurveIndex;
2187 : using namespace OutputReportPredefined;
2188 :
2189 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2190 : int NVPerfNum;
2191 :
2192 : Real64 MaxAirMassFlowRate; // Fan Max mass airflow [kg/s]
2193 : Real64 MotInAirFrac; // Fraction of fan power input to airstream
2194 :
2195 : // Local variables
2196 : Real64 RhoAir; // Air density [kg/m3]
2197 : Real64 MassFlow; // Fan mass airflow [kg/s]
2198 : Real64 FanVolFlow; // Fan volumetric airflow [m3/s]
2199 : Real64 DuctStaticPress; // Duct static pressure setpoint [Pa]
2200 : Real64 DeltaPressTot; // Total pressure rise across fan [N/m2 = Pa]
2201 : Real64 FanOutletVelPress; // Fan outlet velocity pressure [Pa]
2202 : Real64 EulerNum; // Fan Euler number [-]
2203 : Real64 NormalizedEulerNum; // Normalized Fan Euler number [-]
2204 : Real64 FanDimFlow; // Fan dimensionless airflow [-]
2205 : Real64 FanSpdRadS; // Fan shaft rotational speed [rad/s]
2206 : Real64 MotorSpeed; // Motor shaft rotational speed [rpm]
2207 : Real64 FanTrqRatio; // Ratio of fan torque to max fan torque [-]
2208 : Real64 BeltPLEff; // Belt normalized (part-load) efficiency [-]
2209 : Real64 MotorOutPwrRatio; // Ratio of motor output power to max motor output power [-]
2210 : Real64 MotorPLEff; // Motor normalized (part-load) efficiency [-]
2211 57293 : Real64 VFDSpdRatio(0.0); // Ratio of motor speed to motor max speed [-]
2212 57293 : Real64 VFDOutPwrRatio(0.0); // Ratio of VFD output power to max VFD output power [-]
2213 : Real64 FanEnthalpyChange; // Air enthalpy change due to fan, belt, and motor losses [kJ/kg]
2214 :
2215 57293 : auto &NightVentPerf(state.dataFans->NightVentPerf);
2216 57293 : auto &Fan(state.dataFans->Fan);
2217 :
2218 : // Get inputs for night ventilation option
2219 57293 : NVPerfNum = Fan(FanNum).NVPerfNum;
2220 :
2221 57293 : if (state.dataHVACGlobal->NightVentOn && NVPerfNum > 0) {
2222 0 : MotInAirFrac = NightVentPerf(NVPerfNum).MotInAirFrac;
2223 0 : MaxAirMassFlowRate = NightVentPerf(NVPerfNum).MaxAirMassFlowRate;
2224 : } else {
2225 57293 : MotInAirFrac = Fan(FanNum).MotInAirFrac;
2226 57293 : MaxAirMassFlowRate = Fan(FanNum).MaxAirMassFlowRate;
2227 : }
2228 :
2229 : // IF (Fan(FanNum)%EMSFanPressureOverrideOn) DeltaPress = Fan(FanNum)%EMSFanPressureValue
2230 : // IF (Fan(FanNum)%EMSFanEffOverrideOn) FanEff = Fan(FanNum)%EMSFanEffValue
2231 :
2232 : // Get air density at standard conditions and get mass airflow through fan
2233 : // From WeatherManager:
2234 : // StdBaroPress=(101.325d0*(1.0d0-2.25577d-05*WeatherFileElevation)**5.2559d0)*1000.d0
2235 : // StdRhoAir=PsyRhoAirFnPbTdbW(StdBaroPress,20,0)
2236 : // From PsychRoutines:
2237 : // w=MAX(dw,1.0d-5)
2238 : // rhoair = pb/(287.d0*(tdb+DataGlobalConstants::KelvinConv())*(1.0d0+1.6077687d0*w))
2239 57293 : RhoAir = Fan(FanNum).RhoAirStdInit;
2240 57293 : MassFlow = min(Fan(FanNum).InletAirMassFlowRate, Fan(FanNum).MaxAirMassFlowRate);
2241 :
2242 : // IF (Fan(FanNum)%EMSMaxMassFlowOverrideOn) MassFlow = Fan(FanNum)%EMSAirMassFlowValue
2243 :
2244 : // Determine the Fan Schedule for the Time step
2245 171879 : if ((GetCurrentScheduleValue(state, Fan(FanNum).AvailSchedPtrNum) > 0.0 || state.dataFans->LocalTurnFansOn) &&
2246 171879 : !state.dataFans->LocalTurnFansOff && MassFlow > 0.0) {
2247 : // Fan is operating - calculate fan pressure rise, component efficiencies and power, and also air enthalpy rise
2248 :
2249 : // Calculate fan static pressure rise using fan volumetric flow, std air density, air-handling system characteristics,
2250 : // and Sherman-Wray system curve model (assumes static pressure surrounding air distribution system is zero)
2251 46997 : FanVolFlow = MassFlow / RhoAir; //[m3/s at standard conditions]
2252 46997 : DuctStaticPress = CurveValue(state, Fan(FanNum).PressResetCurveIndex, FanVolFlow); // Duct static pressure setpoint [Pa]
2253 46997 : DeltaPressTot = CurveValue(state, Fan(FanNum).PressRiseCurveIndex, FanVolFlow, DuctStaticPress); // Fan total pressure rise [Pa]
2254 46997 : FanOutletVelPress = 0.5 * RhoAir * pow_2(FanVolFlow / Fan(FanNum).FanOutletArea); // Fan outlet velocity pressure [Pa]
2255 : // Outlet velocity pressure cannot exceed total pressure rise
2256 46997 : FanOutletVelPress = min(FanOutletVelPress, DeltaPressTot);
2257 46997 : Fan(FanNum).DeltaPress = DeltaPressTot - FanOutletVelPress; // Fan static pressure rise [Pa]
2258 :
2259 : // IF (Fan(FanNum)%EMSFanPressureOverrideOn) DeltaPress = Fan(FanNum)%EMSFanPressureValue
2260 :
2261 : // Calculate fan static air power using volumetric flow and fan static pressure rise
2262 46997 : Fan(FanNum).FanAirPower = FanVolFlow * Fan(FanNum).DeltaPress; //[W]
2263 :
2264 : // Calculate fan wheel efficiency using fan volumetric flow, fan static pressure rise,
2265 : // fan characteristics, and Wray dimensionless fan static efficiency model
2266 46997 : EulerNum = (Fan(FanNum).DeltaPress * pow_4(Fan(FanNum).FanWheelDia)) / (RhoAir * pow_2(FanVolFlow)); //[-]
2267 46997 : NormalizedEulerNum = std::log10(EulerNum / Fan(FanNum).EuMaxEff);
2268 46997 : if (NormalizedEulerNum <= 0.0) {
2269 14568 : Fan(FanNum).FanWheelEff = CurveValue(state, Fan(FanNum).PLFanEffNormCurveIndex, NormalizedEulerNum);
2270 : } else {
2271 32429 : Fan(FanNum).FanWheelEff = CurveValue(state, Fan(FanNum).PLFanEffStallCurveIndex, NormalizedEulerNum);
2272 : }
2273 46997 : Fan(FanNum).FanWheelEff *= Fan(FanNum).FanMaxEff; // [-]
2274 46997 : Fan(FanNum).FanWheelEff = max(Fan(FanNum).FanWheelEff, 0.01); // Minimum efficiency is 1% to avoid numerical errors
2275 :
2276 : // Calculate fan shaft power using fan static air power and fan static efficiency
2277 46997 : Fan(FanNum).FanShaftPower = Fan(FanNum).FanAirPower / Fan(FanNum).FanWheelEff; //[W]
2278 :
2279 : // Calculate fan shaft speed, fan torque, and motor speed using Wray dimensionless fan airflow model
2280 46997 : if (NormalizedEulerNum <= 0.0) {
2281 14568 : FanDimFlow = CurveValue(state, Fan(FanNum).DimFlowNormCurveIndex, NormalizedEulerNum); //[-]
2282 : } else {
2283 32429 : FanDimFlow = CurveValue(state, Fan(FanNum).DimFlowStallCurveIndex, NormalizedEulerNum); //[-]
2284 : }
2285 46997 : FanSpdRadS = FanVolFlow / (FanDimFlow * Fan(FanNum).FanMaxDimFlow * pow_3(Fan(FanNum).FanWheelDia)); //[rad/s]
2286 46997 : Fan(FanNum).FanTrq = Fan(FanNum).FanShaftPower / FanSpdRadS; //[N-m]
2287 46997 : Fan(FanNum).FanSpd = FanSpdRadS * 9.549296586; //[rpm, conversion factor is 30/PI]
2288 46997 : MotorSpeed = Fan(FanNum).FanSpd * Fan(FanNum).PulleyDiaRatio; //[rpm]
2289 :
2290 : // Calculate belt part-load drive efficiency using correlations and coefficients based on ACEEE data
2291 : // Direct-drive is represented using curve coefficients such that "belt" max eff and PL eff = 1.0
2292 46997 : FanTrqRatio = Fan(FanNum).FanTrq / Fan(FanNum).BeltMaxTorque; //[-]
2293 46997 : if ((FanTrqRatio <= Fan(FanNum).BeltTorqueTrans) && (Fan(FanNum).PLBeltEffReg1CurveIndex != 0)) {
2294 3681 : BeltPLEff = CurveValue(state, Fan(FanNum).PLBeltEffReg1CurveIndex, FanTrqRatio); //[-]
2295 : } else {
2296 43316 : if ((FanTrqRatio > Fan(FanNum).BeltTorqueTrans) && (FanTrqRatio <= 1.0) && (Fan(FanNum).PLBeltEffReg2CurveIndex != 0)) {
2297 43316 : BeltPLEff = CurveValue(state, Fan(FanNum).PLBeltEffReg2CurveIndex, FanTrqRatio); //[-]
2298 : } else {
2299 0 : if ((FanTrqRatio > 1.0) && (Fan(FanNum).PLBeltEffReg3CurveIndex != 0)) {
2300 0 : BeltPLEff = CurveValue(state, Fan(FanNum).PLBeltEffReg3CurveIndex, FanTrqRatio); //[-]
2301 : } else {
2302 0 : BeltPLEff = 1.0; // Direct drive or no curve specified - use constant efficiency
2303 : }
2304 : }
2305 : }
2306 46997 : Fan(FanNum).BeltEff = Fan(FanNum).BeltMaxEff * BeltPLEff; //[-]
2307 46997 : Fan(FanNum).BeltEff = max(Fan(FanNum).BeltEff, 0.01); // Minimum efficiency is 1% to avoid numerical errors
2308 :
2309 : // Calculate belt input power using fan shaft power and belt efficiency
2310 46997 : Fan(FanNum).BeltInputPower = Fan(FanNum).FanShaftPower / Fan(FanNum).BeltEff; //[W]
2311 :
2312 : // Calculate motor part-load efficiency using correlations and coefficients based on MotorMaster+ data
2313 46997 : MotorOutPwrRatio = Fan(FanNum).BeltInputPower / Fan(FanNum).MotorMaxOutPwr; //[-]
2314 46997 : if (Fan(FanNum).PLMotorEffCurveIndex != 0) {
2315 46997 : MotorPLEff = CurveValue(state, Fan(FanNum).PLMotorEffCurveIndex, MotorOutPwrRatio); //[-]
2316 : } else {
2317 0 : MotorPLEff = 1.0; // No curve specified - use constant efficiency
2318 : }
2319 46997 : Fan(FanNum).MotEff = Fan(FanNum).MotorMaxEff * MotorPLEff; //[-]
2320 46997 : Fan(FanNum).MotEff = max(Fan(FanNum).MotEff, 0.01); // Minimum efficiency is 1% to avoid numerical errors
2321 :
2322 : // Calculate motor input power using belt input power and motor efficiency
2323 46997 : Fan(FanNum).MotorInputPower = Fan(FanNum).BeltInputPower / Fan(FanNum).MotEff; //[W]
2324 :
2325 : // Calculate VFD efficiency using correlations and coefficients based on VFD type
2326 46997 : if ((Fan(FanNum).VFDEffType == "SPEED") && (Fan(FanNum).VFDEffCurveIndex != 0)) {
2327 0 : VFDSpdRatio = MotorSpeed / Fan(FanNum).MotorMaxSpd; //[-]
2328 0 : Fan(FanNum).VFDEff = CurveValue(state, Fan(FanNum).VFDEffCurveIndex, VFDSpdRatio); //[-]
2329 : } else {
2330 46997 : if ((Fan(FanNum).VFDEffType == "POWER") && (Fan(FanNum).VFDEffCurveIndex != 0)) {
2331 46997 : VFDOutPwrRatio = Fan(FanNum).MotorInputPower / Fan(FanNum).VFDMaxOutPwr; //[-]
2332 46997 : Fan(FanNum).VFDEff = CurveValue(state, Fan(FanNum).VFDEffCurveIndex, VFDOutPwrRatio); //[-]
2333 : } else {
2334 : // No curve specified - use constant efficiency
2335 0 : Fan(FanNum).VFDMaxOutPwr = 0.0;
2336 0 : Fan(FanNum).VFDEff = 0.97;
2337 : }
2338 : }
2339 46997 : Fan(FanNum).VFDEff = max(Fan(FanNum).VFDEff, 0.01); // Minimum efficiency is 1% to avoid numerical errors
2340 :
2341 : // Calculate VFD input power using motor input power and VFD efficiency
2342 46997 : Fan(FanNum).VFDInputPower = Fan(FanNum).MotorInputPower / Fan(FanNum).VFDEff; //[W]
2343 46997 : Fan(FanNum).FanPower = Fan(FanNum).VFDInputPower; //[W]
2344 :
2345 : // Calculate combined fan system efficiency: includes fan, belt, motor, and VFD
2346 : // Equivalent to Fan(FanNum)%FanAirPower / Fan(FanNum)%FanPower
2347 46997 : Fan(FanNum).FanEff = Fan(FanNum).FanWheelEff * Fan(FanNum).BeltEff * Fan(FanNum).MotEff * Fan(FanNum).VFDEff;
2348 :
2349 : // IF (Fan(FanNum)%EMSFanEffOverrideOn) FanEff = Fan(FanNum)%EMSFanEffValue
2350 :
2351 : // Calculate air enthalpy and temperature rise from power entering air stream from fan wheel, belt, and motor
2352 : // Assumes MotInAirFrac applies to belt and motor but NOT to VFD
2353 46997 : Fan(FanNum).PowerLossToAir =
2354 46997 : Fan(FanNum).FanShaftPower + (Fan(FanNum).MotorInputPower - Fan(FanNum).FanShaftPower) * Fan(FanNum).MotInAirFrac; //[W]
2355 46997 : FanEnthalpyChange = Fan(FanNum).PowerLossToAir / MassFlow; //[kJ/kg]
2356 46997 : Fan(FanNum).OutletAirEnthalpy = Fan(FanNum).InletAirEnthalpy + FanEnthalpyChange; //[kJ/kg]
2357 :
2358 : // This fan does not change the moisture or mass flow across the component
2359 46997 : Fan(FanNum).OutletAirHumRat = Fan(FanNum).InletAirHumRat; //[-]
2360 46997 : Fan(FanNum).OutletAirMassFlowRate = MassFlow; //[kg/s]
2361 46997 : Fan(FanNum).OutletAirTemp = PsyTdbFnHW(Fan(FanNum).OutletAirEnthalpy, Fan(FanNum).OutletAirHumRat);
2362 : } else {
2363 : // Fan is OFF and not operating -- no power consumed and zero mass flow rate
2364 10296 : Fan(FanNum).FanPower = 0.0;
2365 10296 : Fan(FanNum).FanShaftPower = 0.0;
2366 10296 : Fan(FanNum).PowerLossToAir = 0.0;
2367 10296 : Fan(FanNum).OutletAirMassFlowRate = 0.0;
2368 10296 : Fan(FanNum).OutletAirHumRat = Fan(FanNum).InletAirHumRat;
2369 10296 : Fan(FanNum).OutletAirEnthalpy = Fan(FanNum).InletAirEnthalpy;
2370 10296 : Fan(FanNum).OutletAirTemp = Fan(FanNum).InletAirTemp;
2371 : // Set the Control Flow variables to 0.0 flow when OFF.
2372 10296 : Fan(FanNum).MassFlowRateMaxAvail = 0.0;
2373 10296 : Fan(FanNum).MassFlowRateMinAvail = 0.0;
2374 :
2375 10296 : Fan(FanNum).DeltaPress = 0.0;
2376 10296 : Fan(FanNum).FanAirPower = 0.0;
2377 10296 : Fan(FanNum).FanWheelEff = 0.0;
2378 10296 : Fan(FanNum).FanSpd = 0.0;
2379 10296 : Fan(FanNum).FanTrq = 0.0;
2380 10296 : Fan(FanNum).BeltEff = 0.0;
2381 10296 : Fan(FanNum).BeltInputPower = 0.0;
2382 10296 : Fan(FanNum).MotEff = 0.0;
2383 10296 : Fan(FanNum).MotorInputPower = 0.0;
2384 10296 : Fan(FanNum).VFDEff = 0.0;
2385 10296 : Fan(FanNum).VFDInputPower = 0.0;
2386 10296 : Fan(FanNum).FanEff = 0.0;
2387 : }
2388 57293 : }
2389 :
2390 138406141 : void UpdateFan(EnergyPlusData &state, int const FanNum)
2391 : {
2392 :
2393 : // SUBROUTINE INFORMATION:
2394 : // AUTHOR Richard Liesen
2395 : // DATE WRITTEN April 1998
2396 : // MODIFIED L. Gu, Feb. 1, 2007, No unbalance airflow when Zone Exhaust Fans are used in the AirflowNetwork
2397 : // RE-ENGINEERED na
2398 :
2399 : // PURPOSE OF THIS SUBROUTINE:
2400 : // This subroutine updates the fan outlet nodes.
2401 :
2402 : // METHODOLOGY EMPLOYED:
2403 : // Data is moved from the fan data structure to the fan outlet nodes.
2404 :
2405 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2406 : int OutletNode;
2407 : int InletNode;
2408 :
2409 138406141 : auto &Fan(state.dataFans->Fan);
2410 :
2411 138406141 : OutletNode = Fan(FanNum).OutletNodeNum;
2412 138406141 : InletNode = Fan(FanNum).InletNodeNum;
2413 :
2414 : // Set the outlet air nodes of the fan
2415 138406141 : state.dataLoopNodes->Node(OutletNode).MassFlowRate = Fan(FanNum).OutletAirMassFlowRate;
2416 138406141 : state.dataLoopNodes->Node(OutletNode).Temp = Fan(FanNum).OutletAirTemp;
2417 138406141 : state.dataLoopNodes->Node(OutletNode).HumRat = Fan(FanNum).OutletAirHumRat;
2418 138406141 : state.dataLoopNodes->Node(OutletNode).Enthalpy = Fan(FanNum).OutletAirEnthalpy;
2419 : // Set the outlet nodes for properties that just pass through & not used
2420 138406141 : state.dataLoopNodes->Node(OutletNode).Quality = state.dataLoopNodes->Node(InletNode).Quality;
2421 138406141 : state.dataLoopNodes->Node(OutletNode).Press = state.dataLoopNodes->Node(InletNode).Press;
2422 :
2423 : // Set the Node Flow Control Variables from the Fan Control Variables
2424 138406141 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = Fan(FanNum).MassFlowRateMaxAvail;
2425 138406141 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = Fan(FanNum).MassFlowRateMinAvail;
2426 :
2427 138406141 : if (Fan(FanNum).FanType_Num == FanType_ZoneExhaust) {
2428 1632157 : state.dataLoopNodes->Node(InletNode).MassFlowRate = Fan(FanNum).InletAirMassFlowRate;
2429 1632157 : if (state.afn->AirflowNetworkNumOfExhFan == 0) {
2430 1331350 : state.dataHVACGlobal->UnbalExhMassFlow = Fan(FanNum).InletAirMassFlowRate;
2431 1331350 : if (Fan(FanNum).BalancedFractSchedNum > 0) {
2432 334744 : state.dataHVACGlobal->BalancedExhMassFlow =
2433 334744 : state.dataHVACGlobal->UnbalExhMassFlow * GetCurrentScheduleValue(state, Fan(FanNum).BalancedFractSchedNum);
2434 334744 : state.dataHVACGlobal->UnbalExhMassFlow = state.dataHVACGlobal->UnbalExhMassFlow - state.dataHVACGlobal->BalancedExhMassFlow;
2435 : } else {
2436 996606 : state.dataHVACGlobal->BalancedExhMassFlow = 0.0;
2437 : }
2438 : } else {
2439 300807 : state.dataHVACGlobal->UnbalExhMassFlow = 0.0;
2440 300807 : state.dataHVACGlobal->BalancedExhMassFlow = 0.0;
2441 : }
2442 1632157 : Fan(FanNum).UnbalancedOutletMassFlowRate = state.dataHVACGlobal->UnbalExhMassFlow;
2443 1632157 : Fan(FanNum).BalancedOutletMassFlowRate = state.dataHVACGlobal->BalancedExhMassFlow;
2444 : }
2445 :
2446 138406141 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2447 828819 : state.dataLoopNodes->Node(OutletNode).CO2 = state.dataLoopNodes->Node(InletNode).CO2;
2448 : }
2449 :
2450 138406141 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2451 236471 : state.dataLoopNodes->Node(OutletNode).GenContam = state.dataLoopNodes->Node(InletNode).GenContam;
2452 : }
2453 138406141 : }
2454 :
2455 138406141 : void ReportFan(EnergyPlusData &state, int const FanNum)
2456 : {
2457 :
2458 : // SUBROUTINE INFORMATION:
2459 : // AUTHOR Richard Liesen
2460 : // DATE WRITTEN April 1998
2461 : // MODIFIED na
2462 : // RE-ENGINEERED na
2463 :
2464 : // PURPOSE OF THIS SUBROUTINE:
2465 : // This subroutine updates the report variables for the fans.
2466 :
2467 : // Using/Aliasing
2468 138406141 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
2469 :
2470 138406141 : auto &Fan(state.dataFans->Fan);
2471 :
2472 138406141 : Fan(FanNum).FanEnergy = Fan(FanNum).FanPower * TimeStepSys * DataGlobalConstants::SecInHour;
2473 138406141 : Fan(FanNum).DeltaTemp = Fan(FanNum).OutletAirTemp - Fan(FanNum).InletAirTemp;
2474 :
2475 138406141 : if (Fan(FanNum).FanType_Num == FanType_SimpleOnOff) {
2476 107762510 : if (Fan(FanNum).AirLoopNum > 0) {
2477 3746957 : state.dataAirLoop->AirLoopAFNInfo(Fan(FanNum).AirLoopNum).AFNLoopOnOffFanRTF = Fan(FanNum).FanRuntimeFraction;
2478 : }
2479 : }
2480 138406141 : }
2481 :
2482 1980 : void GetFanIndex(EnergyPlusData &state, std::string const &FanName, int &FanIndex, bool &ErrorsFound, std::string_view ThisObjectType)
2483 : {
2484 :
2485 : // SUBROUTINE INFORMATION:
2486 : // AUTHOR Linda Lawrie
2487 : // DATE WRITTEN June 2004
2488 : // MODIFIED na
2489 : // RE-ENGINEERED na
2490 :
2491 : // PURPOSE OF THIS SUBROUTINE:
2492 : // This subroutine sets an index for a given fan -- issues error message if that fan
2493 : // is not legal fan.
2494 :
2495 1980 : if (state.dataFans->GetFanInputFlag) { // First time subroutine has been entered
2496 326 : GetFanInput(state);
2497 326 : state.dataFans->GetFanInputFlag = false;
2498 : }
2499 :
2500 1980 : FanIndex = UtilityRoutines::FindItemInList(FanName, state.dataFans->Fan, &FanEquipConditions::FanName);
2501 1980 : if (FanIndex == 0) {
2502 0 : if (!ThisObjectType.empty()) {
2503 0 : ShowSevereError(state, fmt::format("{}, GetFanIndex: Fan not found={}", ThisObjectType, FanName));
2504 : } else {
2505 0 : ShowSevereError(state, "GetFanIndex: Fan not found=" + FanName);
2506 : }
2507 0 : ErrorsFound = true;
2508 : }
2509 1980 : }
2510 :
2511 15108 : void GetFanVolFlow(EnergyPlusData &state, int const FanIndex, Real64 &FanVolFlow)
2512 : {
2513 :
2514 : // SUBROUTINE INFORMATION:
2515 : // AUTHOR Richard Raustad
2516 : // DATE WRITTEN August 2005
2517 : // MODIFIED na
2518 : // RE-ENGINEERED na
2519 :
2520 : // PURPOSE OF THIS SUBROUTINE:
2521 : // This subroutine gets the fan volumetric flow for use by zone equipment (e.g. Packaged Terminal Heat Pump)
2522 : // Zone equipment must ensure that a properly sized fan is used to meet the maximum supply air flow rate
2523 :
2524 15108 : if (FanIndex == 0) {
2525 0 : FanVolFlow = 0.0;
2526 : } else {
2527 15108 : FanVolFlow = state.dataFans->Fan(FanIndex).MaxAirFlowRate;
2528 : }
2529 15108 : }
2530 :
2531 11098771 : Real64 GetFanPower(EnergyPlusData &state, int const FanIndex)
2532 : {
2533 :
2534 : // SUBROUTINE INFORMATION:
2535 : // AUTHOR B. Griffith
2536 : // DATE WRITTEN July 2012
2537 : // MODIFIED na
2538 : // RE-ENGINEERED na
2539 :
2540 : // PURPOSE OF THIS SUBROUTINE:
2541 : // This subroutine gets the fan power draw
2542 :
2543 11098771 : if (FanIndex == 0) {
2544 3505791 : return 0.0;
2545 : } else {
2546 7592980 : return state.dataFans->Fan(FanIndex).FanPower;
2547 : }
2548 : }
2549 :
2550 3946 : void GetFanType(EnergyPlusData &state,
2551 : std::string const &FanName, // Fan name
2552 : int &FanType, // returned fantype number
2553 : bool &ErrorsFound, // error indicator
2554 : std::string_view const ThisObjectType, // parent object type (for error message)
2555 : std::string_view const ThisObjectName // parent object name (for error message)
2556 : )
2557 : {
2558 :
2559 : // SUBROUTINE INFORMATION:
2560 : // AUTHOR Richard Raustad
2561 : // DATE WRITTEN August 2005
2562 : // MODIFIED na
2563 : // RE-ENGINEERED na
2564 :
2565 : // PURPOSE OF THIS SUBROUTINE:
2566 : // This subroutine sets an integer type for a given fan -- issues error message if that fan
2567 : // is not a legal fan.
2568 :
2569 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2570 : int FanIndex;
2571 :
2572 3946 : auto &Fan(state.dataFans->Fan);
2573 :
2574 3946 : if (state.dataFans->GetFanInputFlag) { // First time subroutine has been entered
2575 181 : GetFanInput(state);
2576 181 : state.dataFans->GetFanInputFlag = false;
2577 : }
2578 :
2579 3946 : FanIndex = UtilityRoutines::FindItemInList(FanName, Fan, &FanEquipConditions::FanName);
2580 3946 : if (FanIndex == 0) {
2581 0 : if ((!ThisObjectType.empty()) && (!ThisObjectName.empty())) {
2582 0 : ShowSevereError(state, fmt::format("GetFanType: {}=\"{}\", invalid Fan specified=\"{}\".", ThisObjectType, ThisObjectName, FanName));
2583 0 : } else if (!ThisObjectType.empty()) {
2584 0 : ShowSevereError(state, fmt::format("{}, GetFanType: Fan not found={}", ThisObjectType, FanName));
2585 : } else {
2586 0 : ShowSevereError(state, "GetFanType: Fan not found=" + FanName);
2587 : }
2588 0 : FanType = 0;
2589 0 : ErrorsFound = true;
2590 : } else {
2591 3946 : FanType = Fan(FanIndex).FanType_Num;
2592 : }
2593 3946 : }
2594 :
2595 4961 : Real64 GetFanDesignVolumeFlowRate(EnergyPlusData &state,
2596 : std::string_view FanType, // must match fan types in this module
2597 : std::string_view FanName, // must match fan names for the fan type
2598 : bool &ErrorsFound, // set to true if problem
2599 : Optional_int_const FanIndex // index to fan
2600 : )
2601 : {
2602 :
2603 : // FUNCTION INFORMATION:
2604 : // AUTHOR Linda Lawrie
2605 : // DATE WRITTEN February 2006
2606 : // MODIFIED R. Raustad, Aug 2007 - added optional fan index
2607 : // RE-ENGINEERED na
2608 :
2609 : // PURPOSE OF THIS FUNCTION:
2610 : // This function looks up the design volume flow rate for the given fan and returns it. If
2611 : // incorrect fan type or name is given, ErrorsFound is returned as true and value is returned
2612 : // as negative.
2613 :
2614 : // Return value
2615 : Real64 DesignVolumeFlowRate; // returned flow rate of matched fan
2616 :
2617 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2618 : int WhichFan;
2619 :
2620 4961 : auto &Fan(state.dataFans->Fan);
2621 :
2622 : // Obtains and Allocates fan related parameters from input file
2623 4961 : if (state.dataFans->GetFanInputFlag) { // First time subroutine has been entered
2624 0 : GetFanInput(state);
2625 0 : state.dataFans->GetFanInputFlag = false;
2626 : }
2627 :
2628 4961 : if (present(FanIndex)) {
2629 4217 : DesignVolumeFlowRate = Fan(FanIndex).MaxAirFlowRate;
2630 : } else {
2631 744 : WhichFan = UtilityRoutines::FindItemInList(FanName, Fan, &FanEquipConditions::FanName);
2632 744 : if (WhichFan != 0) {
2633 744 : DesignVolumeFlowRate = Fan(WhichFan).MaxAirFlowRate;
2634 : } else {
2635 0 : ShowSevereError(
2636 0 : state, "GetFanDesignVolumeFlowRate: Could not find Fan, Type=\"" + std::string{FanType} + "\" Name=\"" + std::string{FanName} + "\"");
2637 0 : ShowContinueError(state, "... Design Volume Flow rate returned as -1000.");
2638 0 : ErrorsFound = true;
2639 0 : DesignVolumeFlowRate = -1000.0;
2640 : }
2641 : }
2642 :
2643 4961 : return DesignVolumeFlowRate;
2644 : }
2645 :
2646 633 : int GetFanInletNode(EnergyPlusData &state,
2647 : std::string_view FanType, // must match fan types in this module
2648 : std::string_view FanName, // must match fan names for the fan type
2649 : bool &ErrorsFound // set to true if problem
2650 : )
2651 : {
2652 :
2653 : // FUNCTION INFORMATION:
2654 : // AUTHOR Linda Lawrie
2655 : // DATE WRITTEN February 2006
2656 : // MODIFIED na
2657 : // RE-ENGINEERED na
2658 :
2659 : // PURPOSE OF THIS FUNCTION:
2660 : // This function looks up the given fan and returns the inlet node. If
2661 : // incorrect fan type or name is given, ErrorsFound is returned as true and value is returned
2662 : // as zero.
2663 :
2664 : // Return value
2665 : int NodeNumber; // returned outlet node of matched fan
2666 :
2667 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2668 : int WhichFan;
2669 :
2670 633 : auto &Fan(state.dataFans->Fan);
2671 :
2672 : // Obtains and Allocates fan related parameters from input file
2673 633 : if (state.dataFans->GetFanInputFlag) { // First time subroutine has been entered
2674 10 : GetFanInput(state);
2675 10 : state.dataFans->GetFanInputFlag = false;
2676 : }
2677 :
2678 633 : WhichFan = UtilityRoutines::FindItemInList(FanName, Fan, &FanEquipConditions::FanName);
2679 633 : if (WhichFan != 0) {
2680 633 : NodeNumber = Fan(WhichFan).InletNodeNum;
2681 : } else {
2682 0 : ShowSevereError(state, "GetFanInletNode: Could not find Fan, Type=\"" + std::string{FanType} + "\" Name=\"" + std::string{FanName} + "\"");
2683 0 : ErrorsFound = true;
2684 0 : NodeNumber = 0;
2685 : }
2686 :
2687 633 : return NodeNumber;
2688 : }
2689 :
2690 0 : int getFanInNodeIndex(EnergyPlusData &state,
2691 : int const FanIndex, // fan index
2692 : bool &ErrorsFound // set to true if problem
2693 : )
2694 : {
2695 :
2696 0 : int NodeNumber = 0; // returned outlet node of matched fan
2697 :
2698 0 : auto &Fan(state.dataFans->Fan);
2699 :
2700 : // Obtains and Allocates fan related parameters from input file
2701 0 : if (state.dataFans->GetFanInputFlag) { // First time subroutine has been entered
2702 0 : GetFanInput(state);
2703 0 : state.dataFans->GetFanInputFlag = false;
2704 : }
2705 :
2706 0 : if (FanIndex != 0) {
2707 0 : NodeNumber = Fan(FanIndex).InletNodeNum;
2708 : } else {
2709 0 : ShowSevereError(state, "getFanInNodeIndex: Could not find Fan");
2710 0 : ErrorsFound = true;
2711 : }
2712 :
2713 0 : return NodeNumber;
2714 : }
2715 :
2716 889 : int GetFanOutletNode(EnergyPlusData &state,
2717 : std::string const &FanType, // must match fan types in this module
2718 : std::string const &FanName, // must match fan names for the fan type
2719 : bool &ErrorsFound // set to true if problem
2720 : )
2721 : {
2722 :
2723 : // FUNCTION INFORMATION:
2724 : // AUTHOR Linda Lawrie
2725 : // DATE WRITTEN February 2006
2726 : // MODIFIED na
2727 : // RE-ENGINEERED na
2728 :
2729 : // PURPOSE OF THIS FUNCTION:
2730 : // This function looks up the given fan and returns the outlet node. If
2731 : // incorrect fan type or name is given, ErrorsFound is returned as true and value is returned
2732 : // as zero.
2733 :
2734 : // Return value
2735 : int NodeNumber; // returned outlet node of matched fan
2736 :
2737 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2738 : int WhichFan;
2739 :
2740 889 : auto &Fan(state.dataFans->Fan);
2741 :
2742 : // Obtains and Allocates fan related parameters from input file
2743 889 : if (state.dataFans->GetFanInputFlag) { // First time subroutine has been entered
2744 1 : GetFanInput(state);
2745 1 : state.dataFans->GetFanInputFlag = false;
2746 : }
2747 :
2748 889 : WhichFan = UtilityRoutines::FindItemInList(FanName, Fan, &FanEquipConditions::FanName);
2749 889 : if (WhichFan != 0) {
2750 889 : NodeNumber = Fan(WhichFan).OutletNodeNum;
2751 : } else {
2752 0 : ShowSevereError(state, "GetFanOutletNode: Could not find Fan, Type=\"" + FanType + "\" Name=\"" + FanName + "\"");
2753 0 : ErrorsFound = true;
2754 0 : NodeNumber = 0;
2755 : }
2756 :
2757 889 : return NodeNumber;
2758 : }
2759 :
2760 811 : int GetFanAvailSchPtr(EnergyPlusData &state,
2761 : std::string const &FanType, // must match fan types in this module
2762 : std::string const &FanName, // must match fan names for the fan type
2763 : bool &ErrorsFound // set to true if problem
2764 : )
2765 : {
2766 :
2767 : // FUNCTION INFORMATION:
2768 : // AUTHOR Richard Raustad
2769 : // DATE WRITTEN September 2007
2770 : // MODIFIED na
2771 : // RE-ENGINEERED na
2772 :
2773 : // PURPOSE OF THIS FUNCTION:
2774 : // This function looks up the given fan and returns the availability schedule pointer. If
2775 : // incorrect fan type or name is given, ErrorsFound is returned as true and value is returned
2776 : // as zero.
2777 :
2778 : // Return value
2779 : int FanAvailSchPtr; // returned availability schedule pointer of matched fan
2780 :
2781 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2782 : int WhichFan;
2783 :
2784 811 : auto &Fan(state.dataFans->Fan);
2785 :
2786 : // Obtains and Allocates fan related parameters from input file
2787 811 : if (state.dataFans->GetFanInputFlag) { // First time subroutine has been entered
2788 0 : GetFanInput(state);
2789 0 : state.dataFans->GetFanInputFlag = false;
2790 : }
2791 :
2792 811 : WhichFan = UtilityRoutines::FindItemInList(FanName, Fan, &FanEquipConditions::FanName);
2793 811 : if (WhichFan != 0) {
2794 811 : FanAvailSchPtr = Fan(WhichFan).AvailSchedPtrNum;
2795 : } else {
2796 0 : ShowSevereError(state, "GetFanAvailSchPtr: Could not find Fan, Type=\"" + FanType + "\" Name=\"" + FanName + "\"");
2797 0 : ErrorsFound = true;
2798 0 : FanAvailSchPtr = 0;
2799 : }
2800 :
2801 811 : return FanAvailSchPtr;
2802 : }
2803 :
2804 560 : int GetFanSpeedRatioCurveIndex(EnergyPlusData &state,
2805 : std::string &FanType, // must match fan types in this module (set if nonzero index passed)
2806 : std::string &FanName, // must match fan names for the fan type (set if nonzero index passed)
2807 : Optional_int IndexIn // optional fan index if fan type and name are unknown or index needs setting
2808 : )
2809 : {
2810 :
2811 : // FUNCTION INFORMATION:
2812 : // AUTHOR Richard Raustad
2813 : // DATE WRITTEN September 2009
2814 : // MODIFIED na
2815 : // RE-ENGINEERED na
2816 :
2817 : // PURPOSE OF THIS FUNCTION:
2818 : // This function looks up the given fan and returns the fan speed curve pointer. If
2819 : // incorrect fan type or name is given, ErrorsFound is returned as true and value is returned
2820 : // as zero. If optional index argument is passed along with fan type and name, the index is set.
2821 :
2822 : // Return value
2823 : int FanSpeedRatioCurveIndex; // index to fan speed ratio curve object
2824 :
2825 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2826 : int WhichFan;
2827 :
2828 560 : auto &Fan(state.dataFans->Fan);
2829 :
2830 : // Obtains and Allocates fan related parameters from input file
2831 560 : if (state.dataFans->GetFanInputFlag) { // First time subroutine has been entered
2832 0 : GetFanInput(state);
2833 0 : state.dataFans->GetFanInputFlag = false;
2834 : }
2835 :
2836 560 : if (present(IndexIn)) {
2837 560 : if (IndexIn > 0) {
2838 560 : WhichFan = IndexIn;
2839 560 : FanType = Fan(WhichFan).FanType;
2840 560 : FanName = Fan(WhichFan).FanName;
2841 : } else {
2842 0 : WhichFan = UtilityRoutines::FindItemInList(FanName, Fan, &FanEquipConditions::FanName);
2843 0 : IndexIn = WhichFan;
2844 : }
2845 : } else {
2846 0 : WhichFan = UtilityRoutines::FindItemInList(FanName, Fan, &FanEquipConditions::FanName);
2847 : }
2848 :
2849 560 : if (WhichFan != 0) {
2850 560 : FanSpeedRatioCurveIndex = Fan(WhichFan).FanPowerRatAtSpeedRatCurveIndex;
2851 : } else {
2852 0 : ShowSevereError(state, "GetFanSpeedRatioCurveIndex: Could not find Fan, Type=\"" + FanType + "\" Name=\"" + FanName + "\"");
2853 0 : FanSpeedRatioCurveIndex = 0;
2854 : }
2855 :
2856 560 : return FanSpeedRatioCurveIndex;
2857 : }
2858 :
2859 0 : void SetFanData(EnergyPlusData &state,
2860 : int const FanNum, // Index of fan
2861 : bool &ErrorsFound, // Set to true if certain errors found
2862 : std::string const &FanName, // Name of fan
2863 : Optional<Real64 const> MaxAirVolFlow, // Fan air volumetric flow rate [m3/s]
2864 : Optional<Real64 const> MinAirVolFlow // Fan air volumetric flow rate [m3/s]
2865 : )
2866 : {
2867 :
2868 : // SUBROUTINE INFORMATION:
2869 : // AUTHOR Richard Raustad
2870 : // DATE WRITTEN October 2007
2871 : // MODIFIED na
2872 : // RE-ENGINEERED na
2873 :
2874 : // PURPOSE OF THIS SUBROUTINE:
2875 : // This routine was designed for to autosize the HeatExchanger:AirToAir:SensibleAndLatent using
2876 : // information from the ZoneHVAC:EnergyRecoveryVentilator object.
2877 : // This is an illustration of setting data from an outside source.
2878 :
2879 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2880 : int WhichFan; // index to generic HX
2881 :
2882 0 : auto &Fan(state.dataFans->Fan);
2883 :
2884 : // Obtains and Allocates fan related parameters from input file
2885 0 : if (state.dataFans->GetFanInputFlag) { // First time subroutine has been entered
2886 0 : GetFanInput(state);
2887 0 : state.dataFans->GetFanInputFlag = false;
2888 : }
2889 :
2890 0 : if (FanNum == 0) {
2891 0 : WhichFan = UtilityRoutines::FindItemInList(FanName, Fan, &FanEquipConditions::FanName);
2892 : } else {
2893 0 : WhichFan = FanNum;
2894 : }
2895 :
2896 0 : if (WhichFan <= 0 || WhichFan > state.dataFans->NumFans) {
2897 0 : ShowSevereError(state, "SetFanData: Could not find fan = \"" + FanName + "\"");
2898 0 : ErrorsFound = true;
2899 0 : return;
2900 : }
2901 :
2902 0 : if (present(MaxAirVolFlow)) {
2903 0 : Fan(WhichFan).MaxAirFlowRate = MaxAirVolFlow;
2904 : }
2905 :
2906 0 : if (present(MinAirVolFlow)) {
2907 0 : Fan(WhichFan).MinAirFlowRate = MinAirVolFlow;
2908 : }
2909 : }
2910 :
2911 0 : [[maybe_unused]] Real64 FanDesDT(EnergyPlusData &state,
2912 : int const FanNum, // index of fan in Fan array
2913 : [[maybe_unused]] Real64 const FanVolFlow // fan volumetric flow rate [m3/s]
2914 : )
2915 : {
2916 : // FUNCTION INFORMATION:
2917 : // AUTHOR Fred Buhl
2918 : // DATE WRITTEN August 2014
2919 : // MODIFIED
2920 : // RE-ENGINEERED na
2921 :
2922 : // PURPOSE OF THIS FUNCTION:
2923 : // This function calculates and returns the design fan delta T from the fan input data
2924 :
2925 : // METHODOLOGY EMPLOYED:
2926 : // Simple fan: Qdot,tot = (Vdot*deltaP)/Eff,tot
2927 : // Qdot,air = Eff,mot*Qdot,tot + (Qdot,tot - Eff,mot*Qdot,tot)*Frac,mot-in-airstream
2928 : // Qdot,air = cp,air*rho,air*Vdot*deltaT
2929 :
2930 : // REFERENCES: EnergyPlus Engineering Reference
2931 :
2932 : // Return value
2933 : Real64 DesignDeltaT; // returned delta T of matched fan [delta deg C]
2934 :
2935 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2936 : Real64 RhoAir; // density of air [kg/m3]
2937 : Real64 CpAir; // specific heat of air [J/kg-K]
2938 : Real64 DeltaP; // fan design pressure rise [N/m2]
2939 : Real64 TotEff; // fan design total efficiency
2940 : Real64 MotEff; // fan design motor efficiency
2941 : Real64 MotInAirFrac; // fraction of motor in the air stream
2942 :
2943 0 : auto &Fan(state.dataFans->Fan);
2944 :
2945 0 : if (FanNum == 0) {
2946 0 : DesignDeltaT = 0.0;
2947 0 : } else if (Fan(FanNum).FanType_Num != FanType_ComponentModel) {
2948 0 : DeltaP = Fan(FanNum).DeltaPress;
2949 0 : TotEff = Fan(FanNum).FanEff;
2950 0 : MotEff = Fan(FanNum).MotEff;
2951 0 : MotInAirFrac = Fan(FanNum).MotInAirFrac;
2952 0 : RhoAir = state.dataEnvrn->StdRhoAir;
2953 0 : CpAir = PsyCpAirFnW(DataPrecisionGlobals::constant_zero);
2954 0 : DesignDeltaT = (DeltaP / (RhoAir * CpAir * TotEff)) * (MotEff + MotInAirFrac * (1.0 - MotEff));
2955 : } else {
2956 0 : DesignDeltaT = 0.0;
2957 : }
2958 :
2959 0 : return DesignDeltaT;
2960 :
2961 : } // FanDesDT
2962 :
2963 2568 : Real64 CalFaultyFanAirFlowReduction(EnergyPlusData &state,
2964 : std::string const &FanName, // name of the fan
2965 : Real64 const FanDesignAirFlowRate, // Fan Design Volume Flow Rate [m3/sec]
2966 : Real64 const FanDesignDeltaPress, // Fan Design Delta Pressure [Pa]
2967 : Real64 const FanFaultyDeltaPressInc, // Increase of Fan Delta Pressure in the Faulty Case [Pa]
2968 : int const FanCurvePtr // Fan Curve Index
2969 : )
2970 : {
2971 :
2972 : // SUBROUTINE INFORMATION:
2973 : // AUTHOR Rongpeng Zhang
2974 : // DATE WRITTEN Apr. 2015
2975 : // MODIFIED na
2976 : // RE-ENGINEERED na
2977 :
2978 : // PURPOSE OF THIS SUBROUTINE:
2979 : // Calculate the decrease of the fan air flow rate, given the fan curve
2980 : // and the increase of fan pressure rise due to fouling air filters
2981 :
2982 : // Using/Aliasing
2983 : using namespace Curve;
2984 :
2985 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2986 : Real64 FanFaultyAirFlowRate; // Fan Volume Flow Rate in the Faulty Case [m3/sec]
2987 : Real64 FanCalDeltaPress; // Calculated Fan Delta Pressure for temp use [Pa]
2988 : Real64 FanCalDeltaPresstemp; // Calculated Fan Delta Pressure for temp use [Pa]
2989 :
2990 : // Check whether the fan curve covers the design operational point of the fan
2991 2568 : FanCalDeltaPress = CurveValue(state, FanCurvePtr, FanDesignAirFlowRate);
2992 2568 : if ((FanCalDeltaPress < 0.9 * FanDesignDeltaPress) || (FanCalDeltaPress > 1.1 * FanDesignDeltaPress)) {
2993 0 : ShowWarningError(state, "The design operational point of the fan " + FanName + " does not fall ");
2994 0 : ShowContinueError(state, "on the fan curve provided in the FaultModel:Fouling:AirFilter object. ");
2995 0 : return 0.0;
2996 : }
2997 :
2998 : // Calculate the Fan Volume Flow Rate in the Faulty Case
2999 2568 : FanFaultyAirFlowRate = FanDesignAirFlowRate;
3000 2568 : FanCalDeltaPresstemp = CurveValue(state, FanCurvePtr, FanFaultyAirFlowRate);
3001 2568 : FanCalDeltaPress = FanCalDeltaPresstemp;
3002 :
3003 1630680 : while (FanCalDeltaPress < (FanDesignDeltaPress + FanFaultyDeltaPressInc)) {
3004 814056 : FanFaultyAirFlowRate = FanFaultyAirFlowRate - 0.005;
3005 814056 : FanCalDeltaPresstemp = CurveValue(state, FanCurvePtr, FanFaultyAirFlowRate);
3006 :
3007 1628112 : if ((FanCalDeltaPresstemp <= FanCalDeltaPress) ||
3008 814056 : (FanFaultyAirFlowRate <= state.dataCurveManager->PerfCurve(FanCurvePtr).inputLimits[0].min)) {
3009 : // The new operational point of the fan go beyond the fan selection range
3010 0 : ShowWarningError(state, "The operational point of the fan " + FanName + " may go beyond the fan selection ");
3011 0 : ShowContinueError(state, "range in the faulty fouling air filter cases");
3012 0 : break;
3013 : }
3014 :
3015 814056 : FanCalDeltaPress = FanCalDeltaPresstemp;
3016 : }
3017 :
3018 2568 : return FanDesignAirFlowRate - FanFaultyAirFlowRate;
3019 : }
3020 :
3021 362 : Real64 FanDesHeatGain(EnergyPlusData &state,
3022 : int const FanNum, // index of fan in Fan array
3023 : Real64 const FanVolFlow // fan volumetric flow rate [m3/s]
3024 : )
3025 : {
3026 : // FUNCTION INFORMATION:
3027 : // AUTHOR Fred Buhl
3028 : // DATE WRITTEN August 2014
3029 : // MODIFIED
3030 : // RE-ENGINEERED na
3031 :
3032 : // PURPOSE OF THIS FUNCTION:
3033 : // This function calculates and returns the design fan heat gain from the fan input data
3034 :
3035 : // METHODOLOGY EMPLOYED:
3036 : // Simple fan: Qdot,tot = (Vdot*deltaP)/Eff,tot
3037 : // Qdot,air = Eff,mot*Qdot,tot + (Qdot,tot - Eff,mot*Qdot,tot)*Frac,mot-in-airstream
3038 :
3039 : // REFERENCES: EnergyPlus Engineering Reference
3040 :
3041 : // Return value
3042 : Real64 DesignHeatGain; // returned heat gain of matched fan [W]
3043 :
3044 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
3045 : Real64 DeltaP; // fan design pressure rise [N/m2]
3046 : Real64 TotEff; // fan design total efficiency
3047 : Real64 MotEff; // fan design motor efficiency
3048 : Real64 MotInAirFrac; // fraction of motor in the air stream
3049 : Real64 FanPowerTot; // total fan power consumption [W]
3050 :
3051 362 : auto &Fan(state.dataFans->Fan);
3052 :
3053 362 : if (FanNum == 0) {
3054 0 : DesignHeatGain = 0.0;
3055 362 : } else if (Fan(FanNum).FanType_Num != FanType_ComponentModel) {
3056 362 : DeltaP = Fan(FanNum).DeltaPress;
3057 362 : TotEff = Fan(FanNum).FanEff;
3058 362 : MotEff = Fan(FanNum).MotEff;
3059 362 : MotInAirFrac = Fan(FanNum).MotInAirFrac;
3060 362 : FanPowerTot = (FanVolFlow * DeltaP) / TotEff;
3061 362 : DesignHeatGain = MotEff * FanPowerTot + (FanPowerTot - MotEff * FanPowerTot) * MotInAirFrac;
3062 : } else {
3063 0 : if (!state.dataGlobal->SysSizingCalc && state.dataFans->MySizeFlag(FanNum)) {
3064 0 : SizeFan(state, FanNum);
3065 0 : state.dataFans->MySizeFlag(FanNum) = false;
3066 : }
3067 0 : DesignHeatGain = Fan(FanNum).FanShaftPower + (Fan(FanNum).MotorInputPower - Fan(FanNum).FanShaftPower) * Fan(FanNum).MotInAirFrac;
3068 : }
3069 :
3070 362 : return DesignHeatGain;
3071 :
3072 : } // FanDesHeatGain
3073 :
3074 11856 : void FanInputsForDesHeatGain(EnergyPlusData &state,
3075 : int const fanIndex,
3076 : Real64 &deltaP,
3077 : Real64 &motEff,
3078 : Real64 &totEff,
3079 : Real64 &motInAirFrac,
3080 : Real64 &fanShaftPow,
3081 : Real64 &motInPower,
3082 : bool &fanCompModel)
3083 : {
3084 11856 : deltaP = 0.0;
3085 11856 : motEff = 0.0;
3086 11856 : totEff = 0.0;
3087 11856 : motInAirFrac = 0.0;
3088 11856 : fanShaftPow = 0.0;
3089 11856 : motInPower = 0.0;
3090 11856 : fanCompModel = false;
3091 :
3092 11856 : auto &Fan(state.dataFans->Fan);
3093 :
3094 11856 : if (fanIndex <= 0) {
3095 15 : return;
3096 11841 : } else if (Fan(fanIndex).FanType_Num != FanType_ComponentModel) {
3097 11830 : deltaP = Fan(fanIndex).DeltaPress;
3098 11830 : motEff = Fan(fanIndex).MotEff;
3099 11830 : totEff = Fan(fanIndex).FanEff;
3100 11830 : motInAirFrac = Fan(fanIndex).MotInAirFrac;
3101 : } else {
3102 11 : if (!state.dataGlobal->SysSizingCalc && state.dataFans->MySizeFlag(fanIndex)) {
3103 1 : SizeFan(state, fanIndex);
3104 1 : state.dataFans->MySizeFlag(fanIndex) = false;
3105 : }
3106 11 : fanCompModel = true;
3107 11 : fanShaftPow = Fan(fanIndex).FanShaftPower;
3108 11 : motInPower = Fan(fanIndex).MotorInputPower;
3109 11 : motInAirFrac = Fan(fanIndex).MotInAirFrac;
3110 : }
3111 : }
3112 :
3113 23 : void SetFanAirLoopNumber(EnergyPlusData &state, int const FanIndex, int const AirLoopNum)
3114 : {
3115 23 : state.dataFans->Fan(FanIndex).AirLoopNum = AirLoopNum;
3116 23 : }
3117 :
3118 2313 : } // namespace EnergyPlus::Fans
|