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 64818 : 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 64818 : int OAUnitNum = 0; // index of outdoor air unit being simulated
144 :
145 64818 : if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
146 2 : GetOutdoorAirUnitInputs(state);
147 2 : state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
148 : }
149 :
150 : // Find the correct Outdoor Air Unit
151 :
152 64818 : if (CompIndex == 0) {
153 12 : OAUnitNum = Util::FindItemInList(CompName, state.dataOutdoorAirUnit->OutAirUnit);
154 12 : if (OAUnitNum == 0) {
155 0 : ShowFatalError(state, format("ZoneHVAC:OutdoorAirUnit not found={}", CompName));
156 : }
157 12 : CompIndex = OAUnitNum;
158 : } else {
159 64806 : OAUnitNum = CompIndex;
160 64806 : 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 64806 : if (state.dataOutdoorAirUnit->CheckEquipName(OAUnitNum)) {
168 12 : 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 12 : state.dataOutdoorAirUnit->CheckEquipName(OAUnitNum) = false;
176 : }
177 : }
178 :
179 64818 : state.dataSize->ZoneEqOutdoorAirUnit = true;
180 :
181 64818 : if (state.dataGlobal->ZoneSizingCalc || state.dataGlobal->SysSizingCalc) {
182 12 : return;
183 : }
184 :
185 64806 : InitOutdoorAirUnit(state, OAUnitNum, ZoneNum, FirstHVACIteration);
186 :
187 64806 : CalcOutdoorAirUnit(state, OAUnitNum, ZoneNum, FirstHVACIteration, PowerMet, LatOutputProvided);
188 :
189 64806 : ReportOutdoorAirUnit(state, OAUnitNum);
190 :
191 64806 : state.dataSize->ZoneEqOutdoorAirUnit = false;
192 : }
193 :
194 2 : 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 2 : if (!state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
241 0 : return;
242 : }
243 :
244 2 : int NumAlphas = 0; // Number of elements in the alpha array
245 2 : int NumNums = 0; // Number of elements in the numeric array
246 2 : Array1D_string AlphArray; // character string data
247 2 : Array1D<Real64> NumArray; // numeric data
248 2 : int IOStat = -1; // IO Status when calling get input subroutine
249 2 : bool ErrorsFound = false;
250 :
251 2 : int MaxNums = 0; // Maximum number of numeric input fields
252 2 : int MaxAlphas = 0; // Maximum number of alpha input fields
253 2 : int TotalArgs = 0; // Total number of alpha and numeric arguments (max) for a
254 : bool IsValid; // Set for outside air node check
255 2 : Array1D_string cAlphaArgs; // Alpha input items for object
256 2 : std::string CurrentModuleObject; // Object type for getting and messages
257 2 : Array1D_string cAlphaFields; // Alpha field names
258 2 : Array1D_string cNumericFields; // Numeric field names
259 2 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
260 2 : 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 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, ZoneHVACOAUnit, TotalArgs, NumAlphas, NumNums);
265 2 : MaxNums = max(MaxNums, NumNums);
266 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
267 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, ZoneHVACEqList, TotalArgs, NumAlphas, NumNums);
268 2 : MaxNums = max(MaxNums, NumNums);
269 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
270 :
271 2 : AlphArray.allocate(MaxAlphas);
272 2 : cAlphaFields.allocate(MaxAlphas);
273 2 : NumArray.dimension(MaxNums, 0.0);
274 2 : cNumericFields.allocate(MaxNums);
275 2 : lAlphaBlanks.dimension(MaxAlphas, true);
276 2 : lNumericBlanks.dimension(MaxNums, true);
277 2 : cAlphaArgs.allocate(NumAlphas);
278 :
279 2 : CurrentModuleObject = ZoneHVACOAUnit;
280 2 : state.dataOutdoorAirUnit->NumOfOAUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
281 :
282 2 : state.dataOutdoorAirUnit->OutAirUnit.allocate(state.dataOutdoorAirUnit->NumOfOAUnits);
283 2 : state.dataOutdoorAirUnit->SupplyFanUniqueNames.reserve(static_cast<unsigned>(state.dataOutdoorAirUnit->NumOfOAUnits));
284 2 : state.dataOutdoorAirUnit->ExhaustFanUniqueNames.reserve(static_cast<unsigned>(state.dataOutdoorAirUnit->NumOfOAUnits));
285 2 : state.dataOutdoorAirUnit->ComponentListUniqueNames.reserve(static_cast<unsigned>(state.dataOutdoorAirUnit->NumOfOAUnits));
286 2 : state.dataOutdoorAirUnit->MyOneTimeErrorFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
287 2 : state.dataOutdoorAirUnit->CheckEquipName.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
288 :
289 14 : for (int OAUnitNum = 1; OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits; ++OAUnitNum) {
290 :
291 12 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
292 :
293 24 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
294 : CurrentModuleObject,
295 : OAUnitNum,
296 12 : state.dataIPShortCut->cAlphaArgs,
297 : NumAlphas,
298 : NumArray,
299 : NumNums,
300 : IOStat,
301 : lNumericBlanks,
302 : lAlphaBlanks,
303 : cAlphaFields,
304 : cNumericFields);
305 :
306 12 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
307 12 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), CurrentModuleObject, ErrorsFound);
308 :
309 : // A1
310 12 : thisOutAirUnit.Name = state.dataIPShortCut->cAlphaArgs(1);
311 :
312 : // A2
313 12 : if (lAlphaBlanks(2)) {
314 0 : thisOutAirUnit.availSched = Sched::GetScheduleAlwaysOn(state);
315 12 : } 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 12 : thisOutAirUnit.ZoneName = state.dataIPShortCut->cAlphaArgs(3);
322 12 : thisOutAirUnit.ZonePtr = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataHeatBal->Zone);
323 :
324 12 : 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 12 : thisOutAirUnit.ZoneNodeNum = state.dataHeatBal->Zone(thisOutAirUnit.ZonePtr).SystemZoneNodeNumber;
342 : // Outside air information:
343 : // N1
344 12 : thisOutAirUnit.OutAirVolFlow = NumArray(1);
345 : // A4
346 12 : if (lAlphaBlanks(4)) {
347 0 : ShowSevereEmptyField(state, eoh, cAlphaFields(4));
348 0 : ErrorsFound = true;
349 12 : } 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 12 : thisOutAirUnit.SFanName = state.dataIPShortCut->cAlphaArgs(5);
356 12 : GlobalNames::IntraObjUniquenessCheck(state,
357 12 : state.dataIPShortCut->cAlphaArgs(5),
358 : CurrentModuleObject,
359 12 : cAlphaFields(5),
360 12 : state.dataOutdoorAirUnit->SupplyFanUniqueNames,
361 : ErrorsFound);
362 :
363 12 : 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 12 : auto *fan = state.dataFans->fans(thisOutAirUnit.SFan_Index);
368 12 : thisOutAirUnit.supFanType = fan->type;
369 12 : thisOutAirUnit.SFanMaxAirVolFlow = fan->maxAirFlowRate;
370 12 : thisOutAirUnit.supFanAvailSched = fan->availSched;
371 : }
372 : // A6 :Fan Place
373 12 : thisOutAirUnit.supFanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, state.dataIPShortCut->cAlphaArgs(6)));
374 :
375 : // A7
376 :
377 12 : 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 12 : } else if (!lAlphaBlanks(7)) {
386 12 : thisOutAirUnit.ExtFanName = state.dataIPShortCut->cAlphaArgs(7);
387 12 : GlobalNames::IntraObjUniquenessCheck(state,
388 12 : state.dataIPShortCut->cAlphaArgs(7),
389 : CurrentModuleObject,
390 12 : cAlphaFields(7),
391 12 : state.dataOutdoorAirUnit->ExhaustFanUniqueNames,
392 : ErrorsFound);
393 :
394 12 : 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 12 : auto *fan = state.dataFans->fans(thisOutAirUnit.ExtFan_Index);
399 12 : thisOutAirUnit.extFanType = fan->type;
400 12 : thisOutAirUnit.EFanMaxAirVolFlow = fan->maxAirFlowRate;
401 12 : thisOutAirUnit.extFanAvailSched = fan->availSched;
402 : }
403 12 : thisOutAirUnit.ExtFan = true;
404 : }
405 :
406 : // N2
407 12 : thisOutAirUnit.ExtAirVolFlow = NumArray(2);
408 12 : if ((thisOutAirUnit.ExtFan) && (!state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance)) {
409 12 : 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 12 : if (thisOutAirUnit.ExtFan) {
423 12 : if (lAlphaBlanks(8)) {
424 0 : ShowSevereEmptyField(state, eoh, cAlphaFields(8));
425 0 : ErrorsFound = true;
426 12 : } 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 12 : } 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 24 : SetUpCompSets(
445 12 : state, CurrentModuleObject, thisOutAirUnit.Name, "UNDEFINED", state.dataIPShortCut->cAlphaArgs(7), "UNDEFINED", "UNDEFINED");
446 : }
447 :
448 : // Process the unit control type
449 12 : if (lAlphaBlanks(9)) {
450 0 : ShowWarningEmptyField(state, eoh, cAlphaFields(9), "Control reset to Unconditioned Control.");
451 0 : thisOutAirUnit.controlType = OAUnitCtrlType::Neutral;
452 : } else {
453 12 : constexpr std::array<std::string_view, (int)OAUnitCtrlType::Num> ctrlTypeNamesUC = {
454 : "NEUTRALCONTROL", "INVALID-UNCONDITIONED", "TEMPERATURECONTROL"};
455 12 : OAUnitCtrlType tmpCtrlType = static_cast<OAUnitCtrlType>(getEnumValue(ctrlTypeNamesUC, state.dataIPShortCut->cAlphaArgs(9)));
456 12 : if (tmpCtrlType == OAUnitCtrlType::Invalid) {
457 0 : ShowWarningEmptyField(state, eoh, cAlphaFields(9), "Control reset to Unconditioned Control.");
458 12 : } else if (tmpCtrlType == OAUnitCtrlType::Neutral || tmpCtrlType == OAUnitCtrlType::Temperature) {
459 12 : thisOutAirUnit.controlType = tmpCtrlType;
460 : }
461 : }
462 :
463 : // A10:High Control Temp :
464 12 : if (lAlphaBlanks(10)) {
465 6 : } 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 12 : if (lAlphaBlanks(11)) {
472 6 : } 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 12 : thisOutAirUnit.CompOutSetTemp = 0.0;
478 :
479 : // A12~A15 : Node Condition
480 :
481 : // Main air nodes (except outside air node):
482 :
483 12 : thisOutAirUnit.AirOutletNode = GetOnlySingleNode(state,
484 12 : state.dataIPShortCut->cAlphaArgs(13),
485 : ErrorsFound,
486 : DataLoopNode::ConnectionObjectType::ZoneHVACOutdoorAirUnit,
487 12 : state.dataIPShortCut->cAlphaArgs(1),
488 : DataLoopNode::NodeFluidType::Air,
489 : DataLoopNode::ConnectionType::Outlet,
490 : NodeInputManager::CompFluidStream::Primary,
491 : ObjectIsParent);
492 12 : if (!lAlphaBlanks(14)) {
493 24 : thisOutAirUnit.AirInletNode = GetOnlySingleNode(state,
494 12 : state.dataIPShortCut->cAlphaArgs(14),
495 : ErrorsFound,
496 : DataLoopNode::ConnectionObjectType::ZoneHVACOutdoorAirUnit,
497 12 : 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 12 : thisOutAirUnit.SFanOutletNode = GetOnlySingleNode(state,
514 12 : state.dataIPShortCut->cAlphaArgs(15),
515 : ErrorsFound,
516 : DataLoopNode::ConnectionObjectType::ZoneHVACOutdoorAirUnit,
517 12 : 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 12 : thisOutAirUnit.OutsideAirNode = GetOnlySingleNode(state,
525 12 : state.dataIPShortCut->cAlphaArgs(12),
526 : ErrorsFound,
527 : DataLoopNode::ConnectionObjectType::ZoneHVACOutdoorAirUnit,
528 12 : state.dataIPShortCut->cAlphaArgs(1),
529 : DataLoopNode::NodeFluidType::Air,
530 : DataLoopNode::ConnectionType::OutsideAirReference,
531 : NodeInputManager::CompFluidStream::Primary,
532 : ObjectIsNotParent);
533 :
534 12 : if (!lAlphaBlanks(12)) {
535 12 : CheckAndAddAirNodeNumber(state, thisOutAirUnit.OutsideAirNode, IsValid);
536 12 : 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 12 : if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::BlowThru) {
548 12 : SetUpCompSets(state,
549 : CurrentModuleObject,
550 : thisOutAirUnit.Name,
551 : "UNDEFINED",
552 6 : state.dataIPShortCut->cAlphaArgs(5),
553 6 : state.dataIPShortCut->cAlphaArgs(12),
554 6 : state.dataIPShortCut->cAlphaArgs(15));
555 : }
556 :
557 : // A16 : component list
558 :
559 12 : GlobalNames::IntraObjUniquenessCheck(state,
560 12 : state.dataIPShortCut->cAlphaArgs(16),
561 : CurrentModuleObject,
562 12 : cAlphaFields(16),
563 12 : state.dataOutdoorAirUnit->ComponentListUniqueNames,
564 : ErrorsFound);
565 12 : std::string const ComponentListName = state.dataIPShortCut->cAlphaArgs(16);
566 12 : thisOutAirUnit.ComponentListName = ComponentListName;
567 12 : if (!lAlphaBlanks(16)) {
568 12 : int const ListNum = state.dataInputProcessing->inputProcessor->getObjectItemNum(state, ZoneHVACEqList, ComponentListName);
569 12 : if (ListNum > 0) {
570 12 : state.dataInputProcessing->inputProcessor->getObjectItem(
571 : state, ZoneHVACEqList, ListNum, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
572 12 : int NumInList = (NumAlphas - 1) / 2; // potential problem if puts in type but not name
573 12 : if (mod(NumAlphas - 1, 2) != 0) {
574 0 : ++NumInList;
575 : }
576 12 : thisOutAirUnit.NumComponents = NumInList;
577 12 : thisOutAirUnit.OAEquip.allocate(NumInList);
578 :
579 : // Get information of component
580 51 : for (int InListNum = 1; InListNum <= NumInList; ++InListNum) {
581 39 : thisOutAirUnit.OAEquip(InListNum).ComponentName = AlphArray(InListNum * 2 + 1);
582 :
583 78 : thisOutAirUnit.OAEquip(InListNum).Type =
584 39 : static_cast<CompType>(getEnumValue(CompTypeNamesUC, Util::makeUPPER(AlphArray(InListNum * 2))));
585 :
586 39 : int const CompNum = InListNum;
587 :
588 : // Coil Types
589 39 : switch (thisOutAirUnit.OAEquip(InListNum).Type) {
590 6 : case CompType::WaterCoil_Cooling: {
591 6 : thisOutAirUnit.OAEquip(CompNum).CoilType = DataPlant::PlantEquipmentType::CoilWaterCooling;
592 12 : thisOutAirUnit.OAEquip(CompNum).ComponentIndex =
593 6 : GetWaterCoilIndex(state,
594 6 : CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
595 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
596 : ErrorsFound);
597 12 : thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
598 6 : WaterCoils::GetCoilInletNode(state,
599 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
600 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
601 : ErrorsFound);
602 12 : thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
603 6 : WaterCoils::GetCoilOutletNode(state,
604 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
605 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
606 : ErrorsFound);
607 12 : thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode =
608 6 : GetCoilWaterInletNode(state,
609 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
610 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
611 : ErrorsFound);
612 12 : thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
613 6 : GetCoilWaterOutletNode(state,
614 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
615 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
616 : ErrorsFound);
617 12 : thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow =
618 6 : WaterCoils::GetCoilMaxWaterFlowRate(state,
619 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
620 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
621 : ErrorsFound);
622 6 : thisOutAirUnit.OAEquip(CompNum).MinVolWaterFlow = 0.0;
623 6 : break;
624 : }
625 6 : case CompType::WaterCoil_SimpleHeat: {
626 6 : thisOutAirUnit.OAEquip(CompNum).CoilType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
627 12 : thisOutAirUnit.OAEquip(CompNum).ComponentIndex =
628 6 : GetWaterCoilIndex(state,
629 6 : CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
630 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
631 : ErrorsFound);
632 12 : thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
633 6 : WaterCoils::GetCoilInletNode(state,
634 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
635 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
636 : ErrorsFound);
637 6 : thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode = WaterCoils::GetCoilOutletNode(
638 6 : state, "Coil:Heating:Water", thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
639 12 : thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode =
640 6 : GetCoilWaterInletNode(state,
641 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
642 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
643 : ErrorsFound);
644 12 : thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
645 6 : GetCoilWaterOutletNode(state,
646 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
647 6 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
648 : ErrorsFound);
649 6 : thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow = WaterCoils::GetCoilMaxWaterFlowRate(
650 6 : state, "Coil:Heating:Water", thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
651 6 : thisOutAirUnit.OAEquip(CompNum).MinVolWaterFlow = 0.0;
652 6 : break;
653 : }
654 0 : case CompType::SteamCoil_AirHeat: {
655 0 : thisOutAirUnit.OAEquip(CompNum).CoilType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
656 0 : thisOutAirUnit.OAEquip(CompNum).ComponentIndex =
657 0 : GetSteamCoilIndex(state,
658 0 : CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
659 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
660 : ErrorsFound);
661 0 : thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode = GetCoilAirInletNode(
662 0 : state, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
663 0 : thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode = GetCoilAirOutletNode(
664 0 : state, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
665 0 : thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode = GetCoilSteamInletNode(
666 0 : state, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
667 0 : thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
668 0 : GetCoilSteamOutletNode(state,
669 0 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
670 0 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
671 : ErrorsFound);
672 :
673 0 : thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow =
674 0 : GetCoilMaxSteamFlowRate(state, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, ErrorsFound);
675 0 : 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 0 : thisOutAirUnit.OAEquip(CompNum).FluidIndex = Fluid::GetRefrigNum(state, "STEAM");
679 0 : 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 4 : case CompType::Coil_ElectricHeat: {
746 : // Get OutAirUnit( OAUnitNum ).OAEquip( CompNum ).ComponentIndex, 2 types of mining functions to choose from
747 4 : HeatingCoils::GetCoilIndex(
748 4 : state, thisOutAirUnit.OAEquip(CompNum).ComponentName, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, ErrorsFound);
749 8 : thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
750 4 : HeatingCoils::GetCoilInletNode(state,
751 4 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
752 4 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
753 : ErrorsFound);
754 8 : thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
755 4 : HeatingCoils::GetCoilOutletNode(state,
756 4 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
757 4 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
758 : ErrorsFound);
759 4 : break;
760 : }
761 2 : case CompType::Coil_GasHeat: {
762 : // Get OutAirUnit( OAUnitNum ).OAEquip( CompNum ).ComponentIndex, 2 types of mining functions to choose from
763 2 : HeatingCoils::GetCoilIndex(
764 2 : state, thisOutAirUnit.OAEquip(CompNum).ComponentName, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, ErrorsFound);
765 4 : thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
766 2 : GetCoilInletNode(state,
767 2 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
768 2 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
769 : ErrorsFound);
770 4 : thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
771 2 : GetCoilOutletNode(state,
772 2 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
773 2 : thisOutAirUnit.OAEquip(CompNum).ComponentName,
774 : ErrorsFound);
775 2 : break;
776 : }
777 8 : 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 8 : break;
782 : }
783 1 : case CompType::DXHeatPumpSystem: {
784 1 : 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 10 : case CompType::HeatXchngrFP:
797 : case CompType::HeatXchngrSL: {
798 : // CASE('HEATEXCHANGER:DESICCANT:BALANCEDFLOW')
799 : // thisOutAirUnit%OAEquip(CompNum)%Type= CompType::HeatXchngr
800 :
801 : // Desiccant Dehumidifier
802 10 : break;
803 : }
804 2 : case CompType::Desiccant: {
805 : // Future Enhancement
806 : // CASE('DEHUMIDIFIER:DESICCANT:SYSTEM')
807 : // thisOutAirUnit%OAEquip(CompNum)%Type= CompType::Desiccant
808 2 : 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 39 : if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::BlowThru) {
823 22 : if (InListNum == 1) { // the component is the first one
824 12 : SetUpCompSets(state,
825 : "ZoneHVAC:OutdoorAirUnit",
826 : thisOutAirUnit.Name,
827 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
828 6 : thisOutAirUnit.OAEquip(InListNum).ComponentName,
829 6 : state.dataIPShortCut->cAlphaArgs(15),
830 : "UNDEFINED");
831 16 : } else if (InListNum != NumInList) { // the component is placed in b/w components
832 20 : SetUpCompSets(state,
833 : "ZoneHVAC:OutdoorAirUnit",
834 : thisOutAirUnit.Name,
835 10 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
836 10 : thisOutAirUnit.OAEquip(InListNum).ComponentName,
837 : "UNDEFINED",
838 : "UNDEFINED");
839 : } else { // (InListNum == NumInList) => the component is the last one
840 18 : SetUpCompSets(state,
841 : "ZoneHVAC:OutdoorAirUnit",
842 : thisOutAirUnit.Name,
843 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
844 6 : thisOutAirUnit.OAEquip(InListNum).ComponentName,
845 : "UNDEFINED",
846 6 : state.dataIPShortCut->cAlphaArgs(13));
847 : }
848 : // If fan is on the end of equipment.
849 17 : } else if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
850 17 : if (InListNum == 1) {
851 12 : SetUpCompSets(state,
852 : "ZoneHVAC:OutdoorAirUnit",
853 : thisOutAirUnit.Name,
854 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
855 6 : thisOutAirUnit.OAEquip(InListNum).ComponentName,
856 6 : state.dataIPShortCut->cAlphaArgs(12),
857 : "UNDEFINED");
858 11 : } else if (InListNum != NumInList) {
859 10 : SetUpCompSets(state,
860 : "ZoneHVAC:OutdoorAirUnit",
861 : thisOutAirUnit.Name,
862 5 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
863 5 : thisOutAirUnit.OAEquip(InListNum).ComponentName,
864 : "UNDEFINED",
865 : "UNDEFINED");
866 : } else { // (InListNum == NumInList) => the component is the last one
867 12 : SetUpCompSets(state,
868 : "ZoneHVAC:OutdoorAirUnit",
869 : thisOutAirUnit.Name,
870 6 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
871 6 : 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 39 : if (CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)] == "COILSYSTEM:COOLING:DX") {
878 8 : UnitarySystems::UnitarySys::checkUnitarySysCoilInOASysExists(
879 8 : 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 12 : if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
885 18 : SetUpCompSets(state,
886 : CurrentModuleObject,
887 : thisOutAirUnit.Name,
888 : "UNDEFINED",
889 6 : state.dataIPShortCut->cAlphaArgs(5),
890 : "UNDEFINED",
891 6 : 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 12 : if (!lAlphaBlanks(17)) {
912 0 : thisOutAirUnit.AvailManagerListName = state.dataIPShortCut->cAlphaArgs(17);
913 : }
914 12 : }
915 :
916 2 : if (ErrorsFound) {
917 0 : ShowFatalError(state, format("{}Errors found in getting {}.", RoutineName, CurrentModuleObject));
918 : }
919 :
920 2 : AlphArray.deallocate();
921 2 : cAlphaFields.deallocate();
922 2 : NumArray.deallocate();
923 2 : cNumericFields.deallocate();
924 2 : lAlphaBlanks.deallocate();
925 2 : lNumericBlanks.deallocate();
926 :
927 2 : state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
928 :
929 : // Setup Report variables for the zone outdoor air unit CurrentModuleObject='ZoneHVAC:OutdoorAirUnit'
930 14 : for (int OAUnitNum = 1; OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits; ++OAUnitNum) {
931 :
932 12 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
933 :
934 24 : SetupOutputVariable(state,
935 : "Zone Outdoor Air Unit Total Heating Rate",
936 : Constant::Units::W,
937 12 : thisOutAirUnit.TotHeatingRate,
938 : OutputProcessor::TimeStepType::System,
939 : OutputProcessor::StoreType::Average,
940 12 : thisOutAirUnit.Name);
941 24 : SetupOutputVariable(state,
942 : "Zone Outdoor Air Unit Total Heating Energy",
943 : Constant::Units::J,
944 12 : thisOutAirUnit.TotHeatingEnergy,
945 : OutputProcessor::TimeStepType::System,
946 : OutputProcessor::StoreType::Sum,
947 12 : thisOutAirUnit.Name);
948 24 : SetupOutputVariable(state,
949 : "Zone Outdoor Air Unit Sensible Heating Rate",
950 : Constant::Units::W,
951 12 : thisOutAirUnit.SensHeatingRate,
952 : OutputProcessor::TimeStepType::System,
953 : OutputProcessor::StoreType::Average,
954 12 : thisOutAirUnit.Name);
955 24 : SetupOutputVariable(state,
956 : "Zone Outdoor Air Unit Sensible Heating Energy",
957 : Constant::Units::J,
958 12 : thisOutAirUnit.SensHeatingEnergy,
959 : OutputProcessor::TimeStepType::System,
960 : OutputProcessor::StoreType::Sum,
961 12 : thisOutAirUnit.Name);
962 24 : SetupOutputVariable(state,
963 : "Zone Outdoor Air Unit Latent Heating Rate",
964 : Constant::Units::W,
965 12 : thisOutAirUnit.LatHeatingRate,
966 : OutputProcessor::TimeStepType::System,
967 : OutputProcessor::StoreType::Average,
968 12 : thisOutAirUnit.Name);
969 24 : SetupOutputVariable(state,
970 : "Zone Outdoor Air Unit Latent Heating Energy",
971 : Constant::Units::J,
972 12 : thisOutAirUnit.LatHeatingEnergy,
973 : OutputProcessor::TimeStepType::System,
974 : OutputProcessor::StoreType::Sum,
975 12 : thisOutAirUnit.Name);
976 24 : SetupOutputVariable(state,
977 : "Zone Outdoor Air Unit Total Cooling Rate",
978 : Constant::Units::W,
979 12 : thisOutAirUnit.TotCoolingRate,
980 : OutputProcessor::TimeStepType::System,
981 : OutputProcessor::StoreType::Average,
982 12 : thisOutAirUnit.Name);
983 24 : SetupOutputVariable(state,
984 : "Zone Outdoor Air Unit Total Cooling Energy",
985 : Constant::Units::J,
986 12 : thisOutAirUnit.TotCoolingEnergy,
987 : OutputProcessor::TimeStepType::System,
988 : OutputProcessor::StoreType::Sum,
989 12 : thisOutAirUnit.Name);
990 24 : SetupOutputVariable(state,
991 : "Zone Outdoor Air Unit Sensible Cooling Rate",
992 : Constant::Units::W,
993 12 : thisOutAirUnit.SensCoolingRate,
994 : OutputProcessor::TimeStepType::System,
995 : OutputProcessor::StoreType::Average,
996 12 : thisOutAirUnit.Name);
997 24 : SetupOutputVariable(state,
998 : "Zone Outdoor Air Unit Sensible Cooling Energy",
999 : Constant::Units::J,
1000 12 : thisOutAirUnit.SensCoolingEnergy,
1001 : OutputProcessor::TimeStepType::System,
1002 : OutputProcessor::StoreType::Sum,
1003 12 : thisOutAirUnit.Name);
1004 24 : SetupOutputVariable(state,
1005 : "Zone Outdoor Air Unit Latent Cooling Rate",
1006 : Constant::Units::W,
1007 12 : thisOutAirUnit.LatCoolingRate,
1008 : OutputProcessor::TimeStepType::System,
1009 : OutputProcessor::StoreType::Average,
1010 12 : thisOutAirUnit.Name);
1011 24 : SetupOutputVariable(state,
1012 : "Zone Outdoor Air Unit Latent Cooling Energy",
1013 : Constant::Units::J,
1014 12 : thisOutAirUnit.LatCoolingEnergy,
1015 : OutputProcessor::TimeStepType::System,
1016 : OutputProcessor::StoreType::Sum,
1017 12 : thisOutAirUnit.Name);
1018 24 : SetupOutputVariable(state,
1019 : "Zone Outdoor Air Unit Air Mass Flow Rate",
1020 : Constant::Units::kg_s,
1021 12 : thisOutAirUnit.AirMassFlow,
1022 : OutputProcessor::TimeStepType::System,
1023 : OutputProcessor::StoreType::Average,
1024 12 : thisOutAirUnit.Name);
1025 24 : SetupOutputVariable(state,
1026 : "Zone Outdoor Air Unit Fan Electricity Rate",
1027 : Constant::Units::W,
1028 12 : thisOutAirUnit.ElecFanRate,
1029 : OutputProcessor::TimeStepType::System,
1030 : OutputProcessor::StoreType::Average,
1031 12 : thisOutAirUnit.Name);
1032 24 : SetupOutputVariable(state,
1033 : "Zone Outdoor Air Unit Fan Electricity Energy",
1034 : Constant::Units::J,
1035 12 : thisOutAirUnit.ElecFanEnergy,
1036 : OutputProcessor::TimeStepType::System,
1037 : OutputProcessor::StoreType::Sum,
1038 12 : thisOutAirUnit.Name);
1039 12 : SetupOutputVariable(state,
1040 : "Zone Outdoor Air Unit Fan Availability Status",
1041 : Constant::Units::None,
1042 12 : (int &)thisOutAirUnit.availStatus,
1043 : OutputProcessor::TimeStepType::System,
1044 : OutputProcessor::StoreType::Average,
1045 12 : 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 2 : }
1049 :
1050 64806 : 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 64806 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
1089 :
1090 64806 : Real64 const RhoAir = state.dataEnvrn->StdRhoAir;
1091 64806 : int const InNode = thisOutAirUnit.AirInletNode;
1092 64806 : int const OutNode = thisOutAirUnit.AirOutletNode;
1093 64806 : int const OutsideAirNode = thisOutAirUnit.OutsideAirNode;
1094 64806 : Real64 const OAFrac = thisOutAirUnit.outAirSched->getCurrentVal();
1095 :
1096 64806 : if (state.dataOutdoorAirUnit->MyOneTimeFlag) {
1097 :
1098 2 : state.dataOutdoorAirUnit->MyEnvrnFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
1099 2 : state.dataOutdoorAirUnit->MySizeFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
1100 2 : state.dataOutdoorAirUnit->MyPlantScanFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
1101 2 : state.dataOutdoorAirUnit->MyZoneEqFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
1102 2 : state.dataOutdoorAirUnit->MyOneTimeFlag = false;
1103 : }
1104 :
1105 64806 : if (allocated(state.dataAvail->ZoneComp)) {
1106 64806 : auto &availMgr = state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::OutdoorAirUnit).ZoneCompAvailMgrs(OAUnitNum);
1107 64806 : if (state.dataOutdoorAirUnit->MyZoneEqFlag(OAUnitNum)) { // initialize the name of each availability manager list and zone number
1108 12 : availMgr.AvailManagerListName = thisOutAirUnit.AvailManagerListName;
1109 12 : availMgr.ZoneNum = ZoneNum;
1110 12 : state.dataOutdoorAirUnit->MyZoneEqFlag(OAUnitNum) = false;
1111 : }
1112 64806 : thisOutAirUnit.availStatus = availMgr.availStatus;
1113 : }
1114 :
1115 64806 : if (state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum) && allocated(state.dataPlnt->PlantLoop)) {
1116 51 : for (int compLoop = 1; compLoop <= thisOutAirUnit.NumComponents; ++compLoop) {
1117 :
1118 39 : CompType const Type = thisOutAirUnit.OAEquip(compLoop).Type;
1119 :
1120 39 : switch (Type) {
1121 12 : case CompType::WaterCoil_Cooling:
1122 : case CompType::WaterCoil_DetailedCool:
1123 : case CompType::WaterCoil_SimpleHeat:
1124 : case CompType::SteamCoil_AirHeat:
1125 :
1126 : {
1127 12 : bool errFlag = false;
1128 24 : ScanPlantLoopsForObject(state,
1129 12 : thisOutAirUnit.OAEquip(compLoop).ComponentName,
1130 12 : thisOutAirUnit.OAEquip(compLoop).CoilType,
1131 12 : thisOutAirUnit.OAEquip(compLoop).plantLoc,
1132 : errFlag,
1133 : _,
1134 : _,
1135 : _,
1136 : _,
1137 : _);
1138 12 : if (errFlag) {
1139 0 : ShowFatalError(state, "InitOutdoorAirUnit: Program terminated for previous conditions.");
1140 : }
1141 12 : break;
1142 : }
1143 27 : default:
1144 27 : break;
1145 : }
1146 : }
1147 :
1148 12 : state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum) = false;
1149 64794 : } else if (state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum) && !state.dataGlobal->AnyPlantInModel) {
1150 0 : 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 64806 : if (!state.dataOutdoorAirUnit->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
1155 2 : state.dataOutdoorAirUnit->ZoneEquipmentListChecked = true;
1156 14 : for (int Loop = 1; Loop <= state.dataOutdoorAirUnit->NumOfOAUnits; ++Loop) {
1157 12 : if (CheckZoneEquipmentList(state, CurrentModuleObject, state.dataOutdoorAirUnit->OutAirUnit(Loop).Name)) {
1158 12 : 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 64818 : if (!state.dataGlobal->SysSizingCalc && state.dataOutdoorAirUnit->MySizeFlag(OAUnitNum) &&
1169 12 : !state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum)) {
1170 :
1171 12 : SizeOutdoorAirUnit(state, OAUnitNum);
1172 :
1173 12 : state.dataOutdoorAirUnit->MySizeFlag(OAUnitNum) = false;
1174 : }
1175 :
1176 : // Do the one time initializations
1177 64806 : if (state.dataGlobal->BeginEnvrnFlag && state.dataOutdoorAirUnit->MyEnvrnFlag(OAUnitNum)) {
1178 : // Node Conditions
1179 72 : thisOutAirUnit.OutAirMassFlow = RhoAir * OAFrac * thisOutAirUnit.OutAirVolFlow;
1180 72 : thisOutAirUnit.SMaxAirMassFlow = RhoAir * OAFrac * thisOutAirUnit.SFanMaxAirVolFlow;
1181 :
1182 72 : if (thisOutAirUnit.ExtFan) {
1183 : // set the exhaust air mass flow rate from input
1184 72 : Real64 const EAFrac = thisOutAirUnit.extAirSched->getCurrentVal();
1185 72 : thisOutAirUnit.ExtAirMassFlow = RhoAir * EAFrac * thisOutAirUnit.ExtAirVolFlow;
1186 72 : thisOutAirUnit.EMaxAirMassFlow = RhoAir * EAFrac * thisOutAirUnit.EFanMaxAirVolFlow;
1187 :
1188 72 : state.dataLoopNodes->Node(InNode).MassFlowRateMax = thisOutAirUnit.EMaxAirMassFlow;
1189 72 : state.dataLoopNodes->Node(InNode).MassFlowRateMin = 0.0;
1190 : }
1191 : // set the node max and min mass flow rates
1192 72 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMax = thisOutAirUnit.SMaxAirMassFlow;
1193 72 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMin = 0.0;
1194 72 : state.dataLoopNodes->Node(OutNode).MassFlowRate = thisOutAirUnit.EMaxAirMassFlow;
1195 :
1196 72 : if (!state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum)) {
1197 72 : bool errFlag = false;
1198 306 : for (int compLoop = 1; compLoop <= thisOutAirUnit.NumComponents; ++compLoop) {
1199 432 : if ((thisOutAirUnit.OAEquip(compLoop).Type == CompType::WaterCoil_Cooling) ||
1200 198 : (thisOutAirUnit.OAEquip(compLoop).Type == CompType::WaterCoil_DetailedCool)) {
1201 72 : thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow =
1202 36 : WaterCoils::GetCoilMaxWaterFlowRate(state,
1203 36 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(compLoop).Type)],
1204 36 : thisOutAirUnit.OAEquip(compLoop).ComponentName,
1205 : errFlag);
1206 36 : Real64 const rho = state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum)
1207 36 : .glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
1208 36 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow;
1209 36 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MinVolWaterFlow;
1210 144 : InitComponentNodes(state,
1211 36 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow,
1212 36 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow,
1213 36 : thisOutAirUnit.OAEquip(compLoop).CoilWaterInletNode,
1214 36 : thisOutAirUnit.OAEquip(compLoop).CoilWaterOutletNode);
1215 : }
1216 :
1217 234 : if (thisOutAirUnit.OAEquip(compLoop).Type == CompType::WaterCoil_SimpleHeat) {
1218 72 : thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow =
1219 36 : WaterCoils::GetCoilMaxWaterFlowRate(state,
1220 36 : CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(compLoop).Type)],
1221 36 : thisOutAirUnit.OAEquip(compLoop).ComponentName,
1222 : errFlag);
1223 36 : Real64 const rho = state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum)
1224 36 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
1225 36 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow;
1226 36 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MinVolWaterFlow;
1227 144 : InitComponentNodes(state,
1228 36 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow,
1229 36 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow,
1230 36 : thisOutAirUnit.OAEquip(compLoop).CoilWaterInletNode,
1231 36 : thisOutAirUnit.OAEquip(compLoop).CoilWaterOutletNode);
1232 : }
1233 234 : if (thisOutAirUnit.OAEquip(compLoop).Type == CompType::SteamCoil_AirHeat) {
1234 0 : thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow =
1235 0 : GetCoilMaxSteamFlowRate(state, thisOutAirUnit.OAEquip(compLoop).ComponentIndex, errFlag);
1236 0 : Real64 const rho = state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum)
1237 0 : .steam->getSatDensity(state, Constant::SteamInitConvTemp, 1.0, RoutineName);
1238 0 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow;
1239 0 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MinVolWaterFlow;
1240 0 : InitComponentNodes(state,
1241 0 : thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow,
1242 0 : thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow,
1243 0 : thisOutAirUnit.OAEquip(compLoop).CoilWaterInletNode,
1244 0 : thisOutAirUnit.OAEquip(compLoop).CoilWaterOutletNode);
1245 : }
1246 234 : 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 72 : state.dataOutdoorAirUnit->MyEnvrnFlag(OAUnitNum) = false;
1265 :
1266 : } // ...end start of environment inits
1267 :
1268 64806 : if (!state.dataGlobal->BeginEnvrnFlag) {
1269 63816 : state.dataOutdoorAirUnit->MyEnvrnFlag(OAUnitNum) = true;
1270 : }
1271 :
1272 : // These initializations are done every iteration...
1273 : // Set all the output variable
1274 64806 : thisOutAirUnit.TotHeatingRate = 0.0;
1275 64806 : thisOutAirUnit.SensHeatingRate = 0.0;
1276 64806 : thisOutAirUnit.LatHeatingRate = 0.0;
1277 64806 : thisOutAirUnit.TotCoolingRate = 0.0;
1278 64806 : thisOutAirUnit.SensCoolingRate = 0.0;
1279 64806 : thisOutAirUnit.LatCoolingRate = 0.0;
1280 64806 : thisOutAirUnit.AirMassFlow = 0.0;
1281 64806 : thisOutAirUnit.ElecFanRate = 0.0;
1282 : // Node Set
1283 :
1284 : // set the mass flow rates from the input volume flow rates
1285 64806 : if (OAFrac > 0.0 || (state.dataHVACGlobal->TurnFansOn && !state.dataHVACGlobal->TurnFansOff)) { // fan is available
1286 63524 : thisOutAirUnit.OutAirMassFlow = RhoAir * OAFrac * thisOutAirUnit.OutAirVolFlow;
1287 : } else {
1288 1282 : thisOutAirUnit.OutAirMassFlow = 0.0;
1289 : }
1290 :
1291 : // set the exhaust air mass flow rate from input
1292 64806 : if (thisOutAirUnit.ExtFan) {
1293 64806 : if (thisOutAirUnit.extFanAvailSched != nullptr) {
1294 64806 : thisOutAirUnit.ExtAirMassFlow = RhoAir * thisOutAirUnit.ExtAirVolFlow * thisOutAirUnit.extAirSched->getCurrentVal();
1295 : } else {
1296 0 : thisOutAirUnit.ExtAirMassFlow = 0.0;
1297 : }
1298 64806 : state.dataLoopNodes->Node(InNode).MassFlowRate = thisOutAirUnit.ExtAirMassFlow;
1299 64806 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail = thisOutAirUnit.ExtAirMassFlow;
1300 64806 : 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 64806 : state.dataLoopNodes->Node(OutNode).MassFlowRate = thisOutAirUnit.OutAirMassFlow;
1308 64806 : state.dataLoopNodes->Node(OutNode).MassFlowRateMaxAvail = thisOutAirUnit.OutAirMassFlow;
1309 64806 : state.dataLoopNodes->Node(OutNode).MassFlowRateMinAvail = 0.0;
1310 64806 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = thisOutAirUnit.OutAirMassFlow;
1311 64806 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMaxAvail = thisOutAirUnit.OutAirMassFlow;
1312 64806 : 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 64806 : if (thisOutAirUnit.ExtFan) {
1318 64806 : state.dataLoopNodes->Node(OutNode).Temp = state.dataLoopNodes->Node(InNode).Temp;
1319 64806 : state.dataLoopNodes->Node(OutNode).Press = state.dataLoopNodes->Node(InNode).Press;
1320 64806 : state.dataLoopNodes->Node(OutNode).HumRat = state.dataLoopNodes->Node(InNode).HumRat;
1321 64806 : 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 64806 : if (FirstHVACIteration || state.dataHVACGlobal->ShortenTimeStepSys) {
1330 : // Initialize the outside air conditions...
1331 37602 : state.dataLoopNodes->Node(OutsideAirNode).Temp = state.dataLoopNodes->Node(OutsideAirNode).OutAirDryBulb;
1332 37602 : state.dataLoopNodes->Node(OutsideAirNode).HumRat = state.dataEnvrn->OutHumRat;
1333 37602 : state.dataLoopNodes->Node(OutsideAirNode).Press = state.dataEnvrn->OutBaroPress;
1334 : }
1335 64806 : }
1336 :
1337 12 : 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 12 : bool IsAutoSize = false; // Indicator to autosize
1364 12 : Real64 OutAirVolFlowDes = 0.0; // Autosized outdoor air flow for reporting
1365 12 : Real64 OutAirVolFlowUser = 0.0; // Hardsized outdoor air flow for reporting
1366 12 : Real64 ExtAirVolFlowDes = 0.0; // Autosized exhaust air flow for reporting
1367 12 : Real64 ExtAirVolFlowUser = 0.0; // Hardsized exhaust air flow for reporting
1368 :
1369 12 : bool ErrorsFound = false;
1370 :
1371 12 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
1372 :
1373 12 : state.dataSize->DataFanType = thisOutAirUnit.supFanType;
1374 12 : state.dataSize->DataFanIndex = thisOutAirUnit.SFan_Index;
1375 12 : state.dataSize->DataFanPlacement = thisOutAirUnit.supFanPlace;
1376 :
1377 12 : if (thisOutAirUnit.OutAirVolFlow == AutoSize) {
1378 5 : IsAutoSize = true;
1379 : }
1380 :
1381 12 : if (state.dataSize->CurZoneEqNum > 0) {
1382 12 : 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 24 : CheckZoneSizing(state, std::string(ZoneHVACOAUnit), thisOutAirUnit.Name);
1389 12 : OutAirVolFlowDes = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
1390 12 : if (OutAirVolFlowDes < SmallAirVolFlow) {
1391 0 : OutAirVolFlowDes = 0.0;
1392 : }
1393 12 : if (IsAutoSize) {
1394 5 : thisOutAirUnit.OutAirVolFlow = OutAirVolFlowDes;
1395 5 : BaseSizer::reportSizerOutput(
1396 : state, ZoneHVACOAUnit, thisOutAirUnit.Name, "Design Size Outdoor Air Flow Rate [m3/s]", OutAirVolFlowDes);
1397 : } else {
1398 7 : if (thisOutAirUnit.OutAirVolFlow > 0.0 && OutAirVolFlowDes > 0.0) {
1399 7 : OutAirVolFlowUser = thisOutAirUnit.OutAirVolFlow;
1400 7 : BaseSizer::reportSizerOutput(
1401 : state, ZoneHVACOAUnit, thisOutAirUnit.Name, "User-Specified Outdoor Air Flow Rate [m3/s]", OutAirVolFlowUser);
1402 7 : 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 12 : IsAutoSize = false;
1421 12 : if (thisOutAirUnit.ExtAirVolFlow == AutoSize) {
1422 5 : IsAutoSize = true;
1423 : }
1424 12 : if (state.dataSize->CurZoneEqNum > 0) {
1425 12 : 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 12 : ExtAirVolFlowDes = thisOutAirUnit.OutAirVolFlow;
1433 12 : if (IsAutoSize) {
1434 5 : thisOutAirUnit.ExtAirVolFlow = ExtAirVolFlowDes;
1435 5 : BaseSizer::reportSizerOutput(
1436 : state, ZoneHVACOAUnit, thisOutAirUnit.Name, "Design Size Exhaust Air Flow Rate [m3/s]", ExtAirVolFlowDes);
1437 : } else {
1438 7 : if (thisOutAirUnit.ExtAirVolFlow > 0.0 && ExtAirVolFlowDes > 0.0) {
1439 7 : ExtAirVolFlowUser = thisOutAirUnit.ExtAirVolFlow;
1440 7 : BaseSizer::reportSizerOutput(
1441 : state, ZoneHVACOAUnit, thisOutAirUnit.Name, "User-Specified Exhaust Air Flow Rate [m3/s]", ExtAirVolFlowUser);
1442 7 : 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 12 : state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirFlow = true;
1461 12 : state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingAirFlow = true;
1462 12 : state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirVolFlow = thisOutAirUnit.OutAirVolFlow;
1463 12 : state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingAirVolFlow = thisOutAirUnit.OutAirVolFlow;
1464 12 : state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = thisOutAirUnit.OutAirVolFlow;
1465 :
1466 12 : if (thisOutAirUnit.SFanMaxAirVolFlow == AutoSize) {
1467 5 : state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, true, _, _);
1468 5 : thisOutAirUnit.SFanMaxAirVolFlow = state.dataFans->fans(thisOutAirUnit.SFan_Index)->maxAirFlowRate;
1469 : }
1470 12 : if (thisOutAirUnit.ExtFan) {
1471 12 : if (thisOutAirUnit.EFanMaxAirVolFlow == AutoSize) {
1472 6 : state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->simulate(state, true, _, _);
1473 6 : thisOutAirUnit.EFanMaxAirVolFlow = state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->maxAirFlowRate;
1474 : }
1475 : }
1476 :
1477 51 : for (int CompNum = 1; CompNum <= thisOutAirUnit.NumComponents; ++CompNum) {
1478 39 : auto &thisOAEquip = thisOutAirUnit.OAEquip(CompNum);
1479 39 : if ((thisOAEquip.Type == CompType::WaterCoil_Cooling) || (thisOAEquip.Type == CompType::WaterCoil_DetailedCool)) {
1480 6 : if (thisOAEquip.MaxVolWaterFlow == AutoSize) {
1481 1 : SimulateWaterCoilComponents(state, thisOAEquip.ComponentName, true, thisOAEquip.ComponentIndex, _, HVAC::FanOp::Cycling, 0.0);
1482 : }
1483 : }
1484 39 : if (thisOAEquip.Type == CompType::WaterCoil_SimpleHeat) {
1485 6 : if (thisOAEquip.MaxVolWaterFlow == AutoSize) {
1486 3 : SimulateWaterCoilComponents(state, thisOAEquip.ComponentName, true, thisOAEquip.ComponentIndex, _, HVAC::FanOp::Cycling, 0.0);
1487 : }
1488 : }
1489 39 : if (thisOAEquip.Type == CompType::SteamCoil_AirHeat) {
1490 0 : if (thisOAEquip.MaxVolWaterFlow == AutoSize) {
1491 0 : SimulateSteamCoilComponents(state, thisOAEquip.ComponentName, true, thisOAEquip.ComponentIndex);
1492 : }
1493 : }
1494 39 : 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 12 : if (ErrorsFound) {
1503 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
1504 : }
1505 12 : }
1506 :
1507 64806 : 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 64806 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
1542 :
1543 64806 : auto &TurnFansOff = state.dataHVACGlobal->TurnFansOff;
1544 64806 : 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 64806 : 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 64806 : 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 64806 : int const InletNode = thisOutAirUnit.AirInletNode; // Unit air inlet node, only used if ExtFan
1579 64806 : int const SFanOutletNode = thisOutAirUnit.SFanOutletNode; // Unit supply fan outlet node
1580 64806 : int const OutletNode = thisOutAirUnit.AirOutletNode; // air outlet node
1581 64806 : int const OutsideAirNode = thisOutAirUnit.OutsideAirNode; // outside air node
1582 64806 : OAUnitCtrlType const UnitControlType = thisOutAirUnit.controlType;
1583 :
1584 64806 : thisOutAirUnit.CompOutSetTemp = 0.0;
1585 64806 : thisOutAirUnit.FanEffect = false;
1586 :
1587 193136 : if ((thisOutAirUnit.availSched->getCurrentVal() <= 0) || (thisOutAirUnit.outAirSched->getCurrentVal() <= 0) ||
1588 193136 : ((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 1282 : if (thisOutAirUnit.ExtFan) {
1592 1282 : state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
1593 1282 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = 0.0;
1594 1282 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = 0.0;
1595 : }
1596 1282 : state.dataLoopNodes->Node(SFanOutletNode).MassFlowRate = 0.0;
1597 1282 : state.dataLoopNodes->Node(SFanOutletNode).MassFlowRateMaxAvail = 0.0;
1598 1282 : state.dataLoopNodes->Node(SFanOutletNode).MassFlowRateMinAvail = 0.0;
1599 1282 : state.dataLoopNodes->Node(OutletNode).MassFlowRate = 0.0;
1600 1282 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = 0.0;
1601 1282 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = 0.0;
1602 1282 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = 0.0;
1603 1282 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMaxAvail = 0.0;
1604 1282 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMinAvail = 0.0;
1605 :
1606 : // Node condition
1607 1282 : if (thisOutAirUnit.ExtFan) {
1608 1282 : state.dataLoopNodes->Node(InletNode).Temp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
1609 1282 : 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 1282 : state.dataLoopNodes->Node(OutletNode).Temp = state.dataLoopNodes->Node(SFanOutletNode).Temp;
1614 :
1615 1282 : 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 1282 : } else if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
1624 1282 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1625 1282 : state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _, _);
1626 :
1627 1282 : if (thisOutAirUnit.ExtFan) {
1628 1282 : state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->simulate(state, FirstHVACIteration, _, _);
1629 : }
1630 : }
1631 :
1632 : } else { // System On
1633 :
1634 : // Flowrate Check
1635 63524 : if (state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate > 0.0) {
1636 63524 : state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = thisOutAirUnit.OutAirMassFlow;
1637 : }
1638 :
1639 : // Fan Positioning Check
1640 :
1641 63524 : if (thisOutAirUnit.ExtFan) {
1642 63524 : state.dataLoopNodes->Node(InletNode).MassFlowRate = thisOutAirUnit.ExtAirMassFlow;
1643 : }
1644 :
1645 : // Air mass balance check
1646 63524 : if ((std::abs(thisOutAirUnit.ExtAirMassFlow - thisOutAirUnit.OutAirMassFlow) > 0.001) &&
1647 0 : (!state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance)) {
1648 0 : if (!thisOutAirUnit.FlowError) {
1649 0 : ShowWarningError(state, "Air mass flow between zone supply and exhaust is not balanced. Only the first occurrence is reported.");
1650 0 : ShowContinueError(state, format("Occurs in ZoneHVAC:OutdoorAirUnit Object= {}", thisOutAirUnit.Name));
1651 0 : 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 0 : ShowContinueErrorTimeStamp(state,
1655 0 : format("The outdoor mass flow rate = {:.3R} and the exhaust mass flow rate = {:.3R}.",
1656 0 : thisOutAirUnit.OutAirMassFlow,
1657 0 : thisOutAirUnit.ExtAirMassFlow));
1658 0 : thisOutAirUnit.FlowError = true;
1659 : }
1660 : }
1661 :
1662 63524 : if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::BlowThru) {
1663 32403 : state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _, _);
1664 32403 : DesOATemp = state.dataLoopNodes->Node(SFanOutletNode).Temp;
1665 31121 : } else if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
1666 31121 : DesOATemp = state.dataLoopNodes->Node(OutsideAirNode).Temp;
1667 : }
1668 :
1669 : // Control type check
1670 63524 : switch (UnitControlType) {
1671 31121 : case OAUnitCtrlType::Neutral: {
1672 31121 : SetPointTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
1673 : // Neutral Control Condition
1674 31121 : 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 31121 : if (DesOATemp < SetPointTemp) { // Heating MODE
1681 16710 : thisOutAirUnit.OperatingMode = Operation::HeatingMode;
1682 16710 : AirOutletTemp = SetPointTemp;
1683 16710 : thisOutAirUnit.CompOutSetTemp = AirOutletTemp;
1684 16710 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1685 : } else { // Cooling Mode
1686 14411 : thisOutAirUnit.OperatingMode = Operation::CoolingMode;
1687 14411 : AirOutletTemp = SetPointTemp;
1688 14411 : thisOutAirUnit.CompOutSetTemp = AirOutletTemp;
1689 14411 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1690 : }
1691 : }
1692 : // SetPoint Temperature Condition
1693 31121 : } break;
1694 32403 : case OAUnitCtrlType::Temperature: {
1695 32403 : SetPointTemp = DesOATemp;
1696 32403 : HiCtrlTemp = thisOutAirUnit.hiCtrlTempSched->getCurrentVal();
1697 32403 : LoCtrlTemp = thisOutAirUnit.loCtrlTempSched->getCurrentVal();
1698 32403 : 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 32403 : if (SetPointTemp < LoCtrlTemp) {
1705 13095 : thisOutAirUnit.OperatingMode = Operation::HeatingMode;
1706 13095 : AirOutletTemp = LoCtrlTemp;
1707 13095 : thisOutAirUnit.CompOutSetTemp = AirOutletTemp;
1708 13095 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1709 19308 : } else if (SetPointTemp > HiCtrlTemp) {
1710 19308 : thisOutAirUnit.OperatingMode = Operation::CoolingMode;
1711 19308 : AirOutletTemp = HiCtrlTemp;
1712 19308 : thisOutAirUnit.CompOutSetTemp = AirOutletTemp;
1713 19308 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1714 : }
1715 : }
1716 32403 : } break;
1717 0 : default:
1718 0 : break;
1719 : }
1720 :
1721 : // Fan positioning
1722 63524 : if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
1723 31121 : state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _, _);
1724 :
1725 31121 : thisOutAirUnit.FanEffect = true; // RE-Simulation to take over the supply fan effect
1726 31121 : thisOutAirUnit.FanCorTemp = (state.dataLoopNodes->Node(OutletNode).Temp - thisOutAirUnit.CompOutSetTemp);
1727 31121 : SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
1728 31121 : state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _, _);
1729 31121 : thisOutAirUnit.FanEffect = false;
1730 : }
1731 63524 : if (thisOutAirUnit.ExtFan) {
1732 63524 : state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->simulate(state, FirstHVACIteration, _, _);
1733 : }
1734 : } // ...end of system ON/OFF IF-THEN block
1735 :
1736 64806 : AirMassFlow = state.dataLoopNodes->Node(OutletNode).MassFlowRate;
1737 64806 : MinHumRat = min(state.dataLoopNodes->Node(OutletNode).HumRat, state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).HumRat);
1738 :
1739 64806 : AirInEnt = PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, MinHumRat); // zone supply air node enthalpy
1740 64806 : ZoneAirEnt = PsyHFnTdbW(state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).Temp, MinHumRat); // zone air enthalpy
1741 64806 : QUnitOut = AirMassFlow * (AirInEnt - ZoneAirEnt); // Senscooling
1742 :
1743 : // CR9155 Remove specific humidity calculations
1744 64806 : SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
1745 64806 : SpecHumIn = state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).HumRat;
1746 64806 : LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
1747 :
1748 : ZoneAirEnt =
1749 64806 : PsyHFnTdbW(state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).Temp, state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).HumRat);
1750 :
1751 64806 : ZoneSupAirEnt = PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(OutletNode).HumRat);
1752 64806 : QTotUnitOut = AirMassFlow * (ZoneSupAirEnt - ZoneAirEnt);
1753 64806 : LatLoadMet = QTotUnitOut - QUnitOut; // watts
1754 :
1755 : // Report variables...
1756 :
1757 64806 : if (QUnitOut < 0.0) {
1758 43892 : thisOutAirUnit.SensCoolingRate = std::abs(QUnitOut);
1759 43892 : thisOutAirUnit.SensHeatingRate = 0.0;
1760 : } else {
1761 20914 : thisOutAirUnit.SensCoolingRate = 0.0;
1762 20914 : thisOutAirUnit.SensHeatingRate = QUnitOut;
1763 : }
1764 :
1765 64806 : if (QTotUnitOut < 0.0) {
1766 50319 : thisOutAirUnit.TotCoolingRate = std::abs(QTotUnitOut);
1767 50319 : thisOutAirUnit.TotHeatingRate = 0.0;
1768 : } else {
1769 14487 : thisOutAirUnit.TotCoolingRate = 0.0;
1770 14487 : thisOutAirUnit.TotHeatingRate = QTotUnitOut;
1771 : }
1772 :
1773 64806 : if (LatLoadMet < 0.0) {
1774 45021 : thisOutAirUnit.LatCoolingRate = std::abs(LatLoadMet);
1775 45021 : thisOutAirUnit.LatHeatingRate = 0.0;
1776 : } else {
1777 19785 : thisOutAirUnit.LatCoolingRate = 0.0;
1778 19785 : 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 64806 : thisOutAirUnit.ElecFanRate = 0.0;
1783 64806 : thisOutAirUnit.ElecFanRate += state.dataFans->fans(thisOutAirUnit.SFan_Index)->totalPower;
1784 :
1785 64806 : if (thisOutAirUnit.ExtFan) {
1786 64806 : thisOutAirUnit.ElecFanRate += state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->totalPower;
1787 : }
1788 :
1789 64806 : PowerMet = QUnitOut;
1790 64806 : LatOutputProvided = LatentOutput;
1791 64806 : }
1792 :
1793 95927 : 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 95927 : bool const Sim = true;
1807 :
1808 95927 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
1809 394574 : for (int EquipNum = 1; EquipNum <= thisOutAirUnit.NumComponents; ++EquipNum) {
1810 298647 : auto &thisOAEquip = thisOutAirUnit.OAEquip(EquipNum);
1811 298647 : SimOutdoorAirEquipComps(state,
1812 : OAUnitNum,
1813 298647 : CompTypeNames[static_cast<int>(thisOAEquip.Type)],
1814 298647 : thisOAEquip.ComponentName,
1815 : EquipNum,
1816 : thisOAEquip.Type,
1817 : FirstHVACIteration,
1818 298647 : thisOAEquip.ComponentIndex,
1819 : Sim);
1820 : }
1821 95927 : }
1822 :
1823 298647 : 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 298647 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
1866 298647 : auto &thisOAEquip = thisOutAirUnit.OAEquip(EquipNum);
1867 298647 : int const InletNodeNum = thisOAEquip.CoilAirInletNode;
1868 298647 : int const OutletNodeNum = thisOAEquip.CoilAirOutletNode;
1869 :
1870 298647 : int UnitNum = OAUnitNum;
1871 298647 : int SimCompNum = EquipNum;
1872 :
1873 298647 : Real64 const CompAirOutTemp = thisOutAirUnit.CompOutSetTemp;
1874 298647 : Operation const OpMode = thisOutAirUnit.OperatingMode;
1875 298647 : CompType const EquipTypeNum = thisOAEquip.Type;
1876 298647 : Real64 const OAMassFlow = thisOutAirUnit.OutAirMassFlow;
1877 :
1878 : // check the fan positioning
1879 298647 : bool const DrawFan = thisOutAirUnit.FanEffect;
1880 298647 : Real64 const FanEffect = DrawFan ? thisOutAirUnit.FanCorTemp : 0.0;
1881 :
1882 : // checking equipment index
1883 :
1884 : {
1885 298647 : switch (EquipTypeNum) {
1886 : // Heat recovery
1887 74325 : case CompType::HeatXchngrFP: // 'HeatExchanger:AirToAir:FlatPlate',
1888 : case CompType::HeatXchngrSL: // 'HeatExchanger:AirToAir:SensibleAndLatent',
1889 : // 'HeatExchanger:Desiccant:BalancedFlow' - unused
1890 : {
1891 :
1892 74325 : if (Sim) {
1893 74325 : SimHeatRecovery(state, EquipName, FirstHVACIteration, CompIndex, HVAC::FanOp::Continuous, _, _, _, _, false, false);
1894 : }
1895 74325 : } break;
1896 : // Desiccant Dehumidifier
1897 10801 : case CompType::Desiccant: { // 'Dehumidifier:Desiccant:NoFans'
1898 10801 : if (Sim) {
1899 10801 : SimDesiccantDehumidifier(state, EquipName, FirstHVACIteration, CompIndex);
1900 : }
1901 :
1902 10801 : } break;
1903 52723 : case CompType::WaterCoil_SimpleHeat: { // ('Coil:Heating:Water')
1904 :
1905 52723 : if (Sim) {
1906 52723 : int const ControlNode = thisOAEquip.CoilWaterInletNode;
1907 52723 : MaxWaterFlow = thisOAEquip.MaxWaterMassFlow;
1908 52723 : 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 52723 : if ((!FirstHVACIteration) && (ControlNode > 0)) {
1912 27414 : MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
1913 27414 : MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
1914 : }
1915 52723 : auto const &whCoilInletNode = state.dataLoopNodes->Node(InletNodeNum);
1916 : // auto &whCoilOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
1917 :
1918 52723 : Real64 const CpAirZn = PsyCpAirFnW(whCoilInletNode.HumRat);
1919 :
1920 52723 : if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::CoolingMode) || (whCoilInletNode.Temp > CompAirOutTemp)) {
1921 25296 : QCompReq = 0.0;
1922 : } else {
1923 27427 : QCompReq = CpAirZn * OAMassFlow * ((CompAirOutTemp - whCoilInletNode.Temp) - FanEffect);
1924 27427 : if (std::abs(QCompReq) < SmallLoad) {
1925 450 : QCompReq = 0.0;
1926 : }
1927 27427 : if (QCompReq < 0.0) {
1928 399 : QCompReq = 0.0; // coil can heat only
1929 : }
1930 : }
1931 :
1932 210892 : ControlCompOutput(state,
1933 52723 : thisOutAirUnit.Name,
1934 158169 : std::string(ZoneHVACOAUnit),
1935 : UnitNum,
1936 : FirstHVACIteration,
1937 : QCompReq,
1938 : ControlNode,
1939 : MaxWaterFlow,
1940 : MinWaterFlow,
1941 : 0.0001,
1942 52723 : thisOutAirUnit.ControlCompTypeNum,
1943 52723 : thisOutAirUnit.CompErrIndex,
1944 : _,
1945 : _,
1946 : _,
1947 105446 : 2,
1948 : SimCompNum,
1949 52723 : thisOAEquip.plantLoc);
1950 : }
1951 52723 : } break;
1952 0 : case CompType::SteamCoil_AirHeat: { // 'Coil:Heating:Steam'
1953 0 : if (Sim) {
1954 0 : CalcOAUnitCoilComps(state, UnitNum, FirstHVACIteration, SimCompNum, QUnitOut);
1955 : }
1956 0 : } break;
1957 43204 : case CompType::Coil_ElectricHeat: // 'Coil:Heating:Electric'
1958 : case CompType::Coil_GasHeat: { // 'Coil:Heating:Fuel'
1959 43204 : if (Sim) {
1960 : // stand-alone coils are temperature controlled (do not pass QCoilReq in argument list, QCoilReq overrides temp SP)
1961 43204 : CalcOAUnitCoilComps(state, UnitNum, FirstHVACIteration, SimCompNum, QUnitOut);
1962 : }
1963 43204 : } break;
1964 : // water cooling coil Types
1965 32403 : case CompType::WaterCoil_Cooling: { // 'Coil:Cooling:Water'
1966 32403 : if (Sim) {
1967 32403 : int const ControlNode = thisOAEquip.CoilWaterInletNode;
1968 32403 : MaxWaterFlow = thisOAEquip.MaxWaterMassFlow;
1969 32403 : MinWaterFlow = thisOAEquip.MinWaterMassFlow;
1970 : // On the first HVAC iteration the system values are given to the controller, but after that
1971 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
1972 32403 : if ((!FirstHVACIteration) && (ControlNode > 0)) {
1973 16833 : MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
1974 16833 : MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
1975 : }
1976 :
1977 32403 : auto const &wcCoilInletNode = state.dataLoopNodes->Node(InletNodeNum);
1978 32403 : auto &wcCoilOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
1979 :
1980 32403 : Real64 const CpAirZn = PsyCpAirFnW(wcCoilInletNode.HumRat);
1981 32403 : if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::HeatingMode) || (wcCoilInletNode.Temp < CompAirOutTemp)) {
1982 18433 : QCompReq = 0.0;
1983 18433 : wcCoilOutletNode.Temp = wcCoilInletNode.Temp;
1984 18433 : wcCoilOutletNode.HumRat = wcCoilInletNode.HumRat;
1985 18433 : wcCoilOutletNode.MassFlowRate = wcCoilInletNode.MassFlowRate;
1986 :
1987 : } else {
1988 :
1989 13970 : QCompReq = CpAirZn * OAMassFlow * ((CompAirOutTemp - wcCoilInletNode.Temp) - FanEffect);
1990 13970 : if (std::abs(QCompReq) < SmallLoad) {
1991 1410 : QCompReq = 0.0;
1992 : }
1993 13970 : if (QCompReq > 0.0) {
1994 0 : QCompReq = 0.0; // coil can cool only
1995 : }
1996 : }
1997 :
1998 129612 : ControlCompOutput(state,
1999 32403 : thisOutAirUnit.Name,
2000 97209 : std::string(ZoneHVACOAUnit),
2001 : UnitNum,
2002 : FirstHVACIteration,
2003 : QCompReq,
2004 : ControlNode,
2005 : MaxWaterFlow,
2006 : MinWaterFlow,
2007 : 0.001,
2008 32403 : thisOutAirUnit.ControlCompTypeNum,
2009 32403 : thisOutAirUnit.CompErrIndex,
2010 : _,
2011 : _,
2012 : _,
2013 64806 : 1,
2014 : SimCompNum,
2015 32403 : thisOAEquip.plantLoc);
2016 : }
2017 32403 : } break;
2018 0 : case CompType::WaterCoil_DetailedCool: { // 'Coil:Cooling:Water:DetailedGeometry'
2019 0 : if (Sim) {
2020 0 : int const ControlNode = thisOAEquip.CoilWaterInletNode;
2021 0 : MaxWaterFlow = thisOAEquip.MaxWaterMassFlow;
2022 0 : MinWaterFlow = thisOAEquip.MinWaterMassFlow;
2023 : // On the first HVAC iteration the system values are given to the controller, but after that
2024 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
2025 0 : if ((!FirstHVACIteration) && (ControlNode > 0)) {
2026 0 : MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
2027 0 : MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
2028 : }
2029 0 : auto const &wcCoilInletNode = state.dataLoopNodes->Node(InletNodeNum);
2030 : // auto &wcCoilOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
2031 :
2032 0 : Real64 const CpAirZn = PsyCpAirFnW(wcCoilInletNode.HumRat);
2033 :
2034 0 : if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::HeatingMode) || (wcCoilInletNode.Temp < CompAirOutTemp)) {
2035 0 : QCompReq = 0.0;
2036 : } else {
2037 :
2038 0 : QCompReq = CpAirZn * OAMassFlow * ((CompAirOutTemp - wcCoilInletNode.Temp) - FanEffect);
2039 0 : if (std::abs(QCompReq) < SmallLoad) {
2040 0 : QCompReq = 0.0;
2041 : }
2042 0 : if (QCompReq > 0.0) {
2043 0 : QCompReq = 0.0; // coil can cool only
2044 : }
2045 : }
2046 :
2047 0 : ControlCompOutput(state,
2048 0 : thisOutAirUnit.Name,
2049 : "ZONEHVAC:OUTDOORAIRUNIT",
2050 : UnitNum,
2051 : FirstHVACIteration,
2052 : QCompReq,
2053 : ControlNode,
2054 : MaxWaterFlow,
2055 : MinWaterFlow,
2056 : 0.001,
2057 0 : thisOutAirUnit.ControlCompTypeNum,
2058 0 : thisOutAirUnit.CompErrIndex,
2059 : _,
2060 : _,
2061 : _,
2062 0 : 1,
2063 : SimCompNum,
2064 0 : thisOAEquip.plantLoc);
2065 : }
2066 0 : } break;
2067 0 : case CompType::WaterCoil_CoolingHXAsst: { // 'CoilSystem:Cooling:Water:HeatExchangerAssisted'
2068 0 : if (Sim) {
2069 0 : int const ControlNode = thisOAEquip.CoilWaterInletNode;
2070 0 : MaxWaterFlow = thisOAEquip.MaxWaterMassFlow;
2071 0 : MinWaterFlow = 0.0;
2072 : // On the first HVAC iteration the system values are given to the controller, but after that
2073 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
2074 0 : if ((!FirstHVACIteration) && (ControlNode > 0)) {
2075 0 : MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
2076 0 : MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
2077 : }
2078 0 : auto const &wcCoilInletNode = state.dataLoopNodes->Node(InletNodeNum);
2079 : // auto &wcCoilOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
2080 :
2081 0 : Real64 const CpAirZn = PsyCpAirFnW(wcCoilInletNode.HumRat);
2082 0 : if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::HeatingMode) || (wcCoilInletNode.Temp < CompAirOutTemp)) {
2083 0 : QCompReq = 0.0;
2084 : } else {
2085 0 : QCompReq = CpAirZn * OAMassFlow * ((CompAirOutTemp - wcCoilInletNode.Temp) - FanEffect);
2086 0 : if (std::abs(QCompReq) < SmallLoad) {
2087 0 : QCompReq = 0.0;
2088 : }
2089 0 : if (QCompReq > 0.0) {
2090 0 : QCompReq = 0.0; // coil can cool only
2091 : }
2092 : }
2093 0 : ControlCompOutput(state,
2094 0 : thisOutAirUnit.Name,
2095 : "ZONEHVAC:OUTDOORAIRUNIT",
2096 : UnitNum,
2097 : FirstHVACIteration,
2098 : QCompReq,
2099 : ControlNode,
2100 : MaxWaterFlow,
2101 : MinWaterFlow,
2102 : 0.001,
2103 0 : thisOutAirUnit.ControlCompTypeNum,
2104 0 : thisOutAirUnit.CompErrIndex,
2105 : _,
2106 : _,
2107 : _,
2108 0 : 1,
2109 : SimCompNum,
2110 0 : thisOAEquip.plantLoc);
2111 : }
2112 0 : } break;
2113 74325 : case CompType::DXSystem: { // CoilSystem:Cooling:DX old 'CompType:UnitaryCoolOnly'
2114 74325 : if (Sim) {
2115 74325 : if (thisOAEquip.compPointer == nullptr) {
2116 8 : UnitarySystems::UnitarySys thisSys;
2117 8 : thisOAEquip.compPointer =
2118 8 : thisSys.factory(state, HVAC::UnitarySysType::Unitary_AnyCoilType, thisOAEquip.ComponentName, false, OAUnitNum);
2119 8 : UnitarySystems::UnitarySys::checkUnitarySysCoilInOASysExists(state, thisOAEquip.ComponentName, OAUnitNum);
2120 8 : }
2121 74325 : if (((OpMode == Operation::NeutralMode) && (thisOutAirUnit.controlType == OAUnitCtrlType::Temperature)) ||
2122 : (OpMode == Operation::HeatingMode)) {
2123 34177 : Dxsystemouttemp = 100.0; // There is no cooling demand for the DX system.
2124 : } else {
2125 40148 : Dxsystemouttemp = CompAirOutTemp - FanEffect;
2126 : }
2127 74325 : Real64 sensOut = 0.0;
2128 74325 : Real64 latOut = 0.0;
2129 74325 : int DXSystemIndex = 0;
2130 74325 : thisOAEquip.compPointer->simulate(state,
2131 : EquipName,
2132 : FirstHVACIteration,
2133 : -1,
2134 : DXSystemIndex,
2135 74325 : state.dataOutdoorAirUnit->HeatActive,
2136 74325 : state.dataOutdoorAirUnit->CoolActive,
2137 : UnitNum,
2138 : Dxsystemouttemp,
2139 : false,
2140 : sensOut,
2141 : latOut);
2142 : }
2143 74325 : } break;
2144 10866 : case CompType::DXHeatPumpSystem: {
2145 10866 : if (Sim) {
2146 10866 : if (((OpMode == Operation::NeutralMode) && (thisOutAirUnit.controlType == OAUnitCtrlType::Temperature)) ||
2147 : (OpMode == Operation::CoolingMode)) {
2148 6374 : Dxsystemouttemp = -20.0; // There is no heating demand for the DX system.
2149 : } else {
2150 4492 : Dxsystemouttemp = CompAirOutTemp - FanEffect;
2151 : }
2152 10866 : int DXSystemIndex = 0;
2153 10866 : SimDXHeatPumpSystem(state, EquipName, FirstHVACIteration, -1, DXSystemIndex, UnitNum, Dxsystemouttemp);
2154 : }
2155 10866 : } break;
2156 : // RAR need new CompType:UnitarySystem object here
2157 0 : case CompType::UnitarySystemModel: { // 'CompType:UnitarySystem'
2158 0 : if (Sim) {
2159 : // This may have to be done in the unitary system object since there can be both cooling and heating
2160 0 : if (((OpMode == Operation::NeutralMode) && (thisOutAirUnit.controlType == OAUnitCtrlType::Temperature)) ||
2161 : (OpMode == Operation::HeatingMode)) {
2162 0 : Dxsystemouttemp = 100.0; // There is no cooling demand.
2163 0 : } else if (((OpMode == Operation::NeutralMode) && (thisOutAirUnit.controlType == OAUnitCtrlType::Temperature)) ||
2164 : (OpMode == Operation::CoolingMode)) {
2165 0 : Dxsystemouttemp = -20.0; // There is no heating demand.
2166 : } else {
2167 0 : Dxsystemouttemp = CompAirOutTemp - FanEffect;
2168 : }
2169 0 : Real64 sensOut = 0.0;
2170 0 : Real64 latOut = 0.0;
2171 0 : int DXSystemIndex = 0;
2172 0 : thisOAEquip.compPointer->simulate(state,
2173 : EquipName,
2174 : FirstHVACIteration,
2175 : -1,
2176 : DXSystemIndex,
2177 0 : state.dataOutdoorAirUnit->HeatActive,
2178 0 : state.dataOutdoorAirUnit->CoolActive,
2179 : UnitNum,
2180 : Dxsystemouttemp,
2181 : false,
2182 : sensOut,
2183 : latOut);
2184 : }
2185 0 : } break;
2186 0 : default: {
2187 0 : ShowFatalError(state, format("Invalid Outdoor Air Unit Component={}", EquipType)); // validate
2188 0 : } break;
2189 : }
2190 : }
2191 298647 : }
2192 :
2193 796352 : void CalcOAUnitCoilComps(EnergyPlusData &state,
2194 : int const CompNum, // actual outdoor air unit num
2195 : bool const FirstHVACIteration,
2196 : int const EquipIndex, // Component Type -- Integerized for this module
2197 : Real64 &LoadMet)
2198 : {
2199 :
2200 : // SUBROUTINE INFORMATION:
2201 : // AUTHOR Young Tae Chae, Rick Strand
2202 : // DATE WRITTEN June 2009
2203 : // MODIFIED
2204 : // RE-ENGINEERED na
2205 :
2206 : // PURPOSE OF THIS SUBROUTINE:
2207 : // This subroutine mainly controls the action of water components in the unit
2208 :
2209 : // METHODOLOGY EMPLOYED:
2210 :
2211 : // REFERENCES:
2212 :
2213 : // USE STATEMENTS:
2214 :
2215 : // Using/Aliasing
2216 : using HVAC::SmallLoad;
2217 : using HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil;
2218 : using SteamCoils::SimulateSteamCoilComponents;
2219 : using WaterCoils::SimulateWaterCoilComponents;
2220 :
2221 : // SUBROUTINE ARGUMENT DEFINITIONS:
2222 :
2223 : // Locals
2224 : // SUBROUTINE LOCAL VARIABLE DEFINITIONS
2225 796352 : int CoilIndex = 0;
2226 :
2227 796352 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(CompNum);
2228 796352 : auto &thisOAEquip = thisOutAirUnit.OAEquip(EquipIndex);
2229 796352 : int const InletNodeNum = thisOAEquip.CoilAirInletNode;
2230 796352 : int const OutletNodeNum = thisOAEquip.CoilAirOutletNode;
2231 796352 : auto const &oaInletNode = state.dataLoopNodes->Node(InletNodeNum);
2232 796352 : auto &oaOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
2233 :
2234 796352 : CompType const CoilTypeNum = thisOAEquip.Type;
2235 796352 : Operation const OpMode = thisOutAirUnit.OperatingMode;
2236 796352 : Real64 const CoilAirOutTemp = thisOutAirUnit.CompOutSetTemp;
2237 796352 : bool const DrawFan = thisOutAirUnit.FanEffect;
2238 796352 : Real64 const FanEffect = DrawFan ? thisOutAirUnit.FanCorTemp : 0.0;
2239 :
2240 : // Actual equipment load
2241 43204 : auto setupQCompReq = [&OpMode, &oaInletNode, &oaOutletNode, &CoilAirOutTemp, &FanEffect]() -> Real64 {
2242 43204 : Real64 QCompReq = 0.0;
2243 43204 : if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::CoolingMode) || (oaInletNode.Temp > CoilAirOutTemp)) {
2244 25921 : QCompReq = 0.0;
2245 : } else {
2246 17283 : oaOutletNode.MassFlowRate = oaInletNode.MassFlowRate;
2247 17283 : Real64 const CpAirZn = PsyCpAirFnW(oaInletNode.HumRat);
2248 17283 : QCompReq = oaInletNode.MassFlowRate * CpAirZn * ((CoilAirOutTemp - oaInletNode.Temp) - FanEffect);
2249 17283 : if (std::abs(QCompReq) < SmallLoad) {
2250 0 : QCompReq = 0.0;
2251 : }
2252 : }
2253 43204 : if (QCompReq <= 0.0) {
2254 25921 : QCompReq = 0.0; // a heating coil can only heat, not cool
2255 25921 : oaOutletNode.Temp = oaInletNode.Temp;
2256 25921 : oaOutletNode.HumRat = oaInletNode.HumRat;
2257 25921 : oaOutletNode.MassFlowRate = oaInletNode.MassFlowRate;
2258 : }
2259 43204 : return QCompReq;
2260 796352 : };
2261 :
2262 796352 : switch (CoilTypeNum) {
2263 32403 : case CompType::Coil_ElectricHeat: {
2264 32403 : Real64 const QCompReq = setupQCompReq();
2265 32403 : HeatingCoils::SimulateHeatingCoilComponents(state, thisOAEquip.ComponentName, FirstHVACIteration, QCompReq, CoilIndex);
2266 32403 : Real64 const AirMassFlow = oaInletNode.MassFlowRate;
2267 32403 : LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
2268 :
2269 32403 : } break;
2270 10801 : case CompType::Coil_GasHeat: { // 'Coil:Heating:Steam'
2271 10801 : Real64 const QCompReq = setupQCompReq();
2272 10801 : HeatingCoils::SimulateHeatingCoilComponents(state, thisOAEquip.ComponentName, FirstHVACIteration, QCompReq, CoilIndex);
2273 10801 : Real64 const AirMassFlow = oaInletNode.MassFlowRate;
2274 10801 : LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
2275 :
2276 10801 : } break;
2277 0 : case CompType::SteamCoil_AirHeat: { // 'Coil:Heating:Steam'
2278 0 : Real64 const QCompReq = setupQCompReq();
2279 0 : SimulateSteamCoilComponents(state, thisOAEquip.ComponentName, FirstHVACIteration, CoilIndex, QCompReq);
2280 0 : Real64 const AirMassFlow = oaInletNode.MassFlowRate;
2281 0 : LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
2282 :
2283 0 : } break;
2284 753148 : case CompType::WaterCoil_SimpleHeat: // 'Coil:Heating:Water')
2285 : case CompType::WaterCoil_Cooling: // 'Coil:Cooling:Water'
2286 : case CompType::WaterCoil_DetailedCool: {
2287 753148 : SimulateWaterCoilComponents(state, thisOAEquip.ComponentName, FirstHVACIteration, CoilIndex);
2288 753148 : Real64 const AirMassFlow = oaInletNode.MassFlowRate;
2289 753148 : LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
2290 :
2291 753148 : } break;
2292 0 : case CompType::WaterCoil_CoolingHXAsst: {
2293 0 : SimHXAssistedCoolingCoil(
2294 : state, thisOAEquip.ComponentName, FirstHVACIteration, HVAC::CompressorOp::On, 0.0, CoilIndex, HVAC::FanOp::Continuous);
2295 0 : Real64 const AirMassFlow = oaInletNode.MassFlowRate;
2296 0 : LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
2297 0 : } break;
2298 0 : default:
2299 0 : ShowFatalError(state, format("Invalid Coil Type = {}", CoilTypeNum)); // validate
2300 0 : break;
2301 : }
2302 796352 : }
2303 :
2304 : // SUBROUTINE UpdateOutdoorAirUnit
2305 :
2306 : // No update routine needed in this module since all of the updates happen on
2307 : // the Node derived type directly and these updates are done by other routines.
2308 :
2309 : // END SUBROUTINE UpdateOutdoorAirUnit
2310 :
2311 64806 : void ReportOutdoorAirUnit(EnergyPlusData &state,
2312 : int const OAUnitNum) // Index for the outdoor air unit under consideration within the derived types
2313 : {
2314 :
2315 : // SUBROUTINE INFORMATION:
2316 : // AUTHOR Young T. Chae
2317 : // DATE WRITTEN Oct. 2009
2318 : // MODIFIED na
2319 : // RE-ENGINEERED na
2320 :
2321 : // PURPOSE OF THIS SUBROUTINE:
2322 : // This subroutine simply produces output for the outdoor air unit.
2323 : // METHODOLOGY EMPLOYED:
2324 : // Standard EnergyPlus methodology.
2325 :
2326 : // Using/Aliasing
2327 64806 : Real64 const TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
2328 :
2329 64806 : auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
2330 64806 : thisOutAirUnit.TotHeatingEnergy = thisOutAirUnit.TotHeatingRate * TimeStepSysSec;
2331 64806 : thisOutAirUnit.SensHeatingEnergy = thisOutAirUnit.SensHeatingRate * TimeStepSysSec;
2332 64806 : thisOutAirUnit.LatHeatingEnergy = thisOutAirUnit.LatHeatingRate * TimeStepSysSec;
2333 64806 : thisOutAirUnit.SensCoolingEnergy = thisOutAirUnit.SensCoolingRate * TimeStepSysSec;
2334 64806 : thisOutAirUnit.LatCoolingEnergy = thisOutAirUnit.LatCoolingRate * TimeStepSysSec;
2335 64806 : thisOutAirUnit.TotCoolingEnergy = thisOutAirUnit.TotCoolingRate * TimeStepSysSec;
2336 64806 : thisOutAirUnit.AirMassFlow = thisOutAirUnit.OutAirMassFlow;
2337 64806 : thisOutAirUnit.ElecFanEnergy = thisOutAirUnit.ElecFanRate * TimeStepSysSec;
2338 :
2339 64806 : if (thisOutAirUnit.FirstPass) { // reset sizing flags so other zone equipment can size normally
2340 12 : if (!state.dataGlobal->SysSizingCalc) {
2341 12 : DataSizing::resetHVACSizingGlobals(state, state.dataSize->CurZoneEqNum, 0, thisOutAirUnit.FirstPass);
2342 : }
2343 : }
2344 64806 : }
2345 :
2346 3474 : int GetOutdoorAirUnitOutAirNode(EnergyPlusData &state, int const OAUnitNum)
2347 : {
2348 :
2349 : // FUNCTION INFORMATION:
2350 : // AUTHOR B Griffith
2351 : // DATE WRITTEN Dec 2006
2352 : // MODIFIED na
2353 : // RE-ENGINEERED na
2354 :
2355 : // PURPOSE OF THIS FUNCTION:
2356 : // lookup function for OA inlet node
2357 :
2358 : // Return value
2359 3474 : int GetOutdoorAirUnitOutAirNode = 0;
2360 :
2361 3474 : if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
2362 0 : OutdoorAirUnit::GetOutdoorAirUnitInputs(state);
2363 0 : state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
2364 : }
2365 :
2366 3474 : if (OAUnitNum > 0 && OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits) {
2367 3474 : GetOutdoorAirUnitOutAirNode = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).OutsideAirNode;
2368 : }
2369 :
2370 3474 : return GetOutdoorAirUnitOutAirNode;
2371 : }
2372 :
2373 3474 : int GetOutdoorAirUnitZoneInletNode(EnergyPlusData &state, int const OAUnitNum)
2374 : {
2375 :
2376 : // FUNCTION INFORMATION:
2377 : // AUTHOR B Griffith
2378 : // DATE WRITTEN Dec 2006
2379 : // MODIFIED na
2380 : // RE-ENGINEERED na
2381 :
2382 : // PURPOSE OF THIS FUNCTION:
2383 : // lookup function for OA inlet node
2384 :
2385 : // Return value
2386 3474 : int GetOutdoorAirUnitZoneInletNode = 0;
2387 :
2388 3474 : if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
2389 0 : OutdoorAirUnit::GetOutdoorAirUnitInputs(state);
2390 0 : state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
2391 : }
2392 :
2393 3474 : if (OAUnitNum > 0 && OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits) {
2394 3474 : GetOutdoorAirUnitZoneInletNode = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).AirOutletNode;
2395 : }
2396 :
2397 3474 : return GetOutdoorAirUnitZoneInletNode;
2398 : }
2399 :
2400 3474 : int GetOutdoorAirUnitReturnAirNode(EnergyPlusData &state, int const OAUnitNum)
2401 : {
2402 :
2403 : // FUNCTION INFORMATION:
2404 : // AUTHOR B Griffith
2405 : // DATE WRITTEN Dec 2006
2406 : // MODIFIED na
2407 : // RE-ENGINEERED na
2408 :
2409 : // PURPOSE OF THIS FUNCTION:
2410 : // lookup function for OA inlet node
2411 :
2412 : // Return value
2413 3474 : int GetOutdoorAirUnitReturnAirNode = 0;
2414 :
2415 3474 : if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
2416 0 : OutdoorAirUnit::GetOutdoorAirUnitInputs(state);
2417 0 : state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
2418 : }
2419 :
2420 3474 : if (OAUnitNum > 0 && OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits) {
2421 3474 : GetOutdoorAirUnitReturnAirNode = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).AirInletNode;
2422 : }
2423 :
2424 3474 : return GetOutdoorAirUnitReturnAirNode;
2425 : }
2426 :
2427 0 : int getOutdoorAirUnitEqIndex(EnergyPlusData &state, std::string_view EquipName)
2428 : {
2429 0 : if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
2430 0 : OutdoorAirUnit::GetOutdoorAirUnitInputs(state);
2431 0 : state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
2432 : }
2433 :
2434 0 : for (int OAUnitNum = 1; OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits; ++OAUnitNum) {
2435 0 : if (Util::SameString(state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).Name, EquipName)) {
2436 0 : return OAUnitNum;
2437 : }
2438 : }
2439 :
2440 0 : return 0;
2441 : }
2442 :
2443 : } // namespace OutdoorAirUnit
2444 :
2445 : } // namespace EnergyPlus
|