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/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Autosizing/All_Simple_Sizing.hh>
57 : #include <EnergyPlus/Autosizing/CoolingAirFlowSizing.hh>
58 : #include <EnergyPlus/Autosizing/CoolingCapacitySizing.hh>
59 : #include <EnergyPlus/Autosizing/HeatingAirFlowSizing.hh>
60 : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
61 : #include <EnergyPlus/Autosizing/SystemAirFlowSizing.hh>
62 : #include <EnergyPlus/BranchNodeConnections.hh>
63 : #include <EnergyPlus/Data/EnergyPlusData.hh>
64 : #include <EnergyPlus/DataAirSystems.hh>
65 : #include <EnergyPlus/DataEnvironment.hh>
66 : #include <EnergyPlus/DataHVACGlobals.hh>
67 : #include <EnergyPlus/DataHeatBalFanSys.hh>
68 : #include <EnergyPlus/DataHeatBalance.hh>
69 : #include <EnergyPlus/DataLoopNode.hh>
70 : #include <EnergyPlus/DataPrecisionGlobals.hh>
71 : #include <EnergyPlus/DataSizing.hh>
72 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
73 : #include <EnergyPlus/DataZoneEquipment.hh>
74 : #include <EnergyPlus/FanCoilUnits.hh>
75 : #include <EnergyPlus/Fans.hh>
76 : #include <EnergyPlus/FluidProperties.hh>
77 : #include <EnergyPlus/GeneralRoutines.hh>
78 : #include <EnergyPlus/HVACFan.hh>
79 : #include <EnergyPlus/HVACHXAssistedCoolingCoil.hh>
80 : #include <EnergyPlus/HeatingCoils.hh>
81 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
82 : #include <EnergyPlus/MixedAir.hh>
83 : #include <EnergyPlus/NodeInputManager.hh>
84 : #include <EnergyPlus/OutputProcessor.hh>
85 : #include <EnergyPlus/Plant/DataPlant.hh>
86 : #include <EnergyPlus/PlantUtilities.hh>
87 : #include <EnergyPlus/Psychrometrics.hh>
88 : #include <EnergyPlus/ReportCoilSelection.hh>
89 : #include <EnergyPlus/SZVAVModel.hh>
90 : #include <EnergyPlus/ScheduleManager.hh>
91 : #include <EnergyPlus/SingleDuct.hh>
92 : #include <EnergyPlus/UtilityRoutines.hh>
93 : #include <EnergyPlus/WaterCoils.hh>
94 : #include <EnergyPlus/ZoneEquipmentManager.hh>
95 : #include <EnergyPlus/ZonePlenum.hh>
96 :
97 : namespace EnergyPlus {
98 :
99 : namespace FanCoilUnits {
100 :
101 : // Module containing the routines dealing with 2 and 4 pipe fan coil units
102 :
103 : // MODULE INFORMATION:
104 : // AUTHOR Fred Buhl
105 : // DATE WRITTEN March 2000
106 : // MODIFIED October 2003 (FSEC added cooling coil type)
107 : // June 2010 Arnaud Flament LBNL added 3-speed and variables-speed fan capacity control;
108 : // outside air schedule; and removed coil water inlet node inputs
109 : // Sept 2010 Brent Griffith, plant upgrades for water coils, fluid properties
110 : // RE-ENGINEERED na
111 :
112 : // PURPOSE OF THIS MODULE:
113 : // To encapsulate the data and algorithms needed to simulate 2 and 4 pipe
114 : // fan coil units.
115 :
116 : // METHODOLOGY EMPLOYED:
117 : // Units are modeled as a collection of components: outside air mixer,
118 : // fan, heating coil and/or cooling coil plus an integrated control
119 : // algorithm that adjusts the hot or cold water flow to meet the zone
120 : // load. Or varies the air flow rate to meet the zone load. Or both.
121 :
122 : // REFERENCES: none
123 :
124 : // OTHER NOTES: none
125 :
126 : // USE STATEMENTS:
127 : // Use statements for data only modules
128 : // Using/Aliasing
129 : using namespace DataLoopNode;
130 : using namespace DataSizing;
131 : using DataHVACGlobals::ATMixer_InletSide;
132 : using DataHVACGlobals::ATMixer_SupplySide;
133 : using DataHVACGlobals::ATMixerExists;
134 : using DataHVACGlobals::cATMixerTypes;
135 : using DataHVACGlobals::cFanTypes;
136 : using DataHVACGlobals::ContFanCycCoil;
137 : using DataHVACGlobals::CycFanCycCoil;
138 : using DataHVACGlobals::SmallAirVolFlow;
139 : using DataHVACGlobals::SmallLoad;
140 : using DataHVACGlobals::SmallMassFlow;
141 : using namespace ScheduleManager;
142 :
143 514191 : void SimFanCoilUnit(EnergyPlusData &state,
144 : std::string_view CompName, // name of the fan coil unit
145 : int const ControlledZoneNum, // number of zone being served
146 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
147 : Real64 &PowerMet, // Sensible power supplied (W)
148 : Real64 &LatOutputProvided, // Latent add/removal supplied by window AC (kg/s), dehumid = negative
149 : int &CompIndex)
150 : {
151 :
152 : // SUBROUTINE INFORMATION:
153 : // AUTHOR Fred Buhl
154 : // DATE WRITTEN March 2000
155 : // MODIFIED Don Shirey, Aug 2009 (LatOutputProvided)
156 : // RE-ENGINEERED na
157 :
158 : // PURPOSE OF THIS SUBROUTINE:
159 : // Manages the simulation of a fan coil unit. Called from SimZone Equipment
160 :
161 : // Using/Aliasing
162 :
163 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
164 : int FanCoilNum; // index of fan coil unit being simulated
165 :
166 : // First time SimFanCoilUnit is called, get the input for all the fan coil units
167 514191 : if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
168 19 : GetFanCoilUnits(state);
169 19 : state.dataFanCoilUnits->GetFanCoilInputFlag = false;
170 : }
171 :
172 : // Find the correct Fan Coil Equipment
173 514191 : if (CompIndex == 0) {
174 81 : FanCoilNum = UtilityRoutines::FindItemInList(CompName, state.dataFanCoilUnits->FanCoil);
175 81 : if (FanCoilNum == 0) {
176 0 : ShowFatalError(state, "SimFanCoil: Unit not found=" + std::string{CompName});
177 : }
178 81 : CompIndex = FanCoilNum;
179 : } else {
180 514110 : FanCoilNum = CompIndex;
181 514110 : if (FanCoilNum > state.dataFanCoilUnits->NumFanCoils || FanCoilNum < 1) {
182 0 : ShowFatalError(state,
183 0 : format("SimFanCoil: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
184 : FanCoilNum,
185 0 : state.dataFanCoilUnits->NumFanCoils,
186 0 : CompName));
187 : }
188 514110 : if (state.dataFanCoilUnits->CheckEquipName(FanCoilNum)) {
189 81 : if (CompName != state.dataFanCoilUnits->FanCoil(FanCoilNum).Name) {
190 0 : ShowFatalError(state,
191 0 : format("SimFanCoil: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
192 : FanCoilNum,
193 : CompName,
194 0 : state.dataFanCoilUnits->FanCoil(FanCoilNum).Name));
195 : }
196 81 : state.dataFanCoilUnits->CheckEquipName(FanCoilNum) = false;
197 : }
198 : }
199 :
200 514191 : state.dataSize->ZoneEqFanCoil = true;
201 :
202 : // Initialize the fan coil unit
203 514191 : InitFanCoilUnits(state, FanCoilNum, ControlledZoneNum);
204 :
205 : // Select the correct unit type
206 514191 : if (state.dataFanCoilUnits->FanCoil(FanCoilNum).UnitType_Num == FanCoilUnit_4Pipe) {
207 514191 : Sim4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, PowerMet, LatOutputProvided);
208 : }
209 :
210 : // Report the result of the simulation
211 514191 : ReportFanCoilUnit(state, FanCoilNum);
212 :
213 514191 : state.dataSize->ZoneEqFanCoil = false;
214 514191 : }
215 :
216 19 : void GetFanCoilUnits(EnergyPlusData &state)
217 : {
218 :
219 : // SUBROUTINE INFORMATION:
220 : // AUTHOR Fred Buhl
221 : // DATE WRITTEN March 2000
222 : // MODIFIED Bereket Nigusse, FSEC, April 2011: eliminated input node names
223 : // added OA Mixer object type
224 : // and fan object type
225 : // Chandan Sharma, FSEC, July 2012: Added zone sys avail managers
226 : // RE-ENGINEERED na
227 :
228 : // PURPOSE OF THIS SUBROUTINE:
229 : // Obtains input data for fan coil units and stores it in fan coil data structures
230 :
231 : // METHODOLOGY EMPLOYED:
232 : // Uses "Get" routines to read in data.
233 :
234 : // Using/Aliasing
235 : using BranchNodeConnections::SetUpCompSets;
236 : using BranchNodeConnections::TestCompSet;
237 : using Fans::GetFanDesignVolumeFlowRate;
238 : using Fans::GetFanType;
239 :
240 : using NodeInputManager::GetOnlySingleNode;
241 : using WaterCoils::GetCoilWaterInletNode;
242 19 : auto &GetHXCoilWaterInletNode(HVACHXAssistedCoolingCoil::GetCoilWaterInletNode);
243 19 : auto &GetHeatingCoilCapacity(HeatingCoils::GetCoilCapacity);
244 : using DataHVACGlobals::FanType_SimpleConstVolume;
245 : using DataHVACGlobals::FanType_SimpleOnOff;
246 : using DataHVACGlobals::FanType_SimpleVAV;
247 : using HVACHXAssistedCoolingCoil::GetHXCoilTypeAndName;
248 : using MixedAir::GetOAMixerIndex;
249 : using MixedAir::GetOAMixerNodeNumbers;
250 : using SingleDuct::GetATMixer;
251 :
252 : // Locals
253 : // SUBROUTINE ARGUMENT DEFINITIONS:
254 : static constexpr std::string_view RoutineName("GetFanCoilUnits: "); // include trailing blank space
255 :
256 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
257 : int FanCoilIndex; // loop index
258 : int FanCoilNum; // current fan coil number
259 : int NumAlphas; // Number of Alphas for each GetObjectItem call
260 : int NumNumbers; // Number of Numbers for each GetObjectItem call
261 38 : Array1D_int OANodeNums(4); // Node numbers of Outdoor air mixer (OA, EA, RA, MA)
262 : int IOStatus; // Used in GetObjectItem
263 : bool IsNotOK; // Flag to verify name
264 38 : std::string CurrentModuleObject; // Object type for getting and error messages
265 38 : Array1D_string Alphas; // Alpha input items for object
266 38 : Array1D_string cAlphaFields; // Alpha field names
267 38 : Array1D_string cNumericFields; // Numeric field names
268 38 : Array1D<Real64> Numbers; // Numeric input items for object
269 38 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
270 38 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
271 : int NodeNum; // index to loop counter
272 38 : std::string ATMixerName;
273 :
274 19 : auto &FanCoil(state.dataFanCoilUnits->FanCoil);
275 19 : auto &ErrorsFound(state.dataFanCoilUnits->ErrorsFound);
276 19 : auto errFlag(state.dataFanCoilUnits->errFlag);
277 :
278 : // find the number of each type of fan coil unit
279 :
280 19 : CurrentModuleObject = state.dataFanCoilUnits->cMO_FanCoil;
281 19 : state.dataFanCoilUnits->Num4PipeFanCoils = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
282 19 : state.dataFanCoilUnits->NumFanCoils = state.dataFanCoilUnits->Num4PipeFanCoils;
283 : // allocate the data structures
284 19 : state.dataFanCoilUnits->FanCoil.allocate(state.dataFanCoilUnits->NumFanCoils);
285 19 : state.dataFanCoilUnits->FanCoilNumericFields.allocate(state.dataFanCoilUnits->NumFanCoils);
286 19 : state.dataFanCoilUnits->CheckEquipName.dimension(state.dataFanCoilUnits->NumFanCoils, true);
287 :
288 38 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
289 19 : state, CurrentModuleObject, state.dataFanCoilUnits->TotalArgs, NumAlphas, NumNumbers);
290 19 : Alphas.allocate(NumAlphas);
291 19 : cAlphaFields.allocate(NumAlphas);
292 19 : cNumericFields.allocate(NumNumbers);
293 19 : Numbers.dimension(NumNumbers, 0.0);
294 19 : lAlphaBlanks.dimension(NumAlphas, true);
295 19 : lNumericBlanks.dimension(NumNumbers, true);
296 :
297 : // loop over 4 pipe fan coil units; get and load the input data
298 100 : for (FanCoilIndex = 1; FanCoilIndex <= state.dataFanCoilUnits->Num4PipeFanCoils; ++FanCoilIndex) {
299 :
300 81 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
301 : CurrentModuleObject,
302 : FanCoilIndex,
303 : Alphas,
304 : NumAlphas,
305 : Numbers,
306 : NumNumbers,
307 : IOStatus,
308 : lNumericBlanks,
309 : lAlphaBlanks,
310 : cAlphaFields,
311 : cNumericFields);
312 :
313 81 : FanCoilNum = FanCoilIndex;
314 :
315 81 : state.dataFanCoilUnits->FanCoilNumericFields(FanCoilNum).FieldNames.allocate(NumNumbers);
316 81 : state.dataFanCoilUnits->FanCoilNumericFields(FanCoilNum).FieldNames = "";
317 81 : state.dataFanCoilUnits->FanCoilNumericFields(FanCoilNum).FieldNames = cNumericFields;
318 :
319 81 : UtilityRoutines::IsNameEmpty(state, Alphas(1), CurrentModuleObject, ErrorsFound);
320 81 : FanCoil(FanCoilNum).Name = Alphas(1);
321 81 : FanCoil(FanCoilNum).UnitType = CurrentModuleObject;
322 81 : FanCoil(FanCoilNum).UnitType_Num = FanCoilUnit_4Pipe;
323 81 : FanCoil(FanCoilNum).Sched = Alphas(2);
324 81 : if (lAlphaBlanks(2)) {
325 0 : FanCoil(FanCoilNum).SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
326 : } else {
327 81 : FanCoil(FanCoilNum).SchedPtr = GetScheduleIndex(state, Alphas(2)); // convert schedule name to pointer
328 81 : if (FanCoil(FanCoilNum).SchedPtr == 0) {
329 0 : ShowSevereError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + Alphas(1) + "\", invalid");
330 0 : ShowContinueError(state, "invalid-not found: " + cAlphaFields(2) + "=\"" + Alphas(2) + "\".");
331 0 : ErrorsFound = true;
332 : }
333 : }
334 :
335 213 : if (UtilityRoutines::SameString(Alphas(3), "ConstantFanVariableFlow") || UtilityRoutines::SameString(Alphas(3), "CyclingFan") ||
336 93 : UtilityRoutines::SameString(Alphas(3), "VariableFanVariableFlow") ||
337 177 : UtilityRoutines::SameString(Alphas(3), "VariableFanConstantFlow") || UtilityRoutines::SameString(Alphas(3), "MultiSpeedFan") ||
338 84 : UtilityRoutines::SameString(Alphas(3), "ASHRAE90VariableFan")) {
339 81 : FanCoil(FanCoilNum).CapCtrlMeth = Alphas(3);
340 81 : if (UtilityRoutines::SameString(Alphas(3), "ConstantFanVariableFlow")) FanCoil(FanCoilNum).CapCtrlMeth_Num = CCM::ConsFanVarFlow;
341 81 : if (UtilityRoutines::SameString(Alphas(3), "CyclingFan")) FanCoil(FanCoilNum).CapCtrlMeth_Num = CCM::CycFan;
342 81 : if (UtilityRoutines::SameString(Alphas(3), "VariableFanVariableFlow")) FanCoil(FanCoilNum).CapCtrlMeth_Num = CCM::VarFanVarFlow;
343 : ;
344 81 : if (UtilityRoutines::SameString(Alphas(3), "VariableFanConstantFlow")) FanCoil(FanCoilNum).CapCtrlMeth_Num = CCM::VarFanConsFlow;
345 81 : if (UtilityRoutines::SameString(Alphas(3), "MultiSpeedFan")) FanCoil(FanCoilNum).CapCtrlMeth_Num = CCM::MultiSpeedFan;
346 81 : if (UtilityRoutines::SameString(Alphas(3), "ASHRAE90VariableFan")) {
347 3 : FanCoil(FanCoilNum).CapCtrlMeth_Num = CCM::ASHRAE;
348 3 : FanCoil(FanCoilNum).DesZoneCoolingLoad = AutoSize;
349 3 : FanCoil(FanCoilNum).DesZoneHeatingLoad = AutoSize;
350 3 : FanCoil(FanCoilNum).FanOpMode = ContFanCycCoil;
351 : }
352 : } else {
353 0 : ShowSevereError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\", invalid");
354 0 : ShowContinueError(state, "illegal value: " + cAlphaFields(3) + "=\"" + Alphas(3) + "\".");
355 0 : ErrorsFound = true;
356 : }
357 :
358 81 : FanCoil(FanCoilNum).SchedOutAir = Alphas(4);
359 81 : FanCoil(FanCoilNum).SchedOutAirPtr = GetScheduleIndex(state, Alphas(4)); // convert schedule name to pointer
360 81 : if (FanCoil(FanCoilNum).SchedOutAirPtr == 0 && (!lAlphaBlanks(4))) {
361 0 : ShowSevereError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\", invalid");
362 0 : ShowContinueError(state, "illegal value: " + cAlphaFields(4) + "=\"" + Alphas(4) + "\".");
363 0 : ErrorsFound = true;
364 : }
365 81 : FanCoil(FanCoilNum).MaxAirVolFlow = Numbers(1);
366 81 : FanCoil(FanCoilNum).LowSpeedRatio = Numbers(2);
367 81 : FanCoil(FanCoilNum).MedSpeedRatio = Numbers(3);
368 : // check if low speed ratio < medium speed ratio, if not : warning & set to default values
369 81 : if (FanCoil(FanCoilNum).LowSpeedRatio > FanCoil(FanCoilNum).MedSpeedRatio) {
370 0 : ShowWarningError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\",");
371 0 : ShowContinueError(state, "... " + cNumericFields(2) + " is greater than the medium speed supply air flow ratio.");
372 0 : ShowContinueError(state, format("... Fan Coil Unit low speed supply air flow ratio = {:.5T} ", FanCoil(FanCoilNum).LowSpeedRatio));
373 0 : ShowContinueError(state, format("... Fan Coit Unit medium speed supply air flow ratio = {:.5T} ", FanCoil(FanCoilNum).MedSpeedRatio));
374 0 : ShowContinueError(state,
375 : "... Fan Coil Unit low speed supply air flow ratio and medium speed supply air flow ratio set to default values");
376 0 : FanCoil(FanCoilNum).LowSpeedRatio = 1.0 / 3.0;
377 0 : FanCoil(FanCoilNum).MedSpeedRatio = 2.0 / 3.0;
378 : }
379 :
380 81 : FanCoil(FanCoilNum).OutAirVolFlow = Numbers(4);
381 :
382 81 : FanCoil(FanCoilNum).AirInNode = GetOnlySingleNode(state,
383 81 : Alphas(5),
384 : ErrorsFound,
385 : DataLoopNode::ConnectionObjectType::ZoneHVACFourPipeFanCoil,
386 81 : Alphas(1),
387 : DataLoopNode::NodeFluidType::Air,
388 : DataLoopNode::ConnectionType::Inlet,
389 : NodeInputManager::CompFluidStream::Primary,
390 81 : ObjectIsParent); // air input node
391 :
392 81 : FanCoil(FanCoilNum).AirOutNode = GetOnlySingleNode(state,
393 81 : Alphas(6),
394 : ErrorsFound,
395 : DataLoopNode::ConnectionObjectType::ZoneHVACFourPipeFanCoil,
396 81 : Alphas(1),
397 : DataLoopNode::NodeFluidType::Air,
398 : DataLoopNode::ConnectionType::Outlet,
399 : NodeInputManager::CompFluidStream::Primary,
400 81 : ObjectIsParent); // air outlet node
401 :
402 81 : FanCoil(FanCoilNum).OAMixType = Alphas(7);
403 81 : FanCoil(FanCoilNum).OAMixName = Alphas(8);
404 : // check to see if local OA mixer specified
405 81 : if (!lAlphaBlanks(8)) {
406 71 : errFlag = false;
407 71 : ValidateComponent(state, FanCoil(FanCoilNum).OAMixType, FanCoil(FanCoilNum).OAMixName, errFlag, CurrentModuleObject);
408 71 : if (errFlag) {
409 0 : ShowContinueError(state, "specified in " + CurrentModuleObject + " = \"" + FanCoil(FanCoilNum).Name + "\".");
410 0 : ErrorsFound = true;
411 : } else {
412 : // Get outdoor air mixer node numbers
413 71 : OANodeNums = GetOAMixerNodeNumbers(state, FanCoil(FanCoilNum).OAMixName, errFlag);
414 71 : if (errFlag) {
415 0 : ShowContinueError(state, "that was specified in " + CurrentModuleObject + " = " + FanCoil(FanCoilNum).Name);
416 0 : ShowContinueError(state, "..OutdoorAir:Mixer is required. Enter an OutdoorAir:Mixer object with this name.");
417 0 : ErrorsFound = true;
418 : } else {
419 71 : FanCoil(FanCoilNum).OutsideAirNode = OANodeNums(1);
420 71 : FanCoil(FanCoilNum).AirReliefNode = OANodeNums(2);
421 71 : FanCoil(FanCoilNum).MixedAirNode = OANodeNums(4);
422 : }
423 : }
424 : }
425 :
426 81 : FanCoil(FanCoilNum).CCoilName = Alphas(12);
427 81 : FanCoil(FanCoilNum).MaxColdWaterVolFlow = Numbers(5);
428 81 : FanCoil(FanCoilNum).MinColdWaterVolFlow = Numbers(6);
429 81 : FanCoil(FanCoilNum).ColdControlOffset = Numbers(7);
430 81 : FanCoil(FanCoilNum).HCoilName = Alphas(14);
431 81 : FanCoil(FanCoilNum).HCoilType = Alphas(13);
432 81 : FanCoil(FanCoilNum).MaxHotWaterVolFlow = Numbers(8);
433 81 : FanCoil(FanCoilNum).MinHotWaterVolFlow = Numbers(9);
434 81 : FanCoil(FanCoilNum).HotControlOffset = Numbers(10);
435 :
436 162 : if (UtilityRoutines::SameString(Alphas(11), "Coil:Cooling:Water") ||
437 162 : UtilityRoutines::SameString(Alphas(11), "Coil:Cooling:Water:DetailedGeometry") ||
438 81 : UtilityRoutines::SameString(Alphas(11), "CoilSystem:Cooling:Water:HeatExchangerAssisted")) {
439 81 : FanCoil(FanCoilNum).CCoilType = Alphas(11);
440 81 : if (UtilityRoutines::SameString(Alphas(11), "Coil:Cooling:Water")) {
441 81 : FanCoil(FanCoilNum).CCoilType_Num = CCoil::Water;
442 81 : FanCoil(FanCoilNum).CCoilPlantName = FanCoil(FanCoilNum).CCoilName;
443 81 : FanCoil(FanCoilNum).CCoilPlantType = DataPlant::PlantEquipmentType::CoilWaterCooling;
444 : }
445 81 : if (UtilityRoutines::SameString(Alphas(11), "Coil:Cooling:Water:DetailedGeometry")) {
446 0 : FanCoil(FanCoilNum).CCoilType_Num = CCoil::Detailed;
447 0 : FanCoil(FanCoilNum).CCoilPlantName = FanCoil(FanCoilNum).CCoilName;
448 0 : FanCoil(FanCoilNum).CCoilPlantType = DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling;
449 : }
450 81 : if (UtilityRoutines::SameString(Alphas(11), "CoilSystem:Cooling:Water:HeatExchangerAssisted")) {
451 0 : FanCoil(FanCoilNum).CCoilType_Num = CCoil::HXAssist;
452 0 : std::string CCoilType;
453 0 : GetHXCoilTypeAndName(state,
454 0 : FanCoil(FanCoilNum).CCoilType,
455 0 : FanCoil(FanCoilNum).CCoilName,
456 : ErrorsFound,
457 : CCoilType,
458 0 : FanCoil(FanCoilNum).CCoilPlantName);
459 0 : if (UtilityRoutines::SameString(CCoilType, "Coil:Cooling:Water")) {
460 0 : FanCoil(FanCoilNum).CCoilPlantType = DataPlant::PlantEquipmentType::CoilWaterCooling;
461 0 : } else if (UtilityRoutines::SameString(CCoilType, "Coil:Cooling:Water:DetailedGeometry")) {
462 0 : FanCoil(FanCoilNum).CCoilPlantType = DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling;
463 : } else {
464 0 : ShowSevereError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\", invalid");
465 0 : ShowContinueError(state, "For: " + cAlphaFields(11) + "=\"" + Alphas(11) + "\".");
466 0 : ShowContinueError(state, format("Invalid Coil Type={}, Name={}", CCoilType, FanCoil(FanCoilNum).CCoilPlantName));
467 0 : ShowContinueError(state, "must be \"Coil:Cooling:Water\" or \"Coil:Cooling:Water:DetailedGeometry\"");
468 0 : ErrorsFound = true;
469 : }
470 : }
471 81 : IsNotOK = false;
472 81 : ValidateComponent(state, FanCoil(FanCoilNum).CCoilType, FanCoil(FanCoilNum).CCoilName, IsNotOK, FanCoil(FanCoilNum).UnitType);
473 81 : if (IsNotOK) {
474 0 : ShowContinueError(state, "...specified in " + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\".");
475 0 : ErrorsFound = true;
476 : } else {
477 81 : if (FanCoil(FanCoilNum).CCoilType_Num != CCoil::HXAssist) {
478 : // mine the cold water node from the coil object
479 81 : FanCoil(FanCoilNum).CoolCoilFluidInletNode =
480 81 : GetCoilWaterInletNode(state, FanCoil(FanCoilNum).CCoilType, FanCoil(FanCoilNum).CCoilName, IsNotOK);
481 81 : FanCoil(FanCoilNum).CoolCoilInletNodeNum =
482 81 : WaterCoils::GetCoilInletNode(state, FanCoil(FanCoilNum).CCoilType, FanCoil(FanCoilNum).CCoilName, IsNotOK);
483 81 : FanCoil(FanCoilNum).CoolCoilOutletNodeNum =
484 81 : WaterCoils::GetCoilOutletNode(state, FanCoil(FanCoilNum).CCoilType, FanCoil(FanCoilNum).CCoilName, IsNotOK);
485 : } else {
486 0 : FanCoil(FanCoilNum).CoolCoilFluidInletNode =
487 0 : GetHXCoilWaterInletNode(state, FanCoil(FanCoilNum).CCoilType, FanCoil(FanCoilNum).CCoilName, IsNotOK);
488 0 : FanCoil(FanCoilNum).CoolCoilInletNodeNum =
489 0 : HVACHXAssistedCoolingCoil::GetCoilInletNode(state, FanCoil(FanCoilNum).CCoilType, FanCoil(FanCoilNum).CCoilName, IsNotOK);
490 0 : FanCoil(FanCoilNum).CoolCoilOutletNodeNum = HVACHXAssistedCoolingCoil::GetCoilOutletNode(
491 0 : state, FanCoil(FanCoilNum).CCoilType, FanCoil(FanCoilNum).CCoilName, IsNotOK);
492 : }
493 : // Other error checks should trap before it gets to this point in the code, but including just in case.
494 81 : if (IsNotOK) {
495 0 : ShowContinueError(state, "...specified in " + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\".");
496 0 : ErrorsFound = true;
497 : }
498 : }
499 : } else {
500 0 : ShowSevereError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\", invalid");
501 0 : ShowContinueError(state, "illegal value: " + cAlphaFields(11) + "=\"" + Alphas(11) + "\".");
502 0 : ErrorsFound = true;
503 : }
504 :
505 81 : if (UtilityRoutines::SameString(Alphas(13), "Coil:Heating:Water")) {
506 80 : FanCoil(FanCoilNum).HCoilType_Num = HCoil::Water;
507 80 : FanCoil(FanCoilNum).HCoilPlantTypeOf = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
508 80 : IsNotOK = false;
509 80 : ValidateComponent(state, FanCoil(FanCoilNum).HCoilType, FanCoil(FanCoilNum).HCoilName, IsNotOK, CurrentModuleObject);
510 80 : if (IsNotOK) {
511 0 : ShowContinueError(state, "...specified in " + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\".");
512 0 : ErrorsFound = true;
513 : } else {
514 : // mine the hot water node from the coil object
515 80 : FanCoil(FanCoilNum).HeatCoilFluidInletNode =
516 80 : GetCoilWaterInletNode(state, FanCoil(FanCoilNum).HCoilType, FanCoil(FanCoilNum).HCoilName, IsNotOK);
517 80 : FanCoil(FanCoilNum).HeatCoilInletNodeNum =
518 80 : WaterCoils::GetCoilInletNode(state, FanCoil(FanCoilNum).HCoilType, FanCoil(FanCoilNum).HCoilName, IsNotOK);
519 80 : FanCoil(FanCoilNum).HeatCoilOutletNodeNum =
520 80 : WaterCoils::GetCoilOutletNode(state, FanCoil(FanCoilNum).HCoilType, FanCoil(FanCoilNum).HCoilName, IsNotOK);
521 80 : if (IsNotOK) {
522 0 : ShowContinueError(state, "...specified in " + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\".");
523 0 : ErrorsFound = true;
524 : }
525 : }
526 1 : } else if (UtilityRoutines::SameString(Alphas(13), "Coil:Heating:Electric")) {
527 1 : FanCoil(FanCoilNum).HCoilType_Num = HCoil::Electric;
528 1 : IsNotOK = false;
529 1 : ValidateComponent(state, FanCoil(FanCoilNum).HCoilType, FanCoil(FanCoilNum).HCoilName, IsNotOK, CurrentModuleObject);
530 1 : if (IsNotOK) {
531 0 : ShowContinueError(state, "...specified in " + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\".");
532 0 : ErrorsFound = true;
533 : } else {
534 1 : FanCoil(FanCoilNum).DesignHeatingCapacity =
535 1 : GetHeatingCoilCapacity(state, FanCoil(FanCoilNum).HCoilType, FanCoil(FanCoilNum).HCoilName, errFlag);
536 1 : FanCoil(FanCoilNum).HeatCoilInletNodeNum =
537 1 : HeatingCoils::GetCoilInletNode(state, FanCoil(FanCoilNum).HCoilType, FanCoil(FanCoilNum).HCoilName, errFlag);
538 1 : FanCoil(FanCoilNum).HeatCoilOutletNodeNum =
539 1 : HeatingCoils::GetCoilOutletNode(state, FanCoil(FanCoilNum).HCoilType, FanCoil(FanCoilNum).HCoilName, errFlag);
540 1 : if (errFlag) {
541 0 : ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + FanCoil(FanCoilNum).Name);
542 0 : ErrorsFound = true;
543 : }
544 : }
545 : } else {
546 0 : ShowSevereError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\", invalid");
547 0 : ShowContinueError(state, "illegal value: " + cAlphaFields(13) + "=\"" + Alphas(13) + "\".");
548 0 : ErrorsFound = true;
549 : }
550 :
551 81 : FanCoil(FanCoilNum).FanType = Alphas(9);
552 81 : FanCoil(FanCoilNum).FanName = Alphas(10);
553 :
554 81 : if (!lAlphaBlanks(15)) {
555 0 : FanCoil(FanCoilNum).AvailManagerListName = Alphas(15);
556 : }
557 :
558 81 : FanCoil(FanCoilNum).HVACSizingIndex = 0;
559 81 : if (!lAlphaBlanks(16)) {
560 3 : FanCoil(FanCoilNum).HVACSizingIndex = UtilityRoutines::FindItemInList(Alphas(16), state.dataSize->ZoneHVACSizing);
561 3 : if (FanCoil(FanCoilNum).HVACSizingIndex == 0) {
562 0 : ShowSevereError(state, cAlphaFields(16) + " = " + Alphas(16) + " not found.");
563 0 : ShowContinueError(state, "Occurs in " + state.dataFanCoilUnits->cMO_FanCoil + " = " + FanCoil(FanCoilNum).Name);
564 0 : ErrorsFound = true;
565 : }
566 : }
567 :
568 81 : errFlag = false;
569 81 : ValidateComponent(state, FanCoil(FanCoilNum).FanType, FanCoil(FanCoilNum).FanName, errFlag, CurrentModuleObject);
570 81 : if (errFlag) {
571 0 : ShowContinueError(state, "specified in " + CurrentModuleObject + " = \"" + FanCoil(FanCoilNum).Name + "\".");
572 0 : ErrorsFound = true;
573 : } else {
574 81 : if (!UtilityRoutines::SameString(FanCoil(FanCoilNum).FanType, "Fan:SystemModel")) {
575 189 : GetFanType(
576 189 : state, FanCoil(FanCoilNum).FanName, FanCoil(FanCoilNum).FanType_Num, errFlag, CurrentModuleObject, FanCoil(FanCoilNum).Name);
577 : // need to grab fan index here
578 : // Fans::GetFanIndex(state, FanCoil(FanCoilNum).FanName, FanCoil(FanCoilNum).FanIndex, errFlag, FanCoil(FanCoilNum).FanType);
579 63 : FanCoil(FanCoilNum).fanAvailSchIndex =
580 63 : Fans::GetFanAvailSchPtr(state, FanCoil(FanCoilNum).FanType, FanCoil(FanCoilNum).FanName, errFlag);
581 63 : if (errFlag) {
582 0 : ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + FanCoil(FanCoilNum).Name);
583 0 : ErrorsFound = true;
584 0 : errFlag = false;
585 : }
586 63 : switch (FanCoil(FanCoilNum).FanType_Num) {
587 63 : case FanType_SimpleConstVolume:
588 : case FanType_SimpleVAV:
589 : case FanType_SimpleOnOff: {
590 : // Get fan air volume flow rate
591 63 : FanCoil(FanCoilNum).FanAirVolFlow =
592 126 : GetFanDesignVolumeFlowRate(state, FanCoil(FanCoilNum).FanType, FanCoil(FanCoilNum).FanName, IsNotOK);
593 : // Check that the fan volumetric flow rate is greater than or equal to the FCU volumetric flow rate
594 63 : if (FanCoil(FanCoilNum).MaxAirVolFlow > FanCoil(FanCoilNum).FanAirVolFlow && FanCoil(FanCoilNum).FanAirVolFlow != AutoSize) {
595 0 : ShowWarningError(state, std::string{RoutineName} + FanCoil(FanCoilNum).UnitType + ": " + FanCoil(FanCoilNum).Name);
596 0 : ShowContinueError(state, "... " + cNumericFields(1) + " is greater than the maximum fan flow rate.");
597 0 : ShowContinueError(state, format("... Fan Coil Unit flow = {:.5T} m3/s.", FanCoil(FanCoilNum).MaxAirVolFlow));
598 0 : ShowContinueError(state, "... Fan = " + cFanTypes(FanCoil(FanCoilNum).FanType_Num) + ": " + FanCoil(FanCoilNum).FanName);
599 0 : ShowContinueError(state, format("... Fan flow = {:.5T} m3/s.", FanCoil(FanCoilNum).FanAirVolFlow));
600 0 : ShowContinueError(state, "... Fan Coil Unit flow rate reduced to match the fan flow rate and the simulation continues.");
601 0 : FanCoil(FanCoilNum).MaxAirVolFlow = FanCoil(FanCoilNum).FanAirVolFlow;
602 : }
603 :
604 : // Check that the fan type match with the capacity control method selected
605 218 : if ((FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::ConsFanVarFlow && (FanCoil(FanCoilNum).FanType_Num == FanType_SimpleVAV)) ||
606 160 : (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::CycFan && FanCoil(FanCoilNum).FanType_Num != FanType_SimpleOnOff) ||
607 189 : (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::VarFanVarFlow && FanCoil(FanCoilNum).FanType_Num != FanType_SimpleVAV) ||
608 63 : (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::VarFanConsFlow && FanCoil(FanCoilNum).FanType_Num != FanType_SimpleVAV)) {
609 0 : ShowSevereError(state, std::string{RoutineName} + FanCoil(FanCoilNum).UnitType + ": " + FanCoil(FanCoilNum).Name);
610 0 : ShowContinueError(state,
611 0 : "...the fan type of the object : " + FanCoil(FanCoilNum).FanName +
612 0 : " does not match with the capacity control method selected : " + FanCoil(FanCoilNum).CapCtrlMeth +
613 : " please see I/O reference");
614 0 : ShowContinueError(state, "...for ConstantFanVariableFlow a Fan:OnOff or Fan:ConstantVolume is valid.");
615 0 : ShowContinueError(state, "...for CyclingFan a Fan:OnOff is valid.");
616 0 : ShowContinueError(state, "...for VariableFanVariableFlow or VariableFanConstantFlow a Fan:VariableVolume is valid.");
617 0 : ErrorsFound = true;
618 : }
619 63 : } break;
620 0 : default: {
621 0 : ShowSevereError(state, CurrentModuleObject + " = \"" + Alphas(1) + "\"");
622 0 : ShowContinueError(state, "Fan Type must be Fan:OnOff, Fan:ConstantVolume or Fan:VariableVolume.");
623 0 : ErrorsFound = true;
624 0 : } break;
625 : }
626 18 : } else if (UtilityRoutines::SameString(FanCoil(FanCoilNum).FanType, "Fan:SystemModel")) {
627 18 : FanCoil(FanCoilNum).FanType_Num = DataHVACGlobals::FanType_SystemModelObject;
628 18 : state.dataHVACFan->fanObjs.emplace_back(new HVACFan::FanSystem(state, FanCoil(FanCoilNum).FanName)); // call constructor
629 18 : FanCoil(FanCoilNum).FanIndex = HVACFan::getFanObjectVectorIndex(state, FanCoil(FanCoilNum).FanName); // zero-based
630 18 : FanCoil(FanCoilNum).fanAvailSchIndex = state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->availSchedIndex;
631 18 : FanCoil(FanCoilNum).FanAirVolFlow = state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->designAirVolFlowRate;
632 : // Check that the fan volumetric flow rate is greater than or equal to the FCU volumetric flow rate
633 18 : if (FanCoil(FanCoilNum).MaxAirVolFlow > FanCoil(FanCoilNum).FanAirVolFlow && FanCoil(FanCoilNum).FanAirVolFlow != AutoSize) {
634 0 : ShowWarningError(state, std::string{RoutineName} + FanCoil(FanCoilNum).UnitType + ": " + FanCoil(FanCoilNum).Name);
635 0 : ShowContinueError(state, "... " + cNumericFields(1) + " is greater than the maximum fan flow rate.");
636 0 : ShowContinueError(state, format("... Fan Coil Unit flow = {:.5T} m3/s.", FanCoil(FanCoilNum).MaxAirVolFlow));
637 0 : ShowContinueError(state, "... Fan = " + cFanTypes(FanCoil(FanCoilNum).FanType_Num) + ": " + FanCoil(FanCoilNum).FanName);
638 0 : ShowContinueError(state, format("... Fan flow = {:.5T} m3/s.", FanCoil(FanCoilNum).FanAirVolFlow));
639 0 : ShowContinueError(state, "... Fan Coil Unit flow rate reduced to match the fan flow rate and the simulation continues.");
640 0 : FanCoil(FanCoilNum).MaxAirVolFlow = FanCoil(FanCoilNum).FanAirVolFlow;
641 : }
642 :
643 : // check that for VariableFanVariableFlow or VariableFanConstantFlow that the fan speed control is continuous
644 36 : if (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::VarFanVarFlow || FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::VarFanConsFlow ||
645 18 : FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::ASHRAE) { // then expect continuous speed control fan
646 3 : if (state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->speedControl !=
647 : HVACFan::FanSystem::SpeedControlMethod::Continuous) {
648 0 : ShowSevereError(state, std::string{RoutineName} + FanCoil(FanCoilNum).UnitType + ": " + FanCoil(FanCoilNum).Name);
649 0 : ShowContinueError(state,
650 0 : "...the fan type of the object : " + FanCoil(FanCoilNum).FanName +
651 0 : " does not match with the capacity control method selected : " + FanCoil(FanCoilNum).CapCtrlMeth +
652 : " please see I/O reference");
653 0 : ShowContinueError(
654 : state,
655 : "...for VariableFanVariableFlow or VariableFanConstantFlow a Fan:SystemModel should have Continuous speed control.");
656 0 : ErrorsFound = true;
657 : }
658 : }
659 : }
660 : }
661 :
662 : // check low speed fan ratio when using ASHRAE90.1 capacity control method
663 81 : if (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::ASHRAE) {
664 3 : if (FanCoil(FanCoilNum).LowSpeedRatio > 0.5) {
665 0 : ShowWarningError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\",");
666 0 : ShowContinueError(state, "... " + cNumericFields(2) + " is greater than the 50% of the supply air flow ratio.");
667 0 : ShowContinueError(state,
668 0 : format("... Fan Coil Unit low speed supply air flow ratio = {:.5T} ", FanCoil(FanCoilNum).LowSpeedRatio));
669 3 : } else if (FanCoil(FanCoilNum).LowSpeedRatio == 0.0) {
670 0 : ShowWarningError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\",");
671 0 : ShowContinueError(state, "... " + cNumericFields(2) + " is equal to 0.");
672 0 : ShowContinueError(state, "... Fan Coil Unit low speed supply air flow ratio should be greater than 0 to comply with ASHRAE90.1.");
673 0 : ShowContinueError(state, "... Fan Coil Unit low speed supply air flow ratio set to 0.5");
674 0 : FanCoil(FanCoilNum).LowSpeedRatio = 0.5;
675 : }
676 : }
677 :
678 : // Set defaults for convergence tolerance
679 81 : if (FanCoil(FanCoilNum).ColdControlOffset <= 0.0) {
680 0 : FanCoil(FanCoilNum).ColdControlOffset = 0.001;
681 : }
682 81 : if (FanCoil(FanCoilNum).HotControlOffset <= 0.0) {
683 0 : FanCoil(FanCoilNum).HotControlOffset = 0.001;
684 : }
685 :
686 : // check for inlet side air mixer
687 567 : GetATMixer(state,
688 81 : FanCoil(FanCoilNum).Name,
689 : ATMixerName,
690 81 : state.dataFanCoilUnits->ATMixerNum,
691 81 : state.dataFanCoilUnits->ATMixerType,
692 81 : state.dataFanCoilUnits->ATMixerPriNode,
693 81 : state.dataFanCoilUnits->ATMixerSecNode,
694 81 : state.dataFanCoilUnits->ATMixerOutNode,
695 81 : FanCoil(FanCoilNum).AirOutNode);
696 81 : FanCoil(FanCoilNum).ControlZoneNum =
697 81 : DataZoneEquipment::GetZoneEquipControlledZoneNum(state, DataZoneEquipment::ZoneEquip::FanCoil4Pipe, FanCoil(FanCoilNum).Name);
698 81 : if (FanCoil(FanCoilNum).ControlZoneNum == 0) {
699 0 : ErrorsFound = true;
700 : }
701 81 : if (state.dataFanCoilUnits->ATMixerType == ATMixer_InletSide) {
702 : // save the air terminal mixer data in the fan coil data array
703 5 : FanCoil(FanCoilNum).ATMixerExists = true;
704 5 : FanCoil(FanCoilNum).ATMixerIndex = state.dataFanCoilUnits->ATMixerNum;
705 5 : FanCoil(FanCoilNum).ATMixerName = ATMixerName;
706 5 : FanCoil(FanCoilNum).ATMixerType = ATMixer_InletSide;
707 5 : FanCoil(FanCoilNum).ATMixerPriNode = state.dataFanCoilUnits->ATMixerPriNode;
708 5 : FanCoil(FanCoilNum).ATMixerSecNode = state.dataFanCoilUnits->ATMixerSecNode;
709 5 : FanCoil(FanCoilNum).ATMixerOutNode = state.dataFanCoilUnits->ATMixerOutNode;
710 : // check that fan coil doesn' have local outside air
711 5 : if (!lAlphaBlanks(8)) {
712 0 : ShowSevereError(state,
713 0 : CurrentModuleObject + " = \"" + FanCoil(FanCoilNum).Name +
714 : "\". Fan coil unit has local as well as central outdoor air specified");
715 : }
716 : // check that the air teminal mixer out node is the fan coil inlet node
717 5 : if (FanCoil(FanCoilNum).AirInNode != state.dataFanCoilUnits->ATMixerOutNode) {
718 0 : ShowSevereError(state,
719 0 : CurrentModuleObject + " = \"" + FanCoil(FanCoilNum).Name +
720 : "\". Fan coil unit air inlet node name must be the same as an air terminal mixer outlet node name.");
721 0 : ShowContinueError(state, "..Air terminal mixer outlet node name is specified in AirTerminal:SingleDuct:InletSideMixer object.");
722 0 : ShowContinueError(state, "..Fan coil unit air inlet node name = " + state.dataLoopNodes->NodeID(FanCoil(FanCoilNum).AirInNode));
723 0 : ErrorsFound = true;
724 : }
725 : // check for supply side air terminal mixer
726 76 : } else if (state.dataFanCoilUnits->ATMixerType == ATMixer_SupplySide) {
727 : // save the air terminal mixer data in the fan coil data array
728 5 : FanCoil(FanCoilNum).ATMixerExists = true;
729 5 : FanCoil(FanCoilNum).ATMixerIndex = state.dataFanCoilUnits->ATMixerNum;
730 5 : FanCoil(FanCoilNum).ATMixerName = ATMixerName;
731 5 : FanCoil(FanCoilNum).ATMixerType = ATMixer_SupplySide;
732 5 : FanCoil(FanCoilNum).ATMixerPriNode = state.dataFanCoilUnits->ATMixerPriNode;
733 5 : FanCoil(FanCoilNum).ATMixerSecNode = state.dataFanCoilUnits->ATMixerSecNode;
734 5 : FanCoil(FanCoilNum).ATMixerOutNode = state.dataFanCoilUnits->ATMixerOutNode;
735 : // check that fan coil doesn' have local outside air
736 5 : if (!lAlphaBlanks(8)) {
737 0 : ShowSevereError(state,
738 0 : CurrentModuleObject + " = \"" + FanCoil(FanCoilNum).Name +
739 : "\". Fan coil unit has local as well as central outdoor air specified");
740 : }
741 : // check that the air teminal mixer secondary air inlet node is the fan coil outlet node
742 5 : if (FanCoil(FanCoilNum).AirOutNode != state.dataFanCoilUnits->ATMixerSecNode) {
743 0 : ShowSevereError(
744 : state,
745 0 : CurrentModuleObject + " = \"" + FanCoil(FanCoilNum).Name +
746 : "\". Fan coil unit air outlet node name must be the same as the air terminal mixer secondary air inlet node name.");
747 0 : ShowContinueError(
748 : state, "..Air terminal mixer secondary inlet node name is specified in AirTerminal:SingleDuct:SupplySideMixer object.");
749 0 : ShowContinueError(state, "..Fan coil unit air outlet node name = " + state.dataLoopNodes->NodeID(FanCoil(FanCoilNum).AirOutNode));
750 0 : ErrorsFound = true;
751 : }
752 5 : bool ZoneNodeNotFound = true;
753 5 : for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(FanCoil(FanCoilNum).ControlZoneNum).NumExhaustNodes; ++NodeNum) {
754 10 : if (FanCoil(FanCoilNum).AirInNode ==
755 5 : state.dataZoneEquip->ZoneEquipConfig(FanCoil(FanCoilNum).ControlZoneNum).ExhaustNode(NodeNum)) {
756 5 : ZoneNodeNotFound = false;
757 5 : break;
758 : }
759 : }
760 5 : if (ZoneNodeNotFound) {
761 0 : bool InletNodeFound = false;
762 0 : if (FanCoil(FanCoilNum).ControlZoneNum > 0) {
763 0 : InletNodeFound =
764 0 : ZonePlenum::ValidateInducedNode(state,
765 0 : FanCoil(FanCoilNum).AirInNode,
766 0 : state.dataZoneEquip->ZoneEquipConfig(FanCoil(FanCoilNum).ControlZoneNum).NumReturnNodes,
767 0 : state.dataZoneEquip->ZoneEquipConfig(FanCoil(FanCoilNum).ControlZoneNum).ReturnNode);
768 : }
769 0 : if (!InletNodeFound) {
770 0 : ShowSevereError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\"");
771 0 : ShowContinueError(state,
772 : "..FanCoil inlet node name must be the same as either a zone exhaust node name or an induced "
773 : "air node in ZonePlenum.");
774 0 : ShowContinueError(state, "..Zone exhaust node name is specified in ZoneHVAC:EquipmentConnections object.");
775 0 : ShowContinueError(state, "..Induced Air Outlet Node name is specified in AirLoopHVAC:ReturnPlenum object.");
776 0 : ShowContinueError(state, "..FanCoil inlet node name = " + state.dataLoopNodes->NodeID(FanCoil(FanCoilNum).AirInNode));
777 0 : ErrorsFound = true;
778 : }
779 : }
780 : // no air terminal mixer; do the normal connectivity checks
781 : } else {
782 : // check that the fan coil inlet node is the same as one of the zone exhaust nodes
783 71 : state.dataFanCoilUnits->ZoneExNodeNotFound = true;
784 71 : for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(FanCoil(FanCoilNum).ControlZoneNum).NumExhaustNodes; ++NodeNum) {
785 142 : if (FanCoil(FanCoilNum).AirInNode ==
786 71 : state.dataZoneEquip->ZoneEquipConfig(FanCoil(FanCoilNum).ControlZoneNum).ExhaustNode(NodeNum)) {
787 71 : state.dataFanCoilUnits->ZoneExNodeNotFound = false;
788 71 : break;
789 : }
790 : }
791 71 : if (state.dataFanCoilUnits->ZoneExNodeNotFound) {
792 0 : bool InletNodeFound = false;
793 0 : InletNodeFound =
794 0 : ZonePlenum::ValidateInducedNode(state,
795 0 : FanCoil(FanCoilNum).AirInNode,
796 0 : state.dataZoneEquip->ZoneEquipConfig(FanCoil(FanCoilNum).ControlZoneNum).NumReturnNodes,
797 0 : state.dataZoneEquip->ZoneEquipConfig(FanCoil(FanCoilNum).ControlZoneNum).ReturnNode);
798 :
799 0 : if (!InletNodeFound) {
800 0 : ShowSevereError(state,
801 0 : CurrentModuleObject + " = \"" + FanCoil(FanCoilNum).Name +
802 : "\". Fan coil unit air inlet node name must be the same either as a zone exhaust node name or an induce "
803 : "air node in ZoePlenum.");
804 0 : ShowContinueError(state, "..Zone exhaust node name is specified in ZoneHVAC:EquipmentConnections object.");
805 0 : ShowContinueError(state, "..Induced Air Outlet Node name is specified in AirLoopHVAC:ReturnPlenum object.");
806 0 : ShowContinueError(state,
807 0 : "..Fan coil unit air inlet node name = " + state.dataLoopNodes->NodeID(FanCoil(FanCoilNum).AirInNode));
808 0 : ErrorsFound = true;
809 : }
810 : }
811 : // check that the fan coil outlet node is the same as one of the zone inlet nodes
812 71 : state.dataFanCoilUnits->ZoneInNodeNotFound = true;
813 71 : if (FanCoil(FanCoilNum).ControlZoneNum > 0) {
814 71 : FanCoil(FanCoilNum).NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(FanCoil(FanCoilNum).ControlZoneNum).ZoneNode;
815 71 : state.dataFanCoilUnits->ZoneInNodeNotFound = false;
816 : }
817 :
818 71 : if (state.dataFanCoilUnits->ZoneInNodeNotFound) {
819 0 : ShowSevereError(state,
820 0 : CurrentModuleObject + " = \"" + FanCoil(FanCoilNum).Name +
821 : "\". Fan coil unit air outlet node name must be the same as a zone inlet node name.");
822 0 : ShowContinueError(state, "..Zone inlet node name is specified in ZoneHVAC:EquipmentConnections object.");
823 0 : ShowContinueError(state, "..Fan coil unit air outlet node name = " + state.dataLoopNodes->NodeID(FanCoil(FanCoilNum).AirOutNode));
824 :
825 0 : ErrorsFound = true;
826 : }
827 : }
828 81 : if (FanCoil(FanCoilNum).CapCtrlMeth == "MULTISPEEDFAN") {
829 3 : if (!lAlphaBlanks(17)) {
830 2 : FanCoil(FanCoilNum).FanOpModeSchedPtr = GetScheduleIndex(state, Alphas(17));
831 4 : if (FanCoil(FanCoilNum).FanType_Num != FanType_SimpleOnOff &&
832 2 : FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
833 0 : ShowSevereError(state, CurrentModuleObject + " = " + FanCoil(FanCoilNum).Name);
834 0 : ShowContinueError(state, "For " + cAlphaFields(17) + " = " + Alphas(17));
835 0 : ShowContinueError(state, "Illegal " + cAlphaFields(9) + " = " + Alphas(9));
836 0 : ShowContinueError(state, "...fan operating schedule is allowed for on off or system model fan type only )");
837 0 : ErrorsFound = true;
838 : } else {
839 2 : if (FanCoil(FanCoilNum).FanOpModeSchedPtr == 0) {
840 0 : ShowSevereError(state, CurrentModuleObject + " = " + FanCoil(FanCoilNum).Name);
841 0 : ShowContinueError(state, "Illegal " + cAlphaFields(17) + " = " + Alphas(17));
842 0 : ErrorsFound = true;
843 : }
844 : }
845 : } else {
846 2 : if (FanCoil(FanCoilNum).FanType_Num == FanType_SimpleOnOff ||
847 1 : FanCoil(FanCoilNum).FanType_Num == DataHVACGlobals::FanType_SystemModelObject) {
848 1 : FanCoil(FanCoilNum).FanOpMode = CycFanCycCoil;
849 : }
850 : }
851 : }
852 :
853 81 : if (!lNumericBlanks(11)) {
854 0 : FanCoil(FanCoilNum).DesignMinOutletTemp = Numbers(11);
855 0 : if (lNumericBlanks(12)) {
856 0 : ShowWarningError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\",");
857 0 : ShowContinueError(state, "... " + cNumericFields(11) + " and " + cNumericFields(12) + " must be used in unison.");
858 0 : ErrorsFound = true;
859 : }
860 : }
861 :
862 81 : if (!lNumericBlanks(12)) {
863 0 : FanCoil(FanCoilNum).DesignMaxOutletTemp = Numbers(12);
864 0 : if (FanCoil(FanCoilNum).DesignMinOutletTemp != AutoSize && FanCoil(FanCoilNum).DesignMaxOutletTemp != AutoSize) {
865 0 : if (FanCoil(FanCoilNum).DesignMaxOutletTemp < FanCoil(FanCoilNum).DesignMinOutletTemp) {
866 0 : ShowWarningError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\",");
867 0 : ShowContinueError(state, "... " + cNumericFields(11) + " is greater than " + cNumericFields(12) + ".");
868 0 : ShowContinueError(state, format("... {} = {:.2T} [C].", cNumericFields(11), FanCoil(FanCoilNum).DesignMinOutletTemp));
869 0 : ShowContinueError(state, format("... {} = {:.2T} [C].", cNumericFields(12), FanCoil(FanCoilNum).DesignMaxOutletTemp));
870 0 : ErrorsFound = true;
871 : }
872 : }
873 0 : if (lNumericBlanks(11)) {
874 0 : ShowWarningError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + FanCoil(FanCoilNum).Name + "\",");
875 0 : ShowContinueError(state, "... " + cNumericFields(11) + " and " + cNumericFields(12) + " must be used in unison.");
876 0 : ErrorsFound = true;
877 : }
878 : }
879 :
880 81 : if (FanCoil(FanCoilNum).DesignMinOutletTemp > 0.0 && FanCoil(FanCoilNum).DesignMaxOutletTemp > 0.0) {
881 0 : FanCoil(FanCoilNum).ASHRAETempControl = true;
882 81 : } else if (FanCoil(FanCoilNum).DesignMinOutletTemp == AutoSize || FanCoil(FanCoilNum).DesignMaxOutletTemp == AutoSize) {
883 0 : FanCoil(FanCoilNum).ASHRAETempControl = true;
884 : }
885 :
886 : // Set up component set for supply fan
887 81 : if (FanCoil(FanCoilNum).OutsideAirNode > 0) {
888 355 : SetUpCompSets(state,
889 71 : FanCoil(FanCoilNum).UnitType,
890 71 : FanCoil(FanCoilNum).Name,
891 71 : FanCoil(FanCoilNum).FanType,
892 71 : FanCoil(FanCoilNum).FanName,
893 71 : state.dataLoopNodes->NodeID(FanCoil(FanCoilNum).MixedAirNode),
894 71 : "UNDEFINED");
895 : } else {
896 50 : SetUpCompSets(state,
897 10 : FanCoil(FanCoilNum).UnitType,
898 10 : FanCoil(FanCoilNum).Name,
899 10 : FanCoil(FanCoilNum).FanType,
900 10 : FanCoil(FanCoilNum).FanName,
901 10 : state.dataLoopNodes->NodeID(FanCoil(FanCoilNum).AirInNode),
902 10 : "UNDEFINED");
903 : }
904 : // Set up component set for cooling coil
905 324 : SetUpCompSets(state,
906 81 : FanCoil(FanCoilNum).UnitType,
907 81 : FanCoil(FanCoilNum).Name,
908 81 : FanCoil(FanCoilNum).CCoilType,
909 81 : FanCoil(FanCoilNum).CCoilName,
910 : "UNDEFINED",
911 81 : "UNDEFINED");
912 :
913 : // Set up component set for heating coil
914 405 : SetUpCompSets(state,
915 81 : FanCoil(FanCoilNum).UnitType,
916 81 : FanCoil(FanCoilNum).Name,
917 81 : FanCoil(FanCoilNum).HCoilType,
918 81 : FanCoil(FanCoilNum).HCoilName,
919 : "UNDEFINED",
920 162 : state.dataLoopNodes->NodeID(FanCoil(FanCoilNum).AirOutNode));
921 :
922 : // Set up component set for OA mixer - use OA node and Mixed air node
923 81 : if (FanCoil(FanCoilNum).OutsideAirNode > 0) {
924 426 : SetUpCompSets(state,
925 71 : FanCoil(FanCoilNum).UnitType,
926 71 : FanCoil(FanCoilNum).Name,
927 71 : FanCoil(FanCoilNum).OAMixType,
928 71 : FanCoil(FanCoilNum).OAMixName,
929 71 : state.dataLoopNodes->NodeID(FanCoil(FanCoilNum).OutsideAirNode),
930 71 : state.dataLoopNodes->NodeID(FanCoil(FanCoilNum).MixedAirNode));
931 : }
932 : }
933 :
934 19 : Alphas.deallocate();
935 19 : cAlphaFields.deallocate();
936 19 : cNumericFields.deallocate();
937 19 : Numbers.deallocate();
938 19 : lAlphaBlanks.deallocate();
939 19 : lNumericBlanks.deallocate();
940 :
941 19 : if (ErrorsFound) {
942 0 : ShowFatalError(state, std::string{RoutineName} + "Errors found in input. Preceding condition(s) cause termination.");
943 : }
944 :
945 100 : for (FanCoilNum = 1; FanCoilNum <= state.dataFanCoilUnits->NumFanCoils; ++FanCoilNum) {
946 : // Setup Report variables for the Fan Coils
947 : // CurrentModuleObject='ZoneHVAC:FourPipeFanCoil'
948 324 : SetupOutputVariable(state,
949 : "Fan Coil Heating Rate",
950 : OutputProcessor::Unit::W,
951 81 : FanCoil(FanCoilNum).HeatPower,
952 : OutputProcessor::SOVTimeStepType::System,
953 : OutputProcessor::SOVStoreType::Average,
954 162 : FanCoil(FanCoilNum).Name);
955 324 : SetupOutputVariable(state,
956 : "Fan Coil Heating Energy",
957 : OutputProcessor::Unit::J,
958 81 : FanCoil(FanCoilNum).HeatEnergy,
959 : OutputProcessor::SOVTimeStepType::System,
960 : OutputProcessor::SOVStoreType::Summed,
961 162 : FanCoil(FanCoilNum).Name);
962 324 : SetupOutputVariable(state,
963 : "Fan Coil Total Cooling Rate",
964 : OutputProcessor::Unit::W,
965 81 : FanCoil(FanCoilNum).TotCoolPower,
966 : OutputProcessor::SOVTimeStepType::System,
967 : OutputProcessor::SOVStoreType::Average,
968 162 : FanCoil(FanCoilNum).Name);
969 324 : SetupOutputVariable(state,
970 : "Fan Coil Total Cooling Energy",
971 : OutputProcessor::Unit::J,
972 81 : FanCoil(FanCoilNum).TotCoolEnergy,
973 : OutputProcessor::SOVTimeStepType::System,
974 : OutputProcessor::SOVStoreType::Summed,
975 162 : FanCoil(FanCoilNum).Name);
976 324 : SetupOutputVariable(state,
977 : "Fan Coil Sensible Cooling Rate",
978 : OutputProcessor::Unit::W,
979 81 : FanCoil(FanCoilNum).SensCoolPower,
980 : OutputProcessor::SOVTimeStepType::System,
981 : OutputProcessor::SOVStoreType::Average,
982 162 : FanCoil(FanCoilNum).Name);
983 324 : SetupOutputVariable(state,
984 : "Fan Coil Sensible Cooling Energy",
985 : OutputProcessor::Unit::J,
986 81 : FanCoil(FanCoilNum).SensCoolEnergy,
987 : OutputProcessor::SOVTimeStepType::System,
988 : OutputProcessor::SOVStoreType::Summed,
989 162 : FanCoil(FanCoilNum).Name);
990 324 : SetupOutputVariable(state,
991 : "Fan Coil Fan Electricity Rate",
992 : OutputProcessor::Unit::W,
993 81 : FanCoil(FanCoilNum).ElecPower,
994 : OutputProcessor::SOVTimeStepType::System,
995 : OutputProcessor::SOVStoreType::Average,
996 162 : FanCoil(FanCoilNum).Name);
997 324 : SetupOutputVariable(state,
998 : "Fan Coil Fan Electricity Energy",
999 : OutputProcessor::Unit::J,
1000 81 : FanCoil(FanCoilNum).ElecEnergy,
1001 : OutputProcessor::SOVTimeStepType::System,
1002 : OutputProcessor::SOVStoreType::Summed,
1003 162 : FanCoil(FanCoilNum).Name);
1004 81 : if (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::CycFan || FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::MultiSpeedFan) {
1005 168 : SetupOutputVariable(state,
1006 : "Fan Coil Runtime Fraction",
1007 : OutputProcessor::Unit::None,
1008 42 : FanCoil(FanCoilNum).PLR,
1009 : OutputProcessor::SOVTimeStepType::System,
1010 : OutputProcessor::SOVStoreType::Average,
1011 84 : FanCoil(FanCoilNum).Name);
1012 168 : SetupOutputVariable(state,
1013 : "Fan Coil Fan Speed Level",
1014 : OutputProcessor::Unit::None,
1015 42 : FanCoil(FanCoilNum).SpeedFanSel,
1016 : OutputProcessor::SOVTimeStepType::System,
1017 : OutputProcessor::SOVStoreType::Average,
1018 84 : FanCoil(FanCoilNum).Name);
1019 42 : if (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::MultiSpeedFan) {
1020 12 : SetupOutputVariable(state,
1021 : "Fan Coil Speed Ratio",
1022 : OutputProcessor::Unit::None,
1023 3 : FanCoil(FanCoilNum).SpeedRatio,
1024 : OutputProcessor::SOVTimeStepType::System,
1025 : OutputProcessor::SOVStoreType::Average,
1026 6 : FanCoil(FanCoilNum).Name);
1027 12 : SetupOutputVariable(state,
1028 : "Fan Coil Part Load Ratio",
1029 : OutputProcessor::Unit::None,
1030 3 : FanCoil(FanCoilNum).PLR,
1031 : OutputProcessor::SOVTimeStepType::System,
1032 : OutputProcessor::SOVStoreType::Average,
1033 6 : FanCoil(FanCoilNum).Name);
1034 : }
1035 : }
1036 81 : if (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::VarFanVarFlow || FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::VarFanConsFlow) {
1037 0 : SetupOutputVariable(state,
1038 : "Fan Coil Part Load Ratio",
1039 : OutputProcessor::Unit::None,
1040 0 : FanCoil(FanCoilNum).PLR,
1041 : OutputProcessor::SOVTimeStepType::System,
1042 : OutputProcessor::SOVStoreType::Average,
1043 0 : FanCoil(FanCoilNum).Name);
1044 : }
1045 324 : SetupOutputVariable(state,
1046 : "Fan Coil Availability Status",
1047 : OutputProcessor::Unit::None,
1048 81 : FanCoil(FanCoilNum).AvailStatus,
1049 : OutputProcessor::SOVTimeStepType::System,
1050 : OutputProcessor::SOVStoreType::Average,
1051 162 : FanCoil(FanCoilNum).Name);
1052 : }
1053 :
1054 100 : for (FanCoilNum = 1; FanCoilNum <= state.dataFanCoilUnits->NumFanCoils; ++FanCoilNum) {
1055 81 : if (FanCoil(FanCoilNum).FanType_Num == DataHVACGlobals::FanType_SystemModelObject) {
1056 90 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilSupplyFanInfo(state,
1057 18 : FanCoil(FanCoilNum).CCoilName,
1058 18 : FanCoil(FanCoilNum).CCoilType,
1059 18 : FanCoil(FanCoilNum).FanName,
1060 : DataAirSystems::ObjectVectorOOFanSystemModel,
1061 18 : FanCoil(FanCoilNum).FanIndex);
1062 90 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilSupplyFanInfo(state,
1063 18 : FanCoil(FanCoilNum).HCoilName,
1064 18 : FanCoil(FanCoilNum).HCoilType,
1065 18 : FanCoil(FanCoilNum).FanName,
1066 : DataAirSystems::ObjectVectorOOFanSystemModel,
1067 18 : FanCoil(FanCoilNum).FanIndex);
1068 : } else {
1069 315 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilSupplyFanInfo(state,
1070 63 : FanCoil(FanCoilNum).CCoilName,
1071 63 : FanCoil(FanCoilNum).CCoilType,
1072 63 : FanCoil(FanCoilNum).FanName,
1073 : DataAirSystems::StructArrayLegacyFanModels,
1074 63 : FanCoil(FanCoilNum).FanIndex);
1075 315 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilSupplyFanInfo(state,
1076 63 : FanCoil(FanCoilNum).HCoilName,
1077 63 : FanCoil(FanCoilNum).HCoilType,
1078 63 : FanCoil(FanCoilNum).FanName,
1079 : DataAirSystems::StructArrayLegacyFanModels,
1080 63 : FanCoil(FanCoilNum).FanIndex);
1081 : }
1082 : }
1083 19 : }
1084 :
1085 514191 : void InitFanCoilUnits(EnergyPlusData &state,
1086 : int const FanCoilNum, // number of the current fan coil unit being simulated
1087 : int const ControlledZoneNum // number of zone being served
1088 : )
1089 : {
1090 :
1091 : // SUBROUTINE INFORMATION:
1092 : // AUTHOR Fred Buhl
1093 : // DATE WRITTEN March 2000
1094 : // MODIFIED July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
1095 : // RE-ENGINEERED na
1096 :
1097 : // PURPOSE OF THIS SUBROUTINE:
1098 : // This subroutine is for initializations of the Fan Coil Components.
1099 :
1100 : // METHODOLOGY EMPLOYED:
1101 : // Uses the status flags to trigger initializations.
1102 :
1103 : // Using/Aliasing
1104 514191 : auto &ZoneComp = state.dataHVACGlobal->ZoneComp;
1105 : using DataZoneEquipment::CheckZoneEquipmentList;
1106 : using FluidProperties::GetDensityGlycol;
1107 : using PlantUtilities::InitComponentNodes;
1108 : using PlantUtilities::ScanPlantLoopsForObject;
1109 : using Psychrometrics::PsyRhoAirFnPbTdbW;
1110 :
1111 : // SUBROUTINE PARAMETER DEFINITIONS:
1112 : static constexpr std::string_view RoutineName("InitFanCoilUnits");
1113 :
1114 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1115 : int InNode; // inlet node number in fan coil loop
1116 : int OutNode; // outlet node number in fan coil loop
1117 : int InletNode; // inlet node number for fan coil FanCoilNum
1118 : int HotConNode; // hot water control node number in fan coil loop
1119 : int ColdConNode; // hot water control node number in fan coil loop
1120 : int OutsideAirNode; // outside air node number in fan coil loop
1121 : int AirRelNode; // relief air node number in fan coil loop
1122 : Real64 RhoAir; // air density at InNode
1123 : int Loop;
1124 : Real64 rho;
1125 : bool errFlag;
1126 :
1127 514191 : auto &FanCoil(state.dataFanCoilUnits->FanCoil);
1128 :
1129 : // Do the one time initializations
1130 514191 : if (state.dataFanCoilUnits->InitFanCoilUnitsOneTimeFlag) {
1131 :
1132 19 : state.dataFanCoilUnits->MyEnvrnFlag.allocate(state.dataFanCoilUnits->NumFanCoils);
1133 19 : state.dataFanCoilUnits->MySizeFlag.allocate(state.dataFanCoilUnits->NumFanCoils);
1134 19 : state.dataFanCoilUnits->MyPlantScanFlag.allocate(state.dataFanCoilUnits->NumFanCoils);
1135 19 : state.dataFanCoilUnits->MyZoneEqFlag.allocate(state.dataFanCoilUnits->NumFanCoils);
1136 19 : state.dataFanCoilUnits->MyEnvrnFlag = true;
1137 19 : state.dataFanCoilUnits->MySizeFlag = true;
1138 19 : state.dataFanCoilUnits->MyPlantScanFlag = true;
1139 19 : state.dataFanCoilUnits->MyZoneEqFlag = true;
1140 19 : state.dataFanCoilUnits->InitFanCoilUnitsOneTimeFlag = false;
1141 : }
1142 :
1143 514191 : if (allocated(ZoneComp)) {
1144 514191 : if (state.dataFanCoilUnits->MyZoneEqFlag(FanCoilNum)) { // initialize the name of each availability manager list and zone number
1145 162 : ZoneComp(DataZoneEquipment::ZoneEquip::FanCoil4Pipe).ZoneCompAvailMgrs(FanCoilNum).AvailManagerListName =
1146 162 : FanCoil(FanCoilNum).AvailManagerListName;
1147 81 : ZoneComp(DataZoneEquipment::ZoneEquip::FanCoil4Pipe).ZoneCompAvailMgrs(FanCoilNum).ZoneNum = ControlledZoneNum;
1148 81 : state.dataFanCoilUnits->MyZoneEqFlag(FanCoilNum) = false;
1149 : }
1150 514191 : FanCoil(FanCoilNum).AvailStatus = ZoneComp(DataZoneEquipment::ZoneEquip::FanCoil4Pipe).ZoneCompAvailMgrs(FanCoilNum).AvailStatus;
1151 : }
1152 :
1153 514191 : if (state.dataFanCoilUnits->MyPlantScanFlag(FanCoilNum) && allocated(state.dataPlnt->PlantLoop)) {
1154 81 : errFlag = false;
1155 81 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
1156 320 : ScanPlantLoopsForObject(state,
1157 80 : FanCoil(FanCoilNum).HCoilName,
1158 80 : FanCoil(FanCoilNum).HCoilPlantTypeOf,
1159 80 : FanCoil(FanCoilNum).HeatCoilPlantLoc,
1160 : errFlag,
1161 : _,
1162 : _,
1163 : _,
1164 : _,
1165 : _);
1166 :
1167 80 : if (errFlag) {
1168 0 : ShowContinueError(state, "Reference Unit=\"" + FanCoil(FanCoilNum).Name + "\", type=" + FanCoil(FanCoilNum).UnitType);
1169 0 : ShowFatalError(state, "InitFanCoilUnits: Program terminated for previous conditions.");
1170 : }
1171 :
1172 80 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum =
1173 80 : DataPlant::CompData::getPlantComponent(state, FanCoil(FanCoilNum).HeatCoilPlantLoc).NodeNumOut;
1174 :
1175 1 : } else if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Electric) {
1176 : // do nothing, valid type
1177 : } else {
1178 0 : ShowFatalError(state, "InitFanCoilUnits: FanCoil=" + FanCoil(FanCoilNum).Name + ", invalid heating coil type. Program terminated.");
1179 : }
1180 :
1181 81 : if ((FanCoil(FanCoilNum).CCoilPlantType == DataPlant::PlantEquipmentType::CoilWaterCooling) ||
1182 0 : (FanCoil(FanCoilNum).CCoilPlantType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling)) {
1183 324 : ScanPlantLoopsForObject(state,
1184 81 : FanCoil(FanCoilNum).CCoilPlantName,
1185 81 : FanCoil(FanCoilNum).CCoilPlantType,
1186 81 : FanCoil(FanCoilNum).CoolCoilPlantLoc,
1187 : errFlag,
1188 : _,
1189 : _,
1190 : _,
1191 : _,
1192 : _);
1193 81 : if (errFlag) {
1194 0 : ShowContinueError(state, "Reference Unit=\"" + FanCoil(FanCoilNum).Name + "\", type=" + FanCoil(FanCoilNum).UnitType);
1195 0 : ShowFatalError(state, "InitFanCoilUnits: Program terminated for previous conditions.");
1196 : }
1197 81 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum =
1198 81 : DataPlant::CompData::getPlantComponent(state, FanCoil(FanCoilNum).CoolCoilPlantLoc).NodeNumOut;
1199 : } else {
1200 0 : ShowFatalError(state, "InitFanCoilUnits: FanCoil=" + FanCoil(FanCoilNum).Name + ", invalid cooling coil type. Program terminated.");
1201 : }
1202 :
1203 81 : state.dataFanCoilUnits->MyPlantScanFlag(FanCoilNum) = false;
1204 : }
1205 :
1206 514191 : if (!state.dataFanCoilUnits->InitFanCoilUnitsCheckInZoneEquipmentListFlag && state.dataZoneEquip->ZoneEquipInputsFilled) {
1207 19 : state.dataFanCoilUnits->InitFanCoilUnitsCheckInZoneEquipmentListFlag = true;
1208 100 : for (Loop = 1; Loop <= state.dataFanCoilUnits->NumFanCoils; ++Loop) {
1209 81 : if (CheckZoneEquipmentList(state, FanCoil(Loop).UnitType, FanCoil(Loop).Name)) continue;
1210 0 : ShowSevereError(state,
1211 0 : "InitFanCoil: FanCoil Unit=[" + FanCoil(Loop).UnitType + ',' + FanCoil(Loop).Name +
1212 : "] is not on any ZoneHVAC:EquipmentList. It will not be simulated.");
1213 : }
1214 : }
1215 :
1216 514272 : if (!state.dataGlobal->SysSizingCalc && state.dataFanCoilUnits->MySizeFlag(FanCoilNum) &&
1217 81 : !state.dataFanCoilUnits->MyPlantScanFlag(FanCoilNum)) {
1218 :
1219 81 : SizeFanCoilUnit(state, FanCoilNum, ControlledZoneNum);
1220 :
1221 81 : state.dataFanCoilUnits->MySizeFlag(FanCoilNum) = false;
1222 : }
1223 :
1224 : // Do the Begin Environment initializations
1225 514671 : if (state.dataGlobal->BeginEnvrnFlag && state.dataFanCoilUnits->MyEnvrnFlag(FanCoilNum) &&
1226 480 : !state.dataFanCoilUnits->MyPlantScanFlag(FanCoilNum)) {
1227 480 : InNode = FanCoil(FanCoilNum).AirInNode;
1228 480 : OutNode = FanCoil(FanCoilNum).AirOutNode;
1229 480 : OutsideAirNode = FanCoil(FanCoilNum).OutsideAirNode;
1230 480 : RhoAir = state.dataEnvrn->StdRhoAir;
1231 480 : HotConNode = FanCoil(FanCoilNum).HeatCoilFluidInletNode;
1232 480 : ColdConNode = FanCoil(FanCoilNum).CoolCoilFluidInletNode;
1233 : // set the mass flow rates from the input volume flow rates
1234 480 : FanCoil(FanCoilNum).MaxAirMassFlow = RhoAir * FanCoil(FanCoilNum).MaxAirVolFlow;
1235 480 : FanCoil(FanCoilNum).OutAirMassFlow = RhoAir * FanCoil(FanCoilNum).OutAirVolFlow;
1236 :
1237 480 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
1238 948 : rho = GetDensityGlycol(state,
1239 474 : state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).HeatCoilPlantLoc.loopNum).FluidName,
1240 : DataGlobalConstants::HWInitConvTemp,
1241 474 : state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).HeatCoilPlantLoc.loopNum).FluidIndex,
1242 : RoutineName);
1243 474 : FanCoil(FanCoilNum).MaxHeatCoilFluidFlow = rho * FanCoil(FanCoilNum).MaxHotWaterVolFlow;
1244 474 : FanCoil(FanCoilNum).MinHotWaterFlow = rho * FanCoil(FanCoilNum).MinHotWaterVolFlow;
1245 : }
1246 :
1247 960 : rho = GetDensityGlycol(state,
1248 480 : state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).CoolCoilPlantLoc.loopNum).FluidName,
1249 : DataGlobalConstants::CWInitConvTemp,
1250 480 : state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).CoolCoilPlantLoc.loopNum).FluidIndex,
1251 : RoutineName);
1252 480 : FanCoil(FanCoilNum).MaxCoolCoilFluidFlow = rho * FanCoil(FanCoilNum).MaxColdWaterVolFlow;
1253 480 : FanCoil(FanCoilNum).MinColdWaterFlow = rho * FanCoil(FanCoilNum).MinColdWaterVolFlow;
1254 :
1255 : // set the node max and min mass flow rates
1256 480 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
1257 1896 : InitComponentNodes(state,
1258 474 : FanCoil(FanCoilNum).MinHotWaterFlow,
1259 474 : FanCoil(FanCoilNum).MaxHeatCoilFluidFlow,
1260 474 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
1261 474 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum);
1262 : }
1263 :
1264 1920 : InitComponentNodes(state,
1265 480 : FanCoil(FanCoilNum).MinColdWaterFlow,
1266 480 : FanCoil(FanCoilNum).MaxCoolCoilFluidFlow,
1267 480 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
1268 480 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum);
1269 : // Node(HotConNode)%MassFlowRateMax = FanCoil(FanCoilNum)%MaxHeatCoilFluidFlow
1270 : // Node(HotConNode)%MassFlowRateMin = FanCoil(FanCoilNum)%MinHotWaterFlow
1271 : // Node(ColdConNode)%MassFlowRateMax = FanCoil(FanCoilNum)%MaxCoolCoilFluidFlow
1272 : // Node(ColdConNode)%MassFlowRateMin = FanCoil(FanCoilNum)%MinColdWaterFlow
1273 :
1274 480 : if (FanCoil(FanCoilNum).OutsideAirNode > 0) {
1275 420 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMax = FanCoil(FanCoilNum).OutAirMassFlow;
1276 420 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMin = 0.0;
1277 : }
1278 480 : state.dataLoopNodes->Node(OutNode).MassFlowRateMax = FanCoil(FanCoilNum).MaxAirMassFlow;
1279 480 : state.dataLoopNodes->Node(OutNode).MassFlowRateMin = 0.0;
1280 480 : state.dataLoopNodes->Node(InNode).MassFlowRateMax = FanCoil(FanCoilNum).MaxAirMassFlow;
1281 480 : state.dataLoopNodes->Node(InNode).MassFlowRateMin = 0.0;
1282 480 : state.dataFanCoilUnits->MyEnvrnFlag(FanCoilNum) = false;
1283 : } // end one time inits
1284 :
1285 514191 : if (!state.dataGlobal->BeginEnvrnFlag) {
1286 510925 : state.dataFanCoilUnits->MyEnvrnFlag(FanCoilNum) = true;
1287 : }
1288 :
1289 : // These initializations are done every iteration
1290 514191 : InletNode = FanCoil(FanCoilNum).AirInNode;
1291 514191 : OutsideAirNode = FanCoil(FanCoilNum).OutsideAirNode;
1292 514191 : AirRelNode = FanCoil(FanCoilNum).AirReliefNode;
1293 514191 : FanCoil(FanCoilNum).SpeedRatio = 0.0;
1294 514191 : if (FanCoil(FanCoilNum).FanOpModeSchedPtr > 0) {
1295 8250 : if (GetCurrentScheduleValue(state, FanCoil(FanCoilNum).FanOpModeSchedPtr) == 0.0) {
1296 14 : FanCoil(FanCoilNum).FanOpMode = CycFanCycCoil;
1297 : } else {
1298 8236 : FanCoil(FanCoilNum).FanOpMode = ContFanCycCoil;
1299 : }
1300 : }
1301 : // Set the inlet node mass flow rate
1302 1542069 : if (((GetCurrentScheduleValue(state, FanCoil(FanCoilNum).SchedPtr) > 0.0 &&
1303 514191 : GetCurrentScheduleValue(state, FanCoil(FanCoilNum).fanAvailSchIndex) > 0.0) ||
1304 1028382 : state.dataHVACGlobal->ZoneCompTurnFansOn) &&
1305 513687 : !state.dataHVACGlobal->ZoneCompTurnFansOff) {
1306 511019 : state.dataLoopNodes->Node(InletNode).MassFlowRate = FanCoil(FanCoilNum).MaxAirMassFlow;
1307 511019 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = state.dataLoopNodes->Node(InletNode).MassFlowRate;
1308 511019 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = 0.0;
1309 :
1310 511019 : if (OutsideAirNode > 0) {
1311 474379 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = FanCoil(FanCoilNum).OutAirMassFlow;
1312 474379 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMaxAvail = FanCoil(FanCoilNum).OutAirMassFlow;
1313 474379 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMinAvail = FanCoil(FanCoilNum).OutAirMassFlow;
1314 474379 : state.dataLoopNodes->Node(AirRelNode).MassFlowRate = FanCoil(FanCoilNum).OutAirMassFlow;
1315 474379 : state.dataLoopNodes->Node(AirRelNode).MassFlowRateMaxAvail = FanCoil(FanCoilNum).OutAirMassFlow;
1316 474379 : state.dataLoopNodes->Node(AirRelNode).MassFlowRateMinAvail = FanCoil(FanCoilNum).OutAirMassFlow;
1317 : }
1318 :
1319 : } else {
1320 3172 : state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
1321 3172 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = 0.0;
1322 3172 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = 0.0;
1323 3172 : if (OutsideAirNode > 0) {
1324 3032 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = 0.0;
1325 3032 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMaxAvail = 0.0;
1326 3032 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMinAvail = 0.0;
1327 3032 : state.dataLoopNodes->Node(AirRelNode).MassFlowRate = 0.0;
1328 3032 : state.dataLoopNodes->Node(AirRelNode).MassFlowRateMaxAvail = 0.0;
1329 3032 : state.dataLoopNodes->Node(AirRelNode).MassFlowRateMinAvail = 0.0;
1330 : }
1331 : }
1332 514191 : }
1333 :
1334 81 : void SizeFanCoilUnit(EnergyPlusData &state,
1335 : int const FanCoilNum,
1336 : int const ControlledZoneNum // index into ZoneEquipConfig array
1337 : )
1338 : {
1339 :
1340 : // SUBROUTINE INFORMATION:
1341 : // AUTHOR Fred Buhl
1342 : // DATE WRITTEN January 2002
1343 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
1344 : // July 2014, B. Nigusse, added scalable sizing
1345 : // RE-ENGINEERED na
1346 :
1347 : // PURPOSE OF THIS SUBROUTINE:
1348 : // This subroutine is for sizing Fan Coil Unit components for which flow rates have not been
1349 : // specified in the input.
1350 :
1351 : // METHODOLOGY EMPLOYED:
1352 : // Obtains flow rates from the zone or system sizing arrays and plant sizing data.
1353 :
1354 : // Using/Aliasing
1355 : using namespace DataSizing;
1356 : using DataHVACGlobals::CoolingAirflowSizing;
1357 : using DataHVACGlobals::CoolingCapacitySizing;
1358 : using DataHVACGlobals::HeatingAirflowSizing;
1359 : using DataHVACGlobals::HeatingCapacitySizing;
1360 : using Fans::GetFanDesignVolumeFlowRate;
1361 : using FluidProperties::GetDensityGlycol;
1362 : using FluidProperties::GetSpecificHeatGlycol;
1363 :
1364 : using HVACHXAssistedCoolingCoil::GetHXCoilType;
1365 : using HVACHXAssistedCoolingCoil::GetHXDXCoilName;
1366 : using PlantUtilities::MyPlantSizingIndex;
1367 : using Psychrometrics::PsyCpAirFnW;
1368 : using Psychrometrics::PsyHFnTdbW;
1369 : using WaterCoils::GetCoilWaterInletNode;
1370 : using WaterCoils::GetCoilWaterOutletNode;
1371 : using WaterCoils::GetWaterCoilIndex;
1372 : using WaterCoils::SetCoilDesFlow;
1373 :
1374 : // SUBROUTINE PARAMETER DEFINITIONS:
1375 : static constexpr std::string_view RoutineName("SizeFanCoilUnit: "); // include trailing blank space
1376 : static constexpr std::string_view RoutineNameNoSpace("SizeFanCoilUnit");
1377 :
1378 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1379 : int PltSizHeatNum; // index of plant sizing object for 1st heating loop
1380 : int PltSizCoolNum; // index of plant sizing object for 1st cooling loop
1381 : bool ErrorsFound; // TRUE if errors foind during sizing
1382 : Real64 DesCoilLoad; // coil load used for sizing [W]
1383 162 : std::string CoolingCoilName;
1384 162 : std::string CoolingCoilType;
1385 : Real64 rho;
1386 : Real64 Cp;
1387 : int zoneHVACIndex; // index of zoneHVAC equipment sizing specification
1388 : bool IsAutoSize; // Indicator to autosize for reporting
1389 : Real64 MaxAirVolFlowDes; // Autosized max air flow for reporting
1390 : Real64 MaxAirVolFlowUser; // Hardsized max air flow for reporting
1391 : Real64 OutAirVolFlowDes; // Autosized outdoor air flow for reporting
1392 : Real64 OutAirVolFlowUser; // Hardsized outdoor air flow for reporting
1393 : Real64 MaxHotWaterVolFlowDes; // Autosized hot water flow for reporting
1394 : Real64 MaxHotWaterVolFlowUser; // Hardsized hot water flow for reporting
1395 : Real64 MaxColdWaterVolFlowDes; // Autosized cold water flow for reporting
1396 : Real64 MaxColdWaterVolFlowUser; // Hardsized cold water flow for reporting
1397 : Real64 CoolingAirVolFlowDes; // cooling supply air flow rate
1398 : Real64 HeatingAirVolFlowDes; // heating supply air flow rate
1399 162 : std::string CompName; // component name
1400 162 : std::string CompType; // component type
1401 162 : std::string SizingString; // input field sizing description (e.g., Nominal Capacity)
1402 : Real64 TempSize; // autosized value of coil input field
1403 81 : int FieldNum = 1; // IDD numeric field number where input field description is found
1404 : int SizingMethod; // Integer representation of sizing method name (e.g., CoolingAirflowSizing, HeatingAirflowSizing, CoolingCapacitySizing,
1405 : // HeatingCapacitySizing, etc.)
1406 : bool PrintFlag; // TRUE when sizing information is reported in the eio file
1407 81 : int SAFMethod(0); // supply air flow rate sizing method (SupplyAirFlowRate, FlowPerFloorArea, FractionOfAutosizedCoolingAirflow,
1408 : // FractionOfAutosizedHeatingAirflow ...)
1409 81 : int CapSizingMethod(0); // capacity sizing methods (HeatingDesignCapacity, CapacityPerFloorArea, FractionOfAutosizedCoolingCapacity, and
1410 : // FractionOfAutosizedHeatingCapacity )
1411 : bool SizingDesRunThisZone; // test for zone sizing
1412 81 : bool DoWaterCoilSizing = false; // if TRUE do water coil sizing calculation
1413 : Real64 WaterCoilSizDeltaT; // water coil deltaT for design water flow rate autosizing
1414 : int CoilNum; // index of water coil object
1415 :
1416 81 : PltSizCoolNum = 0;
1417 81 : PltSizHeatNum = 0;
1418 81 : ErrorsFound = false;
1419 81 : IsAutoSize = false;
1420 81 : MaxAirVolFlowDes = 0.0;
1421 81 : MaxAirVolFlowUser = 0.0;
1422 81 : OutAirVolFlowDes = 0.0;
1423 81 : OutAirVolFlowUser = 0.0;
1424 81 : MaxHotWaterVolFlowDes = 0.0;
1425 81 : MaxHotWaterVolFlowUser = 0.0;
1426 81 : MaxColdWaterVolFlowDes = 0.0;
1427 81 : MaxColdWaterVolFlowUser = 0.0;
1428 :
1429 81 : CoolingAirVolFlowDes = 0.0;
1430 81 : HeatingAirVolFlowDes = 0.0;
1431 81 : state.dataSize->ZoneHeatingOnlyFan = false;
1432 81 : state.dataSize->ZoneCoolingOnlyFan = false;
1433 81 : state.dataSize->DataScalableSizingON = false;
1434 81 : state.dataSize->DataScalableCapSizingON = false;
1435 :
1436 81 : state.dataSize->DataFracOfAutosizedCoolingAirflow = 1.0;
1437 81 : state.dataSize->DataFracOfAutosizedHeatingAirflow = 1.0;
1438 81 : state.dataSize->DataFracOfAutosizedCoolingCapacity = 1.0;
1439 81 : state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
1440 :
1441 81 : auto &FanCoil(state.dataFanCoilUnits->FanCoil);
1442 :
1443 81 : CompType = FanCoil(FanCoilNum).UnitType;
1444 81 : CompName = FanCoil(FanCoilNum).Name;
1445 81 : state.dataSize->DataZoneNumber = FanCoil(FanCoilNum).ControlZoneNum;
1446 81 : if (FanCoil(FanCoilNum).FanType_Num == DataHVACGlobals::FanType_SystemModelObject) {
1447 18 : state.dataSize->DataFanEnumType = DataAirSystems::ObjectVectorOOFanSystemModel;
1448 : } else {
1449 63 : state.dataSize->DataFanEnumType = DataAirSystems::StructArrayLegacyFanModels;
1450 : }
1451 81 : state.dataSize->DataFanIndex = FanCoil(FanCoilNum).FanIndex;
1452 : // fan coil unit is always blow thru
1453 81 : state.dataSize->DataFanPlacement = DataSizing::ZoneFanPlacement::BlowThru;
1454 :
1455 81 : auto &ZoneEqSizing(state.dataSize->ZoneEqSizing);
1456 :
1457 81 : if (state.dataSize->CurZoneEqNum > 0) {
1458 :
1459 81 : if (FanCoil(FanCoilNum).HVACSizingIndex > 0) {
1460 :
1461 : // initialize OA flow for sizing other inputs (e.g., inlet temp, capacity, etc.)
1462 3 : if (FanCoil(FanCoilNum).OutAirVolFlow == AutoSize) {
1463 3 : ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
1464 : } else {
1465 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = FanCoil(FanCoilNum).OutAirVolFlow;
1466 : }
1467 3 : if (FanCoil(FanCoilNum).ATMixerExists) { // set up ATMixer conditions for scalable capacity sizing
1468 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = 0.0; // Equipment OA flow should always be 0 when ATMixer is used
1469 0 : SingleDuct::setATMixerSizingProperties(state, FanCoil(FanCoilNum).ATMixerIndex, ControlledZoneNum, state.dataSize->CurZoneEqNum);
1470 : }
1471 :
1472 3 : zoneHVACIndex = FanCoil(FanCoilNum).HVACSizingIndex;
1473 3 : FieldNum = 1;
1474 3 : PrintFlag = true;
1475 3 : SizingString = state.dataFanCoilUnits->FanCoilNumericFields(FanCoilNum).FieldNames(FieldNum) + " [m3/s]";
1476 3 : if (state.dataGlobal->isEpJSON) SizingString = "maximum_supply_air_flow_rate [m3/s]";
1477 3 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod > 0) {
1478 3 : SizingMethod = CoolingAirflowSizing;
1479 3 : SAFMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod;
1480 3 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SizingMethod(SizingMethod) = SAFMethod;
1481 3 : if (SAFMethod == SupplyAirFlowRate || SAFMethod == FlowPerFloorArea || SAFMethod == FractionOfAutosizedCoolingAirflow) {
1482 3 : if (SAFMethod == SupplyAirFlowRate) {
1483 1 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow > 0.0) {
1484 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow =
1485 0 : state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
1486 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SystemAirFlow = true;
1487 : }
1488 1 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
1489 2 : } else if (SAFMethod == FlowPerFloorArea) {
1490 1 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SystemAirFlow = true;
1491 2 : ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow *
1492 1 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
1493 1 : TempSize = ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow;
1494 1 : state.dataSize->DataScalableSizingON = true;
1495 1 : } else if (SAFMethod == FractionOfAutosizedCoolingAirflow) {
1496 1 : state.dataSize->DataFracOfAutosizedCoolingAirflow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
1497 1 : TempSize = AutoSize;
1498 1 : state.dataSize->DataScalableSizingON = true;
1499 : } else {
1500 0 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
1501 : }
1502 6 : CoolingAirFlowSizer sizingCoolingAirFlow;
1503 3 : sizingCoolingAirFlow.overrideSizingString(SizingString);
1504 : // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1505 3 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1506 6 : CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
1507 :
1508 0 : } else if (SAFMethod == FlowPerCoolingCapacity) {
1509 0 : SizingMethod = CoolingCapacitySizing;
1510 0 : TempSize = AutoSize;
1511 0 : PrintFlag = false;
1512 0 : CoolingCapacitySizer sizerCoolingCapacity;
1513 0 : sizerCoolingCapacity.overrideSizingString(SizingString);
1514 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1515 0 : state.dataSize->DataAutosizedCoolingCapacity = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
1516 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingCapMethod == FractionOfAutosizedCoolingCapacity) {
1517 0 : state.dataSize->DataFracOfAutosizedCoolingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
1518 : }
1519 0 : state.dataSize->DataFlowPerCoolingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
1520 0 : PrintFlag = true;
1521 0 : TempSize = AutoSize;
1522 0 : state.dataSize->DataScalableSizingON = true;
1523 0 : CoolingAirFlowSizer sizingCoolingAirFlow;
1524 0 : sizingCoolingAirFlow.overrideSizingString(SizingString);
1525 : // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1526 0 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1527 0 : CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
1528 : }
1529 0 : } else if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod > 0) {
1530 : // now do heating supply air flow rate sizing
1531 0 : SizingMethod = HeatingAirflowSizing;
1532 0 : SAFMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod;
1533 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SizingMethod(SizingMethod) = SAFMethod;
1534 0 : if (SAFMethod == SupplyAirFlowRate || SAFMethod == FlowPerFloorArea || SAFMethod == FractionOfAutosizedHeatingAirflow) {
1535 0 : if (SAFMethod == SupplyAirFlowRate) {
1536 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow > 0.0) {
1537 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow =
1538 0 : state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
1539 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SystemAirFlow = true;
1540 : }
1541 0 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
1542 0 : } else if (SAFMethod == FlowPerFloorArea) {
1543 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SystemAirFlow = true;
1544 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow *
1545 0 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
1546 0 : TempSize = ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow;
1547 0 : state.dataSize->DataScalableSizingON = true;
1548 0 : } else if (SAFMethod == FractionOfAutosizedHeatingAirflow) {
1549 0 : state.dataSize->DataFracOfAutosizedHeatingAirflow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
1550 0 : TempSize = AutoSize;
1551 0 : state.dataSize->DataScalableSizingON = true;
1552 : } else {
1553 0 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
1554 : }
1555 0 : bool errorsFound = false;
1556 0 : HeatingAirFlowSizer sizingHeatingAirFlow;
1557 0 : sizingHeatingAirFlow.overrideSizingString(SizingString);
1558 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1559 0 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1560 0 : HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, errorsFound);
1561 0 : } else if (SAFMethod == FlowPerHeatingCapacity) {
1562 0 : SizingMethod = HeatingCapacitySizing;
1563 0 : TempSize = AutoSize;
1564 0 : PrintFlag = false;
1565 0 : state.dataSize->DataScalableSizingON = true;
1566 : // initialize OA flow for sizing capacity
1567 0 : if (FanCoil(FanCoilNum).OutAirVolFlow == AutoSize) {
1568 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow =
1569 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
1570 : } else {
1571 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = FanCoil(FanCoilNum).OutAirVolFlow;
1572 : }
1573 0 : bool errorsFound = false;
1574 0 : HeatingCapacitySizer sizerHeatingCapacity;
1575 0 : sizerHeatingCapacity.overrideSizingString(SizingString);
1576 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1577 0 : TempSize = sizerHeatingCapacity.size(state, TempSize, errorsFound);
1578 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingCapMethod == FractionOfAutosizedHeatingCapacity) {
1579 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
1580 : }
1581 0 : state.dataSize->DataAutosizedHeatingCapacity = TempSize;
1582 0 : state.dataSize->DataFlowPerHeatingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
1583 0 : SizingMethod = HeatingAirflowSizing;
1584 0 : PrintFlag = true;
1585 0 : TempSize = AutoSize;
1586 0 : errorsFound = false;
1587 0 : HeatingAirFlowSizer sizingHeatingAirFlow;
1588 0 : sizingHeatingAirFlow.overrideSizingString(SizingString);
1589 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1590 0 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1591 0 : HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, errorsFound);
1592 : }
1593 : }
1594 :
1595 5 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize ||
1596 2 : state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == AutoSize) {
1597 1 : IsAutoSize = true;
1598 1 : FanCoil(FanCoilNum).MaxAirVolFlow = AutoSize;
1599 1 : MaxAirVolFlowDes = max(CoolingAirVolFlowDes, HeatingAirVolFlowDes);
1600 : } else {
1601 2 : FanCoil(FanCoilNum).MaxAirVolFlow = max(CoolingAirVolFlowDes, HeatingAirVolFlowDes);
1602 2 : MaxAirVolFlowDes = 0.0;
1603 : }
1604 : } else {
1605 : // SizingString = "Supply Air Maximum Flow Rate [m3/s]";
1606 78 : TempSize = FanCoil(FanCoilNum).MaxAirVolFlow;
1607 78 : PrintFlag = true;
1608 78 : if (FanCoil(FanCoilNum).MaxAirVolFlow == AutoSize) {
1609 78 : IsAutoSize = true;
1610 156 : SystemAirFlowSizer sizerSystemAirFlow;
1611 : // sizerSystemAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1612 78 : sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1613 78 : MaxAirVolFlowDes = sizerSystemAirFlow.size(state, TempSize, ErrorsFound);
1614 : } else {
1615 0 : MaxAirVolFlowDes = 0.0;
1616 : }
1617 : }
1618 : }
1619 :
1620 81 : if (state.dataSize->CurZoneEqNum > 0) {
1621 :
1622 81 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
1623 :
1624 : } else {
1625 81 : if (MaxAirVolFlowDes < SmallAirVolFlow) {
1626 2 : MaxAirVolFlowDes = 0.0;
1627 : }
1628 :
1629 : // If fan is autosized, get fan volumetric flow rate
1630 81 : if (FanCoil(FanCoilNum).FanAirVolFlow == AutoSize) {
1631 81 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
1632 63 : Fans::SimulateFanComponents(state, FanCoil(FanCoilNum).FanName, true, FanCoil(FanCoilNum).FanIndex);
1633 63 : FanCoil(FanCoilNum).FanAirVolFlow =
1634 126 : GetFanDesignVolumeFlowRate(state, cFanTypes(FanCoil(FanCoilNum).FanType_Num), FanCoil(FanCoilNum).FanName, ErrorsFound);
1635 : } else {
1636 18 : state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(state, _, _, _, _);
1637 18 : FanCoil(FanCoilNum).FanAirVolFlow = state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->designAirVolFlowRate;
1638 : }
1639 : }
1640 : // Check that the fan volumetric flow rate is greater than or equal to the FCU volumetric flow rate
1641 81 : if (MaxAirVolFlowDes > FanCoil(FanCoilNum).FanAirVolFlow) {
1642 0 : ShowWarningError(state, std::string{RoutineName} + FanCoil(FanCoilNum).UnitType + ": " + FanCoil(FanCoilNum).Name);
1643 0 : ShowContinueError(state, "... Maximum supply air flow rate is greater than the maximum fan flow rate.");
1644 0 : ShowContinueError(state, format("... Fan Coil Unit flow = {:.5T} [m3/s].", MaxAirVolFlowDes));
1645 0 : ShowContinueError(state, "... Fan = " + cFanTypes(FanCoil(FanCoilNum).FanType_Num) + ": " + FanCoil(FanCoilNum).FanName);
1646 0 : ShowContinueError(state, format("... Fan flow = {:.5T} [m3/s].", FanCoil(FanCoilNum).FanAirVolFlow));
1647 0 : ShowContinueError(state, "... Fan Coil Unit flow rate reduced to match the fan flow rate and the simulation continues.");
1648 0 : MaxAirVolFlowDes = FanCoil(FanCoilNum).FanAirVolFlow;
1649 : }
1650 :
1651 81 : if (IsAutoSize) {
1652 79 : FanCoil(FanCoilNum).MaxAirVolFlow = MaxAirVolFlowDes;
1653 : } else { // Hard size with sizing data
1654 2 : if (FanCoil(FanCoilNum).MaxAirVolFlow > 0.0 && MaxAirVolFlowDes > 0.0) {
1655 0 : MaxAirVolFlowUser = FanCoil(FanCoilNum).MaxAirVolFlow;
1656 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1657 0 : if ((std::abs(MaxAirVolFlowDes - MaxAirVolFlowUser) / MaxAirVolFlowUser) > state.dataSize->AutoVsHardSizingThreshold) {
1658 0 : ShowMessage(state,
1659 0 : "SizeFanCoilUnit: Potential issue with equipment sizing for " + FanCoil(FanCoilNum).UnitType + ' ' +
1660 0 : FanCoil(FanCoilNum).Name);
1661 0 : ShowContinueError(state, format("User-Specified Supply Air Maximum Flow Rate of {:.5R} [m3/s]", MaxAirVolFlowUser));
1662 0 : ShowContinueError(state,
1663 0 : format("differs from Design Size Supply Air Maximum Flow Rate of {:.5R} [m3/s]", MaxAirVolFlowDes));
1664 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1665 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1666 : }
1667 : }
1668 : }
1669 : }
1670 : }
1671 0 : } else if (FanCoil(FanCoilNum).FanAirVolFlow == AutoSize) {
1672 0 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
1673 0 : Fans::SimulateFanComponents(state, FanCoil(FanCoilNum).FanName, true, FanCoil(FanCoilNum).FanIndex);
1674 0 : FanCoil(FanCoilNum).FanAirVolFlow =
1675 0 : GetFanDesignVolumeFlowRate(state, cFanTypes(FanCoil(FanCoilNum).FanType_Num), FanCoil(FanCoilNum).FanName, ErrorsFound);
1676 : } else {
1677 0 : state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(state, _, _, _, _);
1678 0 : FanCoil(FanCoilNum).FanAirVolFlow = state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->designAirVolFlowRate;
1679 : }
1680 : // Check that the fan volumetric flow rate is greater than or equal to the FCU volumetric flow rate
1681 0 : if (FanCoil(FanCoilNum).MaxAirVolFlow > FanCoil(FanCoilNum).FanAirVolFlow) {
1682 0 : ShowWarningError(state, std::string{RoutineName} + FanCoil(FanCoilNum).UnitType + ": " + FanCoil(FanCoilNum).Name);
1683 0 : ShowContinueError(state, "... Maximum supply air flow rate is greater than the maximum fan flow rate.");
1684 0 : ShowContinueError(state, format("... Fan Coil Unit flow = {:.5T} m3/s.", FanCoil(FanCoilNum).MaxAirVolFlow));
1685 0 : ShowContinueError(state, "... Fan = " + cFanTypes(FanCoil(FanCoilNum).FanType_Num) + ": " + FanCoil(FanCoilNum).FanName);
1686 0 : ShowContinueError(state, format("... Fan flow = {:.5T} m3/s.", FanCoil(FanCoilNum).FanAirVolFlow));
1687 0 : ShowContinueError(state, "... Fan Coil Unit flow rate reduced to match the fan flow rate and the simulation continues.");
1688 0 : FanCoil(FanCoilNum).MaxAirVolFlow = FanCoil(FanCoilNum).FanAirVolFlow;
1689 : }
1690 : }
1691 :
1692 81 : IsAutoSize = false;
1693 81 : if (FanCoil(FanCoilNum).OutAirVolFlow == AutoSize) {
1694 23 : IsAutoSize = true;
1695 : }
1696 :
1697 81 : if (state.dataSize->CurZoneEqNum > 0) {
1698 81 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
1699 0 : if (FanCoil(FanCoilNum).OutAirVolFlow > 0.0) {
1700 0 : BaseSizer::reportSizerOutput(state,
1701 0 : FanCoil(FanCoilNum).UnitType,
1702 0 : FanCoil(FanCoilNum).Name,
1703 : "User-Specified Maximum Outdoor Air Flow Rate [m3/s]",
1704 0 : FanCoil(FanCoilNum).OutAirVolFlow);
1705 : }
1706 : } else {
1707 81 : CheckZoneSizing(state, FanCoil(FanCoilNum).UnitType, FanCoil(FanCoilNum).Name);
1708 81 : OutAirVolFlowDes = min(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA, FanCoil(FanCoilNum).MaxAirVolFlow);
1709 81 : if (OutAirVolFlowDes < SmallAirVolFlow) {
1710 2 : OutAirVolFlowDes = 0.0;
1711 : }
1712 81 : if (IsAutoSize) {
1713 23 : FanCoil(FanCoilNum).OutAirVolFlow = OutAirVolFlowDes;
1714 69 : BaseSizer::reportSizerOutput(state,
1715 23 : FanCoil(FanCoilNum).UnitType,
1716 23 : FanCoil(FanCoilNum).Name,
1717 : "Design Size Maximum Outdoor Air Flow Rate [m3/s]",
1718 23 : OutAirVolFlowDes);
1719 : } else {
1720 58 : if (FanCoil(FanCoilNum).OutAirVolFlow > 0.0 && OutAirVolFlowDes > 0.0) {
1721 0 : OutAirVolFlowUser = FanCoil(FanCoilNum).OutAirVolFlow;
1722 0 : BaseSizer::reportSizerOutput(state,
1723 0 : FanCoil(FanCoilNum).UnitType,
1724 0 : FanCoil(FanCoilNum).Name,
1725 : "Design Size Maximum Outdoor Air Flow Rate [m3/s]",
1726 : OutAirVolFlowDes,
1727 : "User-Specified Maximum Outdoor Air Flow Rate [m3/s]",
1728 0 : OutAirVolFlowUser);
1729 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1730 0 : if ((std::abs(OutAirVolFlowDes - OutAirVolFlowUser) / OutAirVolFlowUser) > state.dataSize->AutoVsHardSizingThreshold) {
1731 0 : ShowMessage(state,
1732 0 : "SizeFanCoilUnit: Potential issue with equipment sizing for " + FanCoil(FanCoilNum).UnitType + ' ' +
1733 0 : FanCoil(FanCoilNum).Name);
1734 0 : ShowContinueError(state, format("User-Specified Maximum Outdoor Air Flow Rate of {:.5R} [m3/s]", OutAirVolFlowUser));
1735 0 : ShowContinueError(
1736 0 : state, format("differs from Design Size Maximum Outdoor Air Flow Rate of {:.5R} [m3/s]", OutAirVolFlowDes));
1737 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1738 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1739 : }
1740 : }
1741 : }
1742 : }
1743 : }
1744 81 : ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = FanCoil(FanCoilNum).OutAirVolFlow; // sets OA frac in sizing
1745 :
1746 81 : if (FanCoil(FanCoilNum).ATMixerExists) { // set up ATMixer conditions for use in component sizing
1747 10 : ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = 0.0; // Equipment OA flow should always be 0 when ATMixer is used
1748 10 : SingleDuct::setATMixerSizingProperties(state, FanCoil(FanCoilNum).ATMixerIndex, ControlledZoneNum, state.dataSize->CurZoneEqNum);
1749 : }
1750 : }
1751 :
1752 81 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
1753 :
1754 80 : IsAutoSize = false;
1755 80 : if (FanCoil(FanCoilNum).MaxHotWaterVolFlow == AutoSize) {
1756 80 : IsAutoSize = true;
1757 : }
1758 :
1759 80 : if (state.dataSize->CurZoneEqNum > 0) {
1760 80 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
1761 0 : if (FanCoil(FanCoilNum).MaxHotWaterVolFlow > 0.0) {
1762 0 : BaseSizer::reportSizerOutput(state,
1763 0 : FanCoil(FanCoilNum).UnitType,
1764 0 : FanCoil(FanCoilNum).Name,
1765 : "User-Specified Maximum Hot Water Flow [m3/s]",
1766 0 : FanCoil(FanCoilNum).MaxHotWaterVolFlow);
1767 : }
1768 : } else {
1769 80 : state.dataFanCoilUnits->CoilWaterInletNode =
1770 160 : WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", FanCoil(FanCoilNum).HCoilName, ErrorsFound);
1771 80 : state.dataFanCoilUnits->CoilWaterOutletNode =
1772 160 : WaterCoils::GetCoilWaterOutletNode(state, "Coil:Heating:Water", FanCoil(FanCoilNum).HCoilName, ErrorsFound);
1773 80 : if (IsAutoSize) {
1774 320 : PltSizHeatNum = MyPlantSizingIndex(state,
1775 : "Coil:Heating:Water",
1776 80 : FanCoil(FanCoilNum).HCoilName,
1777 80 : state.dataFanCoilUnits->CoilWaterInletNode,
1778 80 : state.dataFanCoilUnits->CoilWaterOutletNode,
1779 : ErrorsFound);
1780 80 : CoilNum = WaterCoils::GetWaterCoilIndex(state, "COIL:HEATING:WATER", FanCoil(FanCoilNum).HCoilName, ErrorsFound);
1781 80 : if (state.dataWaterCoils->WaterCoil(CoilNum).UseDesignWaterDeltaTemp) {
1782 0 : WaterCoilSizDeltaT = state.dataWaterCoils->WaterCoil(CoilNum).DesignWaterDeltaTemp;
1783 0 : DoWaterCoilSizing = true;
1784 : } else {
1785 80 : if (PltSizHeatNum > 0) {
1786 80 : WaterCoilSizDeltaT = state.dataSize->PlantSizData(PltSizHeatNum).DeltaT;
1787 80 : DoWaterCoilSizing = true;
1788 : } else {
1789 0 : DoWaterCoilSizing = false;
1790 : // If there is no heating Plant Sizing object and autosizing was requested, issue fatal error message
1791 0 : ShowSevereError(state, "Autosizing of water coil requires a heating loop Sizing:Plant object");
1792 0 : ShowContinueError(state, "Occurs in " + FanCoil(FanCoilNum).UnitType + " Object=" + FanCoil(FanCoilNum).Name);
1793 0 : ErrorsFound = true;
1794 : }
1795 : }
1796 80 : if (DoWaterCoilSizing) {
1797 80 : SizingMethod = HeatingCapacitySizing;
1798 80 : if (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatMassFlow > 0.0) {
1799 80 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatOAFlowFrac = min(
1800 80 : FanCoil(FanCoilNum).OutAirVolFlow / state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatMassFlow,
1801 : 1.0);
1802 : } else {
1803 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatOAFlowFrac = 0.0;
1804 : }
1805 80 : if (FanCoil(FanCoilNum).HVACSizingIndex > 0) {
1806 3 : zoneHVACIndex = FanCoil(FanCoilNum).HVACSizingIndex;
1807 3 : CapSizingMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingCapMethod;
1808 3 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SizingMethod(SizingMethod) = CapSizingMethod;
1809 3 : if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
1810 : CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
1811 3 : if (CapSizingMethod == HeatingDesignCapacity) {
1812 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity > 0.0) {
1813 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingCapacity = true;
1814 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad =
1815 0 : state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
1816 : }
1817 0 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
1818 3 : } else if (CapSizingMethod == CapacityPerFloorArea) {
1819 2 : if (state.dataSize->ZoneSizingRunDone) {
1820 2 : PrintFlag = false;
1821 2 : TempSize = AutoSize;
1822 2 : state.dataSize->DataFlowUsedForSizing =
1823 2 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
1824 2 : bool errorsFound = false;
1825 4 : HeatingCapacitySizer sizerHeatingCapacity;
1826 2 : sizerHeatingCapacity.overrideSizingString(SizingString);
1827 2 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1828 2 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad =
1829 2 : sizerHeatingCapacity.size(state, TempSize, errorsFound);
1830 2 : ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingCapacity = true;
1831 : }
1832 4 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity *
1833 2 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
1834 2 : state.dataSize->DataScalableCapSizingON = true;
1835 1 : } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
1836 1 : CheckZoneSizing(state, CompType, CompName);
1837 1 : PrintFlag = false;
1838 1 : TempSize = AutoSize;
1839 1 : state.dataSize->DataFlowUsedForSizing =
1840 1 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
1841 1 : bool errorsFound = false;
1842 2 : HeatingCapacitySizer sizerHeatingCapacity;
1843 1 : sizerHeatingCapacity.overrideSizingString(SizingString);
1844 1 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1845 1 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad =
1846 1 : sizerHeatingCapacity.size(state, TempSize, errorsFound);
1847 1 : ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingCapacity = true;
1848 2 : TempSize = ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad *
1849 1 : state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
1850 1 : state.dataSize->DataScalableCapSizingON = true;
1851 : }
1852 : }
1853 3 : SizingString = "Heating Design Capacity [W]";
1854 3 : PrintFlag = false;
1855 3 : bool errorsFound = false;
1856 6 : HeatingCapacitySizer sizerHeatingCapacity;
1857 3 : sizerHeatingCapacity.overrideSizingString(SizingString);
1858 3 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1859 3 : DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
1860 3 : state.dataSize->DataScalableCapSizingON = false;
1861 3 : state.dataSize->DataFlowUsedForSizing = 0.0;
1862 :
1863 : } else {
1864 77 : SizingString = "Heating Design Capacity [W]";
1865 77 : PrintFlag = false;
1866 77 : TempSize = AutoSize;
1867 77 : bool errorsFound = false;
1868 154 : HeatingCapacitySizer sizerHeatingCapacity;
1869 77 : sizerHeatingCapacity.overrideSizingString(SizingString);
1870 77 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1871 77 : DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
1872 : }
1873 80 : FanCoil(FanCoilNum).DesHeatingLoad = DesCoilLoad;
1874 80 : if (DesCoilLoad >= SmallLoad) {
1875 160 : rho = GetDensityGlycol(state,
1876 80 : state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).HeatCoilPlantLoc.loopNum).FluidName,
1877 : DataGlobalConstants::HWInitConvTemp,
1878 80 : state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).HeatCoilPlantLoc.loopNum).FluidIndex,
1879 : RoutineNameNoSpace);
1880 160 : Cp = GetSpecificHeatGlycol(state,
1881 80 : state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).HeatCoilPlantLoc.loopNum).FluidName,
1882 : DataGlobalConstants::HWInitConvTemp,
1883 80 : state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).HeatCoilPlantLoc.loopNum).FluidIndex,
1884 : RoutineNameNoSpace);
1885 :
1886 80 : MaxHotWaterVolFlowDes = DesCoilLoad / (WaterCoilSizDeltaT * Cp * rho);
1887 : } else {
1888 0 : MaxHotWaterVolFlowDes = 0.0;
1889 : }
1890 : }
1891 : }
1892 : }
1893 :
1894 80 : if (IsAutoSize) {
1895 80 : FanCoil(FanCoilNum).MaxHotWaterVolFlow = MaxHotWaterVolFlowDes;
1896 240 : BaseSizer::reportSizerOutput(state,
1897 80 : FanCoil(FanCoilNum).UnitType,
1898 80 : FanCoil(FanCoilNum).Name,
1899 : "Design Size Maximum Hot Water Flow [m3/s]",
1900 80 : MaxHotWaterVolFlowDes);
1901 : } else { // Hard size with sizing data
1902 0 : if (FanCoil(FanCoilNum).MaxHotWaterVolFlow > 0.0 && MaxHotWaterVolFlowDes > 0.0) {
1903 0 : MaxHotWaterVolFlowDes = FanCoil(FanCoilNum).MaxHotWaterVolFlow;
1904 0 : BaseSizer::reportSizerOutput(state,
1905 0 : FanCoil(FanCoilNum).UnitType,
1906 0 : FanCoil(FanCoilNum).Name,
1907 : "Design Size Maximum Hot Water Flow [m3/s]",
1908 : MaxHotWaterVolFlowDes,
1909 : "User-Specified Maximum Hot Water Flow [m3/s]",
1910 0 : MaxHotWaterVolFlowUser);
1911 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1912 0 : if ((std::abs(MaxHotWaterVolFlowDes - MaxHotWaterVolFlowUser) / MaxHotWaterVolFlowUser) >
1913 0 : state.dataSize->AutoVsHardSizingThreshold) {
1914 0 : ShowMessage(state,
1915 0 : "SizeFanCoilUnit: Potential issue with equipment sizing for " + FanCoil(FanCoilNum).UnitType + ' ' +
1916 0 : FanCoil(FanCoilNum).Name);
1917 0 : ShowContinueError(state, format("User-Specified Maximum Hot Water Flow of {:.5R} [m3/s]", MaxHotWaterVolFlowUser));
1918 0 : ShowContinueError(state,
1919 0 : format("differs from Design Size Maximum Hot Water Flow of {:.5R} [m3/s]", MaxHotWaterVolFlowDes));
1920 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1921 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1922 : }
1923 : }
1924 : }
1925 : }
1926 : }
1927 1 : } else if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Electric) {
1928 1 : if (FanCoil(FanCoilNum).DesignHeatingCapacity == AutoSize) {
1929 1 : CompName = FanCoil(FanCoilNum).HCoilName;
1930 1 : CompType = FanCoil(FanCoilNum).HCoilType;
1931 1 : SizingMethod = HeatingCapacitySizing;
1932 1 : PrintFlag = false;
1933 1 : TempSize = FanCoil(FanCoilNum).DesignHeatingCapacity;
1934 1 : SizingString = "Nominal Heating Capacity [W]";
1935 1 : bool errorsFound = false;
1936 2 : HeatingCapacitySizer sizerHeatingCapacity;
1937 1 : sizerHeatingCapacity.overrideSizingString(SizingString);
1938 1 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1939 1 : FanCoil(FanCoilNum).DesignHeatingCapacity = sizerHeatingCapacity.size(state, TempSize, errorsFound);
1940 1 : FanCoil(FanCoilNum).DesHeatingLoad = FanCoil(FanCoilNum).DesignHeatingCapacity;
1941 : }
1942 : }
1943 :
1944 81 : IsAutoSize = false;
1945 81 : if (FanCoil(FanCoilNum).MaxColdWaterVolFlow == AutoSize) {
1946 81 : IsAutoSize = true;
1947 : }
1948 81 : if (state.dataSize->CurZoneEqNum > 0) {
1949 81 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
1950 0 : if (FanCoil(FanCoilNum).MaxColdWaterVolFlow > 0.0) {
1951 0 : BaseSizer::reportSizerOutput(state,
1952 0 : FanCoil(FanCoilNum).UnitType,
1953 0 : FanCoil(FanCoilNum).Name,
1954 : "User-Specified Maximum Cold Water Flow [m3/s]",
1955 0 : FanCoil(FanCoilNum).MaxColdWaterVolFlow);
1956 : }
1957 : } else {
1958 81 : if (UtilityRoutines::SameString(FanCoil(FanCoilNum).CCoilType, "CoilSystem:Cooling:Water:HeatExchangerAssisted")) {
1959 0 : CoolingCoilName = GetHXDXCoilName(state, FanCoil(FanCoilNum).CCoilType, FanCoil(FanCoilNum).CCoilName, ErrorsFound);
1960 0 : CoolingCoilType = GetHXCoilType(state, FanCoil(FanCoilNum).CCoilType, FanCoil(FanCoilNum).CCoilName, ErrorsFound);
1961 : } else {
1962 81 : CoolingCoilName = FanCoil(FanCoilNum).CCoilName;
1963 81 : CoolingCoilType = FanCoil(FanCoilNum).CCoilType;
1964 : }
1965 81 : state.dataFanCoilUnits->CoilWaterInletNode = WaterCoils::GetCoilWaterInletNode(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
1966 81 : state.dataFanCoilUnits->CoilWaterOutletNode =
1967 81 : WaterCoils::GetCoilWaterOutletNode(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
1968 81 : if (IsAutoSize) {
1969 243 : PltSizCoolNum = MyPlantSizingIndex(state,
1970 : CoolingCoilType,
1971 : CoolingCoilName,
1972 81 : state.dataFanCoilUnits->CoilWaterInletNode,
1973 81 : state.dataFanCoilUnits->CoilWaterOutletNode,
1974 : ErrorsFound);
1975 81 : CoilNum = WaterCoils::GetWaterCoilIndex(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
1976 81 : if (state.dataWaterCoils->WaterCoil(CoilNum).UseDesignWaterDeltaTemp) {
1977 0 : WaterCoilSizDeltaT = state.dataWaterCoils->WaterCoil(CoilNum).DesignWaterDeltaTemp;
1978 0 : DoWaterCoilSizing = true;
1979 : } else {
1980 81 : if (PltSizCoolNum > 0) {
1981 81 : WaterCoilSizDeltaT = state.dataSize->PlantSizData(PltSizCoolNum).DeltaT;
1982 81 : DoWaterCoilSizing = true;
1983 : } else {
1984 0 : DoWaterCoilSizing = false;
1985 : // If there is no cooling Plant Sizing object and autosizing was requested, issue fatal error message
1986 0 : ShowSevereError(state, "Autosizing of water coil requires a cooling loop Sizing:Plant object");
1987 0 : ShowContinueError(state, "Occurs in " + FanCoil(FanCoilNum).UnitType + " Object=" + FanCoil(FanCoilNum).Name);
1988 0 : ErrorsFound = true;
1989 : }
1990 : }
1991 :
1992 81 : if (DoWaterCoilSizing) {
1993 81 : SizingMethod = CoolingCapacitySizing;
1994 81 : if (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolMassFlow > 0.0) {
1995 81 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolOAFlowFrac =
1996 81 : min(FanCoil(FanCoilNum).OutAirVolFlow / state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolMassFlow,
1997 : 1.0);
1998 : } else {
1999 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolOAFlowFrac = 0.0;
2000 : }
2001 81 : if (FanCoil(FanCoilNum).HVACSizingIndex > 0) {
2002 3 : zoneHVACIndex = FanCoil(FanCoilNum).HVACSizingIndex;
2003 3 : CapSizingMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingCapMethod;
2004 3 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SizingMethod(SizingMethod) = CapSizingMethod;
2005 3 : if (CapSizingMethod == CoolingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
2006 : CapSizingMethod == FractionOfAutosizedCoolingCapacity) {
2007 3 : if (CapSizingMethod == CoolingDesignCapacity) {
2008 1 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity > 0.0) {
2009 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingCapacity = true;
2010 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesCoolingLoad =
2011 0 : state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
2012 : } else {
2013 1 : state.dataSize->DataFlowUsedForSizing =
2014 1 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
2015 : }
2016 1 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
2017 2 : } else if (CapSizingMethod == CapacityPerFloorArea) {
2018 1 : if (state.dataSize->ZoneSizingRunDone) {
2019 1 : CheckZoneSizing(state, CompType, CompName);
2020 1 : PrintFlag = false;
2021 1 : TempSize = AutoSize;
2022 1 : state.dataSize->DataFlowUsedForSizing =
2023 1 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
2024 2 : CoolingCapacitySizer sizerCoolingCapacity;
2025 1 : sizerCoolingCapacity.overrideSizingString(SizingString);
2026 1 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2027 1 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesCoolingLoad =
2028 1 : sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
2029 1 : ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingCapacity = true;
2030 : }
2031 2 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity *
2032 1 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
2033 1 : state.dataSize->DataScalableCapSizingON = true;
2034 1 : } else if (CapSizingMethod == FractionOfAutosizedCoolingCapacity) {
2035 1 : PrintFlag = false;
2036 1 : TempSize = AutoSize;
2037 1 : state.dataSize->DataFlowUsedForSizing =
2038 1 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
2039 2 : CoolingCapacitySizer sizerCoolingCapacity2;
2040 1 : sizerCoolingCapacity2.overrideSizingString(SizingString);
2041 1 : sizerCoolingCapacity2.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2042 1 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesCoolingLoad =
2043 1 : sizerCoolingCapacity2.size(state, TempSize, ErrorsFound);
2044 1 : ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingCapacity = true;
2045 2 : TempSize = ZoneEqSizing(state.dataSize->CurZoneEqNum).DesCoolingLoad *
2046 1 : state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
2047 1 : state.dataSize->DataScalableCapSizingON = true;
2048 : }
2049 : }
2050 3 : SizingString = "Cooling Design Capacity [W]";
2051 3 : PrintFlag = false;
2052 6 : CoolingCapacitySizer sizerCoolingCapacity3;
2053 3 : sizerCoolingCapacity3.overrideSizingString(SizingString);
2054 3 : sizerCoolingCapacity3.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2055 3 : DesCoilLoad = sizerCoolingCapacity3.size(state, TempSize, ErrorsFound);
2056 3 : state.dataSize->DataScalableCapSizingON = false;
2057 3 : state.dataSize->DataFlowUsedForSizing = 0.0;
2058 : } else {
2059 78 : SizingString = "Cooling Design Capacity [W]";
2060 78 : PrintFlag = false;
2061 78 : TempSize = AutoSize;
2062 78 : state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
2063 156 : CoolingCapacitySizer sizerCoolingCapacity;
2064 78 : sizerCoolingCapacity.overrideSizingString(SizingString);
2065 78 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2066 78 : DesCoilLoad = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
2067 : }
2068 81 : FanCoil(FanCoilNum).DesCoolingLoad = DesCoilLoad;
2069 81 : if (DesCoilLoad >= SmallLoad) {
2070 162 : rho = GetDensityGlycol(state,
2071 81 : state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).CoolCoilPlantLoc.loopNum).FluidName,
2072 : 5.,
2073 81 : state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).CoolCoilPlantLoc.loopNum).FluidIndex,
2074 : RoutineNameNoSpace);
2075 162 : Cp = GetSpecificHeatGlycol(state,
2076 81 : state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).CoolCoilPlantLoc.loopNum).FluidName,
2077 : 5.,
2078 81 : state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).CoolCoilPlantLoc.loopNum).FluidIndex,
2079 : RoutineNameNoSpace);
2080 81 : MaxColdWaterVolFlowDes = DesCoilLoad / (WaterCoilSizDeltaT * Cp * rho);
2081 : } else {
2082 0 : MaxColdWaterVolFlowDes = 0.0;
2083 : }
2084 : }
2085 : }
2086 81 : if (IsAutoSize) {
2087 81 : FanCoil(FanCoilNum).MaxColdWaterVolFlow = MaxColdWaterVolFlowDes;
2088 243 : BaseSizer::reportSizerOutput(state,
2089 81 : FanCoil(FanCoilNum).UnitType,
2090 81 : FanCoil(FanCoilNum).Name,
2091 : "Design Size Maximum Cold Water Flow [m3/s]",
2092 81 : MaxColdWaterVolFlowDes);
2093 : } else { // Hard size with sizing data
2094 0 : if (FanCoil(FanCoilNum).MaxColdWaterVolFlow > 0.0 && MaxColdWaterVolFlowDes > 0.0) {
2095 0 : MaxColdWaterVolFlowUser = FanCoil(FanCoilNum).MaxColdWaterVolFlow;
2096 0 : BaseSizer::reportSizerOutput(state,
2097 0 : FanCoil(FanCoilNum).UnitType,
2098 0 : FanCoil(FanCoilNum).Name,
2099 : "Design Size Maximum Cold Water Flow [m3/s]",
2100 : MaxColdWaterVolFlowDes,
2101 : "User-Specified Maximum Cold Water Flow [m3/s]",
2102 0 : MaxColdWaterVolFlowUser);
2103 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2104 0 : if ((std::abs(MaxColdWaterVolFlowDes - MaxColdWaterVolFlowUser) / MaxColdWaterVolFlowUser) >
2105 0 : state.dataSize->AutoVsHardSizingThreshold) {
2106 0 : ShowMessage(state,
2107 0 : "SizeFanCoilUnit: Potential issue with equipment sizing for " + FanCoil(FanCoilNum).UnitType + ' ' +
2108 0 : FanCoil(FanCoilNum).Name);
2109 0 : ShowContinueError(state, format("User-Specified Maximum Cold Water Flow of {:.5R}[m3/s]", MaxColdWaterVolFlowUser));
2110 0 : ShowContinueError(state,
2111 0 : format("differs from Design Size Maximum Cold Water Flow of {:.5R}[m3/s]", MaxColdWaterVolFlowDes));
2112 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2113 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2114 : }
2115 : }
2116 : }
2117 : }
2118 : }
2119 :
2120 81 : if (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::ASHRAE && !FanCoil(FanCoilNum).ASHRAETempControl) {
2121 :
2122 3 : CompType = FanCoil(FanCoilNum).UnitType;
2123 3 : CompName = FanCoil(FanCoilNum).Name;
2124 3 : PrintFlag = true;
2125 :
2126 6 : ZoneCoolingLoadSizer sizerZoneCoolingLoad;
2127 3 : sizerZoneCoolingLoad.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2128 3 : FanCoil(FanCoilNum).DesZoneCoolingLoad = sizerZoneCoolingLoad.size(state, FanCoil(FanCoilNum).DesZoneCoolingLoad, ErrorsFound);
2129 3 : FanCoil(FanCoilNum).DesZoneCoolingLoad *= -1.0;
2130 :
2131 6 : ZoneHeatingLoadSizer sizerZoneHeatingLoad;
2132 3 : sizerZoneHeatingLoad.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2133 3 : FanCoil(FanCoilNum).DesZoneHeatingLoad = sizerZoneHeatingLoad.size(state, FanCoil(FanCoilNum).DesZoneHeatingLoad, ErrorsFound);
2134 :
2135 3 : FanCoil(FanCoilNum).DSOAPtr = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneDesignSpecOAIndex;
2136 :
2137 78 : } else if (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::ASHRAE && FanCoil(FanCoilNum).ASHRAETempControl) {
2138 :
2139 0 : CompType = FanCoil(FanCoilNum).UnitType;
2140 0 : CompName = FanCoil(FanCoilNum).Name;
2141 0 : Real64 capacityMultiplier = 0.6; // 60% of design zone load for water coils
2142 0 : state.dataSize->DataCapacityUsedForSizing = FanCoil(FanCoilNum).DesCoolingLoad * capacityMultiplier;
2143 0 : CheckThisZoneForSizing(state, state.dataSize->CurZoneEqNum, SizingDesRunThisZone);
2144 0 : if (SizingDesRunThisZone) {
2145 0 : state.dataSize->DataCapacityUsedForSizing =
2146 0 : state.dataSize->FinalZoneSizing(FanCoil(FanCoilNum).ControlZoneNum).DesCoolLoad * capacityMultiplier;
2147 : } else {
2148 0 : state.dataSize->DataCapacityUsedForSizing = FanCoil(FanCoilNum).DesCoolingLoad * capacityMultiplier;
2149 : }
2150 0 : state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
2151 0 : PrintFlag = true;
2152 0 : ASHRAEMinSATCoolingSizer sizerASHRAEMinSATCooling;
2153 0 : sizerASHRAEMinSATCooling.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2154 0 : FanCoil(FanCoilNum).DesignMinOutletTemp = sizerASHRAEMinSATCooling.size(state, FanCoil(FanCoilNum).DesignMinOutletTemp, ErrorsFound);
2155 :
2156 0 : if (SizingDesRunThisZone) {
2157 0 : state.dataSize->DataCapacityUsedForSizing =
2158 0 : state.dataSize->FinalZoneSizing(FanCoil(FanCoilNum).ControlZoneNum).DesHeatLoad * capacityMultiplier;
2159 : } else {
2160 0 : state.dataSize->DataCapacityUsedForSizing = FanCoil(FanCoilNum).DesHeatingLoad * capacityMultiplier;
2161 : }
2162 0 : state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
2163 0 : ASHRAEMaxSATHeatingSizer sizerASHRAEMaxSATHeating;
2164 0 : sizerASHRAEMaxSATHeating.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2165 0 : FanCoil(FanCoilNum).DesignMaxOutletTemp = sizerASHRAEMaxSATHeating.size(state, FanCoil(FanCoilNum).DesignMaxOutletTemp, ErrorsFound);
2166 :
2167 0 : state.dataSize->DataCapacityUsedForSizing = 0.0; // reset so other routines don't use this inadvertently
2168 0 : state.dataSize->DataFlowUsedForSizing = 0.0;
2169 :
2170 0 : SizingDesRunThisZone = false;
2171 0 : CheckThisZoneForSizing(state, state.dataSize->CurZoneEqNum, SizingDesRunThisZone);
2172 :
2173 0 : if (SizingDesRunThisZone) {
2174 :
2175 0 : FanCoil(FanCoilNum).DesZoneCoolingLoad =
2176 0 : -1.0 * (FanCoil(FanCoilNum).DesCoolingLoad / state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).CoolSizingFactor);
2177 0 : FanCoil(FanCoilNum).DesZoneHeatingLoad =
2178 0 : FanCoil(FanCoilNum).DesHeatingLoad / state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).HeatSizingFactor;
2179 0 : FanCoil(FanCoilNum).DSOAPtr = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneDesignSpecOAIndex;
2180 :
2181 : } else {
2182 :
2183 0 : FanCoil(FanCoilNum).DesZoneCoolingLoad = -1.0 * FanCoil(FanCoilNum).DesCoolingLoad;
2184 0 : FanCoil(FanCoilNum).DesZoneHeatingLoad = FanCoil(FanCoilNum).DesHeatingLoad;
2185 : }
2186 : }
2187 :
2188 : } // if ( CurZoneEqNum > 0 )
2189 :
2190 : // set the design air flow rates for the heating and cooling coils
2191 81 : if (UtilityRoutines::SameString(FanCoil(FanCoilNum).CCoilType, "CoilSystem:Cooling:Water:HeatExchangerAssisted")) {
2192 0 : CoolingCoilName = GetHXDXCoilName(state, FanCoil(FanCoilNum).CCoilType, FanCoil(FanCoilNum).CCoilName, ErrorsFound);
2193 0 : CoolingCoilType = GetHXCoilType(state, FanCoil(FanCoilNum).CCoilType, FanCoil(FanCoilNum).CCoilName, ErrorsFound);
2194 : } else {
2195 81 : CoolingCoilName = FanCoil(FanCoilNum).CCoilName;
2196 81 : CoolingCoilType = FanCoil(FanCoilNum).CCoilType;
2197 : }
2198 81 : if (state.dataSize->ZoneSizingRunDone) {
2199 81 : WaterCoils::SetCoilDesFlow(
2200 81 : state, CoolingCoilType, CoolingCoilName, state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow, ErrorsFound);
2201 243 : WaterCoils::SetCoilDesFlow(state,
2202 81 : FanCoil(FanCoilNum).HCoilType,
2203 81 : FanCoil(FanCoilNum).HCoilName,
2204 81 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow,
2205 : ErrorsFound);
2206 : } else {
2207 0 : WaterCoils::SetCoilDesFlow(state, CoolingCoilType, CoolingCoilName, FanCoil(FanCoilNum).MaxAirVolFlow, ErrorsFound);
2208 0 : WaterCoils::SetCoilDesFlow(
2209 0 : state, FanCoil(FanCoilNum).HCoilType, FanCoil(FanCoilNum).HCoilName, FanCoil(FanCoilNum).MaxAirVolFlow, ErrorsFound);
2210 : }
2211 81 : if (state.dataSize->CurZoneEqNum > 0) {
2212 81 : ZoneEqSizing(state.dataSize->CurZoneEqNum).MaxHWVolFlow = FanCoil(FanCoilNum).MaxHotWaterVolFlow;
2213 81 : ZoneEqSizing(state.dataSize->CurZoneEqNum).MaxCWVolFlow = FanCoil(FanCoilNum).MaxColdWaterVolFlow;
2214 81 : ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow = FanCoil(FanCoilNum).MaxAirVolFlow;
2215 81 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesCoolingLoad = FanCoil(FanCoilNum).DesCoolingLoad;
2216 81 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad = FanCoil(FanCoilNum).DesHeatingLoad;
2217 81 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesignSizeFromParent = true;
2218 : }
2219 :
2220 81 : if (ErrorsFound) {
2221 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
2222 : }
2223 81 : }
2224 :
2225 514191 : void Sim4PipeFanCoil(EnergyPlusData &state,
2226 : int &FanCoilNum, // number of the current fan coil unit being simulated
2227 : int const ControlledZoneNum, // index into ZoneEqupConfig
2228 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
2229 : Real64 &PowerMet, // Sensible power supplied (W)
2230 : Real64 &LatOutputProvided // Latent power supplied (kg/s), negative = dehumidification
2231 : )
2232 : {
2233 :
2234 : // SUBROUTINE INFORMATION:
2235 : // AUTHOR Fred Buhl
2236 : // DATE WRITTEN March 2000
2237 : // MODIFIED Don Shirey, Aug 2009 (LatOutputProvided)
2238 : // MODIFIED Arnaud Flament June 2010 (added airflow capacity control methods)
2239 : // MODIFIED R. Raustad, FSEC, Feb 2016 (added ASHRAE 90.1 SZVAV system control)
2240 :
2241 : // PURPOSE OF THIS SUBROUTINE:
2242 : // Simulate a 4 pipe fan coil unit; adjust its output to match the
2243 : // remaining zone load.
2244 :
2245 : // METHODOLOGY EMPLOYED:
2246 : // If unit is on, calls ControlCompOutput to obtain the desired unit output
2247 :
2248 : // REFERENCES:
2249 : // SZVAV sysetm control:
2250 : // ASHRAE 90.1 2010 Section 6.4.3.10 - Single Zone Variable-Air-volume Controls (described in Trane newsletter entitled Understanding
2251 : // Single-Zone VAV Systems) Trane Engineers Newsletter -
2252 : // https://www.trane.com/content/dam/Trane/Commercial/global/products-systems/education-training/engineers-newsletters/airside-design/admapn047en_0413.pdf
2253 : //
2254 :
2255 : // Using/Aliasing
2256 : using namespace DataZoneEnergyDemands;
2257 :
2258 : using PlantUtilities::SetComponentFlowRate;
2259 : using Psychrometrics::PsyHFnTdbW;
2260 : using Psychrometrics::PsyRhoAirFnPbTdbW;
2261 : using namespace DataPlant;
2262 : using namespace DataLoopNode;
2263 :
2264 514191 : int constexpr MaxIterCycl(100);
2265 :
2266 : Real64 QZnReq; // heating or cooling needed by zone [watts]
2267 : Real64 QUnitOut; // heating or sens. cooling provided by fan coil unit [watts]
2268 : Real64 QUnitOutMax; // heating or sens. cooling provided by fan coil unit (running during an entire timestep)
2269 : Real64 PLR; // Part Load Ratio, fraction of time step fancoil is on
2270 : bool UnitOn; // TRUE if unit is on
2271 : int ControlNode; // the hot water or cold water inlet node
2272 : Real64 ControlOffset; // tolerance for output control
2273 : Real64 MaxWaterFlow; // maximum water flow for heating or cooling [kg/sec]
2274 : Real64 MinWaterFlow; // minimum water flow for heating or cooling [kg/sec]
2275 : Real64 PLRMin; // minimum PLR used for tighter control of air and water flow rate
2276 : Real64 PLRMax; // maximum PLR used for tighter control of air and water flow rate
2277 : int OutletNode; // unit air outlet node
2278 : int InletNode; // unit air inlet node
2279 : Real64 QTotUnitOut; // total unit output [watts]
2280 : Real64 AirMassFlow; // air mass flow rate [kg/sec]
2281 : Real64 QUnitOutNoHC; // unit output with no active heating or cooling [W]
2282 : Real64 QUnitOutMaxC; // unit output with full active cooling [W]
2283 : Real64 QUnitOutMaxH; // unit output with full active heating [W]
2284 : Real64 QCoilHeatSP; // coil load to the heating setpoint [W]
2285 : Real64 QCoilCoolSP; // coil load to the cooling setpoint [W]
2286 : Real64 LatentOutput; // Latent (moisture) add/removal rate, negative is dehumidification [kg/s]
2287 : Real64 SpecHumOut; // Specific humidity ratio of outlet air (kg moisture / kg moist air)
2288 : Real64 SpecHumIn; // Specific humidity ratio of inlet air (kg moisture / kg moist air)
2289 : Real64 Error; // Error between QZnReq and QUnitOut
2290 : Real64 AbsError; // Absolute error between QZnReq and QUnitOut [W] !FB
2291 : int Iter; // iteration counter
2292 : Real64 Relax;
2293 : Real64 DelPLR;
2294 : Real64 mdot;
2295 : // Real64 Low_mdot;
2296 : Real64 QSensUnitOutNoATM; // unit output not including air added by supply side air terminal mixer
2297 : int SolFlag; // return flag from RegulaFalsi for sensible load
2298 : Real64 ElectricHeaterControl; // 1 or 0, enables or disables heating coil
2299 : Real64 OAVolumeFlowRate; // OA volume flow rate based on design specifications object [m3/s]
2300 : Real64 OAMassFlow; // OA mass flow rate based on design specifications object [kg/s]
2301 : Real64 RhoAir; // density of air [kg/m3]
2302 : Real64 MinSAMassFlowRate; // minimum supply air mass flow rate [kg/s]
2303 : Real64 MaxSAMassFlowRate; // maximum supply air mass flow rate [kg/s]
2304 : // Real64 FCOutletTempOn; // ASHRAE outlet air temperature when coil is on [C]
2305 : Real64 HWFlow; // hot water mass flow rate solution [kg/s]
2306 : Real64 MdotLockH; // saved value of locked chilled water mass flow rate [kg/s]
2307 : Real64 MdotLockC; // saved value of locked hot water mass flow rate [kg/s]
2308 : Real64 CWFlow; // cold water mass flow rate solution [kg/s]
2309 : Real64 CWFlowBypass; // cold water bypassed mass flow rate [kg/s]
2310 : Real64 HWFlowBypass; // hot water bypassed mass flow rate [kg/s]
2311 : bool ColdFlowLocked; // if true cold water flow is locked
2312 : bool HotFlowLocked; // if true Hot water flow is locked
2313 :
2314 514191 : auto &Node(state.dataLoopNodes->Node);
2315 :
2316 : // initialize local variables
2317 514191 : UnitOn = true;
2318 514191 : ControlNode = 0;
2319 514191 : QUnitOut = 0.0;
2320 514191 : QUnitOutMax = 0.0;
2321 514191 : PLR = 0.0;
2322 514191 : LatentOutput = 0.0;
2323 514191 : QUnitOutNoHC = 0.0;
2324 514191 : QCoilHeatSP = 0.0;
2325 514191 : QCoilCoolSP = 0.0;
2326 514191 : QZnReq = 0.0;
2327 514191 : ControlOffset = 0.0;
2328 514191 : MaxWaterFlow = 0.0;
2329 514191 : MinWaterFlow = 0.0;
2330 514191 : OutletNode = state.dataFanCoilUnits->FanCoil(FanCoilNum).AirOutNode;
2331 514191 : InletNode = state.dataFanCoilUnits->FanCoil(FanCoilNum).AirInNode;
2332 514191 : AirMassFlow = Node(InletNode).MassFlowRate;
2333 514191 : Error = 1.0;
2334 514191 : AbsError = 2.0 * SmallLoad;
2335 514191 : Iter = 0;
2336 514191 : Relax = 1.0;
2337 514191 : ElectricHeaterControl = 0.0;
2338 514191 : HWFlow = 0.0;
2339 514191 : HWFlowBypass = 0.0;
2340 514191 : MdotLockH = 0.0;
2341 514191 : MdotLockC = 0.0;
2342 514191 : ColdFlowLocked = false;
2343 514191 : HotFlowLocked = false;
2344 :
2345 514191 : auto &FanCoil(state.dataFanCoilUnits->FanCoil);
2346 :
2347 : // select capacity control method
2348 514191 : switch (FanCoil(FanCoilNum).CapCtrlMeth_Num) {
2349 280714 : case CCM::ConsFanVarFlow: {
2350 :
2351 280714 : if (AirMassFlow < SmallMassFlow) UnitOn = false;
2352 : // zero the hot & cold water flows
2353 :
2354 : // set water coil flow rate to 0 to calculate coil off capacity (only valid while flow is unlocked)
2355 280714 : mdot = 0.0;
2356 842142 : SetComponentFlowRate(state,
2357 : mdot,
2358 280714 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
2359 280714 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
2360 280714 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
2361 561428 : if (state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).CoolCoilPlantLoc.loopNum)
2362 280714 : .LoopSide(FanCoil(FanCoilNum).CoolCoilPlantLoc.loopSideNum)
2363 280714 : .FlowLock == DataPlant::FlowLock::Locked) {
2364 216 : ColdFlowLocked = true; // check for flow lock
2365 : }
2366 280714 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
2367 280714 : mdot = 0.0;
2368 842142 : SetComponentFlowRate(state,
2369 : mdot,
2370 280714 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
2371 280714 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
2372 280714 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
2373 561428 : if (state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).HeatCoilPlantLoc.loopNum)
2374 280714 : .LoopSide(FanCoil(FanCoilNum).HeatCoilPlantLoc.loopSideNum)
2375 280714 : .FlowLock == DataPlant::FlowLock::Locked) {
2376 216 : HotFlowLocked = true; // save locked flow
2377 : }
2378 : }
2379 : // obtain unit output with no active heating/cooling
2380 280714 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutNoHC, 0.0);
2381 :
2382 280714 : if (ColdFlowLocked || HotFlowLocked) {
2383 216 : QUnitOutNoHC = FanCoil(FanCoilNum).QUnitOutNoHC;
2384 : } else { // continue to update QUnitOutNoHC while flow is unlocked
2385 280498 : FanCoil(FanCoilNum).QUnitOutNoHC = QUnitOutNoHC;
2386 : }
2387 :
2388 : // then calculate the loads at the coils
2389 280714 : QCoilHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP - QUnitOutNoHC;
2390 280714 : QCoilCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP - QUnitOutNoHC;
2391 :
2392 : // if cooling
2393 432128 : if (UnitOn && QCoilCoolSP < (-1.0 * SmallLoad) &&
2394 151414 : state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != DataHVACGlobals::ThermostatType::SingleHeating) {
2395 151072 : ControlNode = FanCoil(FanCoilNum).CoolCoilFluidInletNode;
2396 151072 : ControlOffset = FanCoil(FanCoilNum).ColdControlOffset;
2397 151072 : MaxWaterFlow = FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
2398 151072 : MinWaterFlow = FanCoil(FanCoilNum).MinColdWaterFlow;
2399 : // On the first HVAC iteration the system values are given to the controller, but after that
2400 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
2401 151072 : if (!FirstHVACIteration) {
2402 90516 : MaxWaterFlow = Node(ControlNode).MassFlowRateMaxAvail;
2403 90516 : MinWaterFlow = Node(ControlNode).MassFlowRateMinAvail;
2404 : }
2405 : // get full load result
2406 151072 : mdot = MaxWaterFlow;
2407 453216 : SetComponentFlowRate(state,
2408 : mdot,
2409 151072 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
2410 151072 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
2411 151072 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
2412 151072 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMaxC);
2413 151072 : if (!ColdFlowLocked) {
2414 151010 : FanCoil(FanCoilNum).QUnitOutMaxC = QUnitOutMaxC;
2415 : } else {
2416 62 : QUnitOutMaxC = FanCoil(FanCoilNum).QUnitOutMaxC;
2417 62 : MdotLockC = mdot; // save locked flow
2418 : }
2419 151072 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
2420 151072 : if (QUnitOutMaxC < QZnReq) {
2421 : // more cooling than required, find reduced water flow rate to meet the load
2422 : // solve for the cold water flow rate with no limit set by flow rate lockdown
2423 3319552 : auto f = [&state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq](Real64 const CWFlow) {
2424 1659776 : return CalcFanCoilCWLoadResidual(state, CWFlow, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq);
2425 1809546 : };
2426 149770 : General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, CWFlow, f, 0.0, MaxWaterFlow);
2427 149770 : if (SolFlag == -1) {
2428 : // tighten limits on water flow rate to see if this allows convergence
2429 0 : state.dataFanCoilUnits->CoolingLoad = true;
2430 0 : state.dataFanCoilUnits->HeatingLoad = false;
2431 0 : TightenWaterFlowLimits(state,
2432 : FanCoilNum,
2433 0 : state.dataFanCoilUnits->CoolingLoad,
2434 0 : state.dataFanCoilUnits->HeatingLoad,
2435 0 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
2436 : ControlledZoneNum,
2437 : FirstHVACIteration,
2438 : QZnReq,
2439 : MinWaterFlow,
2440 : MaxWaterFlow);
2441 0 : General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, CWFlow, f, MinWaterFlow, MaxWaterFlow);
2442 0 : if (SolFlag == -1) {
2443 0 : ++FanCoil(FanCoilNum).ConvgErrCountC;
2444 0 : if (FanCoil(FanCoilNum).ConvgErrCountC < 2) {
2445 0 : ShowWarningError(state, "Cold Water control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
2446 0 : ShowContinueError(state, " Iteration limit exceeded in calculating water flow rate ");
2447 0 : Node(FanCoil(FanCoilNum).CoolCoilFluidInletNode).MassFlowRate = CWFlow;
2448 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
2449 0 : ShowContinueErrorTimeStamp(state, format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut));
2450 0 : ShowContinueErrorTimeStamp(
2451 : state,
2452 0 : format("Min water flow used during iterations = {}, Max water flow used during iterations = {}",
2453 : MinWaterFlow,
2454 0 : MaxWaterFlow));
2455 0 : ShowContinueErrorTimeStamp(state, format("Water flow rate on last iteration = {}", CWFlow));
2456 0 : ShowContinueErrorTimeStamp(state, "..Water flow rate set to last iteration value ");
2457 : } else {
2458 0 : ShowRecurringWarningErrorAtEnd(state,
2459 0 : "Cold water flow Iteration limit exceeded in fan coil unit " +
2460 0 : FanCoil(FanCoilNum).Name,
2461 0 : FanCoil(FanCoilNum).MaxIterIndexC);
2462 : }
2463 0 : } else if (SolFlag == -2) {
2464 0 : ++FanCoil(FanCoilNum).LimitErrCountC;
2465 0 : if (FanCoil(FanCoilNum).LimitErrCountC < 2) {
2466 0 : ShowWarningError(state, "Cold Water control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
2467 0 : ShowContinueError(state, " Bad cold water mass flow limits");
2468 0 : ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit ");
2469 : } else {
2470 0 : ShowRecurringWarningErrorAtEnd(state,
2471 0 : "Cold Water control failed in fan coil unit " + FanCoil(FanCoilNum).Name,
2472 0 : FanCoil(FanCoilNum).BadMassFlowLimIndexC);
2473 : }
2474 : }
2475 149770 : } else if (SolFlag == -2) {
2476 0 : ++FanCoil(FanCoilNum).LimitErrCountC;
2477 0 : if (FanCoil(FanCoilNum).LimitErrCountC < 2) {
2478 0 : ShowWarningError(state, "Cold Water control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
2479 0 : ShowContinueError(state, " Bad cold water mass flow limits");
2480 0 : ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit ");
2481 : } else {
2482 0 : ShowRecurringWarningErrorAtEnd(state,
2483 0 : "Cold Water control failed in fan coil unit " + FanCoil(FanCoilNum).Name,
2484 0 : FanCoil(FanCoilNum).BadMassFlowLimIndexC);
2485 : }
2486 : }
2487 : } else {
2488 : // demand greater than capacity
2489 1302 : CWFlow = MaxWaterFlow;
2490 : }
2491 151072 : if (!ColdFlowLocked) {
2492 151010 : mdot = CWFlow; // not flowlocked - set flow to CWFlow
2493 453030 : SetComponentFlowRate(state,
2494 : mdot,
2495 151010 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
2496 151010 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
2497 151010 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
2498 151010 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); // get QUnitOut
2499 : } else {
2500 : // flow lock on
2501 62 : if (MdotLockC > CWFlow) { // if mdot > CWFlow, bypass extra flow
2502 31 : Calc4PipeFanCoil(state,
2503 : FanCoilNum,
2504 : ControlledZoneNum,
2505 : FirstHVACIteration,
2506 : QUnitOut); // get QUnitOut with CWFlow; rest will be bypassed
2507 31 : Node(FanCoil(FanCoilNum).CoolCoilFluidInletNode).MassFlowRate =
2508 : MdotLockC; // reset flow to locked value. Since lock is on, must do this by hand
2509 31 : Node(FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum).MassFlowRate = MdotLockC;
2510 : // Keep soln flow rate but reset outlet water temperature - i.e. bypass extra water
2511 31 : CWFlowBypass = MdotLockC - CWFlow;
2512 : // change water outlet temperature and enthalpy
2513 31 : Node(FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum).Temp =
2514 62 : (CWFlowBypass * Node(FanCoil(FanCoilNum).CoolCoilFluidInletNode).Temp +
2515 62 : CWFlow * Node(FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum).Temp) /
2516 : MdotLockC;
2517 31 : Node(FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum).Enthalpy =
2518 62 : (CWFlowBypass * Node(FanCoil(FanCoilNum).CoolCoilFluidInletNode).Enthalpy +
2519 62 : CWFlow * Node(FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum).Enthalpy) /
2520 : MdotLockC;
2521 : } else {
2522 : // if MdotLockC <= CWFlow use MdotLockC as is
2523 31 : Node(FanCoil(FanCoilNum).CoolCoilFluidInletNode).MassFlowRate =
2524 : MdotLockC; // reset flow to locked value. Since lock is on, must do this by hand
2525 31 : Node(FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum).MassFlowRate = MdotLockC;
2526 31 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
2527 : }
2528 : }
2529 151072 : QUnitOut = calcZoneSensibleOutput(AirMassFlow, Node(OutletNode).Temp, Node(InletNode).Temp, Node(InletNode).HumRat);
2530 :
2531 : // if heating
2532 246352 : } else if (UnitOn && QCoilHeatSP > SmallLoad &&
2533 116710 : state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != DataHVACGlobals::ThermostatType::SingleCooling) {
2534 : // get full load result
2535 113859 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) { // if HW Coil
2536 113859 : ControlNode = FanCoil(FanCoilNum).HeatCoilFluidInletNode;
2537 113859 : ControlOffset = FanCoil(FanCoilNum).HotControlOffset;
2538 113859 : MaxWaterFlow = FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
2539 113859 : MinWaterFlow = FanCoil(FanCoilNum).MinHotWaterFlow;
2540 : // On the first HVAC iteration the system values are given to the controller, but after that
2541 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
2542 113859 : if (!FirstHVACIteration) {
2543 56921 : MaxWaterFlow = Node(ControlNode).MassFlowRateMaxAvail;
2544 56921 : MinWaterFlow = Node(ControlNode).MassFlowRateMinAvail;
2545 : }
2546 113859 : mdot = MaxWaterFlow;
2547 341577 : SetComponentFlowRate(state,
2548 : mdot,
2549 113859 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
2550 113859 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
2551 113859 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
2552 113859 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMaxH);
2553 113859 : if (!HotFlowLocked) {
2554 113823 : FanCoil(FanCoilNum).QUnitOutMaxH = QUnitOutMaxH;
2555 : } else {
2556 36 : QUnitOutMaxH = FanCoil(FanCoilNum).QUnitOutMaxH;
2557 36 : MdotLockH = mdot; // save locked flow
2558 : }
2559 : } else {
2560 : // not HW coil
2561 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMaxH, 1.0);
2562 : }
2563 113859 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
2564 113859 : if (QUnitOutMaxH > QZnReq) {
2565 : // more heating than required, find reduced water flow rate to meet the load
2566 113275 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
2567 : // solve for the hot water flow rate with no limit set by flow rate lockdown
2568 9327966 : auto f = [&state, FirstHVACIteration, FanCoilNum, ControlledZoneNum, QZnReq](Real64 HWFlow) {
2569 : // To calculate the part-load ratio for the FCU with electric heating coil
2570 : Real64 QUnitOut; // delivered capacity [W]
2571 4145968 : state.dataLoopNodes->Node(state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode).MassFlowRate = HWFlow;
2572 3109476 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, 1.0);
2573 : // Calculate residual based on output magnitude
2574 1036492 : if (std::abs(QZnReq) <= 100.0) {
2575 924 : return (QUnitOut - QZnReq) / 100.0;
2576 : } else {
2577 3108090 : return (QUnitOut - QZnReq) / QZnReq;
2578 : }
2579 113275 : };
2580 113275 : General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, HWFlow, f, 0.0, MaxWaterFlow);
2581 113275 : if (SolFlag == -1) {
2582 : // tighten limits on water flow rate to see if this allows convergence
2583 0 : state.dataFanCoilUnits->CoolingLoad = false;
2584 0 : state.dataFanCoilUnits->HeatingLoad = true;
2585 0 : TightenWaterFlowLimits(state,
2586 : FanCoilNum,
2587 0 : state.dataFanCoilUnits->CoolingLoad,
2588 0 : state.dataFanCoilUnits->HeatingLoad,
2589 0 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
2590 : ControlledZoneNum,
2591 : FirstHVACIteration,
2592 : QZnReq,
2593 : MinWaterFlow,
2594 : MaxWaterFlow);
2595 0 : General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, HWFlow, f, MinWaterFlow, MaxWaterFlow);
2596 0 : if (SolFlag == -1) {
2597 0 : ++FanCoil(FanCoilNum).ConvgErrCountH;
2598 0 : if (FanCoil(FanCoilNum).ConvgErrCountH < 2) {
2599 0 : ShowWarningError(state, "Hot Water control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
2600 0 : ShowContinueError(state, " Iteration limit exceeded in calculating water flow rate ");
2601 0 : Node(FanCoil(FanCoilNum).HeatCoilFluidInletNode).MassFlowRate = HWFlow;
2602 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
2603 0 : ShowContinueErrorTimeStamp(state, format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut));
2604 0 : ShowContinueErrorTimeStamp(
2605 : state,
2606 0 : format("Min water flow used during iterations = {}, Max water flow used during iterations = {}",
2607 : MinWaterFlow,
2608 0 : MaxWaterFlow));
2609 0 : ShowContinueErrorTimeStamp(state, format("Water flow rate on last iteration = {}", HWFlow));
2610 0 : ShowContinueErrorTimeStamp(state, "..Water flow rate set to last iteration value ");
2611 : } else {
2612 0 : ShowRecurringWarningErrorAtEnd(state,
2613 0 : "Hot water flow Iteration limit exceeded in fan coil unit " +
2614 0 : FanCoil(FanCoilNum).Name,
2615 0 : FanCoil(FanCoilNum).MaxIterIndexH);
2616 : }
2617 0 : } else if (SolFlag == -2) {
2618 0 : ++FanCoil(FanCoilNum).LimitErrCountH;
2619 0 : if (FanCoil(FanCoilNum).LimitErrCountH < 2) {
2620 0 : ShowWarningError(state, "Hot Water control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
2621 0 : ShowContinueError(state, " Bad hot water mass flow limits");
2622 0 : ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit ");
2623 : } else {
2624 0 : ShowRecurringWarningErrorAtEnd(state,
2625 0 : "Hot Water control failed in fan coil unit " + FanCoil(FanCoilNum).Name,
2626 0 : FanCoil(FanCoilNum).BadMassFlowLimIndexH);
2627 : }
2628 : }
2629 113275 : } else if (SolFlag == -2) {
2630 0 : ++FanCoil(FanCoilNum).LimitErrCountH;
2631 0 : if (FanCoil(FanCoilNum).LimitErrCountH < 2) {
2632 0 : ShowWarningError(state, "Hot Water control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
2633 0 : ShowContinueError(state, " Bad hot water mass flow limits");
2634 0 : ShowContinueErrorTimeStamp(state, "..Water flow rate set to lower limit ");
2635 : } else {
2636 0 : ShowRecurringWarningErrorAtEnd(state,
2637 0 : "Hot Water control failed in fan coil unit " + FanCoil(FanCoilNum).Name,
2638 0 : FanCoil(FanCoilNum).BadMassFlowLimIndexH);
2639 : }
2640 : }
2641 : } else {
2642 0 : auto f = [&state, FirstHVACIteration, FanCoilNum, ControlledZoneNum, QZnReq](Real64 const PartLoadRatio) {
2643 0 : return CalcFanCoilLoadResidual(state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq, PartLoadRatio);
2644 0 : };
2645 0 : General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, 0.0, 1.0);
2646 : }
2647 : } else {
2648 : // demand greater than capacity
2649 584 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
2650 584 : HWFlow = MaxWaterFlow;
2651 : } else {
2652 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, 1.0);
2653 : }
2654 : }
2655 113859 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
2656 113859 : if (!HotFlowLocked) {
2657 113823 : mdot = HWFlow; // not flowlocked - set flow to HWFlow
2658 341469 : SetComponentFlowRate(state,
2659 : mdot,
2660 113823 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
2661 113823 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
2662 113823 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
2663 113823 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut); // get QUnitOut
2664 : } else {
2665 : // flow lock on
2666 36 : if (MdotLockH > HWFlow) { // if mdot > HWFlow, bypass extra flow
2667 19 : Calc4PipeFanCoil(state,
2668 : FanCoilNum,
2669 : ControlledZoneNum,
2670 : FirstHVACIteration,
2671 : QUnitOut); // get QUnitOut with HWFlow; rest will be bypassed
2672 19 : Node(FanCoil(FanCoilNum).HeatCoilFluidInletNode).MassFlowRate =
2673 : MdotLockH; // reset flow to locked value. Since lock is on, must do this by hand
2674 19 : Node(FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum).MassFlowRate = MdotLockH;
2675 : // Keep soln flow rate but reset outlet water temperature - i.e. bypass extra water
2676 19 : HWFlowBypass = MdotLockH - HWFlow;
2677 : // change outlet water temperature and enthalpy
2678 19 : Node(FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum).Temp =
2679 38 : (HWFlowBypass * Node(FanCoil(FanCoilNum).HeatCoilFluidInletNode).Temp +
2680 38 : HWFlow * Node(FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum).Temp) /
2681 : MdotLockH;
2682 19 : Node(FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum).Enthalpy =
2683 38 : (HWFlowBypass * Node(FanCoil(FanCoilNum).HeatCoilFluidInletNode).Enthalpy +
2684 38 : HWFlow * Node(FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum).Enthalpy) /
2685 : MdotLockH;
2686 : } else {
2687 : // if MdotLockH <= HWFlow use MdotLockH as is
2688 17 : Node(FanCoil(FanCoilNum).HeatCoilFluidInletNode).MassFlowRate =
2689 : MdotLockH; // reset flow to locked value. Since lock is on, must do this by hand
2690 17 : Node(FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum).MassFlowRate = MdotLockH;
2691 17 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
2692 : }
2693 : }
2694 : }
2695 113859 : QUnitOut = calcZoneSensibleOutput(AirMassFlow, Node(OutletNode).Temp, Node(InletNode).Temp, Node(InletNode).HumRat);
2696 : } else {
2697 : // no action
2698 15783 : QUnitOut = QUnitOutNoHC;
2699 : }
2700 :
2701 : // CR9155 Remove specific humidity calculations
2702 280714 : SpecHumOut = Node(OutletNode).HumRat;
2703 280714 : SpecHumIn = Node(InletNode).HumRat;
2704 280714 : LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
2705 280714 : QTotUnitOut = AirMassFlow * (Node(OutletNode).Enthalpy - Node(InletNode).Enthalpy);
2706 : // report variables
2707 280714 : FanCoil(FanCoilNum).HeatPower = max(0.0, QUnitOut);
2708 280714 : FanCoil(FanCoilNum).SensCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QUnitOut));
2709 280714 : FanCoil(FanCoilNum).TotCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QTotUnitOut));
2710 280714 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
2711 235012 : FanCoil(FanCoilNum).ElecPower = Fans::GetFanPower(state, FanCoil(FanCoilNum).FanIndex);
2712 : } else {
2713 45702 : FanCoil(FanCoilNum).ElecPower = state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->fanPower();
2714 : }
2715 :
2716 280714 : PowerMet = QUnitOut;
2717 280714 : LatOutputProvided = LatentOutput;
2718 :
2719 : // cycling fan constant water flow AND VarFanVarFlow
2720 280714 : } break;
2721 203855 : case CCM::CycFan:
2722 : case CCM::VarFanVarFlow: {
2723 :
2724 203855 : if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ControlledZoneNum) || AirMassFlow < SmallMassFlow) UnitOn = false;
2725 :
2726 : // zero the hot & cold water flows
2727 203855 : mdot = 0.0;
2728 611565 : SetComponentFlowRate(state,
2729 : mdot,
2730 203855 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
2731 203855 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
2732 203855 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
2733 407710 : if (state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).CoolCoilPlantLoc.loopNum)
2734 203855 : .LoopSide(FanCoil(FanCoilNum).CoolCoilPlantLoc.loopSideNum)
2735 203855 : .FlowLock == DataPlant::FlowLock::Locked) {
2736 156 : ColdFlowLocked = true; // check for flow lock
2737 : }
2738 203855 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
2739 203855 : mdot = 0.0;
2740 611565 : SetComponentFlowRate(state,
2741 : mdot,
2742 203855 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
2743 203855 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
2744 203855 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
2745 407710 : if (state.dataPlnt->PlantLoop(FanCoil(FanCoilNum).HeatCoilPlantLoc.loopNum)
2746 203855 : .LoopSide(FanCoil(FanCoilNum).HeatCoilPlantLoc.loopSideNum)
2747 203855 : .FlowLock == DataPlant::FlowLock::Locked) {
2748 156 : HotFlowLocked = true; // save locked flow
2749 : }
2750 : }
2751 :
2752 : // obtain unit output with no active heating/cooling
2753 203855 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutNoHC, 0.0);
2754 :
2755 : // get the loads at the coil
2756 203855 : QCoilHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP - QUnitOutNoHC;
2757 203855 : QCoilCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP - QUnitOutNoHC;
2758 :
2759 : // speed fan selection only for multispeed cycling fan
2760 203855 : if (UnitOn && (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::CycFan)) {
2761 166228 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputRequired;
2762 :
2763 : // set water side mass flow rate
2764 166228 : if (QCoilCoolSP < 0) {
2765 91973 : Node(FanCoil(FanCoilNum).CoolCoilFluidInletNode).MassFlowRate = FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
2766 74255 : } else if (QCoilHeatSP > 0 && FanCoil(FanCoilNum).HCoilType_Num != HCoil::Electric) {
2767 74255 : Node(FanCoil(FanCoilNum).HeatCoilFluidInletNode).MassFlowRate = FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
2768 : }
2769 :
2770 166228 : Node(InletNode).MassFlowRateMax = FanCoil(FanCoilNum).LowSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
2771 166228 : FanCoil(FanCoilNum).SpeedFanSel = 1;
2772 166228 : FanCoil(FanCoilNum).SpeedFanRatSel = FanCoil(FanCoilNum).LowSpeedRatio;
2773 166228 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
2774 166228 : if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
2775 120733 : Node(InletNode).MassFlowRateMax = FanCoil(FanCoilNum).MedSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
2776 120733 : FanCoil(FanCoilNum).SpeedFanSel = 2;
2777 120733 : FanCoil(FanCoilNum).SpeedFanRatSel = FanCoil(FanCoilNum).MedSpeedRatio;
2778 120733 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
2779 : }
2780 166228 : if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
2781 71800 : FanCoil(FanCoilNum).SpeedFanSel = 3;
2782 71800 : FanCoil(FanCoilNum).SpeedFanRatSel = 1.0;
2783 71800 : Node(InletNode).MassFlowRateMax = FanCoil(FanCoilNum).MaxAirMassFlow;
2784 : }
2785 : } else {
2786 37627 : FanCoil(FanCoilNum).SpeedFanSel = 0;
2787 : }
2788 :
2789 : // meet the coil load adjusted for fan operation
2790 295092 : if (UnitOn && QCoilCoolSP < (-1.0 * SmallLoad) &&
2791 91237 : state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != DataHVACGlobals::ThermostatType::SingleHeating) {
2792 : // cooling coil action, maximum cold water flow
2793 91237 : mdot = FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
2794 273711 : SetComponentFlowRate(state,
2795 : mdot,
2796 91237 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
2797 91237 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
2798 91237 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
2799 :
2800 91237 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
2801 91237 : ControlOffset = FanCoil(FanCoilNum).ColdControlOffset;
2802 :
2803 : // get the maximum output of the fcu
2804 91237 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax); // call without PLR means PLR = 1
2805 :
2806 91237 : if (QUnitOutMax < QZnReq) {
2807 : // more cooling than required, find reduced air and water flow rate to meet the load
2808 : // solve for the cold water flow rate with no limit set by flow rate lockdown
2809 1402012 : auto f = [&state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, &FanCoil, QZnReq](Real64 const PLR) {
2810 701006 : return CalcFanCoilPLRResidual(
2811 701006 : state, PLR, FanCoilNum, FirstHVACIteration, ControlledZoneNum, FanCoil(FanCoilNum).CoolCoilFluidInletNode, QZnReq);
2812 425466 : };
2813 74963 : General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, 0.0, 1.0);
2814 74963 : if (SolFlag == -1) {
2815 : // tighten limits on water flow rate to see if this allows convergence
2816 0 : state.dataFanCoilUnits->CoolingLoad = true;
2817 0 : state.dataFanCoilUnits->HeatingLoad = false;
2818 0 : TightenAirAndWaterFlowLimits(state,
2819 : FanCoilNum,
2820 0 : state.dataFanCoilUnits->CoolingLoad,
2821 0 : state.dataFanCoilUnits->HeatingLoad,
2822 0 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
2823 : ControlledZoneNum,
2824 : FirstHVACIteration,
2825 : QZnReq,
2826 : PLRMin,
2827 : PLRMax);
2828 0 : General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, PLRMin, PLRMax);
2829 0 : if (SolFlag == -1) {
2830 0 : ++FanCoil(FanCoilNum).ConvgErrCountC;
2831 0 : if (FanCoil(FanCoilNum).ConvgErrCountC < 2) {
2832 0 : ShowWarningError(state, "Part-load ratio cooling control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
2833 0 : ShowContinueError(state, " Iteration limit exceeded in calculating FCU part-load ratio ");
2834 0 : Node(FanCoil(FanCoilNum).CoolCoilFluidInletNode).MassFlowRate = PLR * FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
2835 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
2836 0 : ShowContinueErrorTimeStamp(state, format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut));
2837 0 : ShowContinueErrorTimeStamp(
2838 : state,
2839 0 : format("Min part-load used during iterations = {}, Max part-load used during iterations = {}", PLRMin, PLRMax));
2840 0 : ShowContinueErrorTimeStamp(state, format("Part-load ratio on last iteration = {}", PLR));
2841 0 : ShowContinueErrorTimeStamp(state, "..Part-load ratio set to last iteration value ");
2842 : } else {
2843 0 : ShowRecurringWarningErrorAtEnd(state,
2844 0 : "Part-load ratio cooling iteration limit exceeded in fan coil unit " +
2845 0 : FanCoil(FanCoilNum).Name,
2846 0 : FanCoil(FanCoilNum).MaxIterIndexC);
2847 : }
2848 0 : } else if (SolFlag == -2) {
2849 0 : ++FanCoil(FanCoilNum).LimitErrCountC;
2850 0 : if (FanCoil(FanCoilNum).LimitErrCountC < 2) {
2851 0 : ShowWarningError(state, "Part-load ratio cooling control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
2852 0 : ShowContinueError(state, " Bad part-load ratio limits");
2853 0 : ShowContinueErrorTimeStamp(state, format("..Part-load ratio set to {}", PLRMin));
2854 : } else {
2855 0 : ShowRecurringWarningErrorAtEnd(state,
2856 0 : "Part-load ratio cooling control failed in fan coil unit " + FanCoil(FanCoilNum).Name,
2857 0 : FanCoil(FanCoilNum).BadMassFlowLimIndexC);
2858 : }
2859 : }
2860 74963 : } else if (SolFlag == -2) {
2861 0 : ++FanCoil(FanCoilNum).LimitErrCountC;
2862 0 : if (FanCoil(FanCoilNum).LimitErrCountC < 2) {
2863 0 : ShowWarningError(state, "Part-load ratio control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
2864 0 : ShowContinueError(state, " Bad part-load ratio limits");
2865 0 : ShowContinueErrorTimeStamp(state, "..Part-load ratio set to 0");
2866 : } else {
2867 0 : ShowRecurringWarningErrorAtEnd(state,
2868 0 : "Part-load ratio control failed in fan coil unit " + FanCoil(FanCoilNum).Name,
2869 0 : FanCoil(FanCoilNum).BadMassFlowLimIndexC);
2870 : }
2871 : }
2872 74963 : mdot = PLR * FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
2873 224889 : SetComponentFlowRate(state,
2874 : mdot,
2875 74963 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
2876 74963 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
2877 74963 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
2878 : } else {
2879 16274 : PLR = 1.0;
2880 16274 : mdot = PLR * FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
2881 48822 : SetComponentFlowRate(state,
2882 : mdot,
2883 16274 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
2884 16274 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
2885 16274 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
2886 : }
2887 :
2888 : // at the end calculate output
2889 91237 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
2890 :
2891 186873 : } else if (UnitOn && QCoilHeatSP > SmallLoad &&
2892 74255 : state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != DataHVACGlobals::ThermostatType::SingleCooling) {
2893 : // heating coil action, maximun hot water flow
2894 :
2895 74255 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
2896 74255 : mdot = FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
2897 222765 : SetComponentFlowRate(state,
2898 : mdot,
2899 74255 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
2900 74255 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
2901 74255 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
2902 : }
2903 :
2904 74255 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
2905 74255 : ControlOffset = FanCoil(FanCoilNum).HotControlOffset;
2906 :
2907 : // get the maximum output of the fcu
2908 74255 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
2909 : // calculate the PLR, if load greater than output, PLR = 1 (output = max)
2910 74255 : if (QUnitOutMax > QZnReq) {
2911 : // more heating than required, find reduced water flow rate to meet the load
2912 70799 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
2913 : // solve for the hot water flow rate with no limit set by flow rate lockdown
2914 1291508 : auto f = [&state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, &FanCoil, QZnReq](Real64 const PLR) {
2915 645754 : return CalcFanCoilPLRResidual(
2916 645754 : state, PLR, FanCoilNum, FirstHVACIteration, ControlledZoneNum, FanCoil(FanCoilNum).HeatCoilFluidInletNode, QZnReq);
2917 393676 : };
2918 70799 : General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, 0.0, 1.0);
2919 70799 : if (SolFlag == -1) {
2920 : // tighten limits on water flow rate to see if this allows convergence
2921 0 : state.dataFanCoilUnits->CoolingLoad = false;
2922 0 : state.dataFanCoilUnits->HeatingLoad = true;
2923 0 : TightenAirAndWaterFlowLimits(state,
2924 : FanCoilNum,
2925 0 : state.dataFanCoilUnits->CoolingLoad,
2926 0 : state.dataFanCoilUnits->HeatingLoad,
2927 0 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
2928 : ControlledZoneNum,
2929 : FirstHVACIteration,
2930 : QZnReq,
2931 : PLRMin,
2932 : PLRMax);
2933 0 : General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, PLRMin, PLRMax);
2934 0 : if (SolFlag == -1) {
2935 0 : ++FanCoil(FanCoilNum).ConvgErrCountH;
2936 0 : if (FanCoil(FanCoilNum).ConvgErrCountH < 2) {
2937 0 : ShowWarningError(state, "Part-load ratio heating control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
2938 0 : ShowContinueError(state, " Iteration limit exceeded in calculating FCU part-load ratio ");
2939 0 : Node(FanCoil(FanCoilNum).HeatCoilFluidInletNode).MassFlowRate = PLR * FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
2940 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
2941 0 : ShowContinueErrorTimeStamp(state, format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut));
2942 0 : ShowContinueErrorTimeStamp(
2943 : state,
2944 0 : format("Min part-load ratio used during iterations = {}, Max part-load used during iterations = {}",
2945 : PLRMin,
2946 0 : PLRMax));
2947 0 : ShowContinueErrorTimeStamp(state, format("Part-load ratio on last iteration = {}", PLR));
2948 0 : ShowContinueErrorTimeStamp(state, "..Part-load ratio set to last iteration value ");
2949 : } else {
2950 0 : ShowRecurringWarningErrorAtEnd(state,
2951 0 : "Part-load ratio heating iteration limit exceeded in fan coil unit " +
2952 0 : FanCoil(FanCoilNum).Name,
2953 0 : FanCoil(FanCoilNum).MaxIterIndexH);
2954 : }
2955 0 : } else if (SolFlag == -2) {
2956 0 : ++FanCoil(FanCoilNum).LimitErrCountH;
2957 0 : if (FanCoil(FanCoilNum).LimitErrCountH < 2) {
2958 0 : ShowWarningError(state, "Part-load ratio heating control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
2959 0 : ShowContinueError(state, " Bad hot part-load ratio limits");
2960 0 : ShowContinueErrorTimeStamp(state, format("..Part-load ratio set to {}", PLRMin));
2961 : } else {
2962 0 : ShowRecurringWarningErrorAtEnd(state,
2963 0 : "Part-load ratio heating control failed in fan coil unit " +
2964 0 : FanCoil(FanCoilNum).Name,
2965 0 : FanCoil(FanCoilNum).BadMassFlowLimIndexH);
2966 : }
2967 : }
2968 70799 : } else if (SolFlag == -2) {
2969 0 : ++FanCoil(FanCoilNum).LimitErrCountH;
2970 0 : if (FanCoil(FanCoilNum).LimitErrCountH < 2) {
2971 0 : ShowWarningError(state, "Part-load ratio heating control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
2972 0 : ShowContinueError(state, " Bad part-load ratio limits");
2973 0 : ShowContinueErrorTimeStamp(state, "..Part-load ratio set to 0");
2974 : } else {
2975 0 : ShowRecurringWarningErrorAtEnd(state,
2976 0 : "Part-load ratio heating control failed in fan coil unit " + FanCoil(FanCoilNum).Name,
2977 0 : FanCoil(FanCoilNum).BadMassFlowLimIndexH);
2978 : }
2979 : }
2980 70799 : HWFlow = PLR * FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
2981 212397 : SetComponentFlowRate(state,
2982 : HWFlow,
2983 70799 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
2984 70799 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
2985 70799 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
2986 :
2987 : } else {
2988 0 : auto f = [&state, FirstHVACIteration, FanCoilNum, ControlledZoneNum, QZnReq](Real64 const PartLoadRatio) {
2989 0 : return CalcFanCoilLoadResidual(state, FanCoilNum, FirstHVACIteration, ControlledZoneNum, QZnReq, PartLoadRatio);
2990 0 : };
2991 0 : General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, PLR, f, 0.0, 1.0);
2992 : }
2993 : } else {
2994 3456 : PLR = 1.0;
2995 3456 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
2996 3456 : mdot = PLR * FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
2997 10368 : SetComponentFlowRate(state,
2998 : mdot,
2999 3456 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
3000 3456 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
3001 3456 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
3002 : }
3003 : }
3004 :
3005 : // at the end calculate output with adjusted PLR
3006 74255 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
3007 :
3008 : } else {
3009 : // no action, zero the air flow rate, the unit is off
3010 38363 : Node(InletNode).MassFlowRate = 0.0;
3011 38363 : Node(OutletNode).MassFlowRate = 0.0;
3012 38363 : FanCoil(FanCoilNum).SpeedFanSel = 0;
3013 38363 : PLR = 0.0;
3014 38363 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
3015 : }
3016 :
3017 203855 : AirMassFlow = Node(InletNode).MassFlowRate;
3018 : // CR9155 Remove specific humidity calculations
3019 203855 : SpecHumOut = Node(OutletNode).HumRat;
3020 203855 : SpecHumIn = Node(InletNode).HumRat;
3021 203855 : LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
3022 203855 : QTotUnitOut = AirMassFlow * (Node(OutletNode).Enthalpy - Node(InletNode).Enthalpy);
3023 : // report variables
3024 203855 : FanCoil(FanCoilNum).HeatPower = max(0.0, QUnitOut);
3025 203855 : FanCoil(FanCoilNum).SensCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QUnitOut));
3026 203855 : FanCoil(FanCoilNum).TotCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QTotUnitOut));
3027 203855 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
3028 185095 : FanCoil(FanCoilNum).ElecPower = Fans::GetFanPower(state, FanCoil(FanCoilNum).FanIndex);
3029 : } else {
3030 18760 : FanCoil(FanCoilNum).ElecPower = state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->fanPower();
3031 : }
3032 203855 : FanCoil(FanCoilNum).PLR = PLR;
3033 203855 : PowerMet = QUnitOut;
3034 203855 : LatOutputProvided = LatentOutput;
3035 :
3036 203855 : } break;
3037 17247 : case CCM::ASHRAE: {
3038 :
3039 17247 : if (AirMassFlow < SmallMassFlow) UnitOn = false;
3040 :
3041 : // zero the hot & cold water flows
3042 17247 : mdot = 0.0;
3043 51741 : SetComponentFlowRate(state,
3044 : mdot,
3045 17247 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
3046 17247 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
3047 17247 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
3048 :
3049 17247 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
3050 11498 : mdot = 0.0;
3051 34494 : SetComponentFlowRate(state,
3052 : mdot,
3053 11498 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
3054 11498 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
3055 11498 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
3056 : }
3057 :
3058 17247 : OAMassFlow = 0.0;
3059 :
3060 : // determine minimum outdoor air flow rate
3061 17247 : if (FanCoil(FanCoilNum).DSOAPtr > 0 && FanCoil(FanCoilNum).OutsideAirNode > 0) {
3062 17244 : OAVolumeFlowRate = DataSizing::calcDesignSpecificationOutdoorAir(state, FanCoil(FanCoilNum).DSOAPtr, ControlledZoneNum, true, true);
3063 51732 : RhoAir = PsyRhoAirFnPbTdbW(state,
3064 17244 : Node(FanCoil(FanCoilNum).OutsideAirNode).Press,
3065 17244 : Node(FanCoil(FanCoilNum).OutsideAirNode).Temp,
3066 17244 : Node(FanCoil(FanCoilNum).OutsideAirNode).HumRat);
3067 17244 : OAMassFlow = OAVolumeFlowRate * RhoAir;
3068 : }
3069 :
3070 17247 : MinSAMassFlowRate =
3071 17247 : min(max(OAMassFlow, FanCoil(FanCoilNum).MaxAirMassFlow * FanCoil(FanCoilNum).LowSpeedRatio), FanCoil(FanCoilNum).MaxAirMassFlow);
3072 17247 : MaxSAMassFlowRate = FanCoil(FanCoilNum).MaxAirMassFlow;
3073 17247 : state.dataFanCoilUnits->HeatingLoad = false;
3074 17247 : state.dataFanCoilUnits->CoolingLoad = false;
3075 17247 : if (UnitOn) {
3076 17223 : Node(InletNode).MassFlowRate = MinSAMassFlowRate;
3077 17223 : FanCoil(FanCoilNum).MaxNoCoolHeatAirMassFlow = MinSAMassFlowRate;
3078 17223 : FanCoil(FanCoilNum).MaxCoolAirMassFlow = MaxSAMassFlowRate;
3079 17223 : FanCoil(FanCoilNum).MaxHeatAirMassFlow = MaxSAMassFlowRate;
3080 17223 : FanCoil(FanCoilNum).LowSpeedCoolFanRatio = MinSAMassFlowRate / MaxSAMassFlowRate;
3081 17223 : FanCoil(FanCoilNum).LowSpeedHeatFanRatio = MinSAMassFlowRate / MaxSAMassFlowRate;
3082 :
3083 17223 : Calc4PipeFanCoil(state,
3084 : FanCoilNum,
3085 : ControlledZoneNum,
3086 : FirstHVACIteration,
3087 : QUnitOutNoHC,
3088 : 0.0); // needs PLR=0 for electric heating coil, otherwise will run at full capacity
3089 :
3090 17223 : QCoilCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
3091 17223 : QCoilHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
3092 :
3093 23649 : if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0 &&
3094 6426 : state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != DataHVACGlobals::ThermostatType::SingleCooling) {
3095 6096 : QZnReq = QCoilHeatSP;
3096 6096 : state.dataFanCoilUnits->HeatingLoad = true;
3097 11457 : } else if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0 &&
3098 330 : state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) == DataHVACGlobals::ThermostatType::SingleCooling) {
3099 330 : QZnReq = 0.0;
3100 21594 : } else if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0 &&
3101 10797 : state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != DataHVACGlobals::ThermostatType::SingleHeating) {
3102 10692 : QZnReq = QCoilCoolSP;
3103 10692 : state.dataFanCoilUnits->CoolingLoad = true;
3104 210 : } else if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0 &&
3105 105 : state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) == DataHVACGlobals::ThermostatType::SingleHeating) {
3106 105 : QZnReq = 0.0;
3107 0 : } else if (QCoilHeatSP <= 0.0 && QCoilCoolSP >= 0.0) {
3108 0 : QZnReq = 0.0;
3109 : }
3110 : }
3111 :
3112 17247 : if (state.dataFanCoilUnits->CoolingLoad) {
3113 :
3114 10692 : Node(InletNode).MassFlowRate = MaxSAMassFlowRate;
3115 :
3116 10692 : mdot = FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
3117 32076 : SetComponentFlowRate(state,
3118 : mdot,
3119 10692 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
3120 10692 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
3121 10692 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
3122 :
3123 6555 : } else if (state.dataFanCoilUnits->HeatingLoad) {
3124 :
3125 6096 : Node(InletNode).MassFlowRate = MaxSAMassFlowRate;
3126 :
3127 6096 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
3128 4054 : mdot = FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
3129 12162 : SetComponentFlowRate(state,
3130 : mdot,
3131 4054 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
3132 4054 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
3133 4054 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
3134 : }
3135 : }
3136 :
3137 17247 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
3138 :
3139 17247 : if ((state.dataFanCoilUnits->CoolingLoad && QUnitOutMax < QZnReq) || (state.dataFanCoilUnits->HeatingLoad && QUnitOutMax > QZnReq)) {
3140 32132 : if ((state.dataFanCoilUnits->CoolingLoad && QUnitOutNoHC < QZnReq) ||
3141 22158 : (state.dataFanCoilUnits->HeatingLoad && QUnitOutNoHC > QZnReq)) {
3142 0 : PLR = 0.0;
3143 0 : FanCoil(FanCoilNum).FanPartLoadRatio = 0.0; // set SZVAV model variable
3144 0 : Node(InletNode).MassFlowRate = MinSAMassFlowRate; // = min air flow rate + ((max-min) air flow rate * FanPartLoadRatio)
3145 0 : mdot = 0.0;
3146 0 : SetComponentFlowRate(state,
3147 : mdot,
3148 0 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
3149 0 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
3150 0 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
3151 :
3152 0 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
3153 0 : mdot = 0.0;
3154 0 : SetComponentFlowRate(state,
3155 : mdot,
3156 0 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
3157 0 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
3158 0 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
3159 : }
3160 : } else {
3161 16066 : Real64 OnOffAirFlowRatio = 1.0;
3162 16066 : bool HXUnitOn = false;
3163 16066 : int AirLoopNum = 0;
3164 16066 : DataHVACGlobals::CompressorOperation CompressorOnFlag = DataHVACGlobals::CompressorOperation::Off;
3165 16066 : auto &SZVAVModel(FanCoil(FanCoilNum));
3166 : // seems like passing these (arguments 2-n) as an array (similar to Par) would make this more uniform across different
3167 : // models
3168 48198 : SZVAVModel::calcSZVAVModel(state,
3169 : SZVAVModel,
3170 : FanCoilNum,
3171 : FirstHVACIteration,
3172 16066 : state.dataFanCoilUnits->CoolingLoad,
3173 16066 : state.dataFanCoilUnits->HeatingLoad,
3174 : QZnReq,
3175 : OnOffAirFlowRatio,
3176 : HXUnitOn,
3177 : AirLoopNum,
3178 : PLR,
3179 : CompressorOnFlag);
3180 : }
3181 2366 : } else if ((state.dataFanCoilUnits->CoolingLoad && QUnitOutMax > QZnReq && QZnReq < 0.0) ||
3182 467 : (state.dataFanCoilUnits->HeatingLoad && QUnitOutMax < QZnReq && QZnReq > 0.0)) {
3183 : // load is larger than capacity, thus run the fancoil unit at full capacity
3184 722 : PLR = 1.0;
3185 : }
3186 17247 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
3187 17247 : PowerMet = QUnitOut;
3188 17247 : AirMassFlow = Node(InletNode).MassFlowRate;
3189 : // CR9155 Remove specific humidity calculations
3190 17247 : SpecHumOut = Node(OutletNode).HumRat;
3191 17247 : SpecHumIn = Node(InletNode).HumRat;
3192 : // Latent rate (kg/s), dehumid = negative
3193 17247 : LatOutputProvided = AirMassFlow * (SpecHumOut - SpecHumIn);
3194 17247 : FanCoil(FanCoilNum).PLR = PLR;
3195 :
3196 : // cycling fan constant water flow AND VarFanVarFlow
3197 17247 : } break;
3198 0 : case CCM::VarFanConsFlow: {
3199 :
3200 0 : if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ControlledZoneNum) || AirMassFlow < SmallMassFlow) UnitOn = false;
3201 :
3202 : // zero the hot & cold water flows
3203 : // Node(FanCoil(FanCoilNum)%CoolCoilFluidInletNode)%MassFlowRate = 0.0
3204 : // Node(FanCoil(FanCoilNum)%HeatCoilFluidInletNode)%MassFlowRate = 0.0
3205 0 : mdot = 0.0;
3206 0 : SetComponentFlowRate(state,
3207 : mdot,
3208 0 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
3209 0 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
3210 0 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
3211 :
3212 0 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
3213 0 : mdot = 0.0;
3214 0 : SetComponentFlowRate(state,
3215 : mdot,
3216 0 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
3217 0 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
3218 0 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
3219 : }
3220 0 : Calc4PipeFanCoil(state,
3221 : FanCoilNum,
3222 : ControlledZoneNum,
3223 : FirstHVACIteration,
3224 : QUnitOutNoHC,
3225 : 0.0); // needs PLR=0 for electric heating coil, otherwise will run at full capacity
3226 :
3227 0 : if (UnitOn && state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP < (-1.0 * SmallLoad) &&
3228 0 : state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != DataHVACGlobals::ThermostatType::SingleHeating) {
3229 : // cooling coil action, maximum cold water flow
3230 0 : mdot = FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
3231 0 : SetComponentFlowRate(state,
3232 : mdot,
3233 0 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
3234 0 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
3235 0 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
3236 0 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
3237 0 : ControlOffset = FanCoil(FanCoilNum).ColdControlOffset;
3238 :
3239 : // get the maximum output of the fcu
3240 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
3241 : // calculate the PLR, if load greater than output, PLR = 1 (output = max)
3242 0 : if (QUnitOutMax != 0.0) PLR = std::abs(QZnReq / QUnitOutMax);
3243 0 : if (PLR > 1.0) PLR = 1.0;
3244 :
3245 : // adjust the PLR to meet the cooling load calling Calc4PipeFanCoil repeatedly with the PLR adjusted
3246 0 : while (std::abs(Error) > ControlOffset && std::abs(AbsError) > SmallLoad && Iter < MaxIterCycl && PLR != 1.0) {
3247 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
3248 0 : Error = (QZnReq - QUnitOut) / QZnReq;
3249 0 : AbsError = QZnReq - QUnitOut;
3250 0 : DelPLR = (QZnReq - QUnitOut) / QUnitOutMax;
3251 0 : PLR += Relax * DelPLR;
3252 0 : PLR = max(0.0, min(1.0, PLR));
3253 0 : ++Iter;
3254 0 : if (Iter == 32) Relax = 0.5;
3255 0 : if (Iter == 65) Relax = 0.25;
3256 : }
3257 :
3258 : // warning if not converged
3259 0 : if (Iter > (MaxIterCycl - 1)) {
3260 0 : if (FanCoil(FanCoilNum).MaxIterIndexC == 0) {
3261 0 : ShowWarningMessage(state,
3262 0 : "ZoneHVAC:FourPipeFanCoil=\"" + FanCoil(FanCoilNum).Name +
3263 : "\" -- Exceeded max iterations while adjusting cycling fan sensible runtime to meet the zone load "
3264 : "within the cooling convergence tolerance.");
3265 0 : ShowContinueErrorTimeStamp(state, format("Iterations={}", MaxIterCycl));
3266 : }
3267 0 : ShowRecurringWarningErrorAtEnd(state,
3268 0 : "ZoneHVAC:FourPipeFanCoil=\"" + FanCoil(FanCoilNum).Name +
3269 : "\" -- Exceeded max iterations error (sensible runtime) continues...",
3270 0 : FanCoil(FanCoilNum).MaxIterIndexC);
3271 : }
3272 :
3273 : // at the end calculate output with adjusted PLR
3274 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
3275 :
3276 0 : } else if (UnitOn && state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP > SmallLoad &&
3277 0 : state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != DataHVACGlobals::ThermostatType::SingleCooling) {
3278 : // heating coil action, maximun hot water flow
3279 0 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
3280 0 : mdot = FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
3281 0 : SetComponentFlowRate(state,
3282 : mdot,
3283 0 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
3284 0 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
3285 0 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
3286 : }
3287 0 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
3288 0 : ControlOffset = FanCoil(FanCoilNum).HotControlOffset;
3289 :
3290 : // get the maximum output of the fcu
3291 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOutMax);
3292 : // calculate the PLR, if load greater than output, PLR = 1 (output = max)
3293 0 : if (QUnitOutMax != 0.0) PLR = std::abs(QZnReq / QUnitOutMax);
3294 0 : if (PLR > 1.0) PLR = 1.0;
3295 :
3296 : // adjust the PLR to meet the heating load calling Calc4PipeFanCoil repeatedly with the PLR adjusted
3297 0 : while (std::abs(Error) > ControlOffset && std::abs(AbsError) > SmallLoad && Iter < MaxIterCycl && PLR != 1.0) {
3298 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
3299 0 : Error = (QZnReq - QUnitOut) / QZnReq;
3300 0 : AbsError = QZnReq - QUnitOut;
3301 0 : DelPLR = (QZnReq - QUnitOut) / QUnitOutMax;
3302 0 : PLR += Relax * DelPLR;
3303 0 : PLR = max(0.0, min(1.0, PLR));
3304 0 : ++Iter;
3305 0 : if (Iter == 32) Relax = 0.5;
3306 0 : if (Iter == 65) Relax = 0.25;
3307 : }
3308 :
3309 : // warning if not converged
3310 0 : if (Iter > (MaxIterCycl - 1)) {
3311 0 : if (FanCoil(FanCoilNum).MaxIterIndexH == 0) {
3312 0 : ShowWarningMessage(state,
3313 0 : "ZoneHVAC:FourPipeFanCoil=\"" + FanCoil(FanCoilNum).Name +
3314 : "\" -- Exceeded max iterations while adjusting cycling fan sensible runtime to meet the zone load "
3315 : "within the heating convergence tolerance.");
3316 0 : ShowContinueError(state, format("...Requested zone load = {:.3T} [W]", QZnReq));
3317 0 : ShowContinueError(state, format("...Fan coil capacity = {:.3T} [W]", QUnitOut));
3318 0 : ShowContinueErrorTimeStamp(state, format("Iterations={}", MaxIterCycl));
3319 : }
3320 0 : ShowRecurringWarningErrorAtEnd(state,
3321 0 : "ZoneHVAC:FourPipeFanCoil=\"" + FanCoil(FanCoilNum).Name +
3322 : "\" -- Exceeded max iterations error (sensible runtime) continues...",
3323 0 : FanCoil(FanCoilNum).MaxIterIndexH);
3324 : }
3325 :
3326 : // at the end calculate output with adjusted PLR
3327 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
3328 :
3329 : // this part of the code is just if we want ventilation in the deadband zone
3330 : // ELSE IF (AirMassFlow .gt. 0.0d0) THEN
3331 : // if fan scheduled available : just ventilation, PLR = 1
3332 : // QUnitOut = QUnitOutNOHC
3333 : // PLR = 1.
3334 :
3335 : } else {
3336 : // no action, zero the air flow rate, the unit is off
3337 0 : Node(InletNode).MassFlowRate = 0.0;
3338 0 : Node(OutletNode).MassFlowRate = 0.0;
3339 0 : FanCoil(FanCoilNum).SpeedFanSel = 0;
3340 0 : PLR = 0.0;
3341 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
3342 : }
3343 :
3344 0 : AirMassFlow = Node(InletNode).MassFlowRate;
3345 : // CR9155 Remove specific humidity calculations
3346 0 : SpecHumOut = Node(OutletNode).HumRat;
3347 0 : SpecHumIn = Node(InletNode).HumRat;
3348 0 : LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
3349 0 : QSensUnitOutNoATM = calcZoneSensibleOutput(AirMassFlow, Node(OutletNode).Temp, Node(InletNode).Temp, Node(InletNode).HumRat);
3350 0 : QTotUnitOut = AirMassFlow * (Node(OutletNode).Enthalpy - Node(InletNode).Enthalpy);
3351 : // report variables
3352 0 : FanCoil(FanCoilNum).HeatPower = max(0.0, QSensUnitOutNoATM);
3353 0 : FanCoil(FanCoilNum).SensCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QSensUnitOutNoATM));
3354 0 : FanCoil(FanCoilNum).TotCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QTotUnitOut));
3355 0 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
3356 0 : FanCoil(FanCoilNum).ElecPower = Fans::GetFanPower(state, FanCoil(FanCoilNum).FanIndex);
3357 : } else {
3358 0 : FanCoil(FanCoilNum).ElecPower = state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->fanPower();
3359 : }
3360 0 : FanCoil(FanCoilNum).PLR = PLR;
3361 0 : PowerMet = QUnitOut;
3362 0 : LatOutputProvided = LatentOutput;
3363 :
3364 0 : } break;
3365 12375 : case CCM::MultiSpeedFan: {
3366 : // call multi-speed fan staging calculation
3367 12375 : SimMultiStage4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
3368 12375 : AirMassFlow = Node(InletNode).MassFlowRate;
3369 12375 : SpecHumOut = Node(OutletNode).HumRat;
3370 12375 : SpecHumIn = Node(InletNode).HumRat;
3371 12375 : LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
3372 12375 : QSensUnitOutNoATM = calcZoneSensibleOutput(AirMassFlow, Node(OutletNode).Temp, Node(InletNode).Temp, Node(InletNode).HumRat);
3373 12375 : QTotUnitOut = AirMassFlow * (Node(OutletNode).Enthalpy - Node(InletNode).Enthalpy);
3374 : // report variables
3375 12375 : FanCoil(FanCoilNum).HeatPower = max(0.0, QSensUnitOutNoATM);
3376 12375 : FanCoil(FanCoilNum).SensCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QSensUnitOutNoATM));
3377 12375 : FanCoil(FanCoilNum).TotCoolPower = std::abs(min(DataPrecisionGlobals::constant_zero, QTotUnitOut));
3378 12375 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
3379 0 : FanCoil(FanCoilNum).ElecPower = Fans::GetFanPower(state, FanCoil(FanCoilNum).FanIndex);
3380 : } else {
3381 12375 : FanCoil(FanCoilNum).ElecPower = state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->fanPower();
3382 : }
3383 12375 : PowerMet = QUnitOut;
3384 12375 : LatOutputProvided = LatentOutput;
3385 12375 : } break;
3386 0 : default:
3387 0 : break;
3388 : }
3389 514191 : }
3390 :
3391 0 : void TightenWaterFlowLimits(EnergyPlusData &state,
3392 : int const FanCoilNum, // Unit index in fan coil array
3393 : bool const CoolingLoad, // true if zone requires cooling
3394 : bool const HeatingLoad, // true if zone requires heating
3395 : int const WaterControlNode, // water control node, either cold or hot water
3396 : int const ControlledZoneNum, // controlling zone index
3397 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
3398 : Real64 const QZnReq, // zone load [W]
3399 : Real64 &MinWaterFlow, // minimum water flow rate
3400 : Real64 &MaxWaterFlow // maximum water flow rate
3401 : )
3402 : {
3403 :
3404 : // SUBROUTINE INFORMATION:
3405 : // AUTHOR R. Raustad, FSEC
3406 : // DATE WRITTEN May 2016
3407 :
3408 : // PURPOSE OF THIS SUBROUTINE:
3409 : // Find tighter limits of water flow rate for fan coil unit.
3410 :
3411 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3412 : Real64 QUnitOut; // fan coil delivered capacity [W]
3413 : Real64 mdot; // water flow rate passed to fan coil unit [kg/s]
3414 :
3415 : // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 10% of flow before iterating
3416 0 : mdot = MaxWaterFlow * 0.1;
3417 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
3418 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
3419 0 : if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
3420 0 : MaxWaterFlow = mdot;
3421 : // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 1% of flow before iterating
3422 0 : mdot *= 0.1;
3423 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
3424 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
3425 0 : if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
3426 0 : MaxWaterFlow = mdot;
3427 : // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 0.1% of flow before iterating
3428 0 : mdot *= 0.1;
3429 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
3430 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
3431 0 : if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
3432 0 : MaxWaterFlow = mdot;
3433 : // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 0.01% of flow before iterating
3434 0 : mdot *= 0.1;
3435 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
3436 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
3437 0 : if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
3438 0 : MaxWaterFlow = mdot;
3439 : // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 0.001% of flow before
3440 : // iterating
3441 0 : mdot *= 0.1;
3442 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mdot;
3443 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut);
3444 0 : if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
3445 0 : MaxWaterFlow = mdot;
3446 : } else {
3447 0 : MinWaterFlow = mdot;
3448 : }
3449 : } else {
3450 0 : MinWaterFlow = mdot;
3451 : }
3452 : } else {
3453 0 : MinWaterFlow = mdot;
3454 : }
3455 : } else {
3456 0 : MinWaterFlow = mdot;
3457 : }
3458 : } else {
3459 0 : MinWaterFlow = mdot;
3460 : }
3461 0 : }
3462 :
3463 0 : void TightenAirAndWaterFlowLimits(EnergyPlusData &state,
3464 : int const FanCoilNum, // Unit index in fan coil array
3465 : bool const CoolingLoad, // true if zone requires cooling
3466 : bool const HeatingLoad, // true if zone requires heating
3467 : int const WaterControlNode, // water control node, either cold or hot water
3468 : int const ControlledZoneNum, // controlling zone index
3469 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
3470 : Real64 const QZnReq, // zone load [W]
3471 : Real64 &PLRMin, // minimum part-load ratio
3472 : Real64 &PLRMax // maximum part-load ratio
3473 : )
3474 : {
3475 :
3476 : // SUBROUTINE INFORMATION:
3477 : // AUTHOR R. Raustad, FSEC
3478 : // DATE WRITTEN August 2016
3479 :
3480 : // PURPOSE OF THIS SUBROUTINE:
3481 : // Find tighter limits of air and water flow rate for fan coil unit.
3482 :
3483 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3484 : Real64 PLR; // operating part-load ratio
3485 : Real64 QUnitOut; // fan coil delivered capacity [W]
3486 :
3487 0 : auto &FanCoil(state.dataFanCoilUnits->FanCoil);
3488 :
3489 : // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 100% of flow before iterating
3490 0 : PLRMin = 0.0;
3491 0 : PLRMax = 1.0;
3492 0 : PLR = 1.0;
3493 0 : if (WaterControlNode == FanCoil(FanCoilNum).CoolCoilFluidInletNode) {
3494 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
3495 0 : } else if (WaterControlNode == FanCoil(FanCoilNum).HeatCoilFluidInletNode && FanCoil(FanCoilNum).HCoilType_Num != HCoil::Electric) {
3496 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
3497 : }
3498 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
3499 0 : if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
3500 0 : PLRMax = PLR;
3501 0 : PLR *= 0.1;
3502 : // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 10% of flow before iterating
3503 0 : if (WaterControlNode == FanCoil(FanCoilNum).CoolCoilFluidInletNode) {
3504 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
3505 0 : } else if (WaterControlNode == FanCoil(FanCoilNum).HeatCoilFluidInletNode && FanCoil(FanCoilNum).HCoilType_Num != HCoil::Electric) {
3506 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
3507 : }
3508 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
3509 0 : if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
3510 0 : PLRMax = PLR;
3511 0 : PLR *= 0.1;
3512 : // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 1% of flow before iterating
3513 0 : if (WaterControlNode == FanCoil(FanCoilNum).CoolCoilFluidInletNode) {
3514 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
3515 0 : } else if (WaterControlNode == FanCoil(FanCoilNum).HeatCoilFluidInletNode && FanCoil(FanCoilNum).HCoilType_Num != HCoil::Electric) {
3516 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
3517 : }
3518 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
3519 0 : if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
3520 0 : PLRMax = PLR;
3521 0 : PLR *= 0.1;
3522 : // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 0.1% of flow before iterating
3523 0 : if (WaterControlNode == FanCoil(FanCoilNum).CoolCoilFluidInletNode) {
3524 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
3525 0 : } else if (WaterControlNode == FanCoil(FanCoilNum).HeatCoilFluidInletNode &&
3526 0 : FanCoil(FanCoilNum).HCoilType_Num != HCoil::Electric) {
3527 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
3528 : }
3529 0 : if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
3530 0 : PLRMax = PLR;
3531 0 : PLR *= 0.1;
3532 : // RegulaFalsi can reach max iteration when low water flow rate is required to meet load. Test at 0.01% of flow before
3533 : // iterating
3534 0 : if (WaterControlNode == FanCoil(FanCoilNum).CoolCoilFluidInletNode) {
3535 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
3536 0 : } else if (WaterControlNode == FanCoil(FanCoilNum).HeatCoilFluidInletNode &&
3537 0 : FanCoil(FanCoilNum).HCoilType_Num != HCoil::Electric) {
3538 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
3539 : }
3540 0 : if ((CoolingLoad && QUnitOut < QZnReq) || (HeatingLoad && QUnitOut > QZnReq)) {
3541 0 : PLRMax = PLR;
3542 : } else {
3543 0 : PLRMin = PLR;
3544 : }
3545 : } else {
3546 0 : PLRMin = PLR;
3547 : }
3548 : } else {
3549 0 : PLRMin = PLR;
3550 : }
3551 : } else {
3552 0 : PLRMin = PLR;
3553 : }
3554 : } else {
3555 0 : PLRMin = PLR;
3556 : }
3557 0 : }
3558 :
3559 5427232 : void Calc4PipeFanCoil(EnergyPlusData &state,
3560 : int const FanCoilNum, // Unit index in fan coil array
3561 : int const ControlledZoneNum, // ZoneEquipConfig index
3562 : bool const FirstHVACIteration, // flag for 1st HVAV iteration in the time step
3563 : Real64 &LoadMet, // load met by unit (watts)
3564 : Optional<Real64> PLR, // Part Load Ratio, fraction of time step fancoil is on
3565 : Real64 eHeatCoilCyclingR // electric heating coil cycling ratio used with MultiSpeedFan capacity control
3566 : )
3567 : {
3568 :
3569 : // SUBROUTINE INFORMATION:
3570 : // AUTHOR Fred Buhl
3571 : // DATE WRITTEN March 2000
3572 : // MODIFIED July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
3573 : // RE-ENGINEERED na
3574 :
3575 : // PURPOSE OF THIS SUBROUTINE:
3576 : // Simulate the components making up the 4 pipe fan coil unit.
3577 :
3578 : // METHODOLOGY EMPLOYED:
3579 : // Simulates the unit components sequentially in the air flow direction.
3580 :
3581 : // REFERENCES:
3582 : // na
3583 :
3584 : // Using/Aliasing
3585 5427232 : auto &ZoneCompTurnFansOff = state.dataHVACGlobal->ZoneCompTurnFansOff;
3586 5427232 : auto &ZoneCompTurnFansOn = state.dataHVACGlobal->ZoneCompTurnFansOn;
3587 : using HeatingCoils::SimulateHeatingCoilComponents;
3588 : using HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil;
3589 : using MixedAir::SimOAMixer;
3590 : using Psychrometrics::PsyHFnTdbW;
3591 : using SingleDuct::SimATMixer;
3592 : using WaterCoils::SimulateWaterCoilComponents;
3593 :
3594 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3595 : int OutletNode; // unit air outlet node
3596 : int InletNode; // unit air inlet node
3597 : Real64 AirMassFlow; // total mass flow through the unit
3598 : Real64 PartLoad; // if PLR present PartLoad = PLR
3599 : Real64 OASchedValue; // value of OASchedValue, =1 if not schedule
3600 5427232 : Real64 ElecHeaterControl(1.0); // 1 or 0, enables or disables heating coil
3601 : Real64 FanSpeedRatio; // ratio of actual fan flow to max design fan flow
3602 :
3603 5427232 : auto &Node(state.dataLoopNodes->Node);
3604 5427232 : auto &FanCoil(state.dataFanCoilUnits->FanCoil);
3605 :
3606 : // if PLR present in arguments, get its value, else default PLR = 1
3607 5427232 : if (present(PLR)) {
3608 4241277 : PartLoad = PLR;
3609 : } else {
3610 1185955 : PartLoad = 1.0;
3611 : }
3612 :
3613 5427232 : OutletNode = FanCoil(FanCoilNum).AirOutNode;
3614 5427232 : InletNode = FanCoil(FanCoilNum).AirInNode;
3615 5427232 : state.dataFanCoilUnits->ZoneNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
3616 :
3617 : // Assume the unit is able to vary the flow. A cycling unit is treated as
3618 : // if it were variable flow, with the flow being the averaqe flow over the time step
3619 16280940 : if (((GetCurrentScheduleValue(state, FanCoil(FanCoilNum).SchedPtr) > 0.0 &&
3620 5427232 : GetCurrentScheduleValue(state, FanCoil(FanCoilNum).fanAvailSchIndex) > 0.0) ||
3621 10854464 : state.dataHVACGlobal->ZoneCompTurnFansOn) &&
3622 5426476 : !state.dataHVACGlobal->ZoneCompTurnFansOff) {
3623 5423808 : if (FanCoil(FanCoilNum).CapCtrlMeth_Num != CCM::ConsFanVarFlow) {
3624 1919884 : if (FanCoil(FanCoilNum).CapCtrlMeth_Num != CCM::ASHRAE) Node(InletNode).MassFlowRate = PartLoad * Node(InletNode).MassFlowRateMax;
3625 : } else {
3626 3503924 : Node(InletNode).MassFlowRate = Node(InletNode).MassFlowRateMax;
3627 : }
3628 : }
3629 :
3630 : // use the value of the outside air schedule if present
3631 5427232 : if (FanCoil(FanCoilNum).SchedOutAirPtr > 0) {
3632 1024759 : OASchedValue = GetCurrentScheduleValue(state, FanCoil(FanCoilNum).SchedOutAirPtr);
3633 : } else {
3634 4402473 : OASchedValue = 1.0;
3635 : }
3636 :
3637 5427232 : if (FanCoil(FanCoilNum).ATMixerExists) {
3638 349032 : state.dataFanCoilUnits->ATMixOutNode = FanCoil(FanCoilNum).ATMixerOutNode;
3639 349032 : if (FanCoil(FanCoilNum).ATMixerType == ATMixer_InletSide) {
3640 : // set the primary air inlet mass flow rate
3641 169646 : Node(FanCoil(FanCoilNum).ATMixerPriNode).MassFlowRate =
3642 169646 : min(Node(FanCoil(FanCoilNum).ATMixerPriNode).MassFlowRateMaxAvail, Node(InletNode).MassFlowRate);
3643 : // now calculate the the mixer outlet conditions (and the secondary air inlet flow rate)
3644 : // the mixer outlet flow rate has already been set above (it is the "inlet" node flow rate)
3645 169646 : SimATMixer(state, FanCoil(FanCoilNum).ATMixerName, FirstHVACIteration, FanCoil(FanCoilNum).ATMixerIndex);
3646 : }
3647 349032 : AirMassFlow = Node(InletNode).MassFlowRate;
3648 : } else {
3649 : // OutdoorAir:Mixer
3650 5078200 : if (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::CycFan) {
3651 1533543 : Node(FanCoil(FanCoilNum).OutsideAirNode).MassFlowRate =
3652 1533543 : min(OASchedValue * Node(FanCoil(FanCoilNum).OutsideAirNode).MassFlowRateMax * PartLoad * FanCoil(FanCoilNum).SpeedFanRatSel,
3653 1533543 : Node(InletNode).MassFlowRate);
3654 3544657 : } else if (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::MultiSpeedFan) {
3655 191980 : Node(FanCoil(FanCoilNum).OutsideAirNode).MassFlowRate =
3656 191980 : min(OASchedValue * Node(FanCoil(FanCoilNum).OutsideAirNode).MassFlowRateMax * PartLoad * state.dataFanCoilUnits->FanFlowRatio,
3657 191980 : Node(InletNode).MassFlowRate);
3658 : } else {
3659 3352677 : if (FanCoil(FanCoilNum).CapCtrlMeth_Num != CCM::ConsFanVarFlow && FanCoil(FanCoilNum).CapCtrlMeth_Num != CCM::ASHRAE) {
3660 0 : Node(FanCoil(FanCoilNum).OutsideAirNode).MassFlowRate =
3661 0 : min(OASchedValue * Node(FanCoil(FanCoilNum).OutsideAirNode).MassFlowRateMax * PartLoad, Node(InletNode).MassFlowRate);
3662 : } else {
3663 3352677 : Node(FanCoil(FanCoilNum).OutsideAirNode).MassFlowRate =
3664 3352677 : min(OASchedValue * Node(FanCoil(FanCoilNum).OutsideAirNode).MassFlowRateMax, Node(InletNode).MassFlowRate);
3665 : }
3666 : }
3667 5078200 : Node(FanCoil(FanCoilNum).AirReliefNode).MassFlowRate = Node(FanCoil(FanCoilNum).OutsideAirNode).MassFlowRate;
3668 5078200 : AirMassFlow = Node(InletNode).MassFlowRate;
3669 5078200 : SimOAMixer(state, FanCoil(FanCoilNum).OAMixName, FirstHVACIteration, FanCoil(FanCoilNum).OAMixIndex);
3670 : }
3671 :
3672 5427232 : if (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::CycFan) {
3673 : // cycling fan coil unit calculation
3674 1533543 : if (FanCoil(FanCoilNum).SpeedFanSel == 1) {
3675 524766 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
3676 1612512 : Fans::SimulateFanComponents(state,
3677 403128 : FanCoil(FanCoilNum).FanName,
3678 : FirstHVACIteration,
3679 403128 : FanCoil(FanCoilNum).FanIndex,
3680 403128 : FanCoil(FanCoilNum).LowSpeedRatio,
3681 : ZoneCompTurnFansOn,
3682 : ZoneCompTurnFansOff);
3683 : } else {
3684 121638 : state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(state, _, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _);
3685 : }
3686 1008777 : } else if (FanCoil(FanCoilNum).SpeedFanSel == 2) {
3687 :
3688 488967 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
3689 1910952 : Fans::SimulateFanComponents(state,
3690 477738 : FanCoil(FanCoilNum).FanName,
3691 : FirstHVACIteration,
3692 477738 : FanCoil(FanCoilNum).FanIndex,
3693 477738 : FanCoil(FanCoilNum).MedSpeedRatio,
3694 : ZoneCompTurnFansOn,
3695 : ZoneCompTurnFansOff);
3696 : } else {
3697 11229 : state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(state, _, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _);
3698 : }
3699 519810 : } else if (FanCoil(FanCoilNum).SpeedFanSel == 3) {
3700 :
3701 443073 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
3702 1329219 : Fans::SimulateFanComponents(state,
3703 443073 : FanCoil(FanCoilNum).FanName,
3704 : FirstHVACIteration,
3705 443073 : FanCoil(FanCoilNum).FanIndex,
3706 : 1.0,
3707 : ZoneCompTurnFansOn,
3708 : ZoneCompTurnFansOff);
3709 : } else {
3710 0 : state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(state, _, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _);
3711 : }
3712 : } else { // using 1.0 here for fan speed ratio seems wrong if FCU max flow rate is different than the fan maximum flow rate
3713 76737 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
3714 201825 : Fans::SimulateFanComponents(state,
3715 67275 : FanCoil(FanCoilNum).FanName,
3716 : FirstHVACIteration,
3717 67275 : FanCoil(FanCoilNum).FanIndex,
3718 : 0.0,
3719 : ZoneCompTurnFansOn,
3720 : ZoneCompTurnFansOff);
3721 : } else {
3722 9462 : state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(state, 0.0, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _);
3723 : }
3724 : }
3725 1533543 : if (FanCoil(FanCoilNum).CCoilType_Num == CCoil::HXAssist) {
3726 0 : SimHXAssistedCoolingCoil(state,
3727 0 : FanCoil(FanCoilNum).CCoilName,
3728 : FirstHVACIteration,
3729 : DataHVACGlobals::CompressorOperation::On,
3730 : 0.0,
3731 0 : FanCoil(FanCoilNum).CCoilName_Index,
3732 : ContFanCycCoil);
3733 : } else {
3734 1533543 : SimulateWaterCoilComponents(state, FanCoil(FanCoilNum).CCoilName, FirstHVACIteration, FanCoil(FanCoilNum).CCoilName_Index, _, 1, PLR);
3735 : }
3736 1533543 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
3737 1533543 : SimulateWaterCoilComponents(state, FanCoil(FanCoilNum).HCoilName, FirstHVACIteration, FanCoil(FanCoilNum).HCoilName_Index, _, 1, PLR);
3738 : } else {
3739 0 : if (Node(FanCoil(FanCoilNum).CoolCoilFluidInletNode).MassFlowRate > 0.0) ElecHeaterControl = 0.0;
3740 0 : SimulateHeatingCoilComponents(state,
3741 0 : FanCoil(FanCoilNum).HCoilName,
3742 : FirstHVACIteration,
3743 0 : FanCoil(FanCoilNum).DesignHeatingCapacity * PartLoad * ElecHeaterControl,
3744 0 : FanCoil(FanCoilNum).HCoilName_Index,
3745 : _,
3746 : false,
3747 : ContFanCycCoil,
3748 : PartLoad);
3749 : }
3750 :
3751 3893689 : } else if (FanCoil(FanCoilNum).CapCtrlMeth_Num == CCM::MultiSpeedFan) {
3752 191980 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
3753 0 : Fans::SimulateFanComponents(state,
3754 0 : FanCoil(FanCoilNum).FanName,
3755 : FirstHVACIteration,
3756 0 : FanCoil(FanCoilNum).FanIndex,
3757 0 : state.dataFanCoilUnits->FanFlowRatio,
3758 : ZoneCompTurnFansOn,
3759 : ZoneCompTurnFansOff);
3760 : } else {
3761 : // FanFlowRatio needs to be accurate here for new fan model
3762 191980 : Real64 ActFanFlowRatio = state.dataFanCoilUnits->FanFlowRatio * PartLoad;
3763 191980 : state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(
3764 : state, ActFanFlowRatio, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _);
3765 : }
3766 191980 : if (FanCoil(FanCoilNum).CCoilType_Num == CCoil::HXAssist) {
3767 0 : SimHXAssistedCoolingCoil(state,
3768 0 : FanCoil(FanCoilNum).CCoilName,
3769 : FirstHVACIteration,
3770 : DataHVACGlobals::CompressorOperation::On,
3771 : 0.0,
3772 0 : FanCoil(FanCoilNum).CCoilName_Index,
3773 : ContFanCycCoil);
3774 : } else {
3775 191980 : SimulateWaterCoilComponents(state, FanCoil(FanCoilNum).CCoilName, FirstHVACIteration, FanCoil(FanCoilNum).CCoilName_Index, _, 1, PLR);
3776 : }
3777 191980 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
3778 191980 : SimulateWaterCoilComponents(state, FanCoil(FanCoilNum).HCoilName, FirstHVACIteration, FanCoil(FanCoilNum).HCoilName_Index, _, 1, PLR);
3779 : } else {
3780 0 : if (Node(FanCoil(FanCoilNum).CoolCoilFluidInletNode).MassFlowRate > 0.0) ElecHeaterControl = 0.0;
3781 0 : Real64 QZnReq = 0.0;
3782 0 : if (FanCoil(FanCoilNum).FanOpMode == ContFanCycCoil) {
3783 0 : QZnReq = FanCoil(FanCoilNum).DesignHeatingCapacity * state.dataFanCoilUnits->FanFlowRatio * eHeatCoilCyclingR * ElecHeaterControl;
3784 : } else {
3785 : // proportionally reduce the full flow capacity based on fan flow fraction
3786 0 : QZnReq = FanCoil(FanCoilNum).DesignHeatingCapacity * state.dataFanCoilUnits->FanFlowRatio * PartLoad * eHeatCoilCyclingR *
3787 : ElecHeaterControl;
3788 : }
3789 0 : SimulateHeatingCoilComponents(state,
3790 0 : FanCoil(FanCoilNum).HCoilName,
3791 : FirstHVACIteration,
3792 : QZnReq,
3793 0 : FanCoil(FanCoilNum).HCoilName_Index,
3794 : _,
3795 : false,
3796 0 : FanCoil(FanCoilNum).FanOpMode, // FanCoil(FanCoilNum).FanOpMode, // ContFanCycCoil, CycFanCycCoil
3797 : PartLoad);
3798 : }
3799 : } else { // capacity control method is VariableFanVariableFlow, VariableFanConstantFlow, or ASHRAE90.1
3800 :
3801 : // calculate fan speed ratio for Fan:OnOff or Fan:SystemModel (not used for other fan types). Only used in fan:OnOff model if performance
3802 : // curves are present.
3803 3701709 : FanSpeedRatio = Node(InletNode).MassFlowRate / (FanCoil(FanCoilNum).FanAirVolFlow * state.dataEnvrn->StdRhoAir);
3804 :
3805 : // Constant fan and variable flow calculation AND variable fan
3806 :
3807 3701709 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
3808 8929536 : Fans::SimulateFanComponents(state,
3809 2976512 : FanCoil(FanCoilNum).FanName,
3810 : FirstHVACIteration,
3811 2976512 : FanCoil(FanCoilNum).FanIndex,
3812 : FanSpeedRatio,
3813 : ZoneCompTurnFansOn,
3814 : ZoneCompTurnFansOff);
3815 : } else {
3816 725197 : state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->simulate(state, FanSpeedRatio, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _);
3817 : }
3818 :
3819 3701709 : if (FanCoil(FanCoilNum).CCoilType_Num == CCoil::HXAssist) {
3820 0 : SimHXAssistedCoolingCoil(state,
3821 0 : FanCoil(FanCoilNum).CCoilName,
3822 : FirstHVACIteration,
3823 : DataHVACGlobals::CompressorOperation::On,
3824 : 0.0,
3825 0 : FanCoil(FanCoilNum).CCoilName_Index,
3826 : ContFanCycCoil);
3827 : } else {
3828 3701709 : SimulateWaterCoilComponents(state, FanCoil(FanCoilNum).CCoilName, FirstHVACIteration, FanCoil(FanCoilNum).CCoilName_Index);
3829 : }
3830 3701709 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
3831 3647564 : SimulateWaterCoilComponents(state, FanCoil(FanCoilNum).HCoilName, FirstHVACIteration, FanCoil(FanCoilNum).HCoilName_Index);
3832 : } else {
3833 54145 : if (Node(FanCoil(FanCoilNum).CoolCoilFluidInletNode).MassFlowRate > 0.0) ElecHeaterControl = 0.0;
3834 270725 : SimulateHeatingCoilComponents(state,
3835 54145 : FanCoil(FanCoilNum).HCoilName,
3836 : FirstHVACIteration,
3837 108290 : FanCoil(FanCoilNum).DesignHeatingCapacity * PartLoad * ElecHeaterControl,
3838 54145 : FanCoil(FanCoilNum).HCoilName_Index,
3839 : _,
3840 : false,
3841 : ContFanCycCoil,
3842 : PartLoad);
3843 : }
3844 : }
3845 :
3846 5427232 : if (FanCoil(FanCoilNum).ATMixerExists) {
3847 349032 : if (FanCoil(FanCoilNum).ATMixerType == ATMixer_SupplySide) {
3848 : // Now calculate the ATM mixer if it is on the supply side of the zone unit
3849 179386 : SimATMixer(state, FanCoil(FanCoilNum).ATMixerName, FirstHVACIteration, FanCoil(FanCoilNum).ATMixerIndex);
3850 538158 : LoadMet = calcZoneSensibleOutput(Node(state.dataFanCoilUnits->ATMixOutNode).MassFlowRate,
3851 179386 : Node(state.dataFanCoilUnits->ATMixOutNode).Temp,
3852 179386 : Node(state.dataFanCoilUnits->ZoneNode).Temp,
3853 179386 : Node(state.dataFanCoilUnits->ZoneNode).HumRat);
3854 : } else {
3855 : // ATM Mixer on inlet side
3856 508938 : LoadMet = calcZoneSensibleOutput(
3857 508938 : AirMassFlow, Node(OutletNode).Temp, Node(state.dataFanCoilUnits->ZoneNode).Temp, Node(state.dataFanCoilUnits->ZoneNode).HumRat);
3858 : }
3859 : } else {
3860 5078200 : LoadMet = calcZoneSensibleOutput(AirMassFlow, Node(OutletNode).Temp, Node(InletNode).Temp, Node(InletNode).HumRat);
3861 : }
3862 5427232 : }
3863 :
3864 12375 : void SimMultiStage4PipeFanCoil(EnergyPlusData &state,
3865 : int &FanCoilNum, // number of the current fan coil unit being simulated
3866 : int const ZoneNum, // number of zone being served
3867 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
3868 : Real64 &PowerMet // Sensible power supplied (W)
3869 : )
3870 : {
3871 :
3872 : // SUBROUTINE INFORMATION:
3873 : // AUTHOR Bereket Nigusse
3874 : // DATE WRITTEN July 2015
3875 : // MODIFIED na
3876 :
3877 : // PURPOSE OF THIS SUBROUTINE:
3878 : // Manages multi-speed fancoil unit simulation;
3879 :
3880 : // METHODOLOGY EMPLOYED:
3881 : // Selects the appropriate fan speed for a given zone heating or cooling load
3882 : // and determines whether heating or cooling is required, then runs the hot
3883 : // or chilled water coils.
3884 :
3885 : // Using/Aliasing
3886 : using namespace DataZoneEnergyDemands;
3887 : using PlantUtilities::SetComponentFlowRate;
3888 :
3889 : // Locals
3890 : // SUBROUTINE ARGUMENT DEFINITIONS:
3891 :
3892 : // SUBROUTINE PARAMETER DEFINITIONS:
3893 : // int const MaxIterCycl( 100 );
3894 :
3895 : // INTERFACE BLOCK SPECIFICATIONS
3896 :
3897 : // DERIVED TYPE DEFINITIONS
3898 : // na
3899 :
3900 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3901 : Real64 mdot; // chilled or hot water flow rate through the water coils
3902 : Real64 QZnReq; // heating or cooling needed by zone [watts]
3903 : Real64 QUnitOut; // heating or sens. cooling provided by fan coil unit [watts]
3904 : Real64 QUnitOutMax; // heating or sens. cooling provided by fan coil unit (running during an entire timestep)
3905 : Real64 QTotUnitOut; // total unit output [watts]
3906 : Real64 AirMassFlow; // air mass flow rate [kg/sec]
3907 : Real64 QUnitOutNoHC; // unit output with no active heating or cooling [W]
3908 : Real64 QCoilHeatSP; // coil load to the heating setpoint [W]
3909 : Real64 QCoilCoolSP; // coil load to the cooling setpoint [W]
3910 : Real64 SpeedRatio; // ratio between lower and higher fan speed
3911 : Real64 PartLoadRatio; // Part Load Ratio, fraction of time step fancoil is on
3912 : int OutletNode; // unit air outlet node
3913 : int InletNode; // unit air inlet node
3914 : bool UnitOn; // TRUE if unit is on
3915 :
3916 12375 : auto &FanCoil(state.dataFanCoilUnits->FanCoil);
3917 12375 : auto &HeatingLoad(state.dataFanCoilUnits->HeatingLoad);
3918 12375 : auto &CoolingLoad(state.dataFanCoilUnits->CoolingLoad);
3919 :
3920 : // initialize local variables
3921 12375 : UnitOn = true;
3922 12375 : SpeedRatio = 0.0;
3923 12375 : PartLoadRatio = 0.0;
3924 12375 : QZnReq = 0.0;
3925 12375 : QUnitOut = 0.0;
3926 12375 : QTotUnitOut = 0.0;
3927 12375 : QUnitOutMax = 0.0;
3928 12375 : QUnitOutNoHC = 0.0;
3929 :
3930 12375 : OutletNode = FanCoil(FanCoilNum).AirOutNode;
3931 12375 : InletNode = FanCoil(FanCoilNum).AirInNode;
3932 12375 : AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
3933 :
3934 12375 : if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum) || AirMassFlow < SmallMassFlow) UnitOn = false;
3935 :
3936 12375 : FanCoil(FanCoilNum).SpeedFanSel = 1;
3937 12375 : FanCoil(FanCoilNum).SpeedFanRatSel = FanCoil(FanCoilNum).LowSpeedRatio;
3938 12375 : state.dataFanCoilUnits->FanFlowRatio = FanCoil(FanCoilNum).SpeedFanRatSel;
3939 12375 : AirMassFlow = FanCoil(FanCoilNum).LowSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
3940 12375 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
3941 12375 : state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
3942 12375 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
3943 12375 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
3944 :
3945 12375 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
3946 12375 : mdot = 0.0;
3947 37125 : SetComponentFlowRate(state,
3948 : mdot,
3949 12375 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
3950 12375 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
3951 12375 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
3952 : }
3953 12375 : mdot = 0.0;
3954 37125 : SetComponentFlowRate(state,
3955 : mdot,
3956 12375 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
3957 12375 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
3958 12375 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
3959 : // no load output, requires setting eHeatCoilCyclingR = 0.0, for electric heating coils
3960 12375 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutNoHC, _, 0.0);
3961 :
3962 12375 : QCoilCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToCoolSP;
3963 12375 : QCoilHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP;
3964 12375 : state.dataFanCoilUnits->HeatingLoad = false;
3965 12375 : state.dataFanCoilUnits->CoolingLoad = false;
3966 :
3967 18790 : if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0 &&
3968 6415 : state.dataHeatBalFanSys->TempControlType(ZoneNum) != DataHVACGlobals::ThermostatType::SingleCooling) {
3969 6070 : QZnReq = QCoilHeatSP;
3970 6070 : HeatingLoad = true;
3971 6650 : } else if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0 &&
3972 345 : state.dataHeatBalFanSys->TempControlType(ZoneNum) == DataHVACGlobals::ThermostatType::SingleCooling) {
3973 345 : QZnReq = 0.0;
3974 11920 : } else if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0 &&
3975 5960 : state.dataHeatBalFanSys->TempControlType(ZoneNum) != DataHVACGlobals::ThermostatType::SingleHeating) {
3976 5811 : QZnReq = QCoilCoolSP;
3977 5811 : CoolingLoad = true;
3978 298 : } else if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0 &&
3979 149 : state.dataHeatBalFanSys->TempControlType(ZoneNum) == DataHVACGlobals::ThermostatType::SingleHeating) {
3980 149 : QZnReq = 0.0;
3981 0 : } else if (QCoilHeatSP <= 0.0 && QCoilCoolSP >= 0.0) {
3982 0 : QZnReq = 0.0;
3983 : }
3984 :
3985 : // Zone load calculation for constant fan systems, adopted from unitary system
3986 12375 : if (FanCoil(FanCoilNum).FanOpMode == ContFanCycCoil) {
3987 8236 : switch (state.dataHeatBalFanSys->TempControlType(ZoneNum)) {
3988 4146 : case DataHVACGlobals::ThermostatType::SingleHeating: {
3989 4146 : CoolingLoad = false;
3990 : // No heating load and constant fan pushes zone below heating set point
3991 4146 : if (QUnitOutNoHC < 0.0 && QCoilHeatSP < 0.0 && QUnitOutNoHC - QCoilHeatSP < -SmallLoad) {
3992 14 : HeatingLoad = true;
3993 14 : CoolingLoad = false;
3994 14 : QZnReq = QCoilHeatSP;
3995 : }
3996 4146 : } break;
3997 4090 : case DataHVACGlobals::ThermostatType::SingleCooling: {
3998 4090 : HeatingLoad = false;
3999 : // No heating load and constant fan pushes zone above cooling set point
4000 4090 : if (QUnitOutNoHC > 0.0 && QCoilCoolSP > 0.0 && QUnitOutNoHC - QCoilCoolSP > SmallLoad) {
4001 0 : HeatingLoad = false;
4002 0 : CoolingLoad = true;
4003 0 : QZnReq = QCoilCoolSP;
4004 : }
4005 4090 : } break;
4006 0 : case DataHVACGlobals::ThermostatType::SingleHeatCool: {
4007 : // zone temp above cooling and heating set point temps
4008 0 : if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0) {
4009 : // zone pushed below heating set point
4010 0 : if (QUnitOutNoHC < 0.0 && QCoilHeatSP - QUnitOutNoHC > SmallLoad) {
4011 0 : HeatingLoad = true;
4012 0 : CoolingLoad = false;
4013 0 : QZnReq = QCoilHeatSP;
4014 : }
4015 : // zone temp below heating set point temp
4016 0 : } else if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0) {
4017 : // zone pushed above cooling set point
4018 0 : if (QUnitOutNoHC > 0.0 && QCoilCoolSP - QUnitOutNoHC > SmallLoad) {
4019 0 : HeatingLoad = false;
4020 0 : CoolingLoad = true;
4021 0 : QZnReq = QCoilCoolSP;
4022 : }
4023 : }
4024 0 : } break;
4025 0 : case DataHVACGlobals::ThermostatType::DualSetPointWithDeadBand: {
4026 : // zone temp above cooling and heating set point temps
4027 0 : if (QCoilHeatSP < 0.0 && QCoilCoolSP < 0.0) {
4028 : // zone pushed into deadband
4029 0 : if (QUnitOutNoHC < 0.0 && QCoilCoolSP - QUnitOutNoHC > SmallLoad) {
4030 0 : HeatingLoad = false;
4031 0 : CoolingLoad = false;
4032 0 : QZnReq = 0.0;
4033 : }
4034 : // zone pushed below heating set point
4035 0 : if (QUnitOutNoHC < 0.0 && QCoilHeatSP - QUnitOutNoHC > SmallLoad) {
4036 0 : HeatingLoad = true;
4037 0 : CoolingLoad = false;
4038 0 : QZnReq = QCoilHeatSP;
4039 : }
4040 : // zone temp below heating set point temp
4041 0 : } else if (QCoilHeatSP > 0.0 && QCoilCoolSP > 0.0) {
4042 : // zone pushed into deadband
4043 0 : if (QUnitOutNoHC > 0.0 && QUnitOutNoHC - QCoilHeatSP > SmallLoad) {
4044 0 : HeatingLoad = false;
4045 0 : CoolingLoad = false;
4046 0 : QZnReq = 0.0;
4047 : }
4048 : // zone pushed above cooling set point
4049 0 : if (QUnitOutNoHC > 0.0 && QUnitOutNoHC - QCoilCoolSP > SmallLoad) {
4050 0 : HeatingLoad = false;
4051 0 : CoolingLoad = true;
4052 0 : QZnReq = QCoilCoolSP;
4053 : }
4054 : // zone temp between set point temps
4055 0 : } else if (QCoilHeatSP < 0.0 && QCoilCoolSP > 0.0) {
4056 : // zone pushed below heating set point
4057 0 : if (QUnitOutNoHC < 0.0 && QUnitOutNoHC - QCoilHeatSP < -SmallLoad) {
4058 0 : HeatingLoad = true;
4059 0 : CoolingLoad = false;
4060 0 : QZnReq = QCoilHeatSP;
4061 : // zone pushed above cooling set point
4062 0 : } else if (QUnitOutNoHC > 0.0 && QUnitOutNoHC - QCoilCoolSP > SmallLoad) {
4063 0 : HeatingLoad = false;
4064 0 : CoolingLoad = true;
4065 0 : QZnReq = QCoilCoolSP;
4066 : }
4067 : }
4068 0 : } break;
4069 0 : default:
4070 0 : break;
4071 : }
4072 : // IF small loads to meet, just shut down unit
4073 8236 : if (std::abs(QZnReq) < FanCoilUnits::Small5WLoad) {
4074 292 : QZnReq = 0.0;
4075 292 : CoolingLoad = false;
4076 292 : HeatingLoad = false;
4077 : }
4078 : }
4079 :
4080 12375 : if (UnitOn && QZnReq < (-1.0 * FanCoilUnits::Small5WLoad) && CoolingLoad) {
4081 5808 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
4082 5808 : mdot = 0.0;
4083 17424 : SetComponentFlowRate(state,
4084 : mdot,
4085 5808 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
4086 5808 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
4087 5808 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
4088 : }
4089 5808 : mdot = FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
4090 17424 : SetComponentFlowRate(state,
4091 : mdot,
4092 5808 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
4093 5808 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
4094 5808 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
4095 : // select fan speed
4096 5808 : FanCoil(FanCoilNum).SpeedFanSel = 1;
4097 5808 : FanCoil(FanCoilNum).SpeedFanRatSel = FanCoil(FanCoilNum).LowSpeedRatio;
4098 5808 : state.dataFanCoilUnits->FanFlowRatio = FanCoil(FanCoilNum).SpeedFanRatSel;
4099 5808 : AirMassFlow = FanCoil(FanCoilNum).LowSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4100 5808 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
4101 5808 : state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
4102 5808 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
4103 5808 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
4104 5808 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
4105 5808 : if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
4106 3070 : FanCoil(FanCoilNum).SpeedFanSel = 2;
4107 3070 : FanCoil(FanCoilNum).SpeedFanRatSel = FanCoil(FanCoilNum).MedSpeedRatio;
4108 3070 : state.dataFanCoilUnits->FanFlowRatio = FanCoil(FanCoilNum).SpeedFanRatSel;
4109 3070 : AirMassFlow = FanCoil(FanCoilNum).MedSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4110 3070 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
4111 3070 : state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
4112 3070 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
4113 3070 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = FanCoil(FanCoilNum).LowSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4114 3070 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
4115 : }
4116 5808 : if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
4117 1626 : FanCoil(FanCoilNum).SpeedFanSel = 3;
4118 1626 : FanCoil(FanCoilNum).SpeedFanRatSel = 1.0;
4119 1626 : state.dataFanCoilUnits->FanFlowRatio = FanCoil(FanCoilNum).SpeedFanRatSel;
4120 1626 : AirMassFlow = FanCoil(FanCoilNum).MaxAirMassFlow;
4121 1626 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
4122 1626 : state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
4123 1626 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
4124 1626 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = FanCoil(FanCoilNum).MedSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4125 : }
4126 5808 : CalcMultiStage4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QZnReq, SpeedRatio, PartLoadRatio, QUnitOut);
4127 :
4128 6567 : } else if (UnitOn && QZnReq > FanCoilUnits::Small5WLoad && HeatingLoad) {
4129 :
4130 6070 : mdot = 0.0;
4131 18210 : SetComponentFlowRate(state,
4132 : mdot,
4133 6070 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
4134 6070 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
4135 6070 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
4136 :
4137 6070 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
4138 6070 : mdot = FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
4139 18210 : SetComponentFlowRate(state,
4140 : mdot,
4141 6070 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
4142 6070 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
4143 6070 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
4144 : }
4145 : // select fan speed
4146 6070 : FanCoil(FanCoilNum).SpeedFanSel = 1;
4147 6070 : FanCoil(FanCoilNum).SpeedFanRatSel = FanCoil(FanCoilNum).LowSpeedRatio;
4148 6070 : state.dataFanCoilUnits->FanFlowRatio = FanCoil(FanCoilNum).SpeedFanRatSel;
4149 6070 : AirMassFlow = FanCoil(FanCoilNum).LowSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4150 6070 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
4151 6070 : state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
4152 6070 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
4153 6070 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
4154 6070 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
4155 6070 : if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
4156 3212 : FanCoil(FanCoilNum).SpeedFanSel = 2;
4157 3212 : FanCoil(FanCoilNum).SpeedFanRatSel = FanCoil(FanCoilNum).MedSpeedRatio;
4158 3212 : state.dataFanCoilUnits->FanFlowRatio = FanCoil(FanCoilNum).SpeedFanRatSel;
4159 3212 : AirMassFlow = FanCoil(FanCoilNum).MedSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4160 3212 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
4161 3212 : state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
4162 3212 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
4163 3212 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = FanCoil(FanCoilNum).LowSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4164 3212 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
4165 : }
4166 6070 : if (std::abs(QUnitOutMax) < std::abs(QZnReq)) {
4167 0 : FanCoil(FanCoilNum).SpeedFanSel = 3;
4168 0 : FanCoil(FanCoilNum).SpeedFanRatSel = 1.0;
4169 0 : state.dataFanCoilUnits->FanFlowRatio = FanCoil(FanCoilNum).SpeedFanRatSel;
4170 0 : AirMassFlow = FanCoil(FanCoilNum).MaxAirMassFlow;
4171 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
4172 0 : state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
4173 0 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
4174 0 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = FanCoil(FanCoilNum).MedSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4175 : }
4176 :
4177 6070 : CalcMultiStage4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QZnReq, SpeedRatio, PartLoadRatio, QUnitOut);
4178 :
4179 : } else {
4180 : // SpeedRatio = 0.0;
4181 497 : if (FanCoil(FanCoilNum).FanOpMode == ContFanCycCoil) {
4182 308 : PartLoadRatio = 1.0;
4183 308 : FanCoil(FanCoilNum).SpeedFanSel = 1;
4184 308 : FanCoil(FanCoilNum).SpeedFanRatSel = FanCoil(FanCoilNum).LowSpeedRatio;
4185 308 : state.dataFanCoilUnits->FanFlowRatio = FanCoil(FanCoilNum).SpeedFanRatSel;
4186 308 : AirMassFlow = FanCoil(FanCoilNum).LowSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4187 308 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
4188 308 : state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
4189 308 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
4190 308 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
4191 : } else {
4192 189 : PartLoadRatio = 0.0;
4193 189 : AirMassFlow = 0.0;
4194 189 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AirMassFlow;
4195 189 : state.dataLoopNodes->Node(InletNode).MassFlowRateMax = AirMassFlow;
4196 189 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
4197 189 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = AirMassFlow;
4198 189 : state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
4199 189 : state.dataLoopNodes->Node(OutletNode).MassFlowRate = 0.0;
4200 189 : FanCoil(FanCoilNum).SpeedFanSel = 0;
4201 189 : state.dataFanCoilUnits->FanFlowRatio = 0.0;
4202 : }
4203 :
4204 497 : mdot = 0.0;
4205 497 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
4206 1491 : SetComponentFlowRate(state,
4207 : mdot,
4208 497 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
4209 497 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
4210 497 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
4211 : }
4212 1491 : SetComponentFlowRate(state,
4213 : mdot,
4214 497 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
4215 497 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
4216 497 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
4217 : // No load output, eHeatCoilCyclingR = 0.0 for electric heating coil
4218 497 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PartLoadRatio, 0.0);
4219 : }
4220 : // output variable
4221 12375 : state.dataLoopNodes->Node(OutletNode).MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
4222 12375 : FanCoil(FanCoilNum).PLR = PartLoadRatio;
4223 12375 : FanCoil(FanCoilNum).SpeedRatio = SpeedRatio;
4224 12375 : PowerMet = QUnitOut;
4225 12375 : }
4226 :
4227 11878 : void CalcMultiStage4PipeFanCoil(EnergyPlusData &state,
4228 : int &FanCoilNum, // number of the current fan coil unit being simulated
4229 : int const ZoneNum, // number of zone being served
4230 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
4231 : Real64 const QZnReq, // current zone cooling or heating load
4232 : Real64 &SpeedRatio, // fan coil speed ratio
4233 : Real64 &PartLoadRatio, // fan coil part load ratio
4234 : Real64 &PowerMet // Sensible power supplied (W)
4235 : )
4236 : {
4237 :
4238 : // SUBROUTINE INFORMATION:
4239 : // AUTHOR Bereket Nigusse
4240 : // DATE WRITTEN July 2015
4241 : // MODIFIED na
4242 :
4243 : // PURPOSE OF THIS SUBROUTINE:
4244 : // Simulate a multi-stage fan 4 pipe fan coil unit; adjust its output to
4245 : // match the remaining zone load.
4246 :
4247 : // METHODOLOGY EMPLOYED:
4248 : // If this unit is on, calculated the speed ratio when cycling between
4249 : // consecutive fan speeds. The hot or chilled water flows either at
4250 : // maximum or zero. The water flow rate is set to zero if there is no
4251 : // load.
4252 :
4253 : // Using/Aliasing
4254 : using namespace DataZoneEnergyDemands;
4255 :
4256 : using PlantUtilities::SetComponentFlowRate;
4257 :
4258 : // Locals
4259 : // SUBROUTINE ARGUMENT DEFINITIONS:
4260 :
4261 : // SUBROUTINE PARAMETER DEFINITIONS:
4262 11878 : constexpr int MaxIterCycl(100);
4263 :
4264 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4265 : Real64 PLR; // Part Load Ratio, fraction of time step fancoil is on
4266 : Real64 SRatio; // capacity speed ratio of the for multi-stage fan fancoil unit
4267 : Real64 mdot; // chilled or hot water flow rate through the water coils
4268 : Real64 QUnitOut; // heating or sens. cooling provided by fan coil unit [watts]
4269 : Real64 QUnitOutMax; // max heating or sens. cooling provided by fan coil unit [watts]
4270 : Real64 ControlOffset; // tolerance for output control
4271 : Real64 QUnitOutMaxHS; // higher fan speed output
4272 : Real64 QUnitOutMaxLS; // lower fan speed output
4273 : Real64 HighSpeedRatio; // fan flow ratio at low speed
4274 : Real64 LowSpeedRatio; // fan flow ratio at low speed
4275 : Real64 AirMassFlowAvg; // supply air flow rate weighted by speed ratio
4276 : Real64 AirMassFlowLow; // supply air flow rate at lower speed
4277 : Real64 AirMassFlowHigh; // supply air flow rate at higher speed
4278 : Real64 FanElecPowerHS; // fan electric power calculated at (fan) higher speed
4279 : Real64 FanElecPowerLS; // fan electric power calculated at (fan) lower speed
4280 : Real64 Error; // Error between QZnReq and QUnitOut
4281 : Real64 AbsError; // Absolute error between QZnReq and QUnitOut [W] !FB
4282 : Real64 Relax;
4283 : Real64 DelPLR;
4284 : int OutletNode; // unit air outlet node
4285 : int InletNode; // unit air inlet node
4286 : int Iter; // iteration counter
4287 : int SolFlag; // return flag from RegulaFalsi for sensible load
4288 :
4289 11878 : auto &FanCoil(state.dataFanCoilUnits->FanCoil);
4290 :
4291 : // initialize local variables
4292 11878 : mdot = 0.0;
4293 11878 : PLR = 1.0;
4294 11878 : SRatio = 0.0;
4295 11878 : QUnitOut = 0.0;
4296 11878 : QUnitOutMax = 0.0;
4297 11878 : ControlOffset = 0.0;
4298 11878 : FanElecPowerHS = 0.0;
4299 11878 : FanElecPowerLS = 0.0;
4300 11878 : AirMassFlowAvg = 0.0;
4301 11878 : AirMassFlowLow = 0.0;
4302 11878 : AirMassFlowHigh = 0.0;
4303 11878 : AbsError = 2.0 * FanCoilUnits::Small5WLoad;
4304 11878 : Error = 1.0;
4305 11878 : Relax = 1.0;
4306 11878 : Iter = 0;
4307 :
4308 11878 : OutletNode = FanCoil(FanCoilNum).AirOutNode;
4309 11878 : InletNode = FanCoil(FanCoilNum).AirInNode;
4310 :
4311 11878 : auto &Node(state.dataLoopNodes->Node);
4312 :
4313 11878 : if (QZnReq < (-1.0 * FanCoilUnits::Small5WLoad) && state.dataFanCoilUnits->CoolingLoad) {
4314 5808 : ControlOffset = FanCoil(FanCoilNum).ColdControlOffset;
4315 5808 : if (FanCoil(FanCoilNum).SpeedFanSel == 1) {
4316 2738 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
4317 2738 : PLR = std::abs(QZnReq / QUnitOutMax);
4318 2738 : if (PLR > 1.0) PLR = 1.0;
4319 : // adjust the PLR to meet the cooling load by calling Calc4PipeFanCoil repeatedly
4320 173150 : while (std::abs(Error) > ControlOffset && std::abs(AbsError) > FanCoilUnits::Small5WLoad && Iter < MaxIterCycl && PLR != 1.0) {
4321 85206 : Node(InletNode).MassFlowRateMinAvail = Node(InletNode).MassFlowRate;
4322 85206 : mdot = PLR * FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
4323 255618 : SetComponentFlowRate(state,
4324 : mdot,
4325 85206 : FanCoil(FanCoilNum).CoolCoilFluidInletNode,
4326 85206 : FanCoil(FanCoilNum).CoolCoilFluidOutletNodeNum,
4327 85206 : FanCoil(FanCoilNum).CoolCoilPlantLoc);
4328 85206 : if (FanCoil(FanCoilNum).FanOpMode == ContFanCycCoil) {
4329 82944 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
4330 : } else {
4331 2262 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
4332 : }
4333 85206 : Error = (QZnReq - QUnitOut) / QZnReq;
4334 85206 : AbsError = QZnReq - QUnitOut;
4335 85206 : DelPLR = (QZnReq - QUnitOut) / QUnitOutMax;
4336 85206 : PLR += Relax * DelPLR;
4337 85206 : PLR = max(0.0, min(1.0, PLR));
4338 85206 : ++Iter;
4339 85206 : if (Iter == 32) Relax = 0.5;
4340 85206 : if (Iter == 65) Relax = 0.25;
4341 85206 : if (Iter > 70 && PLR == 0.0 && DelPLR < 0.0) Error = 0.0;
4342 : }
4343 2738 : if (FanCoil(FanCoilNum).FanOpMode == ContFanCycCoil) {
4344 1870 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
4345 : } else {
4346 868 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
4347 : }
4348 : // warning if not converged
4349 2738 : if (Iter > (MaxIterCycl - 1)) {
4350 0 : if (FanCoil(FanCoilNum).MaxIterIndexC == 0) {
4351 0 : ShowWarningMessage(
4352 : state,
4353 0 : "ZoneHVAC:FourPipeFanCoil=\"" + FanCoil(FanCoilNum).Name +
4354 : "\" -- Exceeded max iterations while adjusting cycling fan sensible runtime to meet the zone load within "
4355 : "the cooling convergence tolerance.");
4356 0 : ShowContinueErrorTimeStamp(state, format("Iterations={}", MaxIterCycl));
4357 : }
4358 0 : ShowRecurringWarningErrorAtEnd(state,
4359 0 : "ZoneHVAC:FourPipeFanCoil=\"" + FanCoil(FanCoilNum).Name +
4360 : "\" -- Exceeded max iterations error (sensible runtime) continues...",
4361 0 : FanCoil(FanCoilNum).MaxIterIndexC);
4362 : }
4363 :
4364 : } else {
4365 3070 : if (FanCoil(FanCoilNum).SpeedFanSel == 2) {
4366 1444 : HighSpeedRatio = FanCoil(FanCoilNum).MedSpeedRatio;
4367 1444 : LowSpeedRatio = FanCoil(FanCoilNum).LowSpeedRatio;
4368 : } else {
4369 1626 : HighSpeedRatio = 1;
4370 1626 : LowSpeedRatio = FanCoil(FanCoilNum).MedSpeedRatio;
4371 : }
4372 : // get capacity at lower speed
4373 3070 : FanCoil(FanCoilNum).SpeedFanRatSel = LowSpeedRatio;
4374 3070 : FanCoil(FanCoilNum).SpeedFanSel = FanCoil(FanCoilNum).SpeedFanSel - 1;
4375 3070 : AirMassFlowLow = LowSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4376 3070 : Node(InletNode).MassFlowRate = AirMassFlowLow;
4377 3070 : Node(InletNode).MassFlowRateMax = AirMassFlowLow;
4378 3070 : Node(InletNode).MassFlowRateMaxAvail = AirMassFlowLow;
4379 3070 : Node(InletNode).MassFlowRateMinAvail = AirMassFlowLow;
4380 3070 : state.dataFanCoilUnits->FanFlowRatio = LowSpeedRatio;
4381 3070 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMaxLS);
4382 3070 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
4383 0 : FanElecPowerLS = Fans::GetFanPower(state, FanCoil(FanCoilNum).FanIndex);
4384 : } else {
4385 3070 : FanElecPowerLS = state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->fanPower();
4386 : }
4387 : // get capacity at higher speed
4388 3070 : FanCoil(FanCoilNum).SpeedFanRatSel = HighSpeedRatio;
4389 3070 : FanCoil(FanCoilNum).SpeedFanSel = FanCoil(FanCoilNum).SpeedFanSel + 1;
4390 3070 : AirMassFlowHigh = HighSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4391 3070 : Node(InletNode).MassFlowRate = AirMassFlowHigh;
4392 3070 : Node(InletNode).MassFlowRateMax = AirMassFlowHigh;
4393 3070 : Node(InletNode).MassFlowRateMaxAvail = AirMassFlowHigh;
4394 3070 : Node(InletNode).MassFlowRateMinAvail = AirMassFlowLow;
4395 3070 : state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio;
4396 3070 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMaxHS);
4397 3070 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
4398 0 : FanElecPowerHS = Fans::GetFanPower(state, FanCoil(FanCoilNum).FanIndex);
4399 : } else {
4400 3070 : FanElecPowerHS = state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->fanPower();
4401 : }
4402 : // calc speed ratio
4403 3070 : if (std::abs(QZnReq) > std::abs(QUnitOutMaxHS)) {
4404 0 : SRatio = 1.0;
4405 0 : AirMassFlowAvg = AirMassFlowHigh;
4406 0 : Node(InletNode).MassFlowRate = AirMassFlowHigh;
4407 0 : Node(InletNode).MassFlowRateMax = AirMassFlowHigh;
4408 0 : Node(InletNode).MassFlowRateMaxAvail = AirMassFlowHigh;
4409 0 : Node(InletNode).MassFlowRateMinAvail = AirMassFlowLow;
4410 0 : state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio;
4411 0 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
4412 : } else {
4413 3070 : SRatio = std::abs((QZnReq - QUnitOutMaxLS) / (QUnitOutMaxHS - QUnitOutMaxLS));
4414 3070 : if (SRatio > 1.0) SRatio = 1.0;
4415 3070 : AirMassFlowAvg = AirMassFlowHigh * SRatio + AirMassFlowLow * (1.0 - SRatio);
4416 3070 : Node(InletNode).MassFlowRate = AirMassFlowAvg;
4417 3070 : Node(InletNode).MassFlowRateMax = AirMassFlowAvg;
4418 3070 : Node(InletNode).MassFlowRateMaxAvail = AirMassFlowAvg;
4419 3070 : Node(InletNode).MassFlowRateMinAvail = AirMassFlowLow;
4420 3070 : state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio * SRatio + LowSpeedRatio * (1.0 - SRatio);
4421 3070 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
4422 : // adjust the PLR to meet the cooling load by calling Calc4PipeFanCoil repeatedly
4423 14850 : while (std::abs(Error) > ControlOffset && std::abs(AbsError) > FanCoilUnits::Small5WLoad && Iter < MaxIterCycl && SRatio != 1.0) {
4424 5890 : AirMassFlowAvg = AirMassFlowHigh * SRatio + AirMassFlowLow * (1.0 - SRatio);
4425 5890 : state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio * SRatio + LowSpeedRatio * (1.0 - SRatio);
4426 5890 : Node(InletNode).MassFlowRate = AirMassFlowAvg;
4427 5890 : Node(InletNode).MassFlowRateMax = AirMassFlowAvg;
4428 5890 : Node(InletNode).MassFlowRateMaxAvail = AirMassFlowAvg;
4429 5890 : Node(InletNode).MassFlowRateMinAvail = AirMassFlowLow;
4430 5890 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
4431 5890 : Error = (QZnReq - QUnitOut) / QZnReq;
4432 5890 : AbsError = QZnReq - QUnitOut;
4433 5890 : DelPLR = (QZnReq - QUnitOut) / (QUnitOutMaxHS - QUnitOutMaxLS);
4434 5890 : SRatio += Relax * DelPLR;
4435 5890 : SRatio = max(0.0, min(1.0, SRatio));
4436 5890 : ++Iter;
4437 5890 : if (Iter == 32) Relax = 0.5;
4438 5890 : if (Iter == 65) Relax = 0.25;
4439 5890 : if (Iter > 70 && SRatio == 0.0 && DelPLR < 0.0) Error = 0.0;
4440 : }
4441 : }
4442 : }
4443 6070 : } else if (QZnReq > FanCoilUnits::Small5WLoad && state.dataFanCoilUnits->HeatingLoad) {
4444 6070 : ControlOffset = FanCoil(FanCoilNum).HotControlOffset;
4445 6070 : if (FanCoil(FanCoilNum).SpeedFanSel == 1) {
4446 2858 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMax);
4447 2858 : PLR = std::abs(QZnReq / QUnitOutMax);
4448 2858 : if (PLR > 1.0) PLR = 1.0;
4449 2858 : if (FanCoil(FanCoilNum).HCoilType_Num == HCoil::Water) {
4450 : // adjust the PLR to meet the heating load by calling Calc4PipeFanCoil repeatedly
4451 63118 : while (std::abs(Error) > ControlOffset && std::abs(AbsError) > FanCoilUnits::Small5WLoad && Iter < MaxIterCycl && PLR != 1.0) {
4452 30130 : Node(InletNode).MassFlowRateMinAvail = Node(InletNode).MassFlowRate;
4453 30130 : mdot = PLR * FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
4454 90390 : SetComponentFlowRate(state,
4455 : mdot,
4456 30130 : FanCoil(FanCoilNum).HeatCoilFluidInletNode,
4457 30130 : FanCoil(FanCoilNum).HeatCoilFluidOutletNodeNum,
4458 30130 : FanCoil(FanCoilNum).HeatCoilPlantLoc);
4459 30130 : if (FanCoil(FanCoilNum).FanOpMode == ContFanCycCoil) {
4460 28456 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
4461 : } else {
4462 1674 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
4463 : }
4464 30130 : Error = (QZnReq - QUnitOut) / QZnReq;
4465 30130 : AbsError = QZnReq - QUnitOut;
4466 30130 : DelPLR = (QZnReq - QUnitOut) / QUnitOutMax;
4467 30130 : PLR += Relax * DelPLR;
4468 30130 : PLR = max(0.0, min(1.0, PLR));
4469 30130 : ++Iter;
4470 30130 : if (Iter == 32) Relax = 0.5;
4471 30130 : if (Iter == 65) Relax = 0.25;
4472 30130 : if (Iter > 70 && PLR == 0.0 && DelPLR < 0.0) Error = 0.0; // exit loop if PLR = 0
4473 : }
4474 2858 : if (FanCoil(FanCoilNum).FanOpMode == ContFanCycCoil) {
4475 2572 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
4476 : } else {
4477 286 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
4478 : }
4479 : // warning if not converged
4480 2858 : if (Iter > (MaxIterCycl - 1)) {
4481 0 : if (FanCoil(FanCoilNum).MaxIterIndexH == 0) {
4482 0 : ShowWarningMessage(
4483 : state,
4484 0 : "ZoneHVAC:FourPipeFanCoil=\"" + FanCoil(FanCoilNum).Name +
4485 : "\" -- Exceeded max iterations while adjusting cycling fan sensible runtime to meet the zone load within "
4486 : "the heating convergence tolerance.");
4487 0 : ShowContinueErrorTimeStamp(state, format("Iterations={}", MaxIterCycl));
4488 : }
4489 0 : ShowRecurringWarningErrorAtEnd(state,
4490 0 : "ZoneHVAC:FourPipeFanCoil=\"" + FanCoil(FanCoilNum).Name +
4491 : "\" -- Exceeded max iterations error (sensible runtime) continues...",
4492 0 : FanCoil(FanCoilNum).MaxIterIndexH);
4493 : }
4494 : } else {
4495 0 : Real64 eHeatCoilPLR = PLR;
4496 : // electric heating coil
4497 0 : if (QUnitOutMax > QZnReq) {
4498 : // heating coil output is larger than required, mudulate the electric heating coil output to meet the load
4499 0 : Node(InletNode).MassFlowRateMinAvail = Node(InletNode).MassFlowRate;
4500 :
4501 0 : if (FanCoil(FanCoilNum).FanOpMode == ContFanCycCoil) {
4502 0 : auto f = [&state, FanCoilNum, FirstHVACIteration, ZoneNum, QZnReq](Real64 const CyclingR) {
4503 0 : return CalcFanCoilHeatCoilPLRResidual(state, CyclingR, FanCoilNum, FirstHVACIteration, ZoneNum, QZnReq);
4504 0 : };
4505 0 : General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, eHeatCoilPLR, f, 0.0, 1.0);
4506 : } else {
4507 0 : auto f = [&state, FirstHVACIteration, FanCoilNum, ZoneNum, QZnReq](Real64 const PartLoadRatio) {
4508 0 : return CalcFanCoilLoadResidual(state, FanCoilNum, FirstHVACIteration, ZoneNum, QZnReq, PartLoadRatio);
4509 0 : };
4510 0 : General::SolveRoot(state, 0.001, MaxIterCycl, SolFlag, eHeatCoilPLR, f, 0.0, 1.0);
4511 : }
4512 0 : if (SolFlag == -1) {
4513 0 : ++FanCoil(FanCoilNum).ConvgErrCountH;
4514 0 : if (FanCoil(FanCoilNum).ConvgErrCountH < 2) {
4515 0 : ShowWarningError(state, "Electric heating coil control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
4516 0 : ShowContinueError(state, " Iteration limit exceeded in calculating electric heating coil capacity modulation ");
4517 0 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, _, eHeatCoilPLR);
4518 0 : ShowContinueErrorTimeStamp(state, format("Load Request = {}, Final Capacity = {}", QZnReq, QUnitOut));
4519 0 : ShowContinueErrorTimeStamp(
4520 0 : state, format("Electric heating coil part load ratio used during last iterations = {}", eHeatCoilPLR));
4521 : } else {
4522 0 : ShowRecurringWarningErrorAtEnd(state,
4523 0 : "Electric heating coil Iteration limit exceeded in fan coil unit " +
4524 0 : FanCoil(FanCoilNum).Name,
4525 0 : FanCoil(FanCoilNum).MaxIterIndexH);
4526 : }
4527 0 : } else if (SolFlag == -2) {
4528 0 : ++FanCoil(FanCoilNum).LimitErrCountH;
4529 0 : if (FanCoil(FanCoilNum).LimitErrCountH < 2) {
4530 0 : ShowWarningError(state,
4531 0 : "Part load ratio electric heating coil control failed in fan coil unit " + FanCoil(FanCoilNum).Name);
4532 0 : ShowContinueError(state, " Bad par load ratio limits");
4533 0 : ShowContinueErrorTimeStamp(state, "..Par load ratio set to 0");
4534 : } else {
4535 0 : ShowRecurringWarningErrorAtEnd(state,
4536 0 : "Part load ratio electric heating coil control failed in fan coil unit " +
4537 0 : FanCoil(FanCoilNum).Name,
4538 0 : FanCoil(FanCoilNum).BadMassFlowLimIndexH);
4539 : }
4540 : }
4541 : } else {
4542 0 : eHeatCoilPLR = 1.0;
4543 : }
4544 0 : PLR = eHeatCoilPLR;
4545 : // at the end calculate output
4546 0 : if (FanCoil(FanCoilNum).FanOpMode == ContFanCycCoil) {
4547 0 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, _, eHeatCoilPLR);
4548 : } else {
4549 0 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR);
4550 : }
4551 : }
4552 :
4553 : } else {
4554 3212 : if (FanCoil(FanCoilNum).SpeedFanSel == 2) {
4555 3212 : HighSpeedRatio = FanCoil(FanCoilNum).MedSpeedRatio;
4556 3212 : LowSpeedRatio = FanCoil(FanCoilNum).LowSpeedRatio;
4557 : } else {
4558 0 : HighSpeedRatio = 1;
4559 0 : LowSpeedRatio = FanCoil(FanCoilNum).MedSpeedRatio;
4560 : }
4561 : // get capacity at lower speed ratio
4562 3212 : FanCoil(FanCoilNum).SpeedFanRatSel = LowSpeedRatio;
4563 3212 : FanCoil(FanCoilNum).SpeedFanSel = FanCoil(FanCoilNum).SpeedFanSel - 1;
4564 3212 : AirMassFlowLow = LowSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4565 3212 : Node(InletNode).MassFlowRate = AirMassFlowLow;
4566 3212 : Node(InletNode).MassFlowRateMax = AirMassFlowLow;
4567 3212 : Node(InletNode).MassFlowRateMaxAvail = AirMassFlowLow;
4568 3212 : Node(InletNode).MassFlowRateMinAvail = AirMassFlowLow;
4569 3212 : state.dataFanCoilUnits->FanFlowRatio = LowSpeedRatio;
4570 3212 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMaxLS);
4571 3212 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
4572 0 : FanElecPowerLS = Fans::GetFanPower(state, FanCoil(FanCoilNum).FanIndex);
4573 : } else {
4574 3212 : FanElecPowerLS = state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->fanPower();
4575 : }
4576 : // get capacity at higher speed
4577 3212 : FanCoil(FanCoilNum).SpeedFanRatSel = HighSpeedRatio;
4578 3212 : FanCoil(FanCoilNum).SpeedFanSel = FanCoil(FanCoilNum).SpeedFanSel + 1;
4579 3212 : AirMassFlowHigh = HighSpeedRatio * FanCoil(FanCoilNum).MaxAirMassFlow;
4580 3212 : Node(InletNode).MassFlowRate = AirMassFlowHigh;
4581 3212 : Node(InletNode).MassFlowRateMax = AirMassFlowHigh;
4582 3212 : Node(InletNode).MassFlowRateMaxAvail = AirMassFlowHigh;
4583 3212 : Node(InletNode).MassFlowRateMinAvail = AirMassFlowLow;
4584 3212 : state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio;
4585 3212 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOutMaxHS);
4586 3212 : if (FanCoil(FanCoilNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
4587 0 : FanElecPowerHS = Fans::GetFanPower(state, FanCoil(FanCoilNum).FanIndex);
4588 : } else {
4589 3212 : FanElecPowerHS = state.dataHVACFan->fanObjs[FanCoil(FanCoilNum).FanIndex]->fanPower();
4590 : }
4591 : // calc speed ratio
4592 3212 : if (std::abs(QZnReq) > std::abs(QUnitOutMaxHS)) {
4593 0 : SRatio = 1.0;
4594 0 : AirMassFlowAvg = AirMassFlowHigh;
4595 0 : Node(InletNode).MassFlowRate = AirMassFlowAvg;
4596 0 : Node(InletNode).MassFlowRateMax = AirMassFlowAvg;
4597 0 : Node(InletNode).MassFlowRateMaxAvail = AirMassFlowAvg;
4598 0 : Node(InletNode).MassFlowRateMinAvail = AirMassFlowLow;
4599 0 : state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio;
4600 0 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
4601 : } else {
4602 3212 : SRatio = std::abs((QZnReq - QUnitOutMaxLS) / (QUnitOutMaxHS - QUnitOutMaxLS));
4603 3212 : if (SRatio > 1.0) SRatio = 1.0;
4604 3212 : AirMassFlowAvg = AirMassFlowHigh * SRatio + AirMassFlowLow * (1.0 - SRatio);
4605 3212 : Node(InletNode).MassFlowRate = AirMassFlowAvg;
4606 3212 : Node(InletNode).MassFlowRateMax = AirMassFlowAvg;
4607 3212 : Node(InletNode).MassFlowRateMaxAvail = AirMassFlowAvg;
4608 3212 : Node(InletNode).MassFlowRateMinAvail = AirMassFlowLow;
4609 3212 : state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio * SRatio + LowSpeedRatio * (1.0 - SRatio);
4610 3212 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
4611 3212 : ControlOffset = FanCoil(FanCoilNum).HotControlOffset;
4612 : // adjust the PLR to meet the heating load calling Calc4PipeFanCoil repeatedly
4613 22580 : while (std::abs(Error) > ControlOffset && std::abs(AbsError) > FanCoilUnits::Small5WLoad && Iter < MaxIterCycl && SRatio != 1.0) {
4614 9684 : AirMassFlowAvg = AirMassFlowHigh * SRatio + AirMassFlowLow * (1.0 - SRatio);
4615 9684 : Node(InletNode).MassFlowRate = AirMassFlowAvg;
4616 9684 : Node(InletNode).MassFlowRateMax = AirMassFlowAvg;
4617 9684 : Node(InletNode).MassFlowRateMaxAvail = AirMassFlowAvg;
4618 9684 : Node(InletNode).MassFlowRateMinAvail = AirMassFlowLow;
4619 9684 : state.dataFanCoilUnits->FanFlowRatio = HighSpeedRatio * SRatio + LowSpeedRatio * (1.0 - SRatio);
4620 9684 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut);
4621 9684 : Error = (QZnReq - QUnitOut) / QZnReq;
4622 9684 : AbsError = QZnReq - QUnitOut;
4623 9684 : DelPLR = (QZnReq - QUnitOut) / (QUnitOutMaxHS - QUnitOutMaxLS);
4624 9684 : SRatio += Relax * DelPLR;
4625 9684 : SRatio = max(0.0, min(1.0, SRatio));
4626 9684 : ++Iter;
4627 9684 : if (Iter == 32) Relax = 0.5;
4628 9684 : if (Iter == 65) Relax = 0.25;
4629 9684 : if (Iter > 70 && SRatio == 0.0 && DelPLR < 0.0) Error = 0.0;
4630 : }
4631 : }
4632 : // FanElecPower = FanElecPowerHS * SRatio + FanElecPowerLS * ( 1.0 - SRatio ); // why set the ugly global here?
4633 3212 : FanCoil(FanCoilNum).ElecPower = FanElecPowerHS * SRatio + FanElecPowerLS * (1.0 - SRatio);
4634 : }
4635 : }
4636 11878 : Node(OutletNode).MassFlowRate = Node(InletNode).MassFlowRate;
4637 11878 : PartLoadRatio = PLR;
4638 11878 : SpeedRatio = SRatio;
4639 11878 : PowerMet = QUnitOut;
4640 11878 : }
4641 :
4642 514191 : void ReportFanCoilUnit(EnergyPlusData &state, int const FanCoilNum) // number of the current fan coil unit being simulated
4643 : {
4644 :
4645 : // SUBROUTINE INFORMATION:
4646 : // AUTHOR Fred Buhl
4647 : // DATE WRITTEN March 2000
4648 : // MODIFIED na
4649 : // RE-ENGINEERED na
4650 :
4651 : // PURPOSE OF THIS SUBROUTINE:
4652 : // Fills some of the report variables for the fan coil units
4653 :
4654 : // METHODOLOGY EMPLOYED:
4655 : // NA
4656 :
4657 : // REFERENCES:
4658 : // na
4659 :
4660 : // Using/Aliasing
4661 514191 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
4662 :
4663 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4664 : Real64 ReportingConstant;
4665 :
4666 514191 : ReportingConstant = TimeStepSys * DataGlobalConstants::SecInHour;
4667 514191 : state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatEnergy = state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatPower * ReportingConstant;
4668 514191 : state.dataFanCoilUnits->FanCoil(FanCoilNum).SensCoolEnergy = state.dataFanCoilUnits->FanCoil(FanCoilNum).SensCoolPower * ReportingConstant;
4669 514191 : state.dataFanCoilUnits->FanCoil(FanCoilNum).TotCoolEnergy = state.dataFanCoilUnits->FanCoil(FanCoilNum).TotCoolPower * ReportingConstant;
4670 514191 : state.dataFanCoilUnits->FanCoil(FanCoilNum).ElecEnergy = state.dataFanCoilUnits->FanCoil(FanCoilNum).ElecPower * ReportingConstant;
4671 :
4672 514191 : if (state.dataFanCoilUnits->FanCoil(FanCoilNum).FirstPass) { // reset sizing flags so other zone equipment can size normally
4673 162 : if (!state.dataGlobal->SysSizingCalc) {
4674 81 : DataSizing::resetHVACSizingGlobals(state, state.dataSize->CurZoneEqNum, 0, state.dataFanCoilUnits->FanCoil(FanCoilNum).FirstPass);
4675 : }
4676 : }
4677 514191 : }
4678 :
4679 25465 : int GetFanCoilZoneInletAirNode(EnergyPlusData &state, int const FanCoilNum)
4680 : {
4681 :
4682 : // FUNCTION INFORMATION:
4683 : // AUTHOR B Griffith
4684 : // DATE WRITTEN Dec 2006
4685 : // MODIFIED na
4686 : // RE-ENGINEERED na
4687 :
4688 : // PURPOSE OF THIS FUNCTION:
4689 : // lookup function for OA inlet node for ventilation rate reporting
4690 :
4691 : // Return value
4692 : int GetFanCoilZoneInletAirNode;
4693 :
4694 25465 : if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
4695 0 : GetFanCoilUnits(state);
4696 0 : state.dataFanCoilUnits->GetFanCoilInputFlag = false;
4697 : }
4698 :
4699 25465 : GetFanCoilZoneInletAirNode = 0;
4700 25465 : if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
4701 25465 : GetFanCoilZoneInletAirNode = state.dataFanCoilUnits->FanCoil(FanCoilNum).AirOutNode;
4702 : }
4703 :
4704 25465 : return GetFanCoilZoneInletAirNode;
4705 : }
4706 :
4707 25465 : int GetFanCoilOutAirNode(EnergyPlusData &state, int const FanCoilNum)
4708 : {
4709 :
4710 : // FUNCTION INFORMATION:
4711 : // AUTHOR B Griffith
4712 : // DATE WRITTEN Dec 2006
4713 : // MODIFIED na
4714 : // RE-ENGINEERED na
4715 :
4716 : // PURPOSE OF THIS FUNCTION:
4717 : // lookup function for OA inlet node for ventilation rate reporting
4718 :
4719 : // Return value
4720 : int GetFanCoilOutAirNode;
4721 :
4722 25465 : if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
4723 0 : GetFanCoilUnits(state);
4724 0 : state.dataFanCoilUnits->GetFanCoilInputFlag = false;
4725 : }
4726 :
4727 25465 : GetFanCoilOutAirNode = 0;
4728 25465 : if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
4729 25465 : GetFanCoilOutAirNode = state.dataFanCoilUnits->FanCoil(FanCoilNum).OutsideAirNode;
4730 : }
4731 :
4732 25465 : return GetFanCoilOutAirNode;
4733 : }
4734 :
4735 25465 : int GetFanCoilReturnAirNode(EnergyPlusData &state, int const FanCoilNum)
4736 : {
4737 :
4738 : // FUNCTION INFORMATION:
4739 : // AUTHOR B Griffith
4740 : // DATE WRITTEN Dec 2006
4741 : // MODIFIED na
4742 : // RE-ENGINEERED na
4743 :
4744 : // PURPOSE OF THIS FUNCTION:
4745 : // lookup function for mixer's return node
4746 :
4747 : // Using/Aliasing
4748 : using MixedAir::GetOAMixerReturnNodeNumber;
4749 :
4750 : // Return value
4751 : int GetFanCoilReturnAirNode;
4752 :
4753 25465 : if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
4754 0 : GetFanCoilUnits(state);
4755 0 : state.dataFanCoilUnits->GetFanCoilInputFlag = false;
4756 : }
4757 :
4758 25465 : GetFanCoilReturnAirNode = 0;
4759 25465 : if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
4760 25465 : if (state.dataFanCoilUnits->FanCoil(FanCoilNum).OAMixIndex > 0) {
4761 23235 : GetFanCoilReturnAirNode = GetOAMixerReturnNodeNumber(state, state.dataFanCoilUnits->FanCoil(FanCoilNum).OAMixIndex);
4762 : } else {
4763 2230 : GetFanCoilReturnAirNode = 0;
4764 : }
4765 : }
4766 :
4767 25465 : return GetFanCoilReturnAirNode;
4768 : }
4769 :
4770 25465 : int GetFanCoilMixedAirNode(EnergyPlusData &state, int const FanCoilNum)
4771 : {
4772 :
4773 : // FUNCTION INFORMATION:
4774 : // AUTHOR B Griffith
4775 : // DATE WRITTEN Dec 2006
4776 : // MODIFIED na
4777 : // RE-ENGINEERED na
4778 :
4779 : // PURPOSE OF THIS FUNCTION:
4780 : // lookup function for mixer's return node
4781 :
4782 : // Using/Aliasing
4783 : using MixedAir::GetOAMixerMixedNodeNumber;
4784 :
4785 : // Return value
4786 : int GetFanCoilMixedAirNode;
4787 :
4788 25465 : if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
4789 0 : GetFanCoilUnits(state);
4790 0 : state.dataFanCoilUnits->GetFanCoilInputFlag = false;
4791 : }
4792 :
4793 25465 : GetFanCoilMixedAirNode = 0;
4794 25465 : if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
4795 25465 : if (state.dataFanCoilUnits->FanCoil(FanCoilNum).OAMixIndex > 0) {
4796 23235 : GetFanCoilMixedAirNode = GetOAMixerMixedNodeNumber(state, state.dataFanCoilUnits->FanCoil(FanCoilNum).OAMixIndex);
4797 : } else {
4798 2230 : GetFanCoilMixedAirNode = 0;
4799 : }
4800 : }
4801 :
4802 25465 : return GetFanCoilMixedAirNode;
4803 : }
4804 :
4805 0 : int GetFanCoilInletAirNode(EnergyPlusData &state, int const FanCoilNum)
4806 : {
4807 :
4808 : // FUNCTION INFORMATION:
4809 : // AUTHOR B Griffith
4810 : // DATE WRITTEN Dec 2006
4811 : // MODIFIED na
4812 : // RE-ENGINEERED na
4813 :
4814 : // PURPOSE OF THIS FUNCTION:
4815 : // lookup function for inlet node for Fan Coil unit
4816 :
4817 : // Return value
4818 : int GetFanCoilInletAirNode;
4819 :
4820 0 : if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
4821 0 : GetFanCoilUnits(state);
4822 0 : state.dataFanCoilUnits->GetFanCoilInputFlag = false;
4823 : }
4824 :
4825 0 : GetFanCoilInletAirNode = 0;
4826 0 : if (FanCoilNum > 0 && FanCoilNum <= state.dataFanCoilUnits->NumFanCoils) {
4827 0 : GetFanCoilInletAirNode = state.dataFanCoilUnits->FanCoil(FanCoilNum).AirOutNode;
4828 : }
4829 :
4830 0 : return GetFanCoilInletAirNode;
4831 : }
4832 :
4833 0 : void GetFanCoilIndex(EnergyPlusData &state, std::string const &FanCoilName, int &FanCoilIndex)
4834 : {
4835 : bool ErrorsFound; // for error trapping
4836 0 : if (state.dataFanCoilUnits->GetFanCoilInputFlag) {
4837 0 : GetFanCoilUnits(state);
4838 0 : state.dataFanCoilUnits->GetFanCoilInputFlag = false;
4839 : }
4840 0 : FanCoilIndex = UtilityRoutines::FindItemInList(FanCoilName, state.dataFanCoilUnits->FanCoil);
4841 0 : if (FanCoilIndex == 0) {
4842 0 : ShowSevereError(state, "GetFanCoilIndex: Fan Coil Unit not found=" + FanCoilName);
4843 : }
4844 0 : ErrorsFound = true;
4845 0 : }
4846 :
4847 6126 : Real64 CalcFanCoilLoadResidual(EnergyPlusData &state,
4848 : int FanCoilNum, // Index to this fan coil unit
4849 : bool FirstHVACIteration, // FirstHVACIteration flag
4850 : int ControlledZoneNum, // zone index
4851 : Real64 QZnReq, // Sensible load to be met [W]
4852 : Real64 const PartLoadRatio // coil part load ratio
4853 : )
4854 : {
4855 : // FUNCTION INFORMATION:
4856 : // AUTHOR Richard Raustad, FSEC
4857 : // DATE WRITTEN July 2015
4858 :
4859 : // PURPOSE OF THIS SUBROUTINE:
4860 : // To calculate the part-load ratio for the FCU with electric heating coil
4861 :
4862 : Real64 QUnitOut; // delivered capacity [W]
4863 6126 : Calc4PipeFanCoil(state,
4864 : FanCoilNum,
4865 : ControlledZoneNum,
4866 : FirstHVACIteration,
4867 : QUnitOut,
4868 : PartLoadRatio); // needs PLR=0 for electric heating coil, otherwise will run a full capacity
4869 : // Calculate residual based on output magnitude
4870 6126 : if (std::abs(QZnReq) <= 100.0) {
4871 0 : return (QUnitOut - QZnReq) / 100.0;
4872 : } else {
4873 6126 : return (QUnitOut - QZnReq) / QZnReq;
4874 : }
4875 : }
4876 :
4877 673380 : Real64 CalcFanCoilPLRResidual(EnergyPlusData &state,
4878 : Real64 const PLR, // part-load ratio of air and water mass flow rate
4879 : int FanCoilNum, // Index to this fan coil unit
4880 : bool FirstHVACIteration, // FirstHVACIteration flag
4881 : int ControlledZoneNum, // zone index
4882 : int WaterControlNode, // water node to control
4883 : Real64 QZnReq // Sensible load to be met [W] // Function parameters
4884 : )
4885 : {
4886 :
4887 : // FUNCTION INFORMATION:
4888 : // AUTHOR Richard Raustad
4889 : // DATE WRITTEN August 2016
4890 :
4891 : // PURPOSE OF THIS SUBROUTINE:
4892 : Real64 QUnitOut; // delivered capacity [W]
4893 673380 : if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode) {
4894 350503 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxCoolCoilFluidFlow;
4895 350503 : Calc4PipeFanCoil(state,
4896 : FanCoilNum,
4897 : ControlledZoneNum,
4898 : FirstHVACIteration,
4899 : QUnitOut,
4900 : PLR); // needs PLR=0 for electric heating coil, otherwise will run a full capacity
4901 645754 : } else if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode &&
4902 322877 : state.dataFanCoilUnits->FanCoil(FanCoilNum).HCoilType_Num != HCoil::Electric) {
4903 322877 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = PLR * state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxHeatCoilFluidFlow;
4904 322877 : Calc4PipeFanCoil(state,
4905 : FanCoilNum,
4906 : ControlledZoneNum,
4907 : FirstHVACIteration,
4908 : QUnitOut,
4909 : PLR); // needs PLR=0 for electric heating coil, otherwise will run a full capacity
4910 : } else {
4911 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR); // needs PLR=1 for electric heating coil
4912 : }
4913 :
4914 : // Calculate residual based on output magnitude
4915 673380 : if (std::abs(QZnReq) <= 100.0) {
4916 16860 : return (QUnitOut - QZnReq) / 100.0;
4917 : } else {
4918 656520 : return (QUnitOut - QZnReq) / QZnReq;
4919 : }
4920 : }
4921 :
4922 0 : Real64 CalcFanCoilHeatCoilPLRResidual(EnergyPlusData &state,
4923 : Real64 const CyclingR, // electric heating coil cycling ratio
4924 : int const FanCoilNum,
4925 : bool const FirstHVACIteration,
4926 : int const ZoneNum,
4927 : Real64 const QZnReq)
4928 : {
4929 : // PURPOSE OF THIS SUBROUTINE:
4930 : // Calculate electric heating coil cycling ratio of FanCoilUnit with MultiSpeedFan
4931 : // capacity control method when running with at lowest speed for a continuous
4932 : // fan operating mode.
4933 :
4934 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4935 : Real64 QUnitOut; // delivered capacity [W]
4936 0 : Real64 constexpr PLR = 1.0; // fan coil unit PLR
4937 :
4938 : // electric heating coil cycling ratio at minimum air flow for constant fan operating mode
4939 0 : Calc4PipeFanCoil(state, FanCoilNum, ZoneNum, FirstHVACIteration, QUnitOut, PLR, CyclingR);
4940 :
4941 : // Calculate residual based on output magnitude
4942 0 : if (std::abs(QZnReq) <= 100.0) {
4943 0 : return (QUnitOut - QZnReq) / 100.0;
4944 : } else {
4945 0 : return (QUnitOut - QZnReq) / QZnReq;
4946 : }
4947 : }
4948 :
4949 1659776 : Real64 CalcFanCoilCWLoadResidual(EnergyPlusData &state,
4950 : Real64 const CWFlow, // water mass flow rate [kg/s]
4951 : int const FanCoilNum,
4952 : bool const FirstHVACIteration,
4953 : int const ControlledZoneNum,
4954 : Real64 const QZnReq)
4955 : {
4956 :
4957 : // FUNCTION INFORMATION:
4958 : // AUTHOR Fred Buhl Jan 2016
4959 : // DATE WRITTEN July 2015
4960 : // MODIFIED na
4961 : // RE-ENGINEERED na
4962 :
4963 : // PURPOSE OF THIS SUBROUTINE:
4964 : // To calculate the part-load ratio for the FCU with electric heating coil
4965 :
4966 : Real64 QUnitOut; // delivered capacity [W]
4967 1659776 : state.dataLoopNodes->Node(state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode).MassFlowRate = CWFlow;
4968 1659776 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, 1.0);
4969 :
4970 : // Calculate residual based on output magnitude
4971 1659776 : if (std::abs(QZnReq) <= 100.0) {
4972 8237 : return (QUnitOut - QZnReq) / 100.0;
4973 : } else {
4974 1651539 : return (QUnitOut - QZnReq) / QZnReq;
4975 : }
4976 : }
4977 :
4978 91060 : Real64 CalcFanCoilWaterFlowResidual(EnergyPlusData &state,
4979 : Real64 const PLR,
4980 : int FanCoilNum,
4981 : bool FirstHVACIteration,
4982 : int ControlledZoneNum,
4983 : Real64 QZnReq,
4984 : int AirInNode,
4985 : int WaterControlNode,
4986 : Real64 maxCoilFluidFlow,
4987 : Real64 AirMassFlowRate)
4988 : {
4989 :
4990 : // FUNCTION INFORMATION:
4991 : // AUTHOR Richard Raustad, FSEC
4992 : // DATE WRITTEN December 2015
4993 : // MODIFIED na
4994 : // RE-ENGINEERED na
4995 :
4996 : // PURPOSE OF THIS SUBROUTINE:
4997 : // To calculate the part-load ratio for the FCU with varying water flow rate
4998 :
4999 91060 : Real64 const mDot = PLR * maxCoilFluidFlow;
5000 91060 : if (WaterControlNode > 0) state.dataLoopNodes->Node(WaterControlNode).MassFlowRate = mDot;
5001 91060 : state.dataLoopNodes->Node(AirInNode).MassFlowRate = AirMassFlowRate;
5002 :
5003 : Real64 QUnitOut;
5004 223710 : if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode ||
5005 83180 : (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode &&
5006 41590 : state.dataFanCoilUnits->FanCoil(FanCoilNum).HCoilType_Num != HCoil::Electric)) {
5007 :
5008 91060 : Calc4PipeFanCoil(state,
5009 : FanCoilNum,
5010 : ControlledZoneNum,
5011 : FirstHVACIteration,
5012 : QUnitOut,
5013 : 0.0); // needs PLR=0 for electric heating coil, otherwise will run a full capacity
5014 :
5015 : } else {
5016 0 : Calc4PipeFanCoil(state, FanCoilNum, ControlledZoneNum, FirstHVACIteration, QUnitOut, PLR);
5017 : }
5018 :
5019 : // Calculate residual based on output magnitude
5020 91060 : if (std::abs(QZnReq) <= 100.0) {
5021 64 : return (QUnitOut - QZnReq) / 100.0;
5022 : } else {
5023 90996 : return (QUnitOut - QZnReq) / QZnReq;
5024 : }
5025 : }
5026 :
5027 20562 : Real64 CalcFanCoilAirAndWaterFlowResidual(EnergyPlusData &state,
5028 : Real64 const PLR, // water and air part load ratio
5029 : int FanCoilNum,
5030 : bool FirstHVACIteration,
5031 : int ControlledZoneNum,
5032 : Real64 QZnReq,
5033 : int AirInNode,
5034 : int WaterControlNode,
5035 : Real64 MinWaterFlow)
5036 : {
5037 :
5038 : // FUNCTION INFORMATION:
5039 : // AUTHOR Richard Raustad, FSEC
5040 : // DATE WRITTEN December 2015
5041 : // MODIFIED na
5042 : // RE-ENGINEERED na
5043 :
5044 : // PURPOSE OF THIS SUBROUTINE:
5045 : // To calculate the part-load ratio for the FCU with varying water flow rate
5046 :
5047 : // METHODOLOGY EMPLOYED:
5048 : // Use SolveRoot to CALL this Function to converge on a solution
5049 :
5050 : // set air flow rate
5051 20562 : state.dataLoopNodes->Node(AirInNode).MassFlowRate =
5052 41124 : state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxAirMassFlow *
5053 20562 : (state.dataFanCoilUnits->FanCoil(FanCoilNum).LowSpeedRatio + (PLR * (1.0 - state.dataFanCoilUnits->FanCoil(FanCoilNum).LowSpeedRatio)));
5054 : // set water flow rate
5055 20562 : if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).CoolCoilFluidInletNode) {
5056 20562 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate =
5057 20562 : MinWaterFlow + (PLR * (state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxCoolCoilFluidFlow - MinWaterFlow));
5058 0 : } else if (WaterControlNode == state.dataFanCoilUnits->FanCoil(FanCoilNum).HeatCoilFluidInletNode) {
5059 0 : state.dataLoopNodes->Node(WaterControlNode).MassFlowRate =
5060 0 : MinWaterFlow + (PLR * (state.dataFanCoilUnits->FanCoil(FanCoilNum).MaxHeatCoilFluidFlow - MinWaterFlow));
5061 : } else {
5062 : // developer error
5063 0 : ShowFatalError(state,
5064 0 : "Developer Error - CalcFanCoilAirAndWaterFlowResidual: Water control node not found for " +
5065 0 : state.dataFanCoilUnits->FanCoil(FanCoilNum).Name);
5066 : }
5067 : Real64 QUnitOut; // delivered capacity [W]
5068 20562 : Calc4PipeFanCoil(state,
5069 : FanCoilNum,
5070 : ControlledZoneNum,
5071 : FirstHVACIteration,
5072 : QUnitOut,
5073 : PLR); // needs PLR for electric heating coil to output a specific capacity
5074 :
5075 : // Calculate residual based on output magnitude
5076 20562 : if (std::abs(QZnReq) <= 100.0) {
5077 0 : return (QUnitOut - QZnReq) / 100.0;
5078 : } else {
5079 20562 : return (QUnitOut - QZnReq) / QZnReq;
5080 : }
5081 : }
5082 :
5083 : } // namespace FanCoilUnits
5084 :
5085 2313 : } // namespace EnergyPlus
|