Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, 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 : #include <ObjexxFCL/string.functions.hh>
55 :
56 : // EnergyPlus Headers
57 : #include <EnergyPlus/Autosizing/CoolingAirFlowSizing.hh>
58 : #include <EnergyPlus/Autosizing/CoolingCapacitySizing.hh>
59 : #include <EnergyPlus/Autosizing/HeatingAirFlowSizing.hh>
60 : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
61 : #include <EnergyPlus/Data/EnergyPlusData.hh>
62 : #include <EnergyPlus/DataContaminantBalance.hh>
63 : #include <EnergyPlus/DataEnvironment.hh>
64 : #include <EnergyPlus/DataHVACGlobals.hh>
65 : #include <EnergyPlus/DataHeatBalFanSys.hh>
66 : #include <EnergyPlus/DataHeatBalance.hh>
67 : #include <EnergyPlus/DataIPShortCuts.hh>
68 : #include <EnergyPlus/DataLoopNode.hh>
69 : #include <EnergyPlus/DataSizing.hh>
70 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
71 : #include <EnergyPlus/DataZoneEquipment.hh>
72 : #include <EnergyPlus/EMSManager.hh>
73 : #include <EnergyPlus/General.hh>
74 : #include <EnergyPlus/GeneralRoutines.hh>
75 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
76 : #include <EnergyPlus/NodeInputManager.hh>
77 : #include <EnergyPlus/OutAirNodeManager.hh>
78 : #include <EnergyPlus/OutputProcessor.hh>
79 : #include <EnergyPlus/Psychrometrics.hh>
80 : #include <EnergyPlus/PurchasedAirManager.hh>
81 : #include <EnergyPlus/ScheduleManager.hh>
82 : #include <EnergyPlus/UtilityRoutines.hh>
83 : #include <EnergyPlus/ZonePlenum.hh>
84 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
85 :
86 : namespace EnergyPlus::PurchasedAirManager {
87 :
88 : // Module containing data and routines dealing with Ideal Loads Air System (formerly PURCHASED AIR).
89 :
90 : // MODULE INFORMATION:
91 : // AUTHOR Russ Taylor
92 : // DATE WRITTEN May 1997
93 : // MODIFIED Fred Buhl Dec 1999
94 : // B. Griffith Dec 2006. added OA lookup function, moved getinputflag up to Module
95 : // M. Witte June 2011, add new features including DCV, economizer, dehumidification and humidification
96 : // NOTE: MJW Sep 13, 2011: Still need to review checks for negative loads and impossible supply temps???
97 : // There are no Deallocate statements in here - should there be?
98 : // RE-ENGINEERED na
99 :
100 : // PURPOSE OF THIS MODULE:
101 : // To encapsulate the data and algorithms required to simulate the
102 : // Zone Ideal Loads Air System component. This component supplies hot or cold air
103 : // at a fixed or variable temperature to a zone to meet the zone load.
104 : // With the June 2011 enhancements it will also supply outdoor air with optional demand-controlled ventilation
105 : // and economizer controls, plus new options for controlling zone humidity.
106 :
107 : // METHODOLOGY EMPLOYED:
108 : // The user can choose via input the max/min hot and cold supply air
109 : // temperature and humidity ratio. The air mass flow rate is chosen
110 : // to meet the (remaining) zone load or based on the outdoor air flow requirement.
111 : // If the outdoor air flow sets the flow rate, the supply air temperature and
112 : // humidity ratio are adjusted to meet the zone load.
113 :
114 : // Using/Aliasing
115 : using namespace ScheduleManager;
116 : using Psychrometrics::PsyCpAirFnW;
117 : using Psychrometrics::PsyHFnTdbW;
118 : using Psychrometrics::PsyRhoAirFnPbTdbW;
119 : using Psychrometrics::PsyTdbFnHW;
120 : using Psychrometrics::PsyTsatFnHPb;
121 : using Psychrometrics::PsyWFnTdbH;
122 : using Psychrometrics::PsyWFnTdbRhPb;
123 :
124 : // Delta humidity ratio limit, 0.00025 equals delta between 45F dewpoint and 46F dewpoint
125 : // used to prevent dividing by near zero
126 : Real64 constexpr SmallDeltaHumRat(0.00025);
127 :
128 2076247 : void SimPurchasedAir(EnergyPlusData &state,
129 : std::string const &PurchAirName,
130 : Real64 &SysOutputProvided,
131 : Real64 &MoistOutputProvided, // Moisture output provided (kg/s), dehumidification = negative
132 : bool const FirstHVACIteration,
133 : int const ControlledZoneNum,
134 : int &CompIndex)
135 : {
136 :
137 : // SUBROUTINE INFORMATION:
138 : // AUTHOR Russ Taylor
139 : // DATE WRITTEN May 1997
140 : // MODIFIED Don Shirey, Aug 2009 (LatOutputProvided - now MoistOutputProvided)
141 : // RE-ENGINEERED na
142 :
143 : // PURPOSE OF THIS SUBROUTINE:
144 : // This subroutine manages Purchased Air component simulation.
145 : // It is called from SimZoneEquipment in the ZoneEquipmentManager
146 : // at the system time step.
147 :
148 : int PurchAirNum;
149 :
150 2076247 : if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
151 78 : GetPurchasedAir(state);
152 78 : state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
153 : }
154 :
155 : // Find the correct PurchasedAir Equipment
156 2076247 : if (CompIndex == 0) {
157 219 : PurchAirNum = Util::FindItemInList(PurchAirName, state.dataPurchasedAirMgr->PurchAir);
158 219 : if (PurchAirNum == 0) {
159 0 : ShowFatalError(state, format("SimPurchasedAir: Unit not found={}", PurchAirName));
160 : }
161 219 : CompIndex = PurchAirNum;
162 : } else {
163 2076028 : PurchAirNum = CompIndex;
164 2076028 : if (PurchAirNum > state.dataPurchasedAirMgr->NumPurchAir || PurchAirNum < 1) {
165 0 : ShowFatalError(state,
166 0 : format("SimPurchasedAir: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
167 : PurchAirNum,
168 0 : state.dataPurchasedAirMgr->NumPurchAir,
169 : PurchAirName));
170 : }
171 2076028 : if (state.dataPurchasedAirMgr->CheckEquipName(PurchAirNum)) {
172 219 : if (PurchAirName != state.dataPurchasedAirMgr->PurchAir(PurchAirNum).Name) {
173 0 : ShowFatalError(state,
174 0 : format("SimPurchasedAir: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
175 : PurchAirNum,
176 : PurchAirName,
177 0 : state.dataPurchasedAirMgr->PurchAir(PurchAirNum).Name));
178 : }
179 219 : state.dataPurchasedAirMgr->CheckEquipName(PurchAirNum) = false;
180 : }
181 : }
182 :
183 2076247 : InitPurchasedAir(state, PurchAirNum, ControlledZoneNum);
184 :
185 2076247 : CalcPurchAirLoads(state, PurchAirNum, SysOutputProvided, MoistOutputProvided, ControlledZoneNum);
186 :
187 2076247 : UpdatePurchasedAir(state, PurchAirNum, FirstHVACIteration);
188 :
189 2076247 : ReportPurchasedAir(state, PurchAirNum);
190 2076247 : }
191 :
192 266 : void GetPurchasedAir(EnergyPlusData &state)
193 : {
194 :
195 : // SUBROUTINE INFORMATION:
196 : // AUTHOR Russ Taylor
197 : // DATE WRITTEN June 1997
198 : // MODIFIED M. Witte, June 2011, add new features including DCV, economizer, dehumidification
199 : // and humidification controls
200 : // RE-ENGINEERED na
201 :
202 : // PURPOSE OF THIS SUBROUTINE:
203 : // Get the input data for the Purchased Air objects.
204 : // Set up output variables.
205 :
206 : // Using/Aliasing
207 : using NodeInputManager::CheckUniqueNodeNames;
208 : using NodeInputManager::EndUniqueNodeCheck;
209 : using NodeInputManager::GetOnlySingleNode;
210 : using NodeInputManager::InitUniqueNodeCheck;
211 : using OutAirNodeManager::CheckAndAddAirNodeNumber;
212 : using namespace DataLoopNode;
213 : using ZonePlenum::GetReturnPlenumIndex;
214 :
215 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
216 : int PurchAirNum;
217 : int NumAlphas;
218 : int NumNums;
219 : int IOStat;
220 : int CtrlZone; // zone index
221 : int NodeNum; // node index
222 : static constexpr std::string_view RoutineName("GetPurchasedAir: "); // include trailing blank space
223 266 : bool ErrorsFound(false); // If errors detected in input
224 : bool IsOANodeListed; // Flag for OA node name listed in OutdoorAir:Node or Nodelist
225 : bool UniqueNodeError; // Flag for non-unique node error(s)
226 266 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
227 266 : cCurrentModuleObject = "ZoneHVAC:IdealLoadsAirSystem";
228 :
229 266 : auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
230 :
231 266 : state.dataPurchasedAirMgr->NumPurchAir = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
232 :
233 266 : PurchAir.allocate(state.dataPurchasedAirMgr->NumPurchAir);
234 266 : state.dataPurchasedAirMgr->CheckEquipName.allocate(state.dataPurchasedAirMgr->NumPurchAir);
235 266 : state.dataPurchasedAirMgr->PurchAirNumericFields.allocate(state.dataPurchasedAirMgr->NumPurchAir);
236 266 : state.dataPurchasedAirMgr->CheckEquipName = true;
237 :
238 266 : if (state.dataPurchasedAirMgr->NumPurchAir > 0) {
239 78 : InitUniqueNodeCheck(state, cCurrentModuleObject);
240 297 : for (PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) {
241 219 : PurchAir(PurchAirNum).cObjectName = cCurrentModuleObject;
242 :
243 438 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
244 : cCurrentModuleObject,
245 : PurchAirNum,
246 219 : state.dataIPShortCut->cAlphaArgs,
247 : NumAlphas,
248 219 : state.dataIPShortCut->rNumericArgs,
249 : NumNums,
250 : IOStat,
251 219 : state.dataIPShortCut->lNumericFieldBlanks,
252 219 : state.dataIPShortCut->lAlphaFieldBlanks,
253 219 : state.dataIPShortCut->cAlphaFieldNames,
254 219 : state.dataIPShortCut->cNumericFieldNames);
255 :
256 219 : state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames.allocate(NumNums);
257 219 : state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames = "";
258 219 : state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames = state.dataIPShortCut->cNumericFieldNames;
259 219 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
260 :
261 219 : PurchAir(PurchAirNum).Name = state.dataIPShortCut->cAlphaArgs(1);
262 : // get optional availability schedule
263 219 : PurchAir(PurchAirNum).AvailSched = state.dataIPShortCut->cAlphaArgs(2);
264 219 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
265 214 : PurchAir(PurchAirNum).AvailSchedPtr = ScheduleManager::ScheduleAlwaysOn;
266 : } else {
267 5 : PurchAir(PurchAirNum).AvailSchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
268 5 : if (PurchAir(PurchAirNum).AvailSchedPtr == 0) {
269 0 : ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
270 0 : ShowContinueError(
271 : state,
272 0 : format("Invalid-not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2)));
273 0 : ErrorsFound = true;
274 : }
275 : }
276 : // Purchased air supply air node is an outlet node
277 438 : PurchAir(PurchAirNum).ZoneSupplyAirNodeNum = GetOnlySingleNode(state,
278 219 : state.dataIPShortCut->cAlphaArgs(3),
279 : ErrorsFound,
280 : DataLoopNode::ConnectionObjectType::ZoneHVACIdealLoadsAirSystem,
281 219 : state.dataIPShortCut->cAlphaArgs(1),
282 : DataLoopNode::NodeFluidType::Air,
283 : DataLoopNode::ConnectionType::Outlet,
284 : NodeInputManager::CompFluidStream::Primary,
285 : ObjectIsNotParent);
286 219 : UniqueNodeError = false;
287 219 : CheckUniqueNodeNames(state,
288 219 : state.dataIPShortCut->cAlphaFieldNames(3),
289 : UniqueNodeError,
290 219 : state.dataIPShortCut->cAlphaArgs(3),
291 219 : state.dataIPShortCut->cAlphaArgs(1));
292 219 : if (UniqueNodeError) ErrorsFound = true;
293 : // If new (optional) exhaust air node name is present, then register it as inlet
294 219 : if (!state.dataIPShortCut->lAlphaFieldBlanks(4)) {
295 6 : if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
296 2 : PurchAir(PurchAirNum).ZoneExhaustAirNodeNum = GetOnlySingleNode(state,
297 1 : state.dataIPShortCut->cAlphaArgs(4),
298 : ErrorsFound,
299 : DataLoopNode::ConnectionObjectType::ZoneHVACIdealLoadsAirSystem,
300 1 : state.dataIPShortCut->cAlphaArgs(1),
301 : DataLoopNode::NodeFluidType::Air,
302 : DataLoopNode::ConnectionType::Inlet,
303 : NodeInputManager::CompFluidStream::Primary,
304 : ObjectIsNotParent);
305 : } else {
306 10 : PurchAir(PurchAirNum).ZoneExhaustAirNodeNum = GetOnlySingleNode(state,
307 5 : state.dataIPShortCut->cAlphaArgs(4),
308 : ErrorsFound,
309 : DataLoopNode::ConnectionObjectType::ZoneHVACIdealLoadsAirSystem,
310 5 : state.dataIPShortCut->cAlphaArgs(1),
311 : DataLoopNode::NodeFluidType::Air,
312 : DataLoopNode::ConnectionType::Outlet,
313 : NodeInputManager::CompFluidStream::Primary,
314 : ObjectIsNotParent);
315 : }
316 6 : UniqueNodeError = false;
317 6 : CheckUniqueNodeNames(state,
318 6 : state.dataIPShortCut->cAlphaFieldNames(4),
319 : UniqueNodeError,
320 6 : state.dataIPShortCut->cAlphaArgs(4),
321 6 : state.dataIPShortCut->cAlphaArgs(1));
322 6 : if (UniqueNodeError) ErrorsFound = true;
323 : }
324 219 : if (!state.dataIPShortCut->lAlphaFieldBlanks(5)) {
325 10 : PurchAir(PurchAirNum).PlenumExhaustAirNodeNum = GetOnlySingleNode(state,
326 5 : state.dataIPShortCut->cAlphaArgs(5),
327 : ErrorsFound,
328 : DataLoopNode::ConnectionObjectType::ZoneHVACIdealLoadsAirSystem,
329 5 : state.dataIPShortCut->cAlphaArgs(1),
330 : DataLoopNode::NodeFluidType::Air,
331 : DataLoopNode::ConnectionType::Inlet,
332 : NodeInputManager::CompFluidStream::Primary,
333 : ObjectIsNotParent);
334 : }
335 219 : PurchAir(PurchAirNum).MaxHeatSuppAirTemp = state.dataIPShortCut->rNumericArgs(1);
336 219 : PurchAir(PurchAirNum).MinCoolSuppAirTemp = state.dataIPShortCut->rNumericArgs(2);
337 219 : PurchAir(PurchAirNum).MaxHeatSuppAirHumRat = state.dataIPShortCut->rNumericArgs(3);
338 219 : PurchAir(PurchAirNum).MinCoolSuppAirHumRat = state.dataIPShortCut->rNumericArgs(4);
339 :
340 219 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(6), "NoLimit")) {
341 217 : PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit;
342 2 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(6), "LimitFlowRate")) {
343 2 : if (state.dataIPShortCut->lNumericFieldBlanks(5)) {
344 0 : PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit;
345 : } else {
346 2 : PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitFlowRate;
347 : }
348 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(6), "LimitCapacity")) {
349 0 : if (state.dataIPShortCut->lNumericFieldBlanks(6)) {
350 0 : PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit;
351 : } else {
352 0 : PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitCapacity;
353 : }
354 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(6), "LimitFlowRateAndCapacity")) {
355 0 : if (state.dataIPShortCut->lNumericFieldBlanks(5) && state.dataIPShortCut->lNumericFieldBlanks(6)) {
356 0 : PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit;
357 0 : } else if (state.dataIPShortCut->lNumericFieldBlanks(5)) {
358 0 : PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitCapacity;
359 0 : } else if (state.dataIPShortCut->lNumericFieldBlanks(6)) {
360 0 : PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitFlowRate;
361 : } else {
362 0 : PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitFlowRateAndCapacity;
363 : }
364 : } else {
365 0 : ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
366 0 : ShowContinueError(state,
367 0 : format("Invalid-entry {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
368 0 : ShowContinueError(state, "Valid entries are NoLimit, LimitFlowRate, LimitCapacity, or LimitFlowRateAndCapacity");
369 0 : ErrorsFound = true;
370 : }
371 219 : PurchAir(PurchAirNum).MaxHeatVolFlowRate = state.dataIPShortCut->rNumericArgs(5);
372 219 : PurchAir(PurchAirNum).MaxHeatSensCap = state.dataIPShortCut->rNumericArgs(6);
373 :
374 219 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "NoLimit")) {
375 215 : PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit;
376 4 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "LimitFlowRate")) {
377 4 : if (state.dataIPShortCut->lNumericFieldBlanks(7)) {
378 0 : PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit;
379 : } else {
380 4 : PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitFlowRate;
381 : }
382 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "LimitCapacity")) {
383 0 : if (state.dataIPShortCut->lNumericFieldBlanks(8)) {
384 0 : PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit;
385 : } else {
386 0 : PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitCapacity;
387 : }
388 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "LimitFlowRateAndCapacity")) {
389 0 : if (state.dataIPShortCut->lNumericFieldBlanks(7) && state.dataIPShortCut->lNumericFieldBlanks(8)) {
390 0 : PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit;
391 0 : } else if (state.dataIPShortCut->lNumericFieldBlanks(7)) {
392 0 : PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitCapacity;
393 0 : } else if (state.dataIPShortCut->lNumericFieldBlanks(8)) {
394 0 : PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitFlowRate;
395 : } else {
396 0 : PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitFlowRateAndCapacity;
397 : }
398 : } else {
399 0 : ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
400 0 : ShowContinueError(state,
401 0 : format("Invalid-entry {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
402 0 : ShowContinueError(state, "Valid entries are NoLimit, LimitFlowRate, LimitCapacity, or LimitFlowRateAndCapacity");
403 0 : ErrorsFound = true;
404 : }
405 219 : PurchAir(PurchAirNum).MaxCoolVolFlowRate = state.dataIPShortCut->rNumericArgs(7);
406 219 : PurchAir(PurchAirNum).MaxCoolTotCap = state.dataIPShortCut->rNumericArgs(8);
407 :
408 : // get optional heating availability schedule
409 219 : PurchAir(PurchAirNum).HeatSched = state.dataIPShortCut->cAlphaArgs(8);
410 219 : if (state.dataIPShortCut->lAlphaFieldBlanks(8)) {
411 218 : PurchAir(PurchAirNum).HeatSchedPtr = ScheduleManager::ScheduleAlwaysOn;
412 : } else {
413 1 : PurchAir(PurchAirNum).HeatSchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(8));
414 1 : if (PurchAir(PurchAirNum).HeatSchedPtr == 0) {
415 0 : ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
416 0 : ShowContinueError(
417 : state,
418 0 : format("Invalid-not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8)));
419 0 : ErrorsFound = true;
420 : }
421 : }
422 : // get optional cooling availability schedule
423 219 : PurchAir(PurchAirNum).CoolSched = state.dataIPShortCut->cAlphaArgs(9);
424 219 : if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
425 218 : PurchAir(PurchAirNum).CoolSchedPtr = ScheduleManager::ScheduleAlwaysOn;
426 : } else {
427 1 : PurchAir(PurchAirNum).CoolSchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(9));
428 1 : if (PurchAir(PurchAirNum).CoolSchedPtr == 0) {
429 0 : ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
430 0 : ShowContinueError(
431 : state,
432 0 : format("Invalid-not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9)));
433 0 : ErrorsFound = true;
434 : }
435 : }
436 : // get Dehumidification control type
437 219 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(10), "None")) {
438 1 : PurchAir(PurchAirNum).DehumidCtrlType = HumControl::None;
439 218 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(10), "ConstantSensibleHeatRatio")) {
440 25 : PurchAir(PurchAirNum).DehumidCtrlType = HumControl::ConstantSensibleHeatRatio;
441 193 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(10), "Humidistat")) {
442 6 : PurchAir(PurchAirNum).DehumidCtrlType = HumControl::Humidistat;
443 187 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(10), "ConstantSupplyHumidityRatio")) {
444 187 : PurchAir(PurchAirNum).DehumidCtrlType = HumControl::ConstantSupplyHumidityRatio;
445 : } else {
446 0 : ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
447 0 : ShowContinueError(
448 0 : state, format("Invalid-entry {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(10), state.dataIPShortCut->cAlphaArgs(10)));
449 0 : ShowContinueError(state, "Valid entries are ConstantSensibleHeatRatio, Humidistat, or ConstantSupplyHumidityRatio");
450 0 : ErrorsFound = true;
451 : }
452 219 : PurchAir(PurchAirNum).CoolSHR = state.dataIPShortCut->rNumericArgs(9);
453 :
454 : // get Humidification control type
455 219 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(11), "None")) {
456 30 : PurchAir(PurchAirNum).HumidCtrlType = HumControl::None;
457 189 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(11), "Humidistat")) {
458 2 : PurchAir(PurchAirNum).HumidCtrlType = HumControl::Humidistat;
459 187 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(11), "ConstantSupplyHumidityRatio")) {
460 187 : PurchAir(PurchAirNum).HumidCtrlType = HumControl::ConstantSupplyHumidityRatio;
461 : } else {
462 0 : ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
463 0 : ShowContinueError(
464 0 : state, format("Invalid-entry {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(11), state.dataIPShortCut->cAlphaArgs(11)));
465 0 : ShowContinueError(state, "Valid entries are None, Humidistat, or ConstantSupplyHumidityRatio");
466 0 : ErrorsFound = true;
467 : }
468 :
469 : // get Design specification outdoor air object
470 219 : if (!state.dataIPShortCut->lAlphaFieldBlanks(12)) {
471 4 : PurchAir(PurchAirNum).OARequirementsPtr = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(12), state.dataSize->OARequirements);
472 4 : if (PurchAir(PurchAirNum).OARequirementsPtr == 0) {
473 0 : ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
474 0 : ShowContinueError(
475 : state,
476 0 : format("Invalid-not found{}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(12), state.dataIPShortCut->cAlphaArgs(12)));
477 0 : ErrorsFound = true;
478 : } else {
479 4 : PurchAir(PurchAirNum).OutdoorAir = true;
480 : }
481 : }
482 :
483 : // If outdoor air specified, then get Outdoor air inlet node and other outdoor air inputs
484 219 : if (PurchAir(PurchAirNum).OutdoorAir) {
485 4 : if (state.dataIPShortCut->lAlphaFieldBlanks(13)) {
486 : // If there is outdoor air and outdoor air inlet node is blank, then create one
487 0 : if (len(state.dataIPShortCut->cAlphaArgs(1)) < Constant::MaxNameLength - 23) { // protect against long name leading to > 100 chars
488 0 : state.dataIPShortCut->cAlphaArgs(13) = state.dataIPShortCut->cAlphaArgs(1) + " OUTDOOR AIR INLET NODE";
489 : } else {
490 0 : state.dataIPShortCut->cAlphaArgs(13) = state.dataIPShortCut->cAlphaArgs(1).substr(0, 75) + " OUTDOOR AIR INLET NODE";
491 : }
492 0 : if (state.dataGlobal->DisplayExtraWarnings) {
493 0 : ShowWarningError(state,
494 0 : format("{}{}=\"{} blank field", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
495 0 : ShowContinueError(
496 : state,
497 0 : format("{} is blank, but there is outdoor air requested for this system.", state.dataIPShortCut->cAlphaFieldNames(13)));
498 0 : ShowContinueError(state, format("Creating node name ={}", state.dataIPShortCut->cAlphaArgs(13)));
499 : }
500 : }
501 : // Register OA node
502 8 : PurchAir(PurchAirNum).OutdoorAirNodeNum = GetOnlySingleNode(state,
503 4 : state.dataIPShortCut->cAlphaArgs(13),
504 : ErrorsFound,
505 : DataLoopNode::ConnectionObjectType::ZoneHVACIdealLoadsAirSystem,
506 4 : state.dataIPShortCut->cAlphaArgs(1),
507 : DataLoopNode::NodeFluidType::Air,
508 : DataLoopNode::ConnectionType::Outlet,
509 : NodeInputManager::CompFluidStream::Primary,
510 : ObjectIsNotParent);
511 : // Check if OA node is initialized in OutdoorAir:Node or OutdoorAir:Nodelist
512 4 : CheckAndAddAirNodeNumber(state, PurchAir(PurchAirNum).OutdoorAirNodeNum, IsOANodeListed);
513 4 : if ((!IsOANodeListed) && state.dataGlobal->DisplayExtraWarnings) {
514 0 : ShowWarningError(state, format("{}{}=\"{} missing data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
515 0 : ShowContinueError(
516 : state,
517 0 : format("{} does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.", state.dataIPShortCut->cAlphaArgs(13)));
518 0 : ShowContinueError(state, format("Adding OutdoorAir:Node={}", state.dataIPShortCut->cAlphaArgs(13)));
519 : }
520 4 : UniqueNodeError = false;
521 4 : CheckUniqueNodeNames(state,
522 4 : state.dataIPShortCut->cAlphaFieldNames(13),
523 : UniqueNodeError,
524 4 : state.dataIPShortCut->cAlphaArgs(13),
525 4 : state.dataIPShortCut->cAlphaArgs(1));
526 4 : if (UniqueNodeError) ErrorsFound = true;
527 :
528 : // get Demand controlled ventilation type
529 4 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(14), "None")) {
530 3 : PurchAir(PurchAirNum).DCVType = DCV::None;
531 1 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(14), "OccupancySchedule")) {
532 1 : PurchAir(PurchAirNum).DCVType = DCV::OccupancySchedule;
533 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(14), "CO2Setpoint")) {
534 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
535 0 : PurchAir(PurchAirNum).DCVType = DCV::CO2SetPoint;
536 : } else {
537 0 : PurchAir(PurchAirNum).DCVType = DCV::None;
538 0 : ShowWarningError(state,
539 0 : format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
540 0 : ShowContinueError(state,
541 0 : format("{}={} but CO2 simulation is not active.",
542 0 : state.dataIPShortCut->cAlphaFieldNames(14),
543 0 : state.dataIPShortCut->cAlphaArgs(14)));
544 0 : ShowContinueError(state, format("Resetting {} to NoDCV", state.dataIPShortCut->cAlphaFieldNames(14)));
545 0 : ShowContinueError(state,
546 : "To activate CO2 simulation, use ZoneAirContaminantBalance object and specify \"Carbon Dioxide "
547 : "Concentration\"=\"Yes\".");
548 : }
549 : } else {
550 0 : ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
551 0 : ShowContinueError(
552 0 : state, format("Invalid-entry {}={}", state.dataIPShortCut->cAlphaFieldNames(14), state.dataIPShortCut->cAlphaArgs(14)));
553 0 : ShowContinueError(state, "Valid entries are None, OccupancySchedule, or CO2Setpoint");
554 0 : ErrorsFound = true;
555 : }
556 : // get Outdoor air economizer type
557 4 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(15), "NoEconomizer")) {
558 1 : PurchAir(PurchAirNum).EconomizerType = Econ::NoEconomizer;
559 3 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(15), "DifferentialDryBulb")) {
560 2 : PurchAir(PurchAirNum).EconomizerType = Econ::DifferentialDryBulb;
561 1 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(15), "DifferentialEnthalpy")) {
562 1 : PurchAir(PurchAirNum).EconomizerType = Econ::DifferentialEnthalpy;
563 : } else {
564 0 : ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
565 0 : ShowContinueError(
566 0 : state, format("Invalid-entry {}={}", state.dataIPShortCut->cAlphaFieldNames(15), state.dataIPShortCut->cAlphaArgs(15)));
567 0 : ShowContinueError(state, "Valid entries are NoEconomizer, DifferentialDryBulb, or DifferentialEnthalpy");
568 0 : ErrorsFound = true;
569 : }
570 : // get Outdoor air heat recovery type and effectiveness
571 4 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(16), "None")) {
572 2 : PurchAir(PurchAirNum).HtRecType = HeatRecovery::None;
573 2 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(16), "Sensible")) {
574 1 : PurchAir(PurchAirNum).HtRecType = HeatRecovery::Sensible;
575 1 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(16), "Enthalpy")) {
576 1 : PurchAir(PurchAirNum).HtRecType = HeatRecovery::Enthalpy;
577 : } else {
578 0 : ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
579 0 : ShowContinueError(
580 0 : state, format("Invalid-entry {}={}", state.dataIPShortCut->cAlphaFieldNames(16), state.dataIPShortCut->cAlphaArgs(16)));
581 0 : ShowContinueError(state, "Valid entries are None, Sensible, or Enthalpy");
582 0 : ErrorsFound = true;
583 : }
584 : } else { // No outdoorair
585 215 : PurchAir(PurchAirNum).DCVType = DCV::None;
586 215 : PurchAir(PurchAirNum).EconomizerType = Econ::NoEconomizer;
587 215 : PurchAir(PurchAirNum).HtRecType = HeatRecovery::None;
588 : }
589 :
590 219 : PurchAir(PurchAirNum).HtRecSenEff = state.dataIPShortCut->rNumericArgs(10);
591 219 : PurchAir(PurchAirNum).HtRecLatEff = state.dataIPShortCut->rNumericArgs(11);
592 :
593 1310 : for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
594 1091 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) continue;
595 2103 : for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++NodeNum) {
596 1040 : if (PurchAir(PurchAirNum).ZoneSupplyAirNodeNum == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(NodeNum)) {
597 219 : PurchAir(PurchAirNum).ZonePtr = CtrlZone;
598 : }
599 : }
600 : }
601 :
602 219 : PurchAir(PurchAirNum).HVACSizingIndex = 0;
603 219 : if (!state.dataIPShortCut->lAlphaFieldBlanks(17)) {
604 0 : PurchAir(PurchAirNum).HVACSizingIndex = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(17), state.dataSize->ZoneHVACSizing);
605 0 : if (PurchAir(PurchAirNum).HVACSizingIndex == 0) {
606 0 : ShowSevereError(state,
607 0 : format("{} = {} not found.", state.dataIPShortCut->cAlphaFieldNames(17), state.dataIPShortCut->cAlphaArgs(17)));
608 0 : ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, PurchAir(PurchAirNum).Name));
609 0 : ErrorsFound = true;
610 : }
611 : }
612 :
613 : // initialize the calculated and report values
614 219 : PurchAir(PurchAirNum).MaxHeatMassFlowRate = 0.0;
615 219 : PurchAir(PurchAirNum).MaxCoolMassFlowRate = 0.0;
616 219 : PurchAir(PurchAirNum).SenHeatEnergy = 0.0;
617 219 : PurchAir(PurchAirNum).LatHeatEnergy = 0.0;
618 219 : PurchAir(PurchAirNum).TotHeatEnergy = 0.0;
619 219 : PurchAir(PurchAirNum).SenCoolEnergy = 0.0;
620 219 : PurchAir(PurchAirNum).LatCoolEnergy = 0.0;
621 219 : PurchAir(PurchAirNum).TotCoolEnergy = 0.0;
622 219 : PurchAir(PurchAirNum).ZoneSenHeatEnergy = 0.0;
623 219 : PurchAir(PurchAirNum).ZoneLatHeatEnergy = 0.0;
624 219 : PurchAir(PurchAirNum).ZoneTotHeatEnergy = 0.0;
625 219 : PurchAir(PurchAirNum).ZoneSenCoolEnergy = 0.0;
626 219 : PurchAir(PurchAirNum).ZoneLatCoolEnergy = 0.0;
627 219 : PurchAir(PurchAirNum).ZoneTotCoolEnergy = 0.0;
628 219 : PurchAir(PurchAirNum).OASenHeatEnergy = 0.0;
629 219 : PurchAir(PurchAirNum).OALatHeatEnergy = 0.0;
630 219 : PurchAir(PurchAirNum).OATotHeatEnergy = 0.0;
631 219 : PurchAir(PurchAirNum).OASenCoolEnergy = 0.0;
632 219 : PurchAir(PurchAirNum).OALatCoolEnergy = 0.0;
633 219 : PurchAir(PurchAirNum).OATotCoolEnergy = 0.0;
634 219 : PurchAir(PurchAirNum).HtRecSenHeatEnergy = 0.0;
635 219 : PurchAir(PurchAirNum).HtRecLatHeatEnergy = 0.0;
636 219 : PurchAir(PurchAirNum).HtRecTotHeatEnergy = 0.0;
637 219 : PurchAir(PurchAirNum).HtRecSenCoolEnergy = 0.0;
638 219 : PurchAir(PurchAirNum).HtRecLatCoolEnergy = 0.0;
639 219 : PurchAir(PurchAirNum).HtRecTotCoolEnergy = 0.0;
640 219 : PurchAir(PurchAirNum).SenHeatRate = 0.0;
641 219 : PurchAir(PurchAirNum).LatHeatRate = 0.0;
642 219 : PurchAir(PurchAirNum).TotHeatRate = 0.0;
643 219 : PurchAir(PurchAirNum).SenCoolRate = 0.0;
644 219 : PurchAir(PurchAirNum).LatCoolRate = 0.0;
645 219 : PurchAir(PurchAirNum).TotCoolRate = 0.0;
646 219 : PurchAir(PurchAirNum).ZoneSenHeatRate = 0.0;
647 219 : PurchAir(PurchAirNum).ZoneLatHeatRate = 0.0;
648 219 : PurchAir(PurchAirNum).ZoneTotHeatRate = 0.0;
649 219 : PurchAir(PurchAirNum).ZoneSenCoolRate = 0.0;
650 219 : PurchAir(PurchAirNum).ZoneLatCoolRate = 0.0;
651 219 : PurchAir(PurchAirNum).ZoneTotCoolRate = 0.0;
652 219 : PurchAir(PurchAirNum).OASenHeatRate = 0.0;
653 219 : PurchAir(PurchAirNum).OALatHeatRate = 0.0;
654 219 : PurchAir(PurchAirNum).OATotHeatRate = 0.0;
655 219 : PurchAir(PurchAirNum).OASenCoolRate = 0.0;
656 219 : PurchAir(PurchAirNum).OALatCoolRate = 0.0;
657 219 : PurchAir(PurchAirNum).OATotCoolRate = 0.0;
658 219 : PurchAir(PurchAirNum).HtRecSenHeatRate = 0.0;
659 219 : PurchAir(PurchAirNum).HtRecLatHeatRate = 0.0;
660 219 : PurchAir(PurchAirNum).HtRecTotHeatRate = 0.0;
661 219 : PurchAir(PurchAirNum).HtRecSenCoolRate = 0.0;
662 219 : PurchAir(PurchAirNum).HtRecLatCoolRate = 0.0;
663 219 : PurchAir(PurchAirNum).HtRecTotCoolRate = 0.0;
664 :
665 219 : PurchAir(PurchAirNum).OutdoorAirMassFlowRate = 0.0;
666 219 : PurchAir(PurchAirNum).OutdoorAirVolFlowRateStdRho = 0.0;
667 219 : PurchAir(PurchAirNum).SupplyAirMassFlowRate = 0.0;
668 219 : PurchAir(PurchAirNum).SupplyAirVolFlowRateStdRho = 0.0;
669 : }
670 78 : EndUniqueNodeCheck(state, cCurrentModuleObject);
671 : }
672 :
673 485 : for (PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) {
674 :
675 : // Setup Output variables
676 : // energy variables
677 438 : SetupOutputVariable(state,
678 : "Zone Ideal Loads Supply Air Sensible Heating Energy",
679 : Constant::Units::J,
680 219 : PurchAir(PurchAirNum).SenHeatEnergy,
681 : OutputProcessor::TimeStepType::System,
682 : OutputProcessor::StoreType::Sum,
683 219 : PurchAir(PurchAirNum).Name);
684 438 : SetupOutputVariable(state,
685 : "Zone Ideal Loads Supply Air Latent Heating Energy",
686 : Constant::Units::J,
687 219 : PurchAir(PurchAirNum).LatHeatEnergy,
688 : OutputProcessor::TimeStepType::System,
689 : OutputProcessor::StoreType::Sum,
690 219 : PurchAir(PurchAirNum).Name);
691 438 : SetupOutputVariable(state,
692 : "Zone Ideal Loads Supply Air Total Heating Energy",
693 : Constant::Units::J,
694 219 : PurchAir(PurchAirNum).TotHeatEnergy,
695 : OutputProcessor::TimeStepType::System,
696 : OutputProcessor::StoreType::Sum,
697 219 : PurchAir(PurchAirNum).Name,
698 : Constant::eResource::DistrictHeatingWater,
699 : OutputProcessor::Group::HVAC,
700 : OutputProcessor::EndUseCat::Heating);
701 438 : SetupOutputVariable(state,
702 : "Zone Ideal Loads Supply Air Sensible Cooling Energy",
703 : Constant::Units::J,
704 219 : PurchAir(PurchAirNum).SenCoolEnergy,
705 : OutputProcessor::TimeStepType::System,
706 : OutputProcessor::StoreType::Sum,
707 219 : PurchAir(PurchAirNum).Name);
708 438 : SetupOutputVariable(state,
709 : "Zone Ideal Loads Supply Air Latent Cooling Energy",
710 : Constant::Units::J,
711 219 : PurchAir(PurchAirNum).LatCoolEnergy,
712 : OutputProcessor::TimeStepType::System,
713 : OutputProcessor::StoreType::Sum,
714 219 : PurchAir(PurchAirNum).Name);
715 438 : SetupOutputVariable(state,
716 : "Zone Ideal Loads Supply Air Total Cooling Energy",
717 : Constant::Units::J,
718 219 : PurchAir(PurchAirNum).TotCoolEnergy,
719 : OutputProcessor::TimeStepType::System,
720 : OutputProcessor::StoreType::Sum,
721 219 : PurchAir(PurchAirNum).Name,
722 : Constant::eResource::DistrictCooling,
723 : OutputProcessor::Group::HVAC,
724 : OutputProcessor::EndUseCat::Cooling);
725 438 : SetupOutputVariable(state,
726 : "Zone Ideal Loads Zone Sensible Heating Energy",
727 : Constant::Units::J,
728 219 : PurchAir(PurchAirNum).ZoneSenHeatEnergy,
729 : OutputProcessor::TimeStepType::System,
730 : OutputProcessor::StoreType::Sum,
731 219 : PurchAir(PurchAirNum).Name);
732 438 : SetupOutputVariable(state,
733 : "Zone Ideal Loads Zone Latent Heating Energy",
734 : Constant::Units::J,
735 219 : PurchAir(PurchAirNum).ZoneLatHeatEnergy,
736 : OutputProcessor::TimeStepType::System,
737 : OutputProcessor::StoreType::Sum,
738 219 : PurchAir(PurchAirNum).Name);
739 438 : SetupOutputVariable(state,
740 : "Zone Ideal Loads Zone Total Heating Energy",
741 : Constant::Units::J,
742 219 : PurchAir(PurchAirNum).ZoneTotHeatEnergy,
743 : OutputProcessor::TimeStepType::System,
744 : OutputProcessor::StoreType::Sum,
745 219 : PurchAir(PurchAirNum).Name);
746 438 : SetupOutputVariable(state,
747 : "Zone Ideal Loads Zone Sensible Cooling Energy",
748 : Constant::Units::J,
749 219 : PurchAir(PurchAirNum).ZoneSenCoolEnergy,
750 : OutputProcessor::TimeStepType::System,
751 : OutputProcessor::StoreType::Sum,
752 219 : PurchAir(PurchAirNum).Name);
753 438 : SetupOutputVariable(state,
754 : "Zone Ideal Loads Zone Latent Cooling Energy",
755 : Constant::Units::J,
756 219 : PurchAir(PurchAirNum).ZoneLatCoolEnergy,
757 : OutputProcessor::TimeStepType::System,
758 : OutputProcessor::StoreType::Sum,
759 219 : PurchAir(PurchAirNum).Name);
760 438 : SetupOutputVariable(state,
761 : "Zone Ideal Loads Zone Total Cooling Energy",
762 : Constant::Units::J,
763 219 : PurchAir(PurchAirNum).ZoneTotCoolEnergy,
764 : OutputProcessor::TimeStepType::System,
765 : OutputProcessor::StoreType::Sum,
766 219 : PurchAir(PurchAirNum).Name);
767 438 : SetupOutputVariable(state,
768 : "Zone Ideal Loads Outdoor Air Sensible Heating Energy",
769 : Constant::Units::J,
770 219 : PurchAir(PurchAirNum).OASenHeatEnergy,
771 : OutputProcessor::TimeStepType::System,
772 : OutputProcessor::StoreType::Sum,
773 219 : PurchAir(PurchAirNum).Name);
774 438 : SetupOutputVariable(state,
775 : "Zone Ideal Loads Outdoor Air Latent Heating Energy",
776 : Constant::Units::J,
777 219 : PurchAir(PurchAirNum).OALatHeatEnergy,
778 : OutputProcessor::TimeStepType::System,
779 : OutputProcessor::StoreType::Sum,
780 219 : PurchAir(PurchAirNum).Name);
781 438 : SetupOutputVariable(state,
782 : "Zone Ideal Loads Outdoor Air Total Heating Energy",
783 : Constant::Units::J,
784 219 : PurchAir(PurchAirNum).OATotHeatEnergy,
785 : OutputProcessor::TimeStepType::System,
786 : OutputProcessor::StoreType::Sum,
787 219 : PurchAir(PurchAirNum).Name);
788 438 : SetupOutputVariable(state,
789 : "Zone Ideal Loads Outdoor Air Sensible Cooling Energy",
790 : Constant::Units::J,
791 219 : PurchAir(PurchAirNum).OASenCoolEnergy,
792 : OutputProcessor::TimeStepType::System,
793 : OutputProcessor::StoreType::Sum,
794 219 : PurchAir(PurchAirNum).Name);
795 438 : SetupOutputVariable(state,
796 : "Zone Ideal Loads Outdoor Air Latent Cooling Energy",
797 : Constant::Units::J,
798 219 : PurchAir(PurchAirNum).OALatCoolEnergy,
799 : OutputProcessor::TimeStepType::System,
800 : OutputProcessor::StoreType::Sum,
801 219 : PurchAir(PurchAirNum).Name);
802 438 : SetupOutputVariable(state,
803 : "Zone Ideal Loads Outdoor Air Total Cooling Energy",
804 : Constant::Units::J,
805 219 : PurchAir(PurchAirNum).OATotCoolEnergy,
806 : OutputProcessor::TimeStepType::System,
807 : OutputProcessor::StoreType::Sum,
808 219 : PurchAir(PurchAirNum).Name);
809 438 : SetupOutputVariable(state,
810 : "Zone Ideal Loads Heat Recovery Sensible Heating Energy",
811 : Constant::Units::J,
812 219 : PurchAir(PurchAirNum).HtRecSenHeatEnergy,
813 : OutputProcessor::TimeStepType::System,
814 : OutputProcessor::StoreType::Sum,
815 219 : PurchAir(PurchAirNum).Name);
816 438 : SetupOutputVariable(state,
817 : "Zone Ideal Loads Heat Recovery Latent Heating Energy",
818 : Constant::Units::J,
819 219 : PurchAir(PurchAirNum).HtRecLatHeatEnergy,
820 : OutputProcessor::TimeStepType::System,
821 : OutputProcessor::StoreType::Sum,
822 219 : PurchAir(PurchAirNum).Name);
823 438 : SetupOutputVariable(state,
824 : "Zone Ideal Loads Heat Recovery Total Heating Energy",
825 : Constant::Units::J,
826 219 : PurchAir(PurchAirNum).HtRecTotHeatEnergy,
827 : OutputProcessor::TimeStepType::System,
828 : OutputProcessor::StoreType::Sum,
829 219 : PurchAir(PurchAirNum).Name);
830 438 : SetupOutputVariable(state,
831 : "Zone Ideal Loads Heat Recovery Sensible Cooling Energy",
832 : Constant::Units::J,
833 219 : PurchAir(PurchAirNum).HtRecSenCoolEnergy,
834 : OutputProcessor::TimeStepType::System,
835 : OutputProcessor::StoreType::Sum,
836 219 : PurchAir(PurchAirNum).Name);
837 438 : SetupOutputVariable(state,
838 : "Zone Ideal Loads Heat Recovery Latent Cooling Energy",
839 : Constant::Units::J,
840 219 : PurchAir(PurchAirNum).HtRecLatCoolEnergy,
841 : OutputProcessor::TimeStepType::System,
842 : OutputProcessor::StoreType::Sum,
843 219 : PurchAir(PurchAirNum).Name);
844 438 : SetupOutputVariable(state,
845 : "Zone Ideal Loads Heat Recovery Total Cooling Energy",
846 : Constant::Units::J,
847 219 : PurchAir(PurchAirNum).HtRecTotCoolEnergy,
848 : OutputProcessor::TimeStepType::System,
849 : OutputProcessor::StoreType::Sum,
850 219 : PurchAir(PurchAirNum).Name);
851 :
852 : // rate variables
853 438 : SetupOutputVariable(state,
854 : "Zone Ideal Loads Supply Air Sensible Heating Rate",
855 : Constant::Units::W,
856 219 : PurchAir(PurchAirNum).SenHeatRate,
857 : OutputProcessor::TimeStepType::System,
858 : OutputProcessor::StoreType::Average,
859 219 : PurchAir(PurchAirNum).Name);
860 438 : SetupOutputVariable(state,
861 : "Zone Ideal Loads Supply Air Latent Heating Rate",
862 : Constant::Units::W,
863 219 : PurchAir(PurchAirNum).LatHeatRate,
864 : OutputProcessor::TimeStepType::System,
865 : OutputProcessor::StoreType::Average,
866 219 : PurchAir(PurchAirNum).Name);
867 438 : SetupOutputVariable(state,
868 : "Zone Ideal Loads Supply Air Total Heating Rate",
869 : Constant::Units::W,
870 219 : PurchAir(PurchAirNum).TotHeatRate,
871 : OutputProcessor::TimeStepType::System,
872 : OutputProcessor::StoreType::Average,
873 219 : PurchAir(PurchAirNum).Name);
874 438 : SetupOutputVariable(state,
875 : "Zone Ideal Loads Supply Air Sensible Cooling Rate",
876 : Constant::Units::W,
877 219 : PurchAir(PurchAirNum).SenCoolRate,
878 : OutputProcessor::TimeStepType::System,
879 : OutputProcessor::StoreType::Average,
880 219 : PurchAir(PurchAirNum).Name);
881 438 : SetupOutputVariable(state,
882 : "Zone Ideal Loads Supply Air Latent Cooling Rate",
883 : Constant::Units::W,
884 219 : PurchAir(PurchAirNum).LatCoolRate,
885 : OutputProcessor::TimeStepType::System,
886 : OutputProcessor::StoreType::Average,
887 219 : PurchAir(PurchAirNum).Name);
888 438 : SetupOutputVariable(state,
889 : "Zone Ideal Loads Supply Air Total Cooling Rate",
890 : Constant::Units::W,
891 219 : PurchAir(PurchAirNum).TotCoolRate,
892 : OutputProcessor::TimeStepType::System,
893 : OutputProcessor::StoreType::Average,
894 219 : PurchAir(PurchAirNum).Name);
895 438 : SetupOutputVariable(state,
896 : "Zone Ideal Loads Zone Sensible Heating Rate",
897 : Constant::Units::W,
898 219 : PurchAir(PurchAirNum).ZoneSenHeatRate,
899 : OutputProcessor::TimeStepType::System,
900 : OutputProcessor::StoreType::Average,
901 219 : PurchAir(PurchAirNum).Name);
902 438 : SetupOutputVariable(state,
903 : "Zone Ideal Loads Zone Latent Heating Rate",
904 : Constant::Units::W,
905 219 : PurchAir(PurchAirNum).ZoneLatHeatRate,
906 : OutputProcessor::TimeStepType::System,
907 : OutputProcessor::StoreType::Average,
908 219 : PurchAir(PurchAirNum).Name);
909 438 : SetupOutputVariable(state,
910 : "Zone Ideal Loads Zone Total Heating Rate",
911 : Constant::Units::W,
912 219 : PurchAir(PurchAirNum).ZoneTotHeatRate,
913 : OutputProcessor::TimeStepType::System,
914 : OutputProcessor::StoreType::Average,
915 219 : PurchAir(PurchAirNum).Name);
916 438 : SetupOutputVariable(state,
917 : "Zone Ideal Loads Zone Sensible Cooling Rate",
918 : Constant::Units::W,
919 219 : PurchAir(PurchAirNum).ZoneSenCoolRate,
920 : OutputProcessor::TimeStepType::System,
921 : OutputProcessor::StoreType::Average,
922 219 : PurchAir(PurchAirNum).Name);
923 438 : SetupOutputVariable(state,
924 : "Zone Ideal Loads Zone Latent Cooling Rate",
925 : Constant::Units::W,
926 219 : PurchAir(PurchAirNum).ZoneLatCoolRate,
927 : OutputProcessor::TimeStepType::System,
928 : OutputProcessor::StoreType::Average,
929 219 : PurchAir(PurchAirNum).Name);
930 438 : SetupOutputVariable(state,
931 : "Zone Ideal Loads Zone Total Cooling Rate",
932 : Constant::Units::W,
933 219 : PurchAir(PurchAirNum).ZoneTotCoolRate,
934 : OutputProcessor::TimeStepType::System,
935 : OutputProcessor::StoreType::Average,
936 219 : PurchAir(PurchAirNum).Name);
937 438 : SetupOutputVariable(state,
938 : "Zone Ideal Loads Outdoor Air Sensible Heating Rate",
939 : Constant::Units::W,
940 219 : PurchAir(PurchAirNum).OASenHeatRate,
941 : OutputProcessor::TimeStepType::System,
942 : OutputProcessor::StoreType::Average,
943 219 : PurchAir(PurchAirNum).Name);
944 438 : SetupOutputVariable(state,
945 : "Zone Ideal Loads Outdoor Air Latent Heating Rate",
946 : Constant::Units::W,
947 219 : PurchAir(PurchAirNum).OALatHeatRate,
948 : OutputProcessor::TimeStepType::System,
949 : OutputProcessor::StoreType::Average,
950 219 : PurchAir(PurchAirNum).Name);
951 438 : SetupOutputVariable(state,
952 : "Zone Ideal Loads Outdoor Air Total Heating Rate",
953 : Constant::Units::W,
954 219 : PurchAir(PurchAirNum).OATotHeatRate,
955 : OutputProcessor::TimeStepType::System,
956 : OutputProcessor::StoreType::Average,
957 219 : PurchAir(PurchAirNum).Name);
958 438 : SetupOutputVariable(state,
959 : "Zone Ideal Loads Outdoor Air Sensible Cooling Rate",
960 : Constant::Units::W,
961 219 : PurchAir(PurchAirNum).OASenCoolRate,
962 : OutputProcessor::TimeStepType::System,
963 : OutputProcessor::StoreType::Average,
964 219 : PurchAir(PurchAirNum).Name);
965 438 : SetupOutputVariable(state,
966 : "Zone Ideal Loads Outdoor Air Latent Cooling Rate",
967 : Constant::Units::W,
968 219 : PurchAir(PurchAirNum).OALatCoolRate,
969 : OutputProcessor::TimeStepType::System,
970 : OutputProcessor::StoreType::Average,
971 219 : PurchAir(PurchAirNum).Name);
972 438 : SetupOutputVariable(state,
973 : "Zone Ideal Loads Outdoor Air Total Cooling Rate",
974 : Constant::Units::W,
975 219 : PurchAir(PurchAirNum).OATotCoolRate,
976 : OutputProcessor::TimeStepType::System,
977 : OutputProcessor::StoreType::Average,
978 219 : PurchAir(PurchAirNum).Name);
979 438 : SetupOutputVariable(state,
980 : "Zone Ideal Loads Heat Recovery Sensible Heating Rate",
981 : Constant::Units::W,
982 219 : PurchAir(PurchAirNum).HtRecSenHeatRate,
983 : OutputProcessor::TimeStepType::System,
984 : OutputProcessor::StoreType::Average,
985 219 : PurchAir(PurchAirNum).Name);
986 438 : SetupOutputVariable(state,
987 : "Zone Ideal Loads Heat Recovery Latent Heating Rate",
988 : Constant::Units::W,
989 219 : PurchAir(PurchAirNum).HtRecLatHeatRate,
990 : OutputProcessor::TimeStepType::System,
991 : OutputProcessor::StoreType::Average,
992 219 : PurchAir(PurchAirNum).Name);
993 438 : SetupOutputVariable(state,
994 : "Zone Ideal Loads Heat Recovery Total Heating Rate",
995 : Constant::Units::W,
996 219 : PurchAir(PurchAirNum).HtRecTotHeatRate,
997 : OutputProcessor::TimeStepType::System,
998 : OutputProcessor::StoreType::Average,
999 219 : PurchAir(PurchAirNum).Name);
1000 438 : SetupOutputVariable(state,
1001 : "Zone Ideal Loads Heat Recovery Sensible Cooling Rate",
1002 : Constant::Units::W,
1003 219 : PurchAir(PurchAirNum).HtRecSenCoolRate,
1004 : OutputProcessor::TimeStepType::System,
1005 : OutputProcessor::StoreType::Average,
1006 219 : PurchAir(PurchAirNum).Name);
1007 438 : SetupOutputVariable(state,
1008 : "Zone Ideal Loads Heat Recovery Latent Cooling Rate",
1009 : Constant::Units::W,
1010 219 : PurchAir(PurchAirNum).HtRecLatCoolRate,
1011 : OutputProcessor::TimeStepType::System,
1012 : OutputProcessor::StoreType::Average,
1013 219 : PurchAir(PurchAirNum).Name);
1014 438 : SetupOutputVariable(state,
1015 : "Zone Ideal Loads Heat Recovery Total Cooling Rate",
1016 : Constant::Units::W,
1017 219 : PurchAir(PurchAirNum).HtRecTotCoolRate,
1018 : OutputProcessor::TimeStepType::System,
1019 : OutputProcessor::StoreType::Average,
1020 219 : PurchAir(PurchAirNum).Name);
1021 :
1022 438 : SetupOutputVariable(state,
1023 : "Zone Ideal Loads Economizer Active Time",
1024 : Constant::Units::hr,
1025 219 : PurchAir(PurchAirNum).TimeEconoActive,
1026 : OutputProcessor::TimeStepType::System,
1027 : OutputProcessor::StoreType::Sum,
1028 219 : PurchAir(PurchAirNum).Name);
1029 438 : SetupOutputVariable(state,
1030 : "Zone Ideal Loads Heat Recovery Active Time",
1031 : Constant::Units::hr,
1032 219 : PurchAir(PurchAirNum).TimeHtRecActive,
1033 : OutputProcessor::TimeStepType::System,
1034 : OutputProcessor::StoreType::Sum,
1035 219 : PurchAir(PurchAirNum).Name);
1036 :
1037 219 : SetupOutputVariable(state,
1038 : "Zone Ideal Loads Hybrid Ventilation Available Status",
1039 : Constant::Units::None,
1040 219 : (int &)PurchAir(PurchAirNum).availStatus,
1041 : OutputProcessor::TimeStepType::System,
1042 : OutputProcessor::StoreType::Average,
1043 219 : PurchAir(PurchAirNum).Name);
1044 :
1045 : // air flows
1046 438 : SetupOutputVariable(state,
1047 : "Zone Ideal Loads Outdoor Air Mass Flow Rate",
1048 : Constant::Units::kg_s,
1049 219 : PurchAir(PurchAirNum).OutdoorAirMassFlowRate,
1050 : OutputProcessor::TimeStepType::System,
1051 : OutputProcessor::StoreType::Average,
1052 219 : PurchAir(PurchAirNum).Name);
1053 438 : SetupOutputVariable(state,
1054 : "Zone Ideal Loads Outdoor Air Standard Density Volume Flow Rate",
1055 : Constant::Units::m3_s,
1056 219 : PurchAir(PurchAirNum).OutdoorAirVolFlowRateStdRho,
1057 : OutputProcessor::TimeStepType::System,
1058 : OutputProcessor::StoreType::Average,
1059 219 : PurchAir(PurchAirNum).Name);
1060 438 : SetupOutputVariable(state,
1061 : "Zone Ideal Loads Supply Air Mass Flow Rate",
1062 : Constant::Units::kg_s,
1063 219 : PurchAir(PurchAirNum).SupplyAirMassFlowRate,
1064 : OutputProcessor::TimeStepType::System,
1065 : OutputProcessor::StoreType::Average,
1066 219 : PurchAir(PurchAirNum).Name);
1067 438 : SetupOutputVariable(state,
1068 : "Zone Ideal Loads Supply Air Standard Density Volume Flow Rate",
1069 : Constant::Units::m3_s,
1070 219 : PurchAir(PurchAirNum).SupplyAirVolFlowRateStdRho,
1071 : OutputProcessor::TimeStepType::System,
1072 : OutputProcessor::StoreType::Average,
1073 219 : PurchAir(PurchAirNum).Name);
1074 :
1075 : // Supply Air temperature
1076 438 : SetupOutputVariable(state,
1077 : "Zone Ideal Loads Supply Air Temperature",
1078 : Constant::Units::C,
1079 219 : PurchAir(PurchAirNum).SupplyTemp,
1080 : OutputProcessor::TimeStepType::System,
1081 : OutputProcessor::StoreType::Average,
1082 219 : PurchAir(PurchAirNum).Name);
1083 : // Supply Air Humidity Ratio
1084 438 : SetupOutputVariable(state,
1085 : "Zone Ideal Loads Supply Air Humidity Ratio",
1086 : Constant::Units::kgWater_kgDryAir,
1087 219 : PurchAir(PurchAirNum).SupplyHumRat,
1088 : OutputProcessor::TimeStepType::System,
1089 : OutputProcessor::StoreType::Average,
1090 219 : PurchAir(PurchAirNum).Name);
1091 :
1092 : // Mixed Air temperature
1093 438 : SetupOutputVariable(state,
1094 : "Zone Ideal Loads Mixed Air Temperature",
1095 : Constant::Units::C,
1096 219 : PurchAir(PurchAirNum).MixedAirTemp,
1097 : OutputProcessor::TimeStepType::System,
1098 : OutputProcessor::StoreType::Average,
1099 219 : PurchAir(PurchAirNum).Name);
1100 : // Mixed Air Humidity Ratio
1101 438 : SetupOutputVariable(state,
1102 : "Zone Ideal Loads Mixed Air Humidity Ratio",
1103 : Constant::Units::kgWater_kgDryAir,
1104 219 : PurchAir(PurchAirNum).MixedAirHumRat,
1105 : OutputProcessor::TimeStepType::System,
1106 : OutputProcessor::StoreType::Average,
1107 219 : PurchAir(PurchAirNum).Name);
1108 :
1109 219 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
1110 38 : SetupEMSActuator(state,
1111 : "Ideal Loads Air System",
1112 19 : PurchAir(PurchAirNum).Name,
1113 : "Air Mass Flow Rate",
1114 : "[kg/s]",
1115 19 : PurchAir(PurchAirNum).EMSOverrideMdotOn,
1116 19 : PurchAir(PurchAirNum).EMSValueMassFlowRate);
1117 38 : SetupEMSActuator(state,
1118 : "Ideal Loads Air System",
1119 19 : PurchAir(PurchAirNum).Name,
1120 : "Outdoor Air Mass Flow Rate",
1121 : "[kg/s]",
1122 19 : PurchAir(PurchAirNum).EMSOverrideOAMdotOn,
1123 19 : PurchAir(PurchAirNum).EMSValueOAMassFlowRate);
1124 38 : SetupEMSActuator(state,
1125 : "Ideal Loads Air System",
1126 19 : PurchAir(PurchAirNum).Name,
1127 : "Air Temperature",
1128 : "[C]",
1129 19 : PurchAir(PurchAirNum).EMSOverrideSupplyTempOn,
1130 19 : PurchAir(PurchAirNum).EMSValueSupplyTemp);
1131 38 : SetupEMSActuator(state,
1132 : "Ideal Loads Air System",
1133 19 : PurchAir(PurchAirNum).Name,
1134 : "Air Humidity Ratio",
1135 : "[kgWater/kgDryAir]",
1136 19 : PurchAir(PurchAirNum).EMSOverrideSupplyHumRatOn,
1137 19 : PurchAir(PurchAirNum).EMSValueSupplyHumRat);
1138 : }
1139 : }
1140 :
1141 266 : if (ErrorsFound) {
1142 0 : ShowFatalError(state, format("{}Errors found in input. Preceding conditions cause termination.", RoutineName));
1143 : }
1144 266 : }
1145 :
1146 2076247 : void InitPurchasedAir(EnergyPlusData &state, int const PurchAirNum, int const ControlledZoneNum)
1147 : {
1148 :
1149 : // SUBROUTINE INFORMATION:
1150 : // AUTHOR Russ Taylor
1151 : // DATE WRITTEN Nov 1997
1152 :
1153 : // PURPOSE OF THIS SUBROUTINE:
1154 : // Initialize the PurchAir data structure.
1155 :
1156 : // Using/Aliasing
1157 : using DataZoneEquipment::CheckZoneEquipmentList;
1158 : using General::FindNumberInList;
1159 : using ZonePlenum::GetReturnPlenumIndex;
1160 : using ZonePlenum::GetReturnPlenumName;
1161 :
1162 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1163 : int Loop;
1164 : bool UnitOn; // simple checks for error
1165 : bool CoolOn; // simple checks for error
1166 : bool HeatOn; // simple checks for error
1167 : int SupplyNodeNum; // Node number for ideal loads supply node
1168 : int ExhaustNodeNum; // Node number for ideal loads exhaust node
1169 : int NodeIndex; // Array index of zone inlet or zone exhaust node that matches ideal loads node
1170 : bool UseReturnNode; // simple checks for error
1171 :
1172 2076247 : auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
1173 :
1174 : // Do the Begin Simulation initializations
1175 2076247 : if (state.dataPurchasedAirMgr->InitPurchasedAirMyOneTimeFlag) {
1176 78 : state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag.allocate(state.dataPurchasedAirMgr->NumPurchAir);
1177 78 : state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag.allocate(state.dataPurchasedAirMgr->NumPurchAir);
1178 78 : state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone.allocate(state.dataPurchasedAirMgr->NumPurchAir);
1179 78 : state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag = true;
1180 78 : state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag = true;
1181 78 : state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone = false;
1182 78 : state.dataPurchasedAirMgr->InitPurchasedAirMyOneTimeFlag = false;
1183 : }
1184 :
1185 : // need to check all units to see if they are on Zone Equipment List or issue warning
1186 2076247 : if (!state.dataPurchasedAirMgr->InitPurchasedAirZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
1187 78 : state.dataPurchasedAirMgr->InitPurchasedAirZoneEquipmentListChecked = true;
1188 297 : for (Loop = 1; Loop <= state.dataPurchasedAirMgr->NumPurchAir; ++Loop) {
1189 :
1190 : // link with return plenum if used (i.e., PlenumExhaustAirNodeNum will be non-zero)
1191 219 : if (PurchAir(Loop).PlenumExhaustAirNodeNum > 0) {
1192 5 : PurchAir(Loop).ReturnPlenumIndex = GetReturnPlenumIndex(state, PurchAir(Loop).PlenumExhaustAirNodeNum);
1193 5 : if (PurchAir(Loop).ReturnPlenumIndex > 0) {
1194 5 : GetReturnPlenumName(state, PurchAir(Loop).ReturnPlenumIndex, PurchAir(Loop).ReturnPlenumName);
1195 5 : InitializePlenumArrays(state, Loop);
1196 : } else {
1197 0 : ShowSevereError(state,
1198 0 : format("InitPurchasedAir: {} = {} cannot find ZoneHVAC:ReturnPlenum. It will not be simulated.",
1199 0 : PurchAir(Loop).cObjectName,
1200 0 : PurchAir(Loop).Name));
1201 : }
1202 : }
1203 :
1204 219 : if (CheckZoneEquipmentList(state, PurchAir(Loop).cObjectName, PurchAir(Loop).Name)) continue;
1205 0 : ShowSevereError(state,
1206 0 : format("InitPurchasedAir: {} = {} is not on any ZoneHVAC:EquipmentList. It will not be simulated.",
1207 0 : PurchAir(Loop).cObjectName,
1208 0 : PurchAir(Loop).Name));
1209 : }
1210 : }
1211 :
1212 : // one time inits for each unit - links PurchAirNum with static input data from ControlledZoneNum and ActualZoneNum
1213 2076247 : if (!state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone(PurchAirNum)) {
1214 219 : state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone(PurchAirNum) = true;
1215 :
1216 : // Is the supply node really a zone inlet node?
1217 : // this check has to be done here because of SimPurchasedAir passing in ControlledZoneNum
1218 219 : SupplyNodeNum = PurchAir(PurchAirNum).ZoneSupplyAirNodeNum;
1219 219 : if (SupplyNodeNum > 0) {
1220 219 : NodeIndex = FindNumberInList(SupplyNodeNum,
1221 219 : state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode,
1222 219 : state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes);
1223 219 : if (NodeIndex == 0) {
1224 0 : ShowSevereError(state, format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
1225 0 : ShowContinueError(state,
1226 0 : format("Zone Supply Air Node Name={} is not a zone inlet node.", state.dataLoopNodes->NodeID(SupplyNodeNum)));
1227 0 : ShowContinueError(
1228 : state,
1229 0 : format("Check ZoneHVAC:EquipmentConnections for zone={}", state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneName));
1230 0 : ShowFatalError(state, "Preceding condition causes termination.");
1231 : }
1232 : }
1233 :
1234 : // Set recirculation node number
1235 : // If exhaust node is specified, then recirculation is exhaust node, otherwise use zone return node
1236 : // this check has to be done here because of SimPurchasedAir passing in ControlledZoneNum
1237 219 : UseReturnNode = false;
1238 219 : if (PurchAir(PurchAirNum).ZoneExhaustAirNodeNum > 0) {
1239 6 : ExhaustNodeNum = PurchAir(PurchAirNum).ZoneExhaustAirNodeNum;
1240 6 : NodeIndex = FindNumberInList(ExhaustNodeNum,
1241 6 : state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ExhaustNode,
1242 6 : state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumExhaustNodes);
1243 6 : if (NodeIndex == 0) {
1244 0 : ShowSevereError(state, format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
1245 0 : ShowContinueError(state,
1246 0 : format("Zone Exhaust Air Node Name={} is not a zone exhaust node.", state.dataLoopNodes->NodeID(ExhaustNodeNum)));
1247 0 : ShowContinueError(
1248 : state,
1249 0 : format("Check ZoneHVAC:EquipmentConnections for zone={}", state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneName));
1250 0 : ShowContinueError(state, "Zone return air node will be used for ideal loads recirculation air.");
1251 0 : UseReturnNode = true;
1252 : } else {
1253 6 : PurchAir(PurchAirNum).ZoneRecircAirNodeNum = PurchAir(PurchAirNum).ZoneExhaustAirNodeNum;
1254 : }
1255 : } else {
1256 213 : UseReturnNode = true;
1257 : }
1258 219 : if (UseReturnNode) {
1259 213 : if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumReturnNodes == 1) {
1260 213 : PurchAir(PurchAirNum).ZoneRecircAirNodeNum = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ReturnNode(1);
1261 0 : } else if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumReturnNodes > 1) {
1262 0 : ShowWarningError(state, format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
1263 0 : ShowContinueError(state,
1264 : "No Zone Exhaust Air Node Name has been specified for this system and the zone has more than one Return Air Node.");
1265 0 : ShowContinueError(state,
1266 0 : format("Using the first return air node ={}",
1267 0 : state.dataLoopNodes->NodeID(state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ReturnNode(1))));
1268 : } else {
1269 0 : ShowFatalError(state, format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
1270 0 : ShowContinueError(
1271 : state,
1272 : " Invalid recirculation node. No exhaust or return node has been specified for this zone in ZoneHVAC:EquipmentConnections.");
1273 0 : ShowFatalError(state, "Preceding condition causes termination.");
1274 : }
1275 : }
1276 : // If there is OA and economizer is active, then there must be a limit on cooling flow rate
1277 219 : if (PurchAir(PurchAirNum).OutdoorAir && (PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer)) {
1278 3 : if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::NoLimit) || (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity)) {
1279 0 : ShowSevereError(state, format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
1280 0 : ShowContinueError(state, "There is outdoor air with economizer active but there is no limit on cooling air flow rate.");
1281 0 : ShowContinueError(state,
1282 : "Cooling Limit must be set to LimitFlowRate or LimitFlowRateAndCapacity, and Maximum Cooling Air Flow Rate "
1283 : "must be set to a value or autosize.");
1284 0 : ShowContinueError(state, "Simulation will proceed with no limit on outdoor air flow rate.");
1285 : }
1286 : }
1287 : }
1288 :
1289 2076247 : if (!state.dataGlobal->SysSizingCalc && state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag(PurchAirNum)) {
1290 :
1291 219 : SizePurchasedAir(state, PurchAirNum);
1292 :
1293 219 : state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag(PurchAirNum) = false;
1294 : }
1295 :
1296 : // Do the Begin Environment initializations
1297 2076247 : if (state.dataGlobal->BeginEnvrnFlag && state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag(PurchAirNum)) {
1298 :
1299 2258 : if ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
1300 1123 : (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) {
1301 12 : PurchAir(PurchAirNum).MaxHeatMassFlowRate = state.dataEnvrn->StdRhoAir * PurchAir(PurchAirNum).MaxHeatVolFlowRate;
1302 : } else {
1303 1123 : PurchAir(PurchAirNum).MaxHeatMassFlowRate = 0.0;
1304 : }
1305 2246 : if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
1306 1111 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) {
1307 24 : PurchAir(PurchAirNum).MaxCoolMassFlowRate = state.dataEnvrn->StdRhoAir * PurchAir(PurchAirNum).MaxCoolVolFlowRate;
1308 : } else {
1309 1111 : PurchAir(PurchAirNum).MaxCoolMassFlowRate = 0.0;
1310 : }
1311 1135 : state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag(PurchAirNum) = false;
1312 : }
1313 :
1314 2076247 : if (!state.dataGlobal->BeginEnvrnFlag) {
1315 2068326 : state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag(PurchAirNum) = true;
1316 : }
1317 :
1318 : // These initializations are done every iteration
1319 : // check that supply air temps can meet the zone thermostat setpoints
1320 2076247 : if (PurchAir(PurchAirNum).MinCoolSuppAirTemp > state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ControlledZoneNum) &&
1321 2076247 : state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ControlledZoneNum) != 0 && PurchAir(PurchAirNum).CoolingLimit == LimitType::NoLimit) {
1322 : // Check if the unit is scheduled off
1323 0 : UnitOn = true;
1324 : // IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN
1325 0 : if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).AvailSchedPtr) <= 0) {
1326 0 : UnitOn = false;
1327 : }
1328 : // END IF
1329 : // Check if cooling available
1330 0 : CoolOn = true;
1331 : // IF (PurchAir(PurchAirNum)%CoolSchedPtr > 0) THEN
1332 0 : if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).CoolSchedPtr) <= 0) {
1333 0 : CoolOn = false;
1334 : }
1335 : // END IF
1336 0 : if (UnitOn && CoolOn) {
1337 0 : if (PurchAir(PurchAirNum).CoolErrIndex == 0) {
1338 0 : ShowSevereError(state,
1339 0 : format("InitPurchasedAir: For {} = {} serving Zone {}",
1340 0 : PurchAir(PurchAirNum).cObjectName,
1341 0 : PurchAir(PurchAirNum).Name,
1342 0 : state.dataHeatBal->Zone(ControlledZoneNum).Name));
1343 0 : ShowContinueError(state,
1344 0 : format("..the minimum supply air temperature for cooling [{:.2R}] is greater than the zone cooling mean air "
1345 : "temperature (MAT) setpoint [{:.2R}].",
1346 0 : PurchAir(PurchAirNum).MinCoolSuppAirTemp,
1347 0 : state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ControlledZoneNum)));
1348 0 : ShowContinueError(state, "..For operative and comfort thermostat controls, the MAT setpoint is computed.");
1349 0 : ShowContinueError(state, "..This error may indicate that the mean radiant temperature or another comfort factor is too warm.");
1350 0 : ShowContinueError(state, "Unit availability is nominally ON and Cooling availability is nominally ON.");
1351 0 : ShowContinueError(state, format("Limit Cooling Capacity Type={}", cLimitType(PurchAir(PurchAirNum).CoolingLimit)));
1352 : // could check for optemp control or comfort control here
1353 0 : ShowContinueErrorTimeStamp(state, "");
1354 : }
1355 0 : ShowRecurringSevereErrorAtEnd(state,
1356 0 : "InitPurchasedAir: For " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name +
1357 0 : " serving Zone " + state.dataHeatBal->Zone(ControlledZoneNum).Name +
1358 : ", the minimum supply air temperature for cooling error continues",
1359 0 : PurchAir(PurchAirNum).CoolErrIndex,
1360 0 : PurchAir(PurchAirNum).MinCoolSuppAirTemp,
1361 0 : PurchAir(PurchAirNum).MinCoolSuppAirTemp,
1362 : _,
1363 : "C",
1364 : "C");
1365 : }
1366 : }
1367 2076247 : if (PurchAir(PurchAirNum).MaxHeatSuppAirTemp < state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ControlledZoneNum) &&
1368 2076247 : state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ControlledZoneNum) != 0 && PurchAir(PurchAirNum).HeatingLimit == LimitType::NoLimit) {
1369 : // Check if the unit is scheduled off
1370 0 : UnitOn = true;
1371 : // IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN
1372 0 : if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).AvailSchedPtr) <= 0) {
1373 0 : UnitOn = false;
1374 : }
1375 : // END IF
1376 : // Check if heating and cooling available
1377 0 : HeatOn = true;
1378 : // IF (PurchAir(PurchAirNum)%HeatSchedPtr > 0) THEN
1379 0 : if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).HeatSchedPtr) <= 0) {
1380 0 : HeatOn = false;
1381 : }
1382 : // END IF
1383 0 : if (UnitOn && HeatOn) {
1384 0 : if (PurchAir(PurchAirNum).HeatErrIndex == 0) {
1385 0 : ShowSevereMessage(state,
1386 0 : format("InitPurchasedAir: For {} = {} serving Zone {}",
1387 0 : PurchAir(PurchAirNum).cObjectName,
1388 0 : PurchAir(PurchAirNum).Name,
1389 0 : state.dataHeatBal->Zone(ControlledZoneNum).Name));
1390 0 : ShowContinueError(state,
1391 0 : format("..the maximum supply air temperature for heating [{:.2R}] is less than the zone mean air temperature "
1392 : "heating setpoint [{:.2R}].",
1393 0 : PurchAir(PurchAirNum).MaxHeatSuppAirTemp,
1394 0 : state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ControlledZoneNum)));
1395 0 : ShowContinueError(state, "..For operative and comfort thermostat controls, the MAT setpoint is computed.");
1396 0 : ShowContinueError(state, "..This error may indicate that the mean radiant temperature or another comfort factor is too cold.");
1397 0 : ShowContinueError(state, "Unit availability is nominally ON and Heating availability is nominally ON.");
1398 0 : ShowContinueError(state, format("Limit Heating Capacity Type={}", cLimitType(PurchAir(PurchAirNum).HeatingLimit)));
1399 : // could check for optemp control or comfort control here
1400 0 : ShowContinueErrorTimeStamp(state, "");
1401 : }
1402 0 : ShowRecurringSevereErrorAtEnd(state,
1403 0 : "InitPurchasedAir: For " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name +
1404 0 : " serving Zone " + state.dataHeatBal->Zone(ControlledZoneNum).Name +
1405 : ", maximum supply air temperature for heating error continues",
1406 0 : PurchAir(PurchAirNum).HeatErrIndex,
1407 0 : PurchAir(PurchAirNum).MaxHeatSuppAirTemp,
1408 0 : PurchAir(PurchAirNum).MaxHeatSuppAirTemp,
1409 : _,
1410 : "C",
1411 : "C");
1412 : }
1413 : }
1414 : // IF (ErrorsFound .and. .not. WarmupFlag) THEN
1415 : // CALL ShowFatalError(state, 'Preceding conditions cause termination.')
1416 : // ENDIF
1417 2076247 : }
1418 :
1419 219 : void SizePurchasedAir(EnergyPlusData &state, int const PurchAirNum)
1420 : {
1421 :
1422 : // SUBROUTINE INFORMATION:
1423 : // AUTHOR Fred Buhl
1424 : // DATE WRITTEN April 2003
1425 : // MODIFIED M. Witte, June 2011, add sizing for new capacity fields
1426 : // August 2013 Daeho Kang, add component sizing table entries
1427 : // RE-ENGINEERED na
1428 :
1429 : // PURPOSE OF THIS SUBROUTINE:
1430 : // This subroutine is for sizing Purchased Air Components for which flow rates have not been
1431 : // specified in the input.
1432 :
1433 : // METHODOLOGY EMPLOYED:
1434 : // Obtains flow rates from the zone sizing arrays.
1435 :
1436 : // Using/Aliasing
1437 : using namespace DataSizing;
1438 : using HVAC::CoolingCapacitySizing;
1439 : using HVAC::HeatingAirflowSizing;
1440 : using HVAC::HeatingCapacitySizing;
1441 : using Psychrometrics::CPCW;
1442 : using Psychrometrics::CPHW;
1443 : using Psychrometrics::PsyCpAirFnW;
1444 : using Psychrometrics::PsyHFnTdbW;
1445 : using Psychrometrics::RhoH2O;
1446 :
1447 : // SUBROUTINE PARAMETER DEFINITIONS:
1448 : static constexpr std::string_view RoutineName("SizePurchasedAir: "); // include trailing blank space
1449 :
1450 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1451 : bool IsAutoSize; // Indicator to autosize
1452 : Real64 MaxHeatVolFlowRateDes; // Autosized maximum heating air flow for reporting
1453 : Real64 MaxHeatVolFlowRateUser; // Hardsized maximum heating air flow for reporting
1454 : Real64 MaxCoolVolFlowRateDes; // Autosized maximum cooling air flow for reporting
1455 : Real64 MaxCoolVolFlowRateUser; // Hardsized maximum cooling air flow for reporting
1456 : Real64 MaxHeatSensCapDes; // Autosized maximum sensible heating capacity for reporting
1457 : Real64 MaxHeatSensCapUser; // Hardsized maximum sensible heating capacity for reporting
1458 : Real64 MaxCoolTotCapDes; // Autosized maximum sensible cooling capacity for reporting
1459 : Real64 MaxCoolTotCapUser; // Hardsized maximum sensible cooling capacity for reporting
1460 219 : std::string CompName; // component name
1461 219 : std::string CompType; // component type
1462 219 : std::string SizingString; // input field sizing description (e.g., Nominal Capacity)
1463 : Real64 TempSize; // autosized value of coil input field
1464 219 : int FieldNum = 2; // IDD numeric field number where input field description is found
1465 : int SizingMethod; // Integer representation of sizing method name (e.g., CoolingAirflowSizing, HeatingAirflowSizing, CoolingCapacitySizing,
1466 : // HeatingCapacitySizing, etc.)
1467 : bool PrintFlag; // TRUE when sizing information is reported in the eio file
1468 : int zoneHVACIndex; // index of zoneHVAC equipment sizing specification
1469 219 : int SAFMethod(0); // supply air flow rate sizing method (SupplyAirFlowRate, FlowPerFloorArea, FractionOfAutosizedCoolingAirflow,
1470 : // FractionOfAutosizedHeatingAirflow ...)
1471 219 : int CapSizingMethod(0); // capacity sizing methods (HeatingDesignCapacity, CapacityPerFloorArea, FractionOfAutosizedCoolingCapacity, and
1472 : // FractionOfAutosizedHeatingCapacity )
1473 219 : Real64 CoolingAirVolFlowDes(0.0); // cooling supply air flow rate
1474 219 : Real64 HeatingAirVolFlowDes(0.0); // heating supply air flow rate
1475 :
1476 219 : auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
1477 219 : auto &ZoneEqSizing(state.dataSize->ZoneEqSizing);
1478 :
1479 219 : IsAutoSize = false;
1480 219 : MaxHeatVolFlowRateDes = 0.0;
1481 219 : MaxHeatVolFlowRateUser = 0.0;
1482 219 : MaxCoolVolFlowRateDes = 0.0;
1483 219 : MaxCoolVolFlowRateUser = 0.0;
1484 219 : MaxHeatSensCapDes = 0.0;
1485 219 : MaxHeatSensCapUser = 0.0;
1486 219 : MaxCoolTotCapDes = 0.0;
1487 219 : MaxCoolTotCapUser = 0.0;
1488 :
1489 219 : state.dataSize->ZoneHeatingOnlyFan = false;
1490 219 : state.dataSize->ZoneCoolingOnlyFan = false;
1491 219 : CompType = PurchAir(PurchAirNum).cObjectName;
1492 219 : CompName = PurchAir(PurchAirNum).Name;
1493 219 : bool ErrorsFound = false;
1494 :
1495 219 : if (state.dataSize->CurZoneEqNum > 0) {
1496 219 : if (PurchAir(PurchAirNum).HVACSizingIndex > 0) {
1497 0 : state.dataSize->DataZoneNumber = PurchAir(PurchAirNum).ZonePtr;
1498 0 : zoneHVACIndex = PurchAir(PurchAirNum).HVACSizingIndex;
1499 :
1500 0 : FieldNum = 5; // N5 , \field Maximum Heating Air Flow Rate
1501 0 : PrintFlag = true;
1502 0 : SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]";
1503 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod > 0) {
1504 0 : SizingMethod = HeatingAirflowSizing;
1505 0 : state.dataSize->ZoneHeatingOnlyFan = true;
1506 0 : SAFMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod;
1507 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SizingMethod(SizingMethod) = SAFMethod;
1508 0 : if (SAFMethod == SupplyAirFlowRate || SAFMethod == FlowPerFloorArea || SAFMethod == FractionOfAutosizedHeatingAirflow) {
1509 0 : if (SAFMethod == SupplyAirFlowRate) {
1510 0 : if ((state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == AutoSize) &&
1511 0 : ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
1512 0 : (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) {
1513 0 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
1514 0 : HeatingAirFlowSizer sizingHeatingAirFlow;
1515 0 : sizingHeatingAirFlow.overrideSizingString(SizingString);
1516 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1517 0 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1518 0 : HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound);
1519 0 : } else {
1520 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow > 0.0) {
1521 0 : HeatingAirFlowSizer sizingHeatingAirFlow;
1522 0 : sizingHeatingAirFlow.overrideSizingString(SizingString);
1523 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1524 0 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1525 : HeatingAirVolFlowDes =
1526 0 : sizingHeatingAirFlow.size(state, state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow, ErrorsFound);
1527 0 : }
1528 : }
1529 0 : } else if (SAFMethod == FlowPerFloorArea) {
1530 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SystemAirFlow = true;
1531 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow *
1532 0 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
1533 0 : TempSize = ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow;
1534 0 : state.dataSize->DataScalableSizingON = true;
1535 0 : HeatingAirFlowSizer sizingHeatingAirFlow;
1536 0 : sizingHeatingAirFlow.overrideSizingString(SizingString);
1537 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1538 0 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1539 0 : HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound);
1540 0 : } else if (SAFMethod == FractionOfAutosizedHeatingAirflow) {
1541 0 : state.dataSize->DataFracOfAutosizedHeatingAirflow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
1542 0 : if ((state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == AutoSize) &&
1543 0 : ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
1544 0 : (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) {
1545 0 : TempSize = AutoSize;
1546 0 : state.dataSize->DataScalableSizingON = true;
1547 0 : HeatingAirFlowSizer sizingHeatingAirFlow;
1548 0 : sizingHeatingAirFlow.overrideSizingString(SizingString);
1549 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1550 0 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1551 0 : HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound);
1552 0 : }
1553 :
1554 : } else {
1555 : // Invalid sizing method
1556 : }
1557 0 : } else if (SAFMethod == FlowPerHeatingCapacity) {
1558 0 : SizingMethod = HeatingCapacitySizing;
1559 0 : TempSize = AutoSize;
1560 0 : PrintFlag = false;
1561 0 : if ((state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == AutoSize) &&
1562 0 : ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
1563 0 : (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) {
1564 0 : TempSize = AutoSize;
1565 0 : state.dataSize->DataScalableSizingON = true;
1566 0 : HeatingCapacitySizer sizerHeatingCapacity;
1567 0 : sizerHeatingCapacity.overrideSizingString(SizingString);
1568 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1569 0 : state.dataSize->DataAutosizedHeatingCapacity = sizerHeatingCapacity.size(state, TempSize, ErrorsFound);
1570 0 : state.dataSize->DataFlowPerHeatingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
1571 0 : SizingMethod = HeatingAirflowSizing;
1572 0 : PrintFlag = true;
1573 0 : TempSize = AutoSize;
1574 0 : HeatingAirFlowSizer sizingHeatingAirFlow;
1575 0 : sizingHeatingAirFlow.overrideSizingString(SizingString);
1576 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1577 0 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1578 0 : HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound);
1579 0 : }
1580 : }
1581 0 : MaxHeatVolFlowRateDes = max(0.0, HeatingAirVolFlowDes);
1582 0 : PurchAir(PurchAirNum).MaxHeatVolFlowRate = MaxHeatVolFlowRateDes;
1583 0 : state.dataSize->ZoneHeatingOnlyFan = false;
1584 :
1585 0 : CapSizingMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingCapMethod;
1586 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).CapSizingMethod = CapSizingMethod;
1587 0 : if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
1588 0 : CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
1589 0 : if (CapSizingMethod == HeatingDesignCapacity) {
1590 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity > 0.0) {
1591 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingCapacity = true;
1592 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad =
1593 0 : state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
1594 : }
1595 0 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
1596 0 : } else if (CapSizingMethod == CapacityPerFloorArea) {
1597 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingCapacity = true;
1598 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad =
1599 0 : state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity *
1600 0 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
1601 0 : state.dataSize->DataScalableSizingON = true;
1602 0 : } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
1603 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
1604 0 : TempSize = AutoSize;
1605 : }
1606 : }
1607 0 : SizingMethod = HeatingCapacitySizing;
1608 0 : SizingString = "";
1609 0 : state.dataSize->ZoneHeatingOnlyFan = true;
1610 0 : PrintFlag = false;
1611 0 : HeatingCapacitySizer sizerHeatingCapacity;
1612 0 : sizerHeatingCapacity.overrideSizingString(SizingString);
1613 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1614 0 : MaxHeatSensCapDes = sizerHeatingCapacity.size(state, TempSize, ErrorsFound);
1615 0 : state.dataSize->ZoneHeatingOnlyFan = false;
1616 0 : if (MaxHeatSensCapDes < HVAC::SmallLoad) {
1617 0 : MaxHeatSensCapDes = 0.0;
1618 : }
1619 0 : if (IsAutoSize) {
1620 0 : PurchAir(PurchAirNum).MaxHeatSensCap = MaxHeatSensCapDes;
1621 0 : BaseSizer::reportSizerOutput(state,
1622 0 : PurchAir(PurchAirNum).cObjectName,
1623 0 : PurchAir(PurchAirNum).Name,
1624 : "Design Size Maximum Sensible Heating Capacity [W]",
1625 : MaxHeatSensCapDes);
1626 : // If there is OA, check if sizing calcs have OA>0, throw warning if not
1627 0 : if ((PurchAir(PurchAirNum).OutdoorAir) && (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA == 0.0)) {
1628 0 : ShowWarningError(state,
1629 0 : format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
1630 0 : ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this ");
1631 0 : ShowContinueError(state, "zone is zero. The Maximum Sensible Heating Capacity will be autosized for zero outdoor air flow. ");
1632 0 : ShowContinueError(state,
1633 0 : format("Check the outdoor air specifications in the Sizing:Zone object for zone {}.",
1634 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneName));
1635 : }
1636 : } else {
1637 0 : if (PurchAir(PurchAirNum).MaxHeatSensCap > 0.0 && MaxHeatSensCapDes > 0.0) {
1638 0 : MaxHeatSensCapUser = PurchAir(PurchAirNum).MaxHeatSensCap;
1639 0 : BaseSizer::reportSizerOutput(state,
1640 0 : PurchAir(PurchAirNum).cObjectName,
1641 0 : PurchAir(PurchAirNum).Name,
1642 : "Design Size Maximum Sensible Heating Capacity [W]",
1643 : MaxHeatSensCapDes,
1644 : "User-Specified Maximum Sensible Heating Capacity [W]",
1645 : MaxHeatSensCapUser);
1646 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1647 0 : if ((std::abs(MaxHeatSensCapDes - MaxHeatSensCapUser) / MaxHeatSensCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
1648 0 : ShowMessage(state,
1649 0 : format("SizePurchasedAir: Potential issue with equipment sizing for {} {}",
1650 0 : PurchAir(PurchAirNum).cObjectName,
1651 0 : PurchAir(PurchAirNum).Name));
1652 0 : ShowContinueError(state,
1653 0 : format("...User-Specified Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapUser));
1654 0 : ShowContinueError(
1655 0 : state, format("...differs from Design Size Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapDes));
1656 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1657 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1658 : }
1659 : }
1660 : }
1661 : }
1662 0 : }
1663 :
1664 0 : PrintFlag = true;
1665 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod > 0) {
1666 0 : state.dataSize->ZoneCoolingOnlyFan = true;
1667 0 : SAFMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod;
1668 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SizingMethod(SizingMethod) = SAFMethod;
1669 0 : if (SAFMethod == SupplyAirFlowRate || SAFMethod == FlowPerFloorArea || SAFMethod == FractionOfAutosizedCoolingAirflow) {
1670 0 : if (SAFMethod == SupplyAirFlowRate) {
1671 0 : if ((state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize) &&
1672 0 : ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
1673 0 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) ||
1674 0 : (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) {
1675 0 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
1676 0 : CoolingAirFlowSizer sizingCoolingAirFlow;
1677 0 : sizingCoolingAirFlow.overrideSizingString(SizingString);
1678 0 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1679 0 : CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
1680 0 : } else {
1681 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow > 0.0) {
1682 0 : CoolingAirVolFlowDes = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
1683 0 : CoolingAirFlowSizer sizingCoolingAirFlow;
1684 0 : sizingCoolingAirFlow.overrideSizingString(SizingString);
1685 0 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1686 0 : CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, CoolingAirVolFlowDes, ErrorsFound);
1687 0 : }
1688 : }
1689 0 : } else if (SAFMethod == FlowPerFloorArea) {
1690 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SystemAirFlow = true;
1691 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow *
1692 0 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
1693 0 : TempSize = ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow;
1694 0 : state.dataSize->DataScalableSizingON = true;
1695 0 : CoolingAirFlowSizer sizingCoolingAirFlow;
1696 0 : std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]";
1697 0 : if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]";
1698 0 : sizingCoolingAirFlow.overrideSizingString(stringOverride);
1699 : // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1700 0 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1701 0 : CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
1702 0 : } else if (SAFMethod == FractionOfAutosizedCoolingAirflow) {
1703 0 : if ((state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize) &&
1704 0 : ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
1705 0 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) ||
1706 0 : (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) {
1707 0 : state.dataSize->DataFracOfAutosizedCoolingAirflow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
1708 0 : TempSize = AutoSize;
1709 0 : state.dataSize->DataScalableSizingON = true;
1710 0 : CoolingAirFlowSizer sizingCoolingAirFlow;
1711 0 : std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]";
1712 0 : if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]";
1713 0 : sizingCoolingAirFlow.overrideSizingString(stringOverride);
1714 : // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1715 0 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1716 0 : CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
1717 0 : }
1718 : } else {
1719 : // Invalid scalable sizing method
1720 : }
1721 0 : } else if (SAFMethod == FlowPerCoolingCapacity) {
1722 0 : if ((state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize) &&
1723 0 : ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
1724 0 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) ||
1725 0 : (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) {
1726 0 : SizingMethod = CoolingCapacitySizing;
1727 0 : TempSize = AutoSize;
1728 0 : PrintFlag = false;
1729 0 : CoolingCapacitySizer sizerCoolingCapacity;
1730 0 : sizerCoolingCapacity.overrideSizingString(SizingString);
1731 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1732 0 : state.dataSize->DataAutosizedCoolingCapacity = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
1733 0 : state.dataSize->DataFlowPerCoolingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
1734 0 : PrintFlag = true;
1735 0 : TempSize = AutoSize;
1736 0 : state.dataSize->DataScalableSizingON = true;
1737 0 : CoolingAirFlowSizer sizingCoolingAirFlow;
1738 0 : std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]";
1739 0 : if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]";
1740 0 : sizingCoolingAirFlow.overrideSizingString(stringOverride);
1741 : // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1742 0 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1743 0 : CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
1744 0 : }
1745 : }
1746 0 : MaxCoolVolFlowRateDes = max(0.0, CoolingAirVolFlowDes);
1747 0 : PurchAir(PurchAirNum).MaxCoolVolFlowRate = MaxCoolVolFlowRateDes;
1748 0 : state.dataSize->ZoneCoolingOnlyFan = false;
1749 0 : state.dataSize->DataScalableSizingON = false;
1750 :
1751 0 : CapSizingMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingCapMethod;
1752 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).CapSizingMethod = CapSizingMethod;
1753 0 : if (CapSizingMethod == CoolingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
1754 0 : CapSizingMethod == FractionOfAutosizedCoolingCapacity) {
1755 0 : if (CapSizingMethod == CoolingDesignCapacity) {
1756 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity > 0.0) {
1757 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingCapacity = true;
1758 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesCoolingLoad =
1759 0 : state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
1760 : } else {
1761 0 : state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolMassFlow;
1762 : }
1763 0 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
1764 0 : } else if (CapSizingMethod == CapacityPerFloorArea) {
1765 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingCapacity = true;
1766 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesCoolingLoad =
1767 0 : state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity *
1768 0 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
1769 0 : state.dataSize->DataScalableSizingON = true;
1770 0 : } else if (CapSizingMethod == FractionOfAutosizedCoolingCapacity) {
1771 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
1772 0 : state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolMassFlow;
1773 0 : TempSize = AutoSize;
1774 : }
1775 : }
1776 0 : SizingMethod = CoolingCapacitySizing;
1777 0 : SizingString = "";
1778 0 : state.dataSize->ZoneCoolingOnlyFan = true;
1779 0 : PrintFlag = false;
1780 0 : TempSize = PurchAir(PurchAirNum).MaxCoolTotCap;
1781 0 : CoolingCapacitySizer sizerCoolingCapacity;
1782 0 : sizerCoolingCapacity.overrideSizingString(SizingString);
1783 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1784 0 : MaxCoolTotCapDes = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
1785 0 : state.dataSize->ZoneCoolingOnlyFan = false;
1786 0 : if (MaxCoolTotCapDes < HVAC::SmallLoad) {
1787 0 : MaxCoolTotCapDes = 0.0;
1788 : }
1789 0 : if (IsAutoSize) {
1790 0 : PurchAir(PurchAirNum).MaxCoolTotCap = MaxCoolTotCapDes;
1791 0 : BaseSizer::reportSizerOutput(state,
1792 0 : PurchAir(PurchAirNum).cObjectName,
1793 0 : PurchAir(PurchAirNum).Name,
1794 : "Design Size Maximum Total Cooling Capacity [W]",
1795 : MaxCoolTotCapDes);
1796 : // If there is OA, check if sizing calcs have OA>0, throw warning if not
1797 0 : if ((PurchAir(PurchAirNum).OutdoorAir) && (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA == 0.0)) {
1798 0 : ShowWarningError(state,
1799 0 : format("SizePurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
1800 0 : ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this ");
1801 0 : ShowContinueError(state, "zone is zero. The Maximum Total Cooling Capacity will be autosized for zero outdoor air flow. ");
1802 0 : ShowContinueError(state,
1803 0 : format("Check the outdoor air specifications in the Sizing:Zone object for zone {}.",
1804 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneName));
1805 : }
1806 : } else {
1807 0 : if (PurchAir(PurchAirNum).MaxCoolTotCap > 0.0 && MaxCoolTotCapDes > 0.0) {
1808 0 : MaxCoolTotCapUser = PurchAir(PurchAirNum).MaxCoolTotCap;
1809 0 : BaseSizer::reportSizerOutput(state,
1810 0 : PurchAir(PurchAirNum).cObjectName,
1811 0 : PurchAir(PurchAirNum).Name,
1812 : "Design Size Maximum Total Cooling Capacity [W]",
1813 : MaxCoolTotCapDes,
1814 : "User-Specified Maximum Total Cooling Capacity [W]",
1815 : MaxCoolTotCapUser);
1816 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1817 0 : if ((std::abs(MaxCoolTotCapDes - MaxCoolTotCapUser) / MaxCoolTotCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
1818 0 : ShowMessage(state,
1819 0 : format("SizePurchasedAir: Potential issue with equipment sizing for {} {}",
1820 0 : PurchAir(PurchAirNum).cObjectName,
1821 0 : PurchAir(PurchAirNum).Name));
1822 0 : ShowContinueError(state, format("User-Specified Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapUser));
1823 0 : ShowContinueError(state,
1824 0 : format("differs from Design Size Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapDes));
1825 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1826 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1827 : }
1828 : }
1829 : }
1830 : }
1831 0 : }
1832 :
1833 : } else {
1834 : // SizingString = "Maximum Heating Air Flow Rate [m3/s]";
1835 219 : SizingMethod = HeatingAirflowSizing;
1836 219 : FieldNum = 5;
1837 219 : SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]";
1838 219 : IsAutoSize = false;
1839 219 : PrintFlag = true;
1840 404 : if ((PurchAir(PurchAirNum).MaxHeatVolFlowRate == AutoSize) &&
1841 185 : ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
1842 183 : (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) {
1843 2 : IsAutoSize = true;
1844 : }
1845 219 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
1846 207 : if (PurchAir(PurchAirNum).MaxHeatVolFlowRate > 0.0) {
1847 2 : HeatingAirFlowSizer sizingHeatingAirFlow;
1848 2 : sizingHeatingAirFlow.overrideSizingString(SizingString);
1849 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1850 2 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1851 4 : PurchAir(PurchAirNum).MaxHeatVolFlowRate =
1852 2 : sizingHeatingAirFlow.size(state, PurchAir(PurchAirNum).MaxHeatVolFlowRate, ErrorsFound);
1853 2 : }
1854 207 : MaxHeatVolFlowRateDes = 0.0;
1855 : } else {
1856 12 : state.dataSize->ZoneHeatingOnlyFan = true;
1857 12 : TempSize = PurchAir(PurchAirNum).MaxHeatVolFlowRate;
1858 12 : HeatingAirFlowSizer sizingHeatingAirFlow;
1859 12 : sizingHeatingAirFlow.overrideSizingString(SizingString);
1860 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1861 12 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1862 12 : MaxHeatVolFlowRateDes = sizingHeatingAirFlow.size(state, PurchAir(PurchAirNum).MaxHeatVolFlowRate, ErrorsFound);
1863 12 : PurchAir(PurchAirNum).MaxHeatVolFlowRate = MaxHeatVolFlowRateDes;
1864 12 : state.dataSize->ZoneHeatingOnlyFan = false;
1865 12 : }
1866 :
1867 219 : IsAutoSize = false;
1868 219 : SizingMethod = HeatingCapacitySizing;
1869 219 : FieldNum = 6; // N6, \field Maximum Sensible Heating Capacity
1870 219 : SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]";
1871 219 : if ((PurchAir(PurchAirNum).MaxHeatSensCap == AutoSize) && ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitCapacity) ||
1872 0 : (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) {
1873 0 : IsAutoSize = true;
1874 : }
1875 219 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
1876 207 : if (PurchAir(PurchAirNum).MaxHeatSensCap > 0.0) {
1877 0 : HeatingCapacitySizer sizerHeatingCapacity;
1878 0 : sizerHeatingCapacity.overrideSizingString(SizingString);
1879 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1880 0 : MaxHeatSensCapDes = sizerHeatingCapacity.size(state, PurchAir(PurchAirNum).MaxHeatSensCap, ErrorsFound);
1881 0 : }
1882 : } else {
1883 12 : TempSize = PurchAir(PurchAirNum).MaxHeatSensCap;
1884 12 : ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
1885 12 : state.dataSize->ZoneHeatingOnlyFan = true;
1886 12 : PrintFlag = false;
1887 12 : HeatingCapacitySizer sizerHeatingCapacity;
1888 12 : sizerHeatingCapacity.overrideSizingString(SizingString);
1889 12 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1890 12 : MaxHeatSensCapDes = sizerHeatingCapacity.size(state, TempSize, ErrorsFound);
1891 12 : state.dataSize->ZoneHeatingOnlyFan = false;
1892 12 : }
1893 219 : if (MaxHeatSensCapDes < HVAC::SmallLoad) {
1894 219 : MaxHeatSensCapDes = 0.0;
1895 : }
1896 219 : if (IsAutoSize) {
1897 0 : PurchAir(PurchAirNum).MaxHeatSensCap = MaxHeatSensCapDes;
1898 0 : BaseSizer::reportSizerOutput(state,
1899 0 : PurchAir(PurchAirNum).cObjectName,
1900 0 : PurchAir(PurchAirNum).Name,
1901 : "Design Size Maximum Sensible Heating Capacity [W]",
1902 : MaxHeatSensCapDes);
1903 : // If there is OA, check if sizing calcs have OA>0, throw warning if not
1904 0 : if ((PurchAir(PurchAirNum).OutdoorAir) && (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA == 0.0)) {
1905 0 : ShowWarningError(state, format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
1906 0 : ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this ");
1907 0 : ShowContinueError(state, "zone is zero. The Maximum Sensible Heating Capacity will be autosized for zero outdoor air flow. ");
1908 0 : ShowContinueError(state,
1909 0 : format("Check the outdoor air specifications in the Sizing:Zone object for zone {}.",
1910 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneName));
1911 : }
1912 : } else {
1913 219 : if (PurchAir(PurchAirNum).MaxHeatSensCap > 0.0 && MaxHeatSensCapDes > 0.0) {
1914 0 : MaxHeatSensCapUser = PurchAir(PurchAirNum).MaxHeatSensCap;
1915 0 : BaseSizer::reportSizerOutput(state,
1916 0 : PurchAir(PurchAirNum).cObjectName,
1917 0 : PurchAir(PurchAirNum).Name,
1918 : "Design Size Maximum Sensible Heating Capacity [W]",
1919 : MaxHeatSensCapDes,
1920 : "User-Specified Maximum Sensible Heating Capacity [W]",
1921 : MaxHeatSensCapUser);
1922 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1923 0 : if ((std::abs(MaxHeatSensCapDes - MaxHeatSensCapUser) / MaxHeatSensCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
1924 0 : ShowMessage(state,
1925 0 : format("SizePurchasedAir: Potential issue with equipment sizing for {} {}",
1926 0 : PurchAir(PurchAirNum).cObjectName,
1927 0 : PurchAir(PurchAirNum).Name));
1928 0 : ShowContinueError(state, format("...User-Specified Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapUser));
1929 0 : ShowContinueError(
1930 0 : state, format("...differs from Design Size Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapDes));
1931 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1932 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1933 : }
1934 : }
1935 : }
1936 : }
1937 :
1938 219 : PrintFlag = true;
1939 219 : IsAutoSize = false;
1940 402 : if ((PurchAir(PurchAirNum).MaxCoolVolFlowRate == AutoSize) &&
1941 183 : ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
1942 179 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) ||
1943 179 : (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) {
1944 4 : IsAutoSize = true;
1945 : }
1946 219 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
1947 207 : if (PurchAir(PurchAirNum).MaxCoolVolFlowRate > 0.0) {
1948 2 : CoolingAirFlowSizer sizingCoolingAirFlow;
1949 2 : std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]";
1950 2 : if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]";
1951 2 : sizingCoolingAirFlow.overrideSizingString(stringOverride);
1952 : // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1953 2 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1954 4 : PurchAir(PurchAirNum).MaxCoolVolFlowRate =
1955 2 : sizingCoolingAirFlow.size(state, PurchAir(PurchAirNum).MaxCoolVolFlowRate, ErrorsFound);
1956 2 : }
1957 : } else {
1958 12 : state.dataSize->ZoneCoolingOnlyFan = true;
1959 12 : TempSize = PurchAir(PurchAirNum).MaxCoolVolFlowRate;
1960 12 : CoolingAirFlowSizer sizingCoolingAirFlow;
1961 12 : std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]";
1962 12 : if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]";
1963 12 : sizingCoolingAirFlow.overrideSizingString(stringOverride);
1964 : // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1965 12 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1966 12 : MaxCoolVolFlowRateDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
1967 12 : PurchAir(PurchAirNum).MaxCoolVolFlowRate = MaxCoolVolFlowRateDes;
1968 12 : state.dataSize->ZoneCoolingOnlyFan = false;
1969 12 : }
1970 :
1971 219 : IsAutoSize = false;
1972 219 : SizingMethod = CoolingCapacitySizing;
1973 219 : FieldNum = 8; // N8, \field Maximum Total Cooling Capacity
1974 219 : SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]";
1975 219 : if ((PurchAir(PurchAirNum).MaxCoolTotCap == AutoSize) && ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) ||
1976 0 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity))) {
1977 0 : IsAutoSize = true;
1978 : }
1979 219 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
1980 207 : if (PurchAir(PurchAirNum).MaxCoolTotCap > 0.0) {
1981 0 : CoolingCapacitySizer sizerCoolingCapacity;
1982 0 : sizerCoolingCapacity.overrideSizingString(SizingString);
1983 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1984 0 : PurchAir(PurchAirNum).MaxCoolTotCap = sizerCoolingCapacity.size(state, PurchAir(PurchAirNum).MaxCoolTotCap, ErrorsFound);
1985 0 : }
1986 : } else {
1987 12 : state.dataSize->ZoneCoolingOnlyFan = true;
1988 12 : ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
1989 12 : PrintFlag = false;
1990 12 : TempSize = PurchAir(PurchAirNum).MaxCoolTotCap;
1991 12 : CoolingCapacitySizer sizerCoolingCapacity;
1992 12 : sizerCoolingCapacity.overrideSizingString(SizingString);
1993 12 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1994 12 : MaxCoolTotCapDes = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
1995 12 : state.dataSize->ZoneCoolingOnlyFan = false;
1996 12 : }
1997 219 : if (MaxCoolTotCapDes < HVAC::SmallLoad) {
1998 219 : MaxCoolTotCapDes = 0.0;
1999 : }
2000 219 : if (IsAutoSize) {
2001 0 : PurchAir(PurchAirNum).MaxCoolTotCap = MaxCoolTotCapDes;
2002 0 : BaseSizer::reportSizerOutput(state,
2003 0 : PurchAir(PurchAirNum).cObjectName,
2004 0 : PurchAir(PurchAirNum).Name,
2005 : "Design Size Maximum Total Cooling Capacity [W]",
2006 : MaxCoolTotCapDes);
2007 : // If there is OA, check if sizing calcs have OA>0, throw warning if not
2008 0 : if ((PurchAir(PurchAirNum).OutdoorAir) && (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA == 0.0)) {
2009 0 : ShowWarningError(state, format("SizePurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
2010 0 : ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this ");
2011 0 : ShowContinueError(state, "zone is zero. The Maximum Total Cooling Capacity will be autosized for zero outdoor air flow. ");
2012 0 : ShowContinueError(state,
2013 0 : format("Check the outdoor air specifications in the Sizing:Zone object for zone {}.",
2014 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneName));
2015 : }
2016 : } else {
2017 219 : if (PurchAir(PurchAirNum).MaxCoolTotCap > 0.0 && MaxCoolTotCapDes > 0.0) {
2018 0 : MaxCoolTotCapUser = PurchAir(PurchAirNum).MaxCoolTotCap;
2019 0 : BaseSizer::reportSizerOutput(state,
2020 0 : PurchAir(PurchAirNum).cObjectName,
2021 0 : PurchAir(PurchAirNum).Name,
2022 : "Design Size Maximum Total Cooling Capacity [W]",
2023 : MaxCoolTotCapDes,
2024 : "User-Specified Maximum Total Cooling Capacity [W]",
2025 : MaxCoolTotCapUser);
2026 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2027 0 : if ((std::abs(MaxCoolTotCapDes - MaxCoolTotCapUser) / MaxCoolTotCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
2028 0 : ShowMessage(state,
2029 0 : format("SizePurchasedAir: Potential issue with equipment sizing for {} {}",
2030 0 : PurchAir(PurchAirNum).cObjectName,
2031 0 : PurchAir(PurchAirNum).Name));
2032 0 : ShowContinueError(state, format("User-Specified Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapUser));
2033 0 : ShowContinueError(state,
2034 0 : format("differs from Design Size Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapDes));
2035 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2036 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2037 : }
2038 : }
2039 : }
2040 : }
2041 : }
2042 : }
2043 :
2044 : // IF (PurchAir(PurchAirNum)%OutdoorAir .AND. PurchAir(PurchAirNum)%OutsideAirVolFlowRate == AutoSize) THEN
2045 : // IF (CurZoneEqNum > 0) THEN
2046 : // CALL CheckZoneSizing(TRIM(PurchAir(PurchAirNum)%cObjectName), PurchAir(PurchAirNum)%Name)
2047 : // PurchAir(PurchAirNum)%OutsideAirVolFlowRate = FinalZoneSizing(CurZoneEqNum)%MinOA
2048 : // IF (PurchAir(PurchAirNum)%OutsideAirVolFlowRate < SmallAirVolFlow) THEN
2049 : // PurchAir(PurchAirNum)%OutsideAirVolFlowRate = 0.0
2050 : // END IF
2051 : // CALL BaseSizer::reportSizerOutput(TRIM(PurchAir(PurchAirNum)%cObjectName), PurchAir(PurchAirNum)%Name, &
2052 : // 'Outdoor Air Flow Rate [m3/s]', PurchAir(PurchAirNum)%OutsideAirVolFlowRate )
2053 : // END IF
2054 : // END IF
2055 219 : }
2056 :
2057 2076247 : void CalcPurchAirLoads(EnergyPlusData &state,
2058 : int const PurchAirNum,
2059 : Real64 &SysOutputProvided, // Sensible output provided [W] cooling = negative
2060 : Real64 &MoistOutputProvided, // Moisture output provided [kg/s] dehumidification = negative
2061 : int const ControlledZoneNum)
2062 : {
2063 :
2064 : // SUBROUTINE INFORMATION:
2065 : // AUTHOR Russ Taylor
2066 : // DATE WRITTEN Nov 1997
2067 : // MODIFIED Shirey, Aug 2009 (LatOutputProvided - now MoistOutputProvided)
2068 : // M. Witte June 2011, add new features including DCV, economizer, dehumidification
2069 : // and humidification,
2070 : // July 2012, Chandan Sharma - FSEC: Added hybrid ventilation manager
2071 : // RE-ENGINEERED na
2072 :
2073 : // SUBROUTINE PARAMETER DEFINITIONS:
2074 : static constexpr std::string_view RoutineName("CalcPurchAirLoads");
2075 :
2076 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2077 : int InNodeNum; // Ideal loads supply node to zone
2078 : // INTEGER :: ExhNodeNum ! Ideal loads exhaust node from zone
2079 : int ZoneNodeNum; // Zone air node
2080 : int OANodeNum; // Outdoor air inlet node
2081 : int RecircNodeNum; // Return air or zone exhaust node
2082 : OpMode OperatingMode; // current operating mode, Off, Heat, Cool, or DeadBand
2083 : Real64 SupplyMassFlowRate; // System supply air mass flow rate [kg/s]
2084 : Real64 SupplyMassFlowRateForHumid; // System supply air mass flow rate required to meet humdification load [kg/s]
2085 : Real64 SupplyMassFlowRateForDehum; // System supply air mass flow rate required to meet dehumidification load [kg/s]
2086 : Real64 SupplyMassFlowRateForCool; // System supply air mass flow rate required to meet sensible cooling load[kg/s]
2087 : Real64 SupplyMassFlowRateForHeat; // System supply air mass flow rate required to meet sensible heating load[kg/s]
2088 : Real64 SupplyHumRatForHumid; // Supply air humidity ratio require to meet the humidification load [kgWater/kgDryAir]
2089 : Real64 SupplyHumRatForDehum; // Supply air humidity ratio require to meet the dehumidification load [kgWater/kgDryAir]
2090 : Real64 OAMassFlowRate; // Outdoor air mass flow rate [kg/s]
2091 : Real64 OAVolFlowRate; // Outdoor air volume flow rate at standard density [m3/s]
2092 : Real64 MinOASensOutput; // Minimum Outdoor air sensible output [W], <0 means OA is cooler than zone air
2093 : Real64 MinOALatOutput; // Minimum Outdoor air moisture load [kg/s]
2094 : Real64 SensOutput; // Sensible output [W] (psitive means heating, negative means cooling)
2095 : Real64 HeatSensOutput; // Heating sensible output [W]
2096 : Real64 CoolSensOutput; // Cooling sensible output [W] (positive value menas cooling)
2097 : Real64 LatOutput; // Latent output [W] (positive value means hudmification, negative means dehumidification)
2098 : Real64 CoolLatOutput; // Cooling latent output [W] (positive value means dehumidification)
2099 : Real64 CoolTotOutput; // Cooling total output [W] (positive value means cooling)
2100 : Real64 DeltaT; // Delta temperature - reused in multiple places
2101 : Real64 DeltaHumRat; // Delta humidity ratio - reused in multiple places
2102 : Real64 QZnHeatSP; // Load required to meet heating setpoint [W] (>0 is a heating load)
2103 : Real64 QZnCoolSP; // Load required to meet cooling setpoint [W] (<0 is a cooling load)
2104 : Real64 MdotZnHumidSP; // Load required to meet humidifying setpoint [kgWater/s] (>0 = a humidify load)
2105 : Real64 MdotZnDehumidSP; // Load required to meet dehumidifying setpoint [kgWater/s] (<0 = a dehumidify load)
2106 : bool UnitOn;
2107 : bool HeatOn; // Flag for heating and humidification availbility schedule, true if heating is on
2108 : bool CoolOn; // Flag for cooling and dehumidification availbility schedule, true if cooling is on
2109 : bool EconoOn; // Flag for economizer operation, true if economizer is on
2110 : Real64 SupplyHumRatOrig; // Supply inlet to zone humidity ratio before saturation check [kgWater/kgDryAir]
2111 : Real64 SupplyHumRatSat; // Supply inlet to zone humidity ratio saturation at SupplyTemp [kgWater/kgDryAir]
2112 : Real64 SupplyEnthalpy; // Supply inlet to zone enthalpy [J/kg]
2113 : Real64 MixedAirEnthalpy; // Mixed air enthalpy [J/kg]
2114 : Real64 CpAir; // Specific heat [J/kg-C] reused in multiple places
2115 : // REAL(r64) :: SpecHumOut ! Specific humidity ratio of outlet air (kg moisture / kg moist air)
2116 : // REAL(r64) :: SpecHumIn ! Specific humidity ratio of inlet [zone] air (kg moisture / kg moist air)
2117 :
2118 2076247 : auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
2119 :
2120 : // Sign convention: SysOutputProvided <0 Supply air is heated on entering zone (zone is cooled)
2121 : // SysOutputProvided >0 Supply air is cooled on entering zone (zone is heated)
2122 2076247 : InNodeNum = PurchAir(PurchAirNum).ZoneSupplyAirNodeNum;
2123 2076247 : ZoneNodeNum = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
2124 2076247 : OANodeNum = PurchAir(PurchAirNum).OutdoorAirNodeNum;
2125 2076247 : RecircNodeNum = PurchAir(PurchAirNum).ZoneRecircAirNodeNum;
2126 2076247 : SupplyMassFlowRate = 0.0;
2127 2076247 : OAMassFlowRate = 0.0;
2128 2076247 : PurchAir(PurchAirNum).MinOAMassFlowRate = 0.0;
2129 2076247 : PurchAir(PurchAirNum).TimeEconoActive = 0.0;
2130 2076247 : PurchAir(PurchAirNum).TimeHtRecActive = 0.0;
2131 2076247 : SysOutputProvided = 0.0;
2132 2076247 : MoistOutputProvided = 0.0;
2133 2076247 : CoolSensOutput = 0.0;
2134 2076247 : CoolLatOutput = 0.0;
2135 2076247 : CoolTotOutput = 0.0;
2136 2076247 : HeatSensOutput = 0.0;
2137 2076247 : LatOutput = 0.0;
2138 :
2139 : // default unit to ON
2140 2076247 : UnitOn = true;
2141 2076247 : EconoOn = false;
2142 : // get current zone requirements
2143 2076247 : QZnHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
2144 2076247 : QZnCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
2145 :
2146 2076247 : if (allocated(state.dataAvail->ZoneComp)) {
2147 2076235 : auto &availMgr = state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::PurchasedAir).ZoneCompAvailMgrs(PurchAirNum);
2148 2076235 : availMgr.ZoneNum = ControlledZoneNum;
2149 2076235 : PurchAir(PurchAirNum).availStatus = availMgr.availStatus;
2150 : // Check if the hybrid ventilation availability manager is turning the unit off
2151 2076235 : if (PurchAir(PurchAirNum).availStatus == Avail::Status::ForceOff) {
2152 0 : UnitOn = false;
2153 : }
2154 : }
2155 :
2156 : // Check if the unit is scheduled off
2157 : // IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN
2158 2076247 : if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).AvailSchedPtr) <= 0) {
2159 0 : UnitOn = false;
2160 : }
2161 : // END IF
2162 : // Check if heating and cooling available
2163 2076247 : HeatOn = true;
2164 : // IF (PurchAir(PurchAirNum)%HeatSchedPtr > 0) THEN
2165 2076247 : if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).HeatSchedPtr) <= 0) {
2166 0 : HeatOn = false;
2167 : }
2168 : // END IF
2169 2076247 : CoolOn = true;
2170 : // IF (PurchAir(PurchAirNum)%CoolSchedPtr > 0) THEN
2171 2076247 : if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).CoolSchedPtr) <= 0) {
2172 8425 : CoolOn = false;
2173 : }
2174 : // END IF
2175 :
2176 2076247 : if (UnitOn) {
2177 2076247 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ControlledZoneNum);
2178 : // Calculate current minimum outdoor air flow rate based on design OA specifications and DCV or CO2 control
2179 2076247 : CalcPurchAirMinOAMassFlow(state, PurchAirNum, ControlledZoneNum, OAMassFlowRate);
2180 :
2181 : // EMS override point Purch air outdoor air massflow rate.....
2182 2076247 : if (PurchAir(PurchAirNum).EMSOverrideOAMdotOn) {
2183 0 : OAMassFlowRate = PurchAir(PurchAirNum).EMSValueOAMassFlowRate;
2184 : }
2185 :
2186 : // Calculate minimum outdoor air sensible and latent load
2187 2076247 : if (PurchAir(PurchAirNum).OutdoorAir) {
2188 14788 : CpAir = PsyCpAirFnW(state.dataLoopNodes->Node(OANodeNum).HumRat);
2189 14788 : MinOASensOutput = OAMassFlowRate * CpAir * (state.dataLoopNodes->Node(OANodeNum).Temp - state.dataLoopNodes->Node(ZoneNodeNum).Temp);
2190 14788 : MinOALatOutput = OAMassFlowRate * (state.dataLoopNodes->Node(OANodeNum).HumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
2191 : } else {
2192 2061459 : MinOASensOutput = 0.0;
2193 2061459 : MinOALatOutput = 0.0;
2194 : }
2195 2076247 : SupplyMassFlowRate = OAMassFlowRate;
2196 :
2197 : // Check if cooling of the supply air stream is required
2198 :
2199 : // Cooling operation
2200 2076247 : if ((MinOASensOutput >= QZnCoolSP) && (state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::ThermostatType::SingleHeating)) {
2201 540317 : OperatingMode = OpMode::Cool;
2202 : // Calculate supply mass flow, temp and humidity with the following constraints:
2203 : // Min cooling supply temp
2204 : // Max total cooling capacity
2205 : // Max cooling airflow
2206 : // Min cooling supply humrat (and Max heating supply humrat)
2207 : // Min OA mass flow rate
2208 :
2209 : // Check if OA flow rate greater than max cooling airflow limit
2210 540317 : if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
2211 552738 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) &&
2212 12421 : (OAMassFlowRate > PurchAir(PurchAirNum).MaxCoolMassFlowRate)) {
2213 0 : OAVolFlowRate = OAMassFlowRate / state.dataEnvrn->StdRhoAir;
2214 0 : if (PurchAir(PurchAirNum).OAFlowMaxCoolOutputError < 1) {
2215 0 : ++PurchAir(PurchAirNum).OAFlowMaxCoolOutputError;
2216 0 : ShowWarningError(state,
2217 0 : format("{} \"{}\" Requested outdoor air flow rate = {:.5T} [m3/s] exceeds limit.",
2218 0 : PurchAir(PurchAirNum).cObjectName,
2219 0 : PurchAir(PurchAirNum).Name,
2220 : OAVolFlowRate));
2221 0 : ShowContinueError(
2222 : state,
2223 0 : format(" Will be reduced to the Maximum Cooling Air Flow Rate = {:.5T} [m3/s]", PurchAir(PurchAirNum).MaxCoolVolFlowRate));
2224 0 : ShowContinueErrorTimeStamp(state, "");
2225 : } else {
2226 0 : ShowRecurringWarningErrorAtEnd(
2227 : state,
2228 0 : PurchAir(PurchAirNum).cObjectName + " \"" + PurchAir(PurchAirNum).Name +
2229 : "\" Requested outdoor air flow rate [m3/s] reduced to Maximum Cooling Air Flow Rate warning continues...",
2230 0 : PurchAir(PurchAirNum).OAFlowMaxCoolOutputIndex,
2231 : OAVolFlowRate);
2232 : }
2233 0 : OAMassFlowRate = PurchAir(PurchAirNum).MaxCoolMassFlowRate;
2234 :
2235 : } else {
2236 : // Model economizer
2237 540317 : if (PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer) {
2238 5122 : if (((PurchAir(PurchAirNum).EconomizerType == Econ::DifferentialDryBulb) &&
2239 10060 : (state.dataLoopNodes->Node(OANodeNum).Temp < state.dataLoopNodes->Node(PurchAir(PurchAirNum).ZoneRecircAirNodeNum).Temp)) ||
2240 4938 : ((PurchAir(PurchAirNum).EconomizerType == Econ::DifferentialEnthalpy) &&
2241 1702 : (state.dataLoopNodes->Node(OANodeNum).Enthalpy <
2242 1702 : state.dataLoopNodes->Node(PurchAir(PurchAirNum).ZoneRecircAirNodeNum).Enthalpy))) {
2243 :
2244 : // Calculate supply MassFlowRate based on sensible load but limit to Max Cooling Supply Air Flow Rate if specified
2245 184 : CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
2246 184 : DeltaT = (state.dataLoopNodes->Node(OANodeNum).Temp - state.dataLoopNodes->Node(ZoneNodeNum).Temp);
2247 184 : if (DeltaT < -HVAC::SmallTempDiff) {
2248 184 : SupplyMassFlowRate = QZnCoolSP / CpAir / DeltaT;
2249 184 : if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
2250 368 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) &&
2251 184 : (PurchAir(PurchAirNum).MaxCoolMassFlowRate > 0.0)) {
2252 184 : SupplyMassFlowRate = min(max(SupplyMassFlowRate, 0.0), PurchAir(PurchAirNum).MaxCoolMassFlowRate);
2253 : }
2254 184 : if (SupplyMassFlowRate > OAMassFlowRate) {
2255 184 : EconoOn = true;
2256 184 : OAMassFlowRate = SupplyMassFlowRate;
2257 184 : PurchAir(PurchAirNum).TimeEconoActive = state.dataHVACGlobal->TimeStepSys;
2258 : }
2259 : }
2260 : }
2261 : }
2262 : }
2263 :
2264 : // Determine supply mass flow rate
2265 : // Mass flow rate to meet sensible load, at Minimum Cooling Supply Air Temperature
2266 540317 : SupplyMassFlowRateForCool = 0.0;
2267 540317 : if (CoolOn) {
2268 535856 : CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
2269 535856 : DeltaT = (PurchAir(PurchAirNum).MinCoolSuppAirTemp - state.dataLoopNodes->Node(ZoneNodeNum).Temp);
2270 535856 : if (DeltaT < -HVAC::SmallTempDiff) {
2271 534980 : SupplyMassFlowRateForCool = QZnCoolSP / CpAir / DeltaT;
2272 : }
2273 : }
2274 :
2275 : // Mass flow rate to meet dehumidification load, if applicable, at Minimum Cooling Supply Humidity Ratio
2276 540317 : SupplyMassFlowRateForDehum = 0.0;
2277 540317 : if (CoolOn) {
2278 535856 : if (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) {
2279 11636 : MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToDehumidSP;
2280 11636 : DeltaHumRat = (PurchAir(PurchAirNum).MinCoolSuppAirHumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
2281 11636 : if ((DeltaHumRat < -SmallDeltaHumRat) && (MdotZnDehumidSP < 0.0)) {
2282 188 : SupplyMassFlowRateForDehum = MdotZnDehumidSP / DeltaHumRat;
2283 : }
2284 : }
2285 : }
2286 :
2287 : // Mass flow rate to meet humidification load, if applicable, at Maximum Heating Supply Humidity Ratio
2288 : // This section is the cooling section, so humidification should activate only if humidification control = humidistat
2289 : // and if dehumidification control = humidistat or none
2290 540317 : SupplyMassFlowRateForHumid = 0.0;
2291 540317 : if (HeatOn) {
2292 540317 : if (PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) {
2293 4994 : if ((PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) ||
2294 1646 : (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::None)) {
2295 1702 : MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToHumidSP;
2296 1702 : DeltaHumRat = (PurchAir(PurchAirNum).MaxHeatSuppAirHumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
2297 1702 : if ((DeltaHumRat > SmallDeltaHumRat) && (MdotZnHumidSP > 0.0)) {
2298 0 : SupplyMassFlowRateForHumid = MdotZnHumidSP / DeltaHumRat;
2299 : }
2300 : }
2301 : }
2302 : }
2303 :
2304 : // If cooling capacity is limited to zero, SupplyMassFlowRate* should be set to zero
2305 540317 : if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) ||
2306 540317 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) &&
2307 0 : (PurchAir(PurchAirNum).MaxCoolTotCap == 0)) {
2308 0 : SupplyMassFlowRateForCool = 0;
2309 0 : SupplyMassFlowRateForDehum = 0;
2310 0 : SupplyMassFlowRateForHumid = 0;
2311 : }
2312 :
2313 : // Supply mass flow is greatest of these, but limit to cooling max flow rate, if applicable
2314 540317 : SupplyMassFlowRate = max(0.0, OAMassFlowRate, SupplyMassFlowRateForCool, SupplyMassFlowRateForDehum, SupplyMassFlowRateForHumid);
2315 : // EMS override point Purch air massflow rate..... but only if unit is on, i.e. SupplyMassFlowRate>0.0
2316 540317 : if (PurchAir(PurchAirNum).EMSOverrideMdotOn) {
2317 79816 : SupplyMassFlowRate = PurchAir(PurchAirNum).EMSValueMassFlowRate;
2318 79816 : OAMassFlowRate = min(OAMassFlowRate, SupplyMassFlowRate);
2319 : }
2320 540317 : if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
2321 552738 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) &&
2322 12421 : (PurchAir(PurchAirNum).MaxCoolMassFlowRate > 0.0)) {
2323 12420 : SupplyMassFlowRate = min(SupplyMassFlowRate, PurchAir(PurchAirNum).MaxCoolMassFlowRate);
2324 : }
2325 :
2326 540317 : if (SupplyMassFlowRate <= HVAC::VerySmallMassFlow) SupplyMassFlowRate = 0.0;
2327 :
2328 : // Calculate mixed air conditions
2329 540317 : CalcPurchAirMixedAir(state,
2330 : PurchAirNum,
2331 : OAMassFlowRate,
2332 : SupplyMassFlowRate,
2333 540317 : PurchAir(PurchAirNum).MixedAirTemp,
2334 540317 : PurchAir(PurchAirNum).MixedAirHumRat,
2335 : MixedAirEnthalpy,
2336 : OperatingMode);
2337 :
2338 : // Calculate supply air conditions using final massflow rate, imposing capacity limits if specified
2339 : // If capacity limits are exceeded, keep massflow rate where it is and adjust supply temp
2340 : // In general, in the cooling section, don't let SupplyTemp be set to something that results in heating
2341 540317 : if (SupplyMassFlowRate > 0.0) {
2342 : // Calculate supply temp at SupplyMassFlowRate and recheck limit on Minimum Cooling Supply Air Temperature
2343 534980 : CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
2344 534980 : PurchAir(PurchAirNum).SupplyTemp = QZnCoolSP / (CpAir * SupplyMassFlowRate) + state.dataLoopNodes->Node(ZoneNodeNum).Temp;
2345 534980 : PurchAir(PurchAirNum).SupplyTemp = max(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MinCoolSuppAirTemp);
2346 : // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
2347 534980 : PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp);
2348 534980 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
2349 534980 : SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
2350 :
2351 : // Check sensible load vs max total cooling capacity, if specified, and adjust supply temp before applying humidity controls
2352 : // Will check again later, too
2353 1069960 : if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) ||
2354 534980 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) {
2355 0 : CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
2356 0 : CoolSensOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy);
2357 0 : if (CoolSensOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) {
2358 0 : CoolSensOutput = PurchAir(PurchAirNum).MaxCoolTotCap;
2359 0 : SupplyEnthalpy = MixedAirEnthalpy - CoolSensOutput / SupplyMassFlowRate;
2360 0 : PurchAir(PurchAirNum).SupplyTemp = PsyTdbFnHW(SupplyEnthalpy, PurchAir(PurchAirNum).SupplyHumRat);
2361 : // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
2362 0 : PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp);
2363 : } // Capacity limit exceeded
2364 : }
2365 :
2366 : // Set supply humidity ratio for cooling/dehumidification
2367 534980 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
2368 534980 : switch (PurchAir(PurchAirNum).DehumidCtrlType) {
2369 30 : case HumControl::None: {
2370 30 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; // Unnecessary line?
2371 30 : } break;
2372 35627 : case HumControl::ConstantSensibleHeatRatio: {
2373 : // SHR = CoolSensOutput/CoolTotOutput
2374 : // CoolTotOutput = CoolSensOutput/SHR
2375 35627 : CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
2376 35627 : CoolSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).MixedAirTemp - PurchAir(PurchAirNum).SupplyTemp);
2377 35627 : CoolTotOutput = CoolSensOutput / PurchAir(PurchAirNum).CoolSHR;
2378 35627 : SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput / SupplyMassFlowRate;
2379 : // Limit for overdrying (avoid Pysch errors which occur if SupplyEnthalpy is too low for SupplyTemp)
2380 35627 : SupplyEnthalpy = max(SupplyEnthalpy, PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, 0.00001));
2381 35627 : PurchAir(PurchAirNum).SupplyHumRat =
2382 35627 : min(PurchAir(PurchAirNum).SupplyHumRat, PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName));
2383 : // Apply min cooling humidity ratio limit
2384 35627 : PurchAir(PurchAirNum).SupplyHumRat = max(PurchAir(PurchAirNum).SupplyHumRat, PurchAir(PurchAirNum).MinCoolSuppAirHumRat);
2385 : // But don't let it be higher than incoming MixedAirHumRat
2386 35627 : PurchAir(PurchAirNum).SupplyHumRat = min(PurchAir(PurchAirNum).SupplyHumRat, PurchAir(PurchAirNum).MixedAirHumRat);
2387 35627 : } break;
2388 11636 : case HumControl::Humidistat: {
2389 11636 : MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToDehumidSP;
2390 11636 : SupplyHumRatForDehum = MdotZnDehumidSP / SupplyMassFlowRate + state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
2391 11636 : SupplyHumRatForDehum = max(SupplyHumRatForDehum, PurchAir(PurchAirNum).MinCoolSuppAirHumRat);
2392 11636 : PurchAir(PurchAirNum).SupplyHumRat = min(PurchAir(PurchAirNum).MixedAirHumRat, SupplyHumRatForDehum);
2393 11636 : } break;
2394 487687 : case HumControl::ConstantSupplyHumidityRatio: {
2395 487687 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MinCoolSuppAirHumRat;
2396 487687 : } break;
2397 0 : default: {
2398 0 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
2399 0 : } break;
2400 : }
2401 :
2402 : // Check supply humidity ratio for humidification (SupplyHumRatForHum should always be < SupplyHumRatForDehum)
2403 : // This section is the cooling section, so humidification should activate only if humidification control = humidistat
2404 : // and if dehumidification control = humidistat or none
2405 534980 : if (HeatOn) {
2406 534980 : if (PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) {
2407 4994 : if ((PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) ||
2408 1646 : (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::None)) {
2409 1702 : MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToHumidSP;
2410 1702 : SupplyHumRatForHumid = MdotZnHumidSP / SupplyMassFlowRate + state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
2411 1702 : SupplyHumRatForHumid = min(SupplyHumRatForHumid, PurchAir(PurchAirNum).MaxHeatSuppAirHumRat);
2412 1702 : PurchAir(PurchAirNum).SupplyHumRat = max(PurchAir(PurchAirNum).SupplyHumRat, SupplyHumRatForHumid);
2413 : }
2414 : }
2415 : }
2416 :
2417 : // Limit supply humidity ratio to saturation at supply outlet temp
2418 :
2419 534980 : SupplyHumRatOrig = PurchAir(PurchAirNum).SupplyHumRat;
2420 534980 : SupplyHumRatSat = PsyWFnTdbRhPb(state, PurchAir(PurchAirNum).SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
2421 534980 : PurchAir(PurchAirNum).SupplyHumRat = min(SupplyHumRatOrig, SupplyHumRatSat);
2422 534980 : SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
2423 :
2424 : // Check max total Cooling capacity, if specified
2425 1069960 : if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) ||
2426 534980 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) {
2427 : // If dehumidifying, compare total cooling to the limit
2428 0 : if (PurchAir(PurchAirNum).SupplyHumRat < PurchAir(PurchAirNum).MixedAirHumRat) { // Dehumidifying
2429 0 : CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy);
2430 0 : if ((CoolTotOutput) > PurchAir(PurchAirNum).MaxCoolTotCap) {
2431 0 : CoolTotOutput = PurchAir(PurchAirNum).MaxCoolTotCap;
2432 0 : SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput / SupplyMassFlowRate;
2433 : // Adjust output based on dehumidification control type
2434 0 : switch (PurchAir(PurchAirNum).DehumidCtrlType) {
2435 0 : case HumControl::ConstantSensibleHeatRatio: {
2436 : // Adjust both supply temp and humidity ratio to maintain SHR
2437 : // SHR = CoolSensOutput/CoolTotOutput
2438 : // CoolSensOutput = SHR*CoolTotOutput
2439 0 : CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
2440 0 : CoolSensOutput = CoolTotOutput * PurchAir(PurchAirNum).CoolSHR;
2441 0 : PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp - CoolSensOutput / (CpAir * SupplyMassFlowRate);
2442 : // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
2443 0 : PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp);
2444 : // Limit for overdrying (avoid Pysch errors which occur if SupplyEnthalpy is too low for SupplyTemp)
2445 0 : SupplyEnthalpy = max(SupplyEnthalpy, PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, 0.00001));
2446 0 : PurchAir(PurchAirNum).SupplyHumRat = PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName);
2447 0 : } break;
2448 0 : case HumControl::Humidistat: {
2449 : // Keep supply temp and adjust humidity ratio to reduce load
2450 0 : PurchAir(PurchAirNum).SupplyHumRat = PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName);
2451 0 : } break;
2452 0 : case HumControl::None:
2453 : case HumControl::ConstantSupplyHumidityRatio: {
2454 : // Keep humidity ratio and adjust supply temp
2455 : // Check if latent output exceeds capacity
2456 0 : CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
2457 0 : CoolSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).MixedAirTemp - PurchAir(PurchAirNum).SupplyTemp);
2458 0 : CoolLatOutput = CoolTotOutput - CoolSensOutput;
2459 0 : if (CoolLatOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) {
2460 0 : PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp;
2461 0 : PurchAir(PurchAirNum).SupplyHumRat =
2462 0 : PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName);
2463 0 : CoolLatOutput = PurchAir(PurchAirNum).MaxCoolTotCap;
2464 : } else {
2465 0 : PurchAir(PurchAirNum).SupplyTemp = PsyTdbFnHW(SupplyEnthalpy, PurchAir(PurchAirNum).SupplyHumRat);
2466 : // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
2467 0 : PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp);
2468 : }
2469 0 : } break;
2470 0 : default:
2471 0 : break;
2472 : }
2473 : // Limit supply humidity ratio to saturation at supply outlet temp
2474 : // If saturation exceeded, then honor capacity limit and set to dew point at supplyenthalpy
2475 :
2476 0 : SupplyHumRatOrig = PurchAir(PurchAirNum).SupplyHumRat;
2477 0 : SupplyHumRatSat = PsyWFnTdbRhPb(state, PurchAir(PurchAirNum).SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
2478 0 : if (SupplyHumRatSat < SupplyHumRatOrig) {
2479 0 : PurchAir(PurchAirNum).SupplyTemp = PsyTsatFnHPb(state, SupplyEnthalpy, state.dataEnvrn->OutBaroPress, RoutineName);
2480 :
2481 : // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
2482 0 : PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp);
2483 0 : PurchAir(PurchAirNum).SupplyHumRat = PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName);
2484 0 : SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
2485 : // CpAir = PsyCpAirFnW(MixedAirHumRat)
2486 : // CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp)
2487 : // CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy)
2488 : }
2489 : } // Capacity limit exceeded
2490 : } else { // Not dehumidifying
2491 : // If not dehumidifying, compare sensible cooling to the limit
2492 : // This section will only increase supply temp, so no need to recheck for super-saturation
2493 0 : CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
2494 0 : CoolSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).MixedAirTemp - PurchAir(PurchAirNum).SupplyTemp);
2495 0 : if (CoolSensOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) {
2496 0 : CoolSensOutput = PurchAir(PurchAirNum).MaxCoolTotCap;
2497 0 : PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp - CoolSensOutput / (SupplyMassFlowRate * CpAir);
2498 : } // Capacity limit exceeded
2499 : } // Dehumidifying or not
2500 : } // Capacity limit active
2501 :
2502 : } else { // SupplyMassFlowRate is zero
2503 5337 : SupplyEnthalpy = MixedAirEnthalpy;
2504 5337 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
2505 5337 : PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp;
2506 5337 : CoolSensOutput = 0.0;
2507 5337 : CoolTotOutput = 0.0;
2508 : }
2509 : // Heating or no-load operation
2510 : } else { // Heating or no-load case
2511 2680373 : if ((MinOASensOutput < QZnHeatSP) &&
2512 1144443 : (state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::ThermostatType::SingleCooling)) {
2513 759612 : OperatingMode = OpMode::Heat;
2514 : } else { // DeadBand mode shuts off heat recovery and economizer
2515 776318 : OperatingMode = OpMode::DeadBand;
2516 : }
2517 : // Calculate supply mass flow, temp and humidity with the following constraints:
2518 : // Max heating supply temp
2519 : // Max sensible heating capacity
2520 : // Max heating airflow
2521 : // Max heating supply humrat (and Min cooling supply humrat)
2522 : // Min OA mass flow rate
2523 :
2524 : // Check if OA flow rate greater than max heating airflow limit
2525 1535930 : if (((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
2526 1544737 : (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) &&
2527 8807 : (OAMassFlowRate > PurchAir(PurchAirNum).MaxHeatMassFlowRate)) {
2528 0 : OAVolFlowRate = OAMassFlowRate / state.dataEnvrn->StdRhoAir;
2529 0 : if (PurchAir(PurchAirNum).OAFlowMaxHeatOutputError < 1) {
2530 0 : ++PurchAir(PurchAirNum).OAFlowMaxHeatOutputError;
2531 0 : ShowWarningError(state,
2532 0 : format("{} \"{}\" Requested outdoor air flow rate = {:.5T} [m3/s] exceeds limit.",
2533 0 : PurchAir(PurchAirNum).cObjectName,
2534 0 : PurchAir(PurchAirNum).Name,
2535 : OAVolFlowRate));
2536 0 : ShowContinueError(
2537 : state,
2538 0 : format(" Will be reduced to the Maximum Heating Air Flow Rate = {:.5T} [m3/s]", PurchAir(PurchAirNum).MaxHeatVolFlowRate));
2539 0 : ShowContinueErrorTimeStamp(state, "");
2540 : } else {
2541 0 : ShowRecurringWarningErrorAtEnd(
2542 : state,
2543 0 : PurchAir(PurchAirNum).cObjectName + " \"" + PurchAir(PurchAirNum).Name +
2544 : "\" Requested outdoor air flow rate [m3/s] reduced to Maximum Heating Air Flow Rate warning continues...",
2545 0 : PurchAir(PurchAirNum).OAFlowMaxHeatOutputIndex,
2546 : OAVolFlowRate);
2547 : }
2548 0 : OAMassFlowRate = PurchAir(PurchAirNum).MaxHeatMassFlowRate;
2549 : }
2550 :
2551 1535930 : SupplyMassFlowRate = OAMassFlowRate;
2552 :
2553 : // Determine supply mass flow rate
2554 : // Mass flow rate to meet sensible load, at Minimum Cooling Supply Air Temperature
2555 1535930 : SupplyMassFlowRateForHeat = 0.0;
2556 1535930 : if ((HeatOn) && (OperatingMode == OpMode::Heat)) {
2557 759612 : CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
2558 759612 : DeltaT = (PurchAir(PurchAirNum).MaxHeatSuppAirTemp - state.dataLoopNodes->Node(ZoneNodeNum).Temp);
2559 759612 : if (DeltaT > HVAC::SmallTempDiff) {
2560 759612 : SupplyMassFlowRateForHeat = QZnHeatSP / CpAir / DeltaT;
2561 : }
2562 : }
2563 :
2564 : // Mass flow rate to meet dehumidification load, if applicable, at Minimum Cooling Supply Humidity Ratio
2565 : // This section is the heating/deadband section, so dehumidification should activate
2566 : // only if dehumidification control = humidistat
2567 : // and if humidification control = humidistat or none or if operating in deadband mode
2568 1535930 : SupplyMassFlowRateForDehum = 0.0;
2569 1535930 : if (CoolOn) {
2570 1531966 : if (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) {
2571 8956 : if ((PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) ||
2572 8956 : (PurchAir(PurchAirNum).HumidCtrlType == HumControl::None) || (OperatingMode == OpMode::DeadBand)) {
2573 8956 : MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToDehumidSP;
2574 8956 : DeltaHumRat = (PurchAir(PurchAirNum).MinCoolSuppAirHumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
2575 8956 : if ((DeltaHumRat < -SmallDeltaHumRat) && (MdotZnDehumidSP < 0.0)) {
2576 447 : SupplyMassFlowRateForDehum = MdotZnDehumidSP / DeltaHumRat;
2577 : }
2578 : }
2579 : }
2580 : }
2581 :
2582 : // Mass flow rate to meet humidification load, if applicable, at Maximum Heating Supply Humidity Ratio
2583 1535930 : SupplyMassFlowRateForHumid = 0.0;
2584 1535930 : if (HeatOn) {
2585 1535930 : if (PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) {
2586 4046 : MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToHumidSP;
2587 4046 : DeltaHumRat = (PurchAir(PurchAirNum).MaxHeatSuppAirHumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
2588 4046 : if ((DeltaHumRat > SmallDeltaHumRat) && (MdotZnHumidSP > 0.0)) {
2589 2810 : SupplyMassFlowRateForHumid = MdotZnHumidSP / DeltaHumRat;
2590 : }
2591 : }
2592 : }
2593 :
2594 : // If heating capacity is limited to zero, SupplyMassFlowRate* should be set to zero
2595 1535930 : if (((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitCapacity) ||
2596 1535930 : (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) &&
2597 0 : (PurchAir(PurchAirNum).MaxHeatSensCap == 0)) {
2598 0 : SupplyMassFlowRateForHeat = 0;
2599 0 : SupplyMassFlowRateForDehum = 0;
2600 0 : SupplyMassFlowRateForHumid = 0;
2601 : }
2602 :
2603 : // Supply mass flow is greatest of these, but limit to heating max flow rate, if applicable
2604 1535930 : SupplyMassFlowRate = max(0.0, OAMassFlowRate, SupplyMassFlowRateForHeat, SupplyMassFlowRateForDehum, SupplyMassFlowRateForHumid);
2605 : // EMS override point Purch air massflow rate..... but only if unit is on, i.e. SupplyMassFlowRate>0.0
2606 1535930 : if (PurchAir(PurchAirNum).EMSOverrideMdotOn) {
2607 162170 : SupplyMassFlowRate = PurchAir(PurchAirNum).EMSValueMassFlowRate;
2608 162170 : OAMassFlowRate = min(OAMassFlowRate, SupplyMassFlowRate);
2609 : }
2610 1535930 : if (((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
2611 1544737 : (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) &&
2612 8807 : (PurchAir(PurchAirNum).MaxHeatMassFlowRate > 0.0)) {
2613 8806 : SupplyMassFlowRate = min(SupplyMassFlowRate, PurchAir(PurchAirNum).MaxHeatMassFlowRate);
2614 : }
2615 :
2616 1535930 : if (SupplyMassFlowRate <= HVAC::VerySmallMassFlow) SupplyMassFlowRate = 0.0;
2617 :
2618 : // Calculate mixed air conditions
2619 1535930 : CalcPurchAirMixedAir(state,
2620 : PurchAirNum,
2621 : OAMassFlowRate,
2622 : SupplyMassFlowRate,
2623 1535930 : PurchAir(PurchAirNum).MixedAirTemp,
2624 1535930 : PurchAir(PurchAirNum).MixedAirHumRat,
2625 : MixedAirEnthalpy,
2626 : OperatingMode);
2627 :
2628 : // Calculate supply air conditions using final massflow rate, imposing capacity limits if specified
2629 : // If capacity limits are exceeded, keep massflow rate where it is and adjust supply temp
2630 1535930 : if (SupplyMassFlowRate > 0.0) {
2631 813748 : if ((HeatOn) && (OperatingMode == OpMode::Heat)) {
2632 : // Calculate supply temp at SupplyMassFlowRate and check limit on Maximum Heating Supply Air Temperature
2633 759612 : CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
2634 759612 : PurchAir(PurchAirNum).SupplyTemp = QZnHeatSP / (CpAir * SupplyMassFlowRate) + state.dataLoopNodes->Node(ZoneNodeNum).Temp;
2635 759612 : PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MaxHeatSuppAirTemp);
2636 : // This is the heating mode, so SupplyTemp can't be less than MixedAirTemp
2637 759612 : PurchAir(PurchAirNum).SupplyTemp = max(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp);
2638 : // Check max heating capacity, if specified
2639 1519224 : if ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitCapacity) ||
2640 759612 : (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) {
2641 0 : CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
2642 0 : HeatSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).SupplyTemp - PurchAir(PurchAirNum).MixedAirTemp);
2643 0 : if (HeatSensOutput > PurchAir(PurchAirNum).MaxHeatSensCap) {
2644 0 : PurchAir(PurchAirNum).SupplyTemp =
2645 0 : PurchAir(PurchAirNum).MaxHeatSensCap / (SupplyMassFlowRate * CpAir) + PurchAir(PurchAirNum).MixedAirTemp;
2646 0 : HeatSensOutput = PurchAir(PurchAirNum).MaxHeatSensCap;
2647 : }
2648 : }
2649 : } else { // Heat is off or operating mode is deadband (i.e. don't do any heating)
2650 54136 : PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp;
2651 : }
2652 :
2653 : // Set supply humidity ratio first for heating/humidification
2654 813748 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
2655 813748 : switch (PurchAir(PurchAirNum).HumidCtrlType) {
2656 55841 : case HumControl::None: {
2657 55841 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
2658 55841 : } break;
2659 3910 : case HumControl::Humidistat: {
2660 3910 : MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToHumidSP;
2661 3910 : SupplyHumRatForHumid = MdotZnHumidSP / SupplyMassFlowRate + state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
2662 3910 : SupplyHumRatForHumid = min(SupplyHumRatForHumid, PurchAir(PurchAirNum).MaxHeatSuppAirHumRat);
2663 3910 : PurchAir(PurchAirNum).SupplyHumRat = max(PurchAir(PurchAirNum).SupplyHumRat, SupplyHumRatForHumid);
2664 3910 : } break;
2665 753997 : case HumControl::ConstantSupplyHumidityRatio: {
2666 753997 : if (OperatingMode == OpMode::Heat) {
2667 : // If this results in dehumidification, must check cooling capacity limit
2668 701971 : if (PurchAir(PurchAirNum).MixedAirHumRat > PurchAir(PurchAirNum).MaxHeatSuppAirHumRat) {
2669 141778 : if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) ||
2670 70889 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) {
2671 0 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MaxHeatSuppAirHumRat;
2672 0 : SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
2673 0 : CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy);
2674 0 : CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
2675 0 : CoolSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).MixedAirTemp - PurchAir(PurchAirNum).SupplyTemp);
2676 0 : CoolLatOutput = CoolTotOutput - CoolSensOutput;
2677 0 : if (CoolLatOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) {
2678 0 : CoolLatOutput = PurchAir(PurchAirNum).MaxCoolTotCap;
2679 0 : CoolTotOutput = CoolSensOutput + CoolLatOutput;
2680 0 : SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput / SupplyMassFlowRate;
2681 0 : PurchAir(PurchAirNum).SupplyHumRat =
2682 0 : PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName);
2683 : }
2684 : } else {
2685 70889 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MaxHeatSuppAirHumRat;
2686 : }
2687 : } else {
2688 631082 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MaxHeatSuppAirHumRat;
2689 : }
2690 : } else {
2691 52026 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
2692 : }
2693 753997 : } break;
2694 0 : default: {
2695 0 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
2696 0 : } break;
2697 : }
2698 813748 : SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
2699 :
2700 : // Check supply humidity ratio for dehumidification (SupplyHumRatForHumid should always be < SupplyHumRatForDehum)
2701 : // This section is the heating/deadband section, so dehumidification should activate
2702 : // only if dehumidification control = humidistat
2703 : // and if humidification control = humidistat or none or if operating in deadband mode
2704 813748 : if (CoolOn) {
2705 809848 : if (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) {
2706 8831 : if ((PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) ||
2707 8831 : (PurchAir(PurchAirNum).HumidCtrlType == HumControl::None) || (OperatingMode == OpMode::DeadBand)) {
2708 8831 : MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToDehumidSP;
2709 8831 : SupplyHumRatForDehum = MdotZnDehumidSP / SupplyMassFlowRate + state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
2710 8831 : SupplyHumRatForDehum = max(SupplyHumRatForDehum, PurchAir(PurchAirNum).MinCoolSuppAirHumRat);
2711 8831 : PurchAir(PurchAirNum).SupplyHumRat = min(PurchAir(PurchAirNum).SupplyHumRat, SupplyHumRatForDehum);
2712 8831 : SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
2713 8831 : if (PurchAir(PurchAirNum).SupplyHumRat < PurchAir(PurchAirNum).MixedAirHumRat) {
2714 : // At this point, the system is heating or deadband but dehumidifying, check max cooling cap limit
2715 447 : CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
2716 447 : SensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).SupplyTemp - PurchAir(PurchAirNum).MixedAirTemp);
2717 447 : LatOutput = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy) - SensOutput;
2718 894 : if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) ||
2719 447 : (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) {
2720 0 : if (LatOutput > PurchAir(PurchAirNum).MaxCoolTotCap) {
2721 0 : LatOutput = PurchAir(PurchAirNum).MaxCoolTotCap;
2722 0 : SupplyEnthalpy = MixedAirEnthalpy + (LatOutput + SensOutput) / SupplyMassFlowRate;
2723 0 : PurchAir(PurchAirNum).SupplyHumRat =
2724 0 : PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName);
2725 : }
2726 : }
2727 : }
2728 : }
2729 : }
2730 : }
2731 :
2732 : // Limit supply humidity ratio to saturation at supply outlet temp
2733 :
2734 813748 : SupplyHumRatOrig = PurchAir(PurchAirNum).SupplyHumRat;
2735 813748 : PurchAir(PurchAirNum).SupplyHumRat =
2736 813748 : min(PurchAir(PurchAirNum).SupplyHumRat,
2737 813748 : PsyWFnTdbRhPb(state, PurchAir(PurchAirNum).SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName));
2738 813748 : SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
2739 :
2740 : } else { // SupplyMassFlowRate is zero
2741 722182 : SupplyEnthalpy = MixedAirEnthalpy;
2742 722182 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
2743 722182 : PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp;
2744 722182 : HeatSensOutput = 0.0;
2745 : }
2746 :
2747 : } // Cooling or heating required
2748 :
2749 2076247 : if (SupplyMassFlowRate > 0.0) {
2750 : // EMS override point Purch air supply temp and humidty ratio ..... but only if unit is on, SupplyMassFlowRate>0.0
2751 1348728 : if (PurchAir(PurchAirNum).EMSOverrideSupplyTempOn) {
2752 241986 : PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).EMSValueSupplyTemp;
2753 : }
2754 1348728 : if (PurchAir(PurchAirNum).EMSOverrideSupplyHumRatOn) {
2755 241986 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).EMSValueSupplyHumRat;
2756 : }
2757 1348728 : SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
2758 :
2759 : // compute coil loads
2760 1436543 : if ((PurchAir(PurchAirNum).SupplyHumRat == PurchAir(PurchAirNum).MixedAirHumRat) &&
2761 87815 : (PurchAir(PurchAirNum).SupplyTemp == PurchAir(PurchAirNum).MixedAirTemp)) {
2762 : // If no change in humrat or temp, then set loads to zero
2763 1715 : PurchAir(PurchAirNum).SenCoilLoad = 0.0;
2764 1715 : PurchAir(PurchAirNum).LatCoilLoad = 0.0;
2765 1433113 : } else if ((PurchAir(PurchAirNum).SupplyHumRat == PurchAir(PurchAirNum).MixedAirHumRat) &&
2766 86100 : (PurchAir(PurchAirNum).SupplyTemp != PurchAir(PurchAirNum).MixedAirTemp)) {
2767 : // If no change in humrat, then set latent load to zero and use enthalpies to calculate sensible load
2768 86100 : PurchAir(PurchAirNum).SenCoilLoad = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy);
2769 86100 : PurchAir(PurchAirNum).LatCoilLoad = 0.0;
2770 : } else {
2771 1260913 : CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
2772 2521826 : PurchAir(PurchAirNum).SenCoilLoad =
2773 1260913 : SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).SupplyTemp - PurchAir(PurchAirNum).MixedAirTemp);
2774 1260913 : PurchAir(PurchAirNum).LatCoilLoad = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy) - PurchAir(PurchAirNum).SenCoilLoad;
2775 : }
2776 :
2777 : // Apply heating and cooling availability schedules to sensible load
2778 1348728 : if (((PurchAir(PurchAirNum).SenCoilLoad > 0.0) && !HeatOn) || ((PurchAir(PurchAirNum).SenCoilLoad < 0.0) && !CoolOn)) {
2779 : // Coil is off
2780 0 : PurchAir(PurchAirNum).SenCoilLoad = 0.0;
2781 0 : PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp;
2782 : }
2783 :
2784 : // Apply heating and cooling availability schedules to latent load
2785 1348728 : if (((PurchAir(PurchAirNum).LatCoilLoad > 0.0) && !HeatOn) || ((PurchAir(PurchAirNum).LatCoilLoad < 0.0) && !CoolOn)) {
2786 : // Coil is off
2787 307 : PurchAir(PurchAirNum).LatCoilLoad = 0.0;
2788 307 : PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
2789 : }
2790 :
2791 : // Double-check if saturation exceeded, then thow warning, shouldn't happen here, don't reset, just warn
2792 :
2793 1348728 : SupplyHumRatOrig = PurchAir(PurchAirNum).SupplyHumRat;
2794 1348728 : SupplyHumRatSat = PsyWFnTdbRhPb(state, PurchAir(PurchAirNum).SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
2795 :
2796 1348728 : DeltaHumRat = SupplyHumRatOrig - SupplyHumRatSat;
2797 1348728 : if (DeltaHumRat > SmallDeltaHumRat) {
2798 0 : if (PurchAir(PurchAirNum).SaturationOutputError < 1) {
2799 0 : ++PurchAir(PurchAirNum).SaturationOutputError;
2800 0 : ShowWarningError(state,
2801 0 : format("{} \"{}\" Supply humidity ratio = {:.5T} exceeds saturation limit {:.5T} [kgWater/kgDryAir]",
2802 0 : PurchAir(PurchAirNum).cObjectName,
2803 0 : PurchAir(PurchAirNum).Name,
2804 : SupplyHumRatOrig,
2805 : SupplyHumRatSat));
2806 0 : ShowContinueError(state, " Simulation continuing . . . ");
2807 0 : ShowContinueErrorTimeStamp(state, "");
2808 : } else {
2809 0 : ShowRecurringWarningErrorAtEnd(
2810 : state,
2811 0 : PurchAir(PurchAirNum).cObjectName + " \"" + PurchAir(PurchAirNum).Name +
2812 : "\" Supply humidity ratio exceeds saturation limit warning continues, delta max/min [kgWater/kgDryAir]...",
2813 0 : PurchAir(PurchAirNum).SaturationOutputIndex,
2814 : DeltaHumRat,
2815 : DeltaHumRat);
2816 : }
2817 : }
2818 :
2819 1348728 : SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
2820 :
2821 1348728 : CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
2822 1348728 : SysOutputProvided = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).SupplyTemp - state.dataLoopNodes->Node(ZoneNodeNum).Temp);
2823 1348728 : MoistOutputProvided =
2824 1348728 : SupplyMassFlowRate * (PurchAir(PurchAirNum).SupplyHumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat); // Latent rate, kg/s
2825 :
2826 1348728 : PurchAir(PurchAirNum).SenOutputToZone = SysOutputProvided;
2827 2697456 : PurchAir(PurchAirNum).LatOutputToZone =
2828 1348728 : SupplyMassFlowRate * (SupplyEnthalpy - state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy) - PurchAir(PurchAirNum).SenOutputToZone;
2829 :
2830 1348728 : CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
2831 1348728 : if (PurchAir(PurchAirNum).OutdoorAir) {
2832 29304 : PurchAir(PurchAirNum).OASenOutput =
2833 14652 : OAMassFlowRate * CpAir * (state.dataLoopNodes->Node(OANodeNum).Temp - state.dataLoopNodes->Node(ZoneNodeNum).Temp);
2834 14652 : PurchAir(PurchAirNum).OALatOutput =
2835 14652 : OAMassFlowRate * (state.dataLoopNodes->Node(OANodeNum).Enthalpy - state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy) -
2836 14652 : PurchAir(PurchAirNum).OASenOutput;
2837 : } else {
2838 1334076 : PurchAir(PurchAirNum).OASenOutput = 0.0;
2839 1334076 : PurchAir(PurchAirNum).OALatOutput = 0.0;
2840 : }
2841 1348728 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2842 133236 : if (PurchAir(PurchAirNum).OutdoorAir) {
2843 0 : state.dataLoopNodes->Node(InNodeNum).CO2 = ((SupplyMassFlowRate - OAMassFlowRate) * state.dataLoopNodes->Node(RecircNodeNum).CO2 +
2844 0 : OAMassFlowRate * state.dataLoopNodes->Node(OANodeNum).CO2) /
2845 : SupplyMassFlowRate;
2846 : } else {
2847 133236 : state.dataLoopNodes->Node(InNodeNum).CO2 = state.dataLoopNodes->Node(RecircNodeNum).CO2;
2848 : }
2849 : }
2850 1348728 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2851 117952 : if (PurchAir(PurchAirNum).OutdoorAir) {
2852 0 : state.dataLoopNodes->Node(InNodeNum).GenContam =
2853 0 : ((SupplyMassFlowRate - OAMassFlowRate) * state.dataLoopNodes->Node(RecircNodeNum).GenContam +
2854 0 : OAMassFlowRate * state.dataLoopNodes->Node(OANodeNum).GenContam) /
2855 : SupplyMassFlowRate;
2856 : } else {
2857 117952 : state.dataLoopNodes->Node(InNodeNum).GenContam = state.dataLoopNodes->Node(RecircNodeNum).GenContam;
2858 : }
2859 : }
2860 : } else { // SupplyMassFlowRate = 0.0
2861 727519 : SysOutputProvided = 0.0;
2862 727519 : MoistOutputProvided = 0.0;
2863 :
2864 727519 : PurchAir(PurchAirNum).SenOutputToZone = 0.0;
2865 727519 : PurchAir(PurchAirNum).LatOutputToZone = 0.0;
2866 727519 : PurchAir(PurchAirNum).SenCoilLoad = 0.0;
2867 727519 : PurchAir(PurchAirNum).LatCoilLoad = 0.0;
2868 727519 : PurchAir(PurchAirNum).OASenOutput = 0.0;
2869 727519 : PurchAir(PurchAirNum).OALatOutput = 0.0;
2870 :
2871 727519 : PurchAir(PurchAirNum).MixedAirTemp = state.dataLoopNodes->Node(RecircNodeNum).Temp;
2872 727519 : PurchAir(PurchAirNum).MixedAirHumRat = state.dataLoopNodes->Node(RecircNodeNum).HumRat;
2873 727519 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2874 :
2875 47732 : state.dataLoopNodes->Node(InNodeNum).CO2 = state.dataLoopNodes->Node(ZoneNodeNum).CO2;
2876 : }
2877 727519 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2878 24552 : state.dataLoopNodes->Node(InNodeNum).GenContam = state.dataLoopNodes->Node(ZoneNodeNum).GenContam;
2879 : }
2880 : }
2881 :
2882 2076247 : state.dataLoopNodes->Node(InNodeNum).Temp = PurchAir(PurchAirNum).SupplyTemp;
2883 2076247 : state.dataLoopNodes->Node(InNodeNum).HumRat = PurchAir(PurchAirNum).SupplyHumRat;
2884 2076247 : state.dataLoopNodes->Node(InNodeNum).Enthalpy = SupplyEnthalpy;
2885 2076247 : state.dataLoopNodes->Node(InNodeNum).MassFlowRate = SupplyMassFlowRate;
2886 2076247 : if (PurchAir(PurchAirNum).OutdoorAir) state.dataLoopNodes->Node(OANodeNum).MassFlowRate = OAMassFlowRate;
2887 :
2888 : } else { // purchased air OFF
2889 :
2890 0 : SysOutputProvided = 0.0;
2891 0 : MoistOutputProvided = 0.0;
2892 0 : SupplyMassFlowRate = 0.0;
2893 0 : OAMassFlowRate = 0.0;
2894 0 : state.dataLoopNodes->Node(InNodeNum).Temp = state.dataLoopNodes->Node(ZoneNodeNum).Temp;
2895 0 : state.dataLoopNodes->Node(InNodeNum).HumRat = state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
2896 0 : state.dataLoopNodes->Node(InNodeNum).Enthalpy = state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy;
2897 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2898 0 : state.dataLoopNodes->Node(InNodeNum).CO2 = state.dataLoopNodes->Node(ZoneNodeNum).CO2;
2899 : }
2900 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2901 0 : state.dataLoopNodes->Node(InNodeNum).GenContam = state.dataLoopNodes->Node(ZoneNodeNum).GenContam;
2902 : }
2903 :
2904 0 : state.dataLoopNodes->Node(InNodeNum).MassFlowRate = 0.0;
2905 0 : if (PurchAir(PurchAirNum).OutdoorAir) state.dataLoopNodes->Node(OANodeNum).MassFlowRate = 0.0;
2906 0 : PurchAir(PurchAirNum).SenHeatRate = 0.0;
2907 0 : PurchAir(PurchAirNum).SenCoolRate = 0.0;
2908 0 : PurchAir(PurchAirNum).TotCoolRate = 0.0;
2909 :
2910 0 : PurchAir(PurchAirNum).SenOutputToZone = 0.0;
2911 0 : PurchAir(PurchAirNum).LatOutputToZone = 0.0;
2912 0 : PurchAir(PurchAirNum).SenCoilLoad = 0.0;
2913 0 : PurchAir(PurchAirNum).LatCoilLoad = 0.0;
2914 0 : PurchAir(PurchAirNum).OASenOutput = 0.0;
2915 0 : PurchAir(PurchAirNum).OALatOutput = 0.0;
2916 0 : PurchAir(PurchAirNum).MixedAirTemp = state.dataLoopNodes->Node(RecircNodeNum).Temp;
2917 0 : PurchAir(PurchAirNum).MixedAirHumRat = state.dataLoopNodes->Node(RecircNodeNum).HumRat;
2918 0 : PurchAir(PurchAirNum).SupplyTemp = state.dataLoopNodes->Node(InNodeNum).Temp;
2919 0 : PurchAir(PurchAirNum).SupplyHumRat = state.dataLoopNodes->Node(InNodeNum).HumRat;
2920 : }
2921 :
2922 2076247 : PurchAir(PurchAirNum).OutdoorAirMassFlowRate = OAMassFlowRate;
2923 2076247 : PurchAir(PurchAirNum).OutdoorAirVolFlowRateStdRho = OAMassFlowRate / state.dataEnvrn->StdRhoAir;
2924 2076247 : PurchAir(PurchAirNum).SupplyAirMassFlowRate = SupplyMassFlowRate;
2925 :
2926 2076247 : PurchAir(PurchAirNum).SupplyAirVolFlowRateStdRho = SupplyMassFlowRate / state.dataEnvrn->StdRhoAir;
2927 :
2928 2076247 : if (PurchAir(PurchAirNum).PlenumExhaustAirNodeNum > 0) {
2929 15075 : state.dataLoopNodes->Node(PurchAir(PurchAirNum).PlenumExhaustAirNodeNum).MassFlowRate = SupplyMassFlowRate;
2930 : }
2931 2076247 : state.dataLoopNodes->Node(RecircNodeNum).MassFlowRate = SupplyMassFlowRate;
2932 2076247 : }
2933 :
2934 2076247 : void CalcPurchAirMinOAMassFlow(EnergyPlusData &state,
2935 : int const PurchAirNum, // index to ideal loads unit
2936 : int const ZoneNum, // index to zone
2937 : Real64 &OAMassFlowRate // outside air mass flow rate [kg/s] from volume flow using std density
2938 : )
2939 : {
2940 :
2941 : // SUBROUTINE INFORMATION:
2942 : // AUTHOR M. Witte (GARD)
2943 : // DATE WRITTEN Jun 2011 (taken from HVACSingleDuctSystem.cc and adapted for Ideal Loads System)
2944 : // MODIFIED na
2945 : // RE-ENGINEERED na
2946 :
2947 : // PURPOSE OF THIS SUBROUTINE:
2948 : // Calculates the amount of outside air required based on optional user input.
2949 : // Zone multipliers have been applied in GetInput.
2950 :
2951 : // METHODOLOGY EMPLOYED:
2952 : // User input defines method used to calculate OA.
2953 :
2954 : // FUNCTION PARAMETER DEFINITIONS:
2955 2076247 : bool constexpr UseMinOASchFlag(true); // Always use min OA schedule in calculations.
2956 :
2957 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2958 : bool UseOccSchFlag; // TRUE = use actual occupancy, FALSE = use total zone people
2959 : Real64 OAVolumeFlowRate; // outside air flow rate (m3/s)
2960 :
2961 2076247 : auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
2962 :
2963 2076247 : if (PurchAir(PurchAirNum).OutdoorAir) {
2964 :
2965 14788 : if (PurchAir(PurchAirNum).DCVType == DCV::OccupancySchedule) {
2966 3697 : UseOccSchFlag = true;
2967 : } else {
2968 11091 : UseOccSchFlag = false;
2969 : }
2970 : OAVolumeFlowRate =
2971 14788 : DataSizing::calcDesignSpecificationOutdoorAir(state, PurchAir(PurchAirNum).OARequirementsPtr, ZoneNum, UseOccSchFlag, UseMinOASchFlag);
2972 14788 : OAMassFlowRate = OAVolumeFlowRate * state.dataEnvrn->StdRhoAir;
2973 :
2974 : // If DCV with CO2SetPoint then check required OA flow to meet CO2 setpoint
2975 14788 : if (PurchAir(PurchAirNum).DCVType == DCV::CO2SetPoint) {
2976 0 : OAMassFlowRate = max(OAMassFlowRate, state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP);
2977 : }
2978 :
2979 14788 : if (OAMassFlowRate <= HVAC::VerySmallMassFlow) OAMassFlowRate = 0.0;
2980 :
2981 : } else { // No outdoor air
2982 2061459 : OAMassFlowRate = 0.0;
2983 : }
2984 2076247 : PurchAir(PurchAirNum).MinOAMassFlowRate = OAMassFlowRate;
2985 2076247 : }
2986 :
2987 2076247 : void CalcPurchAirMixedAir(EnergyPlusData &state,
2988 : int const PurchAirNum, // index to ideal loads unit
2989 : Real64 const OAMassFlowRate, // outside air mass flow rate [kg/s]
2990 : Real64 const SupplyMassFlowRate, // supply air mass flow rate [kg/s]
2991 : Real64 &MixedAirTemp, // Mixed air dry bulb temperature [C]
2992 : Real64 &MixedAirHumRat, // Mixed air humidity ratio [kgWater/kgDryAir]
2993 : Real64 &MixedAirEnthalpy, // Mixed air enthalpy [J/kg]
2994 : OpMode const OperatingMode // current operating mode, Off, Heating, Cooling, or DeadBand
2995 : )
2996 : {
2997 :
2998 : // SUBROUTINE INFORMATION:
2999 : // AUTHOR M. Witte (GARD)
3000 : // DATE WRITTEN Sep 2011
3001 : // MODIFIED na
3002 : // RE-ENGINEERED na
3003 :
3004 : // PURPOSE OF THIS SUBROUTINE:
3005 : // Calculates the mixed air conditions, accounting for heat recovery.
3006 :
3007 : // SUBROUTINE PARAMETER DEFINITIONS:
3008 : static constexpr std::string_view RoutineName("CalcPurchAirMixedAir");
3009 :
3010 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3011 : int RecircNodeNum; // Zone return air node
3012 : int OANodeNum; // Outdoor air inlet node
3013 : Real64 RecircTemp; // Recirculated air from zone dry bulb temperature [C]
3014 : Real64 RecircHumRat; // Recirculated air from zone humidity ratio [kgWater/kgDryAir]
3015 : Real64 RecircEnthalpy; // Recirculated air from zone enthalpy [J/kg]
3016 : Real64 RecircMassFlowRate; // Recirculated air mass flow rate [kg/s]
3017 : Real64 OAInletTemp; // Outdoor air inlet dry bulb temperature [C]
3018 : Real64 OAInletHumRat; // Outdoor air inlet humidity ratio [kgWater/kgDryAir]
3019 : Real64 OAInletEnthalpy; // Outdoor air inlet enthalpy [J/kg]
3020 : Real64 OAAfterHtRecTemp; // Outdoor air after heat recovery to mixing box dry bulb temperature [C]
3021 : Real64 OAAfterHtRecHumRat; // Outdoor air after heat recovery to mixing box humidity ratio [kgWater/kgDryAir]
3022 : Real64 OAAfterHtRecEnthalpy; // Outdoor air after heat recovery to mixing box enthalpy [J/kg]
3023 : bool HeatRecOn;
3024 : Real64 CpAir; // Specific heat [J/kg-C] reused in multiple places
3025 :
3026 2076247 : auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
3027 :
3028 : // Initializations
3029 2076247 : OANodeNum = PurchAir(PurchAirNum).OutdoorAirNodeNum;
3030 2076247 : RecircNodeNum = PurchAir(PurchAirNum).ZoneRecircAirNodeNum;
3031 :
3032 2076247 : RecircMassFlowRate = 0.0;
3033 2076247 : RecircTemp = state.dataLoopNodes->Node(RecircNodeNum).Temp;
3034 2076247 : RecircHumRat = state.dataLoopNodes->Node(RecircNodeNum).HumRat;
3035 2076247 : RecircEnthalpy = state.dataLoopNodes->Node(RecircNodeNum).Enthalpy;
3036 2076247 : if (PurchAir(PurchAirNum).OutdoorAir) {
3037 14788 : OAInletTemp = state.dataLoopNodes->Node(OANodeNum).Temp;
3038 14788 : OAInletHumRat = state.dataLoopNodes->Node(OANodeNum).HumRat;
3039 14788 : OAInletEnthalpy = state.dataLoopNodes->Node(OANodeNum).Enthalpy;
3040 14788 : OAAfterHtRecTemp = OAInletTemp;
3041 14788 : OAAfterHtRecHumRat = OAInletHumRat;
3042 14788 : OAAfterHtRecEnthalpy = OAInletEnthalpy;
3043 : } else {
3044 2061459 : OAInletTemp = 0.0;
3045 2061459 : OAInletHumRat = 0.0;
3046 2061459 : OAInletEnthalpy = 0.0;
3047 2061459 : OAAfterHtRecTemp = OAInletTemp;
3048 2061459 : OAAfterHtRecHumRat = OAInletHumRat;
3049 2061459 : OAAfterHtRecEnthalpy = OAInletEnthalpy;
3050 : }
3051 2076247 : HeatRecOn = false;
3052 :
3053 2076247 : if (PurchAir(PurchAirNum).OutdoorAir && (OAMassFlowRate > 0.0)) {
3054 : // Determine if heat recovery is beneficial
3055 12513 : if (PurchAir(PurchAirNum).HtRecType == HeatRecovery::Sensible) {
3056 3683 : if ((OperatingMode == OpMode::Heat) && (RecircTemp > OAInletTemp)) HeatRecOn = true;
3057 3683 : if ((OperatingMode == OpMode::Cool) && (RecircTemp < OAInletTemp)) HeatRecOn = true;
3058 : }
3059 12513 : if (PurchAir(PurchAirNum).HtRecType == HeatRecovery::Enthalpy) {
3060 1436 : if ((OperatingMode == OpMode::Heat) && (RecircEnthalpy > OAInletEnthalpy)) HeatRecOn = true;
3061 1436 : if ((OperatingMode == OpMode::Cool) && (RecircEnthalpy < OAInletEnthalpy)) HeatRecOn = true;
3062 : }
3063 : // Calculate heat recovery if active
3064 12513 : if (HeatRecOn) {
3065 4472 : PurchAir(PurchAirNum).TimeHtRecActive = state.dataHVACGlobal->TimeStepSys;
3066 4472 : OAAfterHtRecTemp = OAInletTemp + PurchAir(PurchAirNum).HtRecSenEff * (RecircTemp - OAInletTemp);
3067 4472 : if (PurchAir(PurchAirNum).HtRecType == HeatRecovery::Enthalpy)
3068 1436 : OAAfterHtRecHumRat = OAInletHumRat + PurchAir(PurchAirNum).HtRecLatEff * (RecircHumRat - OAInletHumRat);
3069 4472 : OAAfterHtRecEnthalpy = PsyHFnTdbW(OAAfterHtRecTemp, OAAfterHtRecHumRat);
3070 : // Check for saturation in supply outlet and reset temp, then humidity ratio at constant enthalpy
3071 4472 : if (PsyTsatFnHPb(state, OAAfterHtRecEnthalpy, state.dataEnvrn->OutBaroPress, RoutineName) > OAAfterHtRecTemp) {
3072 0 : OAAfterHtRecTemp = PsyTsatFnHPb(state, OAAfterHtRecEnthalpy, state.dataEnvrn->OutBaroPress, RoutineName);
3073 0 : OAAfterHtRecHumRat = PsyWFnTdbH(state, OAAfterHtRecTemp, OAAfterHtRecEnthalpy, RoutineName);
3074 : }
3075 : }
3076 :
3077 12513 : if (SupplyMassFlowRate > OAMassFlowRate) {
3078 4914 : RecircMassFlowRate = SupplyMassFlowRate - OAMassFlowRate;
3079 4914 : MixedAirEnthalpy =
3080 4914 : (RecircMassFlowRate * state.dataLoopNodes->Node(RecircNodeNum).Enthalpy + OAMassFlowRate * OAAfterHtRecEnthalpy) / SupplyMassFlowRate;
3081 4914 : MixedAirHumRat =
3082 4914 : (RecircMassFlowRate * state.dataLoopNodes->Node(RecircNodeNum).HumRat + OAMassFlowRate * OAAfterHtRecHumRat) / SupplyMassFlowRate;
3083 : // Mixed air temperature is calculated from the mixed air enthalpy and humidity ratio.
3084 4914 : MixedAirTemp = PsyTdbFnHW(MixedAirEnthalpy, MixedAirHumRat);
3085 : } else {
3086 7599 : RecircMassFlowRate = 0.0;
3087 7599 : MixedAirEnthalpy = OAAfterHtRecEnthalpy;
3088 7599 : MixedAirHumRat = OAAfterHtRecHumRat;
3089 7599 : MixedAirTemp = OAAfterHtRecTemp;
3090 : }
3091 :
3092 : // Calculate OA and heat recovery sensible and latent rates
3093 12513 : CpAir = PsyCpAirFnW(OAInletHumRat);
3094 12513 : PurchAir(PurchAirNum).HtRecSenOutput = OAMassFlowRate * CpAir * (OAAfterHtRecTemp - OAInletTemp);
3095 12513 : PurchAir(PurchAirNum).HtRecLatOutput = OAMassFlowRate * (OAAfterHtRecEnthalpy - OAInletEnthalpy) - PurchAir(PurchAirNum).HtRecSenOutput;
3096 :
3097 : } else { // No outdoor air
3098 2063734 : RecircMassFlowRate = SupplyMassFlowRate;
3099 2063734 : MixedAirTemp = RecircTemp;
3100 2063734 : MixedAirHumRat = RecircHumRat;
3101 2063734 : MixedAirEnthalpy = RecircEnthalpy;
3102 2063734 : PurchAir(PurchAirNum).HtRecSenOutput = 0.0;
3103 2063734 : PurchAir(PurchAirNum).HtRecLatOutput = 0.0;
3104 : }
3105 2076247 : }
3106 :
3107 2076247 : void UpdatePurchasedAir(EnergyPlusData &state, int const PurchAirNum, bool const FirstHVACIteration)
3108 : {
3109 :
3110 : // SUBROUTINE INFORMATION:
3111 : // AUTHOR M. J. Witte
3112 : // DATE WRITTEN Sep 2011
3113 : // MODIFIED R. Raustad, July 2017, added return plenum
3114 : // RE-ENGINEERED na
3115 :
3116 : // PURPOSE OF THIS SUBROUTINE:
3117 : // Update node data for Ideal Loads (purchased air) system
3118 :
3119 : // USE STATEMENTS:
3120 : using ZonePlenum::SimAirZonePlenum;
3121 :
3122 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3123 : // na
3124 : bool FirstCall;
3125 : bool SupPathInletChanged;
3126 :
3127 2076247 : FirstCall = true; // just used to avoid redundant calulations
3128 2076247 : SupPathInletChanged = false; // don't care if something changes
3129 :
3130 2076247 : auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
3131 :
3132 2076247 : if (PurchAir(PurchAirNum).ReturnPlenumIndex > 0) {
3133 :
3134 : // if connected to a return plenum, set the flag that this ideal loads air system was simulated
3135 15075 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(PurchAir(PurchAirNum).ReturnPlenumIndex)
3136 15075 : .IsSimulated(PurchAir(PurchAirNum).PurchAirArrayIndex) = true;
3137 :
3138 : // if all ideal loads air systems connected to the same plenum have been simulated, simulate the zone air plenum
3139 15075 : if (all(state.dataPurchasedAirMgr->PurchAirPlenumArrays(PurchAir(PurchAirNum).ReturnPlenumIndex).IsSimulated)) {
3140 6030 : SimAirZonePlenum(state,
3141 3015 : PurchAir(PurchAirNum).ReturnPlenumName,
3142 : DataZoneEquipment::AirLoopHVACZone::ReturnPlenum,
3143 3015 : PurchAir(PurchAirNum).ReturnPlenumIndex,
3144 : FirstHVACIteration,
3145 : FirstCall,
3146 : SupPathInletChanged);
3147 : // reset this plenums flags for next iteration
3148 3015 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(PurchAir(PurchAirNum).ReturnPlenumIndex).IsSimulated = false;
3149 : }
3150 : }
3151 2076247 : }
3152 :
3153 2076247 : void ReportPurchasedAir(EnergyPlusData &state, int const PurchAirNum)
3154 : {
3155 :
3156 : // SUBROUTINE INFORMATION:
3157 : // AUTHOR Russ Taylor
3158 : // DATE WRITTEN Nov 1997
3159 : // MODIFIED na
3160 : // RE-ENGINEERED na
3161 :
3162 : // PURPOSE OF THIS SUBROUTINE:
3163 : // Calculate values of report variables, if necessary.
3164 :
3165 : // Using/Aliasing
3166 2076247 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
3167 :
3168 2076247 : auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
3169 :
3170 : // Sort out heating and cooling rates
3171 2076247 : PurchAir(PurchAirNum).SenHeatRate = max(PurchAir(PurchAirNum).SenCoilLoad, 0.0);
3172 2076247 : PurchAir(PurchAirNum).SenCoolRate = std::abs(min(PurchAir(PurchAirNum).SenCoilLoad, 0.0));
3173 2076247 : PurchAir(PurchAirNum).LatHeatRate = max(PurchAir(PurchAirNum).LatCoilLoad, 0.0);
3174 2076247 : PurchAir(PurchAirNum).LatCoolRate = std::abs(min(PurchAir(PurchAirNum).LatCoilLoad, 0.0));
3175 2076247 : PurchAir(PurchAirNum).TotHeatRate = PurchAir(PurchAirNum).SenHeatRate + PurchAir(PurchAirNum).LatHeatRate;
3176 2076247 : PurchAir(PurchAirNum).TotCoolRate = PurchAir(PurchAirNum).SenCoolRate + PurchAir(PurchAirNum).LatCoolRate;
3177 :
3178 2076247 : PurchAir(PurchAirNum).ZoneSenHeatRate = max(PurchAir(PurchAirNum).SenOutputToZone, 0.0);
3179 2076247 : PurchAir(PurchAirNum).ZoneSenCoolRate = std::abs(min(PurchAir(PurchAirNum).SenOutputToZone, 0.0));
3180 2076247 : PurchAir(PurchAirNum).ZoneLatHeatRate = max(PurchAir(PurchAirNum).LatOutputToZone, 0.0);
3181 2076247 : PurchAir(PurchAirNum).ZoneLatCoolRate = std::abs(min(PurchAir(PurchAirNum).LatOutputToZone, 0.0));
3182 2076247 : PurchAir(PurchAirNum).ZoneTotHeatRate = PurchAir(PurchAirNum).ZoneSenHeatRate + PurchAir(PurchAirNum).ZoneLatHeatRate;
3183 2076247 : PurchAir(PurchAirNum).ZoneTotCoolRate = PurchAir(PurchAirNum).ZoneSenCoolRate + PurchAir(PurchAirNum).ZoneLatCoolRate;
3184 :
3185 : // Sort out outdoor air "loads"
3186 : // OASenOutput = Outdoor air sensible output relative to zone conditions [W], <0 means OA is cooler than zone air
3187 : // OALatOutput = Outdoor air latent output relative to zone conditions [W], <0 means OA is drier than zone air
3188 2076247 : if (PurchAir(PurchAirNum).SenCoilLoad > 0.0) { // Heating is active
3189 800783 : PurchAir(PurchAirNum).OASenHeatRate = std::abs(min(PurchAir(PurchAirNum).OASenOutput, 0.0));
3190 : } else {
3191 1275464 : PurchAir(PurchAirNum).OASenHeatRate = 0.0;
3192 : }
3193 2076247 : if (PurchAir(PurchAirNum).SenCoilLoad < 0.0) { // Cooling is active
3194 545761 : PurchAir(PurchAirNum).OASenCoolRate = max(PurchAir(PurchAirNum).OASenOutput, 0.0);
3195 : } else {
3196 1530486 : PurchAir(PurchAirNum).OASenCoolRate = 0.0;
3197 : }
3198 2076247 : if (PurchAir(PurchAirNum).LatCoilLoad > 0.0) { // Humidification is active
3199 797927 : PurchAir(PurchAirNum).OALatHeatRate = std::abs(min(PurchAir(PurchAirNum).OALatOutput, 0.0));
3200 : } else {
3201 1278320 : PurchAir(PurchAirNum).OALatHeatRate = 0.0;
3202 : }
3203 2076247 : if (PurchAir(PurchAirNum).LatCoilLoad < 0.0) { // Dehumidification is active
3204 460875 : PurchAir(PurchAirNum).OALatCoolRate = max(PurchAir(PurchAirNum).OALatOutput, 0.0);
3205 : } else {
3206 1615372 : PurchAir(PurchAirNum).OALatCoolRate = 0.0;
3207 : }
3208 :
3209 2076247 : PurchAir(PurchAirNum).OATotHeatRate = PurchAir(PurchAirNum).OASenHeatRate + PurchAir(PurchAirNum).OALatHeatRate;
3210 2076247 : PurchAir(PurchAirNum).OATotCoolRate = PurchAir(PurchAirNum).OASenCoolRate + PurchAir(PurchAirNum).OALatCoolRate;
3211 :
3212 2076247 : PurchAir(PurchAirNum).HtRecSenHeatRate = max(PurchAir(PurchAirNum).HtRecSenOutput, 0.0);
3213 2076247 : PurchAir(PurchAirNum).HtRecSenCoolRate = std::abs(min(PurchAir(PurchAirNum).HtRecSenOutput, 0.0));
3214 2076247 : PurchAir(PurchAirNum).HtRecLatHeatRate = max(PurchAir(PurchAirNum).HtRecLatOutput, 0.0);
3215 2076247 : PurchAir(PurchAirNum).HtRecLatCoolRate = std::abs(min(PurchAir(PurchAirNum).HtRecLatOutput, 0.0));
3216 2076247 : PurchAir(PurchAirNum).HtRecTotHeatRate = PurchAir(PurchAirNum).HtRecSenHeatRate + PurchAir(PurchAirNum).HtRecLatHeatRate;
3217 2076247 : PurchAir(PurchAirNum).HtRecTotCoolRate = PurchAir(PurchAirNum).HtRecSenCoolRate + PurchAir(PurchAirNum).HtRecLatCoolRate;
3218 :
3219 2076247 : PurchAir(PurchAirNum).SenHeatEnergy = PurchAir(PurchAirNum).SenHeatRate * TimeStepSysSec;
3220 2076247 : PurchAir(PurchAirNum).SenCoolEnergy = PurchAir(PurchAirNum).SenCoolRate * TimeStepSysSec;
3221 2076247 : PurchAir(PurchAirNum).LatHeatEnergy = PurchAir(PurchAirNum).LatHeatRate * TimeStepSysSec;
3222 2076247 : PurchAir(PurchAirNum).LatCoolEnergy = PurchAir(PurchAirNum).LatCoolRate * TimeStepSysSec;
3223 2076247 : PurchAir(PurchAirNum).TotHeatEnergy = PurchAir(PurchAirNum).TotHeatRate * TimeStepSysSec;
3224 2076247 : PurchAir(PurchAirNum).TotCoolEnergy = PurchAir(PurchAirNum).TotCoolRate * TimeStepSysSec;
3225 :
3226 2076247 : PurchAir(PurchAirNum).ZoneSenHeatEnergy = PurchAir(PurchAirNum).ZoneSenHeatRate * TimeStepSysSec;
3227 2076247 : PurchAir(PurchAirNum).ZoneSenCoolEnergy = PurchAir(PurchAirNum).ZoneSenCoolRate * TimeStepSysSec;
3228 2076247 : PurchAir(PurchAirNum).ZoneLatHeatEnergy = PurchAir(PurchAirNum).ZoneLatHeatRate * TimeStepSysSec;
3229 2076247 : PurchAir(PurchAirNum).ZoneLatCoolEnergy = PurchAir(PurchAirNum).ZoneLatCoolRate * TimeStepSysSec;
3230 2076247 : PurchAir(PurchAirNum).ZoneTotHeatEnergy = PurchAir(PurchAirNum).ZoneTotHeatRate * TimeStepSysSec;
3231 2076247 : PurchAir(PurchAirNum).ZoneTotCoolEnergy = PurchAir(PurchAirNum).ZoneTotCoolRate * TimeStepSysSec;
3232 :
3233 2076247 : PurchAir(PurchAirNum).OASenHeatEnergy = PurchAir(PurchAirNum).OASenHeatRate * TimeStepSysSec;
3234 2076247 : PurchAir(PurchAirNum).OASenCoolEnergy = PurchAir(PurchAirNum).OASenCoolRate * TimeStepSysSec;
3235 2076247 : PurchAir(PurchAirNum).OALatHeatEnergy = PurchAir(PurchAirNum).OALatHeatRate * TimeStepSysSec;
3236 2076247 : PurchAir(PurchAirNum).OALatCoolEnergy = PurchAir(PurchAirNum).OALatCoolRate * TimeStepSysSec;
3237 2076247 : PurchAir(PurchAirNum).OATotHeatEnergy = PurchAir(PurchAirNum).OATotHeatRate * TimeStepSysSec;
3238 2076247 : PurchAir(PurchAirNum).OATotCoolEnergy = PurchAir(PurchAirNum).OATotCoolRate * TimeStepSysSec;
3239 :
3240 2076247 : PurchAir(PurchAirNum).HtRecSenHeatEnergy = PurchAir(PurchAirNum).HtRecSenHeatRate * TimeStepSysSec;
3241 2076247 : PurchAir(PurchAirNum).HtRecSenCoolEnergy = PurchAir(PurchAirNum).HtRecSenCoolRate * TimeStepSysSec;
3242 2076247 : PurchAir(PurchAirNum).HtRecLatHeatEnergy = PurchAir(PurchAirNum).HtRecLatHeatRate * TimeStepSysSec;
3243 2076247 : PurchAir(PurchAirNum).HtRecLatCoolEnergy = PurchAir(PurchAirNum).HtRecLatCoolRate * TimeStepSysSec;
3244 2076247 : PurchAir(PurchAirNum).HtRecTotHeatEnergy = PurchAir(PurchAirNum).HtRecTotHeatRate * TimeStepSysSec;
3245 2076247 : PurchAir(PurchAirNum).HtRecTotCoolEnergy = PurchAir(PurchAirNum).HtRecTotCoolRate * TimeStepSysSec;
3246 2076247 : }
3247 :
3248 457856 : Real64 GetPurchasedAirOutAirMassFlow(EnergyPlusData &state, int const PurchAirNum)
3249 : {
3250 :
3251 : // FUNCTION INFORMATION:
3252 : // AUTHOR B Griffith
3253 : // DATE WRITTEN Dec 2006
3254 : // MODIFIED na
3255 : // RE-ENGINEERED na
3256 :
3257 : // PURPOSE OF THIS FUNCTION:
3258 : // lookup function for OA inlet mass flow for ventilation rate reporting
3259 :
3260 : // METHODOLOGY EMPLOYED:
3261 : // most analagous functions look up an outside air node but this function
3262 : // gets the actual mass flow of outdoor air, following the features of the model
3263 :
3264 457856 : if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
3265 0 : GetPurchasedAir(state);
3266 0 : state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
3267 : }
3268 457856 : return state.dataPurchasedAirMgr->PurchAir(PurchAirNum).OutdoorAirMassFlowRate;
3269 : }
3270 :
3271 457856 : int GetPurchasedAirZoneInletAirNode(EnergyPlusData &state, int const PurchAirNum)
3272 : {
3273 :
3274 : // FUNCTION INFORMATION:
3275 : // AUTHOR B Griffith
3276 : // DATE WRITTEN Dec 2006
3277 : // MODIFIED Adapted for purchased air by M.J. Witte, Oct 2013
3278 : // RE-ENGINEERED na
3279 :
3280 : // PURPOSE OF THIS FUNCTION:
3281 : // lookup function for zone inlet node for ventilation rate reporting
3282 :
3283 457856 : if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
3284 0 : GetPurchasedAir(state);
3285 0 : state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
3286 : }
3287 :
3288 457856 : int GetPurchasedAirZoneInletAirNode = 0;
3289 457856 : if (PurchAirNum > 0 && PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir) {
3290 457856 : GetPurchasedAirZoneInletAirNode = state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ZoneSupplyAirNodeNum;
3291 : }
3292 :
3293 457856 : return GetPurchasedAirZoneInletAirNode;
3294 : }
3295 :
3296 457856 : int GetPurchasedAirReturnAirNode(EnergyPlusData &state, int const PurchAirNum)
3297 : {
3298 :
3299 : // FUNCTION INFORMATION:
3300 : // AUTHOR B Griffith
3301 : // DATE WRITTEN Dec 2006
3302 : // MODIFIED Adapted for purchased air by M.J. Witte, Oct 2013
3303 : // RE-ENGINEERED na
3304 :
3305 : // PURPOSE OF THIS FUNCTION:
3306 : // lookup function for recirculation air node for ventilation rate reporting
3307 :
3308 457856 : if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
3309 0 : GetPurchasedAir(state);
3310 0 : state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
3311 : }
3312 :
3313 457856 : int GetPurchasedAirReturnAirNode = 0;
3314 457856 : if (PurchAirNum > 0 && PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir) {
3315 457856 : GetPurchasedAirReturnAirNode = state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ZoneRecircAirNodeNum;
3316 : }
3317 :
3318 457856 : return GetPurchasedAirReturnAirNode;
3319 : }
3320 :
3321 0 : int getPurchasedAirIndex(EnergyPlusData &state, std::string_view PurchAirName)
3322 : {
3323 0 : if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
3324 0 : GetPurchasedAir(state);
3325 0 : state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
3326 : }
3327 :
3328 0 : for (int PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) {
3329 0 : if (Util::SameString(state.dataPurchasedAirMgr->PurchAir(PurchAirNum).Name, PurchAirName)) {
3330 0 : return PurchAirNum;
3331 : }
3332 : }
3333 :
3334 0 : return 0;
3335 : }
3336 :
3337 457856 : Real64 GetPurchasedAirMixedAirTemp(EnergyPlusData &state, int const PurchAirNum)
3338 : {
3339 :
3340 : // FUNCTION INFORMATION:
3341 : // AUTHOR B Griffith
3342 : // DATE WRITTEN Dec 2006
3343 : // MODIFIED Adapted for purchased air by M.J. Witte, Oct 2013
3344 : // RE-ENGINEERED na
3345 :
3346 : // PURPOSE OF THIS FUNCTION:
3347 : // lookup function for mixed air Temp for ventilation rate reporting
3348 :
3349 : // METHODOLOGY EMPLOYED:
3350 : // most analagous functions look up an outside air node but this function
3351 : // gets the actual mass flow of outdoor air, following the features of the model
3352 :
3353 457856 : if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
3354 0 : GetPurchasedAir(state);
3355 0 : state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
3356 : }
3357 :
3358 457856 : return state.dataPurchasedAirMgr->PurchAir(PurchAirNum).MixedAirTemp;
3359 : }
3360 :
3361 457856 : Real64 GetPurchasedAirMixedAirHumRat(EnergyPlusData &state, int const PurchAirNum)
3362 : {
3363 :
3364 : // FUNCTION INFORMATION:
3365 : // AUTHOR B Griffith
3366 : // DATE WRITTEN Dec 2006
3367 : // MODIFIED Adapted for purchased air by M.J. Witte, Oct 2013
3368 : // RE-ENGINEERED na
3369 :
3370 : // PURPOSE OF THIS FUNCTION:
3371 : // lookup function for mixed air HumRat for ventilation rate reporting
3372 :
3373 : // METHODOLOGY EMPLOYED:
3374 : // most analogous functions look up an outside air node but this function
3375 : // gets the actual mass flow of outdoor air, following the features of the model
3376 :
3377 457856 : if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
3378 0 : GetPurchasedAir(state);
3379 0 : state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
3380 : }
3381 :
3382 457856 : return state.dataPurchasedAirMgr->PurchAir(PurchAirNum).MixedAirHumRat;
3383 : }
3384 :
3385 310 : bool CheckPurchasedAirForReturnPlenum(EnergyPlusData &state, int const ReturnPlenumIndex)
3386 : {
3387 :
3388 : // FUNCTION INFORMATION:
3389 : // AUTHOR R Raustad
3390 : // DATE WRITTEN July 2017
3391 :
3392 : // PURPOSE OF THIS FUNCTION:
3393 : // lookup function to check if return plenum is used
3394 :
3395 : // Return value
3396 : bool CheckPurchasedAirForReturnPlenum;
3397 :
3398 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
3399 : int PurchAirNum;
3400 :
3401 310 : if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
3402 188 : GetPurchasedAir(state);
3403 188 : state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
3404 : }
3405 :
3406 310 : CheckPurchasedAirForReturnPlenum = false;
3407 336 : for (PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) {
3408 26 : if (ReturnPlenumIndex != state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ReturnPlenumIndex) continue;
3409 5 : CheckPurchasedAirForReturnPlenum = true;
3410 : }
3411 :
3412 310 : return CheckPurchasedAirForReturnPlenum;
3413 : }
3414 :
3415 5 : void InitializePlenumArrays(EnergyPlusData &state, int const PurchAirNum)
3416 : {
3417 : // FUNCTION INFORMATION:
3418 : // AUTHOR R Raustad
3419 : // DATE WRITTEN July 2017
3420 :
3421 : // PURPOSE OF THIS FUNCTION:
3422 : // to initialize arrays needed to manage ideal load air system used with return plenums
3423 : //
3424 : // Example:
3425 : // NumPlenumArrays = 2 (same as there are two ZoneHVAC:ReturnPlenums objects connected to two or more ideal loads air systems
3426 : // In this example ideal loads air system #4 is not connected to a zone return plenum
3427 : //
3428 : // ZoneHVAC:ReturnPlenum( 1 ) = ReturnPlenum1 is not connected to any ideal loads air systems
3429 : // ZoneHVAC:ReturnPlenum( 2 ) = ReturnPlenum2 is connected to PurchAirPlenumArrays( 1 )
3430 : // ZoneHVAC:ReturnPlenum( 3 ) = ReturnPlenum3 is connected to PurchAirPlenumArrays( 2 )
3431 : //
3432 : // PurchAirPlenumArrays( 1 )
3433 : // PurchAirPlenumArrays( 1 ).NumPurchAir = 2, there are 2 ideal loads air systems connected to this plenum
3434 : // PurchAirPlenumArrays( 1 ).PurchAirArray( 1 ) = 1, ideal loads air system #1 is attached to this plenum
3435 : // PurchAirPlenumArrays( 1 ).PurchAirArray( 2 ) = 3, ideal loads air system #3 is attached to this plenum
3436 : // PurchAirPlenumArrays( 1 ).IsSimulated( 1 ) = true, ideal loads air system #1 has been simulated this iteration
3437 : // PurchAirPlenumArrays( 1 ).IsSimulated( 2 ) = false, ideal loads air system #3 has not yet been simulated this iteration
3438 : //
3439 : // Ideal loads air sytems keep track of which plenum they are connected to
3440 : // PurchAir( 1 ).PlenumArrayIndex = 1
3441 : // PurchAir( 1 ).ReturnPlenumName = ReturnPlenum2;
3442 : // PurchAir( 3 ).PlenumArrayIndex = 1
3443 : // PurchAir( 3 ).ReturnPlenumName = ReturnPlenum2;
3444 : //
3445 : // The ideal loads air sytems also keep track of which item they are in the int and bool arrays
3446 : // PurchAir( 1 ).PurchAirArrayIndex = 1
3447 : // PurchAir( 3 ).PurchAirArrayIndex = 2
3448 : //
3449 : // PurchAirPlenumArrays( 2 )
3450 : // PurchAirPlenumArrays( 2 ).NumPurchAir = 3, there are 3 ideal loads air systems connected to this plenum
3451 : // PurchAirPlenumArrays( 2 ).PurchAirArray( 1 ) = 2, ideal loads air system #2 is attached to this plenum
3452 : // PurchAirPlenumArrays( 2 ).PurchAirArray( 2 ) = 5, ideal loads air system #5 is attached to this plenum
3453 : // PurchAirPlenumArrays( 2 ).PurchAirArray( 3 ) = 6, ideal loads air system #6 is attached to this plenum
3454 : // PurchAirPlenumArrays( 2 ).IsSimulated( 1 ) = true, ideal loads air system #4 has been simulated this iteration
3455 : // PurchAirPlenumArrays( 2 ).IsSimulated( 2 ) = false, ideal loads air system #5 has not yet been simulated this iteration
3456 : // PurchAirPlenumArrays( 2 ).IsSimulated( 3 ) = false, ideal loads air system #6 has not yet been simulated this iteration
3457 : //
3458 : // Ideal loads air sytems keep track of which plenum they are connected to
3459 : // PurchAir( 2 ).PlenumArrayIndex = 2;
3460 : // PurchAir( 2 ).ReturnPlenumName = ReturnPlenum3;
3461 : // PurchAir( 5 ).PlenumArrayIndex = 2;
3462 : // PurchAir( 5 ).ReturnPlenumName = ReturnPlenum3;
3463 : // PurchAir( 6 ).PlenumArrayIndex = 2;
3464 : // PurchAir( 6 ).ReturnPlenumName = ReturnPlenum3;
3465 : //
3466 : // The ideal loads air sytems also keep track of which item they are in the int and bool arrays
3467 : // PurchAir( 2 ).PurchAirArrayIndex = 1;
3468 : // PurchAir( 5 ).PurchAirArrayIndex = 2;
3469 : // PurchAir( 6 ).PurchAirArrayIndex = 3;
3470 : //
3471 : // Given these connections, the data in the IsSimulated array can be set (or checked) according to this syntax:
3472 : //
3473 : // Each time an ideal loads air system is simulated the IsSimulated flag is set to true
3474 : // PurchAirPlenumArrays( PurchAir( PurchNum ).PlenumArrayIndex ).IsSimulated( PurchAir( PurchNum ).PurchAirArrayIndex ) = true;
3475 : //
3476 : // if all ideal loads air systems connected to the same plenum have been simulated, simulate the zone air return plenum (once per set of
3477 : // ideal loads systems) if ( all( PurchAirPlenumArrays( PurchAir( PurchAirNum ).ReturnPlenumIndex ).IsSimulated ) ) {
3478 : // SimAirZonePlenum( PurchAir( PurchAirNum ).ReturnPlenumName, DataZoneEquipment::ZoneReturnPlenum_Type, PurchAir( PurchAirNum
3479 : // ).ReturnPlenumIndex, FirstHVACIteration, FirstCall, SupPathInletChanged ); reset all IsSimulated flags for next iteration
3480 : // PurchAirPlenumArrays( PurchAir( PurchAirNum ).ReturnPlenumIndex ).IsSimulated = false;
3481 : // }
3482 :
3483 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
3484 : int ReturnPlenumIndex; // index to ZoneHVAC:ReturnPlenum object
3485 : int ReturnPlenumNum; // loop counter
3486 : bool PlenumNotFound; // logical to determine if same plenum is used by other ideal loads air systems
3487 : int Loop; // loop counters
3488 : int Loop2; // loop counters
3489 5 : Array1D_int TempPurchArray; // temporary array used for dynamic allocation
3490 5 : Array1D_bool TempIsSimulated; // temporary array used for dynamic allocation
3491 :
3492 : // index to ZoneHVAC:ReturnPlenum object
3493 5 : ReturnPlenumIndex = state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ReturnPlenumIndex;
3494 5 : PlenumNotFound = true;
3495 :
3496 : // if first time through, set up arrays
3497 5 : if (!state.dataPurchasedAirMgr->PurchAirPlenumArrays.allocated()) {
3498 :
3499 : // the ideal loads air system keeps track of which item this system is in a list
3500 1 : state.dataPurchasedAirMgr->PurchAir(PurchAirNum).PurchAirArrayIndex = 1;
3501 : // keep track of how many arrays (i.e., how many different plenums are attached to different ideal loads air systems
3502 1 : state.dataPurchasedAirMgr->NumPlenumArrays = 1;
3503 :
3504 : // allocate new array
3505 1 : state.dataPurchasedAirMgr->PurchAirPlenumArrays.allocate(state.dataPurchasedAirMgr->NumPlenumArrays);
3506 : // set counter for how many ideal loads air systems are attached to this plenum
3507 1 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).NumPurchAir =
3508 : 1; // keeps track of how many ideal loads air system are connected to this return plenum
3509 : // keep track of which plenum this is ( i.e., PurchAirPlenumArrays(1) is ZoneHVAC:ReturnPlenum #4 )
3510 1 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).ReturnPlenumIndex =
3511 : ReturnPlenumIndex; // stores index of return plenum (e.g., 4 of 5)
3512 : // allocate array holding index to one or more ideal loads air systems
3513 1 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray.allocate(1);
3514 : // allocate boolean to keep track of whether or not this ideal loads air system has been simulated
3515 1 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated.allocate(1);
3516 : // save the data
3517 1 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray(1) = PurchAirNum;
3518 1 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated(1) = false;
3519 :
3520 : } else {
3521 :
3522 : // find the correct index to PurchAirPlenumArrays
3523 4 : for (ReturnPlenumNum = 1; ReturnPlenumNum <= state.dataPurchasedAirMgr->NumPlenumArrays; ++ReturnPlenumNum) {
3524 4 : if (ReturnPlenumIndex != state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).ReturnPlenumIndex) continue;
3525 :
3526 : // allocate temporary arrays and save existing data
3527 4 : TempPurchArray.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir);
3528 4 : TempIsSimulated.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir);
3529 : // these are the member arrays in an existing PurchAirPlenumArrays
3530 4 : TempPurchArray = state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).PurchAirArray;
3531 4 : TempIsSimulated = state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).IsSimulated;
3532 :
3533 : // if this array has been used before, we need to increase member array space to save new PurchAir data
3534 4 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir += 1;
3535 : // save the location of this ideal loads air system in the member arrays
3536 4 : state.dataPurchasedAirMgr->PurchAir(PurchAirNum).PurchAirArrayIndex =
3537 4 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir;
3538 :
3539 : // allocate more space, this will wipe out data previously stored
3540 4 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum)
3541 4 : .PurchAirArray.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir);
3542 4 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum)
3543 4 : .IsSimulated.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir);
3544 :
3545 : // re-initialize previous data
3546 14 : for (Loop = 1; Loop < state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir; ++Loop) {
3547 10 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).PurchAirArray(Loop) = TempPurchArray(Loop);
3548 10 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).IsSimulated(Loop) = TempIsSimulated(Loop);
3549 : }
3550 : // delete temporary array
3551 4 : TempPurchArray.deallocate();
3552 4 : TempIsSimulated.deallocate();
3553 :
3554 : // save new data in expanded member array
3555 4 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum)
3556 8 : .PurchAirArray(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir) = PurchAirNum;
3557 4 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum)
3558 4 : .IsSimulated(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir) = false;
3559 :
3560 4 : PlenumNotFound = false;
3561 4 : break;
3562 : }
3563 :
3564 4 : if (PlenumNotFound) {
3565 :
3566 : // need to allocate additional space for new plenum array
3567 : // keep track of how many arrays (i.e., how many different plenums are attached to different ideal loads air systems)
3568 0 : state.dataPurchasedAirMgr->NumPlenumArrays += 1;
3569 :
3570 : // allocate temporary array and save existing data
3571 0 : state.dataPurchasedAirMgr->TempPurchAirPlenumArrays.allocate(state.dataPurchasedAirMgr->NumPlenumArrays);
3572 0 : for (Loop = 1; Loop < state.dataPurchasedAirMgr->NumPlenumArrays; ++Loop) {
3573 0 : state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).NumPurchAir =
3574 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir;
3575 0 : state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).ReturnPlenumIndex =
3576 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).ReturnPlenumIndex;
3577 0 : state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).PurchAirArray.allocate(
3578 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir);
3579 0 : state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).IsSimulated.allocate(
3580 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir);
3581 0 : for (Loop2 = 1; Loop2 <= state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir; ++Loop2) {
3582 0 : state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).PurchAirArray(Loop2) =
3583 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).PurchAirArray(Loop2);
3584 0 : state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).IsSimulated(Loop2) =
3585 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).IsSimulated(Loop2);
3586 : }
3587 : }
3588 :
3589 : // delete primary array (probably could just re-allocate, but this is only done a few times per simulation)
3590 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays.deallocate();
3591 : // reallocate to new size
3592 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays.allocate(state.dataPurchasedAirMgr->NumPlenumArrays);
3593 :
3594 : // allocate member arrays to same size as before
3595 0 : for (Loop = 1; Loop < state.dataPurchasedAirMgr->NumPlenumArrays; ++Loop) {
3596 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).PurchAirArray.allocate(
3597 0 : state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).NumPurchAir);
3598 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).IsSimulated.allocate(
3599 0 : state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).NumPurchAir);
3600 : }
3601 :
3602 : // save the data
3603 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays = state.dataPurchasedAirMgr->TempPurchAirPlenumArrays;
3604 : // delete temporary data
3605 0 : state.dataPurchasedAirMgr->TempPurchAirPlenumArrays.deallocate();
3606 :
3607 : // save the index to where this ideal loads air system data is stored
3608 0 : state.dataPurchasedAirMgr->PurchAir(PurchAirNum).PurchAirArrayIndex = 1;
3609 : // save the number of ideal loads air systems stored in these arrays
3610 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).NumPurchAir = 1;
3611 : // save the index the the ZoneHVAC:ReturnPlenum
3612 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).ReturnPlenumIndex = ReturnPlenumIndex;
3613 : // allocate member array and store data
3614 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray.allocate(1);
3615 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray(1) = PurchAirNum;
3616 : // allocate member array and store data
3617 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated.allocate(1);
3618 0 : state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated(1) = false;
3619 : }
3620 : }
3621 5 : }
3622 :
3623 : } // namespace EnergyPlus::PurchasedAirManager
|