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