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/CoolingAirFlowSizing.hh>
57 : #include <EnergyPlus/Autosizing/CoolingCapacitySizing.hh>
58 : #include <EnergyPlus/Autosizing/HeatingAirFlowSizing.hh>
59 : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
60 : #include <EnergyPlus/Autosizing/SystemAirFlowSizing.hh>
61 : #include <EnergyPlus/BranchNodeConnections.hh>
62 : #include <EnergyPlus/Data/EnergyPlusData.hh>
63 : #include <EnergyPlus/DataAirSystems.hh>
64 : #include <EnergyPlus/DataContaminantBalance.hh>
65 : #include <EnergyPlus/DataEnvironment.hh>
66 : #include <EnergyPlus/DataHVACGlobals.hh>
67 : #include <EnergyPlus/DataHeatBalance.hh>
68 : #include <EnergyPlus/DataLoopNode.hh>
69 : #include <EnergyPlus/DataSizing.hh>
70 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
71 : #include <EnergyPlus/DataZoneEquipment.hh>
72 : #include <EnergyPlus/Fans.hh>
73 : #include <EnergyPlus/FluidProperties.hh>
74 : #include <EnergyPlus/General.hh>
75 : #include <EnergyPlus/GeneralRoutines.hh>
76 : #include <EnergyPlus/HVACFan.hh>
77 : #include <EnergyPlus/HVACHXAssistedCoolingCoil.hh>
78 : #include <EnergyPlus/HeatingCoils.hh>
79 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
80 : #include <EnergyPlus/NodeInputManager.hh>
81 : #include <EnergyPlus/OutAirNodeManager.hh>
82 : #include <EnergyPlus/OutputProcessor.hh>
83 : #include <EnergyPlus/PlantUtilities.hh>
84 : #include <EnergyPlus/Psychrometrics.hh>
85 : #include <EnergyPlus/ScheduleManager.hh>
86 : #include <EnergyPlus/SingleDuct.hh>
87 : #include <EnergyPlus/SteamCoils.hh>
88 : #include <EnergyPlus/UnitVentilator.hh>
89 : #include <EnergyPlus/UtilityRoutines.hh>
90 : #include <EnergyPlus/WaterCoils.hh>
91 : #include <EnergyPlus/ZonePlenum.hh>
92 :
93 : namespace EnergyPlus {
94 :
95 : namespace UnitVentilator {
96 :
97 : // Module containing the routines dealing with the Unit Ventilator
98 :
99 : // MODULE INFORMATION:
100 : // AUTHOR Rick Strand
101 : // DATE WRITTEN May 2000
102 : // MODIFIED March 2001 (addition of gas and electric coils)
103 : // October 2003 (addition of cooling coil type)
104 : // MODIFIED Bereket Nigusse, FSEC, October 2013, Added cycling fan operating mode
105 :
106 : // PURPOSE OF THIS MODULE:
107 : // To simulate unit ventilators.
108 :
109 : // METHODOLOGY EMPLOYED:
110 : // Units are modeled as a collection of components: outside air mixer,
111 : // fan, heating coil and/or cooling coil plus an integrated control
112 : // algorithm that adjusts the hot or cold water flow to meet the zone
113 : // load. Outside air mixing is handled locally as either fixed percent
114 : // or as attempting to meet a prescribed mixed air temperature.
115 :
116 : // REFERENCES:
117 : // ASHRAE Systems and Equipment Handbook (SI), 1996. pp. 31.1-31.3
118 : // Fred Buhl's fan coil module (FanCoilUnits.cc)
119 :
120 : static constexpr std::string_view fluidNameSteam("STEAM");
121 : static constexpr std::string_view fluidNameWater("WATER");
122 : static constexpr std::array<std::string_view, static_cast<int>(CoilsUsed::Num)> CoilsUsedNamesUC = {
123 : "NONE", "HEATINGANDCOOLING", "HEATING", "COOLING"};
124 : static constexpr std::array<std::string_view, static_cast<int>(OAControl::Num)> OAControlNamesUC = {
125 : "VARIABLEPERCENT", "FIXEDTEMPERATURE", "FIXEDAMOUNT"};
126 : static constexpr std::array<std::string_view, static_cast<int>(HeatCoilType::Num)> HeatCoilTypeNamesUC = {
127 : "COIL:HEATING:ELECTRIC", "COIL:HEATING:FUEL", "COIL:HEATING:WATER", "COIL:HEATING:STEAM"};
128 : static constexpr std::array<std::string_view, static_cast<int>(CoolCoilType::Num)> CoolCoilTypeNamesUC = {
129 : "COIL:COOLING:WATER", "COIL:COOLING:WATER:DETAILEDGEOMETRY", "COILSYSTEM:COOLING:WATER:HEATEXCHANGERASSISTED"};
130 :
131 165565 : void SimUnitVentilator(EnergyPlusData &state,
132 : std::string_view CompName, // name of the fan coil unit
133 : int const ZoneNum, // number of zone being served
134 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
135 : Real64 &PowerMet, // Sensible power supplied (W)
136 : Real64 &LatOutputProvided, // Latent add/removal supplied by window AC (kg/s), dehumid = negative
137 : int &CompIndex)
138 : {
139 :
140 : // SUBROUTINE INFORMATION:
141 : // AUTHOR Rick Strand
142 : // DATE WRITTEN May 2000
143 : // MODIFIED Don Shirey, Aug 2009 (LatOutputProvided)
144 :
145 : // PURPOSE OF THIS SUBROUTINE:
146 : // This is the main driver subroutine for the Unit Ventilator simulation.
147 :
148 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
149 : int UnitVentNum; // index of unit ventilator being simulated
150 :
151 165565 : if (state.dataUnitVentilators->GetUnitVentilatorInputFlag) {
152 5 : GetUnitVentilatorInput(state);
153 5 : state.dataUnitVentilators->GetUnitVentilatorInputFlag = false;
154 : }
155 :
156 : // Find the correct Unit Ventilator Equipment
157 165565 : if (CompIndex == 0) {
158 25 : UnitVentNum = UtilityRoutines::FindItemInList(CompName, state.dataUnitVentilators->UnitVent);
159 25 : if (UnitVentNum == 0) {
160 0 : ShowFatalError(state, format("SimUnitVentilator: Unit not found={}", CompName));
161 : }
162 25 : CompIndex = UnitVentNum;
163 : } else {
164 165540 : UnitVentNum = CompIndex;
165 165540 : if (UnitVentNum > state.dataUnitVentilators->NumOfUnitVents || UnitVentNum < 1) {
166 0 : ShowFatalError(state,
167 0 : format("SimUnitVentilator: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
168 : UnitVentNum,
169 0 : state.dataUnitVentilators->NumOfUnitVents,
170 0 : CompName));
171 : }
172 165540 : if (state.dataUnitVentilators->CheckEquipName(UnitVentNum)) {
173 25 : if (CompName != state.dataUnitVentilators->UnitVent(UnitVentNum).Name) {
174 0 : ShowFatalError(state,
175 0 : format("SimUnitVentilator: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
176 : UnitVentNum,
177 : CompName,
178 0 : state.dataUnitVentilators->UnitVent(UnitVentNum).Name));
179 : }
180 25 : state.dataUnitVentilators->CheckEquipName(UnitVentNum) = false;
181 : }
182 : }
183 :
184 165565 : state.dataSize->ZoneEqUnitVent = true;
185 :
186 165565 : InitUnitVentilator(state, UnitVentNum, FirstHVACIteration, ZoneNum);
187 :
188 165565 : CalcUnitVentilator(state, UnitVentNum, ZoneNum, FirstHVACIteration, PowerMet, LatOutputProvided);
189 :
190 165565 : ReportUnitVentilator(state, UnitVentNum);
191 :
192 165565 : state.dataSize->ZoneEqUnitVent = false;
193 165565 : }
194 :
195 5 : void GetUnitVentilatorInput(EnergyPlusData &state)
196 : {
197 :
198 : // SUBROUTINE INFORMATION:
199 : // AUTHOR Rick Strand
200 : // DATE WRITTEN May 2000
201 : // MODIFIED Chandan Sharma, FSEC, March 2011: Added zone sys avail manager
202 : // Bereket Nigusse, FSEC, April 2011: eliminated input node names
203 : // & added fan object type
204 :
205 : // PURPOSE OF THIS SUBROUTINE:
206 : // This subroutine obtains the input for unit ventilators and sets
207 : // up the appropriate derived type.
208 :
209 : // REFERENCES:
210 : // Fred Buhl's fan coil module (FanCoilUnits.cc)
211 :
212 : // SUBROUTINE PARAMETER DEFINITIONS:
213 : static constexpr std::string_view RoutineName("GetUnitVentilatorInput: "); // include trailing blank
214 :
215 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
216 5 : bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
217 : int IOStatus; // Used in GetObjectItem
218 : bool IsNotOK; // TRUE if there was a problem with a list name
219 : int NumFields; // Total number of fields in object
220 : int NumAlphas; // Number of Alphas for each GetObjectItem call
221 : int NumNumbers; // Number of Numbers for each GetObjectItem call
222 : bool IsValid; // Set for outside air node check
223 5 : bool errFlag(false); // interim error flag
224 10 : std::string cCoolingCoilType; // Cooling coil object type
225 10 : std::string cHeatingCoilType; // Heating coil object type
226 : int FanIndex; // index to fan used for flow checks
227 : Real64 FanVolFlow; // volumetric flow rate of fan
228 10 : Array1D_string Alphas; // Alpha items for object
229 10 : Array1D<Real64> Numbers; // Numeric items for object
230 10 : Array1D_string cAlphaFields; // Alpha field names
231 10 : Array1D_string cNumericFields; // Numeric field names
232 10 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
233 10 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
234 : bool ZoneNodeNotFound; // used in error checking
235 :
236 : // Figure out how many unit ventilators there are in the input file
237 :
238 10 : std::string CurrentModuleObject = state.dataUnitVentilators->cMO_UnitVentilator;
239 5 : state.dataUnitVentilators->NumOfUnitVents = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
240 5 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
241 :
242 5 : Alphas.allocate(NumAlphas);
243 5 : Numbers.dimension(NumNumbers, 0.0);
244 5 : cAlphaFields.allocate(NumAlphas);
245 5 : cNumericFields.allocate(NumNumbers);
246 5 : lAlphaBlanks.dimension(NumAlphas, true);
247 5 : lNumericBlanks.dimension(NumNumbers, true);
248 :
249 : // Allocate the local derived type and do one-time initializations for all parts of it
250 5 : if (state.dataUnitVentilators->NumOfUnitVents > 0) {
251 5 : state.dataUnitVentilators->UnitVent.allocate(state.dataUnitVentilators->NumOfUnitVents);
252 5 : state.dataUnitVentilators->CheckEquipName.allocate(state.dataUnitVentilators->NumOfUnitVents);
253 5 : state.dataUnitVentilators->UnitVentNumericFields.allocate(state.dataUnitVentilators->NumOfUnitVents);
254 : }
255 5 : state.dataUnitVentilators->CheckEquipName = true;
256 :
257 : // Loop over all of the unit ventilators found in the input file.
258 30 : for (int UnitVentNum = 1; UnitVentNum <= state.dataUnitVentilators->NumOfUnitVents; ++UnitVentNum) {
259 :
260 25 : auto &unitVent = state.dataUnitVentilators->UnitVent(UnitVentNum);
261 :
262 25 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
263 : CurrentModuleObject,
264 : UnitVentNum,
265 : Alphas,
266 : NumAlphas,
267 : Numbers,
268 : NumNumbers,
269 : IOStatus,
270 : lNumericBlanks,
271 : lAlphaBlanks,
272 : cAlphaFields,
273 : cNumericFields);
274 :
275 25 : state.dataUnitVentilators->UnitVentNumericFields(UnitVentNum).FieldNames.allocate(NumNumbers);
276 25 : state.dataUnitVentilators->UnitVentNumericFields(UnitVentNum).FieldNames = "";
277 25 : state.dataUnitVentilators->UnitVentNumericFields(UnitVentNum).FieldNames = cNumericFields;
278 25 : UtilityRoutines::IsNameEmpty(state, Alphas(1), CurrentModuleObject, ErrorsFound);
279 :
280 25 : unitVent.Name = Alphas(1);
281 25 : if (lAlphaBlanks(2)) {
282 0 : unitVent.SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
283 : } else {
284 25 : unitVent.SchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(2)); // convert schedule name to pointer
285 25 : if (unitVent.SchedPtr == 0) {
286 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, Alphas(1)));
287 0 : ShowContinueError(state, format("not found: {}=\"{}\".", cAlphaFields(2), Alphas(2)));
288 0 : ErrorsFound = true;
289 : }
290 : }
291 :
292 25 : unitVent.MaxAirVolFlow = Numbers(1);
293 :
294 : // Outside air information:
295 25 : unitVent.MinOutAirVolFlow = Numbers(2);
296 :
297 25 : unitVent.MinOASchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(4)); // convert schedule name to pointer
298 25 : if (unitVent.MinOASchedPtr == 0) {
299 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
300 0 : ShowContinueError(state, format("not found: {}=\"{}\".", cAlphaFields(4), Alphas(4)));
301 0 : ErrorsFound = true;
302 : }
303 :
304 25 : unitVent.OutAirVolFlow = Numbers(3);
305 25 : cCoolingCoilType = "";
306 25 : cHeatingCoilType = "";
307 :
308 : {
309 25 : unitVent.OAControlType = (OAControl)getEnumerationValue(OAControlNamesUC, Alphas(3));
310 25 : switch (unitVent.OAControlType) {
311 25 : case OAControl::VariablePercent:
312 : case OAControl::FixedAmount: {
313 25 : unitVent.MaxOASchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(5)); // convert schedule name to pointer
314 25 : if (unitVent.MaxOASchedPtr == 0) {
315 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
316 0 : ShowContinueError(state, format("not found: {}=\"{}\".", cAlphaFields(5), Alphas(5)));
317 0 : ErrorsFound = true;
318 25 : } else if (!ScheduleManager::CheckScheduleValueMinMax(state, unitVent.MaxOASchedPtr, ">=0", 0.0, "<=", 1.0)) {
319 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
320 0 : ShowContinueError(state, format("out of range [0,1]: {}=\"{}\".", cAlphaFields(5), Alphas(5)));
321 0 : ErrorsFound = true;
322 : }
323 25 : } break;
324 0 : case OAControl::FixedTemperature: {
325 0 : unitVent.TempSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(5)); // convert schedule name to pointer
326 0 : if (unitVent.TempSchedPtr == 0) {
327 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
328 0 : ShowContinueError(state, format("not found: {}=\"{}\".", cAlphaFields(5), Alphas(5)));
329 0 : ErrorsFound = true;
330 : }
331 0 : } break;
332 0 : default: {
333 0 : assert(false);
334 : } break;
335 : }
336 : }
337 :
338 : // Main air nodes (except outside air node):
339 : // For node connections, this object is both a parent and a non-parent, because the
340 : // OA mixing box is not called out as a separate component, its nodes must be connected
341 : // as ObjectIsNotParent. But for the fan and coils, the nodes are connected as ObjectIsParent
342 : // To support the diagramming tool, the unit ventilator inlet node must appear both as
343 : // an inlet to the unit ventilator parent object and as an inlet to the implied
344 : // non-parent OA mixing box within the unit ventilator.
345 : // Because there is overlap between the nodes that are parent and non-parent, use a different
346 : // object type for the non parent nodes
347 25 : unitVent.AirInNode = NodeInputManager::GetOnlySingleNode(state,
348 25 : Alphas(6),
349 : ErrorsFound,
350 : DataLoopNode::ConnectionObjectType::ZoneHVACUnitVentilator,
351 25 : Alphas(1),
352 : DataLoopNode::NodeFluidType::Air,
353 : DataLoopNode::ConnectionType::Inlet,
354 : NodeInputManager::CompFluidStream::Primary,
355 25 : DataLoopNode::ObjectIsParent);
356 25 : unitVent.AirOutNode = NodeInputManager::GetOnlySingleNode(state,
357 25 : Alphas(7),
358 : ErrorsFound,
359 : DataLoopNode::ConnectionObjectType::ZoneHVACUnitVentilator,
360 25 : Alphas(1),
361 : DataLoopNode::NodeFluidType::Air,
362 : DataLoopNode::ConnectionType::Outlet,
363 : NodeInputManager::CompFluidStream::Primary,
364 25 : DataLoopNode::ObjectIsParent);
365 :
366 : // Get AirTerminal mixer data
367 25 : SingleDuct::GetATMixer(state,
368 : unitVent.Name,
369 : unitVent.ATMixerName,
370 : unitVent.ATMixerIndex,
371 : unitVent.ATMixerType,
372 : unitVent.ATMixerPriNode,
373 : unitVent.ATMixerSecNode,
374 : unitVent.ATMixerOutNode,
375 : unitVent.AirOutNode);
376 25 : if (unitVent.ATMixerType == DataHVACGlobals::ATMixer_InletSide || unitVent.ATMixerType == DataHVACGlobals::ATMixer_SupplySide) {
377 5 : unitVent.ATMixerExists = true;
378 : }
379 25 : unitVent.ZonePtr = DataZoneEquipment::GetZoneEquipControlledZoneNum(state, DataZoneEquipment::ZoneEquip::UnitVentilator, unitVent.Name);
380 25 : if (unitVent.ZonePtr == 0) {
381 0 : ErrorsFound = true;
382 : }
383 :
384 25 : if (!unitVent.ATMixerExists) {
385 40 : unitVent.AirInNode = NodeInputManager::GetOnlySingleNode(state,
386 20 : Alphas(6),
387 : ErrorsFound,
388 : DataLoopNode::ConnectionObjectType::ZoneHVACUnitVentilator,
389 40 : Alphas(1) + "-OA MIXER",
390 : DataLoopNode::NodeFluidType::Air,
391 : DataLoopNode::ConnectionType::Inlet,
392 : NodeInputManager::CompFluidStream::Primary,
393 20 : DataLoopNode::ObjectIsNotParent);
394 : }
395 :
396 25 : unitVent.FanName = Alphas(12);
397 25 : errFlag = false;
398 25 : ValidateComponent(state, Alphas(11), unitVent.FanName, errFlag, CurrentModuleObject);
399 25 : if (errFlag) {
400 0 : ShowContinueError(state, format("specified in {} = \"{}\".", CurrentModuleObject, unitVent.Name));
401 0 : ErrorsFound = true;
402 : } else {
403 25 : if (!UtilityRoutines::SameString(Alphas(11), "Fan:SystemModel")) {
404 15 : Fans::GetFanType(state, unitVent.FanName, unitVent.FanType_Num, errFlag, CurrentModuleObject, unitVent.Name);
405 :
406 : {
407 15 : if ((BITF_TEST_ANY(BITF(unitVent.FanType_Num),
408 : BITF(DataHVACGlobals::FanType_SimpleConstVolume) | BITF(DataHVACGlobals::FanType_SimpleVAV) |
409 : BITF(DataHVACGlobals::FanType_SimpleOnOff)))) {
410 :
411 15 : if (errFlag) {
412 0 : ShowContinueError(state, format("specified in {} = \"{}\".", CurrentModuleObject, unitVent.Name));
413 0 : ErrorsFound = true;
414 : } else {
415 15 : Fans::GetFanIndex(state, unitVent.FanName, FanIndex, errFlag, CurrentModuleObject);
416 15 : if (FanIndex > 0) {
417 15 : unitVent.FanOutletNode = state.dataFans->Fan(FanIndex).OutletNodeNum;
418 15 : unitVent.FanAvailSchedPtr = state.dataFans->Fan(FanIndex).AvailSchedPtrNum; // Get the fan's availability schedule
419 15 : FanVolFlow = state.dataFans->Fan(FanIndex).MaxAirFlowRate;
420 25 : if (FanVolFlow != DataSizing::AutoSize && unitVent.MaxAirVolFlow != DataSizing::AutoSize &&
421 10 : FanVolFlow < unitVent.MaxAirVolFlow) {
422 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
423 0 : ShowContinueError(
424 : state,
425 0 : format("...air flow rate [{:.7T}] in fan object {} is less than the unit ventilator maximum "
426 : "supply air flow rate [{:.7T}].",
427 : FanVolFlow,
428 : unitVent.FanName,
429 0 : unitVent.MaxAirVolFlow));
430 0 : ShowContinueError(state,
431 : "...the fan flow rate must be greater than or equal to the unit ventilator maximum supply "
432 : "air flow rate.");
433 0 : ErrorsFound = true;
434 15 : } else if (FanVolFlow == DataSizing::AutoSize && unitVent.MaxAirVolFlow != DataSizing::AutoSize) {
435 0 : ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
436 0 : ShowContinueError(state, "...the fan flow rate is autosized while the unit ventilator flow rate is not.");
437 0 : ShowContinueError(state,
438 : "...this can lead to unexpected results where the fan flow rate is less than required.");
439 15 : } else if (FanVolFlow != DataSizing::AutoSize && unitVent.MaxAirVolFlow == DataSizing::AutoSize) {
440 0 : ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
441 0 : ShowContinueError(state, "...the unit ventilator flow rate is autosized while the fan flow rate is not.");
442 0 : ShowContinueError(state,
443 : "...this can lead to unexpected results where the fan flow rate is less than required.");
444 : }
445 : }
446 : }
447 : } else {
448 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
449 0 : ShowContinueError(state, "Fan Type must be Fan:OnOff, Fan:ConstantVolume or Fan:VariableVolume.");
450 0 : ErrorsFound = true;
451 : }
452 : }
453 10 : } else if (UtilityRoutines::SameString(Alphas(11), "Fan:SystemModel")) {
454 10 : unitVent.FanType_Num = DataHVACGlobals::FanType_SystemModelObject;
455 10 : state.dataHVACFan->fanObjs.emplace_back(new HVACFan::FanSystem(state, unitVent.FanName)); // call constructor
456 10 : unitVent.Fan_Index = HVACFan::getFanObjectVectorIndex(state, unitVent.FanName); // zero-based
457 10 : unitVent.FanOutletNode = state.dataHVACFan->fanObjs[unitVent.Fan_Index]->outletNodeNum;
458 10 : FanVolFlow = state.dataHVACFan->fanObjs[unitVent.Fan_Index]->designAirVolFlowRate;
459 10 : if (FanVolFlow != DataSizing::AutoSize && unitVent.MaxAirVolFlow != DataSizing::AutoSize && FanVolFlow < unitVent.MaxAirVolFlow) {
460 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
461 0 : ShowContinueError(
462 : state,
463 0 : format(
464 : "...air flow rate [{:.7T}] in fan object {} is less than the unit ventilator maximum supply air flow rate [{:.7T}].",
465 : FanVolFlow,
466 : unitVent.FanName,
467 0 : unitVent.MaxAirVolFlow));
468 0 : ShowContinueError(state,
469 : "...the fan flow rate must be greater than or equal to the unit ventilator maximum supply air flow rate.");
470 0 : ErrorsFound = true;
471 10 : } else if (FanVolFlow == DataSizing::AutoSize && unitVent.MaxAirVolFlow != DataSizing::AutoSize) {
472 0 : ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
473 0 : ShowContinueError(state, "...the fan flow rate is autosized while the unit ventilator flow rate is not.");
474 0 : ShowContinueError(state, "...this can lead to unexpected results where the fan flow rate is less than required.");
475 10 : } else if (FanVolFlow != DataSizing::AutoSize && unitVent.MaxAirVolFlow == DataSizing::AutoSize) {
476 0 : ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
477 0 : ShowContinueError(state, "...the unit ventilator flow rate is autosized while the fan flow rate is not.");
478 0 : ShowContinueError(state, "...this can lead to unexpected results where the fan flow rate is less than required.");
479 : }
480 10 : unitVent.FanAvailSchedPtr = state.dataHVACFan->fanObjs[unitVent.Fan_Index]->availSchedIndex;
481 : }
482 : }
483 : // For node connections, this object is both a parent and a non-parent, because the
484 : // OA mixing box is not called out as a separate component, its nodes must be connected
485 : // as ObjectIsNotParent. But for the fan and coils, the nodes are connected as ObjectIsParent
486 : // Because there is overlap between the nodes that are parent and non-parent, use a different
487 : // object type for the non parent nodes
488 : // Set connection type to 'OutdoorAir', because this is hardwired to OA conditions
489 25 : if (!unitVent.ATMixerExists) {
490 40 : unitVent.OutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
491 20 : Alphas(8),
492 : ErrorsFound,
493 : DataLoopNode::ConnectionObjectType::ZoneHVACUnitVentilator,
494 40 : Alphas(1) + "-OA MIXER",
495 : DataLoopNode::NodeFluidType::Air,
496 : DataLoopNode::ConnectionType::OutsideAirReference,
497 : NodeInputManager::CompFluidStream::Primary,
498 20 : DataLoopNode::ObjectIsNotParent);
499 20 : if (!lAlphaBlanks(8)) {
500 20 : OutAirNodeManager::CheckAndAddAirNodeNumber(state, unitVent.OutsideAirNode, IsValid);
501 20 : if (!IsValid) {
502 0 : ShowWarningError(state, format("{}{} Adding {}={}", RoutineName, CurrentModuleObject, cAlphaFields(8), Alphas(8)));
503 : }
504 : }
505 :
506 40 : unitVent.AirReliefNode = NodeInputManager::GetOnlySingleNode(state,
507 20 : Alphas(9),
508 : ErrorsFound,
509 : DataLoopNode::ConnectionObjectType::ZoneHVACUnitVentilator,
510 40 : Alphas(1) + "-OA MIXER",
511 : DataLoopNode::NodeFluidType::Air,
512 : DataLoopNode::ConnectionType::ReliefAir,
513 : NodeInputManager::CompFluidStream::Primary,
514 20 : DataLoopNode::ObjectIsNotParent);
515 :
516 40 : unitVent.OAMixerOutNode = NodeInputManager::GetOnlySingleNode(state,
517 20 : Alphas(10),
518 : ErrorsFound,
519 : DataLoopNode::ConnectionObjectType::ZoneHVACUnitVentilator,
520 40 : Alphas(1) + "-OA MIXER",
521 : DataLoopNode::NodeFluidType::Air,
522 : DataLoopNode::ConnectionType::Outlet,
523 : NodeInputManager::CompFluidStream::Primary,
524 20 : DataLoopNode::ObjectIsNotParent);
525 : } else {
526 5 : unitVent.OutsideAirNode = unitVent.ATMixerPriNode;
527 5 : unitVent.OAMixerOutNode = unitVent.ATMixerOutNode;
528 5 : if (!lAlphaBlanks(8) || !lAlphaBlanks(9) || !lAlphaBlanks(10)) {
529 0 : ShowWarningError(state, format("{}{}=\"{}\" is connected to central DOA.", RoutineName, CurrentModuleObject, unitVent.Name));
530 0 : if (!lAlphaBlanks(8)) {
531 0 : ShowContinueError(state, format("... input field {} should have been blank. Specified = {}", cAlphaFields(8), Alphas(8)));
532 : }
533 0 : if (!lAlphaBlanks(9)) {
534 0 : ShowContinueError(state, format("... input field {} should have been blank. Specified = {}", cAlphaFields(9), Alphas(9)));
535 : }
536 0 : if (!lAlphaBlanks(10)) {
537 0 : ShowContinueError(state, format("... input field {} should have been blank. Specified = {}", cAlphaFields(10), Alphas(10)));
538 : }
539 : }
540 : }
541 :
542 25 : if (unitVent.OAControlType == OAControl::FixedAmount) {
543 3 : unitVent.OutAirVolFlow = unitVent.MinOutAirVolFlow;
544 3 : unitVent.MaxOASchedPtr = unitVent.MinOASchedPtr;
545 : }
546 :
547 25 : if (!unitVent.ATMixerExists) {
548 : // Add fan to component sets array
549 60 : BranchNodeConnections::SetUpCompSets(state,
550 : CurrentModuleObject,
551 : unitVent.Name,
552 20 : Alphas(11),
553 : unitVent.FanName,
554 20 : state.dataLoopNodes->NodeID(unitVent.OAMixerOutNode),
555 20 : state.dataLoopNodes->NodeID(unitVent.FanOutletNode));
556 : } else {
557 5 : if (unitVent.ATMixerType == DataHVACGlobals::ATMixer_InletSide) {
558 : // Add fan to component sets array
559 9 : BranchNodeConnections::SetUpCompSets(state,
560 : CurrentModuleObject,
561 : unitVent.Name,
562 3 : Alphas(11),
563 : unitVent.FanName,
564 3 : state.dataLoopNodes->NodeID(unitVent.ATMixerOutNode),
565 3 : state.dataLoopNodes->NodeID(unitVent.FanOutletNode));
566 : }
567 5 : if (unitVent.ATMixerType == DataHVACGlobals::ATMixer_SupplySide) {
568 : // Add fan to component sets array
569 6 : BranchNodeConnections::SetUpCompSets(state,
570 : CurrentModuleObject,
571 : unitVent.Name,
572 2 : Alphas(11),
573 : unitVent.FanName,
574 2 : state.dataLoopNodes->NodeID(unitVent.AirInNode),
575 2 : state.dataLoopNodes->NodeID(unitVent.FanOutletNode));
576 : }
577 : }
578 :
579 25 : if (!lAlphaBlanks(19)) {
580 0 : unitVent.AvailManagerListName = Alphas(19);
581 : }
582 :
583 25 : unitVent.HVACSizingIndex = 0;
584 25 : if (!lAlphaBlanks(20)) {
585 0 : unitVent.HVACSizingIndex = UtilityRoutines::FindItemInList(Alphas(20), state.dataSize->ZoneHVACSizing);
586 0 : if (unitVent.HVACSizingIndex == 0) {
587 0 : ShowSevereError(state, cAlphaFields(20) + " = " + Alphas(20) + " not found.");
588 0 : ShowContinueError(state, format("Occurs in {} = \"{}\".", CurrentModuleObject, unitVent.Name));
589 0 : ErrorsFound = true;
590 : }
591 : }
592 :
593 25 : unitVent.CoilOption = (CoilsUsed)getEnumerationValue(CoilsUsedNamesUC, Alphas(13));
594 :
595 25 : unitVent.FanSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(14));
596 : // Default to cycling fan when fan mode schedule is not present
597 25 : if (!lAlphaBlanks(14) && unitVent.FanSchedPtr == 0) {
598 0 : ShowSevereError(state, CurrentModuleObject + " \"" + unitVent.Name + "\" " + cAlphaFields(14) + " not found: " + Alphas(14));
599 0 : ErrorsFound = true;
600 25 : } else if (lAlphaBlanks(14)) {
601 32 : if (unitVent.FanType_Num == DataHVACGlobals::FanType_SimpleOnOff ||
602 16 : unitVent.FanType_Num == DataHVACGlobals::FanType_SystemModelObject) {
603 1 : unitVent.OpMode = DataHVACGlobals::CycFanCycCoil;
604 : } else {
605 15 : unitVent.OpMode = DataHVACGlobals::ContFanCycCoil;
606 : }
607 : }
608 :
609 : // Check fan's schedule for cycling fan operation if constant volume fan is used
610 25 : if (unitVent.FanSchedPtr > 0 && unitVent.FanType_Num == DataHVACGlobals::FanType_SimpleConstVolume) {
611 0 : if (!ScheduleManager::CheckScheduleValueMinMax(state, unitVent.FanSchedPtr, ">", 0.0, "<=", 1.0)) {
612 0 : ShowSevereError(state, CurrentModuleObject + " = " + Alphas(1));
613 0 : ShowContinueError(state, format("For {} = {}", cAlphaFields(11), Alphas(11)));
614 0 : ShowContinueError(state, "Fan operating mode must be continuous (fan operating mode schedule values > 0).");
615 0 : ShowContinueError(state, format("Error found in {} = {}", cAlphaFields(14), Alphas(14)));
616 0 : ShowContinueError(state, "...schedule values must be (>0., <=1.)");
617 0 : ErrorsFound = true;
618 : }
619 : }
620 :
621 : // Get Coil information
622 25 : if (unitVent.CoilOption == CoilsUsed::Both || unitVent.CoilOption == CoilsUsed::Heating) {
623 23 : if ((!lAlphaBlanks(16))) {
624 23 : unitVent.HCoilPresent = true;
625 23 : cHeatingCoilType = Alphas(15);
626 23 : unitVent.HCoilTypeCh = cHeatingCoilType;
627 23 : unitVent.HCoilType = (HeatCoilType)getEnumerationValue(HeatCoilTypeNamesUC, cHeatingCoilType);
628 23 : unitVent.HeatingCoilType = (DataPlant::PlantEquipmentType)getEnumerationValue(DataPlant::PlantEquipTypeNamesUC, cHeatingCoilType);
629 :
630 23 : unitVent.HCoilName = Alphas(16);
631 23 : ValidateComponent(state, cHeatingCoilType, unitVent.HCoilName, IsNotOK, CurrentModuleObject);
632 23 : if (IsNotOK) {
633 0 : ShowContinueError(state, format("...specified in {} = \"{}\".", CurrentModuleObject, unitVent.Name));
634 0 : ErrorsFound = true;
635 : } else {
636 : // The heating coil control node is necessary for a hot water coil, but not necessary for electric or gas.
637 23 : if (unitVent.HCoilType == HeatCoilType::Water || unitVent.HCoilType == HeatCoilType::Steam) {
638 : // mine the hot water or steam node from the coil object
639 15 : if (unitVent.HCoilType == HeatCoilType::Water) {
640 15 : unitVent.HCoil_Index = WaterCoils::GetCompIndex(state, WaterCoils::CoilModel::HeatingSimple, unitVent.HCoilName);
641 15 : unitVent.HotControlNode = state.dataWaterCoils->WaterCoil(unitVent.HCoil_Index).WaterInletNodeNum;
642 15 : unitVent.MaxVolHotWaterFlow = state.dataWaterCoils->WaterCoil(unitVent.HCoil_Index).MaxWaterVolFlowRate;
643 : // Could probably remove MaxVolHotSteamFlow here
644 15 : unitVent.MaxVolHotSteamFlow = unitVent.MaxVolHotWaterFlow;
645 : } else {
646 0 : unitVent.HCoil_Index = SteamCoils::GetCompIndex(state, unitVent.HCoilName);
647 0 : unitVent.HotControlNode = state.dataSteamCoils->SteamCoil(unitVent.HCoil_Index).SteamInletNodeNum;
648 : // Could probably replace MaxVolHotWaterFlow here with MaxVolHotSteamFlow
649 0 : unitVent.MaxVolHotWaterFlow = state.dataSteamCoils->SteamCoil(unitVent.HCoil_Index).MaxSteamVolFlowRate;
650 : // unitVent.MaxVolHotWaterFlow =
651 : // SteamCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Steam", unitVent.HCoilName, ErrorsFound);
652 0 : unitVent.MaxVolHotSteamFlow = unitVent.MaxVolHotWaterFlow;
653 : }
654 : }
655 : }
656 :
657 23 : unitVent.HotControlOffset = Numbers(4);
658 : // Set default convergence tolerance
659 23 : if (unitVent.HotControlOffset <= 0.0) {
660 0 : unitVent.HotControlOffset = 0.001;
661 : }
662 : } else { // heating coil is required for these options
663 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
664 0 : ShowContinueError(state, format("a heating coil is required for {}=\"{}\".", cAlphaFields(13), Alphas(13)));
665 0 : ErrorsFound = true;
666 : } // IF (.NOT. lAlphaBlanks(15)) THEN - from the start of heating coil information
667 : } // is option both or heating only
668 :
669 25 : if (unitVent.CoilOption == CoilsUsed::Both || unitVent.CoilOption == CoilsUsed::Cooling) {
670 9 : if (!lAlphaBlanks(18)) {
671 9 : unitVent.CCoilPresent = true;
672 9 : errFlag = false;
673 :
674 9 : cCoolingCoilType = Alphas(17);
675 9 : unitVent.CCoilTypeCh = cCoolingCoilType;
676 9 : unitVent.CCoilType = (CoolCoilType)getEnumerationValue(CoolCoilTypeNamesUC, cCoolingCoilType);
677 9 : unitVent.CoolingCoilType = (DataPlant::PlantEquipmentType)getEnumerationValue(DataPlant::PlantEquipTypeNamesUC, cCoolingCoilType);
678 9 : unitVent.CCoilPlantName = Alphas(18);
679 :
680 9 : if (cCoolingCoilType == "COILSYSTEM:COOLING:WATER:HEATEXCHANGERASSISTED") {
681 0 : unitVent.CCoilType = CoolCoilType::HXAssisted;
682 0 : HVACHXAssistedCoolingCoil::GetHXCoilTypeAndName(
683 0 : state, cCoolingCoilType, Alphas(18), ErrorsFound, unitVent.CCoilPlantType, unitVent.CCoilPlantName);
684 0 : if (UtilityRoutines::SameString(unitVent.CCoilPlantType, "Coil:Cooling:Water")) {
685 0 : unitVent.CoolingCoilType = DataPlant::PlantEquipmentType::CoilWaterCooling;
686 0 : } else if (UtilityRoutines::SameString(unitVent.CCoilPlantType, "Coil:Cooling:Water:DetailedGeometry")) {
687 0 : unitVent.CoolingCoilType = DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling;
688 : } else {
689 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
690 0 : ShowContinueError(state, format("For: {}=\"{}\".", cAlphaFields(17), Alphas(17)));
691 0 : ShowContinueError(state, format("Invalid Coil Type={}, Name={}", unitVent.CCoilPlantType, unitVent.CCoilPlantName));
692 0 : ShowContinueError(state,
693 : "must be \"Coil:Cooling:Water\", \"Coil:Cooling:Water:DetailedGeometry\" or, "
694 : "\"CoilSystem:Cooling:Water:HeatExchangerAssisted\".");
695 0 : errFlag = true;
696 0 : ErrorsFound = true;
697 : }
698 : }
699 :
700 9 : if (!errFlag) {
701 9 : unitVent.CCoilName = Alphas(18);
702 9 : ValidateComponent(state, cCoolingCoilType, unitVent.CCoilName, IsNotOK, CurrentModuleObject);
703 9 : if (IsNotOK) {
704 0 : ShowContinueError(state, format("...specified in {} = \"{}\".", CurrentModuleObject, unitVent.Name));
705 0 : ErrorsFound = true;
706 : } else {
707 9 : if (unitVent.CCoilType != CoolCoilType::HXAssisted) {
708 9 : WaterCoils::CoilModel coilModel = WaterCoils::CoilModel::CoolingSimple;
709 9 : if (unitVent.CCoilType == CoolCoilType::Detailed) coilModel = WaterCoils::CoilModel::CoolingDetailed;
710 9 : unitVent.CCoil_Index = WaterCoils::GetCompIndex(state, coilModel, unitVent.CCoilName);
711 9 : unitVent.ColdControlNode = state.dataWaterCoils->WaterCoil(unitVent.CCoil_Index).WaterInletNodeNum;
712 9 : unitVent.MaxVolColdWaterFlow = state.dataWaterCoils->WaterCoil(unitVent.CCoil_Index).MaxWaterVolFlowRate;
713 : } else {
714 : // special case, call the parent and return the child water inlet node and water volume flow rate
715 0 : unitVent.ColdControlNode =
716 0 : HVACHXAssistedCoolingCoil::GetCoilWaterInletNode(state, unitVent.CCoilTypeCh, unitVent.CCoilName, errFlag);
717 0 : unitVent.MaxVolColdWaterFlow = HVACHXAssistedCoolingCoil::GetCoilMaxWaterFlowRate(
718 0 : state, "CoilSystem:Cooling:Water:HeatExchangerAssisted", unitVent.CCoilName, errFlag);
719 : }
720 : // Other error checks should trap before it gets to this point in the code, but including just in case.
721 9 : if (errFlag) {
722 0 : ShowContinueError(state, format("...specified in {} = \"{}\".", CurrentModuleObject, unitVent.Name));
723 0 : ErrorsFound = true;
724 : }
725 : }
726 : }
727 :
728 9 : unitVent.MinVolColdWaterFlow = 0.0;
729 9 : unitVent.ColdControlOffset = Numbers(5);
730 : // Set default convergence tolerance
731 9 : if (unitVent.ColdControlOffset <= 0.0) {
732 0 : unitVent.ColdControlOffset = 0.001;
733 : }
734 : } else { // Cooling Coil is required for this/these options
735 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
736 0 : ShowContinueError(state, format("a cooling coil is required for {}=\"{}\".", cAlphaFields(13), Alphas(13)));
737 0 : ErrorsFound = true;
738 : } // IF (.NOT. lAlphaBlanks(17)) THEN - from the start of cooling coil information
739 : }
740 25 : if (!unitVent.ATMixerExists) {
741 : // check that unit ventilator air inlet node is the same as a zone exhaust node
742 20 : ZoneNodeNotFound = true;
743 20 : for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).NumExhaustNodes; ++NodeNum) {
744 20 : if (unitVent.AirInNode == state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).ExhaustNode(NodeNum)) {
745 20 : ZoneNodeNotFound = false;
746 20 : break;
747 : }
748 : }
749 20 : if (ZoneNodeNotFound) {
750 0 : bool InletNodeFound = false;
751 0 : if (unitVent.ZonePtr > 0) {
752 0 : InletNodeFound = ZonePlenum::ValidateInducedNode(state,
753 : unitVent.AirInNode,
754 0 : state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).NumReturnNodes,
755 0 : state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).ReturnNode);
756 : }
757 0 : if (!InletNodeFound) {
758 0 : ShowSevereError(
759 : state,
760 0 : CurrentModuleObject + " = \"" + unitVent.Name +
761 : "\". Unit ventilator air inlet node name must be the same either as a zone exhaust node name or an induce "
762 : "air node in ZoePlenum.");
763 0 : ShowContinueError(state, "..Zone exhaust node name is specified in ZoneHVAC:EquipmentConnections object.");
764 0 : ShowContinueError(state, "..Induced Air Outlet Node name is specified in AirLoopHVAC:ReturnPlenum object.");
765 0 : ShowContinueError(state,
766 0 : format("..Unit ventilator unit air inlet node name = {}", state.dataLoopNodes->NodeID(unitVent.AirInNode)));
767 0 : ErrorsFound = true;
768 : }
769 : }
770 : // check that unit ventilator air outlet node is the same as a zone inlet node.
771 20 : ZoneNodeNotFound = true;
772 20 : for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).NumInletNodes; ++NodeNum) {
773 20 : if (unitVent.AirOutNode == state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).InletNode(NodeNum)) {
774 20 : ZoneNodeNotFound = false;
775 20 : break;
776 : }
777 : }
778 20 : if (ZoneNodeNotFound) {
779 0 : ShowSevereError(state,
780 0 : CurrentModuleObject + " = \"" + unitVent.Name +
781 : "\". Unit ventilator air outlet node name must be the same as a zone inlet node name.");
782 0 : ShowContinueError(state, "..Zone inlet node name is specified in ZoneHVAC:EquipmentConnections object.");
783 0 : ShowContinueError(state, format("..Unit ventilator air outlet node name = {}", state.dataLoopNodes->NodeID(unitVent.AirOutNode)));
784 0 : ErrorsFound = true;
785 : }
786 : } else {
787 5 : if (unitVent.ATMixerType == DataHVACGlobals::ATMixer_InletSide) {
788 : // check that unit ventilator air outlet node is the same as a zone inlet node.
789 3 : ZoneNodeNotFound = true;
790 3 : for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).NumInletNodes; ++NodeNum) {
791 3 : if (unitVent.AirOutNode == state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).InletNode(NodeNum)) {
792 3 : ZoneNodeNotFound = false;
793 3 : break;
794 : }
795 : }
796 3 : if (ZoneNodeNotFound) {
797 0 : ShowSevereError(state,
798 0 : CurrentModuleObject + " = \"" + unitVent.Name +
799 : "\". Unit ventilator air outlet node name must be the same as a zone inlet node name.");
800 0 : ShowContinueError(state, "..Zone inlet node name is specified in ZoneHVAC:EquipmentConnections object.");
801 0 : ShowContinueError(state,
802 0 : format("..Unit ventilator air outlet node name = {}", state.dataLoopNodes->NodeID(unitVent.AirOutNode)));
803 0 : ErrorsFound = true;
804 : }
805 :
806 : // check that the air mixer out node is the unit ventilator air inlet node
807 3 : if (unitVent.AirInNode != unitVent.ATMixerOutNode) {
808 0 : ShowSevereError(state,
809 0 : CurrentModuleObject + " = \"" + unitVent.Name +
810 : "\". unit ventilator air inlet node name must be the same as the mixer outlet node name.");
811 0 : ShowContinueError(state, "..Air terminal mixer outlet node name is specified in AirTerminal:SingleDuct:Mixer object.");
812 0 : ShowContinueError(state,
813 0 : format("..Unit ventilator air inlet node name = {}", state.dataLoopNodes->NodeID(unitVent.AirInNode)));
814 0 : ErrorsFound = true;
815 : }
816 : }
817 5 : if (unitVent.ATMixerType == DataHVACGlobals::ATMixer_SupplySide) {
818 : // check that the mixer secondary air node is the unit ventilator air outlet node
819 2 : if (unitVent.AirOutNode != unitVent.ATMixerSecNode) {
820 0 : ShowSevereError(state,
821 0 : CurrentModuleObject + " = \"" + unitVent.Name +
822 : "\". unit ventilator air outlet node name must be the same as the mixer secondary air inlet node name.");
823 0 : ShowContinueError(state, "..Air terminal mixer secondary node name is specified in AirTerminal:SingleDuct:Mixer object.");
824 0 : ShowContinueError(state,
825 0 : format("..Unit ventilator air outlet node name = {}", state.dataLoopNodes->NodeID(unitVent.AirOutNode)));
826 0 : ErrorsFound = true;
827 : }
828 :
829 : // check that air teminal mixer outlet node is the same as a zone inlet node.
830 2 : ZoneNodeNotFound = true;
831 2 : for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).NumInletNodes; ++NodeNum) {
832 2 : if (unitVent.ATMixerOutNode == state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).InletNode(NodeNum)) {
833 2 : ZoneNodeNotFound = false;
834 2 : break;
835 : }
836 : }
837 2 : if (ZoneNodeNotFound) {
838 0 : ShowSevereError(state,
839 0 : format("{} = \"{}\". Air mixer outlet node name must be the same as a zone inlet node name.",
840 : CurrentModuleObject,
841 0 : unitVent.Name));
842 0 : ShowContinueError(state, "..Zone inlet node name is specified in ZoneHVAC:EquipmentConnections object.");
843 0 : ShowContinueError(state,
844 0 : format("..Air terminal mixer outlet node name = {}", state.dataLoopNodes->NodeID(unitVent.ATMixerOutNode)));
845 0 : ErrorsFound = true;
846 : } else {
847 2 : bool ExhastNodeNotFound = true;
848 : // check exhaust node
849 2 : for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).NumExhaustNodes; ++NodeNum) {
850 2 : if (unitVent.AirInNode == state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).ExhaustNode(NodeNum)) {
851 2 : ExhastNodeNotFound = false;
852 2 : break;
853 : }
854 : }
855 : // check induce node
856 2 : if (ExhastNodeNotFound) {
857 0 : bool InletNodeFound = false;
858 0 : if (unitVent.ZonePtr > 0) {
859 0 : InletNodeFound =
860 0 : ZonePlenum::ValidateInducedNode(state,
861 : unitVent.AirInNode,
862 0 : state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).NumReturnNodes,
863 0 : state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).ReturnNode);
864 : }
865 0 : if (!InletNodeFound) {
866 0 : ShowSevereError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, unitVent.Name));
867 0 : ShowContinueError(
868 : state,
869 : "..UnitVentilator inlet node name must be the same as either a zone exhaust node name or an induced "
870 : "air node in ZonePlenum.");
871 0 : ShowContinueError(state, "..Zone exhaust node name is specified in ZoneHVAC:EquipmentConnections object.");
872 0 : ShowContinueError(state, "..Induced Air Outlet Node name is specified in AirLoopHVAC:ReturnPlenum object.");
873 0 : ShowContinueError(state,
874 0 : format("..UnitVentilator inlet node name = {}", state.dataLoopNodes->NodeID(unitVent.AirInNode)));
875 0 : ErrorsFound = true;
876 : }
877 : }
878 : }
879 : }
880 : }
881 : {
882 25 : switch (unitVent.CoilOption) {
883 9 : case CoilsUsed::Both: {
884 : // Add cooling coil to component sets array when present
885 9 : BranchNodeConnections::SetUpCompSets(state,
886 : CurrentModuleObject,
887 : unitVent.Name,
888 : cCoolingCoilType,
889 : unitVent.CCoilName,
890 9 : state.dataLoopNodes->NodeID(unitVent.FanOutletNode),
891 9 : "UNDEFINED");
892 :
893 : // Add heating coil to component sets array when cooling coil present
894 18 : BranchNodeConnections::SetUpCompSets(state,
895 : CurrentModuleObject,
896 : unitVent.Name,
897 : cHeatingCoilType,
898 : unitVent.HCoilName,
899 : "UNDEFINED",
900 18 : state.dataLoopNodes->NodeID(unitVent.AirOutNode));
901 9 : } break;
902 14 : case CoilsUsed::Heating: {
903 : // Add heating coil to component sets array when no cooling coil present
904 28 : BranchNodeConnections::SetUpCompSets(state,
905 : CurrentModuleObject,
906 : unitVent.Name,
907 : cHeatingCoilType,
908 : unitVent.HCoilName,
909 14 : state.dataLoopNodes->NodeID(unitVent.FanOutletNode),
910 14 : state.dataLoopNodes->NodeID(unitVent.AirOutNode));
911 14 : } break;
912 0 : case CoilsUsed::Cooling: {
913 : // Add cooling coil to component sets array when no heating coil present
914 0 : BranchNodeConnections::SetUpCompSets(state,
915 : CurrentModuleObject,
916 : unitVent.Name,
917 : cCoolingCoilType,
918 : unitVent.CCoilName,
919 0 : state.dataLoopNodes->NodeID(unitVent.FanOutletNode),
920 0 : state.dataLoopNodes->NodeID(unitVent.AirOutNode));
921 0 : } break;
922 2 : default: {
923 2 : } break;
924 : }
925 : }
926 : } // ...loop over all of the unit ventilators found in the input file
927 :
928 5 : Alphas.deallocate();
929 5 : Numbers.deallocate();
930 5 : cAlphaFields.deallocate();
931 5 : cNumericFields.deallocate();
932 5 : lAlphaBlanks.deallocate();
933 5 : lNumericBlanks.deallocate();
934 :
935 5 : if (ErrorsFound) ShowFatalError(state, format("{}Errors found in input.", RoutineName));
936 :
937 : // Setup Report variables for the Unit Ventilators, CurrentModuleObject='ZoneHVAC:UnitVentilator'
938 30 : for (int UnitVentNum = 1; UnitVentNum <= state.dataUnitVentilators->NumOfUnitVents; ++UnitVentNum) {
939 :
940 25 : auto &unitVent = state.dataUnitVentilators->UnitVent(UnitVentNum);
941 :
942 50 : SetupOutputVariable(state,
943 : "Zone Unit Ventilator Heating Rate",
944 : OutputProcessor::Unit::W,
945 : unitVent.HeatPower,
946 : OutputProcessor::SOVTimeStepType::System,
947 : OutputProcessor::SOVStoreType::Average,
948 25 : unitVent.Name);
949 50 : SetupOutputVariable(state,
950 : "Zone Unit Ventilator Heating Energy",
951 : OutputProcessor::Unit::J,
952 : unitVent.HeatEnergy,
953 : OutputProcessor::SOVTimeStepType::System,
954 : OutputProcessor::SOVStoreType::Summed,
955 25 : unitVent.Name);
956 50 : SetupOutputVariable(state,
957 : "Zone Unit Ventilator Total Cooling Rate",
958 : OutputProcessor::Unit::W,
959 : unitVent.TotCoolPower,
960 : OutputProcessor::SOVTimeStepType::System,
961 : OutputProcessor::SOVStoreType::Average,
962 25 : unitVent.Name);
963 50 : SetupOutputVariable(state,
964 : "Zone Unit Ventilator Total Cooling Energy",
965 : OutputProcessor::Unit::J,
966 : unitVent.TotCoolEnergy,
967 : OutputProcessor::SOVTimeStepType::System,
968 : OutputProcessor::SOVStoreType::Summed,
969 25 : unitVent.Name);
970 50 : SetupOutputVariable(state,
971 : "Zone Unit Ventilator Sensible Cooling Rate",
972 : OutputProcessor::Unit::W,
973 : unitVent.SensCoolPower,
974 : OutputProcessor::SOVTimeStepType::System,
975 : OutputProcessor::SOVStoreType::Average,
976 25 : unitVent.Name);
977 50 : SetupOutputVariable(state,
978 : "Zone Unit Ventilator Sensible Cooling Energy",
979 : OutputProcessor::Unit::J,
980 : unitVent.SensCoolEnergy,
981 : OutputProcessor::SOVTimeStepType::System,
982 : OutputProcessor::SOVStoreType::Summed,
983 25 : unitVent.Name);
984 50 : SetupOutputVariable(state,
985 : "Zone Unit Ventilator Fan Electricity Rate",
986 : OutputProcessor::Unit::W,
987 : unitVent.ElecPower,
988 : OutputProcessor::SOVTimeStepType::System,
989 : OutputProcessor::SOVStoreType::Average,
990 25 : unitVent.Name);
991 : // Note that the unit vent fan electric is NOT metered because this value is already metered through the fan component
992 50 : SetupOutputVariable(state,
993 : "Zone Unit Ventilator Fan Electricity Energy",
994 : OutputProcessor::Unit::J,
995 : unitVent.ElecEnergy,
996 : OutputProcessor::SOVTimeStepType::System,
997 : OutputProcessor::SOVStoreType::Summed,
998 25 : unitVent.Name);
999 50 : SetupOutputVariable(state,
1000 : "Zone Unit Ventilator Fan Availability Status",
1001 : OutputProcessor::Unit::None,
1002 : unitVent.AvailStatus,
1003 : OutputProcessor::SOVTimeStepType::System,
1004 : OutputProcessor::SOVStoreType::Average,
1005 25 : unitVent.Name);
1006 25 : if (unitVent.FanType_Num == DataHVACGlobals::FanType_SimpleOnOff) {
1007 0 : SetupOutputVariable(state,
1008 : "Zone Unit Ventilator Fan Part Load Ratio",
1009 : OutputProcessor::Unit::None,
1010 : unitVent.FanPartLoadRatio,
1011 : OutputProcessor::SOVTimeStepType::System,
1012 : OutputProcessor::SOVStoreType::Average,
1013 0 : unitVent.Name);
1014 : }
1015 : }
1016 :
1017 30 : for (int UnitVentNum = 1; UnitVentNum <= state.dataUnitVentilators->NumOfUnitVents; ++UnitVentNum) {
1018 :
1019 25 : auto &unitVent = state.dataUnitVentilators->UnitVent(UnitVentNum);
1020 25 : auto &coilReportObj = state.dataRptCoilSelection->coilSelectionReportObj;
1021 :
1022 25 : if (unitVent.FanType_Num == DataHVACGlobals::FanType_SystemModelObject) {
1023 10 : if (unitVent.HCoilPresent) {
1024 10 : coilReportObj->setCoilSupplyFanInfo(state,
1025 : unitVent.HCoilName,
1026 : unitVent.HCoilTypeCh,
1027 : unitVent.FanName,
1028 : DataAirSystems::ObjectVectorOOFanSystemModel,
1029 : unitVent.Fan_Index);
1030 : }
1031 10 : if (unitVent.CCoilPresent) {
1032 4 : coilReportObj->setCoilSupplyFanInfo(state,
1033 : unitVent.CCoilName,
1034 : unitVent.CCoilTypeCh,
1035 : unitVent.FanName,
1036 : DataAirSystems::ObjectVectorOOFanSystemModel,
1037 : unitVent.Fan_Index);
1038 : }
1039 : } else {
1040 15 : if (unitVent.HCoilPresent) {
1041 13 : coilReportObj->setCoilSupplyFanInfo(state,
1042 : unitVent.HCoilName,
1043 : unitVent.HCoilTypeCh,
1044 : unitVent.FanName,
1045 : DataAirSystems::StructArrayLegacyFanModels,
1046 : unitVent.Fan_Index);
1047 : }
1048 15 : if (unitVent.CCoilPresent) {
1049 5 : coilReportObj->setCoilSupplyFanInfo(state,
1050 : unitVent.CCoilName,
1051 : unitVent.CCoilTypeCh,
1052 : unitVent.FanName,
1053 : DataAirSystems::StructArrayLegacyFanModels,
1054 : unitVent.Fan_Index);
1055 : }
1056 : }
1057 : }
1058 5 : }
1059 :
1060 165565 : void InitUnitVentilator(EnergyPlusData &state,
1061 : int const UnitVentNum, // index for the current unit ventilator
1062 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
1063 : int const ZoneNum // number of zone being served
1064 : )
1065 : {
1066 :
1067 : // SUBROUTINE INFORMATION:
1068 : // AUTHOR Rick Strand
1069 : // DATE WRITTEN May 2000
1070 : // MODIFIED Chandan Sharma, FSEC, March 2011: Added zone sys avail manager
1071 :
1072 : // PURPOSE OF THIS SUBROUTINE:
1073 : // This subroutine initializes all of the data elements which are necessary
1074 : // to simulate a unit ventilator.
1075 :
1076 : // METHODOLOGY EMPLOYED:
1077 : // Uses the status flags to trigger initializations.
1078 :
1079 165565 : auto &ZoneComp = state.dataHVACGlobal->ZoneComp;
1080 165565 : auto &ZoneCompTurnFansOff = state.dataHVACGlobal->ZoneCompTurnFansOff;
1081 165565 : auto &ZoneCompTurnFansOn = state.dataHVACGlobal->ZoneCompTurnFansOn;
1082 165565 : auto &unitVent = state.dataUnitVentilators->UnitVent(UnitVentNum);
1083 :
1084 : static constexpr std::string_view RoutineName("InitUnitVentilator");
1085 :
1086 165565 : bool SetMassFlowRateToZero = false; // TRUE when mass flow rates need to be set to zero
1087 :
1088 : // Do the one time initializations
1089 165565 : if (state.dataUnitVentilators->MyOneTimeFlag) {
1090 :
1091 5 : state.dataUnitVentilators->MyEnvrnFlag.allocate(state.dataUnitVentilators->NumOfUnitVents);
1092 5 : state.dataUnitVentilators->MySizeFlag.allocate(state.dataUnitVentilators->NumOfUnitVents);
1093 5 : state.dataUnitVentilators->MyPlantScanFlag.allocate(state.dataUnitVentilators->NumOfUnitVents);
1094 5 : state.dataUnitVentilators->MyZoneEqFlag.allocate(state.dataUnitVentilators->NumOfUnitVents);
1095 5 : state.dataUnitVentilators->MyEnvrnFlag = true;
1096 5 : state.dataUnitVentilators->MySizeFlag = true;
1097 5 : state.dataUnitVentilators->MyPlantScanFlag = true;
1098 5 : state.dataUnitVentilators->MyZoneEqFlag = true;
1099 5 : state.dataUnitVentilators->MyOneTimeFlag = false;
1100 : }
1101 :
1102 165565 : if (allocated(ZoneComp)) {
1103 165565 : if (state.dataUnitVentilators->MyZoneEqFlag(UnitVentNum)) { // initialize the name of each availability manager list and zone number
1104 50 : ZoneComp(DataZoneEquipment::ZoneEquip::UnitVentilator).ZoneCompAvailMgrs(UnitVentNum).AvailManagerListName =
1105 50 : unitVent.AvailManagerListName;
1106 25 : ZoneComp(DataZoneEquipment::ZoneEquip::UnitVentilator).ZoneCompAvailMgrs(UnitVentNum).ZoneNum = ZoneNum;
1107 25 : state.dataUnitVentilators->MyZoneEqFlag(UnitVentNum) = false;
1108 : }
1109 165565 : unitVent.AvailStatus = ZoneComp(DataZoneEquipment::ZoneEquip::UnitVentilator).ZoneCompAvailMgrs(UnitVentNum).AvailStatus;
1110 : }
1111 :
1112 165565 : if (state.dataUnitVentilators->MyPlantScanFlag(UnitVentNum) && allocated(state.dataPlnt->PlantLoop)) {
1113 35 : if ((unitVent.HeatingCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) ||
1114 10 : (unitVent.HeatingCoilType == DataPlant::PlantEquipmentType::CoilSteamAirHeating)) {
1115 15 : bool errFlag = false;
1116 15 : PlantUtilities::ScanPlantLoopsForObject(
1117 : state, unitVent.HCoilName, unitVent.HeatingCoilType, unitVent.HWplantLoc, errFlag, _, _, _, _, _);
1118 15 : if (errFlag) {
1119 0 : ShowContinueError(state, format("Reference Unit=\"{}\", type=ZoneHVAC:UnitVentilator", unitVent.Name));
1120 0 : ShowFatalError(state, "InitUnitVentilator: Program terminated due to previous condition(s).");
1121 : }
1122 :
1123 15 : unitVent.HotCoilOutNodeNum = DataPlant::CompData::getPlantComponent(state, unitVent.HWplantLoc).NodeNumOut;
1124 : }
1125 41 : if ((unitVent.CoolingCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) ||
1126 16 : (unitVent.CoolingCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling)) {
1127 9 : bool errFlag = false;
1128 9 : PlantUtilities::ScanPlantLoopsForObject(
1129 : state, unitVent.CCoilPlantName, unitVent.CoolingCoilType, unitVent.CWPlantLoc, errFlag, _, _, _, _, _);
1130 9 : if (errFlag) {
1131 0 : ShowContinueError(state, format("Reference Unit=\"{}\", type=ZoneHVAC:UnitVentilator", unitVent.Name));
1132 0 : ShowFatalError(state, "InitUnitVentilator: Program terminated due to previous condition(s).");
1133 : }
1134 :
1135 9 : unitVent.ColdCoilOutNodeNum = DataPlant::CompData::getPlantComponent(state, unitVent.CWPlantLoc).NodeNumOut;
1136 : } else {
1137 16 : if (unitVent.CCoilPresent)
1138 0 : ShowFatalError(state, "InitUnitVentilator: Unit=" + unitVent.Name + ", invalid cooling coil type. Program terminated.");
1139 : }
1140 25 : state.dataUnitVentilators->MyPlantScanFlag(UnitVentNum) = false;
1141 165540 : } else if (state.dataUnitVentilators->MyPlantScanFlag(UnitVentNum) && !state.dataGlobal->AnyPlantInModel) {
1142 0 : state.dataUnitVentilators->MyPlantScanFlag(UnitVentNum) = false;
1143 : }
1144 :
1145 165565 : if (!state.dataUnitVentilators->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
1146 5 : state.dataUnitVentilators->ZoneEquipmentListChecked = true;
1147 30 : for (int Loop = 1; Loop <= state.dataUnitVentilators->NumOfUnitVents; ++Loop) {
1148 25 : if (DataZoneEquipment::CheckZoneEquipmentList(state, "ZoneHVAC:UnitVentilator", state.dataUnitVentilators->UnitVent(Loop).Name))
1149 25 : continue;
1150 0 : ShowSevereError(state,
1151 0 : "InitUnitVentilator: Unit=[UNIT VENTILATOR," + state.dataUnitVentilators->UnitVent(Loop).Name +
1152 : "] is not on any ZoneHVAC:EquipmentList. It will not be simulated.");
1153 : }
1154 : }
1155 :
1156 165590 : if (!state.dataGlobal->SysSizingCalc && state.dataUnitVentilators->MySizeFlag(UnitVentNum) &&
1157 25 : !state.dataUnitVentilators->MyPlantScanFlag(UnitVentNum)) {
1158 :
1159 25 : SizeUnitVentilator(state, UnitVentNum);
1160 :
1161 25 : state.dataUnitVentilators->MySizeFlag(UnitVentNum) = false;
1162 : }
1163 :
1164 165565 : int InNode = unitVent.AirInNode;
1165 165565 : int OutNode = unitVent.AirOutNode;
1166 165565 : int OutsideAirNode = unitVent.OutsideAirNode;
1167 165565 : int AirRelNode = unitVent.AirReliefNode;
1168 :
1169 : // Do the one time initializations
1170 165710 : if (state.dataGlobal->BeginEnvrnFlag && state.dataUnitVentilators->MyEnvrnFlag(UnitVentNum) &&
1171 145 : !state.dataUnitVentilators->MyPlantScanFlag(UnitVentNum)) {
1172 145 : Real64 RhoAir = state.dataEnvrn->StdRhoAir;
1173 :
1174 : // set the mass flow rates from the input volume flow rates
1175 145 : unitVent.MaxAirMassFlow = RhoAir * unitVent.MaxAirVolFlow;
1176 145 : unitVent.OutAirMassFlow = RhoAir * unitVent.OutAirVolFlow;
1177 145 : unitVent.MinOutAirMassFlow = RhoAir * unitVent.MinOutAirVolFlow;
1178 145 : if (unitVent.OutAirMassFlow > unitVent.MaxAirMassFlow) {
1179 0 : unitVent.OutAirMassFlow = unitVent.MaxAirMassFlow;
1180 0 : unitVent.MinOutAirMassFlow = unitVent.OutAirMassFlow * (unitVent.MinOutAirVolFlow / unitVent.OutAirVolFlow);
1181 0 : ShowWarningError(state,
1182 0 : format("Outdoor air mass flow rate higher than unit flow rate, reset to unit flow rate for {}", unitVent.Name));
1183 : }
1184 :
1185 : // set the node max and min mass flow rates
1186 145 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMax = unitVent.OutAirMassFlow;
1187 145 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMin = 0.0;
1188 :
1189 145 : state.dataLoopNodes->Node(OutNode).MassFlowRateMax = unitVent.MaxAirMassFlow;
1190 145 : state.dataLoopNodes->Node(OutNode).MassFlowRateMin = 0.0;
1191 :
1192 145 : state.dataLoopNodes->Node(InNode).MassFlowRateMax = unitVent.MaxAirMassFlow;
1193 145 : state.dataLoopNodes->Node(InNode).MassFlowRateMin = 0.0;
1194 :
1195 145 : if (unitVent.HCoilPresent) { // Only initialize these if a heating coil is actually present
1196 :
1197 135 : if (unitVent.HCoilType == HeatCoilType::Water) {
1198 :
1199 174 : Real64 rho = FluidProperties::GetDensityGlycol(state,
1200 87 : state.dataPlnt->PlantLoop(unitVent.HWplantLoc.loopNum).FluidName,
1201 : DataGlobalConstants::HWInitConvTemp,
1202 87 : state.dataPlnt->PlantLoop(unitVent.HWplantLoc.loopNum).FluidIndex,
1203 87 : RoutineName);
1204 :
1205 87 : unitVent.MaxHotWaterFlow = rho * unitVent.MaxVolHotWaterFlow;
1206 87 : unitVent.MinHotWaterFlow = rho * unitVent.MinVolHotWaterFlow;
1207 :
1208 87 : PlantUtilities::InitComponentNodes(
1209 : state, unitVent.MinHotWaterFlow, unitVent.MaxHotWaterFlow, unitVent.HotControlNode, unitVent.HotCoilOutNodeNum);
1210 : }
1211 135 : if (unitVent.HCoilType == HeatCoilType::Steam) {
1212 0 : Real64 TempSteamIn = 100.00;
1213 : Real64 SteamDensity =
1214 0 : FluidProperties::GetSatDensityRefrig(state, fluidNameSteam, TempSteamIn, 1.0, unitVent.HCoil_FluidIndex, RoutineName);
1215 0 : unitVent.MaxHotSteamFlow = SteamDensity * unitVent.MaxVolHotSteamFlow;
1216 0 : unitVent.MinHotSteamFlow = SteamDensity * unitVent.MinVolHotSteamFlow;
1217 :
1218 0 : PlantUtilities::InitComponentNodes(
1219 : state, unitVent.MinHotSteamFlow, unitVent.MaxHotSteamFlow, unitVent.HotControlNode, unitVent.HotCoilOutNodeNum);
1220 : }
1221 : } //(UnitVent(UnitVentNum)%HCoilPresent)
1222 :
1223 145 : if (unitVent.CCoilPresent) { // Only initialize these if a cooling coil is actually present
1224 106 : Real64 rho = FluidProperties::GetDensityGlycol(state,
1225 53 : state.dataPlnt->PlantLoop(unitVent.CWPlantLoc.loopNum).FluidName,
1226 : 5.0,
1227 53 : state.dataPlnt->PlantLoop(unitVent.CWPlantLoc.loopNum).FluidIndex,
1228 53 : RoutineName);
1229 :
1230 53 : unitVent.MaxColdWaterFlow = rho * unitVent.MaxVolColdWaterFlow;
1231 53 : unitVent.MinColdWaterFlow = rho * unitVent.MinVolColdWaterFlow;
1232 53 : PlantUtilities::InitComponentNodes(
1233 : state, unitVent.MinColdWaterFlow, unitVent.MaxColdWaterFlow, unitVent.ColdControlNode, unitVent.ColdCoilOutNodeNum);
1234 : }
1235 145 : state.dataUnitVentilators->MyEnvrnFlag(UnitVentNum) = false;
1236 : } // ...end start of environment inits
1237 :
1238 165565 : if (!state.dataGlobal->BeginEnvrnFlag) state.dataUnitVentilators->MyEnvrnFlag(UnitVentNum) = true;
1239 :
1240 : // These initializations are done every iteration...
1241 :
1242 165565 : state.dataUnitVentilators->QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired; // zone load needed
1243 165565 : unitVent.FanPartLoadRatio = 0.0;
1244 :
1245 165565 : if (unitVent.FanSchedPtr > 0) {
1246 58775 : if (ScheduleManager::GetCurrentScheduleValue(state, unitVent.FanSchedPtr) == 0.0) {
1247 0 : unitVent.OpMode = DataHVACGlobals::CycFanCycCoil;
1248 : } else {
1249 58775 : unitVent.OpMode = DataHVACGlobals::ContFanCycCoil;
1250 : }
1251 : }
1252 :
1253 165565 : if (ScheduleManager::GetCurrentScheduleValue(state, unitVent.SchedPtr) > 0) {
1254 165495 : if ((ScheduleManager::GetCurrentScheduleValue(state, unitVent.FanAvailSchedPtr) > 0 || ZoneCompTurnFansOn) && !ZoneCompTurnFansOff) {
1255 321902 : if ((std::abs(state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired) < DataHVACGlobals::SmallLoad) ||
1256 156407 : (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum))) {
1257 102032 : SetMassFlowRateToZero = true;
1258 : }
1259 : } else {
1260 0 : SetMassFlowRateToZero = true;
1261 : }
1262 : } else {
1263 70 : SetMassFlowRateToZero = true;
1264 : }
1265 :
1266 165565 : auto &inNode(state.dataLoopNodes->Node(InNode));
1267 165565 : auto &outNode(state.dataLoopNodes->Node(OutNode));
1268 165565 : auto &oaNode(state.dataLoopNodes->Node(OutsideAirNode));
1269 165565 : if (SetMassFlowRateToZero) {
1270 102102 : inNode.MassFlowRate = 0.0;
1271 102102 : inNode.MassFlowRateMaxAvail = 0.0;
1272 102102 : inNode.MassFlowRateMinAvail = 0.0;
1273 102102 : outNode.MassFlowRate = 0.0;
1274 102102 : outNode.MassFlowRateMaxAvail = 0.0;
1275 102102 : outNode.MassFlowRateMinAvail = 0.0;
1276 102102 : oaNode.MassFlowRate = 0.0;
1277 102102 : oaNode.MassFlowRateMaxAvail = 0.0;
1278 102102 : oaNode.MassFlowRateMinAvail = 0.0;
1279 102102 : if (!unitVent.ATMixerExists) {
1280 75957 : auto &relNode(state.dataLoopNodes->Node(AirRelNode));
1281 75957 : relNode.MassFlowRate = 0.0;
1282 75957 : relNode.MassFlowRateMaxAvail = 0.0;
1283 75957 : relNode.MassFlowRateMinAvail = 0.0;
1284 : }
1285 : } else {
1286 63463 : inNode.MassFlowRate = unitVent.MaxAirMassFlow;
1287 63463 : inNode.MassFlowRateMaxAvail = unitVent.MaxAirMassFlow;
1288 63463 : inNode.MassFlowRateMinAvail = unitVent.MaxAirMassFlow;
1289 63463 : outNode.MassFlowRate = unitVent.MaxAirMassFlow;
1290 63463 : outNode.MassFlowRateMaxAvail = unitVent.MaxAirMassFlow;
1291 63463 : outNode.MassFlowRateMinAvail = unitVent.MaxAirMassFlow;
1292 63463 : oaNode.MassFlowRate = unitVent.OutAirMassFlow;
1293 63463 : oaNode.MassFlowRateMaxAvail = unitVent.OutAirMassFlow;
1294 63463 : oaNode.MassFlowRateMinAvail = unitVent.OutAirMassFlow;
1295 63463 : if (!unitVent.ATMixerExists) {
1296 43438 : auto &relNode(state.dataLoopNodes->Node(AirRelNode));
1297 43438 : relNode.MassFlowRate = unitVent.OutAirMassFlow;
1298 43438 : relNode.MassFlowRateMaxAvail = unitVent.OutAirMassFlow;
1299 43438 : relNode.MassFlowRateMinAvail = unitVent.OutAirMassFlow;
1300 : }
1301 : }
1302 :
1303 : // Initialize the relief air (same as inlet conditions to the unit ventilator...
1304 : // Note that mass flow rates will be taken care of later.
1305 165565 : if (!unitVent.ATMixerExists) {
1306 119395 : state.dataLoopNodes->Node(AirRelNode) = state.dataLoopNodes->Node(InNode);
1307 : }
1308 165565 : state.dataUnitVentilators->OAMassFlowRate = 0.0;
1309 :
1310 : // Just in case the unit is off and conditions do not get sent through
1311 : // the unit for some reason, set the outlet conditions equal to the inlet
1312 : // conditions of the unit ventilator
1313 165565 : outNode.Temp = inNode.Temp;
1314 165565 : outNode.Press = inNode.Press;
1315 165565 : outNode.HumRat = inNode.HumRat;
1316 165565 : outNode.Enthalpy = inNode.Enthalpy;
1317 :
1318 : // These initializations only need to be done once at the start of the iterations...
1319 165565 : if (FirstHVACIteration) {
1320 : // Initialize the outside air conditions...
1321 76855 : if (!unitVent.ATMixerExists) {
1322 59760 : state.dataLoopNodes->Node(OutsideAirNode).Temp = state.dataLoopNodes->Node(OutsideAirNode).OutAirDryBulb;
1323 : }
1324 : }
1325 165565 : }
1326 :
1327 25 : void SizeUnitVentilator(EnergyPlusData &state, int const UnitVentNum)
1328 : {
1329 :
1330 : // SUBROUTINE INFORMATION:
1331 : // AUTHOR Fred Buhl
1332 : // DATE WRITTEN February 2002
1333 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
1334 : // July 2014, B. Nigusse, added scalable sizing
1335 :
1336 : // PURPOSE OF THIS SUBROUTINE:
1337 : // This subroutine is for sizing Unit Ventilator components for which flow rates have not been
1338 : // specified in the input.
1339 :
1340 : // METHODOLOGY EMPLOYED:
1341 : // Obtains flow rates from the zone sizing arrays and plant sizing data.
1342 :
1343 25 : auto &unitVent = state.dataUnitVentilators->UnitVent(UnitVentNum);
1344 25 : auto &ZoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
1345 :
1346 : // SUBROUTINE PARAMETER DEFINITIONS:
1347 : static constexpr std::string_view RoutineName("SizeUnitVentilator");
1348 :
1349 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1350 25 : int PltSizCoolNum = 0; // index of plant sizing object for 1st cooling loop
1351 25 : Real64 DesCoolingLoad = 0.0;
1352 25 : Real64 DesHeatingLoad = 0.0;
1353 25 : Real64 TempSteamIn = 0.0;
1354 25 : Real64 EnthSteamInDry = 0.0;
1355 25 : Real64 EnthSteamOutWet = 0.0;
1356 25 : Real64 LatentHeatSteam = 0.0;
1357 25 : Real64 SteamDensity = 0.0;
1358 25 : int CoilWaterOutletNode = 0;
1359 25 : int CoilSteamOutletNode = 0;
1360 50 : std::string CoolingCoilName;
1361 50 : std::string CoolingCoilType;
1362 25 : Real64 rho = 0.0;
1363 25 : Real64 Cp = 0.0;
1364 :
1365 : Real64 TempSize; // autosized value of coil input field
1366 : int SizingMethod; // Integer representation of sizing method name (e.g., CoolingAirflowSizing, HeatingAirflowSizing, CoolingCapacitySizing,
1367 : // HeatingCapacitySizing, etc.)
1368 : bool PrintFlag; // TRUE when sizing information is reported in the eio file
1369 25 : int SAFMethod(0); // supply air flow rate sizing method (SupplyAirFlowRate, FlowPerFloorArea, FractionOfAutosizedCoolingAirflow,
1370 : // FractionOfAutosizedHeatingAirflow ...)
1371 25 : int CapSizingMethod(0); // capacity sizing methods (HeatingDesignCapacity, CapacityPerFloorArea, FractionOfAutosizedCoolingCapacity, and
1372 : // FractionOfAutosizedHeatingCapacity )
1373 : Real64 WaterCoilSizDeltaT; // water coil deltaT for design water flow rate autosizing
1374 :
1375 25 : int PltSizHeatNum = 0;
1376 25 : bool ErrorsFound = false;
1377 25 : bool IsAutoSize = false;
1378 25 : Real64 OutAirVolFlowDes = 0.0;
1379 25 : Real64 OutAirVolFlowUser = 0.0;
1380 25 : Real64 MinOutAirVolFlowDes = 0.0;
1381 25 : Real64 MinOutAirVolFlowUser = 0.0;
1382 25 : Real64 MaxVolHotWaterFlowDes = 0.0;
1383 25 : Real64 MaxVolHotWaterFlowUser = 0.0;
1384 25 : Real64 MaxVolHotSteamFlowDes = 0.0;
1385 25 : Real64 MaxVolHotSteamFlowUser = 0.0;
1386 25 : Real64 MaxVolColdWaterFlowDes = 0.0;
1387 25 : Real64 MaxVolColdWaterFlowUser = 0.0;
1388 25 : Real64 CoolingAirVolFlowScalable = 0.0;
1389 25 : Real64 HeatingAirVolFlowScalable = 0.0;
1390 25 : state.dataSize->DataScalableSizingON = false;
1391 25 : state.dataSize->DataScalableCapSizingON = false;
1392 50 : std::string CompType = state.dataUnitVentilators->cMO_UnitVentilator;
1393 50 : std::string CompName = unitVent.Name;
1394 25 : state.dataSize->DataZoneNumber = unitVent.ZonePtr;
1395 25 : bool DoWaterCoilSizing = false;
1396 :
1397 25 : if (unitVent.FanType_Num == DataHVACGlobals::FanType_SystemModelObject) {
1398 10 : state.dataSize->DataFanEnumType = DataAirSystems::ObjectVectorOOFanSystemModel;
1399 : } else {
1400 15 : state.dataSize->DataFanEnumType = DataAirSystems::StructArrayLegacyFanModels;
1401 : }
1402 25 : state.dataSize->DataFanIndex = unitVent.Fan_Index;
1403 : // unit ventilator is always blow thru
1404 25 : state.dataSize->DataFanPlacement = DataSizing::ZoneFanPlacement::BlowThru;
1405 :
1406 25 : state.dataSize->ZoneCoolingOnlyFan = (unitVent.CoilOption == CoilsUsed::Both) || (unitVent.CoilOption == CoilsUsed::Cooling);
1407 25 : state.dataSize->ZoneHeatingOnlyFan = (unitVent.CoilOption == CoilsUsed::Both) || (unitVent.CoilOption == CoilsUsed::Heating);
1408 :
1409 25 : if (state.dataSize->CurZoneEqNum > 0) {
1410 25 : if (unitVent.HVACSizingIndex > 0) {
1411 0 : auto &zoneHVACSizing = state.dataSize->ZoneHVACSizing(unitVent.HVACSizingIndex);
1412 :
1413 : // initialize OA flow for sizing other inputs (e.g., inlet temp, capacity, etc.)
1414 0 : if (unitVent.OutAirVolFlow == DataSizing::AutoSize) {
1415 0 : ZoneEqSizing.OAVolFlow = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
1416 : } else {
1417 0 : ZoneEqSizing.OAVolFlow = unitVent.OutAirVolFlow;
1418 : }
1419 0 : if (unitVent.ATMixerExists) { // set up ATMixer conditions for scalable capacity sizing
1420 0 : ZoneEqSizing.OAVolFlow = 0.0; // Equipment OA flow should always be 0 when ATMixer is used
1421 0 : SingleDuct::setATMixerSizingProperties(state, unitVent.ATMixerIndex, unitVent.ZonePtr, state.dataSize->CurZoneEqNum);
1422 : }
1423 :
1424 : // N1 , \field Maximum Supply Air Flow Rate
1425 0 : PrintFlag = true;
1426 :
1427 0 : if (zoneHVACSizing.CoolingSAFMethod > 0 && state.dataSize->ZoneCoolingOnlyFan && !state.dataSize->ZoneHeatingOnlyFan) {
1428 :
1429 0 : SAFMethod = zoneHVACSizing.CoolingSAFMethod;
1430 0 : SizingMethod = DataHVACGlobals::CoolingAirflowSizing;
1431 0 : ZoneEqSizing.SizingMethod(SizingMethod) = SAFMethod;
1432 0 : switch (SAFMethod) {
1433 0 : case DataSizing::None:
1434 : case DataSizing::SupplyAirFlowRate:
1435 : case DataSizing::FlowPerFloorArea:
1436 : case DataSizing::FractionOfAutosizedCoolingAirflow: {
1437 0 : switch (SAFMethod) {
1438 0 : case DataSizing::SupplyAirFlowRate: {
1439 0 : if (zoneHVACSizing.MaxCoolAirVolFlow > 0.0) {
1440 0 : ZoneEqSizing.AirVolFlow = zoneHVACSizing.MaxCoolAirVolFlow;
1441 0 : ZoneEqSizing.SystemAirFlow = true;
1442 : }
1443 0 : TempSize = zoneHVACSizing.MaxCoolAirVolFlow;
1444 0 : } break;
1445 0 : case DataSizing::FlowPerFloorArea: {
1446 0 : ZoneEqSizing.SystemAirFlow = true;
1447 0 : ZoneEqSizing.AirVolFlow =
1448 0 : zoneHVACSizing.MaxCoolAirVolFlow * state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
1449 0 : TempSize = ZoneEqSizing.AirVolFlow;
1450 0 : state.dataSize->DataScalableSizingON = true;
1451 0 : } break;
1452 0 : case DataSizing::FractionOfAutosizedCoolingAirflow: {
1453 0 : state.dataSize->DataFracOfAutosizedCoolingAirflow = zoneHVACSizing.MaxCoolAirVolFlow;
1454 0 : TempSize = DataSizing::AutoSize;
1455 0 : state.dataSize->DataScalableSizingON = true;
1456 0 : } break;
1457 0 : default: {
1458 0 : TempSize = zoneHVACSizing.MaxCoolAirVolFlow;
1459 0 : } break;
1460 : }
1461 0 : bool errorsFound = false;
1462 0 : CoolingAirFlowSizer sizingCoolingAirFlow;
1463 0 : sizingCoolingAirFlow.overrideSizingString(state.dataGlobal->isEpJSON ? "maximum_supply_air_flow_rate [m3/s]"
1464 : : "Maximum Supply Air Flow Rate [m3/s]");
1465 : // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1466 0 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1467 0 : CoolingAirVolFlowScalable = sizingCoolingAirFlow.size(state, TempSize, errorsFound);
1468 0 : } break;
1469 0 : case DataSizing::FlowPerCoolingCapacity: {
1470 0 : SizingMethod = DataHVACGlobals::CoolingCapacitySizing;
1471 0 : TempSize = DataSizing::AutoSize;
1472 0 : PrintFlag = false;
1473 0 : state.dataSize->DataScalableSizingON = true;
1474 0 : state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
1475 0 : CoolingCapacitySizer sizerCoolingCapacity;
1476 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1477 0 : state.dataSize->DataAutosizedCoolingCapacity = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
1478 0 : state.dataSize->DataFlowPerCoolingCapacity = zoneHVACSizing.MaxCoolAirVolFlow;
1479 0 : PrintFlag = true;
1480 0 : TempSize = DataSizing::AutoSize;
1481 0 : bool errorsFound = false;
1482 0 : CoolingAirFlowSizer sizingCoolingAirFlow;
1483 0 : sizingCoolingAirFlow.overrideSizingString(state.dataGlobal->isEpJSON ? "maximum_supply_air_flow_rate [m3/s]"
1484 : : "Maximum Supply Air Flow Rate [m3/s]");
1485 : // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1486 0 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1487 0 : CoolingAirVolFlowScalable = sizingCoolingAirFlow.size(state, TempSize, errorsFound);
1488 0 : } break;
1489 0 : default: {
1490 0 : } break;
1491 : }
1492 : // DataScalableSizingON = false;
1493 :
1494 0 : } else if (zoneHVACSizing.HeatingSAFMethod > 0 && state.dataSize->ZoneHeatingOnlyFan && !state.dataSize->ZoneCoolingOnlyFan) {
1495 0 : SizingMethod = DataHVACGlobals::HeatingAirflowSizing;
1496 0 : SAFMethod = zoneHVACSizing.HeatingSAFMethod;
1497 0 : ZoneEqSizing.SizingMethod(SizingMethod) = SAFMethod;
1498 0 : switch (SAFMethod) {
1499 0 : case DataSizing::None:
1500 : case DataSizing::SupplyAirFlowRate:
1501 : case DataSizing::FlowPerFloorArea:
1502 : case DataSizing::FractionOfAutosizedHeatingAirflow: {
1503 0 : switch (SAFMethod) {
1504 0 : case DataSizing::SupplyAirFlowRate: {
1505 0 : if (zoneHVACSizing.MaxHeatAirVolFlow > 0.0) {
1506 0 : ZoneEqSizing.AirVolFlow = zoneHVACSizing.MaxHeatAirVolFlow;
1507 0 : ZoneEqSizing.SystemAirFlow = true;
1508 : }
1509 0 : TempSize = zoneHVACSizing.MaxHeatAirVolFlow;
1510 0 : } break;
1511 0 : case DataSizing::FlowPerFloorArea: {
1512 0 : ZoneEqSizing.SystemAirFlow = true;
1513 0 : ZoneEqSizing.AirVolFlow =
1514 0 : zoneHVACSizing.MaxHeatAirVolFlow * state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
1515 0 : TempSize = ZoneEqSizing.AirVolFlow;
1516 0 : state.dataSize->DataScalableSizingON = true;
1517 0 : } break;
1518 0 : case DataSizing::FractionOfAutosizedHeatingAirflow: {
1519 0 : state.dataSize->DataFracOfAutosizedHeatingAirflow = zoneHVACSizing.MaxHeatAirVolFlow;
1520 0 : TempSize = DataSizing::AutoSize;
1521 0 : state.dataSize->DataScalableSizingON = true;
1522 0 : } break;
1523 0 : default: {
1524 0 : TempSize = zoneHVACSizing.MaxHeatAirVolFlow;
1525 0 : } break;
1526 : }
1527 0 : bool errorsFound = false;
1528 0 : HeatingAirFlowSizer sizingHeatingAirFlow;
1529 0 : sizingHeatingAirFlow.overrideSizingString(state.dataGlobal->isEpJSON ? "maximum_supply_air_flow_rate [m3/s]"
1530 : : "Maximum Supply Air Flow Rate [m3/s]");
1531 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1532 0 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1533 0 : HeatingAirVolFlowScalable = sizingHeatingAirFlow.size(state, TempSize, errorsFound);
1534 0 : } break;
1535 0 : case DataSizing::FlowPerHeatingCapacity: {
1536 0 : SizingMethod = DataHVACGlobals::HeatingCapacitySizing;
1537 0 : TempSize = DataSizing::AutoSize;
1538 0 : PrintFlag = false;
1539 0 : state.dataSize->DataScalableSizingON = true;
1540 0 : state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
1541 0 : bool errorsFound = false;
1542 0 : HeatingCapacitySizer sizerHeatingCapacity;
1543 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1544 0 : state.dataSize->DataAutosizedHeatingCapacity = sizerHeatingCapacity.size(state, TempSize, errorsFound);
1545 0 : state.dataSize->DataFlowPerHeatingCapacity = zoneHVACSizing.MaxHeatAirVolFlow;
1546 0 : SizingMethod = DataHVACGlobals::HeatingAirflowSizing;
1547 0 : PrintFlag = true;
1548 0 : TempSize = DataSizing::AutoSize;
1549 0 : errorsFound = false;
1550 0 : HeatingAirFlowSizer sizingHeatingAirFlow;
1551 0 : sizingHeatingAirFlow.overrideSizingString(state.dataGlobal->isEpJSON ? "maximum_supply_air_flow_rate [m3/s]"
1552 : : "Maximum Supply Air Flow Rate [m3/s]");
1553 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1554 0 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1555 0 : HeatingAirVolFlowScalable = sizingHeatingAirFlow.size(state, TempSize, errorsFound);
1556 0 : } break;
1557 0 : default: {
1558 0 : } break;
1559 : }
1560 : // DataScalableSizingON = false;
1561 : } else {
1562 :
1563 0 : if (unitVent.CoilOption != CoilsUsed::None) {
1564 0 : if (zoneHVACSizing.CoolingSAFMethod > 0) {
1565 0 : SAFMethod = zoneHVACSizing.CoolingSAFMethod;
1566 0 : SizingMethod = DataHVACGlobals::CoolingAirflowSizing;
1567 0 : ZoneEqSizing.SizingMethod(SizingMethod) = SAFMethod;
1568 0 : switch (SAFMethod) {
1569 0 : case DataSizing::None:
1570 : case DataSizing::SupplyAirFlowRate:
1571 : case DataSizing::FlowPerFloorArea:
1572 : case DataSizing::FractionOfAutosizedCoolingAirflow: {
1573 0 : switch (SAFMethod) {
1574 0 : case DataSizing::SupplyAirFlowRate: {
1575 0 : if (zoneHVACSizing.MaxCoolAirVolFlow > 0.0) {
1576 0 : ZoneEqSizing.AirVolFlow = zoneHVACSizing.MaxCoolAirVolFlow;
1577 0 : ZoneEqSizing.SystemAirFlow = true;
1578 : }
1579 0 : TempSize = zoneHVACSizing.MaxCoolAirVolFlow;
1580 0 : } break;
1581 0 : case DataSizing::FlowPerFloorArea: {
1582 0 : ZoneEqSizing.SystemAirFlow = true;
1583 0 : ZoneEqSizing.AirVolFlow =
1584 0 : zoneHVACSizing.MaxCoolAirVolFlow * state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
1585 0 : TempSize = ZoneEqSizing.AirVolFlow;
1586 0 : state.dataSize->DataScalableSizingON = true;
1587 0 : } break;
1588 0 : case DataSizing::FractionOfAutosizedCoolingAirflow: {
1589 0 : state.dataSize->DataFracOfAutosizedCoolingAirflow = zoneHVACSizing.MaxCoolAirVolFlow;
1590 0 : TempSize = DataSizing::AutoSize;
1591 0 : state.dataSize->DataScalableSizingON = true;
1592 0 : } break;
1593 0 : default: {
1594 0 : TempSize = zoneHVACSizing.MaxCoolAirVolFlow;
1595 0 : } break;
1596 : }
1597 0 : bool errorsFound = false;
1598 0 : CoolingAirFlowSizer sizingCoolingAirFlow;
1599 0 : sizingCoolingAirFlow.overrideSizingString(state.dataGlobal->isEpJSON ? "maximum_supply_air_flow_rate [m3/s]"
1600 : : "Maximum Supply Air Flow Rate [m3/s]");
1601 : // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1602 0 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1603 0 : CoolingAirVolFlowScalable = sizingCoolingAirFlow.size(state, TempSize, errorsFound);
1604 0 : } break;
1605 0 : case DataSizing::FlowPerCoolingCapacity: {
1606 0 : SizingMethod = DataHVACGlobals::CoolingCapacitySizing;
1607 0 : TempSize = DataSizing::AutoSize;
1608 0 : PrintFlag = false;
1609 0 : state.dataSize->DataScalableSizingON = true;
1610 0 : state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
1611 0 : CoolingCapacitySizer sizerCoolingCapacity;
1612 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1613 0 : state.dataSize->DataAutosizedCoolingCapacity = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
1614 0 : state.dataSize->DataFlowPerCoolingCapacity = zoneHVACSizing.MaxCoolAirVolFlow;
1615 0 : PrintFlag = true;
1616 0 : TempSize = DataSizing::AutoSize;
1617 0 : bool errorsFound = false;
1618 0 : CoolingAirFlowSizer sizingCoolingAirFlow;
1619 0 : sizingCoolingAirFlow.overrideSizingString(state.dataGlobal->isEpJSON ? "maximum_supply_air_flow_rate [m3/s]"
1620 : : "Maximum Supply Air Flow Rate [m3/s]");
1621 : // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1622 0 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1623 0 : CoolingAirVolFlowScalable = sizingCoolingAirFlow.size(state, TempSize, errorsFound);
1624 0 : } break;
1625 0 : default: {
1626 0 : } break;
1627 : }
1628 0 : } else if (zoneHVACSizing.HeatingSAFMethod > 0) {
1629 0 : SizingMethod = DataHVACGlobals::HeatingAirflowSizing;
1630 0 : SAFMethod = zoneHVACSizing.HeatingSAFMethod;
1631 0 : ZoneEqSizing.SizingMethod(SizingMethod) = SAFMethod;
1632 0 : switch (SAFMethod) {
1633 0 : case DataSizing::None:
1634 : case DataSizing::SupplyAirFlowRate:
1635 : case DataSizing::FlowPerFloorArea:
1636 : case DataSizing::FractionOfAutosizedHeatingAirflow: {
1637 0 : switch (SAFMethod) {
1638 0 : case DataSizing::SupplyAirFlowRate: {
1639 0 : if (zoneHVACSizing.MaxHeatAirVolFlow > 0.0) {
1640 0 : ZoneEqSizing.AirVolFlow = zoneHVACSizing.MaxHeatAirVolFlow;
1641 0 : ZoneEqSizing.SystemAirFlow = true;
1642 : }
1643 0 : TempSize = zoneHVACSizing.MaxHeatAirVolFlow;
1644 0 : } break;
1645 0 : case DataSizing::FlowPerFloorArea: {
1646 0 : ZoneEqSizing.SystemAirFlow = true;
1647 0 : ZoneEqSizing.AirVolFlow =
1648 0 : zoneHVACSizing.MaxHeatAirVolFlow * state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
1649 0 : TempSize = ZoneEqSizing.AirVolFlow;
1650 0 : state.dataSize->DataScalableSizingON = true;
1651 0 : } break;
1652 0 : case DataSizing::FractionOfAutosizedHeatingAirflow: {
1653 0 : state.dataSize->DataFracOfAutosizedHeatingAirflow = zoneHVACSizing.MaxHeatAirVolFlow;
1654 0 : TempSize = DataSizing::AutoSize;
1655 0 : state.dataSize->DataScalableSizingON = true;
1656 0 : } break;
1657 0 : default: {
1658 0 : TempSize = zoneHVACSizing.MaxHeatAirVolFlow;
1659 0 : } break;
1660 : }
1661 0 : bool errorsFound = false;
1662 0 : HeatingAirFlowSizer sizingHeatingAirFlow;
1663 0 : sizingHeatingAirFlow.overrideSizingString(state.dataGlobal->isEpJSON ? "maximum_supply_air_flow_rate [m3/s]"
1664 : : "Maximum Supply Air Flow Rate [m3/s]");
1665 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1666 0 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1667 0 : HeatingAirVolFlowScalable = sizingHeatingAirFlow.size(state, TempSize, errorsFound);
1668 0 : } break;
1669 0 : case DataSizing::FlowPerHeatingCapacity: {
1670 0 : SizingMethod = DataHVACGlobals::HeatingCapacitySizing;
1671 0 : TempSize = DataSizing::AutoSize;
1672 0 : PrintFlag = false;
1673 0 : state.dataSize->DataScalableSizingON = true;
1674 0 : state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
1675 0 : bool errorsFound = false;
1676 0 : HeatingCapacitySizer sizerHeatingCapacity;
1677 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1678 0 : state.dataSize->DataAutosizedHeatingCapacity = sizerHeatingCapacity.size(state, TempSize, errorsFound);
1679 0 : state.dataSize->DataFlowPerHeatingCapacity = zoneHVACSizing.MaxHeatAirVolFlow;
1680 0 : SizingMethod = DataHVACGlobals::HeatingAirflowSizing;
1681 0 : PrintFlag = true;
1682 0 : TempSize = DataSizing::AutoSize;
1683 0 : errorsFound = false;
1684 0 : HeatingAirFlowSizer sizingHeatingAirFlow;
1685 0 : sizingHeatingAirFlow.overrideSizingString(state.dataGlobal->isEpJSON ? "maximum_supply_air_flow_rate [m3/s]"
1686 : : "Maximum Supply Air Flow Rate [m3/s]");
1687 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1688 0 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1689 0 : HeatingAirVolFlowScalable = sizingHeatingAirFlow.size(state, TempSize, errorsFound);
1690 0 : } break;
1691 0 : default: {
1692 0 : } break;
1693 : }
1694 : }
1695 : // DataScalableSizingON = false;
1696 : } else { // if (unitVent.CoilOption != CoilsUsed::None)
1697 :
1698 0 : PrintFlag = true;
1699 0 : if (unitVent.MaxAirVolFlow == DataSizing::AutoSize) {
1700 0 : TempSize = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
1701 : } else {
1702 0 : TempSize = unitVent.MaxAirVolFlow;
1703 : }
1704 0 : bool errorsFound = false;
1705 0 : SystemAirFlowSizer sizerSystemAirFlow;
1706 : // sizerSystemAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1707 0 : sizerSystemAirFlow.overrideSizingString(state.dataGlobal->isEpJSON ? "maximum_supply_air_flow_rate [m3/s]"
1708 : : "Maximum Supply Air Flow Rate [m3/s]");
1709 0 : sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1710 0 : HeatingAirVolFlowScalable = sizerSystemAirFlow.size(state, TempSize, errorsFound);
1711 : }
1712 : }
1713 :
1714 0 : unitVent.MaxAirVolFlow = max(CoolingAirVolFlowScalable, HeatingAirVolFlowScalable);
1715 :
1716 : } else {
1717 : // no scalble sizing method has been specified. Sizing proceeds using the method specified in the zoneHVAC object
1718 : // N1 , \field Maximum Supply Air Flow Rate
1719 25 : PrintFlag = true;
1720 25 : if (unitVent.CoilOption == CoilsUsed::None) {
1721 :
1722 2 : if (unitVent.MaxAirVolFlow == DataSizing::AutoSize) {
1723 0 : TempSize = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
1724 : } else {
1725 2 : TempSize = unitVent.MaxAirVolFlow;
1726 : }
1727 :
1728 : } else {
1729 23 : TempSize = unitVent.MaxAirVolFlow;
1730 : }
1731 25 : bool errorsFound = false;
1732 50 : SystemAirFlowSizer sizerSystemAirFlow;
1733 : // sizerSystemAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1734 25 : sizerSystemAirFlow.overrideSizingString(state.dataGlobal->isEpJSON ? "maximum_supply_air_flow_rate [m3/s]"
1735 : : "Maximum Supply Air Flow Rate [m3/s]");
1736 25 : sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1737 25 : unitVent.MaxAirVolFlow = sizerSystemAirFlow.size(state, TempSize, errorsFound);
1738 : }
1739 : }
1740 :
1741 25 : IsAutoSize = false;
1742 25 : if (unitVent.OutAirVolFlow == DataSizing::AutoSize) {
1743 15 : IsAutoSize = true;
1744 : }
1745 25 : if (state.dataSize->CurZoneEqNum > 0) {
1746 25 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
1747 10 : if (unitVent.OutAirVolFlow > 0.0) {
1748 30 : BaseSizer::reportSizerOutput(state,
1749 10 : state.dataUnitVentilators->cMO_UnitVentilator,
1750 : unitVent.Name,
1751 : "User-Specified Maximum Outdoor Air Flow Rate [m3/s]",
1752 10 : unitVent.OutAirVolFlow);
1753 : }
1754 : } else {
1755 15 : CheckZoneSizing(state, state.dataUnitVentilators->cMO_UnitVentilator, unitVent.Name);
1756 15 : if (unitVent.OAControlType == OAControl::FixedAmount) {
1757 0 : OutAirVolFlowDes = min(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA, unitVent.MaxAirVolFlow);
1758 : } else {
1759 15 : OutAirVolFlowDes = unitVent.MaxAirVolFlow;
1760 : }
1761 :
1762 15 : if (IsAutoSize) {
1763 15 : unitVent.OutAirVolFlow = OutAirVolFlowDes;
1764 45 : BaseSizer::reportSizerOutput(state,
1765 15 : state.dataUnitVentilators->cMO_UnitVentilator,
1766 : unitVent.Name,
1767 : "Design Size Maximum Outdoor Air Flow Rate [m3/s]",
1768 15 : OutAirVolFlowDes);
1769 : } else {
1770 0 : if (unitVent.OutAirVolFlow > 0.0 && OutAirVolFlowDes > 0.0) {
1771 0 : OutAirVolFlowUser = unitVent.OutAirVolFlow;
1772 0 : BaseSizer::reportSizerOutput(state,
1773 0 : state.dataUnitVentilators->cMO_UnitVentilator,
1774 : unitVent.Name,
1775 : "Design Size Maximum Outdoor Air Flow Rate [m3/s]",
1776 : OutAirVolFlowDes,
1777 : "User-Specified Maximum Outdoor Air Flow Rate [m3/s]",
1778 0 : OutAirVolFlowUser);
1779 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1780 0 : if ((std::abs(OutAirVolFlowDes - OutAirVolFlowUser) / OutAirVolFlowUser) > state.dataSize->AutoVsHardSizingThreshold) {
1781 0 : ShowMessage(state,
1782 0 : "SizeUnitVentilator: Potential issue with equipment sizing for " +
1783 0 : state.dataUnitVentilators->cMO_UnitVentilator + ' ' + unitVent.Name);
1784 0 : ShowContinueError(state, format("User-Specified Maximum Outdoor Air Flow Rate of {:.5R} [m3/s]", OutAirVolFlowUser));
1785 0 : ShowContinueError(
1786 0 : state, format("differs from Design Size Maximum Outdoor Air Flow Rate of {:.5R} [m3/s]", OutAirVolFlowDes));
1787 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1788 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1789 : }
1790 : }
1791 : }
1792 : }
1793 : }
1794 25 : ZoneEqSizing.OAVolFlow = unitVent.OutAirVolFlow;
1795 :
1796 25 : if (unitVent.ATMixerExists) { // set up ATMixer conditions for use in component sizing
1797 5 : ZoneEqSizing.OAVolFlow = 0.0; // Equipment OA flow should always be 0 when ATMixer is used
1798 5 : SingleDuct::setATMixerSizingProperties(state, unitVent.ATMixerIndex, unitVent.ZonePtr, state.dataSize->CurZoneEqNum);
1799 : }
1800 : }
1801 :
1802 25 : IsAutoSize = false;
1803 25 : if (unitVent.MinOutAirVolFlow == DataSizing::AutoSize) {
1804 15 : IsAutoSize = true;
1805 : }
1806 25 : if (state.dataSize->CurZoneEqNum > 0) {
1807 25 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
1808 10 : if (unitVent.MinOutAirVolFlow > 0.0) {
1809 30 : BaseSizer::reportSizerOutput(state,
1810 10 : state.dataUnitVentilators->cMO_UnitVentilator,
1811 : unitVent.Name,
1812 : "User-Specified Minimum Outdoor Air Flow Rate [m3/s]",
1813 10 : unitVent.MinOutAirVolFlow);
1814 : }
1815 : } else {
1816 15 : CheckZoneSizing(state, state.dataUnitVentilators->cMO_UnitVentilator, unitVent.Name);
1817 15 : MinOutAirVolFlowDes = min(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA, unitVent.MaxAirVolFlow);
1818 15 : if (MinOutAirVolFlowDes < DataHVACGlobals::SmallAirVolFlow) {
1819 0 : MinOutAirVolFlowDes = 0.0;
1820 : }
1821 15 : if (IsAutoSize) {
1822 15 : unitVent.MinOutAirVolFlow = MinOutAirVolFlowDes;
1823 45 : BaseSizer::reportSizerOutput(state,
1824 15 : state.dataUnitVentilators->cMO_UnitVentilator,
1825 : unitVent.Name,
1826 : "Design Size Minimum Outdoor Air Flow Rate [m3/s]",
1827 15 : MinOutAirVolFlowDes);
1828 : } else {
1829 0 : if (unitVent.MinOutAirVolFlow > 0.0 && MinOutAirVolFlowDes > 0.0) {
1830 0 : MinOutAirVolFlowUser = unitVent.MinOutAirVolFlow;
1831 0 : BaseSizer::reportSizerOutput(state,
1832 0 : state.dataUnitVentilators->cMO_UnitVentilator,
1833 : unitVent.Name,
1834 : "Design Size Minimum Outdoor Air Flow Rate [m3/s]",
1835 : MinOutAirVolFlowDes,
1836 : "User-Specified Minimum Outdoor Air Flow Rate [m3/s]",
1837 0 : MinOutAirVolFlowUser);
1838 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1839 0 : if ((std::abs(MinOutAirVolFlowDes - MinOutAirVolFlowUser) / MinOutAirVolFlowUser) >
1840 0 : state.dataSize->AutoVsHardSizingThreshold) {
1841 0 : ShowMessage(state,
1842 0 : format("SizeUnitVentilator: Potential issue with equipment sizing for {} = \"{}\".",
1843 0 : state.dataUnitVentilators->cMO_UnitVentilator,
1844 0 : unitVent.Name));
1845 0 : ShowContinueError(state,
1846 0 : format("User-Specified Minimum Outdoor Air Flow Rate of {:.5R} [m3/s]", MinOutAirVolFlowUser));
1847 0 : ShowContinueError(
1848 0 : state, format("differs from Design Size Minimum Outdoor Air Flow Rate of {:.5R} [m3/s]", MinOutAirVolFlowDes));
1849 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1850 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1851 : }
1852 : }
1853 : }
1854 : }
1855 : }
1856 : }
1857 :
1858 25 : IsAutoSize = false;
1859 25 : if (unitVent.MaxVolHotWaterFlow == DataSizing::AutoSize) {
1860 9 : IsAutoSize = true;
1861 : }
1862 25 : if (unitVent.HCoilType == HeatCoilType::Water) {
1863 15 : if (state.dataSize->CurZoneEqNum > 0) {
1864 15 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
1865 6 : if (unitVent.MaxVolHotWaterFlow > 0.0) {
1866 18 : BaseSizer::reportSizerOutput(state,
1867 6 : state.dataUnitVentilators->cMO_UnitVentilator,
1868 : unitVent.Name,
1869 : "User-Specified Maximum Hot Water Flow [m3/s]",
1870 6 : unitVent.MaxVolHotWaterFlow);
1871 : }
1872 : } else {
1873 9 : CheckZoneSizing(state, state.dataUnitVentilators->cMO_UnitVentilator, unitVent.Name);
1874 :
1875 9 : CoilWaterOutletNode = WaterCoils::GetCoilWaterOutletNode(state, "Coil:Heating:Water", unitVent.HCoilName, ErrorsFound);
1876 9 : if (IsAutoSize) {
1877 9 : PltSizHeatNum = PlantUtilities::MyPlantSizingIndex(
1878 : state, "COIL:HEATING:WATER", unitVent.HCoilName, unitVent.HotControlNode, CoilWaterOutletNode, ErrorsFound);
1879 :
1880 9 : if (state.dataWaterCoils->WaterCoil(unitVent.HCoil_Index).UseDesignWaterDeltaTemp) {
1881 0 : WaterCoilSizDeltaT = state.dataWaterCoils->WaterCoil(unitVent.HCoil_Index).DesignWaterDeltaTemp;
1882 0 : DoWaterCoilSizing = true;
1883 : } else {
1884 9 : if (PltSizHeatNum > 0) {
1885 9 : WaterCoilSizDeltaT = state.dataSize->PlantSizData(PltSizHeatNum).DeltaT;
1886 9 : DoWaterCoilSizing = true;
1887 : } else {
1888 0 : DoWaterCoilSizing = false;
1889 : // If there is no heating Plant Sizing object and autosizing was requested, issue fatal error message
1890 0 : ShowSevereError(state, "Autosizing of water flow requires a heating loop Sizing:Plant object");
1891 0 : ShowContinueError(state,
1892 0 : format("Occurs in {} = \"{}\"", state.dataUnitVentilators->cMO_UnitVentilator, unitVent.Name));
1893 0 : ErrorsFound = true;
1894 : }
1895 : }
1896 :
1897 9 : if (DoWaterCoilSizing) {
1898 9 : if (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatMassFlow >= DataHVACGlobals::SmallAirVolFlow) {
1899 9 : SizingMethod = DataHVACGlobals::HeatingCapacitySizing;
1900 9 : if (unitVent.HVACSizingIndex > 0) {
1901 0 : auto &zoneHVACSizing = state.dataSize->ZoneHVACSizing(unitVent.HVACSizingIndex);
1902 0 : CapSizingMethod = zoneHVACSizing.HeatingCapMethod;
1903 0 : ZoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
1904 0 : switch (CapSizingMethod) {
1905 0 : case DataSizing::HeatingDesignCapacity:
1906 : case DataSizing::CapacityPerFloorArea:
1907 : case DataSizing::FractionOfAutosizedHeatingCapacity: {
1908 0 : switch (CapSizingMethod) {
1909 0 : case DataSizing::HeatingDesignCapacity: {
1910 0 : if (zoneHVACSizing.ScaledHeatingCapacity > 0.0) {
1911 0 : ZoneEqSizing.HeatingCapacity = true;
1912 0 : ZoneEqSizing.DesHeatingLoad = zoneHVACSizing.ScaledHeatingCapacity;
1913 : } else {
1914 0 : state.dataSize->DataFlowUsedForSizing =
1915 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
1916 : }
1917 0 : TempSize = zoneHVACSizing.ScaledHeatingCapacity;
1918 0 : } break;
1919 0 : case DataSizing::CapacityPerFloorArea: {
1920 0 : ZoneEqSizing.HeatingCapacity = true;
1921 0 : ZoneEqSizing.DesHeatingLoad = zoneHVACSizing.ScaledHeatingCapacity *
1922 0 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
1923 0 : state.dataSize->DataScalableCapSizingON = true;
1924 0 : } break;
1925 0 : case DataSizing::FractionOfAutosizedHeatingCapacity: {
1926 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = zoneHVACSizing.ScaledHeatingCapacity;
1927 0 : state.dataSize->DataFlowUsedForSizing =
1928 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
1929 0 : TempSize = DataSizing::AutoSize;
1930 0 : state.dataSize->DataScalableCapSizingON = true;
1931 0 : } break;
1932 0 : default: {
1933 0 : } break;
1934 : }
1935 0 : } break;
1936 0 : default: {
1937 0 : } break;
1938 : }
1939 0 : PrintFlag = false;
1940 0 : bool errorsFound = false;
1941 0 : HeatingCapacitySizer sizerHeatingCapacity;
1942 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1943 0 : DesHeatingLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
1944 0 : state.dataSize->DataScalableCapSizingON = false;
1945 : } else {
1946 9 : PrintFlag = false;
1947 9 : TempSize = DataSizing::AutoSize;
1948 9 : state.dataSize->DataFlowUsedForSizing =
1949 9 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
1950 9 : bool errorsFound = false;
1951 18 : HeatingCapacitySizer sizerHeatingCapacity;
1952 9 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1953 9 : DesHeatingLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
1954 : }
1955 18 : rho = FluidProperties::GetDensityGlycol(state,
1956 9 : state.dataPlnt->PlantLoop(unitVent.HWplantLoc.loopNum).FluidName,
1957 : DataGlobalConstants::HWInitConvTemp,
1958 9 : state.dataPlnt->PlantLoop(unitVent.HWplantLoc.loopNum).FluidIndex,
1959 : RoutineName);
1960 18 : Cp = FluidProperties::GetSpecificHeatGlycol(state,
1961 9 : state.dataPlnt->PlantLoop(unitVent.HWplantLoc.loopNum).FluidName,
1962 : DataGlobalConstants::HWInitConvTemp,
1963 9 : state.dataPlnt->PlantLoop(unitVent.HWplantLoc.loopNum).FluidIndex,
1964 : RoutineName);
1965 9 : MaxVolHotWaterFlowDes = DesHeatingLoad / (WaterCoilSizDeltaT * Cp * rho);
1966 :
1967 : } else {
1968 0 : MaxVolHotWaterFlowDes = 0.0;
1969 : }
1970 : }
1971 : }
1972 9 : if (IsAutoSize) {
1973 9 : unitVent.MaxVolHotWaterFlow = MaxVolHotWaterFlowDes;
1974 27 : BaseSizer::reportSizerOutput(state,
1975 9 : state.dataUnitVentilators->cMO_UnitVentilator,
1976 : unitVent.Name,
1977 : "Design Size Maximum Hot Water Flow [m3/s]",
1978 9 : MaxVolHotWaterFlowDes);
1979 : } else {
1980 0 : if (unitVent.MaxVolHotWaterFlow > 0.0 && MaxVolHotWaterFlowDes > 0.0) {
1981 0 : MaxVolHotWaterFlowUser = unitVent.MaxVolHotWaterFlow;
1982 0 : BaseSizer::reportSizerOutput(state,
1983 0 : state.dataUnitVentilators->cMO_UnitVentilator,
1984 : unitVent.Name,
1985 : "Design Size Maximum Hot Water Flow [m3/s]",
1986 : MaxVolHotWaterFlowDes,
1987 : "User-Specified Maximum Hot Water Flow [m3/s]",
1988 0 : MaxVolHotWaterFlowUser);
1989 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1990 0 : if ((std::abs(MaxVolHotWaterFlowDes - MaxVolHotWaterFlowUser) / MaxVolHotWaterFlowUser) >
1991 0 : state.dataSize->AutoVsHardSizingThreshold) {
1992 0 : ShowMessage(state,
1993 0 : "SizeUnitVentilator: Potential issue with equipment sizing for " +
1994 0 : state.dataUnitVentilators->cMO_UnitVentilator + ' ' + unitVent.Name);
1995 0 : ShowContinueError(state,
1996 0 : format("User-Specified Maximum Hot Water Flow of {:.5R} [m3/s]", MaxVolHotWaterFlowUser));
1997 0 : ShowContinueError(
1998 0 : state, format("differs from Design Size Maximum Hot Water Flow of {:.5R} [m3/s]", MaxVolHotWaterFlowDes));
1999 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2000 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2001 : }
2002 : }
2003 : }
2004 : }
2005 : }
2006 : }
2007 : } else {
2008 10 : unitVent.MaxVolHotWaterFlow = 0.0;
2009 : }
2010 :
2011 25 : IsAutoSize = false;
2012 25 : if (unitVent.MaxVolHotSteamFlow == DataSizing::AutoSize) {
2013 9 : IsAutoSize = true;
2014 : }
2015 25 : if (unitVent.HCoilType == HeatCoilType::Steam) {
2016 0 : if (state.dataSize->CurZoneEqNum > 0) {
2017 0 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
2018 0 : if (unitVent.MaxVolHotSteamFlow > 0.0) {
2019 0 : BaseSizer::reportSizerOutput(state,
2020 0 : state.dataUnitVentilators->cMO_UnitVentilator,
2021 : unitVent.Name,
2022 : "User-Specified Maximum Steam Flow [m3/s]",
2023 0 : unitVent.MaxVolHotSteamFlow);
2024 : }
2025 : } else {
2026 0 : CheckZoneSizing(state, state.dataUnitVentilators->cMO_UnitVentilator, unitVent.Name);
2027 :
2028 0 : CoilSteamOutletNode = SteamCoils::GetCoilSteamOutletNode(state, "Coil:Heating:Steam", unitVent.HCoilName, ErrorsFound);
2029 0 : if (IsAutoSize) {
2030 0 : PltSizHeatNum = PlantUtilities::MyPlantSizingIndex(
2031 : state, "Coil:Heating:Steam", unitVent.HCoilName, unitVent.HotControlNode, CoilSteamOutletNode, ErrorsFound);
2032 0 : if (PltSizHeatNum > 0) {
2033 0 : if (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatMassFlow >= DataHVACGlobals::SmallAirVolFlow) {
2034 0 : SizingMethod = DataHVACGlobals::HeatingCapacitySizing;
2035 0 : if (unitVent.HVACSizingIndex > 0) {
2036 0 : auto &zoneHVACSizing = state.dataSize->ZoneHVACSizing(unitVent.HVACSizingIndex);
2037 0 : CapSizingMethod = zoneHVACSizing.HeatingCapMethod;
2038 0 : ZoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
2039 0 : switch (CapSizingMethod) {
2040 0 : case DataSizing::HeatingDesignCapacity:
2041 : case DataSizing::CapacityPerFloorArea:
2042 : case DataSizing::FractionOfAutosizedHeatingCapacity: {
2043 0 : if (CapSizingMethod == DataSizing::HeatingDesignCapacity) {
2044 0 : if (zoneHVACSizing.ScaledHeatingCapacity > 0.0) {
2045 0 : ZoneEqSizing.HeatingCapacity = true;
2046 0 : ZoneEqSizing.DesHeatingLoad = zoneHVACSizing.ScaledHeatingCapacity;
2047 : } else {
2048 0 : state.dataSize->DataFlowUsedForSizing =
2049 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
2050 : }
2051 0 : TempSize = zoneHVACSizing.ScaledHeatingCapacity;
2052 0 : } else if (CapSizingMethod == DataSizing::CapacityPerFloorArea) {
2053 0 : ZoneEqSizing.HeatingCapacity = true;
2054 0 : ZoneEqSizing.DesHeatingLoad = zoneHVACSizing.ScaledHeatingCapacity *
2055 0 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
2056 0 : state.dataSize->DataScalableCapSizingON = true;
2057 0 : } else if (CapSizingMethod == DataSizing::FractionOfAutosizedHeatingCapacity) {
2058 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = zoneHVACSizing.ScaledHeatingCapacity;
2059 0 : state.dataSize->DataFlowUsedForSizing =
2060 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
2061 0 : TempSize = DataSizing::AutoSize;
2062 0 : state.dataSize->DataScalableCapSizingON = true;
2063 : }
2064 0 : } break;
2065 0 : default: {
2066 0 : } break;
2067 : }
2068 0 : PrintFlag = false;
2069 0 : bool errorsFound = false;
2070 0 : HeatingCapacitySizer sizerHeatingCapacity;
2071 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2072 0 : DesHeatingLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
2073 0 : state.dataSize->DataScalableCapSizingON = false;
2074 : } else {
2075 0 : PrintFlag = false;
2076 0 : TempSize = DataSizing::AutoSize;
2077 0 : state.dataSize->DataFlowUsedForSizing =
2078 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow;
2079 0 : bool errorsFound = false;
2080 0 : HeatingCapacitySizer sizerHeatingCapacity;
2081 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2082 0 : DesHeatingLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
2083 : }
2084 0 : TempSteamIn = 100.00;
2085 0 : EnthSteamInDry = FluidProperties::GetSatEnthalpyRefrig(
2086 0 : state, fluidNameSteam, TempSteamIn, 1.0, state.dataUnitVentilators->RefrigIndex, RoutineName);
2087 0 : EnthSteamOutWet = FluidProperties::GetSatEnthalpyRefrig(
2088 0 : state, fluidNameSteam, TempSteamIn, 0.0, state.dataUnitVentilators->RefrigIndex, RoutineName);
2089 0 : LatentHeatSteam = EnthSteamInDry - EnthSteamOutWet;
2090 0 : SteamDensity = FluidProperties::GetSatDensityRefrig(
2091 0 : state, fluidNameSteam, TempSteamIn, 1.0, state.dataUnitVentilators->RefrigIndex, RoutineName);
2092 0 : Cp = FluidProperties::GetSpecificHeatGlycol(state,
2093 : fluidNameWater,
2094 0 : state.dataSize->PlantSizData(PltSizHeatNum).ExitTemp,
2095 0 : state.dataUnitVentilators->DummyWaterIndex,
2096 : RoutineName);
2097 0 : MaxVolHotSteamFlowDes =
2098 0 : DesHeatingLoad / (SteamDensity * (LatentHeatSteam + state.dataSize->PlantSizData(PltSizHeatNum).DeltaT * Cp));
2099 : } else {
2100 0 : MaxVolHotSteamFlowDes = 0.0;
2101 : }
2102 : } else {
2103 0 : ShowSevereError(state, "Autosizing of Steam flow requires a heating loop Sizing:Plant object");
2104 0 : ShowContinueError(state, format("Occurs in {} = \"{}\"", state.dataUnitVentilators->cMO_UnitVentilator, unitVent.Name));
2105 0 : ErrorsFound = true;
2106 : }
2107 : }
2108 0 : if (IsAutoSize) {
2109 0 : unitVent.MaxVolHotSteamFlow = MaxVolHotSteamFlowDes;
2110 0 : BaseSizer::reportSizerOutput(state,
2111 0 : state.dataUnitVentilators->cMO_UnitVentilator,
2112 : unitVent.Name,
2113 : "Design Size Maximum Steam Flow [m3/s]",
2114 0 : MaxVolHotSteamFlowDes);
2115 : } else {
2116 0 : if (unitVent.MaxVolHotSteamFlow > 0.0 && MaxVolHotSteamFlowDes > 0.0) {
2117 0 : MaxVolHotSteamFlowUser = unitVent.MaxVolHotSteamFlow;
2118 0 : BaseSizer::reportSizerOutput(state,
2119 0 : state.dataUnitVentilators->cMO_UnitVentilator,
2120 : unitVent.Name,
2121 : "Design Size Maximum Steam Flow [m3/s]",
2122 : MaxVolHotSteamFlowDes,
2123 : "User-Specified Maximum Steam Flow [m3/s]",
2124 0 : MaxVolHotSteamFlowUser);
2125 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2126 0 : if ((std::abs(MaxVolHotSteamFlowDes - MaxVolHotSteamFlowUser) / MaxVolHotSteamFlowUser) >
2127 0 : state.dataSize->AutoVsHardSizingThreshold) {
2128 0 : ShowMessage(state,
2129 0 : format("SizeUnitVentilator: Potential issue with equipment sizing for {} = \"{}\"",
2130 0 : state.dataUnitVentilators->cMO_UnitVentilator,
2131 0 : unitVent.Name));
2132 0 : ShowContinueError(state, format("User-Specified Maximum Steam Flow of {:.5R} [m3/s]", MaxVolHotSteamFlowUser));
2133 0 : ShowContinueError(state,
2134 0 : format("differs from Design Size Maximum Steam Flow of {:.5R} [m3/s]", MaxVolHotSteamFlowDes));
2135 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2136 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2137 : }
2138 : }
2139 : }
2140 : }
2141 : }
2142 : }
2143 : } else {
2144 25 : unitVent.MaxVolHotSteamFlow = 0.0;
2145 : }
2146 :
2147 25 : IsAutoSize = false;
2148 25 : if (unitVent.MaxVolColdWaterFlow == DataSizing::AutoSize) {
2149 6 : IsAutoSize = true;
2150 : }
2151 41 : if (unitVent.CCoilType == CoolCoilType::Water || unitVent.CCoilType == CoolCoilType::Detailed ||
2152 16 : unitVent.CCoilType == CoolCoilType::HXAssisted) {
2153 :
2154 9 : if (state.dataSize->CurZoneEqNum > 0) {
2155 9 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
2156 3 : if (unitVent.MaxVolColdWaterFlow > 0.0) {
2157 9 : BaseSizer::reportSizerOutput(state,
2158 3 : state.dataUnitVentilators->cMO_UnitVentilator,
2159 : unitVent.Name,
2160 : "User-Specified Maximum Cold Water Flow [m3/s]",
2161 3 : unitVent.MaxVolColdWaterFlow);
2162 : }
2163 : } else {
2164 6 : CheckZoneSizing(state, state.dataUnitVentilators->cMO_UnitVentilator, unitVent.Name);
2165 :
2166 6 : if (unitVent.CCoilType == CoolCoilType::HXAssisted) {
2167 0 : CoolingCoilName = HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, unitVent.CCoilTypeCh, unitVent.CCoilName, ErrorsFound);
2168 0 : CoolingCoilType = HVACHXAssistedCoolingCoil::GetHXCoilType(state, unitVent.CCoilTypeCh, unitVent.CCoilName, ErrorsFound);
2169 : } else {
2170 6 : CoolingCoilName = unitVent.CCoilName;
2171 6 : CoolingCoilType = unitVent.CCoilTypeCh;
2172 : }
2173 6 : CoilWaterOutletNode = WaterCoils::GetCoilWaterOutletNode(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
2174 6 : if (IsAutoSize) {
2175 6 : PltSizCoolNum = PlantUtilities::MyPlantSizingIndex(
2176 : state, CoolingCoilType, CoolingCoilName, unitVent.ColdControlNode, CoilWaterOutletNode, ErrorsFound);
2177 6 : if (state.dataWaterCoils->WaterCoil(unitVent.CCoil_Index).UseDesignWaterDeltaTemp) {
2178 0 : WaterCoilSizDeltaT = state.dataWaterCoils->WaterCoil(unitVent.CCoil_Index).DesignWaterDeltaTemp;
2179 0 : DoWaterCoilSizing = true;
2180 : } else {
2181 6 : if (PltSizCoolNum > 0) {
2182 6 : WaterCoilSizDeltaT = state.dataSize->PlantSizData(PltSizCoolNum).DeltaT;
2183 6 : DoWaterCoilSizing = true;
2184 : } else {
2185 0 : DoWaterCoilSizing = false;
2186 : // If there is no cooling Plant Sizing object and autosizing was requested, issue fatal error message
2187 0 : ShowSevereError(state, "Autosizing of water coil requires a cooling loop Sizing:Plant object");
2188 0 : ShowContinueError(state,
2189 0 : format("Occurs in {} = \"{}\"", state.dataUnitVentilators->cMO_UnitVentilator, unitVent.Name));
2190 0 : ErrorsFound = true;
2191 : }
2192 : }
2193 6 : if (DoWaterCoilSizing) {
2194 6 : if (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolMassFlow >= DataHVACGlobals::SmallAirVolFlow) {
2195 6 : SizingMethod = DataHVACGlobals::CoolingCapacitySizing;
2196 6 : if (unitVent.HVACSizingIndex > 0) {
2197 0 : auto &zoneHVACSizing = state.dataSize->ZoneHVACSizing(unitVent.HVACSizingIndex);
2198 0 : CapSizingMethod = zoneHVACSizing.CoolingCapMethod;
2199 0 : ZoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
2200 0 : switch (CapSizingMethod) {
2201 0 : case DataSizing::CoolingDesignCapacity:
2202 : case DataSizing::CapacityPerFloorArea:
2203 : case DataSizing::FractionOfAutosizedCoolingCapacity: {
2204 0 : if (CapSizingMethod == DataSizing::CoolingDesignCapacity) {
2205 0 : if (zoneHVACSizing.ScaledCoolingCapacity > 0.0) {
2206 0 : ZoneEqSizing.CoolingCapacity = true;
2207 0 : ZoneEqSizing.DesCoolingLoad = zoneHVACSizing.ScaledCoolingCapacity;
2208 : } else {
2209 0 : state.dataSize->DataFlowUsedForSizing =
2210 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
2211 : }
2212 0 : TempSize = zoneHVACSizing.ScaledCoolingCapacity;
2213 0 : } else if (CapSizingMethod == DataSizing::CapacityPerFloorArea) {
2214 0 : ZoneEqSizing.CoolingCapacity = true;
2215 0 : ZoneEqSizing.DesCoolingLoad = zoneHVACSizing.ScaledCoolingCapacity *
2216 0 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
2217 0 : state.dataSize->DataScalableCapSizingON = true;
2218 0 : } else if (CapSizingMethod == DataSizing::FractionOfAutosizedCoolingCapacity) {
2219 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = zoneHVACSizing.ScaledCoolingCapacity;
2220 0 : state.dataSize->DataFlowUsedForSizing =
2221 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
2222 0 : TempSize = DataSizing::AutoSize;
2223 0 : state.dataSize->DataScalableCapSizingON = true;
2224 : }
2225 0 : } break;
2226 0 : default: {
2227 0 : } break;
2228 : }
2229 0 : PrintFlag = false;
2230 0 : CoolingCapacitySizer sizerCoolingCapacity;
2231 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2232 0 : DesCoolingLoad = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
2233 0 : state.dataSize->DataScalableCapSizingON = false;
2234 : } else {
2235 6 : PrintFlag = false;
2236 6 : TempSize = DataSizing::AutoSize;
2237 6 : state.dataSize->DataFlowUsedForSizing =
2238 6 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
2239 12 : CoolingCapacitySizer sizerCoolingCapacity;
2240 6 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
2241 6 : DesCoolingLoad = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
2242 : }
2243 12 : rho = FluidProperties::GetDensityGlycol(state,
2244 6 : state.dataPlnt->PlantLoop(unitVent.CWPlantLoc.loopNum).FluidName,
2245 : 5.,
2246 6 : state.dataPlnt->PlantLoop(unitVent.CWPlantLoc.loopNum).FluidIndex,
2247 : RoutineName);
2248 12 : Cp = FluidProperties::GetSpecificHeatGlycol(state,
2249 6 : state.dataPlnt->PlantLoop(unitVent.CWPlantLoc.loopNum).FluidName,
2250 : 5.,
2251 6 : state.dataPlnt->PlantLoop(unitVent.CWPlantLoc.loopNum).FluidIndex,
2252 : RoutineName);
2253 6 : MaxVolColdWaterFlowDes = DesCoolingLoad / (WaterCoilSizDeltaT * Cp * rho);
2254 :
2255 6 : if (MaxVolColdWaterFlowDes < 0.0) {
2256 0 : ShowWarningError(state, "Autosizing of water flow resulted in negative value.");
2257 0 : ShowContinueError(state,
2258 0 : format("Occurs in {} = \"{}\"", state.dataUnitVentilators->cMO_UnitVentilator, unitVent.Name));
2259 0 : ShowContinueError(state, "...Sizing information found during sizing simulation:");
2260 0 : ShowContinueError(state, format("...Calculated coil design load = {:.3T} W", DesCoolingLoad));
2261 0 : ShowContinueError(state, format("...Calculated water flow rate = {:.3T} m3/s", MaxVolColdWaterFlowDes));
2262 0 : ShowContinueError(state,
2263 : "...Water flow rate will be set to 0. Check sizing inputs for zone and plant, inputs for water "
2264 : "cooling coil object, and design day specifications.");
2265 0 : ShowContinueError(state, "...Consider autosizing all inputs if not already doing so.");
2266 0 : MaxVolColdWaterFlowDes = 0.0;
2267 : }
2268 : } else {
2269 0 : MaxVolColdWaterFlowDes = 0.0;
2270 : }
2271 : }
2272 : }
2273 6 : if (IsAutoSize) {
2274 6 : unitVent.MaxVolColdWaterFlow = MaxVolColdWaterFlowDes;
2275 18 : BaseSizer::reportSizerOutput(state,
2276 6 : state.dataUnitVentilators->cMO_UnitVentilator,
2277 : unitVent.Name,
2278 : "Design Size Maximum Cold Water Flow [m3/s]",
2279 6 : MaxVolColdWaterFlowDes);
2280 : } else {
2281 0 : if (unitVent.MaxVolColdWaterFlow > 0.0 && MaxVolColdWaterFlowDes > 0.0) {
2282 0 : MaxVolColdWaterFlowUser = unitVent.MaxVolColdWaterFlow;
2283 0 : BaseSizer::reportSizerOutput(state,
2284 0 : state.dataUnitVentilators->cMO_UnitVentilator,
2285 : unitVent.Name,
2286 : "Design Size Maximum Cold Water Flow [m3/s]",
2287 : MaxVolColdWaterFlowDes,
2288 : "User-Specified Maximum Cold Water Flow [m3/s]",
2289 0 : MaxVolColdWaterFlowUser);
2290 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2291 0 : if ((std::abs(MaxVolColdWaterFlowDes - MaxVolColdWaterFlowUser) / MaxVolColdWaterFlowUser) >
2292 0 : state.dataSize->AutoVsHardSizingThreshold) {
2293 0 : ShowMessage(state,
2294 0 : format("SizeUnitVentilator: Potential issue with equipment sizing for {} = \"{}\"",
2295 0 : state.dataUnitVentilators->cMO_UnitVentilator,
2296 0 : unitVent.Name));
2297 0 : ShowContinueError(state,
2298 0 : format("User-Specified Maximum Cold Water Flow of {:.5R} [m3/s]", MaxVolColdWaterFlowUser));
2299 0 : ShowContinueError(
2300 0 : state, format("differs from Design Size Maximum Cold Water Flow of {:.5R} [m3/s]", MaxVolColdWaterFlowDes));
2301 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2302 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2303 : }
2304 : }
2305 : }
2306 : }
2307 : }
2308 : }
2309 : }
2310 :
2311 : // set the design air flow rates for the heating and cooling coils
2312 25 : if (unitVent.CCoilType == CoolCoilType::HXAssisted) {
2313 0 : CoolingCoilName = HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, unitVent.CCoilTypeCh, unitVent.CCoilName, ErrorsFound);
2314 0 : CoolingCoilType = HVACHXAssistedCoolingCoil::GetHXCoilType(state, unitVent.CCoilTypeCh, unitVent.CCoilName, ErrorsFound);
2315 : } else {
2316 25 : CoolingCoilName = unitVent.CCoilName;
2317 25 : CoolingCoilType = unitVent.CCoilTypeCh;
2318 : }
2319 25 : WaterCoils::SetCoilDesFlow(state, CoolingCoilType, CoolingCoilName, unitVent.MaxAirVolFlow, ErrorsFound);
2320 25 : WaterCoils::SetCoilDesFlow(state, unitVent.HCoilTypeCh, unitVent.HCoilName, unitVent.MaxAirVolFlow, ErrorsFound);
2321 :
2322 25 : if (state.dataSize->CurZoneEqNum > 0) {
2323 25 : ZoneEqSizing.MaxHWVolFlow = unitVent.MaxVolHotWaterFlow;
2324 25 : ZoneEqSizing.MaxCWVolFlow = unitVent.MaxVolColdWaterFlow;
2325 : }
2326 :
2327 25 : if (ErrorsFound) {
2328 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
2329 : }
2330 25 : }
2331 :
2332 165565 : void CalcUnitVentilator(EnergyPlusData &state,
2333 : int &UnitVentNum, // number of the current fan coil unit being simulated
2334 : int const ZoneNum, // number of zone being served
2335 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
2336 : Real64 &PowerMet, // Sensible power supplied (W)
2337 : Real64 &LatOutputProvided // Latent power supplied (kg/s), negative = dehumidification
2338 : )
2339 : {
2340 :
2341 : // SUBROUTINE INFORMATION:
2342 : // AUTHOR Rick Strand
2343 : // DATE WRITTEN May 2000
2344 : // MODIFIED Don Shirey, Aug 2009 (LatOutputProvided)
2345 : // July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
2346 :
2347 : // PURPOSE OF THIS SUBROUTINE:
2348 : // This subroutine mainly controls the action of the unit ventilator
2349 : // (or more exactly, it controls the amount of outside air brought in)
2350 : // based on the user input for controls and the defined controls
2351 : // algorithms. There are currently (at the initial creation of this
2352 : // subroutine) two control methods: variable percent (ASHRAE "Cycle I"
2353 : // or "Cycle II") and fixed temperature (ASHRAE "Cycle III").
2354 :
2355 : // METHODOLOGY EMPLOYED:
2356 : // Unit is controlled based on user input and what is happening in the
2357 : // simulation. There are various cases to consider:
2358 : // 1. OFF: Unit is schedule off or there is no load on it. All flow
2359 : // rates are set to zero and the temperatures are set to zone conditions
2360 : // (except for the outside air inlet).
2361 : // 2. HEATING/VARIABLE PERCENT: The unit is on, there is a heating load,
2362 : // and variable percent control is specified. The outside air fraction
2363 : // is set to the minimum outside air fraction (schedule based) and the
2364 : // heating coil is activated.
2365 : // 3. HEATING/FIXED TEMPERATURE: The unit is on, there is a heating load,
2366 : // and fixed temperature control is specified. The outside air fraction
2367 : // is varied in an attempt to obtain a mixed air temperature equal to
2368 : // the user specified temperature (schedule based). The heating coil
2369 : // is activated, if necessary.
2370 : // 4. COOLING/NO COIL: The unit is on, there is a cooling load, and no
2371 : // coil is present or it has been scheduled off. Set the amount of
2372 : // outside air based on the control type. Simulate the "mixing box".
2373 : // 5. COOLING/WITH COIL: The unit is on, there is a cooling load, and
2374 : // a cooling coil is present and scheduled on. Tries to use outside
2375 : // air as best as possible and then calls a cooling coil
2376 : // Note: controls are strictly temperature based and do not factor
2377 : // humidity into the equation (not an enthalpy economy cycle but rather
2378 : // a simple return air economy cycle). In addition, temperature predictions
2379 : // are not strict energy balances here in the control routine though
2380 : // in the mixing routine an energy balance is preserved.
2381 :
2382 : // REFERENCES:
2383 : // ASHRAE Systems and Equipment Handbook (SI), 1996. page 31.3
2384 :
2385 : // Using/Aliasing
2386 165565 : auto &ZoneCompTurnFansOff = state.dataHVACGlobal->ZoneCompTurnFansOff;
2387 165565 : auto &ZoneCompTurnFansOn = state.dataHVACGlobal->ZoneCompTurnFansOn;
2388 165565 : auto &unitVent = state.dataUnitVentilators->UnitVent(UnitVentNum);
2389 :
2390 : // Smallest allowed temperature difference for comparisons (below this value the temperatures are assumed equal)
2391 165565 : Real64 constexpr LowTempDiff(0.1);
2392 : // Smallest allowed outside air fraction difference for comparison (below this value the fractions are assumed equal)
2393 165565 : Real64 constexpr LowOAFracDiff(0.01);
2394 165565 : int constexpr MaxIter(50);
2395 :
2396 : Real64 AirMassFlow; // air mass flow rate [kg/sec]
2397 : Real64 MaxOAFrac; // maximum possible outside air fraction
2398 : Real64 MinOAFrac; // minimum possible outside air fraction
2399 : Real64 Tdesired; // desired temperature after mixing inlet and outdoor air [degrees C]
2400 : Real64 Tinlet; // temperature of air coming into the unit ventilator [degrees C]
2401 : Real64 Toutdoor; // temperature of outdoor air being introduced into the unit ventilator [degrees C]
2402 : Real64 mdot;
2403 :
2404 165565 : switch (unitVent.CoilOption) {
2405 154719 : case CoilsUsed::Both:
2406 : case CoilsUsed::Heating: {
2407 154719 : switch (unitVent.HCoilType) {
2408 99339 : case HeatCoilType::Water: {
2409 99339 : WaterCoils::CheckWaterCoilSchedule(state, unitVent.HCoilName, unitVent.HCoilSchedValue, unitVent.HCoil_Index);
2410 99339 : } break;
2411 0 : case HeatCoilType::Steam: {
2412 0 : SteamCoils::CheckSteamCoilSchedule(state, "Coil:Heating:Steam", unitVent.HCoilName, unitVent.HCoilSchedValue, unitVent.HCoil_Index);
2413 0 : } break;
2414 27690 : case HeatCoilType::Electric: {
2415 27690 : HeatingCoils::CheckHeatingCoilSchedule(
2416 : state, "Coil:Heating:Electric", unitVent.HCoilName, unitVent.HCoilSchedValue, unitVent.HCoil_Index);
2417 27690 : } break;
2418 27690 : case HeatCoilType::Gas: {
2419 27690 : HeatingCoils::CheckHeatingCoilSchedule(
2420 : state, "Coil:Heating:Fuel", unitVent.HCoilName, unitVent.HCoilSchedValue, unitVent.HCoil_Index);
2421 27690 : } break;
2422 0 : default: {
2423 0 : } break;
2424 : }
2425 154719 : } break;
2426 10846 : default: {
2427 10846 : } break;
2428 : }
2429 :
2430 165565 : switch (unitVent.CoilOption) {
2431 60803 : case CoilsUsed::Both:
2432 : case CoilsUsed::Cooling: {
2433 60803 : switch (unitVent.CCoilType) {
2434 60803 : case CoolCoilType::Water: {
2435 60803 : WaterCoils::CheckWaterCoilSchedule(state, unitVent.CCoilName, unitVent.CCoilSchedValue, unitVent.CCoil_Index);
2436 60803 : } break;
2437 0 : case CoolCoilType::Detailed: {
2438 0 : WaterCoils::CheckWaterCoilSchedule(state, unitVent.CCoilName, unitVent.CCoilSchedValue, unitVent.CCoil_Index);
2439 0 : } break;
2440 0 : case CoolCoilType::HXAssisted: {
2441 0 : HVACHXAssistedCoolingCoil::CheckHXAssistedCoolingCoilSchedule(
2442 : state, "CoilSystem:Cooling:Water:HeatExchangerAssisted", unitVent.CCoilName, unitVent.CCoilSchedValue, unitVent.CCoil_Index);
2443 0 : } break;
2444 0 : default: {
2445 0 : assert(false);
2446 : } break;
2447 : }
2448 60803 : } break;
2449 104762 : default: {
2450 104762 : } break;
2451 : }
2452 :
2453 : // initialize local variables
2454 165565 : int ControlNode = 0;
2455 165565 : Real64 QUnitOut = 0.0;
2456 165565 : Real64 ControlOffset = 0.0;
2457 165565 : Real64 MaxWaterFlow = 0.0;
2458 165565 : Real64 MinWaterFlow = 0.0;
2459 165565 : Real64 NoOutput = 0.0;
2460 165565 : Real64 FullOutput = 0.0;
2461 165565 : int SolFlag = 0; // # of iterations IF positive, -1 means failed to converge, -2 means bounds are incorrect
2462 165565 : int OpMode = unitVent.OpMode;
2463 165565 : Real64 PartLoadFrac = 0.0;
2464 :
2465 165565 : auto &inletNode(state.dataLoopNodes->Node(unitVent.AirInNode));
2466 165565 : auto &outletNode(state.dataLoopNodes->Node(unitVent.AirOutNode));
2467 165565 : auto &outsideAirNode(state.dataLoopNodes->Node(unitVent.OutsideAirNode));
2468 :
2469 487579 : if ((std::abs(state.dataUnitVentilators->QZnReq) < DataHVACGlobals::SmallLoad) ||
2470 219912 : (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) ||
2471 394593 : (ScheduleManager::GetCurrentScheduleValue(state, unitVent.SchedPtr) <= 0) ||
2472 63463 : ((ScheduleManager::GetCurrentScheduleValue(state, unitVent.FanAvailSchedPtr) <= 0 && !ZoneCompTurnFansOn) || ZoneCompTurnFansOff)) {
2473 :
2474 : // Unit is off or has no load upon it; set the flow rates to zero and then
2475 : // simulate the components with the no flow conditions
2476 102102 : AirMassFlow = outletNode.MassFlowRate;
2477 102102 : state.dataUnitVentilators->HCoilOn = false;
2478 102102 : if (unitVent.HotControlNode > 0) {
2479 57903 : mdot = 0.0;
2480 57903 : PlantUtilities::SetComponentFlowRate(state, mdot, unitVent.HotControlNode, unitVent.HotCoilOutNodeNum, unitVent.HWplantLoc);
2481 : }
2482 102102 : if (unitVent.ColdControlNode > 0) {
2483 36337 : mdot = 0.0;
2484 36337 : PlantUtilities::SetComponentFlowRate(state, mdot, unitVent.ColdControlNode, unitVent.ColdCoilOutNodeNum, unitVent.CWPlantLoc);
2485 : }
2486 :
2487 102102 : if (OpMode == DataHVACGlobals::CycFanCycCoil) {
2488 4560 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, QUnitOut, OpMode, PartLoadFrac);
2489 4560 : if (inletNode.MassFlowRateMax > 0.0) {
2490 4559 : unitVent.FanPartLoadRatio = inletNode.MassFlowRate / inletNode.MassFlowRateMax;
2491 : }
2492 : } else {
2493 97542 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, QUnitOut);
2494 : }
2495 : } else { // Unit is on-->this section is intended to control the outside air and the main
2496 : // result is to set the outside air flow rate variable OAMassFlowRate
2497 63463 : unitVent.FanPartLoadRatio = 1.0;
2498 63463 : if (state.dataUnitVentilators->QZnReq > DataHVACGlobals::SmallLoad) { // HEATING MODE
2499 :
2500 25302 : ControlNode = unitVent.HotControlNode;
2501 25302 : ControlOffset = unitVent.HotControlOffset;
2502 25302 : MaxWaterFlow = unitVent.MaxHotWaterFlow;
2503 25302 : MinWaterFlow = unitVent.MinHotWaterFlow;
2504 : // On the first HVAC iteration the system values are given to the controller, but after that
2505 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
2506 25302 : if (!FirstHVACIteration && unitVent.HCoilType == HeatCoilType::Water) {
2507 10082 : MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
2508 10082 : MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
2509 : }
2510 :
2511 25302 : state.dataUnitVentilators->HCoilOn = true;
2512 :
2513 25302 : if (outsideAirNode.MassFlowRate > 0.0) {
2514 50604 : MinOAFrac = ScheduleManager::GetCurrentScheduleValue(state, unitVent.MinOASchedPtr) *
2515 25302 : (unitVent.MinOutAirMassFlow / outsideAirNode.MassFlowRate);
2516 : } else {
2517 0 : MinOAFrac = 0.0;
2518 : }
2519 25302 : MinOAFrac = min(1.0, max(0.0, MinOAFrac));
2520 :
2521 25302 : if ((!unitVent.HCoilPresent) || (unitVent.HCoilSchedValue <= 0.0)) {
2522 : // In heating mode, but there is no coil to provide heating. This is handled
2523 : // differently than if there was a heating coil present. Fixed temperature
2524 : // will still try to vary the amount of outside air to meet the desired
2525 : // mixed air temperature, while variable percent will go to full ventilation
2526 : // when it is most advantageous.
2527 :
2528 : {
2529 1086 : switch (unitVent.OAControlType) {
2530 0 : case OAControl::FixedAmount: {
2531 : // In this control type, the outdoor air flow rate is fixed to the minimum value
2532 : // which is equal to the maximum value, regardless of all the other conditions.
2533 :
2534 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2535 0 : } break;
2536 1086 : case OAControl::VariablePercent: {
2537 : // This algorithm is probably a bit simplistic in that it just bounces
2538 : // back and forth between the maximum outside air and the minimum. In
2539 : // REAL(r64)ity, a system *might* vary between the two based on the load in
2540 : // the zone.
2541 1086 : Tinlet = inletNode.Temp;
2542 1086 : Toutdoor = outsideAirNode.Temp;
2543 :
2544 1086 : if (Tinlet >= Toutdoor) {
2545 :
2546 1086 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2547 :
2548 : } else { // Tinlet < Toutdoor
2549 :
2550 0 : MaxOAFrac = ScheduleManager::GetCurrentScheduleValue(state, unitVent.MaxOASchedPtr);
2551 0 : state.dataUnitVentilators->OAMassFlowRate = MaxOAFrac * outsideAirNode.MassFlowRate;
2552 : }
2553 1086 : } break;
2554 0 : case OAControl::FixedTemperature: {
2555 : // In heating mode, the outside air for "fixed temperature" attempts
2556 : // to control the outside air fraction so that a desired temperature
2557 : // is met (if possible). If this desired temperature is between the
2558 : // outside air temperature and the zone air temperature (inlet air
2559 : // temperature), then this is possible. If not, the control will try
2560 : // to maximize the amount of air coming from the source that is closer
2561 : // in temperature to the desired temperature.
2562 0 : Tdesired = ScheduleManager::GetCurrentScheduleValue(state, unitVent.TempSchedPtr);
2563 0 : Tinlet = inletNode.Temp;
2564 0 : Toutdoor = outsideAirNode.Temp;
2565 0 : MaxOAFrac = 1.0;
2566 :
2567 0 : if (std::abs(Tinlet - Toutdoor) <= LowTempDiff) { // no difference in indoor and outdoor conditions-->set OA to minimum
2568 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2569 0 : } else if (std::abs(MaxOAFrac - MinOAFrac) <= LowOAFracDiff) { // no difference in outside air fractions
2570 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2571 0 : } else if (((Tdesired <= Tinlet) && (Tdesired >= Toutdoor)) || ((Tdesired >= Tinlet) && (Tdesired <= Toutdoor))) {
2572 : // Desired temperature is between the inlet and outdoor temperatures
2573 : // so vary the flow rate between no outside air and no recirculation air
2574 : // then applying the maximum and minimum limits the user has scheduled
2575 : // to make sure too much/little outside air is being introduced
2576 0 : state.dataUnitVentilators->OAMassFlowRate = ((Tdesired - Tinlet) / (Toutdoor - Tinlet)) * inletNode.MassFlowRate;
2577 0 : state.dataUnitVentilators->OAMassFlowRate =
2578 0 : max(state.dataUnitVentilators->OAMassFlowRate, (MinOAFrac * outsideAirNode.MassFlowRate));
2579 0 : state.dataUnitVentilators->OAMassFlowRate =
2580 0 : min(state.dataUnitVentilators->OAMassFlowRate, (MaxOAFrac * outsideAirNode.MassFlowRate));
2581 0 : } else if ((Tdesired < Tinlet) && (Tdesired < Toutdoor)) {
2582 : // Desired temperature is below both the inlet and outdoor temperatures
2583 : // so use whichever flow rate (max or min) that will get closer
2584 0 : if (Tinlet < Toutdoor) { // Tinlet closer to Tdesired so use minimum outside air
2585 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2586 : } else { // Toutdoor closer to Tdesired so use maximum outside air
2587 0 : state.dataUnitVentilators->OAMassFlowRate = MaxOAFrac * outsideAirNode.MassFlowRate;
2588 : }
2589 0 : } else if ((Tdesired > Tinlet) && (Tdesired > Toutdoor)) {
2590 : // Desired temperature is above both the inlet and outdoor temperatures
2591 : // so use whichever flow rate (max or min) that will get closer
2592 0 : if (Tinlet > Toutdoor) { // Tinlet closer to Tdesired so use minimum outside air
2593 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2594 : } else { // Toutdoor closer to Tdesired so use maximum outside air
2595 0 : state.dataUnitVentilators->OAMassFlowRate = MaxOAFrac * outsideAirNode.MassFlowRate;
2596 : }
2597 : } else {
2598 : // It should NEVER get to this point, but just in case...
2599 0 : ShowFatalError(state, "ZoneHVAC:UnitVentilator simulation control: illogical condition for " + unitVent.Name);
2600 : }
2601 0 : } break;
2602 0 : default: {
2603 0 : assert(false);
2604 : } break;
2605 : }
2606 : }
2607 :
2608 2172 : if (OpMode == DataHVACGlobals::CycFanCycCoil) {
2609 0 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, QUnitOut, OpMode, PartLoadFrac);
2610 0 : if (inletNode.MassFlowRateMax > 0.0) {
2611 0 : unitVent.FanPartLoadRatio = inletNode.MassFlowRate / inletNode.MassFlowRateMax;
2612 : }
2613 : } else {
2614 1086 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, QUnitOut);
2615 : }
2616 :
2617 : } else { // Coil/no coil block
2618 : // There is a heating load and there is a heating coil present (presumably).
2619 : // Variable percent will throttle outside air back to the minimum while
2620 : // fixed temperature will still try to vary the outside air amount to meet
2621 : // the desired mixed air temperature.
2622 :
2623 : {
2624 24216 : switch (unitVent.OAControlType) {
2625 3270 : case OAControl::FixedAmount: {
2626 : // In this control type, the outdoor air flow rate is fixed to the maximum value
2627 : // which is equal to the minimum value, regardless of all the other conditions.
2628 3270 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2629 3270 : } break;
2630 20946 : case OAControl::VariablePercent: {
2631 : // In heating mode, the outside air for "variable percent" control
2632 : // is set to the minimum value
2633 20946 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2634 20946 : } break;
2635 0 : case OAControl::FixedTemperature: {
2636 : // In heating mode, the outside air for "fixed temperature" attempts
2637 : // to control the outside air fraction so that a desired temperature
2638 : // is met (if possible). If this desired temperature is between the
2639 : // outside air temperature and the zone air temperature (inlet air
2640 : // temperature), then this is possible. If not, the control will try
2641 : // to maximize the amount of air coming from the source that is closer
2642 : // in temperature to the desired temperature.
2643 0 : Tdesired = ScheduleManager::GetCurrentScheduleValue(state, unitVent.TempSchedPtr);
2644 0 : Tinlet = inletNode.Temp;
2645 0 : Toutdoor = outsideAirNode.Temp;
2646 0 : MaxOAFrac = 1.0;
2647 :
2648 0 : if (std::abs(Tinlet - Toutdoor) <= LowTempDiff) { // no difference in indoor and outdoor conditions-->set OA to minimum
2649 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2650 0 : } else if (std::abs(MaxOAFrac - MinOAFrac) <= LowOAFracDiff) { // no difference in outside air fractions
2651 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2652 0 : } else if (((Tdesired <= Tinlet) && (Tdesired >= Toutdoor)) || ((Tdesired >= Tinlet) && (Tdesired <= Toutdoor))) {
2653 : // Desired temperature is between the inlet and outdoor temperatures
2654 : // so vary the flow rate between no outside air and no recirculation air
2655 : // then applying the maximum and minimum limits the user has scheduled
2656 : // to make sure too much/little outside air is being introduced
2657 0 : state.dataUnitVentilators->OAMassFlowRate = ((Tdesired - Tinlet) / (Toutdoor - Tinlet)) * inletNode.MassFlowRate;
2658 0 : state.dataUnitVentilators->OAMassFlowRate =
2659 0 : max(state.dataUnitVentilators->OAMassFlowRate, (MinOAFrac * outsideAirNode.MassFlowRate));
2660 0 : state.dataUnitVentilators->OAMassFlowRate =
2661 0 : min(state.dataUnitVentilators->OAMassFlowRate, (MaxOAFrac * outsideAirNode.MassFlowRate));
2662 0 : } else if ((Tdesired < Tinlet) && (Tdesired < Toutdoor)) {
2663 : // Desired temperature is below both the inlet and outdoor temperatures
2664 : // so use whichever flow rate (max or min) that will get closer
2665 0 : if (Tinlet < Toutdoor) { // Tinlet closer to Tdesired so use minimum outside air
2666 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2667 : } else { // Toutdoor closer to Tdesired so use maximum outside air
2668 0 : state.dataUnitVentilators->OAMassFlowRate = MaxOAFrac * outsideAirNode.MassFlowRate;
2669 : }
2670 0 : } else if ((Tdesired > Tinlet) && (Tdesired > Toutdoor)) {
2671 : // Desired temperature is above both the inlet and outdoor temperatures
2672 : // so use whichever flow rate (max or min) that will get closer
2673 0 : if (Tinlet > Toutdoor) { // Tinlet closer to Tdesired so use minimum outside air
2674 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2675 : } else { // Toutdoor closer to Tdesired so use maximum outside air
2676 0 : state.dataUnitVentilators->OAMassFlowRate = MaxOAFrac * outsideAirNode.MassFlowRate;
2677 : }
2678 : } else {
2679 : // It should NEVER get to this point, but just in case...
2680 0 : ShowFatalError(state, "ZoneHVAC:UnitVentilator simulation control: illogical condition for " + unitVent.Name);
2681 : }
2682 0 : } break;
2683 0 : default: {
2684 0 : assert(false);
2685 : } break;
2686 : }
2687 : }
2688 :
2689 24216 : if (OpMode == DataHVACGlobals::CycFanCycCoil) {
2690 :
2691 : // Find part load ratio of unit ventilator coils
2692 714 : PartLoadFrac = 0.0;
2693 714 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, NoOutput, OpMode, PartLoadFrac);
2694 714 : if ((NoOutput - state.dataUnitVentilators->QZnReq) < DataHVACGlobals::SmallLoad) {
2695 : // Unit ventilator is unable to meet the load with coil off, set PLR = 1
2696 714 : PartLoadFrac = 1.0;
2697 714 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, FullOutput, OpMode, PartLoadFrac);
2698 714 : if ((FullOutput - state.dataUnitVentilators->QZnReq) > DataHVACGlobals::SmallLoad) {
2699 : // Unit ventilator full load capacity is able to meet the load, Find PLR
2700 : // Tolerance is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
2701 27468 : auto f = [&state, UnitVentNum, FirstHVACIteration, OpMode](Real64 const PartLoadRatio) {
2702 4578 : Real64 QUnitOut = 0.0; // heating/Cooling provided by unit ventilator [watts]
2703 13734 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, QUnitOut, OpMode, PartLoadRatio);
2704 4578 : if (state.dataUnitVentilators->QZnReq) {
2705 13734 : return (QUnitOut - state.dataUnitVentilators->QZnReq) / state.dataUnitVentilators->QZnReq;
2706 : } else
2707 0 : return 0.0;
2708 534 : };
2709 534 : General::SolveRoot(state, 0.001, MaxIter, SolFlag, PartLoadFrac, f, 0.0, 1.0);
2710 : }
2711 : }
2712 :
2713 714 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, QUnitOut, OpMode, PartLoadFrac);
2714 714 : unitVent.PartLoadFrac = PartLoadFrac;
2715 714 : unitVent.FanPartLoadRatio = PartLoadFrac;
2716 :
2717 : } else { // Not a cycling operating mode
2718 :
2719 : {
2720 23502 : switch (unitVent.HCoilType) {
2721 17535 : case HeatCoilType::Water: {
2722 : // control water flow to obtain output matching QZnReq
2723 52605 : ControlCompOutput(state,
2724 : unitVent.Name,
2725 17535 : state.dataUnitVentilators->cMO_UnitVentilator,
2726 : UnitVentNum,
2727 : FirstHVACIteration,
2728 17535 : state.dataUnitVentilators->QZnReq,
2729 : ControlNode,
2730 : MaxWaterFlow,
2731 : MinWaterFlow,
2732 : ControlOffset,
2733 : unitVent.ControlCompTypeNum,
2734 : unitVent.CompErrIndex,
2735 : _,
2736 : _,
2737 : _,
2738 : _,
2739 : _,
2740 : unitVent.HWplantLoc);
2741 17535 : } break;
2742 5967 : case HeatCoilType::Gas:
2743 : case HeatCoilType::Electric:
2744 : case HeatCoilType::Steam: {
2745 5967 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, QUnitOut);
2746 5967 : } break;
2747 0 : default: {
2748 0 : assert(false);
2749 : } break;
2750 : }
2751 : }
2752 : }
2753 : } // Coil/no coil block
2754 :
2755 : } else { // COOLING MODE
2756 :
2757 38161 : ControlNode = unitVent.ColdControlNode;
2758 38161 : ControlOffset = unitVent.ColdControlOffset;
2759 38161 : MaxWaterFlow = unitVent.MaxColdWaterFlow;
2760 38161 : MinWaterFlow = unitVent.MinColdWaterFlow;
2761 : // On the first HVAC iteration the system values are given to the controller, but after that
2762 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
2763 38161 : if ((!FirstHVACIteration) && (ControlNode > 0) && (unitVent.CCoilPresent)) {
2764 8201 : MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
2765 8201 : MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
2766 : }
2767 38161 : state.dataUnitVentilators->HCoilOn = false;
2768 :
2769 38161 : Tinlet = inletNode.Temp;
2770 38161 : Toutdoor = outsideAirNode.Temp;
2771 :
2772 38161 : if (outsideAirNode.MassFlowRate > 0.0) {
2773 76322 : MinOAFrac = ScheduleManager::GetCurrentScheduleValue(state, unitVent.MinOASchedPtr) *
2774 38161 : (unitVent.MinOutAirMassFlow / outsideAirNode.MassFlowRate);
2775 : } else {
2776 0 : MinOAFrac = 0.0;
2777 : }
2778 38161 : MinOAFrac = min(1.0, max(0.0, MinOAFrac));
2779 :
2780 38161 : if ((!unitVent.CCoilPresent) || (unitVent.CCoilSchedValue <= 0.0)) {
2781 : // In cooling mode, but there is no coil to provide cooling. This is handled
2782 : // differently than if there was a cooling coil present. Fixed temperature
2783 : // will still try to vary the amount of outside air to meet the desired
2784 : // mixed air temperature, while variable percent will go to full ventilation
2785 : // when it is most advantageous.
2786 : {
2787 24471 : switch (unitVent.OAControlType) {
2788 2934 : case OAControl::FixedAmount: {
2789 : // In this control type, the outdoor air flow rate is fixed to the maximum value
2790 : // which is equal to the minimum value, regardless of all the other conditions.
2791 2934 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2792 2934 : } break;
2793 21537 : case OAControl::VariablePercent: {
2794 21537 : state.dataUnitVentilators->OAMassFlowRate =
2795 21537 : SetOAMassFlowRateForCoolingVariablePercent(state,
2796 : UnitVentNum,
2797 : MinOAFrac,
2798 : outsideAirNode.MassFlowRate,
2799 : ScheduleManager::GetCurrentScheduleValue(state, unitVent.MaxOASchedPtr),
2800 : Tinlet,
2801 : Toutdoor);
2802 21537 : } break;
2803 0 : case OAControl::FixedTemperature: {
2804 : // This is basically the same algorithm as for the heating case...
2805 0 : Tdesired = ScheduleManager::GetCurrentScheduleValue(state, unitVent.TempSchedPtr);
2806 0 : MaxOAFrac = 1.0;
2807 :
2808 0 : if (std::abs(Tinlet - Toutdoor) <= LowTempDiff) { // no difference in indoor and outdoor conditions-->set OA to minimum
2809 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2810 0 : } else if (std::abs(MaxOAFrac - MinOAFrac) <= LowOAFracDiff) { // no difference in outside air fractions
2811 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2812 0 : } else if (((Tdesired <= Tinlet) && (Tdesired >= Toutdoor)) || ((Tdesired >= Tinlet) && (Tdesired <= Toutdoor))) {
2813 : // Desired temperature is between the inlet and outdoor temperatures
2814 : // so vary the flow rate between no outside air and no recirculation air
2815 : // then applying the maximum and minimum limits the user has scheduled
2816 : // to make sure too much/little outside air is being introduced
2817 0 : state.dataUnitVentilators->OAMassFlowRate = ((Tdesired - Tinlet) / (Toutdoor - Tinlet)) * inletNode.MassFlowRate;
2818 0 : state.dataUnitVentilators->OAMassFlowRate =
2819 0 : max(state.dataUnitVentilators->OAMassFlowRate, (MinOAFrac * outsideAirNode.MassFlowRate));
2820 0 : state.dataUnitVentilators->OAMassFlowRate =
2821 0 : min(state.dataUnitVentilators->OAMassFlowRate, (MaxOAFrac * outsideAirNode.MassFlowRate));
2822 0 : } else if ((Tdesired < Tinlet) && (Tdesired < Toutdoor)) {
2823 : // Desired temperature is below both the inlet and outdoor temperatures
2824 : // so use whichever flow rate (max or min) that will get closer
2825 0 : if (Tinlet < Toutdoor) { // Tinlet closer to Tdesired so use minimum outside air
2826 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2827 : } else { // Toutdoor closer to Tdesired so use maximum outside air
2828 0 : state.dataUnitVentilators->OAMassFlowRate = MaxOAFrac * outsideAirNode.MassFlowRate;
2829 : }
2830 0 : } else if ((Tdesired > Tinlet) && (Tdesired > Toutdoor)) {
2831 : // Desired temperature is above both the inlet and outdoor temperatures
2832 : // so use whichever flow rate (max or min) that will get closer
2833 0 : if (Tinlet > Toutdoor) { // Tinlet closer to Tdesired so use minimum outside air
2834 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2835 : } else { // Toutdoor closer to Tdesired so use maximum outside air
2836 0 : state.dataUnitVentilators->OAMassFlowRate = MaxOAFrac * outsideAirNode.MassFlowRate;
2837 : }
2838 : } else {
2839 : // It should NEVER get to this point, but just in case...
2840 0 : ShowFatalError(state, "ZoneHVAC:UnitVentilator simulation control: illogical condition for " + unitVent.Name);
2841 : }
2842 0 : } break;
2843 0 : default: {
2844 0 : assert(false);
2845 : } break;
2846 : }
2847 : }
2848 :
2849 48942 : if (OpMode == DataHVACGlobals::CycFanCycCoil) {
2850 0 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, QUnitOut, OpMode, PartLoadFrac);
2851 0 : if (inletNode.MassFlowRateMax > 0.0) {
2852 0 : unitVent.FanPartLoadRatio = inletNode.MassFlowRate / inletNode.MassFlowRateMax;
2853 : }
2854 : } else {
2855 24471 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, QUnitOut);
2856 : }
2857 :
2858 : } else {
2859 : // There is a cooling load and there is a cooling coil present (presumably).
2860 : // Variable percent will throttle outside air back to the minimum while
2861 : // fixed temperature will still try to vary the outside air amount to meet
2862 : // the desired mixed air temperature.
2863 :
2864 : {
2865 13690 : switch (unitVent.OAControlType) {
2866 1222 : case OAControl::FixedAmount: {
2867 : // In this control type, the outdoor air flow rate is fixed to the maximum value
2868 : // which is equal to the minimum value, regardless of all the other conditions.
2869 1222 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2870 1222 : } break;
2871 12468 : case OAControl::VariablePercent: {
2872 12468 : state.dataUnitVentilators->OAMassFlowRate =
2873 12468 : SetOAMassFlowRateForCoolingVariablePercent(state,
2874 : UnitVentNum,
2875 : MinOAFrac,
2876 : outsideAirNode.MassFlowRate,
2877 : ScheduleManager::GetCurrentScheduleValue(state, unitVent.MaxOASchedPtr),
2878 : Tinlet,
2879 : Toutdoor);
2880 12468 : } break;
2881 0 : case OAControl::FixedTemperature: {
2882 : // This is basically the same algorithm as for the heating case...
2883 0 : Tdesired = ScheduleManager::GetCurrentScheduleValue(state, unitVent.TempSchedPtr);
2884 :
2885 0 : MaxOAFrac = 1.0;
2886 :
2887 0 : if (std::abs(Tinlet - Toutdoor) <= LowTempDiff) { // no difference in indoor and outdoor conditions-->set OA to minimum
2888 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2889 0 : } else if (std::abs(MaxOAFrac - MinOAFrac) <= LowOAFracDiff) { // no difference in outside air fractions
2890 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2891 0 : } else if (((Tdesired <= Tinlet) && (Tdesired >= Toutdoor)) || ((Tdesired >= Tinlet) && (Tdesired <= Toutdoor))) {
2892 : // Desired temperature is between the inlet and outdoor temperatures
2893 : // so vary the flow rate between no outside air and no recirculation air
2894 : // then applying the maximum and minimum limits the user has scheduled
2895 : // to make sure too much/little outside air is being introduced
2896 0 : state.dataUnitVentilators->OAMassFlowRate = ((Tdesired - Tinlet) / (Toutdoor - Tinlet)) * inletNode.MassFlowRate;
2897 0 : state.dataUnitVentilators->OAMassFlowRate =
2898 0 : max(state.dataUnitVentilators->OAMassFlowRate, (MinOAFrac * outsideAirNode.MassFlowRate));
2899 0 : state.dataUnitVentilators->OAMassFlowRate =
2900 0 : min(state.dataUnitVentilators->OAMassFlowRate, (MaxOAFrac * outsideAirNode.MassFlowRate));
2901 0 : } else if ((Tdesired < Tinlet) && (Tdesired < Toutdoor)) {
2902 : // Desired temperature is below both the inlet and outdoor temperatures
2903 : // so use whichever flow rate (max or min) that will get closer
2904 0 : if (Tinlet < Toutdoor) { // Tinlet closer to Tdesired so use minimum outside air
2905 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2906 : } else { // Toutdoor closer to Tdesired so use maximum outside air
2907 0 : state.dataUnitVentilators->OAMassFlowRate = MaxOAFrac * outsideAirNode.MassFlowRate;
2908 : }
2909 0 : } else if ((Tdesired > Tinlet) && (Tdesired > Toutdoor)) {
2910 : // Desired temperature is above both the inlet and outdoor temperatures
2911 : // so use whichever flow rate (max or min) that will get closer
2912 0 : if (Tinlet > Toutdoor) { // Tinlet closer to Tdesired so use minimum outside air
2913 0 : state.dataUnitVentilators->OAMassFlowRate = MinOAFrac * outsideAirNode.MassFlowRate;
2914 : } else { // Toutdoor closer to Tdesired so use maximum outside air
2915 0 : state.dataUnitVentilators->OAMassFlowRate = MaxOAFrac * outsideAirNode.MassFlowRate;
2916 : }
2917 : } else {
2918 : // It should NEVER get to this point, but just in case...
2919 0 : ShowFatalError(state, "ZoneHVAC:UnitVentilator simulation control: illogical condition for " + unitVent.Name);
2920 : }
2921 0 : } break;
2922 0 : default: {
2923 0 : assert(false);
2924 : } break;
2925 : }
2926 : }
2927 :
2928 13690 : if (OpMode == DataHVACGlobals::CycFanCycCoil) {
2929 :
2930 1236 : state.dataUnitVentilators->HCoilOn = false;
2931 : // Find part load ratio of unit ventilator coils
2932 1236 : PartLoadFrac = 0.0;
2933 1236 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, NoOutput, OpMode, PartLoadFrac);
2934 1236 : if ((NoOutput - state.dataUnitVentilators->QZnReq) > DataHVACGlobals::SmallLoad) {
2935 : // Unit ventilator is unable to meet the load with coil off, set PLR = 1
2936 1236 : PartLoadFrac = 1.0;
2937 1236 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, FullOutput, OpMode, PartLoadFrac);
2938 1236 : if ((FullOutput - state.dataUnitVentilators->QZnReq) < DataHVACGlobals::SmallLoad) {
2939 : // Unit ventilator full load capacity is able to meet the load, Find PLR
2940 : // Tolerance is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
2941 29016 : auto f = [&state, UnitVentNum, FirstHVACIteration, OpMode](Real64 const PartLoadRatio) {
2942 4836 : Real64 QUnitOut = 0.0; // heating/Cooling provided by unit ventilator [watts]
2943 :
2944 : // Convert parameters to usable variables
2945 14508 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, QUnitOut, OpMode, PartLoadRatio);
2946 4836 : if (state.dataUnitVentilators->QZnReq) {
2947 14508 : return (QUnitOut - state.dataUnitVentilators->QZnReq) / state.dataUnitVentilators->QZnReq;
2948 : }
2949 0 : return 0.0;
2950 1008 : };
2951 1008 : General::SolveRoot(state, 0.001, MaxIter, SolFlag, PartLoadFrac, f, 0.0, 1.0);
2952 : }
2953 : }
2954 1236 : CalcUnitVentilatorComponents(state, UnitVentNum, FirstHVACIteration, QUnitOut, OpMode, PartLoadFrac);
2955 1236 : unitVent.PartLoadFrac = PartLoadFrac;
2956 1236 : unitVent.FanPartLoadRatio = PartLoadFrac;
2957 :
2958 : } else { // NOT a cycling operating mode
2959 : // control water flow to obtain output matching QZnReq
2960 12454 : state.dataUnitVentilators->HCoilOn = false;
2961 37362 : ControlCompOutput(state,
2962 : unitVent.Name,
2963 12454 : state.dataUnitVentilators->cMO_UnitVentilator,
2964 : UnitVentNum,
2965 : FirstHVACIteration,
2966 12454 : state.dataUnitVentilators->QZnReq,
2967 : ControlNode,
2968 : MaxWaterFlow,
2969 : MinWaterFlow,
2970 : ControlOffset,
2971 : unitVent.ControlCompTypeNum,
2972 : unitVent.CompErrIndex,
2973 : _,
2974 : _,
2975 : _,
2976 : _,
2977 : _,
2978 : unitVent.CWPlantLoc);
2979 :
2980 : } // end from IF (OpMode .EQ. DataHVACGlobals::CycFanCycCoil) THEN
2981 : }
2982 :
2983 : } // ...end of HEATING/COOLING IF-THEN block
2984 :
2985 63463 : AirMassFlow = outletNode.MassFlowRate;
2986 63463 : QUnitOut = AirMassFlow *
2987 63463 : (Psychrometrics::PsyHFnTdbW(outletNode.Temp, inletNode.HumRat) - Psychrometrics::PsyHFnTdbW(inletNode.Temp, inletNode.HumRat));
2988 :
2989 : } // ...end of unit ON/OFF IF-THEN block
2990 :
2991 165565 : Real64 QTotUnitOut = AirMassFlow * (outletNode.Enthalpy - inletNode.Enthalpy);
2992 :
2993 : // Report variables...
2994 165565 : unitVent.HeatPower = max(0.0, QUnitOut);
2995 165565 : unitVent.SensCoolPower = std::abs(min(0.0, QUnitOut));
2996 165565 : unitVent.TotCoolPower = std::abs(min(0.0, QTotUnitOut));
2997 165565 : if (unitVent.FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
2998 100280 : unitVent.ElecPower = Fans::GetFanPower(state, unitVent.Fan_Index);
2999 : } else {
3000 65285 : unitVent.ElecPower = state.dataHVACFan->fanObjs[unitVent.Fan_Index]->fanPower();
3001 : }
3002 :
3003 165565 : PowerMet = QUnitOut;
3004 165565 : LatOutputProvided = AirMassFlow * (outletNode.HumRat - inletNode.HumRat); // Latent rate (kg/s), dehumid = negative;
3005 165565 : }
3006 :
3007 500606 : void CalcUnitVentilatorComponents(EnergyPlusData &state,
3008 : int const UnitVentNum, // Unit index in unit ventilator array
3009 : bool const FirstHVACIteration, // flag for 1st HVAV iteration in the time step
3010 : Real64 &LoadMet, // load met by unit (watts)
3011 : Optional_int_const OpMode, // Fan Type
3012 : Optional<Real64 const> PartLoadFrac // Part Load Ratio of coil and fan
3013 : )
3014 : {
3015 :
3016 : // SUBROUTINE INFORMATION:
3017 : // AUTHOR Rick Strand
3018 : // DATE WRITTEN May 2000
3019 : // MODIFIED July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
3020 :
3021 : // PURPOSE OF THIS SUBROUTINE:
3022 : // This subroutine launches the individual component simulations.
3023 : // This is called either when the unit is off to carry null conditions
3024 : // through the unit or during control iterations to continue updating
3025 : // what is going on within the unit.
3026 :
3027 : // METHODOLOGY EMPLOYED:
3028 : // Simply calls the different components in order. Only slight wrinkles
3029 : // here are that the unit ventilator has it's own outside air mixer and
3030 : // that a cooling coil must be present in order to call a cooling coil
3031 : // simulation. Other than that, the subroutine is very straightforward.
3032 :
3033 500606 : auto &ZoneCompTurnFansOff = state.dataHVACGlobal->ZoneCompTurnFansOff;
3034 500606 : auto &ZoneCompTurnFansOn = state.dataHVACGlobal->ZoneCompTurnFansOn;
3035 500606 : auto &unitVent = state.dataUnitVentilators->UnitVent(UnitVentNum);
3036 :
3037 : Real64 mdot; // hot water or steam mass flow rate for current time step
3038 :
3039 500606 : auto &inletNode = state.dataLoopNodes->Node(unitVent.AirInNode);
3040 500606 : auto &outletNode = state.dataLoopNodes->Node(unitVent.AirOutNode);
3041 500606 : state.dataUnitVentilators->ZoneNode = state.dataZoneEquip->ZoneEquipConfig(unitVent.ZonePtr).ZoneNode;
3042 500606 : Real64 QCoilReq = state.dataUnitVentilators->QZnReq;
3043 :
3044 500606 : if (OpMode != DataHVACGlobals::CycFanCycCoil) {
3045 :
3046 480782 : if (unitVent.ATMixerExists) {
3047 142415 : state.dataUnitVentilators->ATMixOutNode = unitVent.ATMixerOutNode;
3048 142415 : state.dataUnitVentilators->ATMixerPriNode = unitVent.ATMixerPriNode;
3049 142415 : if (unitVent.ATMixerType == DataHVACGlobals::ATMixer_InletSide) {
3050 : // set the primary air inlet mass flow rate
3051 104332 : state.dataLoopNodes->Node(state.dataUnitVentilators->ATMixerPriNode).MassFlowRate =
3052 208664 : min(min(state.dataLoopNodes->Node(state.dataUnitVentilators->ATMixerPriNode).MassFlowRateMaxAvail,
3053 104332 : state.dataUnitVentilators->OAMassFlowRate),
3054 : inletNode.MassFlowRate);
3055 : // now calculate the the mixer outlet conditions (and the secondary air inlet flow rate)
3056 104332 : SingleDuct::SimATMixer(state, unitVent.ATMixerName, FirstHVACIteration, unitVent.ATMixerIndex);
3057 : }
3058 : } else {
3059 338367 : SimUnitVentOAMixer(state, UnitVentNum, OpMode);
3060 : }
3061 480782 : if (unitVent.FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
3062 321651 : Fans::SimulateFanComponents(
3063 : state, unitVent.FanName, FirstHVACIteration, unitVent.Fan_Index, _, ZoneCompTurnFansOn, ZoneCompTurnFansOff);
3064 : } else {
3065 159131 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // used for cycling fan, set to 1.0 to be sure
3066 159131 : state.dataHVACFan->fanObjs[unitVent.Fan_Index]->simulate(state, _, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _);
3067 : }
3068 :
3069 480782 : if (unitVent.CCoilPresent) {
3070 223572 : if (unitVent.CCoilType == CoolCoilType::HXAssisted) {
3071 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
3072 : unitVent.CCoilName,
3073 : FirstHVACIteration,
3074 : DataHVACGlobals::CompressorOperation::On,
3075 : 0.0,
3076 : unitVent.CCoil_Index,
3077 : DataHVACGlobals::ContFanCycCoil);
3078 : } else {
3079 223572 : WaterCoils::SimulateWaterCoilComponents(state, unitVent.CCoilName, FirstHVACIteration, unitVent.CCoil_Index);
3080 : }
3081 : }
3082 :
3083 480782 : if (unitVent.HCoilPresent) {
3084 :
3085 : {
3086 469936 : switch (unitVent.HCoilType) {
3087 354653 : case HeatCoilType::Water: {
3088 354653 : WaterCoils::SimulateWaterCoilComponents(state, unitVent.HCoilName, FirstHVACIteration, unitVent.HCoil_Index);
3089 354653 : } break;
3090 0 : case HeatCoilType::Steam: {
3091 0 : if (!state.dataUnitVentilators->HCoilOn) {
3092 0 : QCoilReq = 0.0;
3093 : } else {
3094 0 : int HCoilInAirNode = unitVent.FanOutletNode;
3095 0 : Real64 CpAirZn = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(unitVent.AirInNode).HumRat);
3096 0 : QCoilReq = state.dataUnitVentilators->QZnReq -
3097 0 : state.dataLoopNodes->Node(HCoilInAirNode).MassFlowRate * CpAirZn *
3098 0 : (state.dataLoopNodes->Node(HCoilInAirNode).Temp - state.dataLoopNodes->Node(unitVent.AirInNode).Temp);
3099 : }
3100 :
3101 0 : if (QCoilReq < 0.0) QCoilReq = 0.0; // a heating coil can only heat, not cool
3102 :
3103 0 : SteamCoils::SimulateSteamCoilComponents(state, unitVent.HCoilName, FirstHVACIteration, unitVent.HCoil_Index, QCoilReq);
3104 0 : } break;
3105 115283 : case HeatCoilType::Electric:
3106 : case HeatCoilType::Gas: {
3107 115283 : if (!state.dataUnitVentilators->HCoilOn) {
3108 109316 : QCoilReq = 0.0;
3109 : } else {
3110 5967 : int HCoilInAirNode = unitVent.FanOutletNode;
3111 5967 : Real64 CpAirZn = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(unitVent.AirInNode).HumRat);
3112 11934 : QCoilReq = state.dataUnitVentilators->QZnReq -
3113 11934 : state.dataLoopNodes->Node(HCoilInAirNode).MassFlowRate * CpAirZn *
3114 5967 : (state.dataLoopNodes->Node(HCoilInAirNode).Temp - state.dataLoopNodes->Node(unitVent.AirInNode).Temp);
3115 : }
3116 :
3117 115283 : if (QCoilReq < 0.0) QCoilReq = 0.0; // a heating coil can only heat, not cool
3118 :
3119 115283 : HeatingCoils::SimulateHeatingCoilComponents(state, unitVent.HCoilName, FirstHVACIteration, QCoilReq, unitVent.HCoil_Index);
3120 115283 : } break;
3121 0 : default: {
3122 0 : assert(false);
3123 : } break;
3124 : }
3125 : }
3126 :
3127 : } // (UnitVent(UnitVentNum)%HCoilPresent)
3128 :
3129 : } else { // Fan is Fan:OnOff and is cycling
3130 :
3131 19824 : inletNode.MassFlowRate = inletNode.MassFlowRateMax * PartLoadFrac;
3132 : // Set the fan inlet node maximum available mass flow rates for cycling fans
3133 19824 : inletNode.MassFlowRateMaxAvail = inletNode.MassFlowRate;
3134 :
3135 19824 : if (unitVent.ATMixerExists) {
3136 0 : state.dataUnitVentilators->ATMixOutNode = unitVent.ATMixerOutNode;
3137 0 : state.dataUnitVentilators->ATMixerPriNode = unitVent.ATMixerPriNode;
3138 0 : if (unitVent.ATMixerType == DataHVACGlobals::ATMixer_InletSide) {
3139 : // set the primary air inlet mass flow rate
3140 0 : state.dataLoopNodes->Node(state.dataUnitVentilators->ATMixerPriNode).MassFlowRate =
3141 0 : min(min(state.dataLoopNodes->Node(state.dataUnitVentilators->ATMixerPriNode).MassFlowRateMaxAvail,
3142 0 : state.dataUnitVentilators->OAMassFlowRate),
3143 : inletNode.MassFlowRate);
3144 : // now calculate the mixer outlet conditions (and the secondary air inlet flow rate)
3145 0 : SingleDuct::SimATMixer(state, unitVent.ATMixerName, FirstHVACIteration, unitVent.ATMixerIndex);
3146 : }
3147 : } else {
3148 19824 : SimUnitVentOAMixer(state, UnitVentNum, OpMode);
3149 : }
3150 19824 : if (unitVent.FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
3151 0 : Fans::SimulateFanComponents(
3152 : state, unitVent.FanName, FirstHVACIteration, unitVent.Fan_Index, _, ZoneCompTurnFansOn, ZoneCompTurnFansOff);
3153 : } else {
3154 19824 : state.dataHVACFan->fanObjs[unitVent.Fan_Index]->simulate(state, _, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _);
3155 : }
3156 :
3157 19824 : if (unitVent.CCoilPresent) {
3158 :
3159 : // where is mdot set ?
3160 19824 : CalcMdotCCoilCycFan(state, mdot, QCoilReq, state.dataUnitVentilators->QZnReq, UnitVentNum, PartLoadFrac);
3161 19824 : PlantUtilities::SetComponentFlowRate(state, mdot, unitVent.ColdControlNode, unitVent.ColdCoilOutNodeNum, unitVent.CWPlantLoc);
3162 :
3163 19824 : if (unitVent.CCoilType == CoolCoilType::HXAssisted) {
3164 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
3165 : unitVent.CCoilName,
3166 : FirstHVACIteration,
3167 : DataHVACGlobals::CompressorOperation::On,
3168 : PartLoadFrac,
3169 : unitVent.CCoil_Index,
3170 0 : OpMode);
3171 : } else {
3172 19824 : WaterCoils::SimulateWaterCoilComponents(
3173 : state, unitVent.CCoilName, FirstHVACIteration, unitVent.CCoil_Index, QCoilReq, OpMode, PartLoadFrac);
3174 : }
3175 : }
3176 :
3177 19824 : if (unitVent.HCoilPresent) {
3178 :
3179 : {
3180 19824 : switch (unitVent.HCoilType) {
3181 19824 : case HeatCoilType::Water: {
3182 19824 : if (!state.dataUnitVentilators->HCoilOn) {
3183 13104 : QCoilReq = 0.0;
3184 13104 : mdot = 0.0;
3185 : } else {
3186 6720 : int HCoilInAirNode = unitVent.FanOutletNode;
3187 6720 : Real64 CpAirZn = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(unitVent.AirInNode).HumRat);
3188 13440 : QCoilReq = state.dataUnitVentilators->QZnReq -
3189 13440 : state.dataLoopNodes->Node(HCoilInAirNode).MassFlowRate * CpAirZn *
3190 6720 : (state.dataLoopNodes->Node(HCoilInAirNode).Temp - state.dataLoopNodes->Node(unitVent.AirInNode).Temp);
3191 6720 : mdot = unitVent.MaxHotWaterFlow * PartLoadFrac;
3192 : }
3193 :
3194 19824 : if (QCoilReq < 0.0) QCoilReq = 0.0; // a heating coil can only heat, not cool
3195 19824 : PlantUtilities::SetComponentFlowRate(state, mdot, unitVent.HotControlNode, unitVent.HotCoilOutNodeNum, unitVent.HWplantLoc);
3196 19824 : WaterCoils::SimulateWaterCoilComponents(
3197 : state, unitVent.HCoilName, FirstHVACIteration, unitVent.HCoil_Index, QCoilReq, OpMode, PartLoadFrac);
3198 19824 : } break;
3199 0 : case HeatCoilType::Steam: {
3200 0 : if (!state.dataUnitVentilators->HCoilOn) {
3201 0 : QCoilReq = 0.0;
3202 0 : mdot = 0.0;
3203 : } else {
3204 0 : int HCoilInAirNode = unitVent.FanOutletNode;
3205 0 : Real64 CpAirZn = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(unitVent.AirInNode).HumRat);
3206 0 : QCoilReq = state.dataUnitVentilators->QZnReq -
3207 0 : state.dataLoopNodes->Node(HCoilInAirNode).MassFlowRate * CpAirZn *
3208 0 : (state.dataLoopNodes->Node(HCoilInAirNode).Temp - state.dataLoopNodes->Node(unitVent.AirInNode).Temp);
3209 0 : mdot = unitVent.MaxHotSteamFlow * PartLoadFrac;
3210 : }
3211 :
3212 0 : if (QCoilReq < 0.0) QCoilReq = 0.0;
3213 0 : PlantUtilities::SetComponentFlowRate(state, mdot, unitVent.HotControlNode, unitVent.HotCoilOutNodeNum, unitVent.HWplantLoc);
3214 0 : SteamCoils::SimulateSteamCoilComponents(
3215 : state, unitVent.HCoilName, FirstHVACIteration, unitVent.HCoil_Index, QCoilReq, _, OpMode, PartLoadFrac);
3216 0 : } break;
3217 0 : case HeatCoilType::Electric:
3218 : case HeatCoilType::Gas: {
3219 0 : if (!state.dataUnitVentilators->HCoilOn) {
3220 0 : QCoilReq = 0.0;
3221 : } else {
3222 0 : int HCoilInAirNode = unitVent.FanOutletNode;
3223 0 : Real64 CpAirZn = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(unitVent.AirInNode).HumRat);
3224 0 : QCoilReq = state.dataUnitVentilators->QZnReq -
3225 0 : state.dataLoopNodes->Node(HCoilInAirNode).MassFlowRate * CpAirZn *
3226 0 : (state.dataLoopNodes->Node(HCoilInAirNode).Temp - state.dataLoopNodes->Node(unitVent.AirInNode).Temp);
3227 : }
3228 0 : if (QCoilReq < 0.0) QCoilReq = 0.0;
3229 0 : HeatingCoils::SimulateHeatingCoilComponents(
3230 : state, unitVent.HCoilName, FirstHVACIteration, QCoilReq, unitVent.HCoil_Index, _, _, OpMode, PartLoadFrac);
3231 0 : } break;
3232 0 : default: {
3233 0 : assert(false);
3234 : } break;
3235 : }
3236 : }
3237 : }
3238 : }
3239 500606 : Real64 AirMassFlow = outletNode.MassFlowRate;
3240 : // calculate delivered load
3241 500606 : if (unitVent.ATMixerExists) {
3242 142415 : auto &ATMixOutNode(state.dataLoopNodes->Node(state.dataUnitVentilators->ATMixOutNode));
3243 142415 : auto &ATMixerPriNode(state.dataLoopNodes->Node(state.dataUnitVentilators->ATMixerPriNode));
3244 142415 : if (unitVent.ATMixerType == DataHVACGlobals::ATMixer_SupplySide) {
3245 : // set the primary air inlet mass flow rate
3246 38083 : ATMixerPriNode.MassFlowRate = min(ATMixerPriNode.MassFlowRateMaxAvail, state.dataUnitVentilators->OAMassFlowRate);
3247 : // now calculate the the mixer outlet conditions (and the secondary air inlet flow rate)
3248 38083 : SingleDuct::SimATMixer(state, unitVent.ATMixerName, FirstHVACIteration, unitVent.ATMixerIndex);
3249 38083 : Real64 SpecHumMin = min(ATMixOutNode.HumRat, inletNode.HumRat); // (kg moisture / kg moist air)
3250 76166 : LoadMet = ATMixOutNode.MassFlowRate *
3251 38083 : (Psychrometrics::PsyHFnTdbW(ATMixOutNode.Temp, SpecHumMin) - Psychrometrics::PsyHFnTdbW(inletNode.Temp, SpecHumMin));
3252 : } else {
3253 : // ATM Mixer on inlet side
3254 104332 : auto &zoneNode(state.dataLoopNodes->Node(state.dataUnitVentilators->ZoneNode));
3255 104332 : LoadMet = AirMassFlow *
3256 104332 : (Psychrometrics::PsyHFnTdbW(outletNode.Temp, zoneNode.HumRat) - Psychrometrics::PsyHFnTdbW(zoneNode.Temp, zoneNode.HumRat));
3257 : }
3258 : } else {
3259 358191 : LoadMet = AirMassFlow *
3260 358191 : (Psychrometrics::PsyHFnTdbW(outletNode.Temp, inletNode.HumRat) - Psychrometrics::PsyHFnTdbW(inletNode.Temp, inletNode.HumRat));
3261 : }
3262 500606 : }
3263 :
3264 358191 : void SimUnitVentOAMixer(EnergyPlusData &state,
3265 : int const UnitVentNum, // Unit index in unit ventilator array
3266 : int const FanOpMode // unit ventilator fan operating mode
3267 : )
3268 : {
3269 :
3270 : // SUBROUTINE INFORMATION:
3271 : // AUTHOR Rick Strand
3272 : // DATE WRITTEN May 2000
3273 :
3274 : // PURPOSE OF THIS SUBROUTINE:
3275 : // This responsibility of this subroutine is to set the air flow rates
3276 : // through the mixing box portion of the unit ventilator and then perform
3277 : // an energy balance to arrive at outlet conditions which then would
3278 : // serve as inlet conditions to the coils (or outlet conditions for
3279 : // the device). There is some question as to whether this needs to be
3280 : // called every time the coils and fan are called since how the fans and
3281 : // coil operate won't presumable change how the mixer operates. The
3282 : // method in which this routine is called is slightly cleaner though
3283 : // from a code readability standpoint though less efficient.
3284 :
3285 : // METHODOLOGY EMPLOYED:
3286 : // The OAMassFlowRate has already been calculated in the main control
3287 : // algorithm. Use this flow rate to establish all of the other flow
3288 : // rates and perform an energy balance on the mixing of the return and
3289 : // outdoor air streams.
3290 :
3291 358191 : auto &unitVent = state.dataUnitVentilators->UnitVent(UnitVentNum);
3292 358191 : auto &airRelNode = state.dataLoopNodes->Node(unitVent.AirReliefNode);
3293 358191 : auto &inletNode = state.dataLoopNodes->Node(unitVent.AirInNode);
3294 358191 : auto &OAMixOutNode = state.dataLoopNodes->Node(unitVent.OAMixerOutNode);
3295 358191 : auto &outsideAirNode = state.dataLoopNodes->Node(unitVent.OutsideAirNode);
3296 358191 : Real64 OutAirMassFlowRate = state.dataUnitVentilators->OAMassFlowRate;
3297 :
3298 : // Limit the outdoor air mass flow rate if cycling fan
3299 358191 : if (FanOpMode == DataHVACGlobals::CycFanCycCoil) {
3300 19824 : OutAirMassFlowRate = min(state.dataUnitVentilators->OAMassFlowRate, inletNode.MassFlowRate);
3301 : }
3302 :
3303 : // "Resolve" the air flow rates...
3304 358191 : outsideAirNode.MassFlowRate = OutAirMassFlowRate;
3305 358191 : outsideAirNode.MassFlowRateMinAvail = OutAirMassFlowRate;
3306 358191 : outsideAirNode.MassFlowRateMaxAvail = OutAirMassFlowRate;
3307 :
3308 358191 : airRelNode.MassFlowRate = OutAirMassFlowRate;
3309 358191 : airRelNode.MassFlowRateMinAvail = OutAirMassFlowRate;
3310 358191 : airRelNode.MassFlowRateMaxAvail = OutAirMassFlowRate;
3311 :
3312 358191 : OAMixOutNode.MassFlowRate = inletNode.MassFlowRate;
3313 358191 : OAMixOutNode.MassFlowRateMinAvail = inletNode.MassFlowRate;
3314 358191 : OAMixOutNode.MassFlowRateMaxAvail = inletNode.MassFlowRate;
3315 :
3316 : // "Inlet" conditions for InletNode and OutsideAirNode have already
3317 : // been set elsewhere so we just need to set the "outlet" conditions
3318 358191 : airRelNode.Temp = inletNode.Temp;
3319 358191 : airRelNode.Press = inletNode.Press;
3320 358191 : airRelNode.HumRat = inletNode.HumRat;
3321 358191 : airRelNode.Enthalpy = inletNode.Enthalpy;
3322 :
3323 358191 : Real64 OAFraction = 0.0; // Outside air fraction of inlet air
3324 358191 : if (inletNode.MassFlowRate > 0.0) {
3325 278736 : OAFraction = outsideAirNode.MassFlowRate / inletNode.MassFlowRate;
3326 : }
3327 :
3328 : // Perform an energy and moisture mass balance on the mixing portion of the unit ventilator
3329 358191 : OAMixOutNode.Enthalpy = OAFraction * outsideAirNode.Enthalpy + (1.0 - OAFraction) * inletNode.Enthalpy;
3330 358191 : OAMixOutNode.HumRat = OAFraction * outsideAirNode.HumRat + (1.0 - OAFraction) * inletNode.HumRat;
3331 :
3332 : // Find the other key state points based on calculated conditions
3333 358191 : OAMixOutNode.Temp = Psychrometrics::PsyTdbFnHW(OAMixOutNode.Enthalpy, OAMixOutNode.HumRat);
3334 358191 : OAMixOutNode.Press = inletNode.Press;
3335 :
3336 358191 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
3337 0 : airRelNode.CO2 = inletNode.CO2;
3338 0 : OAMixOutNode.CO2 = OAFraction * outsideAirNode.CO2 + (1.0 - OAFraction) * inletNode.CO2;
3339 : }
3340 358191 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
3341 0 : airRelNode.GenContam = inletNode.GenContam;
3342 0 : OAMixOutNode.GenContam = OAFraction * outsideAirNode.GenContam + (1.0 - OAFraction) * inletNode.GenContam;
3343 : }
3344 358191 : }
3345 :
3346 165565 : void ReportUnitVentilator(EnergyPlusData &state, int const UnitVentNum) // Unit index in unit ventilator array
3347 : {
3348 :
3349 : // SUBROUTINE INFORMATION:
3350 : // AUTHOR Rick Strand
3351 : // DATE WRITTEN May 2000
3352 :
3353 : // Using/Aliasing
3354 165565 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
3355 165565 : auto &unitVent = state.dataUnitVentilators->UnitVent(UnitVentNum);
3356 :
3357 165565 : unitVent.HeatEnergy = unitVent.HeatPower * TimeStepSys * DataGlobalConstants::SecInHour;
3358 165565 : unitVent.SensCoolEnergy = unitVent.SensCoolPower * TimeStepSys * DataGlobalConstants::SecInHour;
3359 165565 : unitVent.TotCoolEnergy = unitVent.TotCoolPower * TimeStepSys * DataGlobalConstants::SecInHour;
3360 165565 : unitVent.ElecEnergy = unitVent.ElecPower * TimeStepSys * DataGlobalConstants::SecInHour;
3361 :
3362 165565 : if (unitVent.FirstPass) { // reset sizing flags so other zone equipment can size normally
3363 40 : if (!state.dataGlobal->SysSizingCalc) {
3364 25 : DataSizing::resetHVACSizingGlobals(state, state.dataSize->CurZoneEqNum, 0, unitVent.FirstPass);
3365 : }
3366 : }
3367 165565 : }
3368 :
3369 8695 : int GetUnitVentilatorOutAirNode(EnergyPlusData &state, int const UnitVentNum)
3370 : {
3371 :
3372 : // FUNCTION INFORMATION:
3373 : // AUTHOR B Griffith
3374 : // DATE WRITTEN Dec 2006
3375 :
3376 : int GetUnitVentilatorOutAirNode;
3377 :
3378 8695 : if (state.dataUnitVentilators->GetUnitVentilatorInputFlag) {
3379 0 : GetUnitVentilatorInput(state);
3380 0 : state.dataUnitVentilators->GetUnitVentilatorInputFlag = false;
3381 : }
3382 :
3383 8695 : GetUnitVentilatorOutAirNode = 0;
3384 8695 : if (UnitVentNum > 0 && UnitVentNum <= state.dataUnitVentilators->NumOfUnitVents) {
3385 8695 : GetUnitVentilatorOutAirNode = state.dataUnitVentilators->UnitVent(UnitVentNum).OutsideAirNode;
3386 : }
3387 :
3388 8695 : return GetUnitVentilatorOutAirNode;
3389 : }
3390 :
3391 8695 : int GetUnitVentilatorZoneInletAirNode(EnergyPlusData &state, int const UnitVentNum)
3392 : {
3393 :
3394 : // FUNCTION INFORMATION:
3395 : // AUTHOR B Griffith
3396 : // DATE WRITTEN Dec 2006
3397 :
3398 : int GetUnitVentilatorZoneInletAirNode;
3399 :
3400 8695 : if (state.dataUnitVentilators->GetUnitVentilatorInputFlag) {
3401 0 : GetUnitVentilatorInput(state);
3402 0 : state.dataUnitVentilators->GetUnitVentilatorInputFlag = false;
3403 : }
3404 :
3405 8695 : GetUnitVentilatorZoneInletAirNode = 0;
3406 8695 : if (UnitVentNum > 0 && UnitVentNum <= state.dataUnitVentilators->NumOfUnitVents) {
3407 8695 : GetUnitVentilatorZoneInletAirNode = state.dataUnitVentilators->UnitVent(UnitVentNum).AirOutNode;
3408 : }
3409 :
3410 8695 : return GetUnitVentilatorZoneInletAirNode;
3411 : }
3412 :
3413 8695 : int GetUnitVentilatorMixedAirNode(EnergyPlusData &state, int const UnitVentNum)
3414 : {
3415 :
3416 : // FUNCTION INFORMATION:
3417 : // AUTHOR B Griffith
3418 : // DATE WRITTEN Dec 2006
3419 :
3420 : int GetUnitVentilatorMixedAirNode;
3421 :
3422 8695 : if (state.dataUnitVentilators->GetUnitVentilatorInputFlag) {
3423 0 : GetUnitVentilatorInput(state);
3424 0 : state.dataUnitVentilators->GetUnitVentilatorInputFlag = false;
3425 : }
3426 :
3427 8695 : GetUnitVentilatorMixedAirNode = 0;
3428 8695 : if (UnitVentNum > 0 && UnitVentNum <= state.dataUnitVentilators->NumOfUnitVents) {
3429 8695 : GetUnitVentilatorMixedAirNode = state.dataUnitVentilators->UnitVent(UnitVentNum).OAMixerOutNode;
3430 : }
3431 :
3432 8695 : return GetUnitVentilatorMixedAirNode;
3433 : }
3434 :
3435 8695 : int GetUnitVentilatorReturnAirNode(EnergyPlusData &state, int const UnitVentNum)
3436 : {
3437 :
3438 : // FUNCTION INFORMATION:
3439 : // AUTHOR B Griffith
3440 : // DATE WRITTEN Dec 2006
3441 :
3442 : int GetUnitVentilatorReturnAirNode;
3443 :
3444 8695 : if (state.dataUnitVentilators->GetUnitVentilatorInputFlag) {
3445 0 : GetUnitVentilatorInput(state);
3446 0 : state.dataUnitVentilators->GetUnitVentilatorInputFlag = false;
3447 : }
3448 :
3449 8695 : GetUnitVentilatorReturnAirNode = 0;
3450 8695 : if (UnitVentNum > 0 && UnitVentNum <= state.dataUnitVentilators->NumOfUnitVents) {
3451 8695 : GetUnitVentilatorReturnAirNode = state.dataUnitVentilators->UnitVent(UnitVentNum).AirInNode;
3452 : }
3453 :
3454 8695 : return GetUnitVentilatorReturnAirNode;
3455 : }
3456 :
3457 34005 : Real64 SetOAMassFlowRateForCoolingVariablePercent(EnergyPlusData &state,
3458 : int const UnitVentNum, // Unit Ventilator index
3459 : Real64 const MinOAFrac, // Minimum Outside Air Fraction
3460 : Real64 const MassFlowRate, // Design Outside Air Mass Flow Rate
3461 : Real64 const MaxOAFrac, // Maximum Outside Air Fraction
3462 : Real64 const Tinlet, // Inlet Temperature to Unit or Zone Temperature
3463 : Real64 const Toutdoor // Outdoor Air Temperature
3464 : )
3465 : {
3466 :
3467 34005 : Real64 ActualOAMassFlowRate(0.0); // Result or return value
3468 :
3469 34005 : if (Tinlet <= Toutdoor) {
3470 :
3471 21597 : ActualOAMassFlowRate = MinOAFrac * MassFlowRate;
3472 :
3473 : } else { // Tinlet > Toutdoor
3474 : // Use cooler outside air to provide "free" cooling without over-cooling.
3475 : // First, use a simple load equals mass flow times Cp time Delta T equation to find OA Mass Flow Rate.
3476 : // This must include the enthalpy difference across the fan. Otherwise, this will potentially put a
3477 : // small load on the cooling coil (if it exists) or will leave a small load that is not met when it could be.
3478 : // Then, limit the OA Mass Flow Rate between the MinOA flow and the MaxOA flow.
3479 :
3480 12408 : auto &unitVent = state.dataUnitVentilators->UnitVent(UnitVentNum);
3481 12408 : Real64 EnthDiffAcrossFan(0.0); // Temperature difference across the fan
3482 12408 : if (!unitVent.ATMixerExists) {
3483 9886 : EnthDiffAcrossFan =
3484 9886 : state.dataLoopNodes->Node(unitVent.FanOutletNode).Enthalpy - state.dataLoopNodes->Node(unitVent.OAMixerOutNode).Enthalpy;
3485 : } else {
3486 2522 : if (unitVent.ATMixerType == DataHVACGlobals::ATMixer_InletSide) {
3487 2445 : EnthDiffAcrossFan =
3488 2445 : state.dataLoopNodes->Node(unitVent.FanOutletNode).Enthalpy - state.dataLoopNodes->Node(unitVent.ATMixerOutNode).Enthalpy;
3489 : }
3490 2522 : if (unitVent.ATMixerType == DataHVACGlobals::ATMixer_SupplySide) {
3491 77 : EnthDiffAcrossFan =
3492 77 : state.dataLoopNodes->Node(unitVent.FanOutletNode).Enthalpy - state.dataLoopNodes->Node(unitVent.AirInNode).Enthalpy;
3493 : }
3494 : }
3495 :
3496 24816 : ActualOAMassFlowRate = (std::abs(state.dataUnitVentilators->QZnReq) + (MassFlowRate * std::abs(EnthDiffAcrossFan))) /
3497 12408 : (Psychrometrics::PsyCpAirFnW(state.dataEnvrn->OutHumRat) * (Tinlet - Toutdoor));
3498 :
3499 12408 : ActualOAMassFlowRate = max(ActualOAMassFlowRate, (MinOAFrac * MassFlowRate));
3500 12408 : ActualOAMassFlowRate = min(ActualOAMassFlowRate, (MaxOAFrac * MassFlowRate));
3501 : }
3502 :
3503 34005 : return ActualOAMassFlowRate;
3504 : }
3505 :
3506 19824 : void CalcMdotCCoilCycFan(EnergyPlusData &state,
3507 : Real64 &mdot, // mass flow rate
3508 : Real64 &QCoilReq, // Remaining load to cooling coil
3509 : Real64 const QZnReq, // Zone load to setpoint
3510 : int const UnitVentNum, // Unit Ventilator index
3511 : Real64 const PartLoadRatio // Part load ratio for unit ventilator
3512 : )
3513 : {
3514 :
3515 19824 : if (QZnReq >= 0.0) { // Heating requested so no cooling coil needed
3516 8853 : mdot = 0.0;
3517 : } else { // Cooling so set first guess at flow rate
3518 10971 : mdot = state.dataUnitVentilators->UnitVent(UnitVentNum).MaxColdWaterFlow * PartLoadRatio;
3519 : }
3520 :
3521 : // Check to see what outside air will do, "turn off" cooling coil if OA can handle the load
3522 19824 : int CCoilInAirNode = state.dataUnitVentilators->UnitVent(UnitVentNum).FanOutletNode;
3523 19824 : int AirInNode = state.dataUnitVentilators->UnitVent(UnitVentNum).AirInNode;
3524 19824 : Real64 CpAirZn = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(AirInNode).HumRat);
3525 39648 : QCoilReq = QZnReq - state.dataLoopNodes->Node(CCoilInAirNode).MassFlowRate * CpAirZn *
3526 19824 : (state.dataLoopNodes->Node(CCoilInAirNode).Temp - state.dataLoopNodes->Node(AirInNode).Temp);
3527 19824 : if (QCoilReq > -DataHVACGlobals::SmallLoad) {
3528 8950 : QCoilReq = 0.0;
3529 8950 : mdot = 0.0;
3530 : }
3531 19824 : }
3532 :
3533 : } // namespace UnitVentilator
3534 :
3535 2313 : } // namespace EnergyPlus
|