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 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Autosizing/Base.hh>
57 : #include <EnergyPlus/BranchNodeConnections.hh>
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataAirSystems.hh>
60 : #include <EnergyPlus/DataEnvironment.hh>
61 : #include <EnergyPlus/DataHVACGlobals.hh>
62 : #include <EnergyPlus/DataIPShortCuts.hh>
63 : #include <EnergyPlus/DataLoopNode.hh>
64 : #include <EnergyPlus/DataSizing.hh>
65 : #include <EnergyPlus/DataZoneEquipment.hh>
66 : #include <EnergyPlus/DesiccantDehumidifiers.hh>
67 : #include <EnergyPlus/Fans.hh>
68 : #include <EnergyPlus/FluidProperties.hh>
69 : #include <EnergyPlus/General.hh>
70 : #include <EnergyPlus/GeneralRoutines.hh>
71 : #include <EnergyPlus/GlobalNames.hh>
72 : #include <EnergyPlus/HVACDXHeatPumpSystem.hh>
73 : #include <EnergyPlus/HVACHXAssistedCoolingCoil.hh>
74 : #include <EnergyPlus/HeatRecovery.hh>
75 : #include <EnergyPlus/HeatingCoils.hh>
76 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
77 : #include <EnergyPlus/NodeInputManager.hh>
78 : #include <EnergyPlus/OutAirNodeManager.hh>
79 : #include <EnergyPlus/OutdoorAirUnit.hh>
80 : #include <EnergyPlus/OutputProcessor.hh>
81 : #include <EnergyPlus/PlantUtilities.hh>
82 : #include <EnergyPlus/Psychrometrics.hh>
83 : #include <EnergyPlus/ScheduleManager.hh>
84 : #include <EnergyPlus/SteamCoils.hh>
85 : #include <EnergyPlus/UnitarySystem.hh>
86 : #include <EnergyPlus/UtilityRoutines.hh>
87 : #include <EnergyPlus/WaterCoils.hh>
88 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
89 :
90 : namespace EnergyPlus {
91 :
92 : namespace OutdoorAirUnit {
93 : // Module containing the routines dealing with the outdoor air unit
94 :
95 : // MODULE INFORMATION:
96 : // AUTHOR Young Tae Chae, Rick Strand
97 : // DATE WRITTEN AUG. 2009
98 : // MODIFIED
99 : // Feb 2013 Bereket Nigusse, FSEC
100 : // Added DX Coil Model For 100% OA systems
101 : // RE-ENGINEERED na
102 :
103 : // PURPOSE OF THIS MODULE:
104 : // Simulate zone outdoor air unit.
105 :
106 : // METHODOLOGY EMPLOYED:
107 : // Systems are modeled as a collection of components:
108 : // fan, heat recovery, dehumidifier, heating coil and/or cooling coil plus an integrated control
109 : // algorithm that adjusts the hot or cold water flow to meet the setpoint
110 : // condition.
111 :
112 : // Using/Aliasing
113 : using namespace DataLoopNode;
114 : using HVAC::SmallAirVolFlow;
115 : using HVAC::SmallLoad;
116 : using HVAC::SmallMassFlow;
117 : using namespace ScheduleManager;
118 : using namespace Psychrometrics;
119 :
120 : // component types addressed by this module
121 : constexpr static std::string_view ZoneHVACOAUnit = {"ZoneHVAC:OutdoorAirUnit"};
122 : constexpr static std::string_view ZoneHVACEqList = {"ZoneHVAC:OutdoorAirUnit:EquipmentList"};
123 :
124 64818 : void SimOutdoorAirUnit(EnergyPlusData &state,
125 : std::string_view CompName, // name of the outdoor air unit
126 : int const ZoneNum, // number of zone being served
127 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
128 : Real64 &PowerMet, // Sensible power supplied (W)
129 : Real64 &LatOutputProvided, // Latent add/removal supplied by window AC (kg/s), dehumid = negative
130 : int &CompIndex)
131 : {
132 :
133 : // SUBROUTINE INFORMATION:
134 : // AUTHOR Rick Strand
135 : // DATE WRITTEN May 2000
136 : // MODIFIED na
137 : // RE-ENGINEERED
138 : // This is re-engineered by Rick Strand and Young T. Chae for OutdoorAirUnit (July, 2009)
139 :
140 : // PURPOSE OF THIS SUBROUTINE:
141 : // This is the main driver subroutine for the outdoor air control unit simulation.
142 :
143 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
144 64818 : int OAUnitNum = 0; // index of outdoor air unit being simulated
145 :
146 64818 : if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
147 2 : GetOutdoorAirUnitInputs(state);
148 2 : state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
149 : }
150 :
151 : // Find the correct Outdoor Air Unit
152 :
153 64818 : if (CompIndex == 0) {
154 12 : OAUnitNum = Util::FindItemInList(CompName, state.dataOutdoorAirUnit->OutAirUnit);
155 12 : if (OAUnitNum == 0) {
156 0 : ShowFatalError(state, format("ZoneHVAC:OutdoorAirUnit not found={}", CompName));
157 : }
158 12 : CompIndex = OAUnitNum;
159 : } else {
160 64806 : OAUnitNum = CompIndex;
161 64806 : if (OAUnitNum > state.dataOutdoorAirUnit->NumOfOAUnits || OAUnitNum < 1) {
162 0 : ShowFatalError(state,
163 0 : format("SimOutdoorAirUnit: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
164 : OAUnitNum,
165 0 : state.dataOutdoorAirUnit->NumOfOAUnits,
166 : CompName));
167 : }
168 64806 : if (state.dataOutdoorAirUnit->CheckEquipName(OAUnitNum)) {
169 12 : if (CompName != state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).Name) {
170 0 : ShowFatalError(state,
171 0 : format("SimOutdoorAirUnit: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
172 : OAUnitNum,
173 : CompName,
174 0 : state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).Name));
175 : }
176 12 : state.dataOutdoorAirUnit->CheckEquipName(OAUnitNum) = false;
177 : }
178 : }
179 :
180 64818 : state.dataSize->ZoneEqOutdoorAirUnit = true;
181 :
182 64818 : if (state.dataGlobal->ZoneSizingCalc || state.dataGlobal->SysSizingCalc) {
183 12 : return;
184 : }
185 :
186 64806 : InitOutdoorAirUnit(state, OAUnitNum, ZoneNum, FirstHVACIteration);
187 :
188 64806 : CalcOutdoorAirUnit(state, OAUnitNum, ZoneNum, FirstHVACIteration, PowerMet, LatOutputProvided);
189 :
190 64806 : ReportOutdoorAirUnit(state, OAUnitNum);
191 :
192 64806 : state.dataSize->ZoneEqOutdoorAirUnit = false;
193 : }
194 :
195 2 : void GetOutdoorAirUnitInputs(EnergyPlusData &state)
196 : {
197 :
198 : // SUBROUTINE INFORMATION:
199 : // AUTHOR Young Tae Chae, Rick Strand
200 : // DATE WRITTEN July 2009
201 : // MODIFIED July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
202 : // RE-ENGINEERED na
203 :
204 : // PURPOSE OF THIS SUBROUTINE:
205 : // This subroutine obtains the input for the outdoor air control unit and sets
206 : // up the appropriate derived type.
207 :
208 : // METHODOLOGY EMPLOYED:
209 : // Standard EnergyPlus methodology.
210 :
211 : // REFERENCES:
212 : // Fred Buhl's fan coil module (FanCoilUnits.cc)
213 : // Kwang Ho Lee's Unit Ventilator Module (UnitVentilator.cc)
214 : // Young Tae Chae's Ventilated Slab System (VentilatedSlab.cc)
215 : // Mixed Air.cc
216 :
217 : // Using/Aliasing
218 : using BranchNodeConnections::SetUpCompSets;
219 : using BranchNodeConnections::TestCompSet;
220 : using NodeInputManager::GetOnlySingleNode;
221 : using ScheduleManager::GetScheduleIndex;
222 : using SteamCoils::GetCoilAirInletNode;
223 : using SteamCoils::GetCoilAirOutletNode;
224 : using SteamCoils::GetCoilMaxSteamFlowRate;
225 : using SteamCoils::GetCoilSteamInletNode;
226 : using SteamCoils::GetCoilSteamOutletNode;
227 : using SteamCoils::GetSteamCoilIndex;
228 : using namespace DataLoopNode;
229 : using HeatingCoils::GetCoilInletNode;
230 : using HeatingCoils::GetCoilOutletNode;
231 : using OutAirNodeManager::CheckAndAddAirNodeNumber;
232 : using WaterCoils::GetCoilWaterInletNode;
233 : using WaterCoils::GetCoilWaterOutletNode;
234 : using WaterCoils::GetWaterCoilIndex;
235 :
236 : // SUBROUTINE PARAMETER DEFINITIONS:
237 : static constexpr std::string_view RoutineName("GetOutdoorAirUnitInputs: "); // include trailing blank space
238 : static constexpr std::string_view routineName = "GetOutdoorAirUnitInputs"; // include trailing blank space
239 :
240 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
241 :
242 2 : if (!state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
243 0 : return;
244 : }
245 :
246 2 : int NumAlphas = 0; // Number of elements in the alpha array
247 2 : int NumNums = 0; // Number of elements in the numeric array
248 2 : Array1D_string AlphArray; // character string data
249 2 : Array1D<Real64> NumArray; // numeric data
250 2 : int IOStat = -1; // IO Status when calling get input subroutine
251 2 : bool ErrorsFound = false;
252 :
253 2 : int MaxNums = 0; // Maximum number of numeric input fields
254 2 : int MaxAlphas = 0; // Maximum number of alpha input fields
255 2 : int TotalArgs = 0; // Total number of alpha and numeric arguments (max) for a
256 : bool IsValid; // Set for outside air node check
257 2 : Array1D_string cAlphaArgs; // Alpha input items for object
258 2 : std::string CurrentModuleObject; // Object type for getting and messages
259 2 : Array1D_string cAlphaFields; // Alpha field names
260 2 : Array1D_string cNumericFields; // Numeric field names
261 2 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
262 2 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
263 :
264 : // Figure out how many outdoor air units there are in the input file
265 :
266 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, ZoneHVACOAUnit, TotalArgs, NumAlphas, NumNums);
267 2 : MaxNums = max(MaxNums, NumNums);
268 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
269 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, ZoneHVACEqList, TotalArgs, NumAlphas, NumNums);
270 2 : MaxNums = max(MaxNums, NumNums);
271 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
272 :
273 2 : AlphArray.allocate(MaxAlphas);
274 2 : cAlphaFields.allocate(MaxAlphas);
275 2 : NumArray.dimension(MaxNums, 0.0);
276 2 : cNumericFields.allocate(MaxNums);
277 2 : lAlphaBlanks.dimension(MaxAlphas, true);
278 2 : lNumericBlanks.dimension(MaxNums, true);
279 2 : cAlphaArgs.allocate(NumAlphas);
280 :
281 2 : CurrentModuleObject = ZoneHVACOAUnit;
282 2 : state.dataOutdoorAirUnit->NumOfOAUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
283 :
284 2 : state.dataOutdoorAirUnit->OutAirUnit.allocate(state.dataOutdoorAirUnit->NumOfOAUnits);
285 2 : state.dataOutdoorAirUnit->SupplyFanUniqueNames.reserve(static_cast<unsigned>(state.dataOutdoorAirUnit->NumOfOAUnits));
286 2 : state.dataOutdoorAirUnit->ExhaustFanUniqueNames.reserve(static_cast<unsigned>(state.dataOutdoorAirUnit->NumOfOAUnits));
287 2 : state.dataOutdoorAirUnit->ComponentListUniqueNames.reserve(static_cast<unsigned>(state.dataOutdoorAirUnit->NumOfOAUnits));
288 2 : state.dataOutdoorAirUnit->MyOneTimeErrorFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
289 2 : state.dataOutdoorAirUnit->CheckEquipName.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
290 :
291 14 : for (int OAUnitNum = 1; OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits; ++OAUnitNum) {
292 :
293 12 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
294 :
295 24 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
296 : CurrentModuleObject,
297 : OAUnitNum,
298 12 : state.dataIPShortCut->cAlphaArgs,
299 : NumAlphas,
300 : NumArray,
301 : NumNums,
302 : IOStat,
303 : lNumericBlanks,
304 : lAlphaBlanks,
305 : cAlphaFields,
306 : cNumericFields);
307 :
308 12 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
309 12 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), CurrentModuleObject, ErrorsFound);
310 :
311 : // A1
312 12 : thisOutAirUnit.Name = state.dataIPShortCut->cAlphaArgs(1);
313 :
314 : // A2
315 12 : thisOutAirUnit.SchedName = state.dataIPShortCut->cAlphaArgs(2);
316 12 : if (lAlphaBlanks(2)) {
317 0 : thisOutAirUnit.SchedPtr = ScheduleManager::ScheduleAlwaysOn;
318 : } else {
319 12 : thisOutAirUnit.SchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2)); // convert schedule name to pointer
320 12 : if (thisOutAirUnit.SchedPtr == 0) {
321 0 : ShowSevereError(state,
322 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
323 : CurrentModuleObject,
324 0 : state.dataIPShortCut->cAlphaArgs(1),
325 0 : state.dataIPShortCut->cAlphaArgs(2),
326 0 : state.dataIPShortCut->cAlphaArgs(2)));
327 0 : ErrorsFound = true;
328 : }
329 : }
330 :
331 : // A3
332 12 : thisOutAirUnit.ZoneName = state.dataIPShortCut->cAlphaArgs(3);
333 12 : thisOutAirUnit.ZonePtr = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataHeatBal->Zone);
334 :
335 12 : if (thisOutAirUnit.ZonePtr == 0) {
336 0 : if (lAlphaBlanks(3)) {
337 0 : ShowSevereError(state,
338 0 : format("{}=\"{}\" invalid {} is required but input is blank.",
339 : CurrentModuleObject,
340 0 : state.dataIPShortCut->cAlphaArgs(1),
341 0 : state.dataIPShortCut->cAlphaArgs(3)));
342 : } else {
343 0 : ShowSevereError(state,
344 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
345 : CurrentModuleObject,
346 0 : state.dataIPShortCut->cAlphaArgs(1),
347 0 : state.dataIPShortCut->cAlphaArgs(3),
348 0 : state.dataIPShortCut->cAlphaArgs(3)));
349 : }
350 0 : ErrorsFound = true;
351 : }
352 12 : thisOutAirUnit.ZoneNodeNum = state.dataHeatBal->Zone(thisOutAirUnit.ZonePtr).SystemZoneNodeNumber;
353 : // Outside air information:
354 : // N1
355 12 : thisOutAirUnit.OutAirVolFlow = NumArray(1);
356 : // A4
357 12 : thisOutAirUnit.OutAirSchedName = state.dataIPShortCut->cAlphaArgs(4);
358 : // convert schedule name to pointer
359 12 : thisOutAirUnit.OutAirSchedPtr = GetScheduleIndex(state, thisOutAirUnit.OutAirSchedName);
360 12 : if (thisOutAirUnit.OutAirSchedPtr == 0) {
361 0 : ShowSevereError(state,
362 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
363 : CurrentModuleObject,
364 0 : state.dataIPShortCut->cAlphaArgs(1),
365 : cAlphaFields(4),
366 0 : state.dataIPShortCut->cAlphaArgs(4)));
367 0 : ErrorsFound = true;
368 : }
369 :
370 : // A5
371 12 : thisOutAirUnit.SFanName = state.dataIPShortCut->cAlphaArgs(5);
372 12 : GlobalNames::IntraObjUniquenessCheck(state,
373 12 : state.dataIPShortCut->cAlphaArgs(5),
374 : CurrentModuleObject,
375 12 : cAlphaFields(5),
376 12 : state.dataOutdoorAirUnit->SupplyFanUniqueNames,
377 : ErrorsFound);
378 :
379 12 : if ((thisOutAirUnit.SFan_Index = Fans::GetFanIndex(state, thisOutAirUnit.SFanName)) == 0) {
380 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(5), thisOutAirUnit.SFanName);
381 0 : ErrorsFound = true;
382 : } else {
383 12 : auto *fan = state.dataFans->fans(thisOutAirUnit.SFan_Index);
384 12 : thisOutAirUnit.supFanType = fan->type;
385 12 : thisOutAirUnit.SFanMaxAirVolFlow = fan->maxAirFlowRate;
386 12 : thisOutAirUnit.SFanAvailSchedPtr = fan->availSchedNum;
387 : }
388 : // A6 :Fan Place
389 12 : thisOutAirUnit.supFanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, state.dataIPShortCut->cAlphaArgs(6)));
390 :
391 : // A7
392 :
393 12 : if (lAlphaBlanks(7)) {
394 0 : thisOutAirUnit.ExtFan = false;
395 0 : if (!state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance) {
396 0 : ShowWarningError(state,
397 0 : format("{}=\"{}\", {} is blank.", CurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1), cAlphaFields(7)));
398 0 : ShowContinueError(state,
399 : "Unbalanced mass flow rates between supply from outdoor air and exhaust from zone air will be introduced.");
400 : }
401 12 : } else if (!lAlphaBlanks(7)) {
402 12 : thisOutAirUnit.ExtFanName = state.dataIPShortCut->cAlphaArgs(7);
403 12 : GlobalNames::IntraObjUniquenessCheck(state,
404 12 : state.dataIPShortCut->cAlphaArgs(7),
405 : CurrentModuleObject,
406 12 : cAlphaFields(7),
407 12 : state.dataOutdoorAirUnit->ExhaustFanUniqueNames,
408 : ErrorsFound);
409 :
410 12 : if ((thisOutAirUnit.ExtFan_Index = Fans::GetFanIndex(state, thisOutAirUnit.ExtFanName)) == 0) {
411 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(7), thisOutAirUnit.ExtFanName);
412 0 : ErrorsFound = true;
413 : } else {
414 12 : auto *fan = state.dataFans->fans(thisOutAirUnit.ExtFan_Index);
415 12 : thisOutAirUnit.extFanType = fan->type;
416 12 : thisOutAirUnit.EFanMaxAirVolFlow = fan->maxAirFlowRate;
417 12 : thisOutAirUnit.ExtFanAvailSchedPtr = fan->availSchedNum;
418 : }
419 12 : thisOutAirUnit.ExtFan = true;
420 : }
421 :
422 : // N2
423 12 : thisOutAirUnit.ExtAirVolFlow = NumArray(2);
424 12 : if ((thisOutAirUnit.ExtFan) && (!state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance)) {
425 12 : if (NumArray(2) != NumArray(1)) {
426 0 : ShowWarningError(state,
427 0 : format("{}=\"{}\", {} and {} are not equal. This may cause unbalanced flow.",
428 : CurrentModuleObject,
429 0 : state.dataIPShortCut->cAlphaArgs(1),
430 : cNumericFields(1),
431 : cNumericFields(2)));
432 0 : ShowContinueError(state, format("{}={:.3R}= and {}{:.3R}", cNumericFields(1), NumArray(1), cNumericFields(2), NumArray(2)));
433 : }
434 : }
435 : // A8
436 12 : thisOutAirUnit.ExtAirSchedName = state.dataIPShortCut->cAlphaArgs(8);
437 : // convert schedule name to pointer
438 12 : thisOutAirUnit.ExtOutAirSchedPtr = GetScheduleIndex(state, thisOutAirUnit.ExtAirSchedName);
439 12 : if (thisOutAirUnit.ExtFan) {
440 12 : if ((thisOutAirUnit.ExtOutAirSchedPtr == 0) || (lNumericBlanks(2))) {
441 0 : ShowSevereError(state,
442 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
443 : CurrentModuleObject,
444 0 : state.dataIPShortCut->cAlphaArgs(1),
445 : cAlphaFields(8),
446 0 : state.dataIPShortCut->cAlphaArgs(8)));
447 0 : ErrorsFound = true;
448 : } else {
449 12 : if ((thisOutAirUnit.ExtOutAirSchedPtr != thisOutAirUnit.OutAirSchedPtr) &&
450 0 : (!state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance)) {
451 0 : ShowWarningError(
452 : state,
453 0 : format("{}=\"{}\", different schedule inputs for outdoor air and exhaust air schedules may cause unbalanced mass flow.",
454 : CurrentModuleObject,
455 0 : state.dataIPShortCut->cAlphaArgs(1)));
456 0 : ShowContinueError(state,
457 0 : format("{}={} and {}={}",
458 : cAlphaFields(4),
459 0 : state.dataIPShortCut->cAlphaArgs(4),
460 : cAlphaFields(8),
461 0 : state.dataIPShortCut->cAlphaArgs(8)));
462 : }
463 : }
464 :
465 24 : SetUpCompSets(
466 12 : state, CurrentModuleObject, thisOutAirUnit.Name, "UNDEFINED", state.dataIPShortCut->cAlphaArgs(7), "UNDEFINED", "UNDEFINED");
467 : }
468 :
469 : // Process the unit control type
470 12 : if (!lAlphaBlanks(9)) {
471 12 : constexpr std::array<std::string_view, static_cast<int>(OAUnitCtrlType::Num)> ctrlTypeNamesUC = {
472 : "NEUTRALCONTROL", "INVALID-UNCONDITIONED", "TEMPERATURECONTROL"};
473 12 : OAUnitCtrlType const tmpCtrlType = static_cast<OAUnitCtrlType>(getEnumValue(ctrlTypeNamesUC, state.dataIPShortCut->cAlphaArgs(9)));
474 12 : switch (tmpCtrlType) {
475 12 : case OAUnitCtrlType::Neutral:
476 : case OAUnitCtrlType::Temperature:
477 12 : thisOutAirUnit.controlType = tmpCtrlType;
478 12 : break;
479 0 : default:
480 0 : break; // just leave it alone, nothing was done here
481 : }
482 : } else {
483 0 : ShowSevereError(state,
484 0 : format(R"({}="{}" invalid {}="{}".)",
485 : CurrentModuleObject,
486 0 : state.dataIPShortCut->cAlphaArgs(1),
487 : cAlphaFields(9),
488 0 : state.dataIPShortCut->cAlphaArgs(9)));
489 0 : ShowContinueError(state, "Control reset to Unconditioned Control.");
490 0 : thisOutAirUnit.controlType = OAUnitCtrlType::Neutral;
491 : }
492 :
493 : // A10:High Control Temp :
494 12 : thisOutAirUnit.HiCtrlTempSched = state.dataIPShortCut->cAlphaArgs(10);
495 12 : thisOutAirUnit.HiCtrlTempSchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(10));
496 12 : if ((thisOutAirUnit.HiCtrlTempSchedPtr == 0) && (!lAlphaBlanks(10))) {
497 0 : ShowSevereError(state,
498 0 : format(R"({}="{}" invalid {}="{}" not found.)",
499 : CurrentModuleObject,
500 0 : state.dataIPShortCut->cAlphaArgs(1),
501 : cAlphaFields(10),
502 0 : state.dataIPShortCut->cAlphaArgs(9)));
503 0 : ErrorsFound = true;
504 : }
505 :
506 : // A11:Low Control Temp :
507 12 : thisOutAirUnit.LoCtrlTempSched = state.dataIPShortCut->cAlphaArgs(11);
508 12 : thisOutAirUnit.LoCtrlTempSchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(11));
509 12 : if ((thisOutAirUnit.LoCtrlTempSchedPtr == 0) && (!lAlphaBlanks(11))) {
510 0 : ShowSevereError(state,
511 0 : format(R"({}="{}" invalid {}="{}" not found.)",
512 : CurrentModuleObject,
513 0 : state.dataIPShortCut->cAlphaArgs(1),
514 : cAlphaFields(11),
515 0 : state.dataIPShortCut->cAlphaArgs(10)));
516 0 : ErrorsFound = true;
517 : }
518 :
519 12 : thisOutAirUnit.CompOutSetTemp = 0.0;
520 :
521 : // A12~A15 : Node Condition
522 :
523 : // Main air nodes (except outside air node):
524 :
525 12 : thisOutAirUnit.AirOutletNode = GetOnlySingleNode(state,
526 12 : state.dataIPShortCut->cAlphaArgs(13),
527 : ErrorsFound,
528 : DataLoopNode::ConnectionObjectType::ZoneHVACOutdoorAirUnit,
529 12 : state.dataIPShortCut->cAlphaArgs(1),
530 : DataLoopNode::NodeFluidType::Air,
531 : DataLoopNode::ConnectionType::Outlet,
532 : NodeInputManager::CompFluidStream::Primary,
533 : ObjectIsParent);
534 12 : if (!lAlphaBlanks(14)) {
535 24 : thisOutAirUnit.AirInletNode = GetOnlySingleNode(state,
536 12 : state.dataIPShortCut->cAlphaArgs(14),
537 : ErrorsFound,
538 : DataLoopNode::ConnectionObjectType::ZoneHVACOutdoorAirUnit,
539 12 : state.dataIPShortCut->cAlphaArgs(1),
540 : DataLoopNode::NodeFluidType::Air,
541 : DataLoopNode::ConnectionType::Inlet,
542 : NodeInputManager::CompFluidStream::Primary,
543 : ObjectIsParent);
544 : } else {
545 0 : if (thisOutAirUnit.ExtFan) {
546 0 : ShowSevereError(state,
547 0 : format("{}=\"{}\" invalid {} cannot be blank when there is an exhaust fan.",
548 : CurrentModuleObject,
549 0 : state.dataIPShortCut->cAlphaArgs(1),
550 : cAlphaFields(14)));
551 0 : ErrorsFound = true;
552 : }
553 : }
554 :
555 12 : thisOutAirUnit.SFanOutletNode = GetOnlySingleNode(state,
556 12 : state.dataIPShortCut->cAlphaArgs(15),
557 : ErrorsFound,
558 : DataLoopNode::ConnectionObjectType::ZoneHVACOutdoorAirUnit,
559 12 : state.dataIPShortCut->cAlphaArgs(1),
560 : DataLoopNode::NodeFluidType::Air,
561 : DataLoopNode::ConnectionType::Internal,
562 : NodeInputManager::CompFluidStream::Primary,
563 : ObjectIsNotParent);
564 :
565 : // Set connection type to 'OutdoorAir', because this is hardwired to OA conditions
566 12 : thisOutAirUnit.OutsideAirNode = GetOnlySingleNode(state,
567 12 : state.dataIPShortCut->cAlphaArgs(12),
568 : ErrorsFound,
569 : DataLoopNode::ConnectionObjectType::ZoneHVACOutdoorAirUnit,
570 12 : state.dataIPShortCut->cAlphaArgs(1),
571 : DataLoopNode::NodeFluidType::Air,
572 : DataLoopNode::ConnectionType::OutsideAirReference,
573 : NodeInputManager::CompFluidStream::Primary,
574 : ObjectIsNotParent);
575 :
576 12 : if (!lAlphaBlanks(12)) {
577 12 : CheckAndAddAirNodeNumber(state, thisOutAirUnit.OutsideAirNode, IsValid);
578 12 : if (!IsValid) {
579 0 : ShowWarningError(state,
580 0 : format("{}=\"{}\", Adding OutdoorAir:Node={}",
581 : CurrentModuleObject,
582 0 : state.dataIPShortCut->cAlphaArgs(1),
583 0 : state.dataIPShortCut->cAlphaArgs(12)));
584 : }
585 : }
586 :
587 : // When the fan position is "BlowThru", Each node is set up
588 :
589 12 : if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::BlowThru) {
590 12 : SetUpCompSets(state,
591 : CurrentModuleObject,
592 : thisOutAirUnit.Name,
593 : "UNDEFINED",
594 6 : state.dataIPShortCut->cAlphaArgs(5),
595 6 : state.dataIPShortCut->cAlphaArgs(12),
596 6 : state.dataIPShortCut->cAlphaArgs(15));
597 : }
598 :
599 : // A16 : component list
600 :
601 12 : GlobalNames::IntraObjUniquenessCheck(state,
602 12 : state.dataIPShortCut->cAlphaArgs(16),
603 : CurrentModuleObject,
604 12 : cAlphaFields(16),
605 12 : state.dataOutdoorAirUnit->ComponentListUniqueNames,
606 : ErrorsFound);
607 24 : std::string const ComponentListName = state.dataIPShortCut->cAlphaArgs(16);
608 12 : thisOutAirUnit.ComponentListName = ComponentListName;
609 12 : if (!lAlphaBlanks(16)) {
610 12 : int const ListNum = state.dataInputProcessing->inputProcessor->getObjectItemNum(state, ZoneHVACEqList, ComponentListName);
611 12 : if (ListNum > 0) {
612 12 : state.dataInputProcessing->inputProcessor->getObjectItem(
613 : state, ZoneHVACEqList, ListNum, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
614 12 : int NumInList = (NumAlphas - 1) / 2; // potential problem if puts in type but not name
615 12 : if (mod(NumAlphas - 1, 2) != 0) {
616 0 : ++NumInList;
617 : }
618 12 : thisOutAirUnit.NumComponents = NumInList;
619 12 : thisOutAirUnit.OAEquip.allocate(NumInList);
620 :
621 : // Get information of component
622 51 : for (int InListNum = 1; InListNum <= NumInList; ++InListNum) {
623 39 : thisOutAirUnit.OAEquip(InListNum).ComponentName = AlphArray(InListNum * 2 + 1);
624 :
625 78 : thisOutAirUnit.OAEquip(InListNum).Type =
626 39 : static_cast<CompType>(getEnumValue(CompTypeNamesUC, Util::makeUPPER(AlphArray(InListNum * 2))));
627 :
628 39 : int const CompNum = InListNum;
629 :
630 : // Coil Types
631 39 : switch (thisOutAirUnit.OAEquip(InListNum).Type) {
632 6 : case CompType::WaterCoil_Cooling: {
633 6 : thisOutAirUnit.OAEquip(CompNum).CoilType = DataPlant::PlantEquipmentType::CoilWaterCooling;
634 12 : thisOutAirUnit.OAEquip(CompNum).ComponentIndex =
635 6 : GetWaterCoilIndex(state,
636 6 : CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
637 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
638 : ErrorsFound);
639 12 : thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
640 6 : WaterCoils::GetCoilInletNode(state,
641 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
642 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
643 : ErrorsFound);
644 12 : thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
645 6 : WaterCoils::GetCoilOutletNode(state,
646 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
647 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
648 : ErrorsFound);
649 12 : thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode =
650 6 : GetCoilWaterInletNode(state,
651 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
652 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
653 : ErrorsFound);
654 12 : thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
655 6 : GetCoilWaterOutletNode(state,
656 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
657 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
658 : ErrorsFound);
659 12 : thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow =
660 6 : WaterCoils::GetCoilMaxWaterFlowRate(state,
661 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
662 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
663 : ErrorsFound);
664 6 : thisOutAirUnit.OAEquip(CompNum).MinVolWaterFlow = 0.0;
665 6 : break;
666 : }
667 6 : case CompType::WaterCoil_SimpleHeat: {
668 6 : thisOutAirUnit.OAEquip(CompNum).CoilType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
669 12 : thisOutAirUnit.OAEquip(CompNum).ComponentIndex =
670 6 : GetWaterCoilIndex(state,
671 6 : CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
672 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
673 : ErrorsFound);
674 12 : thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
675 6 : WaterCoils::GetCoilInletNode(state,
676 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
677 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
678 : ErrorsFound);
679 6 : thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode = WaterCoils::GetCoilOutletNode(
680 6 : state, "Coil:Heating:Water", thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
681 12 : thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode =
682 6 : GetCoilWaterInletNode(state,
683 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
684 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
685 : ErrorsFound);
686 12 : thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
687 6 : GetCoilWaterOutletNode(state,
688 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
689 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
690 : ErrorsFound);
691 6 : thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow = WaterCoils::GetCoilMaxWaterFlowRate(
692 6 : state, "Coil:Heating:Water", thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
693 6 : thisOutAirUnit.OAEquip(CompNum).MinVolWaterFlow = 0.0;
694 6 : break;
695 : }
696 0 : case CompType::SteamCoil_AirHeat: {
697 0 : thisOutAirUnit.OAEquip(CompNum).CoilType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
698 0 : thisOutAirUnit.OAEquip(CompNum).ComponentIndex =
699 0 : GetSteamCoilIndex(state,
700 0 : CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
701 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
702 : ErrorsFound);
703 0 : thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode = GetCoilAirInletNode(
704 0 : state, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
705 0 : thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode = GetCoilAirOutletNode(
706 0 : state, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
707 0 : thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode = GetCoilSteamInletNode(
708 0 : state, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
709 0 : thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
710 0 : GetCoilSteamOutletNode(state,
711 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
712 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
713 : ErrorsFound);
714 :
715 0 : thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow =
716 0 : GetCoilMaxSteamFlowRate(state, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, ErrorsFound);
717 0 : thisOutAirUnit.OAEquip(CompNum).MinVolWaterFlow = 0.0;
718 : // below: no extra error needed if steam properties not in input
719 : // file because getting the steam coil will have done that.
720 0 : thisOutAirUnit.OAEquip(CompNum).FluidIndex = FluidProperties::GetRefrigNum(state, "STEAM");
721 0 : break;
722 : }
723 0 : case CompType::WaterCoil_DetailedCool: {
724 0 : thisOutAirUnit.OAEquip(CompNum).ComponentIndex =
725 0 : GetWaterCoilIndex(state,
726 0 : CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
727 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
728 : ErrorsFound);
729 0 : thisOutAirUnit.OAEquip(CompNum).CoilType = DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling;
730 0 : thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
731 0 : WaterCoils::GetCoilInletNode(state,
732 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
733 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
734 : ErrorsFound);
735 0 : thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
736 0 : WaterCoils::GetCoilOutletNode(state,
737 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
738 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
739 : ErrorsFound);
740 0 : thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode =
741 0 : GetCoilWaterInletNode(state,
742 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
743 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
744 : ErrorsFound);
745 0 : thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
746 0 : GetCoilWaterOutletNode(state,
747 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
748 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
749 : ErrorsFound);
750 0 : thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow =
751 0 : WaterCoils::GetCoilMaxWaterFlowRate(state,
752 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
753 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
754 : ErrorsFound);
755 0 : thisOutAirUnit.OAEquip(CompNum).MinVolWaterFlow = 0.0;
756 0 : break;
757 : }
758 0 : case CompType::WaterCoil_CoolingHXAsst: {
759 0 : thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
760 0 : HVACHXAssistedCoolingCoil::GetCoilInletNode(state,
761 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
762 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
763 : ErrorsFound);
764 0 : thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
765 0 : HVACHXAssistedCoolingCoil::GetCoilOutletNode(state,
766 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
767 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
768 : ErrorsFound);
769 0 : thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode =
770 0 : GetCoilWaterInletNode(state,
771 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
772 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
773 : ErrorsFound);
774 0 : thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
775 0 : GetCoilWaterOutletNode(state,
776 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
777 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
778 : ErrorsFound);
779 0 : thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow = HVACHXAssistedCoolingCoil::GetCoilMaxWaterFlowRate(
780 : state,
781 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
782 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
783 : ErrorsFound);
784 0 : thisOutAirUnit.OAEquip(CompNum).MinVolWaterFlow = 0.0;
785 0 : break;
786 : }
787 4 : case CompType::Coil_ElectricHeat: {
788 : // Get OutAirUnit( OAUnitNum ).OAEquip( CompNum ).ComponentIndex, 2 types of mining functions to choose from
789 4 : HeatingCoils::GetCoilIndex(
790 4 : state, thisOutAirUnit.OAEquip(CompNum).ComponentName, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, ErrorsFound);
791 8 : thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
792 4 : HeatingCoils::GetCoilInletNode(state,
793 4 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
794 4 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
795 : ErrorsFound);
796 8 : thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
797 4 : HeatingCoils::GetCoilOutletNode(state,
798 4 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
799 4 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
800 : ErrorsFound);
801 4 : break;
802 : }
803 2 : case CompType::Coil_GasHeat: {
804 : // Get OutAirUnit( OAUnitNum ).OAEquip( CompNum ).ComponentIndex, 2 types of mining functions to choose from
805 2 : HeatingCoils::GetCoilIndex(
806 2 : state, thisOutAirUnit.OAEquip(CompNum).ComponentName, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, ErrorsFound);
807 4 : thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
808 2 : GetCoilInletNode(state,
809 2 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
810 2 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
811 : ErrorsFound);
812 4 : thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
813 2 : GetCoilOutletNode(state,
814 2 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
815 2 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
816 : ErrorsFound);
817 2 : break;
818 : }
819 8 : case CompType::DXSystem: {
820 : // set the data for 100% DOAS DX cooling coil
821 : // is a different function call needed here? similar to one in HVACDXSystem
822 : // CheckDXCoolingCoilInOASysExists(state, thisOutAirUnit.OAEquip(CompNum).ComponentName);
823 8 : break;
824 : }
825 1 : case CompType::DXHeatPumpSystem: {
826 1 : break;
827 : }
828 0 : case CompType::UnitarySystemModel: {
829 0 : UnitarySystems::UnitarySys thisSys;
830 0 : thisOutAirUnit.OAEquip(CompNum).compPointer = thisSys.factory(
831 0 : state, HVAC::UnitarySysType::Unitary_AnyCoilType, thisOutAirUnit.OAEquip(CompNum).ComponentName, false, OAUnitNum);
832 0 : UnitarySystems::UnitarySys::checkUnitarySysCoilInOASysExists(
833 0 : state, thisOutAirUnit.OAEquip(CompNum).ComponentName, OAUnitNum);
834 :
835 : // Heat recovery
836 0 : break;
837 0 : }
838 10 : case CompType::HeatXchngrFP:
839 : case CompType::HeatXchngrSL: {
840 : // CASE('HEATEXCHANGER:DESICCANT:BALANCEDFLOW')
841 : // thisOutAirUnit%OAEquip(CompNum)%Type= CompType::HeatXchngr
842 :
843 : // Desiccant Dehumidifier
844 10 : break;
845 : }
846 2 : case CompType::Desiccant: {
847 : // Futher Enhancement
848 : // CASE('DEHUMIDIFIER:DESICCANT:SYSTEM')
849 : // thisOutAirUnit%OAEquip(CompNum)%Type= CompType::Desiccant
850 2 : break;
851 : }
852 0 : default: {
853 0 : ShowSevereError(state,
854 0 : format("{}= \"{}\" invalid Outside Air Component=\"{}\".",
855 : CurrentModuleObject,
856 : AlphArray(1),
857 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)]));
858 0 : ErrorsFound = true;
859 : }
860 : }
861 :
862 : // Add equipment to component sets array
863 : // Node set up
864 39 : if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::BlowThru) {
865 22 : if (InListNum == 1) { // the component is the first one
866 12 : SetUpCompSets(state,
867 : "ZoneHVAC:OutdoorAirUnit",
868 : thisOutAirUnit.Name,
869 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
870 6 : thisOutAirUnit.OAEquip(InListNum).ComponentName,
871 6 : state.dataIPShortCut->cAlphaArgs(15),
872 : "UNDEFINED");
873 16 : } else if (InListNum != NumInList) { // the component is placed in b/w components
874 20 : SetUpCompSets(state,
875 : "ZoneHVAC:OutdoorAirUnit",
876 : thisOutAirUnit.Name,
877 10 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
878 10 : thisOutAirUnit.OAEquip(InListNum).ComponentName,
879 : "UNDEFINED",
880 : "UNDEFINED");
881 : } else { // (InListNum == NumInList) => the component is the last one
882 18 : SetUpCompSets(state,
883 : "ZoneHVAC:OutdoorAirUnit",
884 : thisOutAirUnit.Name,
885 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
886 6 : thisOutAirUnit.OAEquip(InListNum).ComponentName,
887 : "UNDEFINED",
888 6 : state.dataIPShortCut->cAlphaArgs(13));
889 : }
890 : // If fan is on the end of equipment.
891 17 : } else if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
892 17 : if (InListNum == 1) {
893 12 : SetUpCompSets(state,
894 : "ZoneHVAC:OutdoorAirUnit",
895 : thisOutAirUnit.Name,
896 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
897 6 : thisOutAirUnit.OAEquip(InListNum).ComponentName,
898 6 : state.dataIPShortCut->cAlphaArgs(12),
899 : "UNDEFINED");
900 11 : } else if (InListNum != NumInList) {
901 10 : SetUpCompSets(state,
902 : "ZoneHVAC:OutdoorAirUnit",
903 : thisOutAirUnit.Name,
904 5 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
905 5 : thisOutAirUnit.OAEquip(InListNum).ComponentName,
906 : "UNDEFINED",
907 : "UNDEFINED");
908 : } else { // (InListNum == NumInList) => the component is the last one
909 12 : SetUpCompSets(state,
910 : "ZoneHVAC:OutdoorAirUnit",
911 : thisOutAirUnit.Name,
912 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
913 6 : thisOutAirUnit.OAEquip(InListNum).ComponentName,
914 : "UNDEFINED",
915 : "UNDEFINED");
916 : }
917 : }
918 : // Must call after SetUpCompSets since this will add another CoilSystem:Cooling:DX object in CompSets
919 39 : if (CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)] == "COILSYSTEM:COOLING:DX") {
920 8 : UnitarySystems::UnitarySys::checkUnitarySysCoilInOASysExists(
921 8 : state, thisOutAirUnit.OAEquip(CompNum).ComponentName, OAUnitNum);
922 : }
923 : } // End Inlist
924 :
925 : // In case of draw through, the last component is linked with the zone air supply node
926 12 : if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
927 18 : SetUpCompSets(state,
928 : CurrentModuleObject,
929 : thisOutAirUnit.Name,
930 : "UNDEFINED",
931 6 : state.dataIPShortCut->cAlphaArgs(5),
932 : "UNDEFINED",
933 6 : state.dataIPShortCut->cAlphaArgs(13));
934 : }
935 :
936 : } else { // when ListNum<0
937 0 : ShowSevereError(state,
938 0 : format("{} = \"{}\" invalid {}=\"{}\" not found.",
939 : CurrentModuleObject,
940 0 : state.dataIPShortCut->cAlphaArgs(1),
941 : cAlphaFields(16),
942 0 : state.dataIPShortCut->cAlphaArgs(16)));
943 0 : ErrorsFound = true;
944 : }
945 : } else { // when Equipment list is left blanked
946 0 : ShowSevereError(state,
947 0 : format("{} = \"{}\" invalid {} is blank and must be entered.",
948 : CurrentModuleObject,
949 0 : state.dataIPShortCut->cAlphaArgs(1),
950 : cAlphaFields(16)));
951 0 : ErrorsFound = true;
952 : }
953 12 : if (!lAlphaBlanks(17)) {
954 0 : thisOutAirUnit.AvailManagerListName = state.dataIPShortCut->cAlphaArgs(17);
955 : }
956 : }
957 :
958 2 : if (ErrorsFound) {
959 0 : ShowFatalError(state, format("{}Errors found in getting {}.", RoutineName, CurrentModuleObject));
960 : }
961 :
962 2 : AlphArray.deallocate();
963 2 : cAlphaFields.deallocate();
964 2 : NumArray.deallocate();
965 2 : cNumericFields.deallocate();
966 2 : lAlphaBlanks.deallocate();
967 2 : lNumericBlanks.deallocate();
968 :
969 2 : state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
970 :
971 : // Setup Report variables for the zone outdoor air unit CurrentModuleObject='ZoneHVAC:OutdoorAirUnit'
972 14 : for (int OAUnitNum = 1; OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits; ++OAUnitNum) {
973 :
974 12 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
975 :
976 24 : SetupOutputVariable(state,
977 : "Zone Outdoor Air Unit Total Heating Rate",
978 : Constant::Units::W,
979 12 : thisOutAirUnit.TotHeatingRate,
980 : OutputProcessor::TimeStepType::System,
981 : OutputProcessor::StoreType::Average,
982 12 : thisOutAirUnit.Name);
983 24 : SetupOutputVariable(state,
984 : "Zone Outdoor Air Unit Total Heating Energy",
985 : Constant::Units::J,
986 12 : thisOutAirUnit.TotHeatingEnergy,
987 : OutputProcessor::TimeStepType::System,
988 : OutputProcessor::StoreType::Sum,
989 12 : thisOutAirUnit.Name);
990 24 : SetupOutputVariable(state,
991 : "Zone Outdoor Air Unit Sensible Heating Rate",
992 : Constant::Units::W,
993 12 : thisOutAirUnit.SensHeatingRate,
994 : OutputProcessor::TimeStepType::System,
995 : OutputProcessor::StoreType::Average,
996 12 : thisOutAirUnit.Name);
997 24 : SetupOutputVariable(state,
998 : "Zone Outdoor Air Unit Sensible Heating Energy",
999 : Constant::Units::J,
1000 12 : thisOutAirUnit.SensHeatingEnergy,
1001 : OutputProcessor::TimeStepType::System,
1002 : OutputProcessor::StoreType::Sum,
1003 12 : thisOutAirUnit.Name);
1004 24 : SetupOutputVariable(state,
1005 : "Zone Outdoor Air Unit Latent Heating Rate",
1006 : Constant::Units::W,
1007 12 : thisOutAirUnit.LatHeatingRate,
1008 : OutputProcessor::TimeStepType::System,
1009 : OutputProcessor::StoreType::Average,
1010 12 : thisOutAirUnit.Name);
1011 24 : SetupOutputVariable(state,
1012 : "Zone Outdoor Air Unit Latent Heating Energy",
1013 : Constant::Units::J,
1014 12 : thisOutAirUnit.LatHeatingEnergy,
1015 : OutputProcessor::TimeStepType::System,
1016 : OutputProcessor::StoreType::Sum,
1017 12 : thisOutAirUnit.Name);
1018 24 : SetupOutputVariable(state,
1019 : "Zone Outdoor Air Unit Total Cooling Rate",
1020 : Constant::Units::W,
1021 12 : thisOutAirUnit.TotCoolingRate,
1022 : OutputProcessor::TimeStepType::System,
1023 : OutputProcessor::StoreType::Average,
1024 12 : thisOutAirUnit.Name);
1025 24 : SetupOutputVariable(state,
1026 : "Zone Outdoor Air Unit Total Cooling Energy",
1027 : Constant::Units::J,
1028 12 : thisOutAirUnit.TotCoolingEnergy,
1029 : OutputProcessor::TimeStepType::System,
1030 : OutputProcessor::StoreType::Sum,
1031 12 : thisOutAirUnit.Name);
1032 24 : SetupOutputVariable(state,
1033 : "Zone Outdoor Air Unit Sensible Cooling Rate",
1034 : Constant::Units::W,
1035 12 : thisOutAirUnit.SensCoolingRate,
1036 : OutputProcessor::TimeStepType::System,
1037 : OutputProcessor::StoreType::Average,
1038 12 : thisOutAirUnit.Name);
1039 24 : SetupOutputVariable(state,
1040 : "Zone Outdoor Air Unit Sensible Cooling Energy",
1041 : Constant::Units::J,
1042 12 : thisOutAirUnit.SensCoolingEnergy,
1043 : OutputProcessor::TimeStepType::System,
1044 : OutputProcessor::StoreType::Sum,
1045 12 : thisOutAirUnit.Name);
1046 24 : SetupOutputVariable(state,
1047 : "Zone Outdoor Air Unit Latent Cooling Rate",
1048 : Constant::Units::W,
1049 12 : thisOutAirUnit.LatCoolingRate,
1050 : OutputProcessor::TimeStepType::System,
1051 : OutputProcessor::StoreType::Average,
1052 12 : thisOutAirUnit.Name);
1053 24 : SetupOutputVariable(state,
1054 : "Zone Outdoor Air Unit Latent Cooling Energy",
1055 : Constant::Units::J,
1056 12 : thisOutAirUnit.LatCoolingEnergy,
1057 : OutputProcessor::TimeStepType::System,
1058 : OutputProcessor::StoreType::Sum,
1059 12 : thisOutAirUnit.Name);
1060 24 : SetupOutputVariable(state,
1061 : "Zone Outdoor Air Unit Air Mass Flow Rate",
1062 : Constant::Units::kg_s,
1063 12 : thisOutAirUnit.AirMassFlow,
1064 : OutputProcessor::TimeStepType::System,
1065 : OutputProcessor::StoreType::Average,
1066 12 : thisOutAirUnit.Name);
1067 24 : SetupOutputVariable(state,
1068 : "Zone Outdoor Air Unit Fan Electricity Rate",
1069 : Constant::Units::W,
1070 12 : thisOutAirUnit.ElecFanRate,
1071 : OutputProcessor::TimeStepType::System,
1072 : OutputProcessor::StoreType::Average,
1073 12 : thisOutAirUnit.Name);
1074 24 : SetupOutputVariable(state,
1075 : "Zone Outdoor Air Unit Fan Electricity Energy",
1076 : Constant::Units::J,
1077 12 : thisOutAirUnit.ElecFanEnergy,
1078 : OutputProcessor::TimeStepType::System,
1079 : OutputProcessor::StoreType::Sum,
1080 12 : thisOutAirUnit.Name);
1081 12 : SetupOutputVariable(state,
1082 : "Zone Outdoor Air Unit Fan Availability Status",
1083 : Constant::Units::None,
1084 12 : (int &)thisOutAirUnit.availStatus,
1085 : OutputProcessor::TimeStepType::System,
1086 : OutputProcessor::StoreType::Average,
1087 12 : thisOutAirUnit.Name);
1088 : //! Note that the outdoor air unit fan electric is NOT metered because this value is already metered through the fan component
1089 : }
1090 2 : }
1091 :
1092 64806 : void InitOutdoorAirUnit(EnergyPlusData &state,
1093 : int const OAUnitNum, // index for the current outdoor air unit
1094 : int const ZoneNum, // number of zone being served
1095 : bool const FirstHVACIteration // TRUE if 1st HVAC simulation of system timestep
1096 : )
1097 : {
1098 :
1099 : // SUBROUTINE INFORMATION:
1100 : // AUTHOR Young Tae Chae, Rick Strand
1101 : // DATE WRITTEN July 2009
1102 : // MODIFIED July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
1103 : // RE-ENGINEERED na
1104 :
1105 : // PURPOSE OF THIS SUBROUTINE:
1106 : // This subroutine initializes all of the data elements which are necessary
1107 : // to simulate a zone outdoor air control unit.
1108 :
1109 : // METHODOLOGY EMPLOYED:
1110 : // Uses the status flags to trigger initializations.
1111 :
1112 : // REFERENCES:
1113 : // na
1114 :
1115 : // Using/Aliasing
1116 : using DataZoneEquipment::CheckZoneEquipmentList;
1117 : using FluidProperties::GetDensityGlycol;
1118 : using HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil;
1119 : using PlantUtilities::InitComponentNodes;
1120 : using PlantUtilities::ScanPlantLoopsForObject;
1121 : using ScheduleManager::GetCurrentScheduleValue;
1122 : using SteamCoils::GetCoilMaxSteamFlowRate;
1123 : using WaterCoils::SimulateWaterCoilComponents;
1124 :
1125 : // SUBROUTINE PARAMETER DEFINITIONS:
1126 : static constexpr std::string_view CurrentModuleObject("ZoneHVAC:OutdoorAirUnit");
1127 : static constexpr std::string_view RoutineName("SizeOutdoorAirUnit");
1128 :
1129 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1130 : // Do the one time initializations
1131 :
1132 64806 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
1133 :
1134 64806 : Real64 const RhoAir = state.dataEnvrn->StdRhoAir;
1135 64806 : int const InNode = thisOutAirUnit.AirInletNode;
1136 64806 : int const OutNode = thisOutAirUnit.AirOutletNode;
1137 64806 : int const OutsideAirNode = thisOutAirUnit.OutsideAirNode;
1138 64806 : Real64 const OAFrac = GetCurrentScheduleValue(state, thisOutAirUnit.OutAirSchedPtr);
1139 :
1140 64806 : if (state.dataOutdoorAirUnit->MyOneTimeFlag) {
1141 :
1142 2 : state.dataOutdoorAirUnit->MyEnvrnFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
1143 2 : state.dataOutdoorAirUnit->MySizeFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
1144 2 : state.dataOutdoorAirUnit->MyPlantScanFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
1145 2 : state.dataOutdoorAirUnit->MyZoneEqFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
1146 2 : state.dataOutdoorAirUnit->MyOneTimeFlag = false;
1147 : }
1148 :
1149 64806 : if (allocated(state.dataAvail->ZoneComp)) {
1150 64806 : auto &availMgr = state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::OutdoorAirUnit).ZoneCompAvailMgrs(OAUnitNum);
1151 64806 : if (state.dataOutdoorAirUnit->MyZoneEqFlag(OAUnitNum)) { // initialize the name of each availability manager list and zone number
1152 12 : availMgr.AvailManagerListName = thisOutAirUnit.AvailManagerListName;
1153 12 : availMgr.ZoneNum = ZoneNum;
1154 12 : state.dataOutdoorAirUnit->MyZoneEqFlag(OAUnitNum) = false;
1155 : }
1156 64806 : thisOutAirUnit.availStatus = availMgr.availStatus;
1157 : }
1158 :
1159 64806 : if (state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum) && allocated(state.dataPlnt->PlantLoop)) {
1160 51 : for (int compLoop = 1; compLoop <= thisOutAirUnit.NumComponents; ++compLoop) {
1161 :
1162 39 : CompType const Type = thisOutAirUnit.OAEquip(compLoop).Type;
1163 :
1164 39 : switch (Type) {
1165 12 : case CompType::WaterCoil_Cooling:
1166 : case CompType::WaterCoil_DetailedCool:
1167 : case CompType::WaterCoil_SimpleHeat:
1168 : case CompType::SteamCoil_AirHeat:
1169 :
1170 : {
1171 12 : bool errFlag = false;
1172 24 : ScanPlantLoopsForObject(state,
1173 12 : thisOutAirUnit.OAEquip(compLoop).ComponentName,
1174 12 : thisOutAirUnit.OAEquip(compLoop).CoilType,
1175 12 : thisOutAirUnit.OAEquip(compLoop).plantLoc,
1176 : errFlag,
1177 : _,
1178 : _,
1179 : _,
1180 : _,
1181 : _);
1182 12 : if (errFlag) {
1183 0 : ShowFatalError(state, "InitOutdoorAirUnit: Program terminated for previous conditions.");
1184 : }
1185 12 : break;
1186 : }
1187 27 : default:
1188 27 : break;
1189 : }
1190 : }
1191 :
1192 12 : state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum) = false;
1193 64794 : } else if (state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum) && !state.dataGlobal->AnyPlantInModel) {
1194 0 : state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum) = false;
1195 : }
1196 :
1197 : // need to check all zone outdoor air control units to see if they are on Zone Equipment List or issue warning
1198 64806 : if (!state.dataOutdoorAirUnit->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
1199 2 : state.dataOutdoorAirUnit->ZoneEquipmentListChecked = true;
1200 14 : for (int Loop = 1; Loop <= state.dataOutdoorAirUnit->NumOfOAUnits; ++Loop) {
1201 12 : if (CheckZoneEquipmentList(state, CurrentModuleObject, state.dataOutdoorAirUnit->OutAirUnit(Loop).Name)) {
1202 12 : continue;
1203 : }
1204 0 : ShowSevereError(
1205 : state,
1206 0 : format("InitOutdoorAirUnit: Zone Outdoor Air Unit=[{},{}] is not on any ZoneHVAC:EquipmentList. It will not be simulated.",
1207 : CurrentModuleObject,
1208 0 : state.dataOutdoorAirUnit->OutAirUnit(Loop).Name));
1209 : }
1210 : }
1211 :
1212 64818 : if (!state.dataGlobal->SysSizingCalc && state.dataOutdoorAirUnit->MySizeFlag(OAUnitNum) &&
1213 12 : !state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum)) {
1214 :
1215 12 : SizeOutdoorAirUnit(state, OAUnitNum);
1216 :
1217 12 : state.dataOutdoorAirUnit->MySizeFlag(OAUnitNum) = false;
1218 : }
1219 :
1220 : // Do the one time initializations
1221 64806 : if (state.dataGlobal->BeginEnvrnFlag && state.dataOutdoorAirUnit->MyEnvrnFlag(OAUnitNum)) {
1222 : // Node Conditions
1223 72 : thisOutAirUnit.OutAirMassFlow = RhoAir * OAFrac * thisOutAirUnit.OutAirVolFlow;
1224 72 : thisOutAirUnit.SMaxAirMassFlow = RhoAir * OAFrac * thisOutAirUnit.SFanMaxAirVolFlow;
1225 :
1226 72 : if (thisOutAirUnit.ExtFan) {
1227 : // set the exhaust air mass flow rate from input
1228 72 : Real64 const EAFrac = GetCurrentScheduleValue(state, thisOutAirUnit.ExtOutAirSchedPtr);
1229 72 : thisOutAirUnit.ExtAirMassFlow = RhoAir * EAFrac * thisOutAirUnit.ExtAirVolFlow;
1230 72 : thisOutAirUnit.EMaxAirMassFlow = RhoAir * EAFrac * thisOutAirUnit.EFanMaxAirVolFlow;
1231 :
1232 72 : state.dataLoopNodes->Node(InNode).MassFlowRateMax = thisOutAirUnit.EMaxAirMassFlow;
1233 72 : state.dataLoopNodes->Node(InNode).MassFlowRateMin = 0.0;
1234 : }
1235 : // set the node max and min mass flow rates
1236 72 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMax = thisOutAirUnit.SMaxAirMassFlow;
1237 72 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMin = 0.0;
1238 72 : state.dataLoopNodes->Node(OutNode).MassFlowRate = thisOutAirUnit.EMaxAirMassFlow;
1239 :
1240 72 : if (!state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum)) {
1241 72 : bool errFlag = false;
1242 306 : for (int compLoop = 1; compLoop <= thisOutAirUnit.NumComponents; ++compLoop) {
1243 432 : if ((thisOutAirUnit.OAEquip(compLoop).Type == CompType::WaterCoil_Cooling) ||
1244 198 : (thisOutAirUnit.OAEquip(compLoop).Type == CompType::WaterCoil_DetailedCool)) {
1245 72 : thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow =
1246 36 : WaterCoils::GetCoilMaxWaterFlowRate(state,
1247 36 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(compLoop).Type)],
1248 36 : thisOutAirUnit.OAEquip(compLoop).ComponentName,
1249 : errFlag);
1250 36 : Real64 const rho = GetDensityGlycol(state,
1251 36 : state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum).FluidName,
1252 : Constant::CWInitConvTemp,
1253 36 : state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum).FluidIndex,
1254 : RoutineName);
1255 36 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow;
1256 36 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MinVolWaterFlow;
1257 144 : InitComponentNodes(state,
1258 36 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow,
1259 36 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow,
1260 36 : thisOutAirUnit.OAEquip(compLoop).CoilWaterInletNode,
1261 36 : thisOutAirUnit.OAEquip(compLoop).CoilWaterOutletNode);
1262 : }
1263 :
1264 234 : if (thisOutAirUnit.OAEquip(compLoop).Type == CompType::WaterCoil_SimpleHeat) {
1265 72 : thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow =
1266 36 : WaterCoils::GetCoilMaxWaterFlowRate(state,
1267 36 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(compLoop).Type)],
1268 36 : thisOutAirUnit.OAEquip(compLoop).ComponentName,
1269 : errFlag);
1270 36 : Real64 const rho = GetDensityGlycol(state,
1271 36 : state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum).FluidName,
1272 : Constant::HWInitConvTemp,
1273 36 : state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum).FluidIndex,
1274 : RoutineName);
1275 36 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow;
1276 36 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MinVolWaterFlow;
1277 144 : InitComponentNodes(state,
1278 36 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow,
1279 36 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow,
1280 36 : thisOutAirUnit.OAEquip(compLoop).CoilWaterInletNode,
1281 36 : thisOutAirUnit.OAEquip(compLoop).CoilWaterOutletNode);
1282 : }
1283 234 : if (thisOutAirUnit.OAEquip(compLoop).Type == CompType::SteamCoil_AirHeat) {
1284 0 : thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow =
1285 0 : GetCoilMaxSteamFlowRate(state, thisOutAirUnit.OAEquip(compLoop).ComponentIndex, errFlag);
1286 0 : Real64 const rho = FluidProperties::GetSatDensityRefrig(
1287 : state,
1288 0 : state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum).FluidName,
1289 : Constant::SteamInitConvTemp,
1290 : 1.0,
1291 0 : state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum).FluidIndex,
1292 : RoutineName);
1293 0 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow;
1294 0 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MinVolWaterFlow;
1295 0 : InitComponentNodes(state,
1296 0 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow,
1297 0 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow,
1298 0 : thisOutAirUnit.OAEquip(compLoop).CoilWaterInletNode,
1299 0 : thisOutAirUnit.OAEquip(compLoop).CoilWaterOutletNode);
1300 : }
1301 234 : if (thisOutAirUnit.OAEquip(compLoop).Type == CompType::WaterCoil_CoolingHXAsst) {
1302 0 : thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow =
1303 0 : WaterCoils::GetCoilMaxWaterFlowRate(state,
1304 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(compLoop).Type)],
1305 0 : thisOutAirUnit.OAEquip(compLoop).ComponentName,
1306 : errFlag);
1307 0 : Real64 const rho = GetDensityGlycol(state,
1308 0 : state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum).FluidName,
1309 : Constant::CWInitConvTemp,
1310 0 : state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum).FluidIndex,
1311 : RoutineName);
1312 0 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow;
1313 0 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MinVolWaterFlow;
1314 0 : InitComponentNodes(state,
1315 0 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow,
1316 0 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow,
1317 0 : thisOutAirUnit.OAEquip(compLoop).CoilWaterInletNode,
1318 0 : thisOutAirUnit.OAEquip(compLoop).CoilWaterOutletNode);
1319 : }
1320 : }
1321 : }
1322 72 : state.dataOutdoorAirUnit->MyEnvrnFlag(OAUnitNum) = false;
1323 :
1324 : } // ...end start of environment inits
1325 :
1326 64806 : if (!state.dataGlobal->BeginEnvrnFlag) {
1327 63816 : state.dataOutdoorAirUnit->MyEnvrnFlag(OAUnitNum) = true;
1328 : }
1329 :
1330 : // These initializations are done every iteration...
1331 : // Set all the output variable
1332 64806 : thisOutAirUnit.TotHeatingRate = 0.0;
1333 64806 : thisOutAirUnit.SensHeatingRate = 0.0;
1334 64806 : thisOutAirUnit.LatHeatingRate = 0.0;
1335 64806 : thisOutAirUnit.TotCoolingRate = 0.0;
1336 64806 : thisOutAirUnit.SensCoolingRate = 0.0;
1337 64806 : thisOutAirUnit.LatCoolingRate = 0.0;
1338 64806 : thisOutAirUnit.AirMassFlow = 0.0;
1339 64806 : thisOutAirUnit.ElecFanRate = 0.0;
1340 : // Node Set
1341 :
1342 : // set the mass flow rates from the input volume flow rates
1343 64806 : if (OAFrac > 0.0 || (state.dataHVACGlobal->TurnFansOn && !state.dataHVACGlobal->TurnFansOff)) { // fan is available
1344 63524 : thisOutAirUnit.OutAirMassFlow = RhoAir * OAFrac * thisOutAirUnit.OutAirVolFlow;
1345 : } else {
1346 1282 : thisOutAirUnit.OutAirMassFlow = 0.0;
1347 : }
1348 :
1349 : // set the exhaust air mass flow rate from input
1350 64806 : if (thisOutAirUnit.ExtFan) {
1351 64806 : Real64 const EAFrac = GetCurrentScheduleValue(state, thisOutAirUnit.ExtOutAirSchedPtr);
1352 64806 : if (thisOutAirUnit.ExtFanAvailSchedPtr > 0.0) {
1353 64806 : thisOutAirUnit.ExtAirMassFlow = RhoAir * EAFrac * thisOutAirUnit.ExtAirVolFlow;
1354 : } else {
1355 0 : thisOutAirUnit.ExtAirMassFlow = 0.0;
1356 : }
1357 64806 : state.dataLoopNodes->Node(InNode).MassFlowRate = thisOutAirUnit.ExtAirMassFlow;
1358 64806 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail = thisOutAirUnit.ExtAirMassFlow;
1359 64806 : state.dataLoopNodes->Node(InNode).MassFlowRateMinAvail = 0.0;
1360 0 : } else if (!thisOutAirUnit.ExtFan) {
1361 0 : thisOutAirUnit.ExtAirMassFlow = 0.0;
1362 : }
1363 :
1364 : // First, set the flow conditions up so that there is flow through the unit
1365 :
1366 64806 : state.dataLoopNodes->Node(OutNode).MassFlowRate = thisOutAirUnit.OutAirMassFlow;
1367 64806 : state.dataLoopNodes->Node(OutNode).MassFlowRateMaxAvail = thisOutAirUnit.OutAirMassFlow;
1368 64806 : state.dataLoopNodes->Node(OutNode).MassFlowRateMinAvail = 0.0;
1369 64806 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = thisOutAirUnit.OutAirMassFlow;
1370 64806 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMaxAvail = thisOutAirUnit.OutAirMassFlow;
1371 64806 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMinAvail = 0.0;
1372 :
1373 : // Just in case the system is off and conditions do not get sent through
1374 : // the system for some reason, set the outlet conditions equal to the inlet
1375 : // conditions of the zone outdoor air control unit
1376 64806 : if (thisOutAirUnit.ExtFan) {
1377 64806 : state.dataLoopNodes->Node(OutNode).Temp = state.dataLoopNodes->Node(InNode).Temp;
1378 64806 : state.dataLoopNodes->Node(OutNode).Press = state.dataLoopNodes->Node(InNode).Press;
1379 64806 : state.dataLoopNodes->Node(OutNode).HumRat = state.dataLoopNodes->Node(InNode).HumRat;
1380 64806 : state.dataLoopNodes->Node(OutNode).Enthalpy = state.dataLoopNodes->Node(InNode).Enthalpy;
1381 : } else {
1382 0 : state.dataLoopNodes->Node(OutNode).Temp = state.dataLoopNodes->Node(OutsideAirNode).Temp;
1383 0 : state.dataLoopNodes->Node(OutNode).Press = state.dataLoopNodes->Node(OutsideAirNode).Press;
1384 0 : state.dataLoopNodes->Node(OutNode).HumRat = state.dataLoopNodes->Node(OutsideAirNode).HumRat;
1385 0 : state.dataLoopNodes->Node(OutNode).Enthalpy = state.dataLoopNodes->Node(OutsideAirNode).Enthalpy;
1386 : }
1387 : // These initializations only need to be done once at the start of the iterations...
1388 64806 : if (FirstHVACIteration || state.dataHVACGlobal->ShortenTimeStepSys) {
1389 : // Initialize the outside air conditions...
1390 37602 : state.dataLoopNodes->Node(OutsideAirNode).Temp = state.dataLoopNodes->Node(OutsideAirNode).OutAirDryBulb;
1391 37602 : state.dataLoopNodes->Node(OutsideAirNode).HumRat = state.dataEnvrn->OutHumRat;
1392 37602 : state.dataLoopNodes->Node(OutsideAirNode).Press = state.dataEnvrn->OutBaroPress;
1393 : }
1394 64806 : }
1395 :
1396 12 : void SizeOutdoorAirUnit(EnergyPlusData &state, int const OAUnitNum)
1397 : {
1398 :
1399 : // SUBROUTINE INFORMATION:
1400 : // AUTHOR Young Tae Chae, Rick Strand
1401 : // DATE WRITTEN July 2009
1402 : // MODIFIED Brent Griffith, March 2010, autosize OA flow rate
1403 : // August 2013 Daeho Kang, add component sizing table entries
1404 : // RE-ENGINEERED na
1405 :
1406 : // PURPOSE OF THIS SUBROUTINE:
1407 : // This subroutine is for sizing zoen outdoor air control unit components for which flow rates have not been
1408 : // specified in the input.
1409 :
1410 : // METHODOLOGY EMPLOYED:
1411 : // Obtains flow rates from the zone sizing arrays and plant sizing data.
1412 :
1413 : // Using/Aliasing
1414 : using namespace DataSizing;
1415 :
1416 : using HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil;
1417 : using PlantUtilities::MyPlantSizingIndex;
1418 : using SteamCoils::SimulateSteamCoilComponents;
1419 : using WaterCoils::SimulateWaterCoilComponents;
1420 :
1421 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1422 12 : bool IsAutoSize = false; // Indicator to autosize
1423 12 : Real64 OutAirVolFlowDes = 0.0; // Autosized outdoor air flow for reporting
1424 12 : Real64 OutAirVolFlowUser = 0.0; // Hardsized outdoor air flow for reporting
1425 12 : Real64 ExtAirVolFlowDes = 0.0; // Autosized exhaust air flow for reporting
1426 12 : Real64 ExtAirVolFlowUser = 0.0; // Hardsized exhaust air flow for reporting
1427 :
1428 12 : bool ErrorsFound = false;
1429 :
1430 12 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
1431 :
1432 12 : state.dataSize->DataFanType = thisOutAirUnit.supFanType;
1433 12 : state.dataSize->DataFanIndex = thisOutAirUnit.SFan_Index;
1434 12 : state.dataSize->DataFanPlacement = thisOutAirUnit.supFanPlace;
1435 :
1436 12 : if (thisOutAirUnit.OutAirVolFlow == AutoSize) {
1437 5 : IsAutoSize = true;
1438 : }
1439 :
1440 12 : if (state.dataSize->CurZoneEqNum > 0) {
1441 12 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
1442 0 : if (thisOutAirUnit.OutAirVolFlow > 0.0) {
1443 0 : BaseSizer::reportSizerOutput(
1444 : state, ZoneHVACOAUnit, thisOutAirUnit.Name, "User-Specified Outdoor Air Flow Rate [m3/s]", thisOutAirUnit.OutAirVolFlow);
1445 : }
1446 : } else {
1447 12 : CheckZoneSizing(state, std::string(ZoneHVACOAUnit), thisOutAirUnit.Name);
1448 12 : OutAirVolFlowDes = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
1449 12 : if (OutAirVolFlowDes < SmallAirVolFlow) {
1450 0 : OutAirVolFlowDes = 0.0;
1451 : }
1452 12 : if (IsAutoSize) {
1453 5 : thisOutAirUnit.OutAirVolFlow = OutAirVolFlowDes;
1454 5 : BaseSizer::reportSizerOutput(
1455 : state, ZoneHVACOAUnit, thisOutAirUnit.Name, "Design Size Outdoor Air Flow Rate [m3/s]", OutAirVolFlowDes);
1456 : } else {
1457 7 : if (thisOutAirUnit.OutAirVolFlow > 0.0 && OutAirVolFlowDes > 0.0) {
1458 7 : OutAirVolFlowUser = thisOutAirUnit.OutAirVolFlow;
1459 7 : BaseSizer::reportSizerOutput(
1460 : state, ZoneHVACOAUnit, thisOutAirUnit.Name, "User-Specified Outdoor Air Flow Rate [m3/s]", OutAirVolFlowUser);
1461 7 : if (state.dataGlobal->DisplayExtraWarnings) {
1462 0 : if ((std::abs(OutAirVolFlowDes - OutAirVolFlowUser) / OutAirVolFlowUser) > state.dataSize->AutoVsHardSizingThreshold) {
1463 0 : BaseSizer::reportSizerOutput(
1464 : state, ZoneHVACOAUnit, thisOutAirUnit.Name, "Design Size Outdoor Air Flow Rate [m3/s]", OutAirVolFlowDes);
1465 0 : ShowMessage(state,
1466 0 : format("SizeOutdoorAirUnit: Potential issue with equipment sizing for ZoneHVAC:OutdoorAirUnit {}",
1467 0 : thisOutAirUnit.Name));
1468 0 : ShowContinueError(state, format("User-Specified Outdoor Air Flow Rate of {:.5R} [m3/s]", OutAirVolFlowUser));
1469 0 : ShowContinueError(state, format("differs from Design Size Outdoor Air Flow Rate of {:.5R} [m3/s]", OutAirVolFlowDes));
1470 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1471 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1472 : }
1473 : }
1474 : }
1475 : }
1476 : }
1477 : }
1478 :
1479 12 : IsAutoSize = false;
1480 12 : if (thisOutAirUnit.ExtAirVolFlow == AutoSize) {
1481 5 : IsAutoSize = true;
1482 : }
1483 12 : if (state.dataSize->CurZoneEqNum > 0) {
1484 12 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
1485 0 : if (thisOutAirUnit.ExtAirVolFlow > 0.0) {
1486 0 : BaseSizer::reportSizerOutput(
1487 : state, ZoneHVACOAUnit, thisOutAirUnit.Name, "User-Specified Exhaust Air Flow Rate [m3/s]", thisOutAirUnit.ExtAirVolFlow);
1488 : }
1489 : } else {
1490 : // set exhaust flow equal to the oa inlet flow
1491 12 : ExtAirVolFlowDes = thisOutAirUnit.OutAirVolFlow;
1492 12 : if (IsAutoSize) {
1493 5 : thisOutAirUnit.ExtAirVolFlow = ExtAirVolFlowDes;
1494 5 : BaseSizer::reportSizerOutput(
1495 : state, ZoneHVACOAUnit, thisOutAirUnit.Name, "Design Size Exhaust Air Flow Rate [m3/s]", ExtAirVolFlowDes);
1496 : } else {
1497 7 : if (thisOutAirUnit.ExtAirVolFlow > 0.0 && ExtAirVolFlowDes > 0.0) {
1498 7 : ExtAirVolFlowUser = thisOutAirUnit.ExtAirVolFlow;
1499 7 : BaseSizer::reportSizerOutput(
1500 : state, ZoneHVACOAUnit, thisOutAirUnit.Name, "User-Specified Exhaust Air Flow Rate [m3/s]", ExtAirVolFlowUser);
1501 7 : if (state.dataGlobal->DisplayExtraWarnings) {
1502 0 : if ((std::abs(ExtAirVolFlowDes - ExtAirVolFlowUser) / ExtAirVolFlowUser) > state.dataSize->AutoVsHardSizingThreshold) {
1503 0 : BaseSizer::reportSizerOutput(
1504 : state, ZoneHVACOAUnit, thisOutAirUnit.Name, "Design Size Exhaust Air Flow Rate [m3/s]", ExtAirVolFlowDes);
1505 0 : ShowMessage(state,
1506 0 : format("SizeOutdoorAirUnit: Potential issue with equipment sizing for ZoneHVAC:OutdoorAirUnit {}",
1507 0 : thisOutAirUnit.Name));
1508 0 : ShowContinueError(state, format("User-Specified Exhaust Air Flow Rate of {:.5R} [m3/s]", ExtAirVolFlowUser));
1509 0 : ShowContinueError(state, format("differs from Design Size Exhaust Air Flow Rate of {:.5R} [m3/s]", ExtAirVolFlowDes));
1510 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1511 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1512 : }
1513 : }
1514 : }
1515 : }
1516 : }
1517 : }
1518 :
1519 12 : state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirFlow = true;
1520 12 : state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingAirFlow = true;
1521 12 : state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirVolFlow = thisOutAirUnit.OutAirVolFlow;
1522 12 : state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingAirVolFlow = thisOutAirUnit.OutAirVolFlow;
1523 12 : state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = thisOutAirUnit.OutAirVolFlow;
1524 :
1525 12 : if (thisOutAirUnit.SFanMaxAirVolFlow == AutoSize) {
1526 5 : state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, true, _, _);
1527 5 : thisOutAirUnit.SFanMaxAirVolFlow = state.dataFans->fans(thisOutAirUnit.SFan_Index)->maxAirFlowRate;
1528 : }
1529 12 : if (thisOutAirUnit.ExtFan) {
1530 12 : if (thisOutAirUnit.EFanMaxAirVolFlow == AutoSize) {
1531 6 : state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->simulate(state, true, _, _);
1532 6 : thisOutAirUnit.EFanMaxAirVolFlow = state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->maxAirFlowRate;
1533 : }
1534 : }
1535 :
1536 51 : for (int CompNum = 1; CompNum <= thisOutAirUnit.NumComponents; ++CompNum) {
1537 39 : auto &thisOAEquip = thisOutAirUnit.OAEquip(CompNum);
1538 39 : if ((thisOAEquip.Type == CompType::WaterCoil_Cooling) || (thisOAEquip.Type == CompType::WaterCoil_DetailedCool)) {
1539 6 : if (thisOAEquip.MaxVolWaterFlow == AutoSize) {
1540 1 : SimulateWaterCoilComponents(state, thisOAEquip.ComponentName, true, thisOAEquip.ComponentIndex, _, HVAC::FanOp::Cycling, 0.0);
1541 : }
1542 : }
1543 39 : if (thisOAEquip.Type == CompType::WaterCoil_SimpleHeat) {
1544 6 : if (thisOAEquip.MaxVolWaterFlow == AutoSize) {
1545 3 : SimulateWaterCoilComponents(state, thisOAEquip.ComponentName, true, thisOAEquip.ComponentIndex, _, HVAC::FanOp::Cycling, 0.0);
1546 : }
1547 : }
1548 39 : if (thisOAEquip.Type == CompType::SteamCoil_AirHeat) {
1549 0 : if (thisOAEquip.MaxVolWaterFlow == AutoSize) {
1550 0 : SimulateSteamCoilComponents(state, thisOAEquip.ComponentName, true, thisOAEquip.ComponentIndex);
1551 : }
1552 : }
1553 39 : if (thisOAEquip.Type == CompType::WaterCoil_CoolingHXAsst) {
1554 0 : if (thisOAEquip.MaxVolWaterFlow == AutoSize) {
1555 0 : SimHXAssistedCoolingCoil(
1556 0 : state, thisOAEquip.ComponentName, true, HVAC::CompressorOp::On, 0.0, thisOAEquip.ComponentIndex, HVAC::FanOp::Continuous);
1557 : }
1558 : }
1559 : }
1560 :
1561 12 : if (ErrorsFound) {
1562 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
1563 : }
1564 12 : }
1565 :
1566 64806 : void CalcOutdoorAirUnit(EnergyPlusData &state,
1567 : int &OAUnitNum, // number of the current unit being simulated
1568 : int const ZoneNum, // number of zone being served
1569 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
1570 : Real64 &PowerMet, // power supplied
1571 : Real64 &LatOutputProvided // Latent power supplied (kg/s), negative = dehumidification
1572 : )
1573 : {
1574 :
1575 : // SUBROUTINE INFORMATION:
1576 : // AUTHOR Young Tae Chae, Rick Strand
1577 : // DATE WRITTEN June 2008
1578 : // MODIFIED July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
1579 : // RE-ENGINEERED na
1580 :
1581 : // PURPOSE OF THIS SUBROUTINE:
1582 : // This subroutine mainly controls the action of the outdoor air unit
1583 : // (or more exactly, it controls the coil outlet temperature of the unit)
1584 : // based on the user input for controls and the defined controls
1585 : // algorithms.
1586 :
1587 : // METHODOLOGY EMPLOYED:
1588 : // Outdoor air unit is controlled based on user input and what is happening in the
1589 : // simulation.
1590 : // Note: controls are strictly temperature based and do not factor
1591 : // humidity into the equation (not an enthalpy economy cycle but rather
1592 : // a simple return air cycle).
1593 :
1594 : // REFERENCES:
1595 : // ASHRAE Systems and Equipment Handbook (SI), 1996. page 31.3
1596 :
1597 : // USE STATEMENTS:
1598 :
1599 : // Using/Aliasing
1600 64806 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
1601 :
1602 64806 : auto &TurnFansOff = state.dataHVACGlobal->TurnFansOff;
1603 64806 : auto &TurnFansOn = state.dataHVACGlobal->TurnFansOn;
1604 : using HeatingCoils::CheckHeatingCoilSchedule;
1605 : using HVACHXAssistedCoolingCoil::CheckHXAssistedCoolingCoilSchedule;
1606 : using ScheduleManager::GetCurrentScheduleValue;
1607 :
1608 : // Locals
1609 :
1610 : // SUBROUTINE ARGUMENT DEFINITIONS:
1611 :
1612 : // SUBROUTINE PARAMETER DEFINITIONS:
1613 : // INTERFACE BLOCK SPECIFICATIONS
1614 :
1615 : // DERIVED TYPE DEFINITIONS
1616 : // na
1617 :
1618 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1619 : Real64 DesOATemp; // Design OA Temp degree C
1620 : Real64 AirMassFlow; // air mass flow rate [kg/s]
1621 : Real64 QTotUnitOut; // total unit output [watts]
1622 64806 : Real64 QUnitOut = 0.0; // heating or sens. cooling provided by fan coil unit [watts]
1623 : Real64 LatLoadMet; // heating or sens. cooling provided by fan coil unit [watts]
1624 : Real64 MinHumRat; // desired temperature after mixing inlet and outdoor air [degrees C]
1625 : Real64 SetPointTemp; // temperature that will be used to control the radiant system [Celsius]
1626 : Real64 HiCtrlTemp; // Current high point in setpoint temperature range
1627 : Real64 LoCtrlTemp; // Current low point in setpoint temperature range
1628 : Real64 AirInEnt; // RE-calcualte the Enthalpy of supply air
1629 64806 : Real64 AirOutletTemp = 0.0;
1630 : Real64 ZoneSupAirEnt; // Specific humidity ratio of inlet air (kg moisture / kg moist air)
1631 : // Latent output
1632 : Real64 LatentOutput; // Latent (moisture) add/removal rate, negative is dehumidification [kg/s]
1633 : Real64 SpecHumOut; // Specific humidity ratio of outlet air (kg moisture / kg moist air)
1634 : Real64 SpecHumIn; // Specific humidity ratio of inlet air (kg moisture / kg moist air)
1635 : Real64 ZoneAirEnt; // zone air enthalphy J/kg
1636 :
1637 : // initialize local variables
1638 64806 : int const InletNode = thisOutAirUnit.AirInletNode; // Unit air inlet node, only used if ExtFan
1639 64806 : int const SFanOutletNode = thisOutAirUnit.SFanOutletNode; // Unit supply fan outlet node
1640 64806 : int const OutletNode = thisOutAirUnit.AirOutletNode; // air outlet node
1641 64806 : int const OutsideAirNode = thisOutAirUnit.OutsideAirNode; // outside air node
1642 64806 : OAUnitCtrlType const UnitControlType = thisOutAirUnit.controlType;
1643 :
1644 64806 : thisOutAirUnit.CompOutSetTemp = 0.0;
1645 64806 : thisOutAirUnit.FanEffect = false;
1646 :
1647 129612 : if ((GetCurrentScheduleValue(state, thisOutAirUnit.SchedPtr) <= 0) || (GetCurrentScheduleValue(state, thisOutAirUnit.OutAirSchedPtr) <= 0) ||
1648 129612 : ((GetCurrentScheduleValue(state, thisOutAirUnit.SFanAvailSchedPtr) <= 0) && !TurnFansOn) || TurnFansOff) {
1649 : // System is off or has no load upon the unit; set the flow rates to zero and then
1650 : // simulate the components with the no flow conditions
1651 1282 : if (thisOutAirUnit.ExtFan) {
1652 1282 : state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
1653 1282 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = 0.0;
1654 1282 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = 0.0;
1655 : }
1656 1282 : state.dataLoopNodes->Node(SFanOutletNode).MassFlowRate = 0.0;
1657 1282 : state.dataLoopNodes->Node(SFanOutletNode).MassFlowRateMaxAvail = 0.0;
1658 1282 : state.dataLoopNodes->Node(SFanOutletNode).MassFlowRateMinAvail = 0.0;
1659 1282 : state.dataLoopNodes->Node(OutletNode).MassFlowRate = 0.0;
1660 1282 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = 0.0;
1661 1282 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = 0.0;
1662 1282 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = 0.0;
1663 1282 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMaxAvail = 0.0;
1664 1282 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMinAvail = 0.0;
1665 :
1666 : // Node condition
1667 1282 : if (thisOutAirUnit.ExtFan) {
1668 1282 : state.dataLoopNodes->Node(InletNode).Temp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
1669 1282 : state.dataLoopNodes->Node(SFanOutletNode).Temp = state.dataLoopNodes->Node(InletNode).Temp;
1670 : } else {
1671 0 : state.dataLoopNodes->Node(SFanOutletNode).Temp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
1672 : }
1673 1282 : state.dataLoopNodes->Node(OutletNode).Temp = state.dataLoopNodes->Node(SFanOutletNode).Temp;
1674 :
1675 1282 : if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::BlowThru) {
1676 0 : state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _);
1677 :
1678 0 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1679 0 : if (thisOutAirUnit.ExtFan) {
1680 0 : state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->simulate(state, FirstHVACIteration, _, _);
1681 : }
1682 :
1683 1282 : } else if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
1684 1282 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1685 1282 : state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _, _);
1686 :
1687 1282 : if (thisOutAirUnit.ExtFan) {
1688 1282 : state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->simulate(state, FirstHVACIteration, _, _);
1689 : }
1690 : }
1691 :
1692 : } else { // System On
1693 :
1694 : // Flowrate Check
1695 63524 : if (state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate > 0.0) {
1696 63524 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = thisOutAirUnit.OutAirMassFlow;
1697 : }
1698 :
1699 : // Fan Positioning Check
1700 :
1701 63524 : if (thisOutAirUnit.ExtFan) {
1702 63524 : state.dataLoopNodes->Node(InletNode).MassFlowRate = thisOutAirUnit.ExtAirMassFlow;
1703 : }
1704 :
1705 : // Air mass balance check
1706 63524 : if ((std::abs(thisOutAirUnit.ExtAirMassFlow - thisOutAirUnit.OutAirMassFlow) > 0.001) &&
1707 0 : (!state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance)) {
1708 0 : if (!thisOutAirUnit.FlowError) {
1709 0 : ShowWarningError(state, "Air mass flow between zone supply and exhaust is not balanced. Only the first occurrence is reported.");
1710 0 : ShowContinueError(state, format("Occurs in ZoneHVAC:OutdoorAirUnit Object= {}", thisOutAirUnit.Name));
1711 0 : ShowContinueError(state,
1712 : "Air mass balance is required by other outdoor air units: Fan:ZoneExhaust, ZoneMixing, ZoneCrossMixing, or "
1713 : "other air flow control inputs.");
1714 0 : ShowContinueErrorTimeStamp(state,
1715 0 : format("The outdoor mass flow rate = {:.3R} and the exhaust mass flow rate = {:.3R}.",
1716 0 : thisOutAirUnit.OutAirMassFlow,
1717 0 : thisOutAirUnit.ExtAirMassFlow));
1718 0 : thisOutAirUnit.FlowError = true;
1719 : }
1720 : }
1721 :
1722 63524 : if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::BlowThru) {
1723 32403 : state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _, _);
1724 32403 : DesOATemp = state.dataLoopNodes->Node(SFanOutletNode).Temp;
1725 31121 : } else if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
1726 31121 : DesOATemp = state.dataLoopNodes->Node(OutsideAirNode).Temp;
1727 : }
1728 :
1729 : // Control type check
1730 63524 : switch (UnitControlType) {
1731 31121 : case OAUnitCtrlType::Neutral: {
1732 31121 : SetPointTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
1733 : // Neutral Control Condition
1734 31121 : if (DesOATemp == SetPointTemp) {
1735 0 : thisOutAirUnit.OperatingMode = Operation::NeutralMode;
1736 0 : AirOutletTemp = DesOATemp;
1737 0 : thisOutAirUnit.CompOutSetTemp = DesOATemp;
1738 0 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1739 : } else {
1740 31121 : if (DesOATemp < SetPointTemp) { // Heating MODE
1741 16710 : thisOutAirUnit.OperatingMode = Operation::HeatingMode;
1742 16710 : AirOutletTemp = SetPointTemp;
1743 16710 : thisOutAirUnit.CompOutSetTemp = AirOutletTemp;
1744 16710 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1745 : } else { // Cooling Mode
1746 14411 : thisOutAirUnit.OperatingMode = Operation::CoolingMode;
1747 14411 : AirOutletTemp = SetPointTemp;
1748 14411 : thisOutAirUnit.CompOutSetTemp = AirOutletTemp;
1749 14411 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1750 : }
1751 : }
1752 : // SetPoint Temperature Condition
1753 31121 : } break;
1754 32403 : case OAUnitCtrlType::Temperature: {
1755 32403 : SetPointTemp = DesOATemp;
1756 32403 : HiCtrlTemp = GetCurrentScheduleValue(state, thisOutAirUnit.HiCtrlTempSchedPtr);
1757 32403 : LoCtrlTemp = GetCurrentScheduleValue(state, thisOutAirUnit.LoCtrlTempSchedPtr);
1758 32403 : if ((DesOATemp <= HiCtrlTemp) && (DesOATemp >= LoCtrlTemp)) {
1759 0 : thisOutAirUnit.OperatingMode = Operation::NeutralMode;
1760 0 : AirOutletTemp = DesOATemp;
1761 0 : thisOutAirUnit.CompOutSetTemp = DesOATemp;
1762 0 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1763 : } else {
1764 32403 : if (SetPointTemp < LoCtrlTemp) {
1765 13095 : thisOutAirUnit.OperatingMode = Operation::HeatingMode;
1766 13095 : AirOutletTemp = LoCtrlTemp;
1767 13095 : thisOutAirUnit.CompOutSetTemp = AirOutletTemp;
1768 13095 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1769 19308 : } else if (SetPointTemp > HiCtrlTemp) {
1770 19308 : thisOutAirUnit.OperatingMode = Operation::CoolingMode;
1771 19308 : AirOutletTemp = HiCtrlTemp;
1772 19308 : thisOutAirUnit.CompOutSetTemp = AirOutletTemp;
1773 19308 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1774 : }
1775 : }
1776 32403 : } break;
1777 0 : default:
1778 0 : break;
1779 : }
1780 :
1781 : // Fan positioning
1782 63524 : if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
1783 31121 : state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _, _);
1784 :
1785 31121 : thisOutAirUnit.FanEffect = true; // RE-Simulation to take over the supply fan effect
1786 31121 : thisOutAirUnit.FanCorTemp = (state.dataLoopNodes->Node(OutletNode).Temp - thisOutAirUnit.CompOutSetTemp);
1787 31121 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1788 31121 : state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _, _);
1789 31121 : thisOutAirUnit.FanEffect = false;
1790 : }
1791 63524 : if (thisOutAirUnit.ExtFan) {
1792 63524 : state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->simulate(state, FirstHVACIteration, _, _);
1793 : }
1794 : } // ...end of system ON/OFF IF-THEN block
1795 :
1796 64806 : AirMassFlow = state.dataLoopNodes->Node(OutletNode).MassFlowRate;
1797 64806 : MinHumRat = min(state.dataLoopNodes->Node(OutletNode).HumRat, state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).HumRat);
1798 :
1799 64806 : AirInEnt = PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, MinHumRat); // zone supply air node enthalpy
1800 64806 : ZoneAirEnt = PsyHFnTdbW(state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).Temp, MinHumRat); // zone air enthalpy
1801 64806 : QUnitOut = AirMassFlow * (AirInEnt - ZoneAirEnt); // Senscooling
1802 :
1803 : // CR9155 Remove specific humidity calculations
1804 64806 : SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
1805 64806 : SpecHumIn = state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).HumRat;
1806 64806 : LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
1807 :
1808 : ZoneAirEnt =
1809 64806 : PsyHFnTdbW(state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).Temp, state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).HumRat);
1810 :
1811 64806 : ZoneSupAirEnt = PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(OutletNode).HumRat);
1812 64806 : QTotUnitOut = AirMassFlow * (ZoneSupAirEnt - ZoneAirEnt);
1813 64806 : LatLoadMet = QTotUnitOut - QUnitOut; // watts
1814 :
1815 : // Report variables...
1816 :
1817 64806 : if (QUnitOut < 0.0) {
1818 43892 : thisOutAirUnit.SensCoolingRate = std::abs(QUnitOut);
1819 43892 : thisOutAirUnit.SensHeatingRate = 0.0;
1820 : } else {
1821 20914 : thisOutAirUnit.SensCoolingRate = 0.0;
1822 20914 : thisOutAirUnit.SensHeatingRate = QUnitOut;
1823 : }
1824 :
1825 64806 : if (QTotUnitOut < 0.0) {
1826 50319 : thisOutAirUnit.TotCoolingRate = std::abs(QTotUnitOut);
1827 50319 : thisOutAirUnit.TotHeatingRate = 0.0;
1828 : } else {
1829 14487 : thisOutAirUnit.TotCoolingRate = 0.0;
1830 14487 : thisOutAirUnit.TotHeatingRate = QTotUnitOut;
1831 : }
1832 :
1833 64806 : if (LatLoadMet < 0.0) {
1834 45025 : thisOutAirUnit.LatCoolingRate = std::abs(LatLoadMet);
1835 45025 : thisOutAirUnit.LatHeatingRate = 0.0;
1836 : } else {
1837 19781 : thisOutAirUnit.LatCoolingRate = 0.0;
1838 19781 : thisOutAirUnit.LatHeatingRate = LatLoadMet;
1839 : }
1840 :
1841 : // OutAirUnit( OAUnitNum ).ElecFanRate = FanElecPower; //Issue #5524 this would only get the last fan called, not both if there are two
1842 64806 : thisOutAirUnit.ElecFanRate = 0.0;
1843 64806 : thisOutAirUnit.ElecFanRate += state.dataFans->fans(thisOutAirUnit.SFan_Index)->totalPower;
1844 :
1845 64806 : if (thisOutAirUnit.ExtFan) {
1846 64806 : thisOutAirUnit.ElecFanRate += state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->totalPower;
1847 : }
1848 :
1849 64806 : PowerMet = QUnitOut;
1850 64806 : LatOutputProvided = LatentOutput;
1851 64806 : }
1852 :
1853 95927 : void SimZoneOutAirUnitComps(EnergyPlusData &state, int const OAUnitNum, bool const FirstHVACIteration)
1854 : {
1855 :
1856 : // SUBROUTINE INFORMATION:
1857 : // AUTHOR Fred Buhl
1858 : // DATE WRITTEN Oct 1998
1859 : // MODIFIED na
1860 : // RE-ENGINEERED na
1861 :
1862 : // PURPOSE OF THIS SUBROUTINE
1863 : // Simulate the controllers and components in the outside air system.
1864 :
1865 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1866 95927 : bool const Sim = true;
1867 :
1868 95927 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
1869 394574 : for (int EquipNum = 1; EquipNum <= thisOutAirUnit.NumComponents; ++EquipNum) {
1870 298647 : auto &thisOAEquip = thisOutAirUnit.OAEquip(EquipNum);
1871 298647 : SimOutdoorAirEquipComps(state,
1872 : OAUnitNum,
1873 298647 : CompTypeNames[static_cast<int>(thisOAEquip.Type)],
1874 298647 : thisOAEquip.ComponentName,
1875 : EquipNum,
1876 : thisOAEquip.Type,
1877 : FirstHVACIteration,
1878 298647 : thisOAEquip.ComponentIndex,
1879 : Sim);
1880 : }
1881 95927 : }
1882 :
1883 298647 : void SimOutdoorAirEquipComps(EnergyPlusData &state,
1884 : int const OAUnitNum, // actual outdoor air unit num
1885 : std::string_view EquipType, // the component type
1886 : std::string const &EquipName, // the component Name
1887 : int const EquipNum,
1888 : [[maybe_unused]] CompType const CompTypeNum, // Component Type -- Integerized for this module
1889 : bool const FirstHVACIteration,
1890 : int &CompIndex,
1891 : bool const Sim // if TRUE, simulate component
1892 : )
1893 : {
1894 :
1895 : // SUBROUTINE INFORMATION:
1896 : // AUTHOR Young Tae Chae, Rick Strand
1897 : // DATE WRITTEN June 2008
1898 : // MODIFIED
1899 : // RE-ENGINEERED na
1900 :
1901 : // PURPOSE OF THIS SUBROUTINE:
1902 : // Outdoor air unit has various coil options. This subroutine defines the coil loads and execute
1903 : // to simulate each components
1904 : // METHODOLOGY EMPLOYED:
1905 :
1906 : // REFERENCES:
1907 :
1908 : // USE STATEMENTS:
1909 :
1910 : // Using/Aliasing
1911 : using DesiccantDehumidifiers::SimDesiccantDehumidifier;
1912 : using HeatRecovery::SimHeatRecovery;
1913 : using HVAC::SmallLoad;
1914 : using HVACDXHeatPumpSystem::SimDXHeatPumpSystem;
1915 : using HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil;
1916 : using ScheduleManager::GetCurrentScheduleValue;
1917 : using WaterCoils::SimulateWaterCoilComponents;
1918 :
1919 : // SUBROUTINE LOCAL VARIABLE DEFINITIONS
1920 : Real64 QCompReq;
1921 : Real64 MaxWaterFlow;
1922 : Real64 MinWaterFlow;
1923 : Real64 QUnitOut;
1924 : Real64 Dxsystemouttemp;
1925 :
1926 298647 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
1927 298647 : auto &thisOAEquip = thisOutAirUnit.OAEquip(EquipNum);
1928 298647 : int const InletNodeNum = thisOAEquip.CoilAirInletNode;
1929 298647 : int const OutletNodeNum = thisOAEquip.CoilAirOutletNode;
1930 :
1931 298647 : int UnitNum = OAUnitNum;
1932 298647 : int SimCompNum = EquipNum;
1933 :
1934 298647 : Real64 const CompAirOutTemp = thisOutAirUnit.CompOutSetTemp;
1935 298647 : Operation const OpMode = thisOutAirUnit.OperatingMode;
1936 298647 : CompType const EquipTypeNum = thisOAEquip.Type;
1937 298647 : Real64 const OAMassFlow = thisOutAirUnit.OutAirMassFlow;
1938 :
1939 : // check the fan positioning
1940 298647 : bool const DrawFan = thisOutAirUnit.FanEffect;
1941 298647 : Real64 const FanEffect = DrawFan ? thisOutAirUnit.FanCorTemp : 0.0;
1942 :
1943 : // checking equipment index
1944 :
1945 : {
1946 298647 : switch (EquipTypeNum) {
1947 : // Heat recovery
1948 74325 : case CompType::HeatXchngrFP: // 'HeatExchanger:AirToAir:FlatPlate',
1949 : case CompType::HeatXchngrSL: // 'HeatExchanger:AirToAir:SensibleAndLatent',
1950 : // 'HeatExchanger:Desiccant:BalancedFlow' - unused
1951 : {
1952 :
1953 74325 : if (Sim) {
1954 74325 : SimHeatRecovery(state, EquipName, FirstHVACIteration, CompIndex, HVAC::FanOp::Continuous, _, _, _, _, false, false);
1955 : }
1956 74325 : } break;
1957 : // Desiccant Dehumidifier
1958 10801 : case CompType::Desiccant: { // 'Dehumidifier:Desiccant:NoFans'
1959 10801 : if (Sim) {
1960 10801 : SimDesiccantDehumidifier(state, EquipName, FirstHVACIteration, CompIndex);
1961 : }
1962 :
1963 10801 : } break;
1964 52723 : case CompType::WaterCoil_SimpleHeat: { // ('Coil:Heating:Water')
1965 :
1966 52723 : if (Sim) {
1967 52723 : int const ControlNode = thisOAEquip.CoilWaterInletNode;
1968 52723 : MaxWaterFlow = thisOAEquip.MaxWaterMassFlow;
1969 52723 : MinWaterFlow = thisOAEquip.MinWaterMassFlow;
1970 : // On the first HVAC iteration the system values are given to the controller, but after that
1971 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
1972 52723 : if ((!FirstHVACIteration) && (ControlNode > 0)) {
1973 27414 : MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
1974 27414 : MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
1975 : }
1976 52723 : auto const &whCoilInletNode = state.dataLoopNodes->Node(InletNodeNum);
1977 : // auto &whCoilOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
1978 :
1979 52723 : Real64 const CpAirZn = PsyCpAirFnW(whCoilInletNode.HumRat);
1980 :
1981 52723 : if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::CoolingMode) || (whCoilInletNode.Temp > CompAirOutTemp)) {
1982 25296 : QCompReq = 0.0;
1983 : } else {
1984 27427 : QCompReq = CpAirZn * OAMassFlow * ((CompAirOutTemp - whCoilInletNode.Temp) - FanEffect);
1985 27427 : if (std::abs(QCompReq) < SmallLoad) QCompReq = 0.0;
1986 27427 : if (QCompReq < 0.0) QCompReq = 0.0; // coil can heat only
1987 : }
1988 :
1989 210892 : ControlCompOutput(state,
1990 52723 : thisOutAirUnit.Name,
1991 105446 : std::string(ZoneHVACOAUnit),
1992 : UnitNum,
1993 : FirstHVACIteration,
1994 : QCompReq,
1995 : ControlNode,
1996 : MaxWaterFlow,
1997 : MinWaterFlow,
1998 : 0.0001,
1999 52723 : thisOutAirUnit.ControlCompTypeNum,
2000 52723 : thisOutAirUnit.CompErrIndex,
2001 : _,
2002 : _,
2003 : _,
2004 105446 : 2,
2005 : SimCompNum,
2006 52723 : thisOAEquip.plantLoc);
2007 : }
2008 52723 : } break;
2009 0 : case CompType::SteamCoil_AirHeat: { // 'Coil:Heating:Steam'
2010 0 : if (Sim) {
2011 0 : CalcOAUnitCoilComps(state, UnitNum, FirstHVACIteration, SimCompNum, QUnitOut);
2012 : }
2013 0 : } break;
2014 43204 : case CompType::Coil_ElectricHeat: // 'Coil:Heating:Electric'
2015 : case CompType::Coil_GasHeat: { // 'Coil:Heating:Fuel'
2016 43204 : if (Sim) {
2017 : // stand-alone coils are temperature controlled (do not pass QCoilReq in argument list, QCoilReq overrides temp SP)
2018 43204 : CalcOAUnitCoilComps(state, UnitNum, FirstHVACIteration, SimCompNum, QUnitOut);
2019 : }
2020 43204 : } break;
2021 : // water cooling coil Types
2022 32403 : case CompType::WaterCoil_Cooling: { // 'Coil:Cooling:Water'
2023 32403 : if (Sim) {
2024 32403 : int const ControlNode = thisOAEquip.CoilWaterInletNode;
2025 32403 : MaxWaterFlow = thisOAEquip.MaxWaterMassFlow;
2026 32403 : MinWaterFlow = thisOAEquip.MinWaterMassFlow;
2027 : // On the first HVAC iteration the system values are given to the controller, but after that
2028 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
2029 32403 : if ((!FirstHVACIteration) && (ControlNode > 0)) {
2030 16833 : MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
2031 16833 : MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
2032 : }
2033 :
2034 32403 : auto const &wcCoilInletNode = state.dataLoopNodes->Node(InletNodeNum);
2035 32403 : auto &wcCoilOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
2036 :
2037 32403 : Real64 const CpAirZn = PsyCpAirFnW(wcCoilInletNode.HumRat);
2038 32403 : if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::HeatingMode) || (wcCoilInletNode.Temp < CompAirOutTemp)) {
2039 18433 : QCompReq = 0.0;
2040 18433 : wcCoilOutletNode.Temp = wcCoilInletNode.Temp;
2041 18433 : wcCoilOutletNode.HumRat = wcCoilInletNode.HumRat;
2042 18433 : wcCoilOutletNode.MassFlowRate = wcCoilInletNode.MassFlowRate;
2043 :
2044 : } else {
2045 :
2046 13970 : QCompReq = CpAirZn * OAMassFlow * ((CompAirOutTemp - wcCoilInletNode.Temp) - FanEffect);
2047 13970 : if (std::abs(QCompReq) < SmallLoad) QCompReq = 0.0;
2048 13970 : if (QCompReq > 0.0) QCompReq = 0.0; // coil can cool only
2049 : }
2050 :
2051 129612 : ControlCompOutput(state,
2052 32403 : thisOutAirUnit.Name,
2053 64806 : std::string(ZoneHVACOAUnit),
2054 : UnitNum,
2055 : FirstHVACIteration,
2056 : QCompReq,
2057 : ControlNode,
2058 : MaxWaterFlow,
2059 : MinWaterFlow,
2060 : 0.001,
2061 32403 : thisOutAirUnit.ControlCompTypeNum,
2062 32403 : thisOutAirUnit.CompErrIndex,
2063 : _,
2064 : _,
2065 : _,
2066 64806 : 1,
2067 : SimCompNum,
2068 32403 : thisOAEquip.plantLoc);
2069 : }
2070 32403 : } break;
2071 0 : case CompType::WaterCoil_DetailedCool: { // 'Coil:Cooling:Water:DetailedGeometry'
2072 0 : if (Sim) {
2073 0 : int const ControlNode = thisOAEquip.CoilWaterInletNode;
2074 0 : MaxWaterFlow = thisOAEquip.MaxWaterMassFlow;
2075 0 : MinWaterFlow = thisOAEquip.MinWaterMassFlow;
2076 : // On the first HVAC iteration the system values are given to the controller, but after that
2077 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
2078 0 : if ((!FirstHVACIteration) && (ControlNode > 0)) {
2079 0 : MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
2080 0 : MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
2081 : }
2082 0 : auto const &wcCoilInletNode = state.dataLoopNodes->Node(InletNodeNum);
2083 : // auto &wcCoilOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
2084 :
2085 0 : Real64 const CpAirZn = PsyCpAirFnW(wcCoilInletNode.HumRat);
2086 :
2087 0 : if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::HeatingMode) || (wcCoilInletNode.Temp < CompAirOutTemp)) {
2088 0 : QCompReq = 0.0;
2089 : } else {
2090 :
2091 0 : QCompReq = CpAirZn * OAMassFlow * ((CompAirOutTemp - wcCoilInletNode.Temp) - FanEffect);
2092 0 : if (std::abs(QCompReq) < SmallLoad) QCompReq = 0.0;
2093 0 : if (QCompReq > 0.0) QCompReq = 0.0; // coil can cool only
2094 : }
2095 :
2096 0 : ControlCompOutput(state,
2097 0 : thisOutAirUnit.Name,
2098 : "ZONEHVAC:OUTDOORAIRUNIT",
2099 : UnitNum,
2100 : FirstHVACIteration,
2101 : QCompReq,
2102 : ControlNode,
2103 : MaxWaterFlow,
2104 : MinWaterFlow,
2105 : 0.001,
2106 0 : thisOutAirUnit.ControlCompTypeNum,
2107 0 : thisOutAirUnit.CompErrIndex,
2108 : _,
2109 : _,
2110 : _,
2111 0 : 1,
2112 : SimCompNum,
2113 0 : thisOAEquip.plantLoc);
2114 : }
2115 0 : } break;
2116 0 : case CompType::WaterCoil_CoolingHXAsst: { // 'CoilSystem:Cooling:Water:HeatExchangerAssisted'
2117 0 : if (Sim) {
2118 0 : int const ControlNode = thisOAEquip.CoilWaterInletNode;
2119 0 : MaxWaterFlow = thisOAEquip.MaxWaterMassFlow;
2120 0 : MinWaterFlow = 0.0;
2121 : // On the first HVAC iteration the system values are given to the controller, but after that
2122 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
2123 0 : if ((!FirstHVACIteration) && (ControlNode > 0)) {
2124 0 : MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
2125 0 : MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
2126 : }
2127 0 : auto const &wcCoilInletNode = state.dataLoopNodes->Node(InletNodeNum);
2128 : // auto &wcCoilOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
2129 :
2130 0 : Real64 const CpAirZn = PsyCpAirFnW(wcCoilInletNode.HumRat);
2131 0 : if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::HeatingMode) || (wcCoilInletNode.Temp < CompAirOutTemp)) {
2132 0 : QCompReq = 0.0;
2133 : } else {
2134 0 : QCompReq = CpAirZn * OAMassFlow * ((CompAirOutTemp - wcCoilInletNode.Temp) - FanEffect);
2135 0 : if (std::abs(QCompReq) < SmallLoad) QCompReq = 0.0;
2136 0 : if (QCompReq > 0.0) QCompReq = 0.0; // coil can cool only
2137 : }
2138 0 : ControlCompOutput(state,
2139 0 : thisOutAirUnit.Name,
2140 : "ZONEHVAC:OUTDOORAIRUNIT",
2141 : UnitNum,
2142 : FirstHVACIteration,
2143 : QCompReq,
2144 : ControlNode,
2145 : MaxWaterFlow,
2146 : MinWaterFlow,
2147 : 0.001,
2148 0 : thisOutAirUnit.ControlCompTypeNum,
2149 0 : thisOutAirUnit.CompErrIndex,
2150 : _,
2151 : _,
2152 : _,
2153 0 : 1,
2154 : SimCompNum,
2155 0 : thisOAEquip.plantLoc);
2156 : }
2157 0 : } break;
2158 74325 : case CompType::DXSystem: { // CoilSystem:Cooling:DX old 'CompType:UnitaryCoolOnly'
2159 74325 : if (Sim) {
2160 74325 : if (thisOAEquip.compPointer == nullptr) {
2161 8 : UnitarySystems::UnitarySys thisSys;
2162 8 : thisOAEquip.compPointer =
2163 8 : thisSys.factory(state, HVAC::UnitarySysType::Unitary_AnyCoilType, thisOAEquip.ComponentName, false, OAUnitNum);
2164 8 : UnitarySystems::UnitarySys::checkUnitarySysCoilInOASysExists(state, thisOAEquip.ComponentName, OAUnitNum);
2165 8 : }
2166 74325 : if (((OpMode == Operation::NeutralMode) && (thisOutAirUnit.controlType == OAUnitCtrlType::Temperature)) ||
2167 : (OpMode == Operation::HeatingMode)) {
2168 34177 : Dxsystemouttemp = 100.0; // There is no cooling demand for the DX system.
2169 : } else {
2170 40148 : Dxsystemouttemp = CompAirOutTemp - FanEffect;
2171 : }
2172 74325 : Real64 sensOut = 0.0;
2173 74325 : Real64 latOut = 0.0;
2174 74325 : int DXSystemIndex = 0;
2175 74325 : thisOAEquip.compPointer->simulate(state,
2176 : EquipName,
2177 : FirstHVACIteration,
2178 : -1,
2179 : DXSystemIndex,
2180 74325 : state.dataOutdoorAirUnit->HeatActive,
2181 74325 : state.dataOutdoorAirUnit->CoolActive,
2182 : UnitNum,
2183 : Dxsystemouttemp,
2184 : false,
2185 : sensOut,
2186 : latOut);
2187 : }
2188 74325 : } break;
2189 10866 : case CompType::DXHeatPumpSystem: {
2190 10866 : if (Sim) {
2191 10866 : if (((OpMode == Operation::NeutralMode) && (thisOutAirUnit.controlType == OAUnitCtrlType::Temperature)) ||
2192 : (OpMode == Operation::CoolingMode)) {
2193 6374 : Dxsystemouttemp = -20.0; // There is no heating demand for the DX system.
2194 : } else {
2195 4492 : Dxsystemouttemp = CompAirOutTemp - FanEffect;
2196 : }
2197 10866 : int DXSystemIndex = 0;
2198 10866 : SimDXHeatPumpSystem(state, EquipName, FirstHVACIteration, -1, DXSystemIndex, UnitNum, Dxsystemouttemp);
2199 : }
2200 10866 : } break;
2201 : // RAR need new CompType:UnitarySystem object here
2202 0 : case CompType::UnitarySystemModel: { // 'CompType:UnitarySystem'
2203 0 : if (Sim) {
2204 : // This may have to be done in the unitary system object since there can be both cooling and heating
2205 0 : if (((OpMode == Operation::NeutralMode) && (thisOutAirUnit.controlType == OAUnitCtrlType::Temperature)) ||
2206 : (OpMode == Operation::HeatingMode)) {
2207 0 : Dxsystemouttemp = 100.0; // There is no cooling demand.
2208 0 : } else if (((OpMode == Operation::NeutralMode) && (thisOutAirUnit.controlType == OAUnitCtrlType::Temperature)) ||
2209 : (OpMode == Operation::CoolingMode)) {
2210 0 : Dxsystemouttemp = -20.0; // There is no heating demand.
2211 : } else {
2212 0 : Dxsystemouttemp = CompAirOutTemp - FanEffect;
2213 : }
2214 0 : Real64 sensOut = 0.0;
2215 0 : Real64 latOut = 0.0;
2216 0 : int DXSystemIndex = 0;
2217 0 : thisOAEquip.compPointer->simulate(state,
2218 : EquipName,
2219 : FirstHVACIteration,
2220 : -1,
2221 : DXSystemIndex,
2222 0 : state.dataOutdoorAirUnit->HeatActive,
2223 0 : state.dataOutdoorAirUnit->CoolActive,
2224 : UnitNum,
2225 : Dxsystemouttemp,
2226 : false,
2227 : sensOut,
2228 : latOut);
2229 : }
2230 0 : } break;
2231 0 : default: {
2232 0 : ShowFatalError(state, format("Invalid Outdoor Air Unit Component={}", EquipType)); // validate
2233 0 : } break;
2234 : }
2235 : }
2236 298647 : }
2237 :
2238 796352 : void CalcOAUnitCoilComps(EnergyPlusData &state,
2239 : int const CompNum, // actual outdoor air unit num
2240 : bool const FirstHVACIteration,
2241 : int const EquipIndex, // Component Type -- Integerized for this module
2242 : Real64 &LoadMet)
2243 : {
2244 :
2245 : // SUBROUTINE INFORMATION:
2246 : // AUTHOR Young Tae Chae, Rick Strand
2247 : // DATE WRITTEN June 2009
2248 : // MODIFIED
2249 : // RE-ENGINEERED na
2250 :
2251 : // PURPOSE OF THIS SUBROUTINE:
2252 : // This subroutine mainly controls the action of water components in the unit
2253 :
2254 : // METHODOLOGY EMPLOYED:
2255 :
2256 : // REFERENCES:
2257 :
2258 : // USE STATEMENTS:
2259 :
2260 : // Using/Aliasing
2261 : using HVAC::SmallLoad;
2262 : using HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil;
2263 : using SteamCoils::SimulateSteamCoilComponents;
2264 : using WaterCoils::SimulateWaterCoilComponents;
2265 :
2266 : // SUBROUTINE ARGUMENT DEFINITIONS:
2267 :
2268 : // Locals
2269 : // SUBROUTINE LOCAL VARIABLE DEFINITIONS
2270 796352 : int CoilIndex = 0;
2271 :
2272 796352 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(CompNum);
2273 796352 : auto &thisOAEquip = thisOutAirUnit.OAEquip(EquipIndex);
2274 796352 : int const InletNodeNum = thisOAEquip.CoilAirInletNode;
2275 796352 : int const OutletNodeNum = thisOAEquip.CoilAirOutletNode;
2276 796352 : auto const &oaInletNode = state.dataLoopNodes->Node(InletNodeNum);
2277 796352 : auto &oaOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
2278 :
2279 796352 : CompType const CoilTypeNum = thisOAEquip.Type;
2280 796352 : Operation const OpMode = thisOutAirUnit.OperatingMode;
2281 796352 : Real64 const CoilAirOutTemp = thisOutAirUnit.CompOutSetTemp;
2282 796352 : bool const DrawFan = thisOutAirUnit.FanEffect;
2283 796352 : Real64 const FanEffect = DrawFan ? thisOutAirUnit.FanCorTemp : 0.0;
2284 :
2285 : // Actual equipment load
2286 164355 : auto setupQCompReq = [&OpMode, &oaInletNode, &oaOutletNode, &CoilAirOutTemp, &FanEffect]() -> Real64 {
2287 43204 : Real64 QCompReq = 0.0;
2288 43204 : if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::CoolingMode) || (oaInletNode.Temp > CoilAirOutTemp)) {
2289 25921 : QCompReq = 0.0;
2290 : } else {
2291 17283 : oaOutletNode.MassFlowRate = oaInletNode.MassFlowRate;
2292 17283 : Real64 const CpAirZn = PsyCpAirFnW(oaInletNode.HumRat);
2293 17283 : QCompReq = oaInletNode.MassFlowRate * CpAirZn * ((CoilAirOutTemp - oaInletNode.Temp) - FanEffect);
2294 17283 : if (std::abs(QCompReq) < SmallLoad) {
2295 0 : QCompReq = 0.0;
2296 : }
2297 : }
2298 43204 : if (QCompReq <= 0.0) {
2299 25921 : QCompReq = 0.0; // a heating coil can only heat, not cool
2300 25921 : oaOutletNode.Temp = oaInletNode.Temp;
2301 25921 : oaOutletNode.HumRat = oaInletNode.HumRat;
2302 25921 : oaOutletNode.MassFlowRate = oaInletNode.MassFlowRate;
2303 : }
2304 43204 : return QCompReq;
2305 796352 : };
2306 :
2307 796352 : switch (CoilTypeNum) {
2308 32403 : case CompType::Coil_ElectricHeat: {
2309 32403 : Real64 const QCompReq = setupQCompReq();
2310 32403 : HeatingCoils::SimulateHeatingCoilComponents(state, thisOAEquip.ComponentName, FirstHVACIteration, QCompReq, CoilIndex);
2311 32403 : Real64 const AirMassFlow = oaInletNode.MassFlowRate;
2312 32403 : LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
2313 :
2314 32403 : } break;
2315 10801 : case CompType::Coil_GasHeat: { // 'Coil:Heating:Steam'
2316 10801 : Real64 const QCompReq = setupQCompReq();
2317 10801 : HeatingCoils::SimulateHeatingCoilComponents(state, thisOAEquip.ComponentName, FirstHVACIteration, QCompReq, CoilIndex);
2318 10801 : Real64 const AirMassFlow = oaInletNode.MassFlowRate;
2319 10801 : LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
2320 :
2321 10801 : } break;
2322 0 : case CompType::SteamCoil_AirHeat: { // 'Coil:Heating:Steam'
2323 0 : Real64 const QCompReq = setupQCompReq();
2324 0 : SimulateSteamCoilComponents(state, thisOAEquip.ComponentName, FirstHVACIteration, CoilIndex, QCompReq);
2325 0 : Real64 const AirMassFlow = oaInletNode.MassFlowRate;
2326 0 : LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
2327 :
2328 0 : } break;
2329 753148 : case CompType::WaterCoil_SimpleHeat: // 'Coil:Heating:Water')
2330 : case CompType::WaterCoil_Cooling: // 'Coil:Cooling:Water'
2331 : case CompType::WaterCoil_DetailedCool: {
2332 753148 : SimulateWaterCoilComponents(state, thisOAEquip.ComponentName, FirstHVACIteration, CoilIndex);
2333 753148 : Real64 const AirMassFlow = oaInletNode.MassFlowRate;
2334 753148 : LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
2335 :
2336 753148 : } break;
2337 0 : case CompType::WaterCoil_CoolingHXAsst: {
2338 0 : SimHXAssistedCoolingCoil(
2339 : state, thisOAEquip.ComponentName, FirstHVACIteration, HVAC::CompressorOp::On, 0.0, CoilIndex, HVAC::FanOp::Continuous);
2340 0 : Real64 const AirMassFlow = oaInletNode.MassFlowRate;
2341 0 : LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
2342 0 : } break;
2343 0 : default:
2344 0 : ShowFatalError(state, format("Invalid Coil Type = {}", CoilTypeNum)); // validate
2345 0 : break;
2346 : }
2347 796352 : }
2348 :
2349 : // SUBROUTINE UpdateOutdoorAirUnit
2350 :
2351 : // No update routine needed in this module since all of the updates happen on
2352 : // the Node derived type directly and these updates are done by other routines.
2353 :
2354 : // END SUBROUTINE UpdateOutdoorAirUnit
2355 :
2356 64806 : void ReportOutdoorAirUnit(EnergyPlusData &state,
2357 : int const OAUnitNum) // Index for the outdoor air unit under consideration within the derived types
2358 : {
2359 :
2360 : // SUBROUTINE INFORMATION:
2361 : // AUTHOR Young T. Chae
2362 : // DATE WRITTEN Oct. 2009
2363 : // MODIFIED na
2364 : // RE-ENGINEERED na
2365 :
2366 : // PURPOSE OF THIS SUBROUTINE:
2367 : // This subroutine simply produces output for the outdoor air unit.
2368 : // METHODOLOGY EMPLOYED:
2369 : // Standard EnergyPlus methodology.
2370 :
2371 : // Using/Aliasing
2372 64806 : Real64 const TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
2373 :
2374 64806 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
2375 64806 : thisOutAirUnit.TotHeatingEnergy = thisOutAirUnit.TotHeatingRate * TimeStepSysSec;
2376 64806 : thisOutAirUnit.SensHeatingEnergy = thisOutAirUnit.SensHeatingRate * TimeStepSysSec;
2377 64806 : thisOutAirUnit.LatHeatingEnergy = thisOutAirUnit.LatHeatingRate * TimeStepSysSec;
2378 64806 : thisOutAirUnit.SensCoolingEnergy = thisOutAirUnit.SensCoolingRate * TimeStepSysSec;
2379 64806 : thisOutAirUnit.LatCoolingEnergy = thisOutAirUnit.LatCoolingRate * TimeStepSysSec;
2380 64806 : thisOutAirUnit.TotCoolingEnergy = thisOutAirUnit.TotCoolingRate * TimeStepSysSec;
2381 64806 : thisOutAirUnit.AirMassFlow = thisOutAirUnit.OutAirMassFlow;
2382 64806 : thisOutAirUnit.ElecFanEnergy = thisOutAirUnit.ElecFanRate * TimeStepSysSec;
2383 :
2384 64806 : if (thisOutAirUnit.FirstPass) { // reset sizing flags so other zone equipment can size normally
2385 12 : if (!state.dataGlobal->SysSizingCalc) {
2386 12 : DataSizing::resetHVACSizingGlobals(state, state.dataSize->CurZoneEqNum, 0, thisOutAirUnit.FirstPass);
2387 : }
2388 : }
2389 64806 : }
2390 :
2391 3474 : int GetOutdoorAirUnitOutAirNode(EnergyPlusData &state, int const OAUnitNum)
2392 : {
2393 :
2394 : // FUNCTION INFORMATION:
2395 : // AUTHOR B Griffith
2396 : // DATE WRITTEN Dec 2006
2397 : // MODIFIED na
2398 : // RE-ENGINEERED na
2399 :
2400 : // PURPOSE OF THIS FUNCTION:
2401 : // lookup function for OA inlet node
2402 :
2403 : // Return value
2404 3474 : int GetOutdoorAirUnitOutAirNode = 0;
2405 :
2406 3474 : if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
2407 0 : OutdoorAirUnit::GetOutdoorAirUnitInputs(state);
2408 0 : state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
2409 : }
2410 :
2411 3474 : if (OAUnitNum > 0 && OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits) {
2412 3474 : GetOutdoorAirUnitOutAirNode = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).OutsideAirNode;
2413 : }
2414 :
2415 3474 : return GetOutdoorAirUnitOutAirNode;
2416 : }
2417 :
2418 3474 : int GetOutdoorAirUnitZoneInletNode(EnergyPlusData &state, int const OAUnitNum)
2419 : {
2420 :
2421 : // FUNCTION INFORMATION:
2422 : // AUTHOR B Griffith
2423 : // DATE WRITTEN Dec 2006
2424 : // MODIFIED na
2425 : // RE-ENGINEERED na
2426 :
2427 : // PURPOSE OF THIS FUNCTION:
2428 : // lookup function for OA inlet node
2429 :
2430 : // Return value
2431 3474 : int GetOutdoorAirUnitZoneInletNode = 0;
2432 :
2433 3474 : if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
2434 0 : OutdoorAirUnit::GetOutdoorAirUnitInputs(state);
2435 0 : state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
2436 : }
2437 :
2438 3474 : if (OAUnitNum > 0 && OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits) {
2439 3474 : GetOutdoorAirUnitZoneInletNode = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).AirOutletNode;
2440 : }
2441 :
2442 3474 : return GetOutdoorAirUnitZoneInletNode;
2443 : }
2444 :
2445 3474 : int GetOutdoorAirUnitReturnAirNode(EnergyPlusData &state, int const OAUnitNum)
2446 : {
2447 :
2448 : // FUNCTION INFORMATION:
2449 : // AUTHOR B Griffith
2450 : // DATE WRITTEN Dec 2006
2451 : // MODIFIED na
2452 : // RE-ENGINEERED na
2453 :
2454 : // PURPOSE OF THIS FUNCTION:
2455 : // lookup function for OA inlet node
2456 :
2457 : // Return value
2458 3474 : int GetOutdoorAirUnitReturnAirNode = 0;
2459 :
2460 3474 : if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
2461 0 : OutdoorAirUnit::GetOutdoorAirUnitInputs(state);
2462 0 : state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
2463 : }
2464 :
2465 3474 : if (OAUnitNum > 0 && OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits) {
2466 3474 : GetOutdoorAirUnitReturnAirNode = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).AirInletNode;
2467 : }
2468 :
2469 3474 : return GetOutdoorAirUnitReturnAirNode;
2470 : }
2471 :
2472 0 : int getOutdoorAirUnitEqIndex(EnergyPlusData &state, std::string_view EquipName)
2473 : {
2474 0 : if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
2475 0 : OutdoorAirUnit::GetOutdoorAirUnitInputs(state);
2476 0 : state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
2477 : }
2478 :
2479 0 : for (int OAUnitNum = 1; OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits; ++OAUnitNum) {
2480 0 : if (Util::SameString(state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).Name, EquipName)) {
2481 0 : return OAUnitNum;
2482 : }
2483 : }
2484 :
2485 0 : return 0;
2486 : }
2487 :
2488 : } // namespace OutdoorAirUnit
2489 :
2490 : } // namespace EnergyPlus
|