Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 : #include <string>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Array.functions.hh>
54 : #include <ObjexxFCL/Fmath.hh>
55 :
56 : // EnergyPlus Headers
57 : #include <EnergyPlus/Autosizing/Base.hh>
58 : #include <EnergyPlus/BranchNodeConnections.hh>
59 : #include <EnergyPlus/CurveManager.hh>
60 : #include <EnergyPlus/Data/EnergyPlusData.hh>
61 : #include <EnergyPlus/DataAirLoop.hh>
62 : #include <EnergyPlus/DataContaminantBalance.hh>
63 : #include <EnergyPlus/DataDefineEquip.hh>
64 : #include <EnergyPlus/DataEnvironment.hh>
65 : #include <EnergyPlus/DataHVACGlobals.hh>
66 : #include <EnergyPlus/DataHeatBalance.hh>
67 : #include <EnergyPlus/DataIPShortCuts.hh>
68 : #include <EnergyPlus/DataLoopNode.hh>
69 : #include <EnergyPlus/DataSizing.hh>
70 : #include <EnergyPlus/DataZoneControls.hh>
71 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
72 : #include <EnergyPlus/DataZoneEquipment.hh>
73 : #include <EnergyPlus/DesiccantDehumidifiers.hh>
74 : #include <EnergyPlus/EMSManager.hh>
75 : #include <EnergyPlus/EvaporativeCoolers.hh>
76 : #include <EnergyPlus/Fans.hh>
77 : #include <EnergyPlus/FaultsManager.hh>
78 : #include <EnergyPlus/General.hh>
79 : #include <EnergyPlus/GeneralRoutines.hh>
80 : #include <EnergyPlus/GlobalNames.hh>
81 : #include <EnergyPlus/HVACControllers.hh>
82 : #include <EnergyPlus/HVACDXHeatPumpSystem.hh>
83 : #include <EnergyPlus/HVACFan.hh>
84 : #include <EnergyPlus/HVACHXAssistedCoolingCoil.hh>
85 : #include <EnergyPlus/HVACVariableRefrigerantFlow.hh>
86 : #include <EnergyPlus/HeatRecovery.hh>
87 : #include <EnergyPlus/HeatingCoils.hh>
88 : #include <EnergyPlus/Humidifiers.hh>
89 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
90 : #include <EnergyPlus/MixedAir.hh>
91 : #include <EnergyPlus/NodeInputManager.hh>
92 : #include <EnergyPlus/OutAirNodeManager.hh>
93 : #include <EnergyPlus/OutputProcessor.hh>
94 : #include <EnergyPlus/OutputReportPredefined.hh>
95 : #include <EnergyPlus/PhotovoltaicThermalCollectors.hh>
96 : #include <EnergyPlus/Psychrometrics.hh>
97 : #include <EnergyPlus/ScheduleManager.hh>
98 : #include <EnergyPlus/SetPointManager.hh>
99 : #include <EnergyPlus/SimAirServingZones.hh>
100 : #include <EnergyPlus/SteamCoils.hh>
101 : #include <EnergyPlus/TranspiredCollector.hh>
102 : #include <EnergyPlus/UnitarySystem.hh>
103 : #include <EnergyPlus/UserDefinedComponents.hh>
104 : #include <EnergyPlus/UtilityRoutines.hh>
105 : #include <EnergyPlus/WaterCoils.hh>
106 :
107 : namespace EnergyPlus::MixedAir {
108 :
109 : // Module containing the routines dealing with the mixed air portion
110 : // of the HVAC air loop.
111 :
112 : // MODULE INFORMATION:
113 : // AUTHOR Fred Buhl
114 : // DATE WRITTEN October 1998
115 : // MODIFIED Shirey/Raustad FSEC, June/Aug 2003, Jan 2004
116 : // Lawrie, March 2006 - Module order (per template)
117 : // Craig Wray 22Aug2010 - Added Fan ComponentModel
118 : // Chandan Sharma, FSEC, 25Aug 2011 - Added ProportionalControl
119 : // to enhance CO2 based DCV control
120 : // Feb 2013 Bereket Nigusse, FSEC
121 : // Added DX Coil Model For 100% OA systems
122 : // RE-ENGINEERED na
123 :
124 : // PURPOSE OF THIS MODULE:
125 : // To encapsulate the data and algorithms required to
126 : // simulate the mixed air portion of the EPlus air loop.
127 :
128 : // METHODOLOGY EMPLOYED:
129 : // An algorithmic controller will be employed - there is no attempt to
130 : // simulate real controllers for the economizer. The mixed air controller
131 : // will sense various node conditions and set some node flow rates. Mixed
132 : // air components will operate with predetermined flow rates.
133 :
134 : // Using/Aliasing
135 : using namespace DataLoopNode;
136 : using namespace DataAirLoop;
137 : using namespace DataEnvironment;
138 : using namespace DataHVACGlobals;
139 : using namespace ScheduleManager;
140 : using namespace DataSizing;
141 : using namespace FaultsManager;
142 :
143 771 : Array1D_string const CurrentModuleObjects(8,
144 : {"AirLoopHVAC:OutdoorAirSystem",
145 : "AirLoopHVAC:OutdoorAirSystem:EquipmentList",
146 : "AirLoopHVAC:ControllerList",
147 : "AvailabilityManagerAssignmentList",
148 : "Controller:OutdoorAir",
149 : "ZoneHVAC:EnergyRecoveryVentilator:Controller",
150 : "Controller:MechanicalVentilation",
151 771 : "OutdoorAir:Mixer"});
152 :
153 : constexpr std::array<std::string_view, static_cast<int>(DataSizing::SysOAMethod::Num)> SOAMNamesUC{"ZONESUM",
154 : "STANDARD62.1VENTILATIONRATEPROCEDURE",
155 : "INDOORAIRQUALITYPROCEDURE",
156 : "PROPORTIONALCONTROLBASEDONOCCUPANCYSCHEDULE",
157 : "INDOORAIRQUALITYPROCEDUREGENERICCONTAMINANT",
158 : "INDOORAIRQUALITYPROCEDURECOMBINED",
159 : "PROPORTIONALCONTROLBASEDONDESIGNOCCUPANCY",
160 : "PROPORTIONALCONTROLBASEDONDESIGNOARATE",
161 : "STANDARD62.1SIMPLIFIEDPROCEDURE",
162 : "STANDARD62.1VENTILATIONRATEPROCEDUREWITHLIMIT"};
163 :
164 : constexpr std::array<std::string_view, static_cast<int>(SimAirServingZones::CompType::Num)> CompTypeNamesUC{
165 : "OUTDOORAIR:MIXER",
166 : "FAN:CONSTANTVOLUME",
167 : "FAN:VARIABLEVOLUME",
168 : "COIL:COOLING:WATER",
169 : "COIL:HEATING:WATER",
170 : "COIL:HEATING:STEAM",
171 : "COIL:COOLING:WATER:DETAILEDGEOMETRY",
172 : "COIL:HEATING:ELECTRIC",
173 : "COIL:HEATING:FUEL",
174 : "COILSYSTEM:COOLING:WATER:HEATEXCHANGERASSISTED",
175 : "COIL:HEATING:DESUPERHEATER",
176 : "COILSYSTEM:COOLING:DX",
177 : "HEATEXCHANGER:AIRTOAIR:FLATPLATE",
178 : "DEHUMIDIFIER:DESICCANT:NOFANS",
179 : "SOLARCOLLECTOR:UNGLAZEDTRANSPIRED",
180 : "EVAPORATIVECOOLER:DIRECT:CELDEKPAD",
181 : "AIRLOOPHVAC:UNITARY:FURNACE:HEATONLY",
182 : "AIRLOOPHVAC:UNITARY:FURNACE:HEATCOOL",
183 : "HUMIDIFIER:STEAM:ELECTRIC",
184 : "DUCT",
185 : "AIRLOOPHVAC:UNITARYHEATCOOL:VAVCHANGEOVERBYPASS",
186 : "AIRLOOPHVAC:UNITARYHEATPUMP:AIRTOAIR:MULTISPEED",
187 : "FAN:COMPONENTMODEL",
188 : "COILSYSTEM:HEATING:DX",
189 : "COIL:USERDEFINED",
190 : "FAN:SYSTEMMODEL",
191 : "AIRLOOPHVAC:UNITARYSYSTEM",
192 : "ZONEHVAC:TERMINALUNIT:VARIABLEREFRIGERANTFLOW",
193 : "SOLARCOLLECTOR:FLATPLATE:PHOTOVOLTAICTHERMAL",
194 : "COILSYSTEM:COOLING:WATER"};
195 :
196 : static constexpr std::array<std::string_view, static_cast<int>(DataSizing::SysOAMethod::Num)> printSysOAMethod{
197 : "ZoneSum,",
198 : "Standard62.1VentilationRateProcedure,",
199 : "IndoorAirQualityProcedure,",
200 : "ProportionalControlBasedOnOccupancySchedule,",
201 : "IndoorAirQualityGenericContaminant,",
202 : "IndoorAirQualityProcedureCombined,",
203 : "ProportionalControlBasedOnDesignOccupancy,",
204 : "ProportionalControlBasedOnDesignOARate,",
205 : "Standard62.1SimplifiedProcedure,",
206 : "Standard62.1VentilationRateProcedureWithLimit,"};
207 :
208 977 : Real64 OAGetFlowRate(EnergyPlusData &state, int OAPtr)
209 : {
210 977 : Real64 FlowRate(0);
211 977 : if ((OAPtr > 0) && (OAPtr <= state.dataMixedAir->NumOAControllers) && (state.dataEnvrn->StdRhoAir != 0)) {
212 977 : FlowRate = state.dataMixedAir->OAController(OAPtr).OAMassFlow / state.dataEnvrn->StdRhoAir;
213 : }
214 977 : return FlowRate;
215 : }
216 0 : Real64 OAGetMinFlowRate(EnergyPlusData &state, int OAPtr)
217 : {
218 0 : Real64 MinFlowRate(0);
219 0 : if ((OAPtr > 0) && (OAPtr <= state.dataMixedAir->NumOAControllers)) {
220 0 : MinFlowRate = state.dataMixedAir->OAController(OAPtr).MinOA;
221 : }
222 0 : return MinFlowRate;
223 : }
224 84 : void OASetDemandManagerVentilationState(EnergyPlusData &state, int OAPtr, bool aState)
225 : {
226 84 : if ((OAPtr > 0) && (OAPtr <= state.dataMixedAir->NumOAControllers)) {
227 84 : state.dataMixedAir->OAController(OAPtr).ManageDemand = aState;
228 : }
229 84 : }
230 42 : void OASetDemandManagerVentilationFlow(EnergyPlusData &state, int OAPtr, Real64 aFlow)
231 : {
232 42 : if ((OAPtr > 0) && (OAPtr <= state.dataMixedAir->NumOAControllers)) {
233 42 : state.dataMixedAir->OAController(OAPtr).DemandLimitFlowRate = aFlow * state.dataEnvrn->StdRhoAir;
234 : }
235 42 : }
236 1031 : int GetOAController(EnergyPlusData &state, std::string const &OAName)
237 : {
238 1031 : int CurrentOAController(0);
239 13162 : for (int i = 1; i <= state.dataMixedAir->NumOAControllers; i++) {
240 13162 : if (OAName == state.dataMixedAir->OAController(i).Name) {
241 1031 : CurrentOAController = i;
242 1031 : break;
243 : }
244 : }
245 1031 : return CurrentOAController;
246 : }
247 :
248 24268600 : void ManageOutsideAirSystem(EnergyPlusData &state, std::string const &OASysName, bool const FirstHVACIteration, int const AirLoopNum, int &OASysNum)
249 : {
250 :
251 : // SUBROUTINE INFORMATION:
252 : // AUTHOR Fred Buhl
253 : // DATE WRITTEN Oct 1998
254 : // MODIFIED na
255 : // RE-ENGINEERED na
256 :
257 : // PURPOSE OF THIS SUBROUTINE
258 : // Manage the outside air system
259 :
260 24268600 : if (state.dataMixedAir->GetOASysInputFlag) {
261 0 : GetOutsideAirSysInputs(state);
262 0 : state.dataMixedAir->GetOASysInputFlag = false;
263 : }
264 :
265 24268600 : if (OASysNum == 0) {
266 1021 : OASysNum = UtilityRoutines::FindItemInList(OASysName, state.dataAirLoop->OutsideAirSys);
267 1021 : if (OASysNum == 0) {
268 0 : ShowFatalError(state, "ManageOutsideAirSystem: AirLoopHVAC:OutdoorAirSystem not found=" + OASysName);
269 : }
270 : }
271 :
272 24268600 : InitOutsideAirSys(state, OASysNum, FirstHVACIteration, AirLoopNum);
273 :
274 24268600 : SimOutsideAirSys(state, OASysNum, FirstHVACIteration, AirLoopNum);
275 24268600 : }
276 :
277 24335080 : void SimOASysComponents(EnergyPlusData &state, int const OASysNum, bool const FirstHVACIteration, int const AirLoopNum)
278 : {
279 : int CompNum;
280 24335080 : auto &CompType = state.dataMixedAir->CompType;
281 24335080 : auto &CompName = state.dataMixedAir->CompName;
282 24335080 : bool ReSim(false);
283 24335080 : bool Sim(true);
284 24335080 : bool OAHeatCoil(false);
285 24335080 : bool OACoolCoil(false);
286 24335080 : bool OAHX(false);
287 :
288 54326732 : for (CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(OASysNum).NumComponents; ++CompNum) {
289 29991652 : CompType = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(CompNum);
290 29991652 : CompName = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(CompNum);
291 89974956 : SimOAComponent(state,
292 : CompType,
293 : CompName,
294 29991652 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum),
295 : FirstHVACIteration,
296 29991652 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentIndex(CompNum),
297 : AirLoopNum,
298 : Sim,
299 : OASysNum,
300 : OAHeatCoil,
301 : OACoolCoil,
302 : OAHX);
303 29991652 : if (OAHX) ReSim = true;
304 : }
305 : // if there were heat exchangers and/or desiccant wheel in the OA path, need to simulate again
306 : // in reverse order to propagate the air flow and conditions out the relief air path to the relief air
307 : // exit node
308 24335080 : if (ReSim) {
309 1260822 : for (CompNum = state.dataAirLoop->OutsideAirSys(OASysNum).NumComponents - 1; CompNum >= 1; --CompNum) {
310 683958 : CompType = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(CompNum);
311 683958 : CompName = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(CompNum);
312 2051874 : SimOAComponent(state,
313 : CompType,
314 : CompName,
315 683958 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum),
316 : FirstHVACIteration,
317 683958 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentIndex(CompNum),
318 : AirLoopNum,
319 : Sim,
320 : OASysNum,
321 : OAHeatCoil,
322 : OACoolCoil,
323 : OAHX);
324 : }
325 : // now simulate again propagate current temps back through OA system
326 1837686 : for (CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(OASysNum).NumComponents; ++CompNum) {
327 1260822 : CompType = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(CompNum);
328 1260822 : CompName = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(CompNum);
329 3782466 : SimOAComponent(state,
330 : CompType,
331 : CompName,
332 1260822 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum),
333 : FirstHVACIteration,
334 1260822 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentIndex(CompNum),
335 : AirLoopNum,
336 : Sim,
337 : OASysNum,
338 : OAHeatCoil,
339 : OACoolCoil,
340 : OAHX);
341 : }
342 : }
343 24335080 : }
344 :
345 24268600 : void SimOutsideAirSys(EnergyPlusData &state, int const OASysNum, bool const FirstHVACIteration, int const AirLoopNum)
346 : {
347 :
348 : // SUBROUTINE INFORMATION:
349 : // AUTHOR Fred Buhl
350 : // DATE WRITTEN Oct 1998
351 : // MODIFIED na
352 : // RE-ENGINEERED na
353 :
354 : // PURPOSE OF THIS SUBROUTINE
355 : // Simulate the controllers and components in the outside air system.
356 :
357 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
358 : int CompNum;
359 : // INTEGER :: CtrlNum
360 : int OAMixerNum;
361 : int OAControllerNum; // OA controller index in OAController
362 24268600 : auto &CompType = state.dataMixedAir->CompType; // Tuned Made static
363 24268600 : auto &CompName = state.dataMixedAir->CompName; // Tuned Made static
364 24268600 : bool FatalErrorFlag(false);
365 :
366 : // SimOutsideAirSys can handle only 1 controller right now. This must be
367 : // an Outside Air Controller. This is because of the lack of iteration
368 : // and convergence control in the following code.
369 : // DO CtrlNum=1,OutsideAirSys(OASysNum)%NumControllers
370 : // CtrlName = OutsideAirSys(OASysNum)%ControllerName(CtrlNum)
371 : // CALL SimOAController(CtrlName,FirstHVACIteration)
372 : // END DO
373 24268600 : state.dataSize->CurOASysNum = OASysNum;
374 24268600 : auto &CurrentOASystem(state.dataAirLoop->OutsideAirSys(OASysNum));
375 24268600 : if (state.dataAirLoop->OutsideAirSys(OASysNum).AirLoopDOASNum == -1) {
376 24257718 : SimOAController(state, CurrentOASystem.OAControllerName, CurrentOASystem.OAControllerIndex, FirstHVACIteration, AirLoopNum);
377 : }
378 24268600 : SimOASysComponents(state, OASysNum, FirstHVACIteration, AirLoopNum);
379 :
380 24268600 : if (state.dataMixedAir->MyOneTimeErrorFlag(OASysNum)) {
381 1022 : if (CurrentOASystem.NumControllers - CurrentOASystem.NumSimpleControllers > 1) {
382 0 : ShowWarningError(
383 0 : state, "AirLoopHVAC:OutdoorAirSystem " + CurrentOASystem.Name + " has more than 1 outside air controller; only the 1st will be used");
384 : }
385 2166 : for (CompNum = 1; CompNum <= CurrentOASystem.NumComponents; ++CompNum) {
386 1144 : CompType = CurrentOASystem.ComponentType(CompNum);
387 1144 : CompName = CurrentOASystem.ComponentName(CompNum);
388 1144 : if (UtilityRoutines::SameString(CompType, "OutdoorAir:Mixer")) {
389 1021 : OAMixerNum = UtilityRoutines::FindItemInList(CompName, state.dataMixedAir->OAMixer);
390 1021 : OAControllerNum = CurrentOASystem.OAControllerIndex;
391 1021 : if (state.dataMixedAir->OAController(OAControllerNum).MixNode != state.dataMixedAir->OAMixer(OAMixerNum).MixNode) {
392 0 : ShowSevereError(state,
393 0 : "The mixed air node of Controller:OutdoorAir=\"" + state.dataMixedAir->OAController(OAControllerNum).Name + "\"");
394 0 : ShowContinueError(state,
395 0 : "should be the same node as the mixed air node of OutdoorAir:Mixer=\"" +
396 0 : state.dataMixedAir->OAMixer(OAMixerNum).Name + "\".");
397 0 : ShowContinueError(state,
398 0 : "Controller:OutdoorAir mixed air node=\"" +
399 0 : state.dataLoopNodes->NodeID(state.dataMixedAir->OAController(OAControllerNum).MixNode) + "\".");
400 0 : ShowContinueError(state,
401 0 : "OutdoorAir:Mixer mixed air node=\"" +
402 0 : state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OAMixerNum).MixNode) + "\".");
403 0 : FatalErrorFlag = true;
404 : }
405 1021 : if (state.dataMixedAir->OAController(OAControllerNum).RelNode != state.dataMixedAir->OAMixer(OAMixerNum).RelNode) {
406 0 : ShowSevereError(
407 0 : state, "The relief air node of Controller:OutdoorAir=\"" + state.dataMixedAir->OAController(OAControllerNum).Name + "\"");
408 0 : ShowContinueError(state,
409 0 : "should be the same node as the relief air node of OutdoorAir:Mixer=\"" +
410 0 : state.dataMixedAir->OAMixer(OAMixerNum).Name + "\".");
411 0 : ShowContinueError(state,
412 0 : "Controller:OutdoorAir relief air node=\"" +
413 0 : state.dataLoopNodes->NodeID(state.dataMixedAir->OAController(OAControllerNum).RelNode) + "\".");
414 0 : ShowContinueError(state,
415 0 : "OutdoorAir:Mixer relief air node=\"" +
416 0 : state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OAMixerNum).RelNode) + "\".");
417 0 : FatalErrorFlag = true;
418 : }
419 1021 : if (state.dataMixedAir->OAController(OAControllerNum).RetNode != state.dataMixedAir->OAMixer(OAMixerNum).RetNode) {
420 0 : ShowSevereError(
421 0 : state, "The return air node of Controller:OutdoorAir=\"" + state.dataMixedAir->OAController(OAControllerNum).Name + "\"");
422 0 : ShowContinueError(state,
423 0 : "should be the same node as the return air node of OutdoorAir:Mixer=\"" +
424 0 : state.dataMixedAir->OAMixer(OAMixerNum).Name + "\".");
425 0 : ShowContinueError(state,
426 0 : "Controller:OutdoorAir return air node=\"" +
427 0 : state.dataLoopNodes->NodeID(state.dataMixedAir->OAController(OAControllerNum).RetNode) + "\".");
428 0 : ShowContinueError(state,
429 0 : "OutdoorAir:Mixer return air node=\"" +
430 0 : state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OAMixerNum).RetNode) + "\".");
431 0 : FatalErrorFlag = true;
432 : }
433 : }
434 : }
435 1022 : state.dataMixedAir->MyOneTimeErrorFlag(OASysNum) = false;
436 1022 : if (FatalErrorFlag) ShowFatalError(state, "Previous severe error(s) cause program termination");
437 : }
438 :
439 24268600 : state.dataSize->CurOASysNum = 0;
440 24268600 : if (state.dataAirLoop->OutsideAirSys(OASysNum).AirLoopDOASNum == -1) {
441 24257718 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysComponentsSimulated = true;
442 : }
443 24268600 : }
444 :
445 31938724 : void SimOAComponent(EnergyPlusData &state,
446 : std::string const &CompType, // the component type
447 : std::string const &CompName, // the component Name
448 : SimAirServingZones::CompType const CompTypeNum, // Component Type -- Integerized for this module
449 : bool const FirstHVACIteration,
450 : int &CompIndex,
451 : int const AirLoopNum, // air loop index for economizer lockout coordination
452 : bool const Sim, // if TRUE, simulate component; if FALSE, just set the coil exisitence flags
453 : int const OASysNum, // index to outside air system
454 : bool &OAHeatingCoil, // TRUE indicates a heating coil has been found
455 : bool &OACoolingCoil, // TRUE indicates a cooling coil has been found
456 : bool &OAHX // TRUE indicates a heat exchanger has been found
457 : )
458 : {
459 :
460 : // SUBROUTINE INFORMATION
461 : // AUTHOR: Russ Taylor, Dan Fisher, Fred Buhl
462 : // DATE WRITTEN: Oct 1997
463 : // MODIFIED: Dec 1997 Fred Buhl, D Shirey Feb/Sept 2003
464 : // Nov 2004 M. J. Witte, GARD Analytics, Inc.
465 : // Add DXSystem:AirLoop as valid OA system equipment
466 : // Work supported by ASHRAE research project 1254-RP
467 : // RE-ENGINEERED: This is new code, not reengineered
468 :
469 : // PURPOSE OF THIS SUBROUTINE:
470 : // Calls the individual air loop component simulation routines
471 :
472 : // METHODOLOGY EMPLOYED: None
473 :
474 : // REFERENCES: None
475 :
476 : // USE Statements
477 : // Using/Aliasing
478 : using DesiccantDehumidifiers::SimDesiccantDehumidifier;
479 : using EvaporativeCoolers::SimEvapCooler;
480 : using HeatingCoils::SimulateHeatingCoilComponents;
481 : using HeatRecovery::SimHeatRecovery;
482 : using Humidifiers::SimHumidifier;
483 : using HVACDXHeatPumpSystem::SimDXHeatPumpSystem;
484 : using HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil;
485 : using SimAirServingZones::SolveWaterCoilController;
486 : using SteamCoils::SimulateSteamCoilComponents;
487 : using TranspiredCollector::SimTranspiredCollector;
488 : using UserDefinedComponents::SimCoilUserDefined;
489 : // Locals
490 : // SUBROUTINE ARGUMENTS:
491 :
492 : // SUBROUTINE PARAMETER DEFINITIONS: None
493 :
494 : // INTERFACE BLOCK DEFINITIONS: None
495 :
496 : // DERIVED TYPE DEFINITIONS: None
497 :
498 : // SUBROUTINE LOCAL VARIABLE DEFINITIONS
499 :
500 31938724 : OAHeatingCoil = false;
501 31938724 : OACoolingCoil = false;
502 31938724 : OAHX = false;
503 : Real64 AirloopPLR;
504 : int FanOpMode;
505 :
506 31938724 : if (CompTypeNum == SimAirServingZones::CompType::OAMixer_Num) { // 'OutdoorAir:Mixer'
507 24903114 : if (Sim) {
508 24901062 : SimOAMixer(state, CompName, FirstHVACIteration, CompIndex);
509 : }
510 :
511 : // Fan Types
512 7035610 : } else if (CompTypeNum == SimAirServingZones::CompType::Fan_Simple_CV) { // 'Fan:ConstantVolume'
513 0 : if (Sim) {
514 0 : Fans::SimulateFanComponents(state, CompName, FirstHVACIteration, CompIndex);
515 : }
516 7035610 : } else if (CompTypeNum == SimAirServingZones::CompType::Fan_Simple_VAV) { // 'Fan:VariableVolume'
517 17611 : if (Sim) {
518 17609 : Fans::SimulateFanComponents(state, CompName, FirstHVACIteration, CompIndex);
519 : }
520 :
521 7017999 : } else if (CompTypeNum == SimAirServingZones::CompType::Fan_System_Object) { // 'Fan:SystemModel'
522 10882 : if (CompIndex == 0) { // 0 means has not been filled because of 1-based arrays in old fortran
523 0 : CompIndex = HVACFan::getFanObjectVectorIndex(state, CompName) + 1; // + 1 for shift from zero-based vector to 1-based compIndex
524 : }
525 10882 : if (Sim) {
526 10882 : state.dataHVACFan->fanObjs[CompIndex - 1]->simulate(state, _, _, _, _); // vector is 0 based, but CompIndex is 1 based so shift
527 : }
528 7007117 : } else if (CompTypeNum == SimAirServingZones::CompType::Fan_ComponentModel) { // 'Fan:ComponentModel'
529 0 : if (Sim) {
530 0 : Fans::SimulateFanComponents(state, CompName, FirstHVACIteration, CompIndex);
531 : }
532 :
533 : // Coil Types
534 7007117 : } else if (CompTypeNum == SimAirServingZones::CompType::WaterCoil_Cooling) { // 'Coil:Cooling:Water'
535 1275051 : if (Sim) {
536 : // get water coil and controller data if not called previously
537 1274999 : if (CompIndex == 0) WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, CompIndex);
538 : // iterate on OA sys controller and water coil at the same time
539 1274999 : if (!state.dataWaterCoils->WaterCoil(CompIndex).heatRecoveryCoil) {
540 2517534 : SolveWaterCoilController(state,
541 : FirstHVACIteration,
542 : AirLoopNum,
543 : CompName,
544 : CompIndex,
545 1258767 : state.dataWaterCoils->WaterCoil(CompIndex).ControllerName,
546 1258767 : state.dataWaterCoils->WaterCoil(CompIndex).ControllerIndex,
547 : false);
548 : // set flag to tell HVAC controller it will be simulated only in SolveWaterCoilController()
549 1258767 : state.dataHVACControllers->ControllerProps(state.dataWaterCoils->WaterCoil(CompIndex).ControllerIndex).BypassControllerCalc = true;
550 : } else {
551 16232 : WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, CompIndex);
552 : }
553 : } else {
554 : // This is not working as intended ... don't want to include the HR coil in sizing.
555 : // But if the water coil is called to get this index, then the controller is called to set the
556 : // controller index and the simulation sizes the controller before the cooling coil.
557 : // Pushing this aspect forward to a follow up issue where the
558 : // controller index call is moved out of water coils getInput.
559 : // if (CompIndex == 0) {
560 : // bool errFound = false;
561 : // CompIndex = WaterCoils::GetWaterCoilIndex(state, CompType, CompName, errFound);
562 : // if (errFound) ShowFatalError(state, "SimOAComponent: Program terminates for preceding reason.");
563 : // }
564 : // if (!state.dataWaterCoils->WaterCoil(CompIndex).heatRecoveryCoil) OACoolingCoil = true;
565 : // should not include heat recovery coils in sizing since heat transfer at peak cooling is minimal.
566 52 : OACoolingCoil = true;
567 : }
568 5732066 : } else if (CompTypeNum == SimAirServingZones::CompType::WaterCoil_SimpleHeat) { // 'Coil:Heating:Water')
569 1285603 : if (Sim) {
570 : // get water coil and controller data if not called previously
571 1285549 : if (CompIndex == 0) WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, CompIndex);
572 : // iterate on OA sys controller and water coil at the same time
573 2571098 : SolveWaterCoilController(state,
574 : FirstHVACIteration,
575 : AirLoopNum,
576 : CompName,
577 : CompIndex,
578 1285549 : state.dataWaterCoils->WaterCoil(CompIndex).ControllerName,
579 1285549 : state.dataWaterCoils->WaterCoil(CompIndex).ControllerIndex,
580 : false);
581 : // set flag to tell HVAC controller it will be simulated only in SolveWaterCoilController()
582 1285549 : state.dataHVACControllers->ControllerProps(state.dataWaterCoils->WaterCoil(CompIndex).ControllerIndex).BypassControllerCalc = true;
583 : }
584 1285603 : OAHeatingCoil = true;
585 4446463 : } else if (CompTypeNum == SimAirServingZones::CompType::SteamCoil_AirHeat) { // 'Coil:Heating:Steam'
586 0 : if (Sim) {
587 0 : SimulateSteamCoilComponents(state, CompName, FirstHVACIteration, CompIndex, 0.0);
588 : }
589 0 : OAHeatingCoil = true;
590 4446463 : } else if (CompTypeNum == SimAirServingZones::CompType::WaterCoil_DetailedCool) { // 'Coil:Cooling:Water:DetailedGeometry'
591 0 : if (Sim) {
592 : // get water coil and controller data if not called previously
593 0 : if (CompIndex == 0) WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, CompIndex);
594 : // iterate on OA sys controller and water coil at the same time
595 0 : SolveWaterCoilController(state,
596 : FirstHVACIteration,
597 : AirLoopNum,
598 : CompName,
599 : CompIndex,
600 0 : state.dataWaterCoils->WaterCoil(CompIndex).ControllerName,
601 0 : state.dataWaterCoils->WaterCoil(CompIndex).ControllerIndex,
602 : false);
603 : // set flag to tell HVAC controller it will be simulated only in SolveWaterCoilController()
604 0 : state.dataHVACControllers->ControllerProps(state.dataWaterCoils->WaterCoil(CompIndex).ControllerIndex).BypassControllerCalc = true;
605 : }
606 0 : OACoolingCoil = true;
607 4446463 : } else if (CompTypeNum == SimAirServingZones::CompType::Coil_ElectricHeat) { // 'Coil:Heating:Electric'
608 26696 : if (Sim) {
609 : // stand-alone coils are temperature controlled (do not pass QCoilReq in argument list, QCoilReq overrides temp SP)
610 26694 : SimulateHeatingCoilComponents(state, CompName, FirstHVACIteration, _, CompIndex);
611 : }
612 26696 : OAHeatingCoil = true;
613 4419767 : } else if (CompTypeNum == SimAirServingZones::CompType::Coil_GasHeat) { // 'Coil:Heating:Fuel'
614 0 : if (Sim) {
615 : // stand-alone coils are temperature controlled (do not pass QCoilReq in argument list, QCoilReq overrides temp SP)
616 0 : SimulateHeatingCoilComponents(state, CompName, FirstHVACIteration, _, CompIndex);
617 : }
618 0 : OAHeatingCoil = true;
619 4419767 : } else if (CompTypeNum == SimAirServingZones::CompType::WaterCoil_CoolingHXAsst) { // 'CoilSystem:Cooling:Water:HeatExchangerAssisted'
620 0 : if (Sim) {
621 : // get water coil and controller data if not called previously
622 0 : if (CompIndex == 0)
623 0 : SimHXAssistedCoolingCoil(state, CompName, FirstHVACIteration, CompressorOperation::On, 0.0, CompIndex, ContFanCycCoil);
624 : // iterate on OA sys controller and water coil at the same time
625 0 : SolveWaterCoilController(state,
626 : FirstHVACIteration,
627 : AirLoopNum,
628 : CompName,
629 : CompIndex,
630 0 : state.dataHVACAssistedCC->HXAssistedCoil(CompIndex).ControllerName,
631 0 : state.dataHVACAssistedCC->HXAssistedCoil(CompIndex).ControllerIndex,
632 : true);
633 : // set flag to tell HVAC controller it will be simulated only in SolveWaterCoilController()
634 0 : state.dataHVACControllers->ControllerProps(state.dataHVACAssistedCC->HXAssistedCoil(CompIndex).ControllerIndex).BypassControllerCalc =
635 : true;
636 : }
637 0 : OACoolingCoil = true;
638 4419767 : } else if (CompTypeNum == SimAirServingZones::CompType::DXSystem) { // CoilSystem:Cooling:DX old 'AirLoopHVAC:UnitaryCoolOnly'
639 3716 : if (Sim) {
640 3714 : if (state.dataAirLoop->OutsideAirSys(OASysNum).compPointer[CompIndex] == nullptr) {
641 4 : UnitarySystems::UnitarySys thisSys;
642 2 : state.dataAirLoop->OutsideAirSys(OASysNum).compPointer[CompIndex] =
643 4 : thisSys.factory(state, DataHVACGlobals::UnitarySys_AnyCoilType, CompName, false, 0);
644 2 : CompIndex = UnitarySystems::getUnitarySystemIndex(state, CompName) + 1;
645 2 : UnitarySystems::UnitarySys::checkUnitarySysCoilInOASysExists(state, CompName, 0);
646 : }
647 3714 : bool HeatingActive = false;
648 3714 : bool CoolingActive = false;
649 3714 : Real64 OAUCoilOutTemp = 0.0;
650 3714 : bool ZoneEquipFlag = false;
651 3714 : Real64 sensOut = 0.0;
652 3714 : Real64 latOut = 0.0;
653 3714 : int compNum = CompIndex - 1;
654 7428 : state.dataAirLoop->OutsideAirSys(OASysNum).compPointer[compNum]->simulate(state,
655 : CompName,
656 : FirstHVACIteration,
657 : AirLoopNum,
658 : compNum,
659 : HeatingActive,
660 : CoolingActive,
661 : 0,
662 : OAUCoilOutTemp,
663 : ZoneEquipFlag,
664 : sensOut,
665 3714 : latOut);
666 : }
667 3716 : OACoolingCoil = true;
668 4416051 : } else if (CompTypeNum == SimAirServingZones::CompType::CoilSystemWater) { // "CoilSystem:Cooling:Water"
669 16234 : if (state.dataAirLoop->OutsideAirSys(OASysNum).compPointer[CompIndex] == nullptr) {
670 2 : UnitarySystems::UnitarySys thisSys;
671 1 : state.dataAirLoop->OutsideAirSys(OASysNum).compPointer[CompIndex] =
672 2 : thisSys.factory(state, DataHVACGlobals::UnitarySys_AnyCoilType, CompName, false, 0);
673 1 : UnitarySystems::UnitarySys::checkUnitarySysCoilInOASysExists(state, CompName, 0);
674 : }
675 16234 : if (Sim) {
676 16232 : bool HeatingActive = false;
677 16232 : bool CoolingActive = false;
678 16232 : Real64 OAUCoilOutTemp = 0.0;
679 16232 : bool ZoneEquipFlag = false;
680 16232 : Real64 sensOut = 0.0;
681 16232 : Real64 latOut = 0.0;
682 32464 : state.dataAirLoop->OutsideAirSys(OASysNum).compPointer[CompIndex]->simulate(state,
683 : CompName,
684 : FirstHVACIteration,
685 : AirLoopNum,
686 : CompIndex,
687 : HeatingActive,
688 : CoolingActive,
689 : CompIndex,
690 : OAUCoilOutTemp,
691 : ZoneEquipFlag,
692 : sensOut,
693 16232 : latOut);
694 : }
695 16234 : OACoolingCoil = true;
696 4399817 : } else if (CompTypeNum == SimAirServingZones::CompType::UnitarySystemModel) { // AirLoopHVAC:UnitarySystem
697 0 : if (Sim) {
698 0 : bool HeatingActive = false;
699 0 : bool CoolingActive = false;
700 0 : Real64 OAUCoilOutTemp = 0.0;
701 0 : bool ZoneEquipFlag = false;
702 0 : Real64 sensOut = 0.0;
703 0 : Real64 latOut = 0.0;
704 0 : state.dataAirLoop->OutsideAirSys(OASysNum).compPointer[CompIndex]->simulate(state,
705 : CompName,
706 : FirstHVACIteration,
707 : AirLoopNum,
708 : CompIndex,
709 : HeatingActive,
710 : CoolingActive,
711 : CompIndex,
712 : OAUCoilOutTemp,
713 : ZoneEquipFlag,
714 : sensOut,
715 0 : latOut);
716 : }
717 0 : if (state.dataMixedAir->MyOneTimeCheckUnitarySysFlag(OASysNum)) {
718 0 : UnitarySystems::UnitarySys::getUnitarySysHeatCoolCoil(state, CompName, OACoolingCoil, OAHeatingCoil, 0);
719 0 : UnitarySystems::UnitarySys::checkUnitarySysCoilInOASysExists(state, CompName, 0);
720 0 : if (Sim) state.dataMixedAir->MyOneTimeCheckUnitarySysFlag(OASysNum) = false;
721 : }
722 4399817 : } else if (CompTypeNum == SimAirServingZones::CompType::DXHeatPumpSystem) {
723 0 : if (Sim) {
724 0 : SimDXHeatPumpSystem(state, CompName, FirstHVACIteration, AirLoopNum, CompIndex);
725 : }
726 0 : OAHeatingCoil = true;
727 4399817 : } else if (CompTypeNum == SimAirServingZones::CompType::CoilUserDefined) {
728 26786 : if (Sim) {
729 26782 : SimCoilUserDefined(state, CompName, CompIndex, AirLoopNum, OAHeatingCoil, OACoolingCoil);
730 : }
731 : // Heat recovery
732 4373031 : } else if (CompTypeNum ==
733 : SimAirServingZones::CompType::HeatXchngr) { // 'HeatExchanger:AirToAir:FlatPlate', 'HeatExchanger:AirToAir:SensibleAndLatent',
734 : // 'HeatExchanger:Desiccant:BalancedFlow'
735 1730644 : if (Sim) {
736 1730592 : if (state.dataAirLoop->OutsideAirSys(OASysNum).AirLoopDOASNum > -1) {
737 0 : AirloopPLR = 1.0;
738 0 : FanOpMode = DataHVACGlobals::ContFanCycCoil;
739 : } else {
740 1730592 : if (state.dataAirLoop->AirLoopControlInfo(AirLoopNum).FanOpMode == DataHVACGlobals::CycFanCycCoil) {
741 0 : FanOpMode = DataHVACGlobals::CycFanCycCoil;
742 : } else {
743 1730592 : FanOpMode = DataHVACGlobals::ContFanCycCoil;
744 : }
745 1730592 : if (FanOpMode == DataHVACGlobals::CycFanCycCoil) {
746 : // HX's in the OA system can be troublesome given that the OA flow rate is not necessarily proportional to air loop PLR
747 : // adding that user input for branch flow rate, HX nominal flow rate, OA system min/max flow rate will not necessarily be
748 : // perfectly input, a compromise is used for OA sys HX's as the ratio of flow to max. Issue #4298.
749 : // AirloopPLR = AirLoopFlow( AirLoopNum ).FanPLR;
750 0 : AirloopPLR = state.dataMixedAir->OAController(OASysNum).OAMassFlow / state.dataMixedAir->OAController(OASysNum).MaxOAMassFlowRate;
751 : } else {
752 1730592 : AirloopPLR = 1.0;
753 : }
754 : }
755 1730592 : if (state.dataAirLoop->OutsideAirSys(OASysNum).AirLoopDOASNum > -1) {
756 0 : SimHeatRecovery(state, CompName, FirstHVACIteration, CompIndex, FanOpMode, AirloopPLR, _, _, _, _, _);
757 : } else {
758 5191776 : SimHeatRecovery(state,
759 : CompName,
760 : FirstHVACIteration,
761 : CompIndex,
762 : FanOpMode,
763 : AirloopPLR,
764 : _,
765 : _,
766 : _,
767 1730592 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).HeatRecoveryBypass,
768 1730592 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).HighHumCtrlActive);
769 : }
770 : }
771 1730644 : OAHX = true;
772 :
773 : // Desiccant Dehumidifier
774 2642387 : } else if (CompTypeNum == SimAirServingZones::CompType::Desiccant) { // 'Dehumidifier:Desiccant:NoFans'
775 : // 'Dehumidifier:Desiccant:System'
776 246811 : if (Sim) {
777 246801 : SimDesiccantDehumidifier(state, CompName, FirstHVACIteration, CompIndex);
778 : }
779 246811 : OAHX = true;
780 :
781 : // Humidifiers
782 2395576 : } else if (CompTypeNum == SimAirServingZones::CompType::Humidifier) { // 'Humidifier:Steam:Electric'
783 : // 'Humidifier:Steam:Gas'
784 47789 : if (Sim) {
785 47787 : SimHumidifier(state, CompName, FirstHVACIteration, CompIndex);
786 : }
787 :
788 : // Unglazed Transpired Solar Collector
789 2347787 : } else if (CompTypeNum == SimAirServingZones::CompType::Unglazed_SolarCollector) { // 'SolarCollector:UnglazedTranspired'
790 40693 : if (Sim) {
791 40675 : SimTranspiredCollector(state, CompName, CompIndex);
792 : }
793 :
794 : // Air-based Photovoltaic-thermal flat plate collector
795 2307094 : } else if (CompTypeNum == SimAirServingZones::CompType::PVT_AirBased) { // 'SolarCollector:FlatPlate:PhotovoltaicThermal'
796 45653 : if (Sim) {
797 45643 : if (CompIndex == 0) {
798 5 : CompIndex = PhotovoltaicThermalCollectors::getPVTindexFromName(state, CompName);
799 : }
800 45643 : PhotovoltaicThermalCollectors::simPVTfromOASys(state, CompIndex, FirstHVACIteration);
801 : }
802 :
803 : // Evaporative Cooler Types
804 2261441 : } else if (CompTypeNum ==
805 : SimAirServingZones::CompType::EvapCooler) { // 'EvaporativeCooler:Direct:CelDekPad','EvaporativeCooler:Indirect:CelDekPad'
806 : // 'EvaporativeCooler:Indirect:WetCoil','EvaporativeCooler:Indirect:ResearchSpecial'
807 2258255 : if (Sim) {
808 2258227 : SimEvapCooler(state, CompName, CompIndex);
809 : }
810 :
811 3186 : } else if (CompTypeNum == SimAirServingZones::CompType::ZoneVRFasAirLoopEquip) { // 'ZoneHVAC:TerminalUnit:VariableRefrigerantFlow'
812 3186 : if (Sim) {
813 3184 : int ControlledZoneNum = 0;
814 3184 : bool HeatingActive = false;
815 3184 : bool CoolingActive = false;
816 3184 : int constexpr OAUnitNum = 0;
817 3184 : Real64 constexpr OAUCoilOutTemp = 0.0;
818 3184 : bool constexpr ZoneEquipment = false;
819 3184 : Real64 sysOut = 0.0;
820 3184 : Real64 latOut = 0.0;
821 3184 : HVACVariableRefrigerantFlow::SimulateVRF(state,
822 : CompName,
823 : FirstHVACIteration,
824 : ControlledZoneNum,
825 : CompIndex,
826 : HeatingActive,
827 : CoolingActive,
828 : OAUnitNum,
829 : OAUCoilOutTemp,
830 : ZoneEquipment,
831 : sysOut,
832 : latOut);
833 : } else {
834 2 : HVACVariableRefrigerantFlow::isVRFCoilPresent(state, CompName, OACoolingCoil, OAHeatingCoil);
835 : }
836 :
837 : } else {
838 0 : ShowFatalError(state, "Invalid Outside Air Component=" + CompType);
839 : }
840 31938724 : }
841 :
842 43707297 : void SimOAMixer(EnergyPlusData &state, std::string const &CompName, bool const FirstHVACIteration, int &CompIndex)
843 : {
844 :
845 : // SUBROUTINE INFORMATION:
846 : // AUTHOR Fred Buhl
847 : // DATE WRITTEN Oct 1998
848 : // MODIFIED na
849 : // RE-ENGINEERED na
850 :
851 : // PURPOSE OF THIS SUBROUTINE
852 : // Simulate an Outside Air Mixer component
853 :
854 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
855 : int OAMixerNum;
856 :
857 43707297 : if (state.dataMixedAir->GetOAMixerInputFlag) {
858 0 : GetOAMixerInputs(state);
859 0 : state.dataMixedAir->GetOAMixerInputFlag = false;
860 : }
861 :
862 43707297 : if (CompIndex == 0) {
863 1167 : OAMixerNum = UtilityRoutines::FindItemInList(CompName, state.dataMixedAir->OAMixer);
864 1167 : CompIndex = OAMixerNum;
865 1167 : if (OAMixerNum == 0) {
866 0 : ShowFatalError(state, "SimOAMixer: OutdoorAir:Mixer not found=" + CompName);
867 : }
868 : } else {
869 43706130 : OAMixerNum = CompIndex;
870 : }
871 :
872 43707297 : InitOAMixer(state, OAMixerNum, FirstHVACIteration);
873 :
874 43707297 : CalcOAMixer(state, OAMixerNum);
875 :
876 43707297 : UpdateOAMixer(state, OAMixerNum);
877 :
878 43707297 : ReportOAMixer(OAMixerNum);
879 43707297 : }
880 :
881 24821703 : void SimOAController(EnergyPlusData &state, std::string const &CtrlName, int &CtrlIndex, bool const FirstHVACIteration, int const AirLoopNum)
882 : {
883 :
884 : // SUBROUTINE INFORMATION:
885 : // AUTHOR Fred Buhl
886 : // DATE WRITTEN Oct 1998
887 : // MODIFIED na
888 : // RE-ENGINEERED na
889 :
890 : // PURPOSE OF THIS SUBROUTINE
891 : // Simulate an Outside Air Controller component
892 :
893 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
894 : int OAControllerNum;
895 :
896 24821703 : if ((state.dataMixedAir->GetOAControllerInputFlag) &&
897 : (AirLoopNum > 0)) { // Gets input for object first time Sim routine is called from an airloop
898 393 : GetOAControllerInputs(state);
899 393 : state.dataMixedAir->GetOAControllerInputFlag = false;
900 : }
901 :
902 24821703 : if (CtrlIndex == 0) {
903 1021 : if (state.dataMixedAir->NumOAControllers > 0) {
904 1021 : OAControllerNum = UtilityRoutines::FindItemInList(CtrlName, state.dataMixedAir->OAController);
905 : } else {
906 0 : OAControllerNum = 0;
907 : }
908 1021 : CtrlIndex = OAControllerNum;
909 1021 : if (OAControllerNum == 0) {
910 0 : ShowFatalError(state, "SimOAController: Outside Air Controller not found=" + CtrlName);
911 : }
912 : } else {
913 24820682 : OAControllerNum = CtrlIndex;
914 : }
915 :
916 24821703 : InitOAController(state, OAControllerNum, FirstHVACIteration, AirLoopNum);
917 :
918 24821703 : state.dataMixedAir->OAController(OAControllerNum).CalcOAController(state, AirLoopNum, FirstHVACIteration);
919 24821703 : state.dataMixedAir->OAController(OAControllerNum).UpdateOAController(state);
920 24821703 : }
921 :
922 : // Get Input Section of the Module
923 : //******************************************************************************
924 :
925 770 : void GetOutsideAirSysInputs(EnergyPlusData &state)
926 : {
927 :
928 : // SUBROUTINE INFORMATION:
929 : // AUTHOR Fred Buhl
930 : // DATE WRITTEN Oct 1998
931 : // MODIFIED na
932 : // RE-ENGINEERED na
933 :
934 : // PURPOSE OF THIS SUBROUTINE
935 : // Input the Outside Air System data and store it in the OutsideAirSys array.
936 :
937 : // METHODOLOGY EMPLOYED:
938 : // Use the Get routines from the InputProcessor module.
939 :
940 : // Using/Aliasing
941 : using BranchNodeConnections::SetUpCompSets;
942 : using BranchNodeConnections::TestCompSet;
943 :
944 : // Locals
945 : // SUBROUTINE PARAMETER DEFINITIONS:
946 : static constexpr std::string_view RoutineName("GetOutsideAirSysInputs: "); // include trailing blank space
947 :
948 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
949 :
950 : int NumNums; // Number of real numbers returned by GetObjectItem
951 : int NumAlphas; // Number of alphanumerics returned by GetObjectItem
952 : int IOStat;
953 1540 : Array1D<Real64> NumArray;
954 1540 : Array1D_string AlphArray;
955 : int OASysNum;
956 : int CompNum;
957 : int Item;
958 : // unused0909INTEGER :: NumComponents
959 : int AlphaNum;
960 1540 : std::string ComponentListName;
961 1540 : std::string ControllerListName;
962 : int NumInList;
963 : int InListNum;
964 : int ListNum;
965 : int NumSimpControllers; // number of Controller:Simple objects in an OA System
966 770 : bool ErrorsFound(false);
967 1540 : std::string CurrentModuleObject; // Object type for getting and messages
968 1540 : Array1D_string cAlphaFields; // Alpha field names
969 1540 : Array1D_string cNumericFields; // Numeric field names
970 1540 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
971 1540 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
972 770 : int MaxNums(0); // Maximum number of numeric input fields
973 770 : int MaxAlphas(0); // Maximum number of alpha input fields
974 770 : int TotalArgs(0); // Total number of alpha and numeric arguments (max) for a
975 : // certain object in the input file
976 :
977 770 : if (!state.dataMixedAir->GetOASysInputFlag) return;
978 :
979 1540 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
980 770 : state, CurrentModuleObjects(static_cast<int>(CMO::OASystem)), TotalArgs, NumAlphas, NumNums);
981 770 : MaxNums = max(MaxNums, NumNums);
982 770 : MaxAlphas = max(MaxAlphas, NumAlphas);
983 1540 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
984 770 : state, CurrentModuleObjects(static_cast<int>(CMO::AirLoopEqList)), TotalArgs, NumAlphas, NumNums);
985 770 : MaxNums = max(MaxNums, NumNums);
986 770 : MaxAlphas = max(MaxAlphas, NumAlphas);
987 1540 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
988 770 : state, CurrentModuleObjects(static_cast<int>(CMO::ControllerList)), TotalArgs, NumAlphas, NumNums);
989 770 : MaxNums = max(MaxNums, NumNums);
990 770 : MaxAlphas = max(MaxAlphas, NumAlphas);
991 :
992 770 : AlphArray.allocate(MaxAlphas);
993 770 : cAlphaFields.allocate(MaxAlphas);
994 770 : NumArray.dimension(MaxNums, 0.0);
995 770 : cNumericFields.allocate(MaxNums);
996 770 : lAlphaBlanks.dimension(MaxAlphas, true);
997 770 : lNumericBlanks.dimension(MaxNums, true);
998 :
999 770 : CurrentModuleObject = CurrentModuleObjects(static_cast<int>(CMO::ControllerList));
1000 770 : state.dataMixedAir->NumControllerLists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
1001 :
1002 770 : state.dataMixedAir->ControllerLists.allocate(state.dataMixedAir->NumControllerLists);
1003 :
1004 2212 : for (Item = 1; Item <= state.dataMixedAir->NumControllerLists; ++Item) {
1005 :
1006 : // create a reference for convenience
1007 1442 : auto &thisControllerList(state.dataMixedAir->ControllerLists(Item));
1008 1442 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1009 : CurrentModuleObject,
1010 : Item,
1011 : AlphArray,
1012 : NumAlphas,
1013 : NumArray,
1014 : NumNums,
1015 : IOStat,
1016 : lNumericBlanks,
1017 : lAlphaBlanks,
1018 : cAlphaFields,
1019 : cNumericFields);
1020 1442 : UtilityRoutines::IsNameEmpty(state, AlphArray(1), CurrentModuleObject, ErrorsFound);
1021 1442 : thisControllerList.Name = AlphArray(1);
1022 1442 : thisControllerList.NumControllers = (NumAlphas - 1) / 2;
1023 1442 : thisControllerList.ControllerType.allocate(thisControllerList.NumControllers);
1024 1442 : thisControllerList.ControllerName.allocate(thisControllerList.NumControllers);
1025 1442 : AlphaNum = 2;
1026 3290 : for (CompNum = 1; CompNum <= thisControllerList.NumControllers; ++CompNum) {
1027 4722 : if (UtilityRoutines::SameString(AlphArray(AlphaNum), "Controller:WaterCoil") ||
1028 2874 : UtilityRoutines::SameString(AlphArray(AlphaNum), "Controller:OutdoorAir")) {
1029 1848 : thisControllerList.ControllerType(CompNum) = AlphArray(AlphaNum);
1030 1848 : thisControllerList.ControllerName(CompNum) = AlphArray(AlphaNum + 1);
1031 : // loop over all previous controller lists to check if this controllers is also present on previous controllers
1032 9328 : for (int previousListNum = 1; previousListNum < Item; ++previousListNum) {
1033 : // loop over each of the controllers listed for this list
1034 7480 : auto &previousList(state.dataMixedAir->ControllerLists(previousListNum));
1035 17315 : for (int PreviousListControllerNum = 1; PreviousListControllerNum <= previousList.NumControllers; ++PreviousListControllerNum) {
1036 17335 : if ((previousList.ControllerType(PreviousListControllerNum) == thisControllerList.ControllerType(CompNum)) &&
1037 7500 : (previousList.ControllerName(PreviousListControllerNum) == thisControllerList.ControllerName(CompNum))) {
1038 0 : ShowSevereError(state, "Controller instance repeated in multiple " + CurrentModuleObject + " objects");
1039 0 : ShowContinueError(state, "Found in " + CurrentModuleObject + " = " + thisControllerList.Name);
1040 0 : ShowContinueError(state, "Also found in " + CurrentModuleObject + " = " + previousList.Name);
1041 0 : ErrorsFound = true;
1042 : }
1043 : }
1044 : }
1045 : } else {
1046 0 : ShowSevereError(state, "For " + CurrentModuleObject + "=\"" + AlphArray(1) + "\" invalid " + cAlphaFields(AlphaNum));
1047 0 : ShowContinueError(state, "...entered=\"" + AlphArray(AlphaNum) + "\", should be Controller:WaterCoil or Controller:OutdoorAir.");
1048 0 : ErrorsFound = true;
1049 : }
1050 1848 : AlphaNum += 2;
1051 : }
1052 : }
1053 :
1054 770 : CurrentModuleObject = CurrentModuleObjects(static_cast<int>(CMO::OASystem));
1055 :
1056 770 : state.dataAirLoop->NumOASystems = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
1057 :
1058 770 : state.dataAirLoop->OutsideAirSys.allocate(state.dataAirLoop->NumOASystems);
1059 770 : state.dataSize->OASysEqSizing.allocate(state.dataAirLoop->NumOASystems);
1060 770 : state.dataMixedAir->ControllerListUniqueNames.reserve(static_cast<unsigned>(state.dataAirLoop->NumOASystems));
1061 770 : state.dataMixedAir->MyOneTimeErrorFlag.dimension(state.dataAirLoop->NumOASystems, true);
1062 770 : state.dataMixedAir->MyOneTimeCheckUnitarySysFlag.dimension(state.dataAirLoop->NumOASystems, true);
1063 770 : state.dataMixedAir->initOASysFlag.dimension(state.dataAirLoop->NumOASystems, true);
1064 :
1065 1797 : for (OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; ++OASysNum) {
1066 :
1067 1027 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1068 : CurrentModuleObject,
1069 : OASysNum,
1070 : AlphArray,
1071 : NumAlphas,
1072 : NumArray,
1073 : NumNums,
1074 : IOStat,
1075 : lNumericBlanks,
1076 : lAlphaBlanks,
1077 : cAlphaFields,
1078 : cNumericFields);
1079 1027 : UtilityRoutines::IsNameEmpty(state, AlphArray(1), CurrentModuleObject, ErrorsFound);
1080 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).Name = AlphArray(1);
1081 1027 : if (!AlphArray(2).empty()) {
1082 3081 : GlobalNames::IntraObjUniquenessCheck(
1083 3081 : state, AlphArray(2), CurrentModuleObject, cAlphaFields(2), state.dataMixedAir->ControllerListUniqueNames, ErrorsFound);
1084 : }
1085 1027 : ControllerListName = AlphArray(2);
1086 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).ControllerListName = AlphArray(2);
1087 1027 : ComponentListName = AlphArray(3);
1088 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentListName = AlphArray(3);
1089 :
1090 1027 : TestCompSet(state, CurrentModuleObject, AlphArray(1), "UNDEFINED", "UNDEFINED", "Air Nodes");
1091 :
1092 1027 : if (!lAlphaBlanks(3)) {
1093 2054 : ListNum = state.dataInputProcessing->inputProcessor->getObjectItemNum(
1094 1027 : state, CurrentModuleObjects(static_cast<int>(CMO::AirLoopEqList)), ComponentListName);
1095 1027 : if (ListNum > 0) {
1096 2054 : state.dataInputProcessing->inputProcessor->getObjectItem(
1097 1027 : state, CurrentModuleObjects(static_cast<int>(CMO::AirLoopEqList)), ListNum, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
1098 1027 : NumInList = (NumAlphas - 1) / 2;
1099 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).NumComponents = NumInList;
1100 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName.allocate(NumInList);
1101 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType.allocate(NumInList);
1102 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum.dimension(NumInList, SimAirServingZones::CompType::Invalid);
1103 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentIndex.dimension(NumInList, 0);
1104 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).InletNodeNum.dimension(NumInList, 0);
1105 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).OutletNodeNum.dimension(NumInList, 0);
1106 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).compPointer.resize(NumInList + 1, nullptr);
1107 2176 : for (InListNum = 1; InListNum <= NumInList; ++InListNum) {
1108 1149 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(InListNum) = AlphArray(InListNum * 2 + 1);
1109 1149 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(InListNum) = AlphArray(InListNum * 2);
1110 :
1111 : // Add equipment to component sets array
1112 3447 : SetUpCompSets(state,
1113 : CurrentModuleObject,
1114 1149 : state.dataAirLoop->OutsideAirSys(OASysNum).Name,
1115 1149 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(InListNum),
1116 1149 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(InListNum),
1117 : "UNDEFINED",
1118 1149 : "UNDEFINED");
1119 : }
1120 : } else {
1121 0 : ShowSevereError(
1122 0 : state, CurrentModuleObject + " = \"" + AlphArray(1) + "\" invalid " + cAlphaFields(3) + "=\"" + AlphArray(3) + "\" not found.");
1123 0 : ErrorsFound = true;
1124 : }
1125 : } else {
1126 0 : ShowSevereError(state, CurrentModuleObject + " = \"" + AlphArray(1) + "\" invalid " + cAlphaFields(3) + " is blank and must be entered.");
1127 0 : ErrorsFound = true;
1128 : }
1129 :
1130 1027 : ListNum = 0;
1131 1027 : NumSimpControllers = 0;
1132 1027 : if (!lAlphaBlanks(2)) {
1133 2054 : ListNum = state.dataInputProcessing->inputProcessor->getObjectItemNum(
1134 1027 : state, CurrentModuleObjects(static_cast<int>(CMO::ControllerList)), ControllerListName);
1135 1027 : if (ListNum > 0) {
1136 2054 : state.dataInputProcessing->inputProcessor->getObjectItem(
1137 1027 : state, CurrentModuleObjects(static_cast<int>(CMO::ControllerList)), ListNum, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
1138 1027 : NumInList = (NumAlphas - 1) / 2;
1139 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).NumControllers = NumInList;
1140 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).ControllerName.allocate(NumInList);
1141 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).ControllerType.allocate(NumInList);
1142 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).ControllerIndex.dimension(NumInList, 0);
1143 2107 : for (InListNum = 1; InListNum <= NumInList; ++InListNum) {
1144 1080 : state.dataAirLoop->OutsideAirSys(OASysNum).ControllerName(InListNum) = AlphArray(InListNum * 2 + 1);
1145 1080 : state.dataAirLoop->OutsideAirSys(OASysNum).ControllerType(InListNum) = AlphArray(InListNum * 2);
1146 1080 : if (!UtilityRoutines::SameString(state.dataAirLoop->OutsideAirSys(OASysNum).ControllerType(InListNum),
1147 1080 : CurrentModuleObjects(static_cast<int>(CMO::OAController)))) {
1148 54 : ++NumSimpControllers;
1149 : }
1150 : }
1151 : } else {
1152 0 : ShowSevereError(
1153 0 : state, CurrentModuleObject + " = \"" + AlphArray(1) + "\" invalid " + cAlphaFields(2) + "=\"" + AlphArray(2) + "\" not found.");
1154 0 : ErrorsFound = true;
1155 : }
1156 : } else {
1157 0 : if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirLoopHVAC:DedicatedOutdoorAirSystem") == 0) {
1158 0 : ShowSevereError(state,
1159 0 : CurrentModuleObject + " = \"" + AlphArray(1) + "\" invalid " + cAlphaFields(2) + " is blank and must be entered.");
1160 0 : ErrorsFound = true;
1161 : } else {
1162 0 : ShowWarningError(state,
1163 0 : CurrentModuleObject + " = \"" + AlphArray(1) + "\": blank " + cAlphaFields(2) +
1164 : " must be used with AirLoopHVAC:DedicatedOutdoorAirSystem.");
1165 : }
1166 : }
1167 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).ControllerListNum = ListNum;
1168 1027 : state.dataAirLoop->OutsideAirSys(OASysNum).NumSimpleControllers = NumSimpControllers;
1169 : }
1170 :
1171 1797 : for (OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; ++OASysNum) {
1172 2176 : for (CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(OASysNum).NumComponents; ++CompNum) {
1173 2298 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum) = static_cast<SimAirServingZones::CompType>(getEnumerationValue(
1174 3447 : CompTypeNamesUC, UtilityRoutines::MakeUPPERCase(state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(CompNum))));
1175 1149 : if (state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum) == SimAirServingZones::CompType::Fan_System_Object) {
1176 : // construct fan object
1177 2 : state.dataHVACFan->fanObjs.emplace_back(
1178 2 : new HVACFan::FanSystem(state, state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(CompNum)));
1179 1 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentIndex(CompNum) = state.dataHVACFan->fanObjs.size();
1180 1148 : } else if (state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum) == SimAirServingZones::CompType::CoilSystemWater) {
1181 1 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentIndex(CompNum) = CompNum;
1182 2 : UnitarySystems::UnitarySys thisSys;
1183 1 : state.dataAirLoop->OutsideAirSys(OASysNum).compPointer[CompNum] = thisSys.factory(
1184 1 : state, DataHVACGlobals::UnitarySys_AnyCoilType, state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(CompNum), false, 0);
1185 1147 : } else if (state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum) == SimAirServingZones::CompType::UnitarySystemModel) {
1186 0 : UnitarySystems::UnitarySys thisSys;
1187 0 : state.dataAirLoop->OutsideAirSys(OASysNum).compPointer[CompNum] = thisSys.factory(
1188 0 : state, DataHVACGlobals::UnitarySys_AnyCoilType, state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(CompNum), false, 0);
1189 0 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentIndex(CompNum) =
1190 0 : UnitarySystems::getUnitarySystemIndex(state, state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(CompNum)) + 1;
1191 1147 : } else if (state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum) == SimAirServingZones::CompType::Invalid) {
1192 74 : std::string thisComp = UtilityRoutines::MakeUPPERCase(state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(CompNum));
1193 37 : if (thisComp == "HEATEXCHANGER:AIRTOAIR:SENSIBLEANDLATENT" || thisComp == "HEATEXCHANGER:DESICCANT:BALANCEDFLOW") {
1194 21 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum) = SimAirServingZones::CompType::HeatXchngr;
1195 16 : } else if (thisComp == "DEHUMIDIFIER:DESICCANT:SYSTEM") {
1196 2 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum) = SimAirServingZones::CompType::Desiccant;
1197 56 : } else if (thisComp == "EVAPORATIVECOOLER:INDIRECT:CELDEKPAD" || thisComp == "EVAPORATIVECOOLER:INDIRECT:WETCOIL" ||
1198 36 : thisComp == "EVAPORATIVECOOLER:INDIRECT:RESEARCHSPECIAL" || thisComp == "EVAPORATIVECOOLER:DIRECT:RESEARCHSPECIAL") {
1199 14 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum) = SimAirServingZones::CompType::EvapCooler;
1200 0 : } else if (thisComp == "HUMIDIFIER:STEAM:GAS") {
1201 0 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum) = SimAirServingZones::CompType::Humidifier;
1202 : } else {
1203 0 : ShowSevereError(state,
1204 0 : CurrentModuleObject + " = \"" + AlphArray(1) + "\" invalid Outside Air Component=\"" +
1205 0 : state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(CompNum) + "\".");
1206 0 : ErrorsFound = true;
1207 : }
1208 : }
1209 : }
1210 :
1211 : // loop through the controllers in the controller list for OA system and save the pointer to the OA controller index
1212 1029 : for (int OAControllerNum = 1; OAControllerNum <= state.dataAirLoop->OutsideAirSys(OASysNum).NumControllers; ++OAControllerNum) {
1213 1028 : if (UtilityRoutines::SameString(state.dataAirLoop->OutsideAirSys(OASysNum).ControllerType(OAControllerNum),
1214 1028 : CurrentModuleObjects(static_cast<int>(CMO::OAController)))) {
1215 2052 : state.dataAirLoop->OutsideAirSys(OASysNum).OAControllerName =
1216 2052 : state.dataAirLoop->OutsideAirSys(OASysNum).ControllerName(OAControllerNum);
1217 1026 : break;
1218 : }
1219 : }
1220 : }
1221 :
1222 770 : if (ErrorsFound) {
1223 0 : ShowFatalError(state, std::string{RoutineName} + "Errors found in getting " + CurrentModuleObject + '.');
1224 : }
1225 :
1226 770 : AlphArray.deallocate();
1227 770 : cAlphaFields.deallocate();
1228 770 : NumArray.deallocate();
1229 770 : cNumericFields.deallocate();
1230 770 : lAlphaBlanks.deallocate();
1231 770 : lNumericBlanks.deallocate();
1232 :
1233 770 : state.dataMixedAir->GetOASysInputFlag = false;
1234 : }
1235 :
1236 393 : void GetOAControllerInputs(EnergyPlusData &state)
1237 : {
1238 :
1239 : // SUBROUTINE INFORMATION:
1240 : // AUTHOR Fred Buhl
1241 : // DATE WRITTEN Oct 1998
1242 : // MODIFIED Shirey/Raustad FSEC, June 2003, Jan 2004
1243 : // Mangesh Basarkar, 06/2011: Getting zone OA specifications from Design Specification Object
1244 : // Tianzhen Hong, 3/2012: getting zone air distribution effectiveness and secondary recirculation
1245 : // from DesignSpecification:ZoneAirDistribution objects
1246 :
1247 : // PURPOSE OF THIS SUBROUTINE
1248 : // Input the OAController data and store it in the OAController array.
1249 : // Input the Ventilation:Mechanical data and store it in the VentilationMechanical array.
1250 : // Condense Ventilation:Mechanical data array to include only unique zones specified for each instance of this object.
1251 :
1252 : // METHODOLOGY EMPLOYED:
1253 : // Use the Get routines from the InputProcessor module.
1254 :
1255 : // Using/Aliasing
1256 : using namespace DataDefineEquip;
1257 : using namespace OutputReportPredefined;
1258 :
1259 : using Curve::GetCurveIndex;
1260 : using OutAirNodeManager::CheckOutAirNodeNumber;
1261 :
1262 : // SUBROUTINE PARAMETER DEFINITIONS:
1263 : static constexpr std::string_view RoutineName("GetOAControllerInputs: "); // include trailing blank space
1264 :
1265 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1266 :
1267 : int ZoneNum; // zone number attached to a given air loop
1268 : int NumNums; // Number of real numbers returned by GetObjectItem
1269 : int NumAlphas; // Number of alphanumerics returned by GetObjectItem
1270 : int OutAirNum; // Number of Controller:OutdoorAir or CONTROLLER:STAND ALONE ERV objects
1271 : int OAControllerNum; // Index to Controller:OutdoorAir or CONTROLLER:STAND ALONE ERV objects
1272 : int VentMechNum; // Number of VENTILATION:MECHANICAL objects
1273 : int groupNum; // Index to group in extensible VENTILATION:MECHANICAL object
1274 : int IOStat; // Status of GetObjectItem call
1275 786 : Array1D<Real64> NumArray;
1276 786 : Array1D_string AlphArray;
1277 786 : std::string CurrentModuleObject; // Object type for getting and messages
1278 786 : Array1D_string cAlphaFields; // Alpha field names
1279 786 : Array1D_string cNumericFields; // Numeric field names
1280 786 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
1281 786 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
1282 393 : bool ErrorsFound(false); // Flag identifying errors found during get input
1283 : int ZoneListNum; // Index to Zone List
1284 : int MechVentZoneCount; // Index counter for zones with mechanical ventilation
1285 : int NumArg; // Number of arguments from GetObjectDefMaxArgs call
1286 : int MaxAlphas; // Maximum alphas in multiple objects
1287 : int MaxNums; // Maximum numbers in multiple objects
1288 :
1289 : int NumGroups; // Number of extensible input groups of the VentilationMechanical object
1290 393 : int ObjIndex(0);
1291 393 : int EquipListIndex(0);
1292 393 : int EquipNum(0);
1293 393 : int EquipListNum(0);
1294 393 : int ADUNum(0);
1295 : int jZone;
1296 : int i;
1297 :
1298 : // Formats
1299 :
1300 : // First, call other get input routines in this module to make sure data is filled during this routine.
1301 393 : if (state.dataMixedAir->GetOASysInputFlag) { // Gets input for object first time Sim routine is called
1302 0 : GetOutsideAirSysInputs(state);
1303 0 : state.dataMixedAir->GetOASysInputFlag = false;
1304 : }
1305 393 : if (state.dataMixedAir->GetOAMixerInputFlag) { // Gets input for object first time Sim routine is called
1306 0 : GetOAMixerInputs(state);
1307 0 : state.dataMixedAir->GetOAMixerInputFlag = false;
1308 : }
1309 :
1310 393 : FaultsManager::CheckAndReadFaults(state);
1311 :
1312 786 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
1313 393 : state, CurrentModuleObjects(static_cast<int>(CMO::OAController)), NumArg, NumAlphas, NumNums);
1314 393 : MaxAlphas = NumAlphas;
1315 393 : MaxNums = NumNums;
1316 786 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
1317 393 : state, CurrentModuleObjects(static_cast<int>(CMO::ERVController)), NumArg, NumAlphas, NumNums);
1318 393 : MaxAlphas = max(MaxAlphas, NumAlphas);
1319 393 : MaxNums = max(MaxNums, NumNums);
1320 786 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
1321 393 : state, CurrentModuleObjects(static_cast<int>(CMO::MechVentilation)), NumArg, NumAlphas, NumNums);
1322 393 : MaxAlphas = max(MaxAlphas, NumAlphas);
1323 393 : MaxNums = max(MaxNums, NumNums);
1324 :
1325 393 : AlphArray.allocate(MaxAlphas);
1326 393 : NumArray.dimension(MaxNums, 0.0);
1327 393 : lAlphaBlanks.dimension(MaxAlphas, true);
1328 393 : lNumericBlanks.dimension(MaxNums, true);
1329 393 : cAlphaFields.allocate(MaxAlphas);
1330 393 : cNumericFields.allocate(MaxNums);
1331 :
1332 : // Count OAcontrollers and ERVcontrollers and allocate arrays
1333 393 : AllocateOAControllers(state);
1334 :
1335 : // If there are ERV controllers, they have been filled before now NumOAControllers includes the count of NumERVControllers
1336 393 : if (state.dataMixedAir->NumOAControllers > state.dataMixedAir->NumERVControllers) {
1337 393 : CurrentModuleObject = CurrentModuleObjects(static_cast<int>(CMO::OAController));
1338 393 : int currentOAControllerNum = 0;
1339 1414 : for (OutAirNum = state.dataMixedAir->NumERVControllers + 1; OutAirNum <= state.dataMixedAir->NumOAControllers; ++OutAirNum) {
1340 1021 : ++currentOAControllerNum;
1341 1021 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1342 : CurrentModuleObject,
1343 : currentOAControllerNum,
1344 : AlphArray,
1345 : NumAlphas,
1346 : NumArray,
1347 : NumNums,
1348 : IOStat,
1349 : lNumericBlanks,
1350 : lAlphaBlanks,
1351 : cAlphaFields,
1352 : cNumericFields);
1353 2042 : GlobalNames::VerifyUniqueInterObjectName(
1354 2042 : state, state.dataMixedAir->OAControllerUniqueNames, AlphArray(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
1355 :
1356 1021 : ProcessOAControllerInputs(state,
1357 : CurrentModuleObject,
1358 : OutAirNum,
1359 : AlphArray,
1360 : NumAlphas,
1361 : NumArray,
1362 : NumNums,
1363 : lNumericBlanks,
1364 : lAlphaBlanks,
1365 : cAlphaFields,
1366 : cNumericFields,
1367 : ErrorsFound);
1368 :
1369 : // add applicable faults identifier to avoid string comparison at each time step
1370 : // loop through each fault for each OA controller and determine economizer faultys
1371 1041 : for (i = 1; i <= state.dataFaultsMgr->NumFaultyEconomizer; ++i) {
1372 20 : if (state.dataFaultsMgr->FaultsEconomizer(i).ControllerTypeEnum != iController_AirEconomizer) continue;
1373 20 : if (UtilityRoutines::SameString(state.dataMixedAir->OAController(OutAirNum).Name,
1374 20 : state.dataFaultsMgr->FaultsEconomizer(i).ControllerName)) {
1375 5 : state.dataFaultsMgr->FaultsEconomizer(i).ControllerID = OutAirNum;
1376 5 : ++state.dataMixedAir->OAController(OutAirNum).NumFaultyEconomizer;
1377 : }
1378 : }
1379 : // loop through each fault for each OA controller to determine faulty counts
1380 1021 : state.dataMixedAir->OAController(OutAirNum).EconmizerFaultNum.allocate(state.dataMixedAir->OAController(OutAirNum).NumFaultyEconomizer);
1381 1021 : if (state.dataMixedAir->OAController(OutAirNum).NumFaultyEconomizer > 0) {
1382 12 : for (int j = 0, i = 1; i <= state.dataFaultsMgr->NumFaultyEconomizer; ++i) {
1383 10 : if (state.dataFaultsMgr->FaultsEconomizer(i).ControllerTypeEnum != iController_AirEconomizer) continue;
1384 10 : if (UtilityRoutines::SameString(state.dataMixedAir->OAController(OutAirNum).Name,
1385 10 : state.dataFaultsMgr->FaultsEconomizer(i).ControllerName)) {
1386 5 : state.dataMixedAir->OAController(OutAirNum).EconmizerFaultNum(++j) = i;
1387 : }
1388 : }
1389 : }
1390 : } // LOOP FOR OutAirNum
1391 :
1392 393 : if (ErrorsFound) {
1393 0 : AlphArray.deallocate();
1394 0 : NumArray.deallocate();
1395 0 : lNumericBlanks.deallocate();
1396 0 : lAlphaBlanks.deallocate();
1397 0 : cAlphaFields.deallocate();
1398 0 : cNumericFields.deallocate();
1399 0 : ShowFatalError(state, std::string{RoutineName} + "Errors found in getting " + CurrentModuleObject + " inputs.");
1400 : }
1401 : }
1402 :
1403 393 : state.dataMixedAir->GetOAControllerInputFlag = false;
1404 :
1405 : // Process Controller:MechanicalVentilation objects
1406 393 : CurrentModuleObject = CurrentModuleObjects(static_cast<int>(CMO::MechVentilation));
1407 393 : state.dataMixedAir->NumVentMechControllers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
1408 393 : if (state.dataMixedAir->NumVentMechControllers > 0) {
1409 24 : state.dataMixedAir->VentilationMechanical.allocate(state.dataMixedAir->NumVentMechControllers);
1410 76 : for (VentMechNum = 1; VentMechNum <= state.dataMixedAir->NumVentMechControllers; ++VentMechNum) {
1411 52 : auto &thisVentilationMechanical(state.dataMixedAir->VentilationMechanical(VentMechNum));
1412 52 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1413 : CurrentModuleObject,
1414 : VentMechNum,
1415 : AlphArray,
1416 : NumAlphas,
1417 : NumArray,
1418 : NumNums,
1419 : IOStat,
1420 : lNumericBlanks,
1421 : lAlphaBlanks,
1422 : cAlphaFields,
1423 : cNumericFields);
1424 :
1425 52 : MechVentZoneCount = 0;
1426 :
1427 52 : NumGroups = (NumAlphas + NumNums - 5) / 3;
1428 52 : if (mod((NumAlphas + NumNums - 5), 3) != 0) ++NumGroups;
1429 52 : thisVentilationMechanical.Name = AlphArray(1);
1430 :
1431 52 : UtilityRoutines::IsNameEmpty(state, AlphArray(1), CurrentModuleObject, ErrorsFound);
1432 :
1433 52 : thisVentilationMechanical.SchName = AlphArray(2);
1434 52 : if (lAlphaBlanks(2)) {
1435 3 : thisVentilationMechanical.SchPtr = DataGlobalConstants::ScheduleAlwaysOn;
1436 : } else {
1437 49 : thisVentilationMechanical.SchPtr = GetScheduleIndex(state, AlphArray(2)); // convert schedule name to pointer
1438 49 : if (thisVentilationMechanical.SchPtr == 0) {
1439 0 : ShowSevereError(
1440 0 : state, CurrentModuleObject + "=\"" + AlphArray(1) + "\" invalid " + cAlphaFields(2) + "=\"" + AlphArray(2) + "\" not found.");
1441 0 : ErrorsFound = true;
1442 : }
1443 : }
1444 :
1445 : // Adding new flag for DCV
1446 52 : if (UtilityRoutines::SameString(AlphArray(3), "Yes")) {
1447 50 : thisVentilationMechanical.DCVFlag = true;
1448 2 : } else if (UtilityRoutines::SameString(AlphArray(3), "No") || lAlphaBlanks(3)) {
1449 2 : thisVentilationMechanical.DCVFlag = false;
1450 : } else {
1451 0 : ShowSevereError(state,
1452 0 : CurrentModuleObject + "=\"" + AlphArray(1) + "\" invalid value " + cAlphaFields(3) + "=\"" + AlphArray(3) + "\".");
1453 0 : ShowContinueError(state, "...Valid values are \"Yes\" or \"No\".");
1454 0 : ErrorsFound = true;
1455 : }
1456 :
1457 : // System outdoor air method
1458 52 : thisVentilationMechanical.SystemOAMethod =
1459 104 : static_cast<DataSizing::SysOAMethod>(getEnumerationValue(SOAMNamesUC, UtilityRoutines::MakeUPPERCase(AlphArray(4))));
1460 :
1461 103 : if (thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::IAQP ||
1462 101 : thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc ||
1463 100 : thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc ||
1464 99 : thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate ||
1465 49 : thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::IAQPCOM) {
1466 3 : if (!state.dataContaminantBalance->Contaminant.CO2Simulation) {
1467 0 : ShowSevereError(state,
1468 0 : CurrentModuleObject + "=\"" + AlphArray(1) + "\" valid " + cAlphaFields(2) + "=\"" + AlphArray(2) +
1469 : "\" requires CO2 simulation.");
1470 0 : ShowContinueError(state, "The choice must be Yes for the field Carbon Dioxide Concentration in ZoneAirContaminantBalance");
1471 0 : ErrorsFound = true;
1472 : }
1473 : }
1474 :
1475 103 : if (thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::IAQPGC ||
1476 51 : thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::IAQPCOM) {
1477 1 : if (!state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1478 0 : ShowSevereError(state,
1479 0 : CurrentModuleObject + "=\"" + AlphArray(1) + "\" valid " + cAlphaFields(2) + "=\"" + AlphArray(2) +
1480 : "\" requires generic contaminant simulation.");
1481 0 : ShowContinueError(state, "The choice must be Yes for the field Generic Contaminant Concentration in ZoneAirContaminantBalance");
1482 0 : ErrorsFound = true;
1483 : }
1484 : }
1485 :
1486 52 : if (thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::Invalid) { // If specified incorrectly, show errors
1487 0 : thisVentilationMechanical.SystemOAMethod = DataSizing::SysOAMethod::ZoneSum;
1488 0 : ShowWarningError(state,
1489 0 : CurrentModuleObject + "=\"" + AlphArray(1) + "\" incorrect specification for " + cAlphaFields(4) +
1490 : ", the ZoneSum method will be used.");
1491 : // ErrorsFound=.TRUE.
1492 : }
1493 :
1494 : // Zone maximum outdoor air fraction
1495 52 : thisVentilationMechanical.ZoneMaxOAFraction = NumArray(1);
1496 :
1497 52 : state.dataMixedAir->VentMechZoneOrListName.allocate(NumGroups);
1498 52 : state.dataMixedAir->DesignSpecOAObjName.allocate(NumGroups);
1499 52 : state.dataMixedAir->DesignSpecOAObjIndex.dimension(NumGroups, 0);
1500 52 : state.dataMixedAir->DesignSpecZoneADObjName.allocate(NumGroups);
1501 52 : state.dataMixedAir->DesignSpecZoneADObjIndex.dimension(NumGroups, 0);
1502 :
1503 : // First time through find the total number of zones requiring mechanical ventilation
1504 : // May include duplicate zones. Will check for duplicate zones further down in this subroutine.
1505 393 : for (groupNum = 1; groupNum <= NumGroups; ++groupNum) {
1506 341 : state.dataMixedAir->VentMechZoneOrListName(groupNum) = AlphArray((groupNum - 1) * 3 + 5);
1507 :
1508 : // Getting OA details from design specification OA object
1509 341 : if (!lAlphaBlanks((groupNum - 1) * 3 + 6)) {
1510 341 : state.dataMixedAir->DesignSpecOAObjName(groupNum) = AlphArray((groupNum - 1) * 3 + 6);
1511 341 : ObjIndex = UtilityRoutines::FindItemInList(state.dataMixedAir->DesignSpecOAObjName(groupNum), state.dataSize->OARequirements);
1512 341 : state.dataMixedAir->DesignSpecOAObjIndex(groupNum) = ObjIndex;
1513 :
1514 341 : if (ObjIndex == 0) {
1515 0 : ShowSevereError(state,
1516 0 : std::string{RoutineName} + CurrentModuleObject + "=\"" + thisVentilationMechanical.Name + "\", invalid");
1517 0 : ShowContinueError(state,
1518 0 : "... not found " + cAlphaFields((groupNum - 1) * 3 + 6) + "=\"" +
1519 0 : state.dataMixedAir->DesignSpecOAObjName(groupNum) + "\".");
1520 0 : ErrorsFound = true;
1521 : }
1522 : }
1523 :
1524 : // Get zone air distribution details from design specification Zone Air Distribution object
1525 341 : if (!lAlphaBlanks((groupNum - 1) * 3 + 7)) {
1526 341 : state.dataMixedAir->DesignSpecZoneADObjName(groupNum) = AlphArray((groupNum - 1) * 3 + 7);
1527 341 : ObjIndex =
1528 341 : UtilityRoutines::FindItemInList(state.dataMixedAir->DesignSpecZoneADObjName(groupNum), state.dataSize->ZoneAirDistribution);
1529 341 : state.dataMixedAir->DesignSpecZoneADObjIndex(groupNum) = ObjIndex;
1530 :
1531 341 : if (ObjIndex == 0) {
1532 : // Cannot find the design specification Zone Air Distribution object
1533 0 : ShowSevereError(state,
1534 0 : std::string{RoutineName} + CurrentModuleObject + "=\"" + thisVentilationMechanical.Name + "\", invalid");
1535 0 : ShowContinueError(state,
1536 0 : "... not found " + cAlphaFields((groupNum - 1) * 3 + 7) + "=\"" +
1537 0 : state.dataMixedAir->DesignSpecZoneADObjName(groupNum) + "\".");
1538 0 : ErrorsFound = true;
1539 : }
1540 : }
1541 :
1542 341 : ZoneNum = UtilityRoutines::FindItemInList(state.dataMixedAir->VentMechZoneOrListName(groupNum), state.dataHeatBal->Zone);
1543 341 : if (ZoneNum > 0) {
1544 335 : ++MechVentZoneCount;
1545 : } else {
1546 6 : ZoneListNum = UtilityRoutines::FindItemInList(state.dataMixedAir->VentMechZoneOrListName(groupNum), state.dataHeatBal->ZoneList);
1547 6 : if (ZoneListNum > 0) {
1548 6 : MechVentZoneCount += state.dataHeatBal->ZoneList(ZoneListNum).NumOfZones;
1549 : } else {
1550 0 : ShowWarningError(
1551 0 : state, CurrentModuleObject + "=\"" + AlphArray(1) + "\" invalid " + cAlphaFields((groupNum - 1) * 3 + 5) + " not found.");
1552 0 : ShowContinueError(
1553 0 : state, "Missing " + cAlphaFields((groupNum - 1) * 3 + 5) + " = " + state.dataMixedAir->VentMechZoneOrListName(groupNum));
1554 0 : ErrorsFound = true;
1555 : }
1556 : }
1557 : }
1558 :
1559 52 : thisVentilationMechanical.NumofVentMechZones = MechVentZoneCount;
1560 :
1561 : // Now allocate and store unique zone and associated ventilation rate information
1562 52 : thisVentilationMechanical.VentMechZone.dimension(MechVentZoneCount, 0);
1563 52 : thisVentilationMechanical.VentMechZoneName.dimension(MechVentZoneCount);
1564 52 : thisVentilationMechanical.ZoneDesignSpecOAObjName.dimension(MechVentZoneCount);
1565 52 : thisVentilationMechanical.ZoneDesignSpecOAObjIndex.dimension(MechVentZoneCount, 0);
1566 52 : thisVentilationMechanical.ZoneOAAreaRate.dimension(MechVentZoneCount, 0.0);
1567 52 : thisVentilationMechanical.ZoneOAPeopleRate.dimension(MechVentZoneCount, 0.0);
1568 52 : thisVentilationMechanical.ZoneOAFlowRate.dimension(MechVentZoneCount, 0.0);
1569 52 : thisVentilationMechanical.ZoneOAACHRate.dimension(MechVentZoneCount, 0.0);
1570 52 : thisVentilationMechanical.ZoneOAFlowMethod.dimension(MechVentZoneCount);
1571 52 : thisVentilationMechanical.ZoneOASchPtr.dimension(MechVentZoneCount, 0);
1572 52 : thisVentilationMechanical.OAPropCtlMinRateSchPtr.dimension(MechVentZoneCount, 0);
1573 :
1574 : // added for new DCV, 2/12/2009
1575 52 : thisVentilationMechanical.ZoneADEffCooling.dimension(MechVentZoneCount, 1.0);
1576 : // Zone air distribution effectiveness in heating mode
1577 52 : thisVentilationMechanical.ZoneADEffHeating.dimension(MechVentZoneCount, 1.0);
1578 : // Indices to the zone air distribution effectiveness schedules
1579 52 : thisVentilationMechanical.ZoneADEffSchPtr.dimension(MechVentZoneCount, 0);
1580 : // Zone air secondary recirculation ratio, added 3/2012
1581 52 : thisVentilationMechanical.ZoneSecondaryRecirculation.dimension(MechVentZoneCount, 0.0);
1582 52 : thisVentilationMechanical.ZoneDesignSpecADObjName.allocate(MechVentZoneCount);
1583 52 : thisVentilationMechanical.ZoneDesignSpecADObjIndex.dimension(MechVentZoneCount, 0);
1584 :
1585 52 : MechVentZoneCount = 0;
1586 :
1587 : // Loop through zone names and list of zone names, remove duplicate zones, and store designspec names and indexes
1588 393 : for (groupNum = 1; groupNum <= NumGroups; ++groupNum) {
1589 341 : ZoneNum = UtilityRoutines::FindItemInList(state.dataMixedAir->VentMechZoneOrListName(groupNum), state.dataHeatBal->Zone);
1590 341 : if (ZoneNum > 0) {
1591 335 : if (any_eq(thisVentilationMechanical.VentMechZone, ZoneNum)) {
1592 : // Disregard duplicate zone names, show warning and do not store data for this zone
1593 0 : ShowWarningError(state,
1594 0 : "Zone name = " + state.dataMixedAir->VentMechZoneOrListName(groupNum) + " for " + CurrentModuleObject +
1595 0 : " object = " + thisVentilationMechanical.Name);
1596 0 : ShowContinueError(state, "is specified more than once. The first ventilation values specified for this zone will be used");
1597 0 : ShowContinueError(state, "and the rest will be ignored. Simulation will continue..");
1598 : } else {
1599 : // Store unique zone names
1600 335 : ++MechVentZoneCount;
1601 335 : thisVentilationMechanical.VentMechZone(MechVentZoneCount) = ZoneNum;
1602 335 : thisVentilationMechanical.VentMechZoneName(MechVentZoneCount) = state.dataHeatBal->Zone(ZoneNum).Name;
1603 :
1604 : // Populating new temp array to hold design spec OA object for each zone
1605 335 : if (state.dataMixedAir->DesignSpecOAObjIndex(groupNum) > 0) {
1606 335 : thisVentilationMechanical.ZoneDesignSpecOAObjName(MechVentZoneCount) = state.dataMixedAir->DesignSpecOAObjName(groupNum);
1607 335 : thisVentilationMechanical.ZoneDesignSpecOAObjIndex(MechVentZoneCount) =
1608 335 : state.dataMixedAir->DesignSpecOAObjIndex(groupNum);
1609 : } else {
1610 0 : if (state.dataGlobal->DoZoneSizing) {
1611 0 : ObjIndex = UtilityRoutines::FindItemInList(state.dataMixedAir->VentMechZoneOrListName(groupNum),
1612 0 : state.dataSize->ZoneSizingInput,
1613 : &ZoneSizingInputData::ZoneName);
1614 0 : if (ObjIndex > 0) {
1615 0 : thisVentilationMechanical.ZoneDesignSpecOAObjName(MechVentZoneCount) =
1616 0 : state.dataSize->ZoneSizingInput(ObjIndex).DesignSpecOAObjName;
1617 0 : thisVentilationMechanical.ZoneDesignSpecOAObjIndex(MechVentZoneCount) =
1618 0 : state.dataSize->ZoneSizingInput(ObjIndex).ZoneDesignSpecOAIndex;
1619 : }
1620 : }
1621 : }
1622 : // Zone Air Distribution inputs
1623 335 : if (state.dataMixedAir->DesignSpecZoneADObjIndex(groupNum) > 0) {
1624 : // new DCV inputs
1625 335 : thisVentilationMechanical.ZoneDesignSpecADObjName(MechVentZoneCount) =
1626 335 : state.dataMixedAir->DesignSpecZoneADObjName(groupNum);
1627 335 : thisVentilationMechanical.ZoneDesignSpecADObjIndex(MechVentZoneCount) =
1628 335 : state.dataMixedAir->DesignSpecZoneADObjIndex(groupNum);
1629 : } else {
1630 0 : if (state.dataGlobal->DoZoneSizing) {
1631 0 : ObjIndex = UtilityRoutines::FindItemInList(state.dataMixedAir->VentMechZoneOrListName(groupNum),
1632 0 : state.dataSize->ZoneSizingInput,
1633 : &ZoneSizingInputData::ZoneName);
1634 0 : if (ObjIndex > 0) {
1635 0 : thisVentilationMechanical.ZoneDesignSpecADObjName(MechVentZoneCount) =
1636 0 : state.dataSize->ZoneSizingInput(ObjIndex).ZoneAirDistEffObjName;
1637 0 : thisVentilationMechanical.ZoneDesignSpecADObjIndex(MechVentZoneCount) =
1638 0 : state.dataSize->ZoneSizingInput(ObjIndex).ZoneAirDistributionIndex;
1639 : }
1640 : }
1641 : }
1642 : }
1643 : } else {
1644 : // Not a zone name, must be a zone list
1645 6 : ZoneListNum = UtilityRoutines::FindItemInList(state.dataMixedAir->VentMechZoneOrListName(groupNum), state.dataHeatBal->ZoneList);
1646 6 : if (ZoneListNum > 0) {
1647 18 : for (int ScanZoneListNum = 1; ScanZoneListNum <= state.dataHeatBal->ZoneList(ZoneListNum).NumOfZones; ++ScanZoneListNum) {
1648 12 : ObjIndex = 0;
1649 : // check to make sure zone name is unique (not listed more than once)...
1650 12 : ZoneNum = state.dataHeatBal->ZoneList(ZoneListNum).Zone(ScanZoneListNum);
1651 12 : if (any_eq(thisVentilationMechanical.VentMechZone, ZoneNum)) {
1652 : // Disregard duplicate zone names, show warning and do not store data for this zone
1653 0 : ShowWarningError(state,
1654 0 : "Zone name = " + state.dataHeatBal->Zone(ZoneNum).Name +
1655 0 : " in ZoneList = " + state.dataMixedAir->VentMechZoneOrListName(groupNum) + " for " +
1656 0 : CurrentModuleObject + " object = " + thisVentilationMechanical.Name);
1657 0 : ShowContinueError(state, "is a duplicate. The first ventilation values specified for this zone will be used ");
1658 0 : ShowContinueError(state, "and the rest will be ignored. The simulation will continue...");
1659 : } else {
1660 : // Store data for each zone name from zone list (duplicate zone names accounted for in
1661 : // HeatBalanceManager)
1662 12 : ++MechVentZoneCount;
1663 12 : thisVentilationMechanical.VentMechZone(MechVentZoneCount) = ZoneNum;
1664 12 : thisVentilationMechanical.VentMechZoneName(MechVentZoneCount) = state.dataHeatBal->Zone(ZoneNum).Name;
1665 : // Populating new temp array to hold design spec OA object for each zone
1666 12 : if (state.dataMixedAir->DesignSpecOAObjIndex(groupNum) > 0) {
1667 12 : thisVentilationMechanical.ZoneDesignSpecOAObjName(MechVentZoneCount) =
1668 12 : state.dataMixedAir->DesignSpecOAObjName(groupNum);
1669 12 : thisVentilationMechanical.ZoneDesignSpecOAObjIndex(MechVentZoneCount) =
1670 12 : state.dataMixedAir->DesignSpecOAObjIndex(groupNum);
1671 : } else {
1672 0 : if (state.dataGlobal->DoZoneSizing) {
1673 0 : ObjIndex = UtilityRoutines::FindItemInList(
1674 0 : state.dataHeatBal->Zone(ZoneNum).Name, state.dataSize->ZoneSizingInput, &ZoneSizingInputData::ZoneName);
1675 0 : if (ObjIndex > 0) {
1676 0 : thisVentilationMechanical.ZoneDesignSpecOAObjName(MechVentZoneCount) =
1677 0 : state.dataSize->ZoneSizingInput(ObjIndex).DesignSpecOAObjName;
1678 0 : thisVentilationMechanical.ZoneDesignSpecOAObjIndex(MechVentZoneCount) =
1679 0 : state.dataSize->ZoneSizingInput(ObjIndex).ZoneDesignSpecOAIndex;
1680 : }
1681 : }
1682 : }
1683 :
1684 12 : if (state.dataMixedAir->DesignSpecZoneADObjIndex(groupNum) > 0) {
1685 : // new DCV inputs
1686 12 : thisVentilationMechanical.ZoneDesignSpecADObjName(MechVentZoneCount) =
1687 12 : state.dataMixedAir->DesignSpecZoneADObjName(groupNum);
1688 12 : thisVentilationMechanical.ZoneDesignSpecADObjIndex(MechVentZoneCount) =
1689 12 : state.dataMixedAir->DesignSpecZoneADObjIndex(groupNum);
1690 : } else {
1691 0 : if (state.dataGlobal->DoZoneSizing) {
1692 0 : ObjIndex = UtilityRoutines::FindItemInList(
1693 0 : state.dataHeatBal->Zone(ZoneNum).Name, state.dataSize->ZoneSizingInput, &ZoneSizingInputData::ZoneName);
1694 0 : if (ObjIndex > 0) {
1695 0 : thisVentilationMechanical.ZoneDesignSpecADObjName(MechVentZoneCount) =
1696 0 : state.dataSize->ZoneSizingInput(ObjIndex).ZoneAirDistEffObjName;
1697 0 : thisVentilationMechanical.ZoneDesignSpecADObjIndex(MechVentZoneCount) =
1698 0 : state.dataSize->ZoneSizingInput(ObjIndex).ZoneAirDistributionIndex;
1699 : }
1700 : }
1701 : }
1702 : }
1703 : }
1704 : }
1705 : }
1706 : }
1707 :
1708 : // Overwrite previous number of zones with number that does not include duplicates
1709 52 : thisVentilationMechanical.NumofVentMechZones = MechVentZoneCount;
1710 :
1711 : // Loop over zones and fill OA and AD specs, if none were found, use defaults
1712 399 : for (int ventMechZoneNum = 1; ventMechZoneNum <= MechVentZoneCount; ++ventMechZoneNum) {
1713 347 : int zoneOAReqObjIndex = thisVentilationMechanical.ZoneDesignSpecOAObjIndex(ventMechZoneNum);
1714 347 : if (zoneOAReqObjIndex > 0) {
1715 347 : auto const &curOARequirements(state.dataSize->OARequirements(zoneOAReqObjIndex));
1716 347 : thisVentilationMechanical.ZoneOAAreaRate(ventMechZoneNum) = curOARequirements.OAFlowPerArea;
1717 347 : thisVentilationMechanical.ZoneOAPeopleRate(ventMechZoneNum) = curOARequirements.OAFlowPerPerson;
1718 347 : thisVentilationMechanical.ZoneOAFlowRate(ventMechZoneNum) = curOARequirements.OAFlowPerZone;
1719 347 : thisVentilationMechanical.ZoneOAACHRate(ventMechZoneNum) = curOARequirements.OAFlowACH;
1720 347 : thisVentilationMechanical.ZoneOAFlowMethod(ventMechZoneNum) = curOARequirements.OAFlowMethod;
1721 347 : thisVentilationMechanical.ZoneOASchPtr(ventMechZoneNum) = curOARequirements.OAFlowFracSchPtr;
1722 347 : thisVentilationMechanical.OAPropCtlMinRateSchPtr(ventMechZoneNum) = curOARequirements.OAPropCtlMinRateSchPtr;
1723 347 : if (thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate) {
1724 3 : if (thisVentilationMechanical.ZoneOAPeopleRate(ventMechZoneNum) == 0.0 &&
1725 0 : thisVentilationMechanical.ZoneOAAreaRate(ventMechZoneNum) == 0.0) {
1726 0 : ShowSevereError(state,
1727 0 : std::string{RoutineName} + CurrentModuleObject + "=\"" + thisVentilationMechanical.Name +
1728 : "\", invalid input with System Outdoor Air Method = ProportionalControlBasedOnDesignOARate.");
1729 0 : ShowContinueError(state,
1730 : " The values of Outdoor Air Flow per Person and Outdoor Air Flow per Zone Floor Area in the same "
1731 : "object can not be zero.");
1732 0 : ErrorsFound = true;
1733 : }
1734 : }
1735 : } else { // use defaults
1736 0 : thisVentilationMechanical.ZoneOAAreaRate(ventMechZoneNum) = 0.0;
1737 : // since this is case with no DesSpcOA object, cannot determine the method and default would be Flow/Person which should
1738 : // default to this flow rate
1739 0 : thisVentilationMechanical.ZoneOAPeopleRate(ventMechZoneNum) = 0.00944;
1740 0 : thisVentilationMechanical.ZoneOAFlowRate(ventMechZoneNum) = 0.0;
1741 0 : thisVentilationMechanical.ZoneOAACHRate = 0.0;
1742 0 : thisVentilationMechanical.ZoneOAFlowMethod(ventMechZoneNum) = OAFlowCalcMethod::PerPerson;
1743 0 : thisVentilationMechanical.ZoneOASchPtr(ventMechZoneNum) = DataGlobalConstants::ScheduleAlwaysOn;
1744 0 : ShowWarningError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + thisVentilationMechanical.Name);
1745 0 : ShowContinueError(state,
1746 0 : "Cannot locate a matching DesignSpecification:OutdoorAir object for Zone=\"" +
1747 0 : thisVentilationMechanical.VentMechZoneName(ventMechZoneNum) + "\".");
1748 0 : ShowContinueError(state, "Using default OA of 0.00944 m3/s-person and 0.0 m3/s-m2.");
1749 : }
1750 347 : int zoneAirDistObjIndex = thisVentilationMechanical.ZoneDesignSpecADObjIndex(ventMechZoneNum);
1751 347 : if (zoneAirDistObjIndex > 0) {
1752 347 : auto const &curZoneAirDistribution(state.dataSize->ZoneAirDistribution(zoneAirDistObjIndex));
1753 347 : thisVentilationMechanical.ZoneADEffCooling(ventMechZoneNum) = curZoneAirDistribution.ZoneADEffCooling;
1754 347 : thisVentilationMechanical.ZoneADEffHeating(ventMechZoneNum) = curZoneAirDistribution.ZoneADEffHeating;
1755 347 : thisVentilationMechanical.ZoneADEffSchPtr(ventMechZoneNum) = curZoneAirDistribution.ZoneADEffSchPtr;
1756 347 : thisVentilationMechanical.ZoneSecondaryRecirculation(ventMechZoneNum) = curZoneAirDistribution.ZoneSecondaryRecirculation;
1757 : } else { // use defaults
1758 0 : thisVentilationMechanical.ZoneADEffCooling(ventMechZoneNum) = 1.0;
1759 0 : thisVentilationMechanical.ZoneADEffHeating(ventMechZoneNum) = 1.0;
1760 0 : thisVentilationMechanical.ZoneSecondaryRecirculation(ventMechZoneNum) = 0.0;
1761 0 : ShowWarningError(state, std::string{RoutineName} + CurrentModuleObject + "=\"" + thisVentilationMechanical.Name);
1762 0 : ShowContinueError(state,
1763 0 : "Cannot locate a matching DesignSpecification:ZoneAirDistribution object for Zone=\"" +
1764 0 : thisVentilationMechanical.VentMechZoneName(ventMechZoneNum) + "\".");
1765 0 : ShowContinueError(state, "Using default zone air distribution effectiveness of 1.0 for heating and cooling.");
1766 : }
1767 : }
1768 52 : state.dataMixedAir->VentMechZoneOrListName.deallocate();
1769 52 : state.dataMixedAir->DesignSpecOAObjName.deallocate();
1770 52 : state.dataMixedAir->DesignSpecOAObjIndex.deallocate();
1771 52 : state.dataMixedAir->DesignSpecZoneADObjName.deallocate();
1772 52 : state.dataMixedAir->DesignSpecZoneADObjIndex.deallocate();
1773 : }
1774 :
1775 76 : for (VentMechNum = 1; VentMechNum <= state.dataMixedAir->NumVentMechControllers; ++VentMechNum) {
1776 52 : auto &thisVentilationMechanical(state.dataMixedAir->VentilationMechanical(VentMechNum));
1777 399 : for (jZone = 1; jZone <= thisVentilationMechanical.NumofVentMechZones; ++jZone) {
1778 347 : if (thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc) {
1779 3 : if (thisVentilationMechanical.ZoneOAACHRate(jZone) > 0.0 || thisVentilationMechanical.ZoneOAFlowRate(jZone) > 0.0) {
1780 0 : ShowWarningError(state,
1781 0 : CurrentModuleObject + "=\"" + thisVentilationMechanical.Name + "\", inappropriate outdoor air method");
1782 0 : ShowContinueError(state,
1783 0 : "Inappropriate method for Design Specification Outdoor Air Object Name=\"" +
1784 0 : thisVentilationMechanical.ZoneDesignSpecOAObjName(jZone) + "\".");
1785 0 : ShowContinueError(state, "For Zone=\"" + thisVentilationMechanical.VentMechZoneName(jZone) + "\".");
1786 0 : ShowContinueError(state,
1787 : "Since System Outdoor Air Method= ProportionalControlBasedOnOccupancySchedule\", AirChanges/Hour or "
1788 : "Flow/Zone outdoor air methods are not valid. Simulation continues.... ");
1789 : }
1790 : }
1791 347 : if (thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc) {
1792 0 : if (thisVentilationMechanical.ZoneOAACHRate(jZone) > 0.0 || thisVentilationMechanical.ZoneOAFlowRate(jZone) > 0.0) {
1793 0 : ShowWarningError(state,
1794 0 : CurrentModuleObject + "=\"" + thisVentilationMechanical.Name + "\", inappropriate outdoor air method");
1795 0 : ShowContinueError(state,
1796 0 : "Inappropriate method for Design Specification Outdoor Air Object Name=\"" +
1797 0 : thisVentilationMechanical.ZoneDesignSpecOAObjName(jZone) + "\".");
1798 0 : ShowContinueError(state, "For Zone=\"" + thisVentilationMechanical.VentMechZoneName(jZone) + "\".");
1799 0 : ShowContinueError(state,
1800 : "Since System Outdoor Air Method= ProportionalControlBasedOnDesignOccupancy\", AirChanges/Hour or "
1801 : "Flow/Zone outdoor air methods are not valid. Simulation continues.... ");
1802 : }
1803 : }
1804 :
1805 : // Error check to see if a single duct air terminal is assigned to a zone that has zone secondary recirculation
1806 347 : if (thisVentilationMechanical.ZoneSecondaryRecirculation(jZone) > 0.0) {
1807 5 : ZoneNum = thisVentilationMechanical.VentMechZone(jZone);
1808 5 : if (ZoneNum > 0) {
1809 5 : EquipListIndex = state.dataZoneEquip->ZoneEquipConfig(ZoneNum).EquipListIndex;
1810 5 : if (EquipListIndex > 0) {
1811 15 : for (EquipListNum = 1; EquipListNum <= state.dataZoneEquip->NumOfZoneEquipLists; ++EquipListNum) {
1812 15 : if (EquipListNum == EquipListIndex) {
1813 5 : for (EquipNum = 1; EquipNum <= state.dataZoneEquip->ZoneEquipList(EquipListNum).NumOfEquipTypes; ++EquipNum) {
1814 5 : if (UtilityRoutines::SameString(state.dataZoneEquip->ZoneEquipList(EquipListNum).EquipType(EquipNum),
1815 5 : "ZONEHVAC:AIRDISTRIBUTIONUNIT")) {
1816 15 : for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
1817 15 : if (UtilityRoutines::SameString(state.dataZoneEquip->ZoneEquipList(EquipListNum).EquipName(EquipNum),
1818 15 : state.dataDefineEquipment->AirDistUnit(ADUNum).Name)) {
1819 10 : if ((state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
1820 1 : DataDefineEquip::ZnAirLoopEquipType::SingleDuctVAVReheat) ||
1821 1 : (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
1822 1 : DataDefineEquip::ZnAirLoopEquipType::SingleDuctConstVolNoReheat) ||
1823 1 : (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
1824 1 : DataDefineEquip::ZnAirLoopEquipType::SingleDuctConstVolReheat) ||
1825 1 : (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
1826 1 : DataDefineEquip::ZnAirLoopEquipType::SingleDuctVAVNoReheat) ||
1827 1 : (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
1828 1 : DataDefineEquip::ZnAirLoopEquipType::SingleDuctVAVReheatVSFan) ||
1829 1 : (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
1830 1 : DataDefineEquip::ZnAirLoopEquipType::SingleDuctCBVAVReheat) ||
1831 1 : (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
1832 1 : DataDefineEquip::ZnAirLoopEquipType::SingleDuctCBVAVNoReheat) ||
1833 1 : (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
1834 1 : DataDefineEquip::ZnAirLoopEquipType::SingleDuctConstVolCooledBeam) ||
1835 1 : (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
1836 6 : DataDefineEquip::ZnAirLoopEquipType::SingleDuctConstVolFourPipeBeam) ||
1837 1 : (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
1838 : DataDefineEquip::ZnAirLoopEquipType::DualDuctVAVOutdoorAir)) {
1839 12 : ShowWarningError(state,
1840 8 : CurrentModuleObject + "=\"" + thisVentilationMechanical.Name +
1841 : "\", inappropriate use of Zone secondary recirculation");
1842 4 : ShowContinueError(state,
1843 : "A zone secondary recirculation fraction is specified for zone served by ");
1844 12 : ShowContinueError(state,
1845 8 : "...terminal unit \"" +
1846 12 : state.dataDefineEquipment->AirDistUnit(ADUNum).Name +
1847 : "\" , that indicates a single path system");
1848 12 : ShowContinueError(state,
1849 8 : "For Zone=\"" + thisVentilationMechanical.VentMechZoneName(jZone) + "\".");
1850 4 : ShowContinueError(state, "...The zone secondary recirculation for that zone was set to 0.0");
1851 4 : thisVentilationMechanical.ZoneSecondaryRecirculation(jZone) = 0.0;
1852 : }
1853 5 : goto EquipLoop_exit;
1854 : }
1855 : }
1856 : }
1857 : }
1858 : }
1859 : }
1860 0 : EquipLoop_exit:;
1861 : }
1862 : }
1863 : }
1864 347 : if (thisVentilationMechanical.ZoneDesignSpecOAObjName(jZone).empty()) {
1865 0 : ShowSevereError(state,
1866 0 : CurrentModuleObject + "=\"" + thisVentilationMechanical.Name +
1867 : "\", Design Specification Outdoor Air Object Name blank");
1868 0 : ShowContinueError(state, "For Zone=\"" + thisVentilationMechanical.VentMechZoneName(jZone) + "\".");
1869 0 : ShowContinueError(state, "This field either needs to be filled in in this object or Sizing:Zone object.");
1870 0 : ShowContinueError(state, "For this run, default values for these fields will be used.");
1871 : }
1872 347 : if (thisVentilationMechanical.ZoneOAPeopleRate(jZone) <= 0.0 && thisVentilationMechanical.DCVFlag) {
1873 2 : ShowWarningError(state, CurrentModuleObject + "=\"" + thisVentilationMechanical.Name + "\", Zone OA/person rate");
1874 2 : ShowContinueError(state, "For Zone=\"" + thisVentilationMechanical.VentMechZoneName(jZone) + "\".");
1875 6 : ShowContinueError(state,
1876 4 : "Zone outside air per person rate not set in Design Specification Outdoor Air Object=\"" +
1877 6 : thisVentilationMechanical.ZoneDesignSpecOAObjName(jZone) + "\".");
1878 : }
1879 :
1880 347 : if (thisVentilationMechanical.ZoneOAAreaRate(jZone) < 0.0) {
1881 0 : ShowSevereError(state, CurrentModuleObject + "=\"" + thisVentilationMechanical.Name + "\", invalid Outdoor Air flow per area");
1882 0 : ShowContinueError(state, "For Zone=\"" + thisVentilationMechanical.VentMechZoneName(jZone) + "\".");
1883 0 : ShowContinueError(state,
1884 0 : "invalid Outdoor Air flow per area specified in object=\"" +
1885 0 : thisVentilationMechanical.ZoneDesignSpecOAObjName(jZone) + "\". Value must be >= 0.0.");
1886 0 : ErrorsFound = true;
1887 : }
1888 347 : if (thisVentilationMechanical.ZoneOAPeopleRate(jZone) < 0.0) {
1889 0 : ShowSevereError(state, CurrentModuleObject + "=\"" + thisVentilationMechanical.Name + "\", invalid Outdoor Air flow per person");
1890 0 : ShowContinueError(state, "For Zone=\"" + thisVentilationMechanical.VentMechZoneName(jZone) + "\".");
1891 0 : ShowContinueError(state,
1892 0 : "invalid Outdoor Air flow per person specified in object \"" +
1893 0 : thisVentilationMechanical.ZoneDesignSpecOAObjName(jZone) + "\". Value must be >= 0.0.");
1894 0 : ErrorsFound = true;
1895 : }
1896 : }
1897 : }
1898 :
1899 : // Link OA controller object with mechanical ventilation object
1900 111 : for (OAControllerNum = 1; OAControllerNum <= state.dataMixedAir->NumOAControllers; ++OAControllerNum) {
1901 174 : state.dataMixedAir->OAController(OAControllerNum).VentMechObjectNum = UtilityRoutines::FindItemInList(
1902 174 : state.dataMixedAir->OAController(OAControllerNum).VentilationMechanicalName, state.dataMixedAir->VentilationMechanical);
1903 122 : if (state.dataMixedAir->OAController(OAControllerNum).VentMechObjectNum == 0 &&
1904 35 : !state.dataMixedAir->OAController(OAControllerNum).VentilationMechanicalName.empty()) {
1905 0 : ShowSevereError(state,
1906 0 : CurrentModuleObject + "=\"" + state.dataMixedAir->OAController(OAControllerNum).VentilationMechanicalName +
1907 : "\", non-match to Controller:OutdoorAir");
1908 0 : ShowContinueError(state,
1909 0 : "Invalid specified in Controller:OutdoorAir object = " + state.dataMixedAir->OAController(OAControllerNum).Name);
1910 0 : ShowContinueError(state,
1911 0 : CurrentModuleObject + " object name must match the " + CurrentModuleObject +
1912 : " object name specified in Controller:OutdoorAir.");
1913 0 : ErrorsFound = true;
1914 : }
1915 : }
1916 :
1917 : // write to .eio file
1918 : static constexpr std::string_view Format_700(
1919 : "!<Controller:MechanicalVentilation>,Name,Availability Schedule Name,Demand Controlled Ventilation "
1920 : "{Yes/No},System Outdoor Air Method,Zone Maximum Outdoor Air Fraction,Number of Zones,Zone Name,DSOA "
1921 : "Name,DSZAD Name");
1922 24 : print(state.files.eio, "{}\n", Format_700);
1923 76 : for (VentMechNum = 1; VentMechNum <= state.dataMixedAir->NumVentMechControllers; ++VentMechNum) {
1924 156 : print(state.files.eio,
1925 : " Controller:MechanicalVentilation,{},{},",
1926 52 : state.dataMixedAir->VentilationMechanical(VentMechNum).Name,
1927 104 : state.dataMixedAir->VentilationMechanical(VentMechNum).SchName);
1928 :
1929 52 : if (state.dataMixedAir->VentilationMechanical(VentMechNum).DCVFlag) {
1930 50 : print(state.files.eio, "Yes,");
1931 : } else {
1932 2 : print(state.files.eio, "No,");
1933 : }
1934 :
1935 52 : if (state.dataMixedAir->VentilationMechanical(VentMechNum).SystemOAMethod != DataSizing::SysOAMethod::Invalid) {
1936 52 : print(state.files.eio, printSysOAMethod[static_cast<int>(state.dataMixedAir->VentilationMechanical(VentMechNum).SystemOAMethod)]);
1937 : } else {
1938 0 : print(state.files.eio, "Invalid/Unknown,");
1939 : }
1940 :
1941 52 : print(state.files.eio, "{:.2R},", state.dataMixedAir->VentilationMechanical(VentMechNum).ZoneMaxOAFraction);
1942 52 : print(state.files.eio, "{},", state.dataMixedAir->VentilationMechanical(VentMechNum).NumofVentMechZones);
1943 :
1944 399 : for (jZone = 1; jZone <= state.dataMixedAir->VentilationMechanical(VentMechNum).NumofVentMechZones; ++jZone) {
1945 347 : if (jZone < state.dataMixedAir->VentilationMechanical(VentMechNum).NumofVentMechZones) {
1946 1180 : print(state.files.eio,
1947 : "{},{},{},",
1948 295 : state.dataHeatBal->Zone(state.dataMixedAir->VentilationMechanical(VentMechNum).VentMechZone(jZone)).Name,
1949 295 : state.dataMixedAir->VentilationMechanical(VentMechNum).ZoneDesignSpecOAObjName(jZone),
1950 590 : state.dataMixedAir->VentilationMechanical(VentMechNum).ZoneDesignSpecADObjName(jZone));
1951 : } else {
1952 208 : print(state.files.eio,
1953 : "{},{},{}\n",
1954 52 : state.dataHeatBal->Zone(state.dataMixedAir->VentilationMechanical(VentMechNum).VentMechZone(jZone)).Name,
1955 52 : state.dataMixedAir->VentilationMechanical(VentMechNum).ZoneDesignSpecOAObjName(jZone),
1956 104 : state.dataMixedAir->VentilationMechanical(VentMechNum).ZoneDesignSpecADObjName(jZone));
1957 : }
1958 : }
1959 : }
1960 :
1961 : } // Number of Mechanical Ventilation Objects > 0
1962 :
1963 393 : AlphArray.deallocate();
1964 393 : NumArray.deallocate();
1965 393 : lNumericBlanks.deallocate();
1966 393 : lAlphaBlanks.deallocate();
1967 393 : cAlphaFields.deallocate();
1968 393 : cNumericFields.deallocate();
1969 :
1970 393 : if (ErrorsFound) {
1971 0 : ShowFatalError(state, std::string{RoutineName} + "Errors found when getting " + CurrentModuleObject + " inputs.");
1972 : }
1973 393 : }
1974 :
1975 396 : void AllocateOAControllers(EnergyPlusData &state)
1976 : {
1977 :
1978 : // PURPOSE OF THIS SUBROUTINE:
1979 : // Allocate the OA controller arrays which are shared by Controller:OutdoorAir and ZoneHVAC:EnergyRecoveryVentilator:Controller
1980 :
1981 396 : if (state.dataMixedAir->AllocateOAControllersFlag) {
1982 394 : state.dataMixedAir->NumOAControllers =
1983 394 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObjects(static_cast<int>(CMO::OAController)));
1984 394 : state.dataMixedAir->NumERVControllers =
1985 394 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObjects(static_cast<int>(CMO::ERVController)));
1986 394 : state.dataMixedAir->NumOAControllers += state.dataMixedAir->NumERVControllers;
1987 394 : state.dataMixedAir->OAController.allocate(state.dataMixedAir->NumOAControllers);
1988 394 : state.dataMixedAir->OAControllerUniqueNames.reserve(static_cast<unsigned>(state.dataMixedAir->NumOAControllers));
1989 394 : state.dataMixedAir->AllocateOAControllersFlag = false;
1990 : }
1991 396 : }
1992 :
1993 435 : void GetOAMixerInputs(EnergyPlusData &state)
1994 : {
1995 :
1996 : // SUBROUTINE INFORMATION:
1997 : // AUTHOR Fred Buhl
1998 : // DATE WRITTEN Oct 1998
1999 : // MODIFIED na
2000 : // RE-ENGINEERED na
2001 :
2002 : // PURPOSE OF THIS SUBROUTINE
2003 : // Input the OAMixer data and store it in the OAMixer array.
2004 :
2005 : // METHODOLOGY EMPLOYED:
2006 : // Use the Get routines from the InputProcessor module.
2007 :
2008 : // Using/Aliasing
2009 : using BranchNodeConnections::TestCompSet;
2010 : using NodeInputManager::GetOnlySingleNode;
2011 :
2012 : // Locals
2013 : // SUBROUTINE PARAMETER DEFINITIONS:
2014 : static constexpr std::string_view RoutineName("GetOAMixerInputs: "); // include trailing blank space
2015 :
2016 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2017 :
2018 : int NumNums; // Number of REAL(r64) numbers returned by GetObjectItem
2019 : int NumAlphas; // Number of alphanumerics returned by GetObjectItem
2020 : int NumArg; // Number of arguments from GetObjectDefMaxArgs call
2021 : int OutAirNum;
2022 : int IOStat;
2023 870 : Array1D<Real64> NumArray; // array that holds numeric input values
2024 870 : Array1D_string AlphArray; // array that holds alpha input values
2025 870 : std::string CurrentModuleObject; // Object type for getting and messages
2026 870 : Array1D_string cAlphaFields; // Alpha field names
2027 870 : Array1D_string cNumericFields; // Numeric field names
2028 870 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
2029 870 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
2030 435 : bool ErrorsFound(false);
2031 :
2032 435 : if (!state.dataMixedAir->GetOAMixerInputFlag) return;
2033 :
2034 870 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
2035 435 : state, CurrentModuleObjects(static_cast<int>(CMO::OAMixer)), NumArg, NumAlphas, NumNums);
2036 :
2037 435 : AlphArray.allocate(NumAlphas);
2038 435 : NumArray.dimension(NumNums, 0.0);
2039 435 : lNumericBlanks.dimension(NumNums, true);
2040 435 : lAlphaBlanks.dimension(NumAlphas, true);
2041 435 : cAlphaFields.allocate(NumAlphas);
2042 435 : cNumericFields.allocate(NumNums);
2043 :
2044 435 : CurrentModuleObject = CurrentModuleObjects(static_cast<int>(CMO::OAMixer));
2045 :
2046 435 : state.dataMixedAir->NumOAMixers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
2047 :
2048 435 : if (state.dataMixedAir->NumOAMixers > 0) {
2049 :
2050 435 : state.dataMixedAir->OAMixer.allocate(state.dataMixedAir->NumOAMixers);
2051 :
2052 1774 : for (OutAirNum = 1; OutAirNum <= state.dataMixedAir->NumOAMixers; ++OutAirNum) {
2053 1339 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2054 : CurrentModuleObject,
2055 : OutAirNum,
2056 : AlphArray,
2057 : NumAlphas,
2058 : NumArray,
2059 : NumNums,
2060 : IOStat,
2061 : lNumericBlanks,
2062 : lAlphaBlanks,
2063 : cAlphaFields,
2064 : cNumericFields);
2065 1339 : UtilityRoutines::IsNameEmpty(state, AlphArray(1), CurrentModuleObject, ErrorsFound);
2066 :
2067 1339 : state.dataMixedAir->OAMixer(OutAirNum).Name = AlphArray(1);
2068 1339 : state.dataMixedAir->OAMixer(OutAirNum).MixNode = GetOnlySingleNode(state,
2069 1339 : AlphArray(2),
2070 : ErrorsFound,
2071 : DataLoopNode::ConnectionObjectType::OutdoorAirMixer,
2072 1339 : AlphArray(1),
2073 : DataLoopNode::NodeFluidType::Air,
2074 : DataLoopNode::ConnectionType::Outlet,
2075 : NodeInputManager::CompFluidStream::Primary,
2076 1339 : ObjectIsNotParent);
2077 : // Set connection type to 'Inlet', because this is not necessarily directly from
2078 : // outside air. Outside Air Inlet Node List will set the connection to outside air
2079 1339 : state.dataMixedAir->OAMixer(OutAirNum).InletNode = GetOnlySingleNode(state,
2080 1339 : AlphArray(3),
2081 : ErrorsFound,
2082 : DataLoopNode::ConnectionObjectType::OutdoorAirMixer,
2083 1339 : AlphArray(1),
2084 : DataLoopNode::NodeFluidType::Air,
2085 : DataLoopNode::ConnectionType::Inlet,
2086 : NodeInputManager::CompFluidStream::Primary,
2087 1339 : ObjectIsNotParent);
2088 1339 : state.dataMixedAir->OAMixer(OutAirNum).RelNode = GetOnlySingleNode(state,
2089 1339 : AlphArray(4),
2090 : ErrorsFound,
2091 : DataLoopNode::ConnectionObjectType::OutdoorAirMixer,
2092 1339 : AlphArray(1),
2093 : DataLoopNode::NodeFluidType::Air,
2094 : DataLoopNode::ConnectionType::ReliefAir,
2095 : NodeInputManager::CompFluidStream::Primary,
2096 1339 : ObjectIsNotParent);
2097 1339 : state.dataMixedAir->OAMixer(OutAirNum).RetNode = GetOnlySingleNode(state,
2098 1339 : AlphArray(5),
2099 : ErrorsFound,
2100 : DataLoopNode::ConnectionObjectType::OutdoorAirMixer,
2101 1339 : AlphArray(1),
2102 : DataLoopNode::NodeFluidType::Air,
2103 : DataLoopNode::ConnectionType::Inlet,
2104 : NodeInputManager::CompFluidStream::Primary,
2105 1339 : ObjectIsNotParent);
2106 : // Check for dupes in the four nodes.
2107 1339 : if (state.dataMixedAir->OAMixer(OutAirNum).MixNode == state.dataMixedAir->OAMixer(OutAirNum).InletNode) {
2108 0 : ShowSevereError(state,
2109 0 : CurrentModuleObject + " = " + state.dataMixedAir->OAMixer(OutAirNum).Name + ' ' + cAlphaFields(3) + " = " +
2110 0 : state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OutAirNum).InletNode) + " duplicates the " +
2111 0 : cAlphaFields(2) + '.');
2112 0 : ErrorsFound = true;
2113 1339 : } else if (state.dataMixedAir->OAMixer(OutAirNum).MixNode == state.dataMixedAir->OAMixer(OutAirNum).RelNode) {
2114 0 : ShowSevereError(state,
2115 0 : CurrentModuleObject + " = " + state.dataMixedAir->OAMixer(OutAirNum).Name + ' ' + cAlphaFields(4) + " = " +
2116 0 : state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OutAirNum).RelNode) + " duplicates the " +
2117 0 : cAlphaFields(2) + '.');
2118 0 : ErrorsFound = true;
2119 1339 : } else if (state.dataMixedAir->OAMixer(OutAirNum).MixNode == state.dataMixedAir->OAMixer(OutAirNum).RetNode) {
2120 0 : ShowSevereError(state,
2121 0 : CurrentModuleObject + " = " + state.dataMixedAir->OAMixer(OutAirNum).Name + ' ' + cAlphaFields(5) + " = " +
2122 0 : state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OutAirNum).RetNode) + " duplicates the " +
2123 0 : cAlphaFields(2) + '.');
2124 0 : ErrorsFound = true;
2125 : }
2126 :
2127 1339 : if (state.dataMixedAir->OAMixer(OutAirNum).InletNode == state.dataMixedAir->OAMixer(OutAirNum).RelNode) {
2128 0 : ShowSevereError(state,
2129 0 : CurrentModuleObject + " = " + state.dataMixedAir->OAMixer(OutAirNum).Name + ' ' + cAlphaFields(4) + " = " +
2130 0 : state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OutAirNum).RelNode) + " duplicates the " +
2131 0 : cAlphaFields(3) + '.');
2132 0 : ErrorsFound = true;
2133 1339 : } else if (state.dataMixedAir->OAMixer(OutAirNum).InletNode == state.dataMixedAir->OAMixer(OutAirNum).RetNode) {
2134 0 : ShowSevereError(state,
2135 0 : CurrentModuleObject + " = " + state.dataMixedAir->OAMixer(OutAirNum).Name + ' ' + cAlphaFields(5) + " = " +
2136 0 : state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OutAirNum).RetNode) + " duplicates the " +
2137 0 : cAlphaFields(3) + '.');
2138 0 : ErrorsFound = true;
2139 : }
2140 :
2141 1339 : if (state.dataMixedAir->OAMixer(OutAirNum).RelNode == state.dataMixedAir->OAMixer(OutAirNum).RetNode) {
2142 0 : ShowSevereError(state,
2143 0 : CurrentModuleObject + " = " + state.dataMixedAir->OAMixer(OutAirNum).Name + ' ' + cAlphaFields(5) + " = " +
2144 0 : state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OutAirNum).RetNode) + " duplicates the " +
2145 0 : cAlphaFields(4) + '.');
2146 0 : ErrorsFound = true;
2147 : }
2148 :
2149 1339 : TestCompSet(state, CurrentModuleObject, state.dataMixedAir->OAMixer(OutAirNum).Name, AlphArray(3), AlphArray(2), "Air Nodes");
2150 : }
2151 : }
2152 :
2153 435 : if (ErrorsFound) {
2154 0 : ShowFatalError(state, std::string{RoutineName} + "Errors found in getting " + CurrentModuleObject);
2155 : }
2156 :
2157 435 : state.dataMixedAir->GetOAMixerInputFlag = false;
2158 : }
2159 :
2160 1021 : void ProcessOAControllerInputs(EnergyPlusData &state,
2161 : std::string const &CurrentModuleObject,
2162 : int const OutAirNum,
2163 : Array1D_string const &AlphArray,
2164 : int &NumAlphas,
2165 : Array1D<Real64> const &NumArray,
2166 : int &NumNums,
2167 : Array1D_bool const &lNumericBlanks, // Unused
2168 : Array1D_bool const &lAlphaBlanks,
2169 : Array1D_string const &cAlphaFields,
2170 : Array1D_string const &cNumericFields, // Unused
2171 : bool &ErrorsFound // If errors found in input
2172 : )
2173 : {
2174 :
2175 : // SUBROUTINE INFORMATION:
2176 : // AUTHOR Fred Buhl
2177 : // DATE WRITTEN Oct 1998
2178 : // MODIFIED Shirey/Raustad FSEC, June 2003, Jan 2004
2179 : // Mangesh Basarkar, 06/2011: Getting zone OA specifications from Design Specification Object
2180 : // Tianzhen Hong, 3/2012: getting zone air distribution effectiveness and secondary recirculation
2181 : // from DesignSpecification:ZoneAirDistribution objects
2182 : // RE-ENGINEERED MJW: Split out processing controller:outdoorair input to facilitate unit testing, Feb 2015
2183 :
2184 : // PURPOSE OF THIS SUBROUTINE
2185 : // Input the OAController data and store it in the OAController array.
2186 :
2187 : // METHODOLOGY EMPLOYED:
2188 :
2189 : // Using/Aliasing
2190 : using namespace DataDefineEquip;
2191 : using Curve::GetCurveIndex;
2192 : using NodeInputManager::GetOnlySingleNode;
2193 : using namespace OutputReportPredefined;
2194 :
2195 : using OutAirNodeManager::CheckOutAirNodeNumber;
2196 :
2197 : using SetPointManager::GetMixedAirNumWithCoilFreezingCheck;
2198 :
2199 : // SUBROUTINE PARAMETER DEFINITIONS:
2200 : static constexpr std::string_view RoutineName("GetOAControllerInputs: "); // include trailing blank space
2201 :
2202 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2203 :
2204 : int OAControllerNum; // Index to Controller:OutdoorAir or CONTROLLER:STAND ALONE ERV objects
2205 : int ControlledZoneNum; // Index to controlled zones
2206 : bool AirNodeFound; // Used to determine if control zone is valid
2207 : bool AirLoopFound; // Used to determine if control zone is served by furnace air loop
2208 : int BranchNum; // Used to determine if control zone is served by furnace air loop
2209 : int CompNum; // Used to determine if control zone is served by furnace air loop
2210 : int HStatZoneNum; // Used to determine if control zone has a humidistat object
2211 : int OASysNum; // Used to find OA System index for OA Controller
2212 : int OASysIndex; // Index to OA System
2213 : bool OASysFound; // OA Controller found OA System index
2214 : Real64 OAFlowRatio; // Ratio of minimum OA flow rate to maximum OA flow rate
2215 :
2216 1021 : state.dataMixedAir->OAController(OutAirNum).Name = AlphArray(1);
2217 1021 : state.dataMixedAir->OAController(OutAirNum).ControllerType = CurrentModuleObject;
2218 1021 : state.dataMixedAir->OAController(OutAirNum).ControllerType_Num = MixedAirControllerType::ControllerOutsideAir;
2219 1021 : state.dataMixedAir->OAController(OutAirNum).MaxOA = NumArray(2);
2220 1021 : state.dataMixedAir->OAController(OutAirNum).MinOA = NumArray(1);
2221 1021 : state.dataMixedAir->OAController(OutAirNum).MixNode = GetOnlySingleNode(state,
2222 1021 : AlphArray(4),
2223 : ErrorsFound,
2224 : DataLoopNode::ConnectionObjectType::ControllerOutdoorAir,
2225 1021 : AlphArray(1),
2226 : DataLoopNode::NodeFluidType::Air,
2227 : DataLoopNode::ConnectionType::Sensor,
2228 : NodeInputManager::CompFluidStream::Primary,
2229 1021 : ObjectIsNotParent);
2230 1021 : state.dataMixedAir->OAController(OutAirNum).OANode = GetOnlySingleNode(state,
2231 1021 : AlphArray(5),
2232 : ErrorsFound,
2233 : DataLoopNode::ConnectionObjectType::ControllerOutdoorAir,
2234 1021 : AlphArray(1),
2235 : DataLoopNode::NodeFluidType::Air,
2236 : DataLoopNode::ConnectionType::Actuator,
2237 : NodeInputManager::CompFluidStream::Primary,
2238 1021 : ObjectIsNotParent);
2239 1021 : if (!CheckOutAirNodeNumber(state, state.dataMixedAir->OAController(OutAirNum).OANode)) {
2240 0 : ShowWarningError(
2241 0 : state, CurrentModuleObject + "=\"" + AlphArray(1) + "\": " + cAlphaFields(5) + "=\"" + AlphArray(5) + "\" is not an OutdoorAir:Node.");
2242 0 : ShowContinueError(state, "Confirm that this is the intended source for the outdoor air stream.");
2243 : }
2244 1021 : if (UtilityRoutines::SameString(AlphArray(6), "NoEconomizer")) {
2245 507 : state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::NoEconomizer;
2246 514 : } else if (UtilityRoutines::SameString(AlphArray(6), "FixedDryBulb")) {
2247 123 : state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::FixedDryBulb;
2248 391 : } else if (UtilityRoutines::SameString(AlphArray(6), "FixedEnthalpy")) {
2249 0 : state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::FixedEnthalpy;
2250 391 : } else if (UtilityRoutines::SameString(AlphArray(6), "FixedDewPointAndDryBulb")) {
2251 0 : state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::FixedDewPointAndDryBulb;
2252 391 : } else if (UtilityRoutines::SameString(AlphArray(6), "DifferentialDryBulb")) {
2253 366 : state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::DifferentialDryBulb;
2254 25 : } else if (UtilityRoutines::SameString(AlphArray(6), "DifferentialEnthalpy")) {
2255 18 : state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::DifferentialEnthalpy;
2256 7 : } else if (UtilityRoutines::SameString(AlphArray(6), "DifferentialDryBulbAndEnthalpy")) {
2257 0 : state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::DifferentialDryBulbAndEnthalpy;
2258 7 : } else if (UtilityRoutines::SameString(AlphArray(6), "ElectronicEnthalpy")) {
2259 7 : state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::ElectronicEnthalpy;
2260 : } else {
2261 0 : ShowSevereError(state, CurrentModuleObject + "=\"" + AlphArray(1) + "\" invalid " + cAlphaFields(6) + "=\"" + AlphArray(6) + "\" value.");
2262 0 : ErrorsFound = true;
2263 : }
2264 : // Bypass choice - Added by Amit for new feature implementation
2265 1021 : if (UtilityRoutines::SameString(AlphArray(7), "ModulateFlow")) {
2266 1005 : state.dataMixedAir->OAController(OutAirNum).EconBypass = false;
2267 16 : } else if (UtilityRoutines::SameString(AlphArray(7), "MinimumFlowWithBypass")) {
2268 16 : state.dataMixedAir->OAController(OutAirNum).EconBypass = true;
2269 : } else {
2270 0 : ShowSevereError(state, CurrentModuleObject + "=\"" + AlphArray(1) + "\" invalid " + cAlphaFields(7) + "=\"" + AlphArray(7) + "\" value.");
2271 0 : ErrorsFound = true;
2272 : }
2273 :
2274 1021 : if (UtilityRoutines::SameString(AlphArray(9), "NoLockout")) {
2275 784 : state.dataMixedAir->OAController(OutAirNum).Lockout = LockoutType::NoLockoutPossible;
2276 237 : } else if (UtilityRoutines::SameString(AlphArray(9), "LockoutWithHeating")) {
2277 196 : state.dataMixedAir->OAController(OutAirNum).Lockout = LockoutType::LockoutWithHeatingPossible;
2278 41 : } else if (UtilityRoutines::SameString(AlphArray(9), "LockoutWithCompressor")) {
2279 41 : state.dataMixedAir->OAController(OutAirNum).Lockout = LockoutType::LockoutWithCompressorPossible;
2280 : } else {
2281 0 : ShowSevereError(state, CurrentModuleObject + "=\"" + AlphArray(1) + "\" invalid " + cAlphaFields(9) + "=\"" + AlphArray(9) + "\" value.");
2282 0 : ErrorsFound = true;
2283 : }
2284 1021 : if (UtilityRoutines::SameString(AlphArray(10), "FixedMinimum")) {
2285 981 : state.dataMixedAir->OAController(OutAirNum).FixedMin = true;
2286 : } else {
2287 40 : state.dataMixedAir->OAController(OutAirNum).FixedMin = false;
2288 : }
2289 1021 : if (lNumericBlanks(3)) {
2290 291 : state.dataMixedAir->OAController(OutAirNum).TempLim = BlankNumeric;
2291 : } else {
2292 730 : state.dataMixedAir->OAController(OutAirNum).TempLim = NumArray(3);
2293 : }
2294 :
2295 1021 : if (lNumericBlanks(4)) {
2296 634 : state.dataMixedAir->OAController(OutAirNum).EnthLim = BlankNumeric;
2297 : } else {
2298 387 : state.dataMixedAir->OAController(OutAirNum).EnthLim = NumArray(4);
2299 : }
2300 1021 : if (lNumericBlanks(5)) {
2301 1006 : state.dataMixedAir->OAController(OutAirNum).DPTempLim = BlankNumeric;
2302 : } else {
2303 15 : state.dataMixedAir->OAController(OutAirNum).DPTempLim = NumArray(5);
2304 : }
2305 :
2306 1021 : if (lNumericBlanks(6)) {
2307 357 : state.dataMixedAir->OAController(OutAirNum).TempLowLim = BlankNumeric;
2308 : } else {
2309 664 : state.dataMixedAir->OAController(OutAirNum).TempLowLim = NumArray(6);
2310 : }
2311 :
2312 1021 : if (!lAlphaBlanks(8)) {
2313 7 : state.dataMixedAir->OAController(OutAirNum).EnthalpyCurvePtr = GetCurveIndex(state, AlphArray(8)); // convert curve name to number
2314 7 : if (state.dataMixedAir->OAController(OutAirNum).EnthalpyCurvePtr == 0) {
2315 0 : ShowSevereError(state,
2316 0 : CurrentModuleObject + "=\"" + AlphArray(1) + "\" invalid " + cAlphaFields(8) + "=\"" + AlphArray(8) + "\" not found.");
2317 0 : ErrorsFound = true;
2318 : } else {
2319 : // Verify Curve Object, only legal types are Quadratic and Cubic
2320 21 : ErrorsFound |= Curve::CheckCurveDims(state,
2321 7 : state.dataMixedAir->OAController(OutAirNum).EnthalpyCurvePtr, // Curve index
2322 : {1}, // Valid dimensions
2323 : RoutineName, // Routine name
2324 : CurrentModuleObject, // Object Type
2325 7 : state.dataMixedAir->OAController(OutAirNum).Name, // Object Name
2326 7 : cAlphaFields(8)); // Field Name
2327 : }
2328 : }
2329 :
2330 1021 : state.dataMixedAir->OAController(OutAirNum).RelNode = GetOnlySingleNode(state,
2331 1021 : AlphArray(2),
2332 : ErrorsFound,
2333 : DataLoopNode::ConnectionObjectType::ControllerOutdoorAir,
2334 1021 : AlphArray(1),
2335 : DataLoopNode::NodeFluidType::Air,
2336 : DataLoopNode::ConnectionType::Actuator,
2337 : NodeInputManager::CompFluidStream::Primary,
2338 1021 : ObjectIsNotParent);
2339 1021 : state.dataMixedAir->OAController(OutAirNum).RetNode = GetOnlySingleNode(state,
2340 1021 : AlphArray(3),
2341 : ErrorsFound,
2342 : DataLoopNode::ConnectionObjectType::ControllerOutdoorAir,
2343 1021 : AlphArray(1),
2344 : DataLoopNode::NodeFluidType::Air,
2345 : DataLoopNode::ConnectionType::Sensor,
2346 : NodeInputManager::CompFluidStream::Primary,
2347 1021 : ObjectIsNotParent);
2348 1021 : state.dataMixedAir->OAController(OutAirNum).MinOASch = AlphArray(11);
2349 1021 : state.dataMixedAir->OAController(OutAirNum).MinOASchPtr = GetScheduleIndex(state, AlphArray(11));
2350 1021 : if (state.dataMixedAir->OAController(OutAirNum).MinOASchPtr == 0 && (!lAlphaBlanks(11))) {
2351 0 : ShowSevereError(state,
2352 0 : CurrentModuleObject + "=\"" + AlphArray(1) + "\" invalid " + cAlphaFields(11) + "=\"" + AlphArray(11) + "\" not found.");
2353 0 : ErrorsFound = true;
2354 : }
2355 :
2356 : // Changed by Amit for new feature implementation
2357 1021 : state.dataMixedAir->OAController(OutAirNum).MinOAflowSch = AlphArray(12);
2358 1021 : state.dataMixedAir->OAController(OutAirNum).MinOAflowSchPtr = GetScheduleIndex(state, AlphArray(12));
2359 1021 : if (state.dataMixedAir->OAController(OutAirNum).MinOAflowSchPtr == 0 && (!lAlphaBlanks(12))) {
2360 0 : ShowSevereError(state,
2361 0 : CurrentModuleObject + "=\"" + AlphArray(1) + "\" invalid " + cAlphaFields(12) + "=\"" + AlphArray(12) + "\" not found.");
2362 0 : ErrorsFound = true;
2363 : }
2364 :
2365 1021 : state.dataMixedAir->OAController(OutAirNum).MaxOAflowSch = AlphArray(13);
2366 1021 : state.dataMixedAir->OAController(OutAirNum).MaxOAflowSchPtr = GetScheduleIndex(state, AlphArray(13));
2367 1021 : if (state.dataMixedAir->OAController(OutAirNum).MaxOAflowSchPtr == 0 && (!lAlphaBlanks(13))) {
2368 0 : ShowSevereError(state,
2369 0 : CurrentModuleObject + "=\"" + AlphArray(1) + "\" invalid " + cAlphaFields(13) + "=\"" + AlphArray(13) + "\" not found.");
2370 0 : ErrorsFound = true;
2371 : }
2372 1021 : state.dataMixedAir->OAController(OutAirNum).VentilationMechanicalName = AlphArray(14);
2373 :
2374 : // Check for a time of day economizer control schedule
2375 1021 : state.dataMixedAir->OAController(OutAirNum).EconomizerOASchedPtr = GetScheduleIndex(state, AlphArray(15));
2376 :
2377 : // High humidity control option can be used with any economizer flag
2378 1021 : if (UtilityRoutines::SameString(AlphArray(16), "Yes")) {
2379 :
2380 6 : state.dataMixedAir->OAController(OutAirNum).HumidistatZoneNum = UtilityRoutines::FindItemInList(AlphArray(17), state.dataHeatBal->Zone);
2381 :
2382 : // Get the node number for the zone with the humidistat
2383 6 : if (state.dataMixedAir->OAController(OutAirNum).HumidistatZoneNum > 0) {
2384 6 : AirNodeFound = false;
2385 6 : AirLoopFound = false;
2386 6 : OASysFound = false;
2387 25 : for (ControlledZoneNum = 1; ControlledZoneNum <= state.dataGlobal->NumOfZones; ++ControlledZoneNum) {
2388 19 : if (ControlledZoneNum != state.dataMixedAir->OAController(OutAirNum).HumidistatZoneNum) continue;
2389 : // Find the controlled zone number for the specified humidistat location
2390 6 : state.dataMixedAir->OAController(OutAirNum).NodeNumofHumidistatZone =
2391 6 : state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
2392 : // Determine which OA System uses this OA Controller
2393 6 : OASysIndex = 0;
2394 6 : for (OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; ++OASysNum) {
2395 6 : for (OAControllerNum = 1; OAControllerNum <= state.dataAirLoop->OutsideAirSys(OASysNum).NumControllers; ++OAControllerNum) {
2396 12 : if (!UtilityRoutines::SameString(state.dataAirLoop->OutsideAirSys(OASysNum).ControllerType(OAControllerNum),
2397 12 : CurrentModuleObject) ||
2398 6 : !UtilityRoutines::SameString(state.dataAirLoop->OutsideAirSys(OASysNum).ControllerName(OAControllerNum),
2399 6 : state.dataMixedAir->OAController(OutAirNum).Name))
2400 0 : continue;
2401 6 : OASysIndex = OASysNum;
2402 6 : OASysFound = true;
2403 6 : break;
2404 : }
2405 6 : if (OASysFound) break;
2406 : }
2407 : // Determine if controller is on air loop served by the humidistat location specified
2408 12 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
2409 6 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
2410 12 : if (AirLoopNumber > 0 && OASysIndex > 0) {
2411 6 : for (BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
2412 6 : for (CompNum = 1; CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
2413 : ++CompNum) {
2414 18 : if (!UtilityRoutines::SameString(
2415 6 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
2416 18 : state.dataAirLoop->OutsideAirSys(OASysIndex).Name) ||
2417 12 : !UtilityRoutines::SameString(
2418 6 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
2419 6 : "AirLoopHVAC:OutdoorAirSystem"))
2420 0 : continue;
2421 6 : AirLoopFound = true;
2422 6 : break;
2423 : }
2424 6 : if (AirLoopFound) break;
2425 : }
2426 6 : for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) {
2427 12 : if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum !=
2428 6 : state.dataMixedAir->OAController(OutAirNum).HumidistatZoneNum)
2429 0 : continue;
2430 6 : AirNodeFound = true;
2431 6 : break;
2432 : }
2433 : } else {
2434 0 : if (OASysIndex == 0) {
2435 0 : ShowSevereError(state,
2436 0 : "Did not find an AirLoopHVAC:OutdoorAirSystem for " +
2437 0 : state.dataMixedAir->OAController(OutAirNum).ControllerType + " = \"" +
2438 0 : state.dataMixedAir->OAController(OutAirNum).Name + "\"");
2439 0 : ErrorsFound = true;
2440 : }
2441 : }
2442 : }
2443 : }
2444 6 : if (!AirNodeFound) {
2445 0 : ShowSevereError(state,
2446 0 : "Did not find Air Node (Zone with Humidistat), " + state.dataMixedAir->OAController(OutAirNum).ControllerType +
2447 0 : " = \"" + state.dataMixedAir->OAController(OutAirNum).Name + "\"");
2448 0 : ShowContinueError(state, "Specified " + cAlphaFields(17) + " = " + AlphArray(17));
2449 0 : ShowContinueError(state,
2450 : "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Humidistat object must be specified for this zone.");
2451 0 : ErrorsFound = true;
2452 : }
2453 6 : if (!AirLoopFound) {
2454 0 : ShowSevereError(state,
2455 0 : "Did not find correct Primary Air Loop for " + state.dataMixedAir->OAController(OutAirNum).ControllerType + " = \"" +
2456 0 : state.dataMixedAir->OAController(OutAirNum).Name + "\"");
2457 0 : ShowContinueError(state, cAlphaFields(17) + " = " + AlphArray(17) + " is not served by this Primary Air Loop equipment.");
2458 0 : ErrorsFound = true;
2459 : }
2460 : } else {
2461 0 : ShowSevereError(state,
2462 0 : "Did not find Air Node (Zone with Humidistat), " + state.dataMixedAir->OAController(OutAirNum).ControllerType + " = \"" +
2463 0 : state.dataMixedAir->OAController(OutAirNum).Name + "\"");
2464 0 : ShowContinueError(state, "Specified " + cAlphaFields(17) + " = " + AlphArray(17));
2465 0 : ShowContinueError(state,
2466 : "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Humidistat object must be specified for this zone.");
2467 0 : ErrorsFound = true;
2468 : }
2469 :
2470 6 : state.dataMixedAir->OAController(OutAirNum).HighRHOAFlowRatio = NumArray(7);
2471 6 : if (state.dataMixedAir->OAController(OutAirNum).HighRHOAFlowRatio <= 0.0 && NumNums > 6) {
2472 0 : ShowWarningError(state, CurrentModuleObject + " \"" + state.dataMixedAir->OAController(OutAirNum).Name + "\"");
2473 0 : ShowContinueError(state, ' ' + cNumericFields(7) + " must be greater than 0.");
2474 0 : ShowContinueError(state, ' ' + cNumericFields(7) + " is reset to 1 and the simulation continues.");
2475 0 : state.dataMixedAir->OAController(OutAirNum).HighRHOAFlowRatio = 1.0;
2476 : }
2477 :
2478 6 : if (UtilityRoutines::SameString(AlphArray(16), "Yes") && state.dataMixedAir->OAController(OutAirNum).FixedMin) {
2479 6 : if (state.dataMixedAir->OAController(OutAirNum).MaxOA > 0.0 && state.dataMixedAir->OAController(OutAirNum).MinOA != AutoSize) {
2480 5 : OAFlowRatio = state.dataMixedAir->OAController(OutAirNum).MinOA / state.dataMixedAir->OAController(OutAirNum).MaxOA;
2481 5 : if (state.dataMixedAir->OAController(OutAirNum).HighRHOAFlowRatio < OAFlowRatio) {
2482 0 : ShowWarningError(state, CurrentModuleObject + " \"" + state.dataMixedAir->OAController(OutAirNum).Name + "\"");
2483 0 : ShowContinueError(state, "... A fixed minimum outside air flow rate and high humidity control have been specified.");
2484 0 : ShowContinueError(state,
2485 0 : "... The " + cNumericFields(7) +
2486 : " is less than the ratio of the outside air controllers minimum to maximum outside air flow rate.");
2487 0 : ShowContinueError(
2488 0 : state, format("... Controller {} = {:.4T} m3/s.", cNumericFields(1), state.dataMixedAir->OAController(OutAirNum).MinOA));
2489 0 : ShowContinueError(
2490 0 : state, format("... Controller {} = {:.4T} m3/s.", cNumericFields(2), state.dataMixedAir->OAController(OutAirNum).MaxOA));
2491 0 : ShowContinueError(state, format("... Controller minimum to maximum flow ratio = {:.4T}.", OAFlowRatio));
2492 0 : ShowContinueError(state,
2493 0 : format("... {} = {:.4T}.", cNumericFields(7), state.dataMixedAir->OAController(OutAirNum).HighRHOAFlowRatio));
2494 : }
2495 : }
2496 : }
2497 :
2498 6 : if (NumAlphas >= 18) {
2499 6 : if (UtilityRoutines::SameString(AlphArray(18), "Yes")) {
2500 6 : state.dataMixedAir->OAController(OutAirNum).ModifyDuringHighOAMoisture = false;
2501 0 : } else if (UtilityRoutines::SameString(AlphArray(18), "No")) {
2502 0 : state.dataMixedAir->OAController(OutAirNum).ModifyDuringHighOAMoisture = true;
2503 : } else {
2504 0 : ShowSevereError(state, CurrentModuleObject + " \"" + state.dataMixedAir->OAController(OutAirNum).Name + "\", invalid field value");
2505 0 : ShowContinueError(state, "..." + cAlphaFields(18) + "=\"" + AlphArray(18) + "\" - valid values are \"Yes\" or \"No\".");
2506 0 : ErrorsFound = true;
2507 : }
2508 : } else {
2509 0 : if (state.dataMixedAir->OAController(OutAirNum).Econo == EconoOp::NoEconomizer) {
2510 0 : state.dataMixedAir->OAController(OutAirNum).ModifyDuringHighOAMoisture = true;
2511 : } else {
2512 0 : state.dataMixedAir->OAController(OutAirNum).ModifyDuringHighOAMoisture = false;
2513 0 : ShowWarningError(state, CurrentModuleObject + " \"" + state.dataMixedAir->OAController(OutAirNum).Name + "\", missing field value");
2514 0 : ShowContinueError(state, "..." + cAlphaFields(18) + " will default to Yes when " + cAlphaFields(16) + "= \"Yes\"");
2515 : }
2516 : }
2517 :
2518 1015 : } else if (UtilityRoutines::SameString(AlphArray(16), "No") || lAlphaBlanks(16)) {
2519 1015 : if (NumAlphas >= 18) {
2520 121 : if (!UtilityRoutines::SameString(AlphArray(18), "Yes") && !UtilityRoutines::SameString(AlphArray(18), "No")) {
2521 0 : ShowSevereError(state, CurrentModuleObject + " \"" + state.dataMixedAir->OAController(OutAirNum).Name + "\", invalid field value");
2522 0 : ShowContinueError(state, "..." + cAlphaFields(18) + "=\"" + AlphArray(18) + "\" - valid values are \"Yes\" or \"No\".");
2523 0 : ErrorsFound = true;
2524 : }
2525 : }
2526 : } else { // Invalid field 16
2527 0 : ShowSevereError(state, CurrentModuleObject + " \"" + state.dataMixedAir->OAController(OutAirNum).Name + "\", invalid field value");
2528 0 : ShowContinueError(state, "..." + cAlphaFields(16) + "=\"" + AlphArray(16) + "\" - valid values are \"Yes\" or \"No\".");
2529 0 : ErrorsFound = true;
2530 0 : if (NumAlphas >= 18) {
2531 0 : if (!UtilityRoutines::SameString(AlphArray(18), "Yes") && !UtilityRoutines::SameString(AlphArray(18), "No")) {
2532 0 : ShowSevereError(state, CurrentModuleObject + " \"" + state.dataMixedAir->OAController(OutAirNum).Name + "\", invalid field value");
2533 0 : ShowContinueError(state, "..." + cAlphaFields(18) + "=\"" + AlphArray(18) + "\" - valid values are \"Yes\" or \"No\".");
2534 0 : ErrorsFound = true;
2535 : }
2536 : }
2537 : }
2538 :
2539 1021 : if (NumAlphas > 18) {
2540 120 : if (!lAlphaBlanks(19)) {
2541 120 : if (UtilityRoutines::SameString(AlphArray(19), "BypassWhenWithinEconomizerLimits")) {
2542 103 : state.dataMixedAir->OAController(OutAirNum).HeatRecoveryBypassControlType = BypassWhenWithinEconomizerLimits;
2543 17 : } else if (UtilityRoutines::SameString(AlphArray(19), "BypassWhenOAFlowGreaterThanMinimum")) {
2544 17 : state.dataMixedAir->OAController(OutAirNum).HeatRecoveryBypassControlType = BypassWhenOAFlowGreaterThanMinimum;
2545 : } else {
2546 0 : ShowWarningError(state,
2547 0 : CurrentModuleObject + "=\"" + AlphArray(1) + "\" invalid " + cAlphaFields(19) + "=\"" + AlphArray(19) + "\".");
2548 0 : ShowContinueError(state, "...assuming \"BypassWhenWithinEconomizerLimits\" and the simulation continues.");
2549 0 : state.dataMixedAir->OAController(OutAirNum).HeatRecoveryBypassControlType = BypassWhenWithinEconomizerLimits;
2550 : }
2551 : }
2552 : }
2553 :
2554 1021 : if (UtilityRoutines::SameString(AlphArray(16), "Yes") && state.dataMixedAir->OAController(OutAirNum).Econo == EconoOp::NoEconomizer) {
2555 0 : ShowWarningError(
2556 0 : state, state.dataMixedAir->OAController(OutAirNum).ControllerType + " \"" + state.dataMixedAir->OAController(OutAirNum).Name + "\"");
2557 0 : ShowContinueError(state, "...Economizer operation must be enabled when " + cAlphaFields(16) + " is set to YES.");
2558 0 : ShowContinueError(state, "...The high humidity control option will be disabled and the simulation continues.");
2559 : }
2560 :
2561 1021 : state.dataMixedAir->OAController(OutAirNum).MixedAirSPMNum =
2562 1021 : GetMixedAirNumWithCoilFreezingCheck(state, state.dataMixedAir->OAController(OutAirNum).MixNode);
2563 1021 : }
2564 :
2565 : // End of Get Input subroutines for the Module
2566 : //******************************************************************************
2567 :
2568 : // Beginning Initialization Section of the Module
2569 : //******************************************************************************
2570 :
2571 24268600 : void InitOutsideAirSys(EnergyPlusData &state, int const(OASysNum), bool const FirstHVACIteration, int const AirLoopNum)
2572 : {
2573 :
2574 : // SUBROUTINE INFORMATION:
2575 : // AUTHOR Fred Buhl
2576 : // DATE WRITTEN Oct 1998
2577 : // MODIFIED na
2578 : // RE-ENGINEERED na
2579 :
2580 : // PURPOSE OF THIS SUBROUTINE
2581 : // Initialize the OutsideAirSys data structure
2582 :
2583 : // METHODOLOGY EMPLOYED:
2584 :
2585 : // REFERENCES:
2586 :
2587 : // Using/Aliasing
2588 : using namespace DataLoopNode;
2589 :
2590 : // Locals
2591 : // SUBROUTINE ARGUMENT DEFINITIONS
2592 :
2593 : // SUBROUTINE PARAMETER DEFINITIONS:
2594 :
2595 : // INTERFACE BLOCK SPECIFICATIONS
2596 : // na
2597 :
2598 : // DERIVED TYPE DEFINITIONS
2599 : // na
2600 :
2601 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2602 :
2603 : // if ( BeginEnvrnFlag && FirstHVACIteration ) {
2604 : // }
2605 :
2606 : // if ( BeginDayFlag ) {
2607 : // }
2608 :
2609 24268600 : if (state.dataAirLoop->OutsideAirSys(OASysNum).AirLoopDOASNum > -1) return;
2610 :
2611 24257718 : if (state.dataMixedAir->initOASysFlag(OASysNum)) {
2612 1021 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysNum = OASysNum;
2613 1021 : state.dataMixedAir->initOASysFlag(OASysNum) = false;
2614 : }
2615 :
2616 : // Each time step
2617 : if (FirstHVACIteration) {
2618 : }
2619 :
2620 : // Each iteration
2621 : }
2622 :
2623 24821703 : void InitOAController(EnergyPlusData &state, int const OAControllerNum, bool const FirstHVACIteration, int const AirLoopNum)
2624 : {
2625 :
2626 : // SUBROUTINE INFORMATION:
2627 : // AUTHOR Fred Buhl
2628 : // DATE WRITTEN Oct 1998
2629 : // MODIFIED Shirey/Raustad FSEC, June/Aug 2003, Feb 2004
2630 : // Tianzhen Hong, Feb 2009 for DCV
2631 : // Tianzhen Hong, Aug 2013 for economizer faults
2632 :
2633 : // PURPOSE OF THIS SUBROUTINE
2634 : // Initialize the OAController data structure with input node data
2635 :
2636 : using namespace DataLoopNode;
2637 : using Psychrometrics::PsyRhoAirFnPbTdbW;
2638 :
2639 : using namespace OutputReportPredefined;
2640 : using EMSManager::CheckIfNodeSetPointManagedByEMS;
2641 :
2642 24821703 : auto &OAControllerMyOneTimeFlag = state.dataMixedAir->OAControllerMyOneTimeFlag; // One-time initialization flag
2643 24821703 : auto &OAControllerMyEnvrnFlag = state.dataMixedAir->OAControllerMyEnvrnFlag; // One-time initialization flag
2644 24821703 : auto &OAControllerMySizeFlag = state.dataMixedAir->OAControllerMySizeFlag; // One-time initialization flag
2645 24821703 : auto &MechVentCheckFlag = state.dataMixedAir->MechVentCheckFlag; // One-time initialization flag
2646 : bool FoundZone; // Logical determines if ZONE object is accounted for in VENTILATION:MECHANICAL object
2647 : bool FoundAreaZone; // Logical determines if ZONE object is accounted for in VENTILATION:MECHANICAL object
2648 : bool FoundPeopleZone; // Logical determines if ZONE object is accounted for in VENTILATION:MECHANICAL object
2649 : bool OASysFound; // Logical determines if OA system found
2650 : bool AirLoopFound; // Logical determines if primary air loop found
2651 : bool ErrorsFound; // Errors found getting input
2652 : Real64 RhoAirStdInit; // Standard air density
2653 : Real64 TotalPeopleOAFlow; // Total outside air required for PEOPLE objects served by this OA controller
2654 : int MixedAirNode; // Controller:OutdoorAir mixed air node
2655 : int AirLoopZoneInfoZoneNum; // Index to AirLoopZoneInfo structure
2656 : int NumZone; // Zone number in AirLoopZoneInfo structure
2657 : int PeopleNum; // Index to PEOPLE objects
2658 : int NumMechVentZone; // Index to number of zones in VentilationMechanical structure
2659 : int TempMechVentArrayCounter; // Temporary array counter
2660 : int thisOASys; // Temporary array counter
2661 : int thisNumForMixer; // Temporary array counter
2662 : int thisMixerIndex; // Temporary array counter
2663 : int OASysNum; // Temporary array counter
2664 : int found; // Temporary index to equipment
2665 : int OANode; // OA node index
2666 : int VentMechObjectNum; // Temporary variable
2667 : int OAControllerLoop; // Index to OA controller in an OA system
2668 : int OAControllerLoop2; // Index to OA controller in an OA system
2669 : int thisAirLoop; // Temporary array counter
2670 : int BranchNum; // Temporary array counter
2671 : int CompNum; // Temporary array counter
2672 49643406 : std::string equipName; // Temporary equipment name
2673 49643406 : std::string airloopName; // Temporary equipment name
2674 49643406 : std::string zoneName;
2675 : int jZone;
2676 :
2677 : Real64 rSchVal;
2678 : Real64 rOffset;
2679 : int i;
2680 : EconoOp iEco;
2681 :
2682 24821703 : ErrorsFound = false;
2683 24821703 : OANode = 0;
2684 :
2685 24821703 : auto &thisOAController(state.dataMixedAir->OAController(OAControllerNum));
2686 :
2687 24821703 : if (state.dataMixedAir->InitOAControllerOneTimeFlag) {
2688 394 : OAControllerMyOneTimeFlag.dimension(state.dataMixedAir->NumOAControllers, true);
2689 394 : OAControllerMyEnvrnFlag.dimension(state.dataMixedAir->NumOAControllers, true);
2690 394 : OAControllerMySizeFlag.dimension(state.dataMixedAir->NumOAControllers, true);
2691 394 : MechVentCheckFlag.dimension(state.dataMixedAir->NumOAControllers, true);
2692 394 : state.dataMixedAir->InitOAControllerSetPointCheckFlag.dimension(state.dataMixedAir->NumOAControllers, true);
2693 394 : state.dataMixedAir->InitOAControllerOneTimeFlag = false;
2694 : }
2695 24821703 : if (OAControllerMyOneTimeFlag(OAControllerNum)) {
2696 : // Determine Inlet node index for OAController, not a user input for controller, but is obtained from OutsideAirSys and OAMixer
2697 1125 : switch (thisOAController.ControllerType_Num) {
2698 1021 : case MixedAirControllerType::ControllerOutsideAir: {
2699 1021 : thisOASys = 0;
2700 6280 : for (OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; ++OASysNum) {
2701 : // find which OAsys has this controller
2702 12560 : found = UtilityRoutines::FindItemInList(thisOAController.Name,
2703 6280 : state.dataAirLoop->OutsideAirSys(OASysNum).ControllerName,
2704 6280 : isize(state.dataAirLoop->OutsideAirSys(OASysNum).ControllerName));
2705 6280 : if (found != 0) {
2706 1021 : thisOASys = OASysNum;
2707 1021 : state.dataAirLoop->OutsideAirSys(thisOASys).OAControllerIndex = GetOAController(state, thisOAController.Name);
2708 1021 : break; // we found it
2709 : }
2710 : }
2711 1021 : if (thisOASys == 0) {
2712 0 : ShowSevereError(state, "InitOAController: Did not find OAController=\"" + thisOAController.Name + "\".");
2713 0 : ShowContinueError(state, "in list of valid OA Controllers.");
2714 0 : ErrorsFound = true;
2715 : }
2716 2042 : thisNumForMixer = UtilityRoutines::FindItem(CurrentModuleObjects(static_cast<int>(CMO::OAMixer)),
2717 1021 : state.dataAirLoop->OutsideAirSys(thisOASys).ComponentType,
2718 1021 : isize(state.dataAirLoop->OutsideAirSys(thisOASys).ComponentType));
2719 1021 : if (thisNumForMixer != 0) {
2720 1021 : equipName = state.dataAirLoop->OutsideAirSys(thisOASys).ComponentName(thisNumForMixer);
2721 1021 : thisMixerIndex = UtilityRoutines::FindItemInList(equipName, state.dataMixedAir->OAMixer);
2722 1021 : if (thisMixerIndex != 0) {
2723 1021 : thisOAController.InletNode = state.dataMixedAir->OAMixer(thisMixerIndex).InletNode;
2724 : } else {
2725 0 : ShowSevereError(state, "InitOAController: Did not find OAMixer=\"" + equipName + "\".");
2726 0 : ShowContinueError(state, "in list of valid OA Mixers.");
2727 0 : ErrorsFound = true;
2728 : }
2729 : } else {
2730 0 : ShowSevereError(state, "InitOAController: Did not find OutdoorAir:Mixer Component=\"OutdoorAir:Mixer\".");
2731 0 : ShowContinueError(state, "in list of valid OA Components.");
2732 0 : ErrorsFound = true;
2733 : }
2734 :
2735 1021 : if (thisOAController.InletNode == 0) { // throw an error
2736 0 : ShowSevereError(state,
2737 0 : "InitOAController: Failed to find proper inlet node for OutdoorAir:Mixer and Controller = " + thisOAController.Name);
2738 0 : ErrorsFound = true;
2739 : }
2740 1021 : } break;
2741 104 : case MixedAirControllerType::ControllerStandAloneERV: {
2742 : // set the inlet node to also equal the OA node because this is a special controller for economizing stand alone ERV
2743 : // with the assumption that equipment is bypassed....
2744 104 : thisOAController.InletNode = thisOAController.OANode;
2745 104 : } break;
2746 0 : default: {
2747 0 : ShowSevereError(state, "InitOAController: Failed to find ControllerType: " + thisOAController.ControllerType);
2748 0 : ErrorsFound = true;
2749 0 : } break;
2750 : }
2751 :
2752 1125 : OAControllerMyOneTimeFlag(OAControllerNum) = false;
2753 : }
2754 :
2755 74474805 : if (!state.dataGlobal->SysSizingCalc && state.dataMixedAir->InitOAControllerSetPointCheckFlag(OAControllerNum) &&
2756 24835411 : state.dataHVACGlobal->DoSetPointTest && !FirstHVACIteration) {
2757 1125 : MixedAirNode = thisOAController.MixNode;
2758 1125 : if (MixedAirNode > 0) {
2759 : // IF (OAController(OAControllerNum)%Econo == 1 .AND. .NOT. AirLoopControlInfo(AirLoopNum)%CyclingFan) THEN
2760 1021 : if (thisOAController.Econo > EconoOp::NoEconomizer && state.dataAirLoop->AirLoopControlInfo(AirLoopNum).AnyContFan) {
2761 480 : if (state.dataLoopNodes->Node(MixedAirNode).TempSetPoint == SensedNodeFlagValue) {
2762 16 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
2763 0 : ShowSevereError(state, "MixedAir: Missing temperature setpoint for economizer controller " + thisOAController.Name);
2764 0 : ShowSevereError(state, "Node Referenced (by Controller)=" + state.dataLoopNodes->NodeID(MixedAirNode));
2765 0 : ShowContinueError(
2766 : state, " use a Setpoint Manager with Control Variable = \"Temperature\" to establish a setpoint at the mixed air node.");
2767 0 : state.dataHVACGlobal->SetPointErrorFlag = true;
2768 : } else {
2769 : // add call to check node in EMS
2770 16 : CheckIfNodeSetPointManagedByEMS(
2771 16 : state, MixedAirNode, EMSManager::SPControlType::TemperatureSetPoint, state.dataHVACGlobal->SetPointErrorFlag);
2772 16 : if (state.dataHVACGlobal->SetPointErrorFlag) {
2773 0 : ShowSevereError(state, "MixedAir: Missing temperature setpoint for economizer controller " + thisOAController.Name);
2774 0 : ShowSevereError(state, "Node Referenced (by Controller)=" + state.dataLoopNodes->NodeID(MixedAirNode));
2775 0 : ShowContinueError(state,
2776 : " use a Setpoint Manager with Control Variable = \"Temperature\" to establish a setpoint at the "
2777 : "mixed air node.");
2778 0 : ShowContinueError(state, "Or add EMS Actuator to provide temperature setpoint at this node");
2779 : }
2780 : }
2781 : }
2782 : }
2783 : }
2784 :
2785 1125 : state.dataMixedAir->InitOAControllerSetPointCheckFlag(OAControllerNum) = false;
2786 : }
2787 :
2788 24821703 : if (!state.dataGlobal->SysSizingCalc && OAControllerMySizeFlag(OAControllerNum)) {
2789 1125 : thisOAController.SizeOAController(state);
2790 1125 : if (AirLoopNum > 0) {
2791 1021 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OACtrlNum = OAControllerNum;
2792 1021 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OACtrlName = thisOAController.Name;
2793 1021 : if (thisOAController.Lockout == LockoutType::LockoutWithHeatingPossible) {
2794 196 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithHeating = true;
2795 196 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithCompressor = false;
2796 196 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanNotLockoutEcono = false;
2797 825 : } else if (thisOAController.Lockout == LockoutType::LockoutWithCompressorPossible) {
2798 41 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithHeating = false;
2799 41 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithCompressor = true;
2800 41 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanNotLockoutEcono = false;
2801 : } else {
2802 784 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithHeating = false;
2803 784 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithCompressor = false;
2804 784 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanNotLockoutEcono = true;
2805 : }
2806 : }
2807 1125 : if ((thisOAController.MaxOA - thisOAController.MinOA) < -SmallAirVolFlow) {
2808 0 : ShowSevereError(state, "For Controller:OutdoorAir: " + thisOAController.Name);
2809 0 : ShowContinueError(state,
2810 0 : format(" maximum outdoor air flow rate ({:.4R}) < minimum outdoor air flow rate ({:.4R})",
2811 : thisOAController.MaxOA,
2812 0 : thisOAController.MinOA));
2813 0 : ShowContinueError(state,
2814 : " To set the minimum outside air flow rate use the \"Design (minimum) outdoor air flow rate\" field in the "
2815 : "Sizing:System object");
2816 0 : ErrorsFound = true;
2817 : }
2818 :
2819 1125 : if (AirLoopNum > 0) {
2820 1021 : Real64 DesSupplyVolFlowRate = state.dataAirLoop->AirLoopFlow(AirLoopNum).DesSupply / state.dataEnvrn->StdRhoAir;
2821 1021 : if ((thisOAController.MinOA - DesSupplyVolFlowRate) > 0.0001) {
2822 0 : ShowWarningError(state,
2823 0 : "InitOAController: Minimum Outdoor Air Flow Rate for Controller:OutdoorAir=" + thisOAController.Name +
2824 0 : " is greater than Design Supply Air Flow Rate for AirLoopHVAC=" +
2825 0 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNum).Name + ".");
2826 0 : ShowContinueError(state,
2827 0 : format("...Minimum Outdoor Air Flow Rate={:.6R} will be reset to loop Design Supply Air Flow Rate={:.6R}",
2828 : thisOAController.MinOA,
2829 0 : DesSupplyVolFlowRate));
2830 0 : thisOAController.MinOA = DesSupplyVolFlowRate;
2831 1021 : } else if ((thisOAController.MinOA - DesSupplyVolFlowRate) > 0.0) {
2832 : // If difference is tiny, reset silently
2833 0 : thisOAController.MinOA = DesSupplyVolFlowRate;
2834 : }
2835 1021 : if ((thisOAController.MaxOA - DesSupplyVolFlowRate) > 0.0001) {
2836 0 : ShowWarningError(state,
2837 0 : "InitOAController: Maximum Outdoor Air Flow Rate for Controller:OutdoorAir=" + thisOAController.Name +
2838 0 : " is greater than Design Supply Air Flow Rate for AirLoopHVAC=" +
2839 0 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNum).Name + ".");
2840 0 : ShowContinueError(state,
2841 0 : format("...Maximum Outdoor Air Flow Rate={:.6R} will be reset to loop Design Supply Air Flow Rate={:.6R}",
2842 : thisOAController.MaxOA,
2843 0 : DesSupplyVolFlowRate));
2844 0 : thisOAController.MaxOA = DesSupplyVolFlowRate;
2845 1021 : } else if ((thisOAController.MaxOA - DesSupplyVolFlowRate) > 0.0) {
2846 : // If difference is tiny, reset silently
2847 9 : thisOAController.MaxOA = DesSupplyVolFlowRate;
2848 : }
2849 :
2850 : // Check if system has a Sizing:System object and a sizing run has been done
2851 1021 : bool SizingDesRunThisAirSys = false;
2852 1021 : CheckThisAirSystemForSizing(state, AirLoopNum, SizingDesRunThisAirSys);
2853 :
2854 : // Get design outdoor air flow rate
2855 1021 : if (SizingDesRunThisAirSys && thisOAController.VentMechObjectNum > 0) {
2856 46 : state.dataMixedAir->VentilationMechanical(thisOAController.VentMechObjectNum).SysDesOA =
2857 46 : state.dataSize->FinalSysSizing(AirLoopNum).DesOutAirVolFlow;
2858 : }
2859 : }
2860 :
2861 1125 : OAControllerMySizeFlag(OAControllerNum) = false;
2862 : }
2863 :
2864 24821703 : if (state.dataGlobal->BeginEnvrnFlag && OAControllerMyEnvrnFlag(OAControllerNum)) {
2865 7204 : OANode = thisOAController.OANode;
2866 7204 : RhoAirStdInit = state.dataEnvrn->StdRhoAir;
2867 7204 : thisOAController.MinOAMassFlowRate = thisOAController.MinOA * RhoAirStdInit;
2868 7204 : thisOAController.MaxOAMassFlowRate = thisOAController.MaxOA * RhoAirStdInit;
2869 7204 : OAControllerMyEnvrnFlag(OAControllerNum) = false;
2870 7204 : state.dataLoopNodes->Node(OANode).MassFlowRateMax = thisOAController.MaxOAMassFlowRate;
2871 :
2872 : // predefined reporting
2873 7204 : if (thisOAController.Econo > EconoOp::NoEconomizer) {
2874 3517 : equipName = thisOAController.Name;
2875 : // 90.1 descriptor for economizer controls
2876 : // Changed by Amit for New Feature implementation
2877 3517 : if (thisOAController.Econo == EconoOp::DifferentialEnthalpy) {
2878 118 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoKind, equipName, "DifferentialEnthalpy");
2879 3399 : } else if (thisOAController.Econo == EconoOp::DifferentialDryBulb) {
2880 2612 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoKind, equipName, "DifferentialDryBulb");
2881 787 : } else if (thisOAController.Econo == EconoOp::FixedEnthalpy) {
2882 0 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoKind, equipName, "FixedEnthalpy");
2883 787 : } else if (thisOAController.Econo == EconoOp::FixedDryBulb) {
2884 740 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoKind, equipName, "FixedDryBulb");
2885 : } else {
2886 47 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoKind, equipName, "Other");
2887 : }
2888 :
2889 3517 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoMinOA, equipName, thisOAController.MinOA);
2890 3517 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoMaxOA, equipName, thisOAController.MaxOA);
2891 : // EnergyPlus input echos for economizer controls
2892 : // Chnged by Amit for new feature implementation
2893 3517 : if (thisOAController.Econo == EconoOp::DifferentialDryBulb) {
2894 2612 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, "Yes");
2895 : } else {
2896 905 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, "No");
2897 : }
2898 3517 : if (thisOAController.Econo == EconoOp::DifferentialEnthalpy) {
2899 118 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, "Yes");
2900 : } else {
2901 3399 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, "No");
2902 : }
2903 3517 : if (thisOAController.Econo == EconoOp::FixedDryBulb) {
2904 740 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, thisOAController.TempLim);
2905 : } else {
2906 2777 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, "-");
2907 : }
2908 3517 : if (thisOAController.Econo == EconoOp::FixedEnthalpy) {
2909 0 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, thisOAController.EnthLim);
2910 : } else {
2911 3517 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, "-");
2912 : }
2913 : }
2914 : }
2915 :
2916 24821703 : if (!state.dataGlobal->BeginEnvrnFlag) {
2917 24740261 : OAControllerMyEnvrnFlag(OAControllerNum) = true;
2918 : }
2919 :
2920 24821703 : VentMechObjectNum = thisOAController.VentMechObjectNum;
2921 24821703 : if (MechVentCheckFlag(OAControllerNum)) {
2922 : // Make these checks only once at the beginning of the simulation
2923 :
2924 : // Make sure all air loop zones and air loop zones with people objects are covered by mechanical ventilation
2925 : // Issue a warning only if the zone is not accounted for in the associated mechanical ventilation object
2926 1125 : if (VentMechObjectNum > 0) {
2927 52 : auto &vent_mech(state.dataMixedAir->VentilationMechanical(VentMechObjectNum));
2928 :
2929 : // Make sure all zones with mechanical ventilation are on the correct air loop
2930 52 : TempMechVentArrayCounter = 0;
2931 399 : for (NumMechVentZone = 1; NumMechVentZone <= vent_mech.NumofVentMechZones; ++NumMechVentZone) {
2932 347 : int ZoneNum = vent_mech.VentMechZone(NumMechVentZone);
2933 347 : auto const &zone(state.dataHeatBal->Zone(ZoneNum));
2934 347 : FoundZone = false;
2935 :
2936 3200 : for (AirLoopZoneInfoZoneNum = 1; AirLoopZoneInfoZoneNum <= state.dataAirLoop->AirLoopZoneInfo(AirLoopNum).NumZones;
2937 : ++AirLoopZoneInfoZoneNum) {
2938 3200 : NumZone = state.dataAirLoop->AirLoopZoneInfo(AirLoopNum).ActualZoneNumber(AirLoopZoneInfoZoneNum);
2939 3200 : if (ZoneNum == NumZone) {
2940 347 : FoundZone = true;
2941 347 : ++TempMechVentArrayCounter;
2942 347 : if (TempMechVentArrayCounter < NumMechVentZone) { // Copy to lower index
2943 0 : vent_mech.VentMechZone(TempMechVentArrayCounter) = vent_mech.VentMechZone(NumMechVentZone);
2944 0 : vent_mech.ZoneOAAreaRate(TempMechVentArrayCounter) = vent_mech.ZoneOAAreaRate(NumMechVentZone);
2945 0 : vent_mech.ZoneOAPeopleRate(TempMechVentArrayCounter) = vent_mech.ZoneOAPeopleRate(NumMechVentZone);
2946 0 : vent_mech.ZoneOAFlowRate(TempMechVentArrayCounter) = vent_mech.ZoneOAFlowRate(NumMechVentZone);
2947 0 : vent_mech.ZoneOAACHRate(TempMechVentArrayCounter) = vent_mech.ZoneOAACHRate(NumMechVentZone);
2948 0 : vent_mech.ZoneOAFlowMethod(TempMechVentArrayCounter) = vent_mech.ZoneOAFlowMethod(NumMechVentZone);
2949 0 : vent_mech.ZoneOASchPtr(TempMechVentArrayCounter) = vent_mech.ZoneOASchPtr(NumMechVentZone);
2950 0 : vent_mech.ZoneDesignSpecOAObjIndex(TempMechVentArrayCounter) = vent_mech.ZoneDesignSpecOAObjIndex(NumMechVentZone);
2951 0 : vent_mech.ZoneDesignSpecOAObjName(TempMechVentArrayCounter) = vent_mech.ZoneDesignSpecOAObjName(NumMechVentZone);
2952 :
2953 : // new DCV
2954 0 : vent_mech.ZoneADEffCooling(TempMechVentArrayCounter) = vent_mech.ZoneADEffCooling(NumMechVentZone);
2955 0 : vent_mech.ZoneADEffHeating(TempMechVentArrayCounter) = vent_mech.ZoneADEffHeating(NumMechVentZone);
2956 0 : vent_mech.ZoneADEffSchPtr(TempMechVentArrayCounter) = vent_mech.ZoneADEffSchPtr(NumMechVentZone);
2957 : }
2958 :
2959 : // Sum outside air per unit floor area for each mechanical ventilation object only once per simulation
2960 347 : vent_mech.TotAreaOAFlow += zone.FloorArea * zone.Multiplier * zone.ListMultiplier * vent_mech.ZoneOAAreaRate(NumMechVentZone);
2961 347 : vent_mech.TotZoneOAFlow += zone.Multiplier * zone.ListMultiplier * vent_mech.ZoneOAFlowRate(NumMechVentZone);
2962 347 : vent_mech.TotZoneOAACH +=
2963 347 : zone.Multiplier * zone.ListMultiplier * (vent_mech.ZoneOAACHRate(NumMechVentZone) * zone.Volume / 3600.0);
2964 347 : break;
2965 : }
2966 : }
2967 347 : if (!FoundZone) {
2968 0 : ShowWarningError(state,
2969 0 : "Zone name = " + zone.Name + " in " + CurrentModuleObjects(static_cast<int>(CMO::MechVentilation)) +
2970 0 : " object name = " + thisOAController.VentilationMechanicalName +
2971 0 : " is not on the same air loop as Controller:OutdoorAir = " + thisOAController.Name);
2972 0 : ShowContinueError(state, "This zone will not be used and the simulation will continue...");
2973 : }
2974 : }
2975 :
2976 : // Shrink final arrays to conserve environment space
2977 52 : if (TempMechVentArrayCounter < vent_mech.NumofVentMechZones) {
2978 0 : vent_mech.VentMechZone.redimension(TempMechVentArrayCounter);
2979 0 : vent_mech.ZoneOAAreaRate.redimension(TempMechVentArrayCounter);
2980 0 : vent_mech.ZoneOAPeopleRate.redimension(TempMechVentArrayCounter);
2981 0 : vent_mech.ZoneOAFlowRate.redimension(TempMechVentArrayCounter);
2982 0 : vent_mech.ZoneOAACHRate.redimension(TempMechVentArrayCounter);
2983 0 : vent_mech.ZoneOAFlowMethod.redimension(TempMechVentArrayCounter);
2984 0 : vent_mech.ZoneOASchPtr.redimension(TempMechVentArrayCounter);
2985 0 : vent_mech.ZoneDesignSpecOAObjIndex.redimension(TempMechVentArrayCounter);
2986 0 : vent_mech.ZoneDesignSpecOAObjName.redimension(TempMechVentArrayCounter);
2987 :
2988 0 : vent_mech.ZoneADEffCooling.redimension(TempMechVentArrayCounter);
2989 0 : vent_mech.ZoneADEffHeating.redimension(TempMechVentArrayCounter);
2990 0 : vent_mech.ZoneADEffSchPtr.redimension(TempMechVentArrayCounter);
2991 :
2992 0 : vent_mech.NumofVentMechZones = TempMechVentArrayCounter;
2993 : }
2994 :
2995 : // predefined report
2996 399 : for (jZone = 1; jZone <= vent_mech.NumofVentMechZones; ++jZone) {
2997 347 : zoneName = state.dataHeatBal->Zone(vent_mech.VentMechZone(jZone)).Name;
2998 347 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVventMechName, zoneName, vent_mech.Name);
2999 347 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVperPerson, zoneName, vent_mech.ZoneOAPeopleRate(jZone), 6);
3000 347 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVperArea, zoneName, vent_mech.ZoneOAAreaRate(jZone), 6);
3001 347 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVperZone, zoneName, vent_mech.ZoneOAFlowRate(jZone), 6);
3002 347 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVperACH, zoneName, vent_mech.ZoneOAACHRate(jZone), 6);
3003 694 : PreDefTableEntry(state,
3004 347 : state.dataOutRptPredefined->pdchDCVMethod,
3005 : zoneName,
3006 347 : OAFlowCalcMethodNames[static_cast<int>(vent_mech.ZoneOAFlowMethod(jZone))]);
3007 347 : if (vent_mech.ZoneOASchPtr(jZone) > 0) {
3008 2 : PreDefTableEntry(
3009 3 : state, state.dataOutRptPredefined->pdchDCVOASchName, zoneName, GetScheduleName(state, vent_mech.ZoneOASchPtr(jZone)));
3010 : } else {
3011 346 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVOASchName, zoneName, "");
3012 : }
3013 :
3014 : // added for new DCV inputs
3015 347 : if (vent_mech.ZoneADEffSchPtr(jZone) > 0) {
3016 5 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVZoneADEffCooling, zoneName, "");
3017 5 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVZoneADEffHeating, zoneName, "");
3018 10 : PreDefTableEntry(state,
3019 5 : state.dataOutRptPredefined->pdchDCVZoneADEffSchName,
3020 : zoneName,
3021 10 : GetScheduleName(state, vent_mech.ZoneADEffSchPtr(jZone)));
3022 : } else {
3023 342 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVZoneADEffCooling, zoneName, vent_mech.ZoneADEffCooling(jZone), 2);
3024 342 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVZoneADEffHeating, zoneName, vent_mech.ZoneADEffHeating(jZone), 2);
3025 342 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVZoneADEffSchName, zoneName, "");
3026 : }
3027 : }
3028 :
3029 : // Check to see if any zones on an air loop are not accounted for by a mechanical ventilation object
3030 399 : for (AirLoopZoneInfoZoneNum = 1; AirLoopZoneInfoZoneNum <= state.dataAirLoop->AirLoopZoneInfo(AirLoopNum).NumZones;
3031 : ++AirLoopZoneInfoZoneNum) {
3032 347 : NumZone = state.dataAirLoop->AirLoopZoneInfo(AirLoopNum).ActualZoneNumber(AirLoopZoneInfoZoneNum);
3033 347 : FoundAreaZone = false;
3034 347 : FoundPeopleZone = false;
3035 3200 : for (NumMechVentZone = 1; NumMechVentZone <= vent_mech.NumofVentMechZones; ++NumMechVentZone) {
3036 3200 : int ZoneNum = vent_mech.VentMechZone(NumMechVentZone);
3037 3200 : if (ZoneNum == NumZone) {
3038 347 : FoundAreaZone = true;
3039 347 : if (vent_mech.ZoneOAPeopleRate(NumMechVentZone) > 0.0) {
3040 336 : FoundPeopleZone = true;
3041 : }
3042 347 : break;
3043 : }
3044 : }
3045 347 : if (!FoundAreaZone) {
3046 0 : ShowWarningError(state,
3047 0 : "Zone name = " + state.dataHeatBal->Zone(NumZone).Name + " is not accounted for by " +
3048 0 : CurrentModuleObjects(static_cast<int>(CMO::MechVentilation)) +
3049 0 : " object name = " + thisOAController.VentilationMechanicalName);
3050 0 : ShowContinueError(state, "Ventilation per unit floor area has not been specified for this zone, which is connected to");
3051 0 : ShowContinueError(state,
3052 0 : "the air loop served by Controller:OutdoorAir = " + thisOAController.Name + ". Simulation will continue...");
3053 : }
3054 347 : if (!FoundPeopleZone) {
3055 : // Loop through people objects to see if this zone has a people object and only then show a warning
3056 257 : for (PeopleNum = 1; PeopleNum <= state.dataHeatBal->TotPeople; ++PeopleNum) {
3057 246 : if (state.dataHeatBal->People(PeopleNum).ZonePtr == NumZone) {
3058 7 : if (!FoundAreaZone) {
3059 0 : ShowWarningError(state,
3060 0 : "PEOPLE object for zone = " + state.dataHeatBal->Zone(NumZone).Name + " is not accounted for by " +
3061 0 : CurrentModuleObjects(static_cast<int>(CMO::MechVentilation)) +
3062 0 : " object name = " + thisOAController.VentilationMechanicalName);
3063 0 : ShowContinueError(state,
3064 0 : "A \"PEOPLE\" object has been specified in the idf for this zone, but it is not included in this " +
3065 0 : CurrentModuleObjects(static_cast<int>(CMO::MechVentilation)) + " Object.");
3066 0 : ShowContinueError(state,
3067 0 : "Check " + CurrentModuleObjects(static_cast<int>(CMO::MechVentilation)) +
3068 : " object. Simulation will continue.");
3069 : }
3070 : }
3071 : }
3072 : } else { // People > 0, check to make sure there is a people statement in the zone
3073 336 : FoundAreaZone = false;
3074 7247 : for (PeopleNum = 1; PeopleNum <= state.dataHeatBal->TotPeople; ++PeopleNum) {
3075 7203 : if (state.dataHeatBal->People(PeopleNum).ZonePtr != NumZone) continue;
3076 292 : FoundAreaZone = true;
3077 292 : break;
3078 : }
3079 336 : if (!FoundAreaZone) {
3080 132 : ShowWarningError(state,
3081 88 : CurrentModuleObjects(static_cast<int>(CMO::MechVentilation)) + " = \"" +
3082 132 : thisOAController.VentilationMechanicalName + "\", Zone=\"" + state.dataHeatBal->Zone(NumZone).Name +
3083 : "\".");
3084 44 : ShowContinueError(state,
3085 : "No \"PEOPLE\" object has been specified in the idf for this zone, but the ventilation rate is > 0 in "
3086 : "this Controller:MechanicalVentilation Object.");
3087 44 : ShowContinueError(state, "Check ventilation rate in Controller:MechanicalVentilation object. Simulation will continue.");
3088 : }
3089 : }
3090 : }
3091 : }
3092 :
3093 1125 : MechVentCheckFlag(OAControllerNum) = false;
3094 : }
3095 : //****
3096 :
3097 : // Perform a one time initialization of AirloopHVAC OA System report variables
3098 : // If AirloopHVAC objects are used, NumPrimaryAirSys > 0 and the initialization proceeds and then sets
3099 : // SetUpAirLoopHVACVariables to .FALSE. so this is never done again and only the first IF is checked
3100 : // each time through Init. If for some reason the primary air system have not yet been read in, this
3101 : // code waits for the air loop data to be available before performing the report variable initialization.
3102 : // If AirloopHVAC objects are not used, NumPrimaryAirSys is always equal to 0 and only these
3103 : // two IF statements are checked each time through Init (e.g., if StandAloneERV controllers are used
3104 : // without AirloopHVAC objects).
3105 24821703 : if (state.dataMixedAir->InitOAControllerSetUpAirLoopHVACVariables) {
3106 7771 : if (AirLoopNum > 0) {
3107 : // Added code to report (TH, 10/20/2008):
3108 : // air economizer status (1 = on, 0 = off or does not exist), and
3109 : // actual and minimum outside air fraction (0 to 1)
3110 1516 : for (OAControllerLoop = 1; OAControllerLoop <= state.dataMixedAir->NumOAControllers; ++OAControllerLoop) {
3111 1123 : auto &loopOAController(state.dataMixedAir->OAController(OAControllerLoop));
3112 :
3113 : // Find the outside air system that has the OA controller
3114 1123 : if (loopOAController.ControllerType_Num == MixedAirControllerType::ControllerStandAloneERV) continue; // ERV controller not on airloop
3115 1021 : OASysFound = false;
3116 1021 : thisOASys = 0;
3117 6280 : for (OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; ++OASysNum) {
3118 11541 : for (OAControllerLoop2 = 1; OAControllerLoop2 <= state.dataAirLoop->OutsideAirSys(OASysNum).NumControllers; ++OAControllerLoop2) {
3119 6282 : if (UtilityRoutines::SameString(state.dataAirLoop->OutsideAirSys(OASysNum).ControllerName(OAControllerLoop2),
3120 : loopOAController.Name)) {
3121 1021 : thisOASys = OASysNum;
3122 1021 : OASysFound = true;
3123 1021 : break;
3124 : }
3125 : }
3126 6280 : if (OASysFound) break;
3127 : }
3128 :
3129 1021 : if (thisOASys <= 0) {
3130 : // Check outside air system name
3131 0 : ShowWarningError(state, "Cannot find the AirLoopHVAC:OutdoorAirSystem for the OA Controller: " + thisOAController.Name);
3132 0 : AirLoopFound = false;
3133 : } else {
3134 : // Find the primary air loop that has the outside air system
3135 1021 : AirLoopFound = false;
3136 6280 : for (thisAirLoop = 1; thisAirLoop <= state.dataHVACGlobal->NumPrimaryAirSys; ++thisAirLoop) {
3137 11542 : for (BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(thisAirLoop).NumBranches; ++BranchNum) {
3138 19084 : for (CompNum = 1; CompNum <= state.dataAirSystemsData->PrimaryAirSystems(thisAirLoop).Branch(BranchNum).TotalComponents;
3139 : ++CompNum) {
3140 41466 : if (!UtilityRoutines::SameString(
3141 13822 : state.dataAirSystemsData->PrimaryAirSystems(thisAirLoop).Branch(BranchNum).Comp(CompNum).Name,
3142 28665 : state.dataAirLoop->OutsideAirSys(thisOASys).Name) ||
3143 14843 : !UtilityRoutines::SameString(
3144 1021 : state.dataAirSystemsData->PrimaryAirSystems(thisAirLoop).Branch(BranchNum).Comp(CompNum).TypeOf,
3145 1021 : "AirLoopHVAC:OutdoorAirSystem"))
3146 12801 : continue;
3147 1021 : AirLoopFound = true;
3148 1021 : break;
3149 : }
3150 6283 : if (AirLoopFound) break;
3151 : }
3152 6280 : if (AirLoopFound) break;
3153 : }
3154 : }
3155 : // Check primary air loop name
3156 1021 : if (AirLoopFound && thisAirLoop > 0) {
3157 1021 : airloopName = state.dataAirSystemsData->PrimaryAirSystems(thisAirLoop).Name; // OutsideAirSys(OASysIndex)%Name
3158 : } else {
3159 0 : ShowWarningError(state, "Cannot find the primary air loop for the OA Controller: " + thisOAController.Name);
3160 0 : airloopName = "AirLoop not found";
3161 : }
3162 :
3163 : // Note use of OAControllerLoop here to keep DO Loop index separate from InitOAController local variable
3164 : // CurrentModuleObject='AirLoopHVAC'
3165 2042 : SetupOutputVariable(state,
3166 : "Air System Outdoor Air Economizer Status",
3167 : OutputProcessor::Unit::None,
3168 : loopOAController.EconomizerStatus,
3169 : OutputProcessor::SOVTimeStepType::System,
3170 : OutputProcessor::SOVStoreType::Average,
3171 1021 : airloopName);
3172 :
3173 2042 : SetupOutputVariable(state,
3174 : "Air System Outdoor Air Heat Recovery Bypass Status",
3175 : OutputProcessor::Unit::None,
3176 : loopOAController.HeatRecoveryBypassStatus,
3177 : OutputProcessor::SOVTimeStepType::System,
3178 : OutputProcessor::SOVStoreType::Average,
3179 1021 : airloopName);
3180 :
3181 2042 : SetupOutputVariable(state,
3182 : "Air System Outdoor Air Heat Recovery Bypass Heating Coil Activity Status",
3183 : OutputProcessor::Unit::None,
3184 : loopOAController.HRHeatingCoilActive,
3185 : OutputProcessor::SOVTimeStepType::System,
3186 : OutputProcessor::SOVStoreType::Average,
3187 1021 : airloopName);
3188 2042 : SetupOutputVariable(state,
3189 : "Air System Outdoor Air Heat Recovery Bypass Minimum Outdoor Air Mixed Air Temperature",
3190 : OutputProcessor::Unit::C,
3191 : loopOAController.MixedAirTempAtMinOAFlow,
3192 : OutputProcessor::SOVTimeStepType::System,
3193 : OutputProcessor::SOVStoreType::Average,
3194 1021 : airloopName);
3195 :
3196 2042 : SetupOutputVariable(state,
3197 : "Air System Outdoor Air High Humidity Control Status",
3198 : OutputProcessor::Unit::None,
3199 : loopOAController.HighHumCtrlStatus,
3200 : OutputProcessor::SOVTimeStepType::System,
3201 : OutputProcessor::SOVStoreType::Average,
3202 1021 : airloopName);
3203 :
3204 2042 : SetupOutputVariable(state,
3205 : "Air System Outdoor Air Limiting Factor",
3206 : OutputProcessor::Unit::None,
3207 : loopOAController.OALimitingFactor,
3208 : OutputProcessor::SOVTimeStepType::System,
3209 : OutputProcessor::SOVStoreType::Average,
3210 1021 : airloopName);
3211 :
3212 2042 : SetupOutputVariable(state,
3213 : "Air System Outdoor Air Flow Fraction",
3214 : OutputProcessor::Unit::None,
3215 : loopOAController.OAFractionRpt,
3216 : OutputProcessor::SOVTimeStepType::System,
3217 : OutputProcessor::SOVStoreType::Average,
3218 1021 : airloopName);
3219 :
3220 2042 : SetupOutputVariable(state,
3221 : "Air System Outdoor Air Minimum Flow Fraction",
3222 : OutputProcessor::Unit::None,
3223 : loopOAController.MinOAFracLimit,
3224 : OutputProcessor::SOVTimeStepType::System,
3225 : OutputProcessor::SOVStoreType::Average,
3226 1021 : airloopName);
3227 :
3228 2042 : SetupOutputVariable(state,
3229 : "Air System Outdoor Air Mass Flow Rate",
3230 : OutputProcessor::Unit::kg_s,
3231 : loopOAController.OAMassFlow,
3232 : OutputProcessor::SOVTimeStepType::System,
3233 : OutputProcessor::SOVStoreType::Average,
3234 1021 : airloopName);
3235 :
3236 2042 : SetupOutputVariable(state,
3237 : "Air System Mixed Air Mass Flow Rate",
3238 : OutputProcessor::Unit::kg_s,
3239 : loopOAController.MixMassFlow,
3240 : OutputProcessor::SOVTimeStepType::System,
3241 : OutputProcessor::SOVStoreType::Average,
3242 1021 : airloopName);
3243 :
3244 2042 : SetupOutputVariable(state,
3245 : "Air System Relief Air Heat Transfer Rate",
3246 : OutputProcessor::Unit::W,
3247 : loopOAController.RelTotalLossRate,
3248 : OutputProcessor::SOVTimeStepType::System,
3249 : OutputProcessor::SOVStoreType::Average,
3250 1021 : airloopName);
3251 :
3252 2042 : SetupOutputVariable(state,
3253 : "Air System Relief Air Sensible Heat Transfer Rate",
3254 : OutputProcessor::Unit::W,
3255 : loopOAController.RelSensiLossRate,
3256 : OutputProcessor::SOVTimeStepType::System,
3257 : OutputProcessor::SOVStoreType::Average,
3258 1021 : airloopName);
3259 :
3260 2042 : SetupOutputVariable(state,
3261 : "Air System Relief Air Latent Heat Transfer Rate",
3262 : OutputProcessor::Unit::W,
3263 : loopOAController.RelLatentLossRate,
3264 : OutputProcessor::SOVTimeStepType::System,
3265 : OutputProcessor::SOVStoreType::Average,
3266 1021 : airloopName);
3267 :
3268 1021 : if (loopOAController.MixedAirSPMNum > 0) {
3269 2 : SetupOutputVariable(state,
3270 : "Air System Outdoor Air Maximum Flow Fraction",
3271 : OutputProcessor::Unit::None,
3272 : loopOAController.MaxOAFracBySetPoint,
3273 : OutputProcessor::SOVTimeStepType::System,
3274 : OutputProcessor::SOVStoreType::Average,
3275 1 : airloopName);
3276 : }
3277 :
3278 1021 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
3279 969 : SetupEMSInternalVariable(
3280 646 : state, "Outdoor Air Controller Maximum Mass Flow Rate", loopOAController.Name, "[kg/s]", loopOAController.MaxOAMassFlowRate);
3281 969 : SetupEMSInternalVariable(
3282 646 : state, "Outdoor Air Controller Minimum Mass Flow Rate", loopOAController.Name, "[kg/s]", loopOAController.MinOAMassFlowRate);
3283 969 : SetupEMSActuator(state,
3284 : "Outdoor Air Controller",
3285 : loopOAController.Name,
3286 : "Air Mass Flow Rate",
3287 : "[kg/s]",
3288 : loopOAController.EMSOverrideOARate,
3289 646 : loopOAController.EMSOARateValue);
3290 : }
3291 :
3292 1021 : VentMechObjectNum = loopOAController.VentMechObjectNum;
3293 1021 : if (VentMechObjectNum > 0 && thisAirLoop > 0) {
3294 104 : SetupOutputVariable(state,
3295 : "Air System Outdoor Air Mechanical Ventilation Requested Mass Flow Rate",
3296 : OutputProcessor::Unit::kg_s,
3297 : loopOAController.MechVentOAMassFlowRequest,
3298 : OutputProcessor::SOVTimeStepType::System,
3299 : OutputProcessor::SOVStoreType::Average,
3300 52 : airloopName);
3301 52 : if (!state.dataMixedAir->VentilationMechanical(VentMechObjectNum).DCVFlag) {
3302 2 : state.dataAirLoop->AirLoopControlInfo(thisAirLoop).AirLoopDCVFlag = false;
3303 : }
3304 : }
3305 : }
3306 :
3307 393 : state.dataMixedAir->InitOAControllerSetUpAirLoopHVACVariables = false;
3308 : }
3309 : }
3310 :
3311 : // Each time step
3312 24821703 : if (FirstHVACIteration) {
3313 : // Mixed air setpoint. Set by a setpoint manager.
3314 8606988 : if (thisOAController.ControllerType_Num == MixedAirControllerType::ControllerOutsideAir) {
3315 8461036 : if (state.dataLoopNodes->Node(thisOAController.MixNode).TempSetPoint > SensedNodeFlagValue) {
3316 7613497 : thisOAController.MixSetTemp = state.dataLoopNodes->Node(thisOAController.MixNode).TempSetPoint;
3317 : } else {
3318 847539 : thisOAController.MixSetTemp = thisOAController.TempLowLim;
3319 : }
3320 :
3321 8461036 : TotalPeopleOAFlow = 0.0;
3322 8461036 : if (VentMechObjectNum != 0) {
3323 343560 : auto &vent_mech(state.dataMixedAir->VentilationMechanical(VentMechObjectNum));
3324 2825748 : for (int ZoneIndex = 1; ZoneIndex <= vent_mech.NumofVentMechZones; ++ZoneIndex) {
3325 2482188 : int ZoneNum = vent_mech.VentMechZone(ZoneIndex);
3326 :
3327 : // ZoneIntGain(ZoneNum)%NOFOCC is the number of occupants of a zone at each time step, already counting the occupant schedule
3328 2482188 : OAFlowCalcMethod OAFlowMethod = vent_mech.ZoneOAFlowMethod(ZoneIndex);
3329 2482188 : if (OAFlowMethod == OAFlowCalcMethod::PerPerson || OAFlowMethod == OAFlowCalcMethod::Sum ||
3330 : OAFlowMethod == OAFlowCalcMethod::Max) {
3331 7446564 : TotalPeopleOAFlow += state.dataHeatBal->ZoneIntGain(ZoneNum).NOFOCC * state.dataHeatBal->Zone(ZoneNum).Multiplier *
3332 7446564 : state.dataHeatBal->Zone(ZoneNum).ListMultiplier * vent_mech.ZoneOAPeopleRate(ZoneIndex) *
3333 2482188 : GetCurrentScheduleValue(state, vent_mech.ZoneOASchPtr(ZoneIndex));
3334 : }
3335 : }
3336 343560 : vent_mech.TotPeopleOAFlow = TotalPeopleOAFlow;
3337 : }
3338 : } else {
3339 : // Stand Alone ERV does not require a termperature setpoint schedule, make setpoint equal to lower economizer limit
3340 145952 : thisOAController.MixSetTemp = thisOAController.TempLowLim;
3341 : }
3342 : }
3343 :
3344 : // Each iteration
3345 :
3346 24821703 : if (thisOAController.ControllerType_Num == MixedAirControllerType::ControllerOutsideAir) {
3347 : // zone exhaust mass flow is saved in AirLoopFlow%ZoneExhaust
3348 : // the zone exhaust mass flow that is said to be balanced by simple air flows is saved in AirLoopFlow%ZoneExhaustBalanced
3349 24257718 : if (AirLoopNum > 0) {
3350 24257718 : thisOAController.ExhMassFlow =
3351 24257718 : max(0.0, state.dataAirLoop->AirLoopFlow(AirLoopNum).SupFlow - state.dataAirLoop->AirLoopFlow(AirLoopNum).SysRetFlow);
3352 24257718 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).ZoneExhMassFlow = thisOAController.ExhMassFlow;
3353 24257718 : if (state.dataAirLoop->AirLoopControlInfo(AirLoopNum).LoopFlowRateSet && !FirstHVACIteration) {
3354 : // if flow rate has been specified by a manager, set it to the specified value
3355 21240 : thisOAController.MixMassFlow =
3356 21240 : state.dataAirLoop->AirLoopFlow(AirLoopNum).ReqSupplyFrac * state.dataAirLoop->AirLoopFlow(AirLoopNum).DesSupply;
3357 : } else {
3358 24236478 : thisOAController.MixMassFlow = state.dataLoopNodes->Node(thisOAController.RetNode).MassFlowRate + thisOAController.ExhMassFlow;
3359 :
3360 : // The following was commented out after discussion on PR 7382, it can be reopened for discussion anytime
3361 : // found this equation results in flow that exceeds the design flow rate when there is exhaust flow rate is greater than
3362 : // the design supply air flow rate. Capped the mixed air flow rate at design supply air flow rate, issue #77379
3363 : // thisOAController.MixMassFlow = Node(thisOAController.RetNode).MassFlowRate + thisOAController.ExhMassFlow;
3364 : // thisOAController.MixMassFlow =
3365 : // min(Node(thisOAController.RetNode).MassFlowRate + thisOAController.ExhMassFlow, AirLoopFlow(AirLoopNum).DesSupply);
3366 : }
3367 : } else {
3368 0 : thisOAController.ExhMassFlow = 0.0;
3369 0 : thisOAController.MixMassFlow = state.dataLoopNodes->Node(thisOAController.RetNode).MassFlowRate;
3370 : }
3371 24257718 : if (state.dataLoopNodes->Node(thisOAController.MixNode).MassFlowRateMaxAvail <= 0.0) {
3372 1781680 : thisOAController.MixMassFlow = 0.0;
3373 : }
3374 : } else {
3375 : // Mixed and exhaust flow rates are passed through to model CONTROLLER:STAND ALONE ERV in SimOAController
3376 563985 : thisOAController.OAMassFlow = thisOAController.MaxOAMassFlowRate;
3377 563985 : thisOAController.MixMassFlow = thisOAController.MaxOAMassFlowRate;
3378 563985 : thisOAController.ExhMassFlow = state.dataLoopNodes->Node(thisOAController.RetNode).MassFlowRate;
3379 : }
3380 24821703 : thisOAController.ExhMassFlow = max(thisOAController.ExhMassFlow, 0.0);
3381 :
3382 : // Outside air values
3383 24821703 : thisOAController.OATemp = state.dataLoopNodes->Node(thisOAController.OANode).Temp;
3384 24821703 : thisOAController.OAEnth = state.dataLoopNodes->Node(thisOAController.OANode).Enthalpy;
3385 24821703 : thisOAController.OAPress = state.dataLoopNodes->Node(thisOAController.OANode).Press;
3386 24821703 : thisOAController.OAHumRat = state.dataLoopNodes->Node(thisOAController.OANode).HumRat;
3387 :
3388 : // Inlet air values (on OA input side)
3389 24821703 : thisOAController.InletTemp = state.dataLoopNodes->Node(thisOAController.InletNode).Temp;
3390 24821703 : thisOAController.InletEnth = state.dataLoopNodes->Node(thisOAController.InletNode).Enthalpy;
3391 24821703 : thisOAController.InletPress = state.dataLoopNodes->Node(thisOAController.InletNode).Press;
3392 24821703 : thisOAController.InletHumRat = state.dataLoopNodes->Node(thisOAController.InletNode).HumRat;
3393 :
3394 : // Return air values
3395 24821703 : thisOAController.RetTemp = state.dataLoopNodes->Node(thisOAController.RetNode).Temp;
3396 24821703 : thisOAController.RetEnth = state.dataLoopNodes->Node(thisOAController.RetNode).Enthalpy;
3397 :
3398 : // Check sensors faults for the air economizer
3399 24821703 : iEco = thisOAController.Econo;
3400 24821703 : if (state.dataFaultsMgr->AnyFaultsInModel && (iEco != EconoOp::NoEconomizer)) {
3401 : int j; // index to economizer faults
3402 1744681 : for (i = 1; i <= thisOAController.NumFaultyEconomizer; ++i) {
3403 241001 : j = thisOAController.EconmizerFaultNum(i);
3404 241001 : if (GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsEconomizer(j).AvaiSchedPtr) > 0.0) {
3405 241001 : rSchVal = 1.0;
3406 241001 : if (state.dataFaultsMgr->FaultsEconomizer(j).SeveritySchedPtr > 0) {
3407 47025 : rSchVal = GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsEconomizer(j).SeveritySchedPtr);
3408 : }
3409 : } else {
3410 : // no fault
3411 0 : continue;
3412 : }
3413 :
3414 241001 : rOffset = rSchVal * state.dataFaultsMgr->FaultsEconomizer(j).Offset;
3415 :
3416 241001 : if (std::abs(rOffset) < 0.000000001) continue;
3417 :
3418 : // ECONOMIZER - outdoor air dry-bulb temperature sensor offset
3419 232646 : switch (iEco) {
3420 232646 : case EconoOp::FixedDryBulb:
3421 : case EconoOp::DifferentialDryBulb:
3422 : case EconoOp::FixedDewPointAndDryBulb:
3423 : case EconoOp::ElectronicEnthalpy:
3424 : case EconoOp::DifferentialDryBulbAndEnthalpy: {
3425 232646 : if (state.dataFaultsMgr->FaultsEconomizer(j).FaultTypeEnum == Fault::TemperatureSensorOffset_OutdoorAir) {
3426 : // FaultModel:TemperatureSensorOffset:OutdoorAir
3427 38670 : thisOAController.OATemp += rOffset;
3428 38670 : thisOAController.InletTemp += rOffset;
3429 : }
3430 232646 : } break;
3431 0 : default:
3432 0 : break;
3433 : }
3434 :
3435 : // ECONOMIZER - outdoor air humidity ratio sensor offset. really needed ???
3436 232646 : switch (iEco) {
3437 0 : case EconoOp::FixedDewPointAndDryBulb:
3438 : case EconoOp::ElectronicEnthalpy: {
3439 0 : if (state.dataFaultsMgr->FaultsEconomizer(j).FaultTypeEnum == Fault::HumiditySensorOffset_OutdoorAir) {
3440 : // FaultModel:HumiditySensorOffset:OutdoorAir
3441 0 : thisOAController.OAHumRat += rOffset;
3442 0 : thisOAController.InletHumRat += rOffset;
3443 : }
3444 0 : } break;
3445 232646 : default:
3446 232646 : break;
3447 : }
3448 :
3449 : // ECONOMIZER - outdoor air enthalpy sensor offset
3450 232646 : switch (iEco) {
3451 0 : case EconoOp::FixedEnthalpy:
3452 : case EconoOp::ElectronicEnthalpy:
3453 : case EconoOp::DifferentialDryBulbAndEnthalpy: {
3454 0 : if (state.dataFaultsMgr->FaultsEconomizer(j).FaultTypeEnum == Fault::EnthalpySensorOffset_OutdoorAir) {
3455 : // FaultModel:EnthalpySensorOffset:OutdoorAir
3456 0 : thisOAController.OAEnth += rOffset;
3457 0 : thisOAController.InletEnth += rOffset;
3458 : }
3459 0 : } break;
3460 232646 : default:
3461 232646 : break;
3462 : }
3463 :
3464 : // ECONOMIZER - return air dry-bulb temperature sensor offset
3465 232646 : switch (iEco) {
3466 232646 : case EconoOp::DifferentialDryBulb:
3467 : case EconoOp::DifferentialDryBulbAndEnthalpy: {
3468 232646 : if (state.dataFaultsMgr->FaultsEconomizer(j).FaultTypeEnum == Fault::TemperatureSensorOffset_ReturnAir) {
3469 : // FaultModel:TemperatureSensorOffset:ReturnAir
3470 49963 : thisOAController.RetTemp += rOffset;
3471 : }
3472 232646 : } break;
3473 0 : default:
3474 0 : break;
3475 : }
3476 :
3477 : // ECONOMIZER - return air enthalpy sensor offset
3478 232646 : switch (iEco) {
3479 0 : case EconoOp::ElectronicEnthalpy:
3480 : case EconoOp::DifferentialDryBulbAndEnthalpy: {
3481 0 : if (state.dataFaultsMgr->FaultsEconomizer(j).FaultTypeEnum == Fault::EnthalpySensorOffset_ReturnAir) {
3482 : // FaultModel:EnthalpySensorOffset:ReturnAir
3483 0 : thisOAController.RetEnth += rOffset;
3484 : }
3485 0 : } break;
3486 232646 : default:
3487 232646 : break;
3488 : }
3489 : }
3490 : }
3491 :
3492 24821703 : if (ErrorsFound) {
3493 0 : ShowFatalError(state, "Error in " + CurrentModuleObjects(static_cast<int>(CMO::OAController)) + "; program terminated");
3494 : }
3495 24821703 : } // namespace MixedAir
3496 :
3497 43707297 : void InitOAMixer(EnergyPlusData &state, int const OAMixerNum, bool const FirstHVACIteration)
3498 : {
3499 :
3500 : // SUBROUTINE INFORMATION:
3501 : // AUTHOR Fred Buhl
3502 : // DATE WRITTEN Oct 1998
3503 : // MODIFIED na
3504 : // RE-ENGINEERED na
3505 :
3506 : // PURPOSE OF THIS SUBROUTINE
3507 : // Initialize the OAMixer data structure with input node data
3508 :
3509 : // METHODOLOGY EMPLOYED:
3510 :
3511 : // REFERENCES:
3512 :
3513 : // Using/Aliasing
3514 : using namespace DataLoopNode;
3515 :
3516 : // Locals
3517 : // SUBROUTINE ARGUMENT DEFINITIONS
3518 :
3519 : // SUBROUTINE PARAMETER DEFINITIONS:
3520 :
3521 : // INTERFACE BLOCK SPECIFICATIONS
3522 : // na
3523 :
3524 : // DERIVED TYPE DEFINITIONS
3525 : // na
3526 :
3527 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3528 : int RetNode;
3529 : int InletNode;
3530 : int RelNode;
3531 :
3532 43707297 : RetNode = state.dataMixedAir->OAMixer(OAMixerNum).RetNode;
3533 43707297 : InletNode = state.dataMixedAir->OAMixer(OAMixerNum).InletNode;
3534 43707297 : RelNode = state.dataMixedAir->OAMixer(OAMixerNum).RelNode;
3535 :
3536 43707297 : if (state.dataGlobal->BeginEnvrnFlag && FirstHVACIteration) {
3537 : }
3538 :
3539 43707297 : if (state.dataGlobal->BeginDayFlag) {
3540 : }
3541 :
3542 : if (FirstHVACIteration) {
3543 : }
3544 :
3545 : // Each iteration
3546 :
3547 : // Return air stream data
3548 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).RetTemp = state.dataLoopNodes->Node(RetNode).Temp;
3549 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).RetHumRat = state.dataLoopNodes->Node(RetNode).HumRat;
3550 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).RetEnthalpy = state.dataLoopNodes->Node(RetNode).Enthalpy;
3551 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).RetPressure = state.dataLoopNodes->Node(RetNode).Press;
3552 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).RetMassFlowRate = state.dataLoopNodes->Node(RetNode).MassFlowRate;
3553 : // Outside air stream data
3554 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).OATemp = state.dataLoopNodes->Node(InletNode).Temp;
3555 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).OAHumRat = state.dataLoopNodes->Node(InletNode).HumRat;
3556 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).OAEnthalpy = state.dataLoopNodes->Node(InletNode).Enthalpy;
3557 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).OAPressure = state.dataLoopNodes->Node(InletNode).Press;
3558 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).OAMassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
3559 : // Relief air data
3560 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).RelMassFlowRate = state.dataLoopNodes->Node(RelNode).MassFlowRate;
3561 43707297 : }
3562 :
3563 : // End of Initialization Section of the Module
3564 : //******************************************************************************
3565 :
3566 : // Beginning Calculation Section of the Module
3567 : //******************************************************************************
3568 :
3569 24821703 : void OAControllerProps::CalcOAController(EnergyPlusData &state, int const AirLoopNum, bool const FirstHVACIteration)
3570 : {
3571 :
3572 : // SUBROUTINE INFORMATION:
3573 : // AUTHOR Fred Buhl
3574 : // DATE WRITTEN Oct 1998
3575 : // MODIFIED Shirey/Raustad FSEC, June 2003
3576 : // Tianzhen Hong, Feb 2009 for new DCV
3577 : // Brent Griffith ,EMS override of OA rate
3578 : // Mangesh Basarkar, 06/2011: Modifying outside air calculation based on DCV flag
3579 : // Chandan Sharma, FSEC, 25Aug 2011 - Added ProportionalControl
3580 : // to enhance CO2 based DCV control
3581 : // Tianzhen Hong, March 2012, zone maximum OA fraction - a TRACE feature
3582 : // Tianzhen Hong, March 2012, multi-path VRP based on ASHRAE 62.1-2010
3583 : // RE-ENGINEERED na
3584 :
3585 : // PURPOSE OF THIS SUBROUTINE
3586 : // Determine the outside air flow
3587 :
3588 : // METHODOLOGY EMPLOYED:
3589 :
3590 : // REFERENCES:
3591 : // DOE-2.1E Supplement pages 3.97 - 3.100
3592 : // BLAST User Reference pages 183 - 186
3593 : // ASHRAE Standard 62.1-2010
3594 :
3595 : // Using/Aliasing
3596 : using Curve::CurveValue;
3597 :
3598 : // Locals
3599 : // SUBROUTINE ARGUMENT DEFINITIONS
3600 :
3601 : // SUBROUTINE PARAMETER DEFINITIONS:
3602 : static constexpr std::string_view RoutineName("CalcOAController: ");
3603 :
3604 : // INTERFACE BLOCK SPECIFICATIONS
3605 : // na
3606 :
3607 : // DERIVED TYPE DEFINITIONS
3608 : // na
3609 :
3610 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3611 : Real64 OutAirMinFrac; // Local variable used to calculate min OA fraction
3612 :
3613 : Real64 MechVentOutsideAirMinFrac; // fraction of OA specified by mechanical ventilation object
3614 : Real64 MechVentOAMassFlow; // outside air mass flow rate calculated by mechanical ventilation object [kg/s]
3615 : Real64 MinOASchedVal; // value of the minimum outside air schedule
3616 : Real64 OASignal; // Outside air flow rate fraction (0.0 to 1.0)
3617 : bool AirLoopCyclingFan; // Type of air loop fan (TRUE if Fan:OnOff)
3618 : bool HighHumidityOperationFlag; // TRUE if zone humidistat senses a high humidity condition
3619 : Real64 RecircTemp; // - return air temp, used for custom economizer control calculation
3620 : Real64 MixedAirTempAtMinOAFlow; // - mixed air temperature at min flow rate, used for custom economizer control calculation
3621 : Real64 RecircMassFlowRateAtMinOAFlow; // recirc air mass flow rate at min OA, used for custom economizer control calculation
3622 : Real64 ReliefMassFlowAtMinOA; // relief air mass flow rate at min OA, used for custom economizer control calculation
3623 24821703 : Real64 SysSA(0.0); // System supply air mass flow rate [kg/s]
3624 24821703 : MinOASchedVal = 1.0;
3625 :
3626 24821703 : if (AirLoopNum > 0) {
3627 24257718 : AirLoopCyclingFan = (state.dataAirLoop->AirLoopControlInfo(AirLoopNum).FanOpMode == CycFanCycCoil);
3628 : } else {
3629 563985 : AirLoopCyclingFan = false;
3630 : }
3631 :
3632 24821703 : this->OALimitingFactor = limitFactorNone; // oa controller limiting factor
3633 :
3634 : // Check for no flow
3635 24821703 : if (this->MixMassFlow <= SmallMassFlow) {
3636 :
3637 1809228 : this->OAMassFlow = 0.0; // outside air mass flow rate
3638 1809228 : this->RelMassFlow = 0.0; // relief air mass flow rate
3639 1809228 : this->MixMassFlow = 0.0; // mixed air mass flow rate
3640 1809228 : this->MinOAFracLimit = 0.0; // minimum OA fraction limit
3641 :
3642 1809228 : this->EconomizerStatus = 0; // economizer status for reporting
3643 1809228 : this->HeatRecoveryBypassStatus = 0; // HR bypass status for reporting
3644 1809228 : this->HRHeatingCoilActive = 0; // resets report variable
3645 1809228 : this->MixedAirTempAtMinOAFlow = state.dataLoopNodes->Node(this->RetNode).Temp; // track return T
3646 1809228 : this->HighHumCtrlStatus = 0; // high humdity control status for reporting
3647 1809228 : this->OAFractionRpt = 0.0; // actual OA fraction for reporting
3648 :
3649 1809228 : this->EconoActive = false; // DataAirLoop variable (OA Controllers)
3650 1809228 : this->HighHumCtrlActive = false; // DataAirLoop variable (OA Controllers)
3651 :
3652 : // also reset air loop data for use by other routines
3653 1809228 : if (AirLoopNum > 0) {
3654 1809126 : auto &curAirLoopControlInfo(state.dataAirLoop->AirLoopControlInfo(AirLoopNum));
3655 1809126 : auto &curAirLoopFlow(state.dataAirLoop->AirLoopFlow(AirLoopNum));
3656 :
3657 1809126 : curAirLoopControlInfo.EconoActive = false; // DataAirLoop variable (AirloopHVAC)
3658 1809126 : curAirLoopControlInfo.HeatRecoveryBypass = false; // DataAirLoop variable (AirloopHVAC)
3659 1809126 : curAirLoopControlInfo.HighHumCtrlActive = false; // DataAirLoop variable (AirloopHVAC)
3660 1809126 : curAirLoopControlInfo.ResimAirLoopFlag = false; // DataAirLoop variable (AirloopHVAC)
3661 1809126 : curAirLoopFlow.OAFrac = 0.0; // DataAirLoop variable (AirloopHVAC)
3662 1809126 : curAirLoopFlow.OAMinFrac = 0.0; // DataAirLoop variable (AirloopHVAC)
3663 1809126 : curAirLoopFlow.MinOutAir = 0.0;
3664 1809126 : curAirLoopFlow.OAFlow = 0.0;
3665 : }
3666 :
3667 3618456 : return;
3668 : }
3669 :
3670 : // set OutAirMinFrac
3671 23012475 : if (AirLoopNum > 0) {
3672 22448592 : auto &curAirLoopFlow(state.dataAirLoop->AirLoopFlow(AirLoopNum));
3673 :
3674 22448592 : if (curAirLoopFlow.DesSupply >= SmallAirVolFlow) {
3675 22448592 : OutAirMinFrac = this->MinOAMassFlowRate / curAirLoopFlow.DesSupply;
3676 : } else {
3677 0 : OutAirMinFrac = 0.0;
3678 : }
3679 : } else {
3680 563883 : if (this->MaxOA >= SmallAirVolFlow) {
3681 563883 : OutAirMinFrac = this->MinOA / this->MaxOA;
3682 : } else {
3683 0 : OutAirMinFrac = 0.0;
3684 : }
3685 : }
3686 23012475 : if (this->MinOASchPtr > 0) {
3687 21740148 : MinOASchedVal = GetCurrentScheduleValue(state, this->MinOASchPtr);
3688 21740148 : MinOASchedVal = min(max(MinOASchedVal, 0.0), 1.0);
3689 21740148 : OutAirMinFrac *= MinOASchedVal;
3690 21740148 : this->OALimitingFactor = limitFactorLimits;
3691 : }
3692 :
3693 : // Get mechanical ventilation
3694 23012475 : MechVentOAMassFlow = 0.0;
3695 23012475 : MechVentOutsideAirMinFrac = 0.0;
3696 23012475 : if (AirLoopNum > 0 && this->VentMechObjectNum != 0) {
3697 1211670 : auto &curAirLoopControlInfo(state.dataAirLoop->AirLoopControlInfo(AirLoopNum));
3698 1211670 : auto &curAirLoopFlow(state.dataAirLoop->AirLoopFlow(AirLoopNum));
3699 :
3700 : // Get system supply air flow rate
3701 1211670 : if (curAirLoopControlInfo.LoopFlowRateSet) {
3702 : // if flow rate has been specified by a manager, set it to the specified value
3703 : // DesSupply and SupFlow are mass flow rate in kg/s
3704 0 : SysSA = curAirLoopFlow.ReqSupplyFrac * curAirLoopFlow.DesSupply;
3705 : } else {
3706 1211670 : SysSA = curAirLoopFlow.SupFlow;
3707 : }
3708 :
3709 1211670 : state.dataMixedAir->VentilationMechanical(this->VentMechObjectNum).CalcMechVentController(state, SysSA, MechVentOAMassFlow);
3710 1211670 : MechVentOutsideAirMinFrac = MechVentOAMassFlow / curAirLoopFlow.DesSupply;
3711 1211670 : if (curAirLoopFlow.FanPLR > 0.0) {
3712 1210685 : MechVentOutsideAirMinFrac *= curAirLoopFlow.FanPLR;
3713 1210685 : MechVentOAMassFlow *= curAirLoopFlow.FanPLR;
3714 : }
3715 : }
3716 23012475 : this->MechVentOAMassFlowRequest = MechVentOAMassFlow;
3717 : //****** use greater of Mechanical Ventilation Outside Air fraction and OutAirMinFrac
3718 23012475 : if ((MechVentOutsideAirMinFrac > 0.0) && (OutAirMinFrac > MechVentOutsideAirMinFrac)) {
3719 0 : if (!state.dataGlobal->WarmupFlag) {
3720 0 : if (this->CountMechVentFrac == 0) {
3721 0 : ++this->CountMechVentFrac;
3722 0 : ShowWarningError(state,
3723 0 : std::string{RoutineName} +
3724 0 : "Minimum OA fraction > Mechanical Ventilation Controller request for Controller:OutdoorAir=" + this->Name +
3725 : ", Min OA fraction is used.");
3726 0 : ShowContinueError(state,
3727 : "This may be overriding desired ventilation controls. Check inputs for Minimum Outdoor Air Flow Rate, Minimum "
3728 : "Outdoor Air Schedule Name and Controller:MechanicalVentilation");
3729 0 : ShowContinueErrorTimeStamp(
3730 0 : state, format("Minimum OA fraction = {:.4R}, Mech Vent OA fraction = {:.4R}", OutAirMinFrac, MechVentOutsideAirMinFrac));
3731 : } else {
3732 0 : ShowRecurringWarningErrorAtEnd(state,
3733 0 : "Controller:OutdoorAir=\"" + this->Name +
3734 : "\": Min OA fraction > Mechanical ventilation OA fraction, continues...",
3735 : this->IndexMechVentFrac,
3736 : OutAirMinFrac,
3737 : OutAirMinFrac);
3738 : }
3739 : }
3740 : }
3741 23012475 : if (MechVentOutsideAirMinFrac > OutAirMinFrac) {
3742 830782 : OutAirMinFrac = MechVentOutsideAirMinFrac;
3743 830782 : this->OALimitingFactor = limitFactorDCV;
3744 : }
3745 :
3746 23012475 : OutAirMinFrac = min(max(OutAirMinFrac, 0.0), 1.0);
3747 :
3748 : // At this point, OutAirMinFrac is still based on AirLoopFlow.DesSupply
3749 23012475 : if (AirLoopNum > 0) {
3750 22448592 : auto &curAirLoopFlow(state.dataAirLoop->AirLoopFlow(AirLoopNum));
3751 :
3752 22448592 : curAirLoopFlow.MinOutAir = OutAirMinFrac * curAirLoopFlow.DesSupply;
3753 :
3754 : // calculate mixed air temp at min OA flow rate
3755 22448592 : ReliefMassFlowAtMinOA = max(curAirLoopFlow.MinOutAir - this->ExhMassFlow, 0.0);
3756 22448592 : RecircMassFlowRateAtMinOAFlow = max(state.dataLoopNodes->Node(this->RetNode).MassFlowRate - ReliefMassFlowAtMinOA, 0.0);
3757 22448592 : if ((RecircMassFlowRateAtMinOAFlow + curAirLoopFlow.MinOutAir) > 0.0) {
3758 22436986 : RecircTemp = state.dataLoopNodes->Node(this->RetNode).Temp;
3759 22436986 : MixedAirTempAtMinOAFlow =
3760 22436986 : (RecircMassFlowRateAtMinOAFlow * RecircTemp + curAirLoopFlow.MinOutAir * state.dataLoopNodes->Node(this->OANode).Temp) /
3761 22436986 : (RecircMassFlowRateAtMinOAFlow + curAirLoopFlow.MinOutAir);
3762 : } else {
3763 11606 : MixedAirTempAtMinOAFlow = state.dataLoopNodes->Node(this->RetNode).Temp;
3764 : }
3765 22448592 : this->MixedAirTempAtMinOAFlow = MixedAirTempAtMinOAFlow;
3766 : }
3767 :
3768 : // Economizer
3769 23012475 : this->CalcOAEconomizer(state, AirLoopNum, OutAirMinFrac, OASignal, HighHumidityOperationFlag, FirstHVACIteration);
3770 :
3771 23012475 : this->OAMassFlow = OASignal * this->MixMassFlow;
3772 :
3773 : // Do not allow OA to be below Ventilation:Mechanical flow rate or above mixed mass flow rate
3774 23012475 : if (AirLoopNum > 0 && VentMechObjectNum != 0) {
3775 1211670 : if (MechVentOAMassFlow > this->OAMassFlow) {
3776 564704 : this->OAMassFlow = min(MechVentOAMassFlow, this->MixMassFlow);
3777 : }
3778 : }
3779 :
3780 : // Do not allow OA to be below Exh for controller:outside air
3781 23012475 : if (this->ControllerType_Num == MixedAirControllerType::ControllerOutsideAir) {
3782 22448592 : if (this->ExhMassFlow > this->OAMassFlow) {
3783 504541 : this->OAMassFlow = this->ExhMassFlow;
3784 504541 : this->OALimitingFactor = limitFactorExhaust;
3785 : }
3786 : }
3787 :
3788 : // if fixed minimum, don't let go below min OA
3789 23012475 : if (this->FixedMin) {
3790 : // cycling fans allow "average" min OA to be below minimum
3791 22095811 : if (!AirLoopCyclingFan) {
3792 19862215 : Real64 minOASchedMassFlowRate = this->MinOAMassFlowRate * MinOASchedVal;
3793 19862215 : if (minOASchedMassFlowRate > this->OAMassFlow) {
3794 7313053 : this->OAMassFlow = minOASchedMassFlowRate;
3795 7313053 : this->OALimitingFactor = limitFactorLimits;
3796 : }
3797 : }
3798 : }
3799 :
3800 : // Apply Minimum Fraction of Outdoor Air Schedule
3801 23012475 : if (this->MinOAflowSchPtr > 0) {
3802 1323839 : Real64 MinOAflowfracVal = GetCurrentScheduleValue(state, this->MinOAflowSchPtr);
3803 1323839 : MinOAflowfracVal = min(max(MinOAflowfracVal, 0.0), 1.0);
3804 1323839 : OutAirMinFrac = max(MinOAflowfracVal, OutAirMinFrac);
3805 1323839 : Real64 minOAFracMassFlowRate = this->MixMassFlow * MinOAflowfracVal;
3806 1323839 : if (minOAFracMassFlowRate > this->OAMassFlow) {
3807 740224 : this->OAMassFlow = minOAFracMassFlowRate;
3808 740224 : this->OALimitingFactor = limitFactorLimits;
3809 : }
3810 : }
3811 :
3812 : // Apply Maximum Fraction of Outdoor Air Schedule
3813 23012475 : Real64 currentMaxOAMassFlowRate = this->MaxOAMassFlowRate;
3814 23012475 : if (this->MaxOAflowSchPtr > 0) {
3815 1130563 : Real64 MaxOAflowfracVal = GetCurrentScheduleValue(state, this->MaxOAflowSchPtr);
3816 1130563 : MaxOAflowfracVal = min(max(MaxOAflowfracVal, 0.0), 1.0);
3817 1130563 : currentMaxOAMassFlowRate = min(this->MaxOAMassFlowRate, this->MixMassFlow * MaxOAflowfracVal);
3818 1130563 : OutAirMinFrac = min(MaxOAflowfracVal, OutAirMinFrac);
3819 1130563 : if (currentMaxOAMassFlowRate < this->OAMassFlow) {
3820 31059 : this->OAMassFlow = currentMaxOAMassFlowRate;
3821 31059 : this->OALimitingFactor = limitFactorLimits;
3822 : }
3823 : }
3824 :
3825 : // Don't let the OA flow be > than the max OA limit. OA for high humidity control is allowed to be greater than max OA.
3826 : // Night Ventilation has priority and may override an OASignal > 1 high humidity condition with OASignal = 1
3827 23012475 : if (HighHumidityOperationFlag) {
3828 394 : Real64 maxOAMassFlow = this->MaxOAMassFlowRate * max(1.0, OASignal);
3829 394 : if (maxOAMassFlow < this->OAMassFlow) {
3830 0 : this->OAMassFlow = maxOAMassFlow;
3831 0 : this->OALimitingFactor = limitFactorLimits;
3832 : }
3833 : } else {
3834 23012081 : if (this->MaxOAMassFlowRate < this->OAMassFlow) {
3835 116276 : this->OAMassFlow = this->MaxOAMassFlowRate;
3836 116276 : this->OALimitingFactor = limitFactorLimits;
3837 : }
3838 : }
3839 :
3840 23012475 : if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && (this->ManageDemand) && (this->OAMassFlow > this->DemandLimitFlowRate)) {
3841 3973 : this->OAMassFlow = this->DemandLimitFlowRate;
3842 3973 : this->OALimitingFactor = limitFactorDemandLimit;
3843 : }
3844 23012475 : if (this->EMSOverrideOARate) {
3845 0 : this->OAMassFlow = this->EMSOARateValue;
3846 0 : this->OALimitingFactor = limitFactorEMS;
3847 : }
3848 :
3849 : // Don't let OA flow be > mixed air flow.
3850 : // Seems if RAB (return air bypass) that this should be don't let OA flow be > design supply flow but that causes other issues
3851 23012475 : if (this->MixMassFlow < this->OAMassFlow) {
3852 233157 : this->OAMassFlow = this->MixMassFlow;
3853 233157 : this->OALimitingFactor = limitFactorMixedAir;
3854 : }
3855 :
3856 : // save the min outside air flow fraction and max outside air mass flow rate
3857 23012475 : if (AirLoopNum > 0) {
3858 22448592 : auto &curAirLoopControlInfo(state.dataAirLoop->AirLoopControlInfo(AirLoopNum));
3859 22448592 : auto &curAirLoopFlow(state.dataAirLoop->AirLoopFlow(AirLoopNum));
3860 :
3861 22448592 : curAirLoopFlow.OAMinFrac = OutAirMinFrac;
3862 22448592 : if (this->FixedMin) {
3863 22095811 : curAirLoopFlow.MinOutAir = min(OutAirMinFrac * curAirLoopFlow.DesSupply, this->MixMassFlow);
3864 : } else {
3865 352781 : curAirLoopFlow.MinOutAir = OutAirMinFrac * this->MixMassFlow;
3866 : }
3867 22448592 : if (this->MixMassFlow > 0.0) {
3868 22448592 : curAirLoopFlow.OAFrac = this->OAMassFlow / this->MixMassFlow;
3869 22448592 : curAirLoopFlow.OAFlow = this->OAMassFlow;
3870 : } else {
3871 0 : curAirLoopFlow.OAFrac = 0.0;
3872 0 : curAirLoopFlow.OAFlow = 0.0;
3873 : }
3874 22448592 : this->MinOAFracLimit = OutAirMinFrac;
3875 22448592 : if (HighHumidityOperationFlag && OASignal > 1.0) {
3876 62 : curAirLoopFlow.MaxOutAir = this->MaxOAMassFlowRate * OASignal;
3877 : } else {
3878 22448530 : curAirLoopFlow.MaxOutAir = currentMaxOAMassFlowRate;
3879 : }
3880 :
3881 : // MJW - Not sure if this is necessary but keeping it for now
3882 22448592 : if (curAirLoopControlInfo.HeatingActiveFlag && curAirLoopControlInfo.EconomizerFlowLocked) {
3883 : // The airloop needs to be simulated again so that the heating coil & HX can be resimulated
3884 970490 : if (curAirLoopControlInfo.HeatRecoveryResimFlag && curAirLoopControlInfo.OASysComponentsSimulated) {
3885 43098 : curAirLoopControlInfo.ResimAirLoopFlag = true;
3886 43098 : curAirLoopControlInfo.HeatRecoveryResimFlag = false;
3887 43098 : curAirLoopControlInfo.HeatRecoveryResimFlag2 = true;
3888 : // on the first iteration, air loop heating coils have not be simulated so HeatingCoilActive=FALSE
3889 : // on the second iteration, the heating coils could have been on, but logic tests here could deactivate heating coil
3890 : // reset heating coil active status and HX since logic tests may turn off heating coil
3891 : // the ResimAirLoopFlag will force another iteration and things should line up on subsequent iterations
3892 43098 : curAirLoopControlInfo.HeatingActiveFlag = false;
3893 43098 : this->HRHeatingCoilActive = 0;
3894 43098 : curAirLoopControlInfo.HeatRecoveryBypass = true;
3895 43098 : this->HeatRecoveryBypassStatus = 1;
3896 442147 : } else if (curAirLoopControlInfo.HeatRecoveryResimFlag2) {
3897 43084 : curAirLoopControlInfo.ResimAirLoopFlag = true;
3898 43084 : curAirLoopControlInfo.HeatRecoveryResimFlag2 = false;
3899 : } else {
3900 399063 : curAirLoopControlInfo.ResimAirLoopFlag = false;
3901 : }
3902 21963347 : } else if (curAirLoopControlInfo.HeatingActiveFlag) {
3903 2748734 : this->HRHeatingCoilActive = 1;
3904 : } else {
3905 19214613 : this->HRHeatingCoilActive = 0;
3906 : }
3907 :
3908 : } // if (AirLoopNum > 0)
3909 :
3910 : // Set the relief air flow rate (must be done last to account for changes in OAMassFlow
3911 23012475 : this->RelMassFlow = max(this->OAMassFlow - this->ExhMassFlow, 0.0);
3912 :
3913 : // Save OA fraction for reporting
3914 23012475 : if (this->MixMassFlow > 0) {
3915 23012475 : this->OAFractionRpt = this->OAMassFlow / this->MixMassFlow;
3916 : } else {
3917 0 : if (this->OAMassFlow > 0) {
3918 0 : this->OAFractionRpt = OASignal;
3919 : } else {
3920 0 : this->OAFractionRpt = 0.0;
3921 : }
3922 : }
3923 23012475 : this->RelTemp = this->RetTemp;
3924 23012475 : this->RelEnth = this->RetEnth;
3925 23012475 : this->RelSensiLossRate =
3926 23012475 : this->RelMassFlow * Psychrometrics::PsyCpAirFnW(state.dataEnvrn->OutHumRat) * (this->RelTemp - state.dataEnvrn->OutDryBulbTemp);
3927 23012475 : this->RelTotalLossRate = this->RelMassFlow * (this->RelEnth - state.dataEnvrn->OutEnthalpy);
3928 23012475 : this->RelLatentLossRate = this->RelTotalLossRate - this->RelSensiLossRate;
3929 : }
3930 :
3931 1211670 : void VentilationMechanicalProps::CalcMechVentController(
3932 : EnergyPlusData &state,
3933 : Real64 &SysSA, // System supply air mass flow rate [kg/s]
3934 : Real64 &MechVentOAMassFlow // outside air mass flow rate calculated by mechanical ventilation object [kg/s]
3935 : )
3936 : {
3937 : using Psychrometrics::PsyRhoAirFnPbTdbW;
3938 :
3939 : static constexpr std::string_view RoutineName("CalcMechVentController: ");
3940 1211670 : static std::string const &CurrentModuleObject(CurrentModuleObjects(static_cast<int>(CMO::MechVentilation)));
3941 :
3942 : // new local variables for DCV
3943 1211670 : std::array<Real64, static_cast<int>(DataSizing::OAFlowCalcMethod::Num)> ZoneOACalc{
3944 : 0.0}; // Zone OA flow rate based on each calculation method [m3/s]
3945 : Real64 ZoneOABZ; // Zone breathing-zone OA flow rate [m3/s]
3946 : Real64 ZoneOAMin; // Minimum Zone OA flow rate when the zone is unoccupied (i.e. ZoneOAPeople = 0)
3947 : // used for "ProportionalControl" System outdoor air method
3948 : Real64 ZoneOAMax; // Maximum Zone OA flow rate (ZoneOAPeople + ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)])
3949 : // used for "ProportionalControl" System outdoor air method
3950 : Real64 ZoneOA; // Zone OA flow rate [m3/s]
3951 : Real64 ZoneOAFrac; // Zone OA fraction (as a fraction of actual supply air flow rate)
3952 : Real64 ZoneEz; // Zone air distribution effectiveness
3953 : Real64 ZoneSA; // Zone supply air flow rate
3954 : Real64 ZonePA; // Zone primary air flow rate
3955 : Real64 SysOAuc; // System uncorrected OA flow rate
3956 : Real64 SysOA; // System supply OA volume flow rate [m3/s]
3957 : Real64 SysOAMassFlow; // System supply OA mass flow rate [kg/s]
3958 : Real64 SysEv; // System ventilation efficiency
3959 : Real64 NodeTemp; // node temperature
3960 : Real64 NodeHumRat; // node humidity ratio
3961 : Real64 MassFlowRate; // Temporary variable
3962 : Real64 ZoneLoad; // Zone loads
3963 2423340 : std::string ZoneName; // Zone name
3964 : int OAIndex; // index to design specification outdoor air objects
3965 : int PeopleNum;
3966 : Real64 ZoneMaxCO2; // Breathing-zone CO2 concentartion
3967 : Real64 ZoneMinCO2; // Minimum CO2 concentration in zone
3968 : Real64 ZoneContamControllerSched; // Schedule value for ZoneControl:ContaminantController
3969 : Real64 CO2PeopleGeneration; // CO2 generation from people at design level
3970 :
3971 : int PriNode; // primary node of zone terminal unit
3972 : int InletNode; // outlet node of zone terminal unit
3973 :
3974 1211670 : ZoneMaxCO2 = 0.0;
3975 1211670 : ZoneMinCO2 = 0.0;
3976 1211670 : ZoneOAMin = 0.0;
3977 1211670 : ZoneOAMax = 0.0;
3978 1211670 : ZoneContamControllerSched = 0.0;
3979 1211670 : MechVentOAMassFlow = 0.0;
3980 :
3981 : // Apply mechanical ventilation only when it is available/allowed
3982 1211670 : if (GetCurrentScheduleValue(state, this->SchPtr) > 0) {
3983 937404 : if (this->SystemOAMethod == DataSizing::SysOAMethod::IAQP) {
3984 : // IAQP for CO2 control
3985 6176 : SysOAMassFlow = 0.0;
3986 24704 : for (int ZoneIndex = 1; ZoneIndex <= this->NumofVentMechZones; ++ZoneIndex) {
3987 18528 : int ZoneNum = this->VentMechZone(ZoneIndex);
3988 37056 : SysOAMassFlow += state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP *
3989 18528 : GetCurrentScheduleValue(state, this->ZoneOASchPtr(ZoneIndex));
3990 : }
3991 6176 : MechVentOAMassFlow = SysOAMassFlow;
3992 931228 : } else if (this->SystemOAMethod == DataSizing::SysOAMethod::IAQPGC) {
3993 : // IAQP for generic contaminant control
3994 7228 : SysOAMassFlow = 0.0;
3995 28912 : for (int ZoneIndex = 1; ZoneIndex <= this->NumofVentMechZones; ++ZoneIndex) {
3996 21684 : int ZoneNum = this->VentMechZone(ZoneIndex);
3997 43368 : SysOAMassFlow += state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToGCSP *
3998 21684 : GetCurrentScheduleValue(state, this->ZoneOASchPtr(ZoneIndex));
3999 : }
4000 7228 : MechVentOAMassFlow = SysOAMassFlow;
4001 924000 : } else if (this->SystemOAMethod == DataSizing::SysOAMethod::IAQPCOM) {
4002 : // IAQP for both CO2 and generic contaminant control
4003 0 : SysOAMassFlow = 0.0;
4004 0 : for (int ZoneIndex = 1; ZoneIndex <= this->NumofVentMechZones; ++ZoneIndex) {
4005 0 : int ZoneNum = this->VentMechZone(ZoneIndex);
4006 0 : SysOAMassFlow += state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP *
4007 0 : GetCurrentScheduleValue(state, this->ZoneOASchPtr(ZoneIndex));
4008 : }
4009 0 : MechVentOAMassFlow = SysOAMassFlow;
4010 0 : SysOAMassFlow = 0.0;
4011 0 : for (int ZoneIndex = 1; ZoneIndex <= this->NumofVentMechZones; ++ZoneIndex) {
4012 0 : int ZoneNum = this->VentMechZone(ZoneIndex);
4013 0 : SysOAMassFlow += state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToGCSP *
4014 0 : GetCurrentScheduleValue(state, this->ZoneOASchPtr(ZoneIndex));
4015 : }
4016 0 : MechVentOAMassFlow = max(SysOAMassFlow, MechVentOAMassFlow);
4017 : } else {
4018 : // for system OA methods: Zone_Sum, VRP, CO2 methods
4019 : // new code for DCV method complying with the VRP defined in ASHRAE Standard 62.1-2010
4020 :
4021 : // Loop through each zone first to calc uncorrected system OA flow rate
4022 924000 : SysOAuc = 0.0;
4023 924000 : SysOA = 0.0;
4024 7691481 : for (int ZoneIndex = 1; ZoneIndex <= this->NumofVentMechZones; ++ZoneIndex) {
4025 6767481 : int ZoneNum = this->VentMechZone(ZoneIndex);
4026 6767481 : auto const &curZone(state.dataHeatBal->Zone(ZoneNum));
4027 6767481 : Real64 curZoneOASchValue = GetCurrentScheduleValue(state, this->ZoneOASchPtr(ZoneIndex));
4028 :
4029 : // Calc the zone OA flow rate based on the people component
4030 : // ZoneIntGain(ZoneNum)%NOFOCC is the number of occupants of a zone at each time step, already counting the occupant schedule
4031 : // Checking DCV flag before calculating zone OA per person
4032 6767481 : if (this->DCVFlag && this->SystemOAMethod != DataSizing::SysOAMethod::ProportionalControlDesOcc) {
4033 16905264 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] = state.dataHeatBal->ZoneIntGain(ZoneNum).NOFOCC *
4034 16905264 : curZone.Multiplier * curZone.ListMultiplier *
4035 11270176 : this->ZoneOAPeopleRate(ZoneIndex) * curZoneOASchValue;
4036 : } else {
4037 1132393 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] =
4038 1132393 : curZone.TotOccupants * curZone.Multiplier * curZone.ListMultiplier * this->ZoneOAPeopleRate(ZoneIndex) * curZoneOASchValue;
4039 : }
4040 :
4041 : // Calc the zone OA flow rate based on the floor area component
4042 6767481 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] =
4043 6767481 : curZone.FloorArea * curZone.Multiplier * curZone.ListMultiplier * this->ZoneOAAreaRate(ZoneIndex) * curZoneOASchValue;
4044 6767481 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)] =
4045 6767481 : curZone.Multiplier * curZone.ListMultiplier * this->ZoneOAFlowRate(ZoneIndex) * curZoneOASchValue;
4046 6767481 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)] =
4047 6767481 : curZone.Multiplier * curZone.ListMultiplier * (this->ZoneOAACHRate(ZoneIndex) * curZone.Volume) * curZoneOASchValue / 3600.0;
4048 6767481 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::Sum)] =
4049 13534962 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] +
4050 13534962 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] +
4051 13534962 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)] +
4052 6767481 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)];
4053 6767481 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::Max)] =
4054 20302443 : max(ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)],
4055 6767481 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)],
4056 6767481 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)],
4057 6767481 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)]);
4058 :
4059 : // Calc the breathing-zone OA flow rate
4060 6767481 : OAIndex = this->ZoneDesignSpecOAObjIndex(ZoneIndex);
4061 6767481 : if (OAIndex > 0) {
4062 6767481 : ZoneOABZ = ZoneOACalc[static_cast<int>(state.dataSize->OARequirements(OAIndex).OAFlowMethod)];
4063 : } else {
4064 0 : ZoneOABZ = ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)];
4065 : }
4066 :
4067 6767481 : if (this->SystemOAMethod == DataSizing::SysOAMethod::ZoneSum) {
4068 : // Sum the zone OA flow rates and done
4069 605311 : SysOA += ZoneOABZ;
4070 : } else {
4071 : // Calc the uncorrected system OA flow rate - VRP and ProportionalControl
4072 6162170 : SysOAuc += ZoneOABZ;
4073 : }
4074 : }
4075 :
4076 : // get system supply air flow rate
4077 1743634 : if (this->SystemOAMethod == DataSizing::SysOAMethod::VRP || this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc ||
4078 1639268 : this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc ||
4079 1633080 : this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate ||
4080 813446 : this->SystemOAMethod == DataSizing::SysOAMethod::VRPL) {
4081 :
4082 : // System supply air flow rate is always greater than or equal the system outdoor air flow rate
4083 780873 : if ((SysSA > 0.0) && (SysSA < (SysOAuc * state.dataEnvrn->StdRhoAir))) SysSA = SysOAuc * state.dataEnvrn->StdRhoAir;
4084 :
4085 : // calc Xs - average outdoor air fraction
4086 780873 : if (SysSA > 0.0) {
4087 770578 : Xs = (SysOAuc * state.dataEnvrn->StdRhoAir) / SysSA;
4088 : } else {
4089 10295 : Xs = 0.0;
4090 : }
4091 :
4092 : // Loop through each zone again
4093 780873 : SysEv = 2.0; // starting with a big fraction
4094 6943043 : for (int ZoneIndex = 1; ZoneIndex <= this->NumofVentMechZones; ++ZoneIndex) {
4095 6162170 : int ZoneNum = this->VentMechZone(ZoneIndex);
4096 6162170 : int ZoneEquipConfigNum = ZoneNum; // correspondence - 1:1 of ZoneEquipConfig to Zone index
4097 6162170 : ZoneEz = 0.0;
4098 :
4099 : // Assign references
4100 6162170 : auto &curZone(state.dataHeatBal->Zone(ZoneNum));
4101 6162170 : auto &curZoneEquipConfig(state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigNum));
4102 6162170 : auto &curZoneSysEnergyDemand(state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneEquipConfigNum));
4103 6162170 : ZoneName = curZone.Name;
4104 6162170 : Real64 curZoneOASchValue = GetCurrentScheduleValue(state, this->ZoneOASchPtr(ZoneIndex));
4105 :
4106 : // Calc the zone OA flow rate based on the people component
4107 : // ZoneIntGain(ZoneNum)%NOFOCC is the number of occupants of a zone at each time step, already counting the occupant schedule
4108 : // Checking DCV flag before calculating zone OA per person
4109 6162170 : if (this->DCVFlag && this->SystemOAMethod != DataSizing::SysOAMethod::ProportionalControlDesOcc) {
4110 15719226 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] = state.dataHeatBal->ZoneIntGain(ZoneNum).NOFOCC *
4111 15719226 : curZone.Multiplier * curZone.ListMultiplier *
4112 10479484 : this->ZoneOAPeopleRate(ZoneIndex) * curZoneOASchValue;
4113 : } else {
4114 2767284 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] = curZone.TotOccupants * curZone.Multiplier *
4115 1844856 : curZone.ListMultiplier *
4116 1844856 : this->ZoneOAPeopleRate(ZoneIndex) * curZoneOASchValue;
4117 922428 : CO2PeopleGeneration = 0.0;
4118 922428 : if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc) {
4119 : // Accumulate CO2 generation from people at design occupancy and current activity level
4120 0 : for (PeopleNum = 1; PeopleNum <= state.dataHeatBal->TotPeople; ++PeopleNum) {
4121 0 : if (state.dataHeatBal->People(PeopleNum).ZonePtr != ZoneNum) continue;
4122 0 : CO2PeopleGeneration += state.dataHeatBal->People(PeopleNum).NumberOfPeople *
4123 0 : state.dataHeatBal->People(PeopleNum).CO2RateFactor *
4124 0 : GetCurrentScheduleValue(state, state.dataHeatBal->People(PeopleNum).ActivityLevelPtr);
4125 : }
4126 : }
4127 : }
4128 :
4129 : // Calc the zone OA flow rate based on the floor area component
4130 6162170 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] =
4131 6162170 : curZone.FloorArea * curZone.Multiplier * curZone.ListMultiplier * this->ZoneOAAreaRate(ZoneIndex) * curZoneOASchValue;
4132 6162170 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)] =
4133 6162170 : curZone.Multiplier * curZone.ListMultiplier * this->ZoneOAFlowRate(ZoneIndex) * curZoneOASchValue;
4134 6162170 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)] =
4135 6162170 : curZone.Multiplier * curZone.ListMultiplier * (this->ZoneOAACHRate(ZoneIndex) * curZone.Volume) * curZoneOASchValue / 3600.0;
4136 :
4137 : // Calc the breathing-zone OA flow rate
4138 6162170 : OAIndex = this->ZoneDesignSpecOAObjIndex(ZoneIndex);
4139 6162170 : if (OAIndex > 0) {
4140 6162170 : std::array<Real64, static_cast<int>(OAFlowCalcMethod::Num)> BZOAFlowRate{
4141 6162170 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)],
4142 6162170 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)],
4143 6162170 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)],
4144 6162170 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)],
4145 12324340 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] +
4146 12324340 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] +
4147 12324340 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)] +
4148 6162170 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)],
4149 18486510 : max(ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)],
4150 6162170 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)],
4151 6162170 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)],
4152 6162170 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)]),
4153 : 0.0,
4154 : 0.0,
4155 36973020 : 0.0};
4156 :
4157 6162170 : ZoneOABZ = BZOAFlowRate[static_cast<int>(state.dataSize->OARequirements(OAIndex).OAFlowMethod)];
4158 : }
4159 :
4160 : // use the ventilation rate procedure in ASHRAE Standard 62.1-2007
4161 : // Calc the zone supplied OA flow rate counting the zone air distribution effectiveness
4162 : // First check whether the zone air distribution effectiveness schedule exists, if yes uses it;
4163 : // otherwise uses the inputs of zone distribution effectiveness in cooling mode or heating mode
4164 6162170 : int ADEffSchPtr = this->ZoneADEffSchPtr(ZoneIndex);
4165 6162170 : if (ADEffSchPtr > 0) {
4166 : // Get schedule value for the zone air distribution effectiveness
4167 18564 : ZoneEz = GetCurrentScheduleValue(state, ADEffSchPtr);
4168 : } else {
4169 6143606 : ZoneLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).TotalOutputRequired;
4170 :
4171 : // Zone in cooling mode
4172 6143606 : if (ZoneLoad < 0.0) ZoneEz = this->ZoneADEffCooling(ZoneIndex);
4173 :
4174 : // Zone in heating mode
4175 6143606 : if (ZoneLoad > 0.0) ZoneEz = this->ZoneADEffHeating(ZoneIndex);
4176 : }
4177 6162170 : if (ZoneEz <= 0.0) {
4178 : // Enforce defaults
4179 550500 : ZoneEz = 1.0;
4180 : }
4181 :
4182 : // Calc zone supply OA flow rate
4183 6162170 : if (this->SystemOAMethod == DataSizing::SysOAMethod::VRP || this->SystemOAMethod == DataSizing::SysOAMethod::VRPL) {
4184 : // the VRP case
4185 6125042 : ZoneOA = ZoneOABZ / ZoneEz;
4186 :
4187 55692 : } else if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc ||
4188 37128 : this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc ||
4189 18564 : this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate) {
4190 : // Check whether "Carbon Dioxide Control Availability Schedule" for ZoneControl:ContaminantController is specified
4191 37128 : if (curZone.ZoneContamControllerSchedIndex > 0.0) {
4192 : // Check the availability schedule value for ZoneControl:ContaminantController
4193 12376 : ZoneContamControllerSched = GetCurrentScheduleValue(state, curZone.ZoneContamControllerSchedIndex);
4194 12376 : if (ZoneContamControllerSched > 0.0) {
4195 12376 : ZoneOAMin = ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] / ZoneEz;
4196 37128 : ZoneOAMax = (ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] +
4197 24752 : ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)]) /
4198 : ZoneEz;
4199 12376 : if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate) {
4200 6188 : ZoneOAMax = ZoneOABZ / ZoneEz;
4201 6188 : if (this->OAPropCtlMinRateSchPtr(ZoneIndex) > 0) {
4202 0 : ZoneOAMin = ZoneOAMax * GetCurrentScheduleValue(state, this->OAPropCtlMinRateSchPtr(ZoneIndex));
4203 : } else {
4204 6188 : ZoneOAMin = ZoneOAMax;
4205 : }
4206 6188 : if (ZoneOAMax < ZoneOAMin) {
4207 0 : ZoneOAMin = ZoneOAMax;
4208 0 : ++this->OAMaxMinLimitErrorCount;
4209 0 : if (this->OAMaxMinLimitErrorCount < 2) {
4210 0 : ShowSevereError(state, std::string{RoutineName} + CurrentModuleObject + " = \"" + this->Name + "\".");
4211 0 : ShowContinueError(
4212 : state,
4213 0 : format("For System Outdoor Air Method = ProportionalControlBasedOnDesignOARate, maximum zone "
4214 : "outdoor air rate ({:.4R}), is not greater than minimum zone outdoor air rate ({:.4R}).",
4215 : ZoneOAMax,
4216 0 : ZoneOAMin));
4217 0 : ShowContinueError(state,
4218 : " The minimum zone outdoor air rate is set to the maximum zone outdoor air rate. "
4219 : "Simulation continues...");
4220 0 : ShowContinueErrorTimeStamp(state, "");
4221 : } else {
4222 0 : ShowRecurringWarningErrorAtEnd(
4223 : state,
4224 0 : CurrentModuleObject + " = \"" + this->Name +
4225 : "\", For System Outdoor Air Method = ProportionalControlBasedOnDesignOARate, maximum zone "
4226 : "outdoor air rate is not greater than minimum zone outdoor air rate. Error continues...",
4227 : this->OAMaxMinLimitErrorIndex);
4228 : }
4229 : }
4230 : }
4231 :
4232 12376 : if (ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] > 0.0) {
4233 5824 : if (state.dataContaminantBalance->ZoneCO2GainFromPeople(ZoneNum) > 0.0) {
4234 5824 : if (curZone.ZoneMinCO2SchedIndex > 0.0) {
4235 : // Take the schedule value of "Minimum Carbon Dioxide Concentration Schedule Name"
4236 : // in the ZoneControl:ContaminantController
4237 2912 : ZoneMinCO2 = GetCurrentScheduleValue(state, curZone.ZoneMinCO2SchedIndex);
4238 : } else {
4239 2912 : ZoneMinCO2 = state.dataContaminantBalance->OutdoorCO2;
4240 : }
4241 :
4242 : // Calculate zone maximum target CO2 concentration in PPM
4243 5824 : if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc) {
4244 0 : ZoneMaxCO2 = state.dataContaminantBalance->OutdoorCO2 +
4245 0 : (CO2PeopleGeneration * curZone.Multiplier * curZone.ListMultiplier * 1.0e6) / ZoneOAMax;
4246 5824 : } else if (curZone.ZoneMaxCO2SchedIndex > 0.0) {
4247 2912 : ZoneMaxCO2 = GetCurrentScheduleValue(state, curZone.ZoneMaxCO2SchedIndex);
4248 : } else {
4249 5824 : ZoneMaxCO2 = state.dataContaminantBalance->OutdoorCO2 +
4250 5824 : (state.dataContaminantBalance->ZoneCO2GainFromPeople(ZoneNum) * curZone.Multiplier *
4251 5824 : curZone.ListMultiplier * 1.0e6) /
4252 : ZoneOAMax;
4253 : }
4254 :
4255 5824 : if (ZoneMaxCO2 <= ZoneMinCO2) {
4256 0 : ++this->CO2MaxMinLimitErrorCount;
4257 0 : if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc) {
4258 0 : if (this->CO2MaxMinLimitErrorCount < 2) {
4259 0 : ShowSevereError(state,
4260 0 : std::string{RoutineName} + CurrentModuleObject + " = \"" + this->Name + "\".");
4261 0 : ShowContinueError(
4262 : state,
4263 0 : format("For System Outdoor Air Method = ProportionalControlBasedOnOccupancySchedule, "
4264 : "maximum target CO2 concentration ({:.2R}), is not greater than minimum target "
4265 : "CO2 concentration ({:.2R}).",
4266 : ZoneMaxCO2,
4267 0 : ZoneMinCO2));
4268 0 : ShowContinueError(state,
4269 : "\"ProportionalControlBasedOnOccupancySchedule\" will not be modeled. "
4270 : "Default \"Standard62.1VentilationRateProcedure\" will be modeled. Simulation "
4271 : "continues...");
4272 0 : ShowContinueErrorTimeStamp(state, "");
4273 : } else {
4274 0 : ShowRecurringWarningErrorAtEnd(state,
4275 0 : CurrentModuleObject + " = \"" + this->Name +
4276 : "\", For System Outdoor Air Method = "
4277 : "ProportionalControlBasedOnOccupancySchedule, maximum "
4278 : "target CO2 concentration is not greater than minimum "
4279 : "target CO2 concentration. Error continues...",
4280 : this->CO2MaxMinLimitErrorIndex);
4281 : }
4282 : }
4283 0 : if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc) {
4284 0 : if (this->CO2MaxMinLimitErrorCount < 2) {
4285 0 : ShowSevereError(state,
4286 0 : std::string{RoutineName} + CurrentModuleObject + " = \"" + this->Name + "\".");
4287 0 : ShowContinueError(
4288 : state,
4289 0 : format("For System Outdoor Air Method = ProportionalControlBasedOnDesignOccupancy, "
4290 : "maximum target CO2 concentration ({:.2R}), is not greater than minimum target "
4291 : "CO2 concentration ({:.2R}).",
4292 : ZoneMaxCO2,
4293 0 : ZoneMinCO2));
4294 0 : ShowContinueError(state,
4295 : "\"ProportionalControlBasedOnDesignOccupancy\" will not be modeled. "
4296 : "Default \"Standard62.1VentilationRateProcedure\" will be modeled. Simulation "
4297 : "continues...");
4298 0 : ShowContinueErrorTimeStamp(state, "");
4299 : } else {
4300 0 : ShowRecurringWarningErrorAtEnd(state,
4301 0 : CurrentModuleObject + " = \"" + this->Name +
4302 : "\", For System Outdoor Air Method = "
4303 : "ProportionalControlBasedOnDesignOccupancy, maximum "
4304 : "target CO2 concentration is not greater than minimum "
4305 : "target CO2 concentration. Error continues...",
4306 : this->CO2MaxMinLimitErrorIndex);
4307 : }
4308 : }
4309 0 : if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate) {
4310 0 : if (this->CO2MaxMinLimitErrorCount < 2) {
4311 0 : ShowSevereError(state,
4312 0 : std::string{RoutineName} + CurrentModuleObject + " = \"" + this->Name + "\".");
4313 0 : ShowContinueError(
4314 : state,
4315 0 : format("For System Outdoor Air Method = ProportionalControlBasedOnDesignOARate, maximum "
4316 : "target CO2 concentration ({:.2R}), is not greater than minimum target CO2 "
4317 : "concentration ({:.2R}).",
4318 : ZoneMaxCO2,
4319 0 : ZoneMinCO2));
4320 0 : ShowContinueError(
4321 : state,
4322 : "\"ProportionalControlBasedOnDesignOARate\" will not be modeled. Default "
4323 : "\"Standard62.1VentilationRateProcedure\" will be modeled. Simulation continues...");
4324 0 : ShowContinueErrorTimeStamp(state, "");
4325 : } else {
4326 0 : ShowRecurringWarningErrorAtEnd(state,
4327 0 : CurrentModuleObject + " = \"" + this->Name +
4328 : "\", For System Outdoor Air Method = "
4329 : "ProportionalControlBasedOnDesignOARate, maximum target "
4330 : "CO2 concentration is not greater than minimum target CO2 "
4331 : "concentration. Error continues...",
4332 : this->CO2MaxMinLimitErrorIndex);
4333 : }
4334 : }
4335 :
4336 0 : ZoneOA = ZoneOABZ / ZoneEz;
4337 : } else {
4338 :
4339 5824 : if (state.dataContaminantBalance->ZoneAirCO2(ZoneNum) <= ZoneMinCO2) {
4340 : // Zone air CO2 concentration is less than minimum zone CO2 concentration, set the Zone OA flow
4341 : // rate to minimum Zone OA flow rate when the zone is unoccupied
4342 0 : ZoneOA = ZoneOAMin;
4343 5824 : } else if (state.dataContaminantBalance->ZoneAirCO2(ZoneNum) >= ZoneMaxCO2) {
4344 : // Zone air CO2 concentration is greater than maximum zone CO2 concentration, set the Zone OA flow
4345 : // rate to maximum Zone OA flow rate (i.e.
4346 : // ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] + ZoneOAPeople)
4347 1156 : ZoneOA = ZoneOAMax;
4348 : } else {
4349 : // Zone air CO2 concentration is between maximum and minimum limits of zone CO2 concentration,
4350 : // set Zone OA flow rate by proportionally adjusting between ZoneOAMin and ZoneOAMax
4351 4668 : ZoneOA = ZoneOAMin +
4352 9336 : (ZoneOAMax - ZoneOAMin) * ((state.dataContaminantBalance->ZoneAirCO2(ZoneNum) - ZoneMinCO2) /
4353 4668 : (ZoneMaxCO2 - ZoneMinCO2));
4354 : }
4355 : }
4356 : } else {
4357 0 : if (state.dataGlobal->DisplayExtraWarnings) {
4358 0 : ++this->CO2GainErrorCount;
4359 0 : if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc) {
4360 0 : if (this->CO2GainErrorCount < 2) {
4361 0 : ShowSevereError(state,
4362 0 : std::string{RoutineName} + CurrentModuleObject + " = \"" + this->Name + "\".");
4363 0 : ShowContinueError(state,
4364 : "For System Outdoor Air Method = "
4365 : "ProportionalControlBasedOnOccupancySchedule, CO2 generation from people "
4366 0 : "is not greater than zero. Occurs in Zone =\"" +
4367 0 : curZone.Name + "\". ");
4368 0 : ShowContinueError(state,
4369 : "\"ProportionalControlBasedOnOccupancySchedule\" will not be modeled. "
4370 : "Default \"Standard62.1VentilationRateProcedure\" will be modeled. Simulation "
4371 : "continues...");
4372 0 : ShowContinueErrorTimeStamp(state, "");
4373 : } else {
4374 0 : ShowRecurringWarningErrorAtEnd(
4375 : state,
4376 0 : CurrentModuleObject + " = \"" + this->Name +
4377 : "\", For System Outdoor Air Method = ProportionalControlBasedOnOccupancySchedule, "
4378 : "CO2 generation from people is not greater than zero. Error continues...",
4379 : this->CO2GainErrorIndex);
4380 : }
4381 : }
4382 0 : if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc) {
4383 0 : if (this->CO2GainErrorCount < 2) {
4384 0 : ShowSevereError(state,
4385 0 : std::string{RoutineName} + CurrentModuleObject + " = \"" + this->Name + "\".");
4386 0 : ShowContinueError(state,
4387 : "For System Outdoor Air Method = "
4388 : "ProportionalControlBasedOnDesignOccupancy, CO2 generation from people is "
4389 0 : "not greater than zero. Occurs in Zone =\"" +
4390 0 : curZone.Name + "\". ");
4391 0 : ShowContinueError(state,
4392 : "\"ProportionalControlBasedOnDesignOccupancy\" will not be modeled. "
4393 : "Default \"Standard62.1VentilationRateProcedure\" will be modeled. Simulation "
4394 : "continues...");
4395 0 : ShowContinueErrorTimeStamp(state, "");
4396 : } else {
4397 0 : ShowRecurringWarningErrorAtEnd(
4398 : state,
4399 0 : CurrentModuleObject + " = \"" + this->Name +
4400 : "\", For System Outdoor Air Method = ProportionalControlBasedOnDesignOccupancy, CO2 "
4401 : "generation from people is not greater than zero. Error continues...",
4402 : this->CO2GainErrorIndex);
4403 : }
4404 : }
4405 : }
4406 0 : ZoneOA = ZoneOABZ / ZoneEz;
4407 : }
4408 : } else {
4409 : // ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] is less than or equal to zero
4410 6552 : ZoneOA = ZoneOABZ / ZoneEz;
4411 : }
4412 : } else {
4413 : // ZoneControl:ContaminantController is scheduled off (not available)
4414 0 : ZoneOA = ZoneOABZ / ZoneEz;
4415 : }
4416 : } else {
4417 : // "Carbon Dioxide Control Availability Schedule" for ZoneControl:ContaminantController not found
4418 24752 : ZoneOA = ZoneOABZ / ZoneEz;
4419 : }
4420 37128 : SysOA = SysOA + ZoneOA;
4421 : }
4422 :
4423 : // Get the zone supply air flow rate
4424 6162170 : ZoneSA = 0.0;
4425 6162170 : ZonePA = 0.0;
4426 6162170 : Ep = 1.0;
4427 6162170 : if (ZoneEquipConfigNum > 0) {
4428 12324340 : for (int InNodeIndex = 1; InNodeIndex <= curZoneEquipConfig.NumInletNodes; ++InNodeIndex) {
4429 : // Assume primary air is always stored at the AirDistUnitCool (cooling deck if dual duct)
4430 6162170 : PriNode = curZoneEquipConfig.AirDistUnitCool(InNodeIndex).InNode;
4431 6162170 : if (PriNode > 0) {
4432 6162170 : NodeTemp = state.dataLoopNodes->Node(PriNode).Temp;
4433 6162170 : NodeHumRat = state.dataLoopNodes->Node(PriNode).HumRat;
4434 6162170 : MassFlowRate = state.dataLoopNodes->Node(PriNode).MassFlowRate;
4435 : } else {
4436 0 : MassFlowRate = 0.0;
4437 : }
4438 : // total primary air to terminal units of the zone
4439 6162170 : if (MassFlowRate > 0.0)
4440 6110663 : ZonePA += MassFlowRate / PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, NodeTemp, NodeHumRat);
4441 :
4442 : // or InletNode = ZoneEquipConfig(ZoneEquipConfigNum)%AirDistUnitCool(InNodeIndex)%OutNode
4443 6162170 : InletNode = curZoneEquipConfig.InletNode(InNodeIndex);
4444 6162170 : if (InletNode > 0) {
4445 6162170 : NodeTemp = state.dataLoopNodes->Node(InletNode).Temp;
4446 6162170 : NodeHumRat = state.dataLoopNodes->Node(InletNode).HumRat; // ZoneAirHumRat(ZoneNum)
4447 6162170 : MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
4448 : } else {
4449 0 : MassFlowRate = 0.0;
4450 : }
4451 : // total supply air to the zone
4452 6162170 : if (MassFlowRate > 0.0)
4453 6113987 : ZoneSA += MassFlowRate / PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, NodeTemp, NodeHumRat);
4454 : }
4455 :
4456 : // calc zone primary air fraction
4457 6162170 : if (ZoneSA > 0.0) Ep = ZonePA / ZoneSA;
4458 6162170 : if (Ep > 1.0) Ep = 1.0;
4459 : }
4460 :
4461 : // Calc the zone OA fraction = Zone OA flow rate / Zone supply air flow rate
4462 6162170 : if (ZoneSA > 0.0) {
4463 6113987 : ZoneOAFrac = ZoneOA / ZoneSA;
4464 : // Zone OA fraction cannot be more than 1
4465 6113987 : if (ZoneOAFrac > 1.0) ZoneOAFrac = 1.0;
4466 : } else {
4467 48183 : ZoneOAFrac = 0.0;
4468 : }
4469 :
4470 : // added for TRACE - zone maximum OA fraction - calculate the adjustment factor for the TU/zone supply air flow
4471 : // only for VRP system OA method
4472 6162170 : curZoneSysEnergyDemand.SupplyAirAdjustFactor = 1.0;
4473 :
4474 6162170 : if (this->SystemOAMethod == DataSizing::SysOAMethod::VRP || this->SystemOAMethod == DataSizing::SysOAMethod::VRPL) {
4475 6125042 : if (ZoneOAFrac > this->ZoneMaxOAFraction) {
4476 0 : if (this->ZoneMaxOAFraction > 0.0) {
4477 0 : curZoneSysEnergyDemand.SupplyAirAdjustFactor = ZoneOAFrac / this->ZoneMaxOAFraction;
4478 : } else {
4479 0 : curZoneSysEnergyDemand.SupplyAirAdjustFactor = 1.0;
4480 : }
4481 :
4482 : // cap zone OA fraction at the maximum specified
4483 0 : ZoneOAFrac = this->ZoneMaxOAFraction;
4484 : }
4485 : }
4486 :
4487 : // Zone air secondary recirculation fraction
4488 6162170 : Er = this->ZoneSecondaryRecirculation(ZoneIndex);
4489 6162170 : if (Er > 0.0) {
4490 : // multi-path ventilation system using VRP
4491 19630 : Fa = Ep + (1.0 - Ep) * Er;
4492 19630 : Fb = Ep;
4493 19630 : Fc = 1.0 - (1.0 - ZoneEz) * (1.0 - Er) * (1.0 - Ep);
4494 :
4495 : // Calc zone ventilation efficiency
4496 19630 : if (Fa > 0.0) {
4497 19630 : Evz = 1.0 + Xs * Fb / Fa - ZoneOAFrac * Ep * Fc / Fa;
4498 : } else {
4499 0 : Evz = 1.0;
4500 : }
4501 : } else {
4502 : // single-path ventilation system
4503 6142540 : Evz = 1.0 + Xs - ZoneOAFrac;
4504 : }
4505 :
4506 : // calc system ventilation efficiency = Minimum of zone ventilation efficiency
4507 6162170 : if (Evz < 0.0) Evz = 0.0;
4508 6162170 : if (Evz < SysEv) SysEv = Evz;
4509 :
4510 : } // zone loop
4511 :
4512 : // Calc the system supply OA flow rate counting the system ventilation efficiency
4513 780873 : if (SysEv <= 0.0) SysEv = 1.0;
4514 :
4515 : // Calc system outdoor air requirement
4516 1555558 : if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc ||
4517 1549370 : this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc ||
4518 774685 : this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate) {
4519 12376 : SysOA = SysOA / SysEv;
4520 768497 : } else if (this->SystemOAMethod == DataSizing::SysOAMethod::VRPL && this->SysDesOA > 0.0) {
4521 : // Limit system OA to design OA minimum flow rate, as per ASHRAE Guideline 36-2018 Section 5.16.3.1
4522 : // If no system sizing run is done (i.e. no Sizing:System) the design outdoor air flow rate is not known
4523 670319 : SysOA = min(SysOAuc / SysEv, this->SysDesOA);
4524 : } else {
4525 98178 : SysOA = SysOAuc / SysEv;
4526 : }
4527 : }
4528 :
4529 : // Finally calc the system supply OA mass flow rate
4530 924000 : MechVentOAMassFlow = SysOA * state.dataEnvrn->StdRhoAir;
4531 : }
4532 :
4533 : } else {
4534 274266 : MechVentOAMassFlow = 0.0;
4535 : }
4536 1211670 : }
4537 :
4538 23012475 : void OAControllerProps::CalcOAEconomizer(EnergyPlusData &state,
4539 : int const AirLoopNum,
4540 : Real64 const OutAirMinFrac,
4541 : Real64 &OASignal,
4542 : bool &HighHumidityOperationFlag,
4543 : bool const FirstHVACIteration)
4544 : {
4545 : using General::SolveRoot;
4546 : using SetPointManager::GetCoilFreezingCheckFlag;
4547 :
4548 23012475 : int constexpr MaxIte(500); // Maximum number of iterations
4549 23012475 : Real64 constexpr Acc(0.0001); // Accuracy of result
4550 : bool AirLoopEconoLockout; // Economizer lockout flag
4551 : bool AirLoopNightVent; // Night Ventilation flag for air loop
4552 : bool EconomizerOperationFlag; // TRUE if OA economizer is active
4553 : Real64 EconomizerAirFlowScheduleValue; // value of economizer operation schedule (push-button type control schedule)
4554 : Real64 MaximumOAFracBySetPoint; // The maximum OA fraction due to freezing cooling coil check
4555 : Real64 OutAirSignal; // Used to set OA mass flow rate
4556 : int SolFla; // Flag of solver
4557 : Real64 lowFlowResiduum; // result of low OA flow calculation (Tmixedair_sp - Tmixedair)
4558 : Real64 highFlowResiduum; // result of high OA flow calculation (Tmixedair_sp - Tmixedair)
4559 : Real64 minOAFrac;
4560 :
4561 23012475 : if (AirLoopNum > 0) {
4562 : // Check lockout with heating for any airloop - will lockout economizer even on airloops without a unitary system
4563 22448592 : if (this->Lockout == LockoutType::LockoutWithHeatingPossible) {
4564 : // For all system types (even ones that don't set AirLoopEconoLockout) lock out economizer if unfavorable for heating
4565 3994185 : if (state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CheckHeatRecoveryBypassStatus &&
4566 568422 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysComponentsSimulated) {
4567 :
4568 270574 : if (this->MixedAirTempAtMinOAFlow <= state.dataLoopNodes->Node(this->MixNode).TempSetPoint) {
4569 76834 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconomizerFlowLocked = true;
4570 : // this->OAMassFlow = AirLoopFlow( AirLoopNum ).MinOutAir;
4571 : // AirLoopFlow( AirLoopNum ).OAFrac = this->OAMassFlow / this->MixMassFlow;
4572 76834 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoLockout = true;
4573 76834 : EconomizerOperationFlag = false;
4574 : } else {
4575 193740 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconomizerFlowLocked = false;
4576 193740 : this->HRHeatingCoilActive = 0;
4577 : }
4578 270574 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CheckHeatRecoveryBypassStatus = false;
4579 : }
4580 : }
4581 : }
4582 :
4583 23012475 : if (AirLoopNum > 0) {
4584 22448592 : AirLoopEconoLockout = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoLockout;
4585 22448592 : AirLoopNightVent = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).NightVent;
4586 : } else {
4587 563883 : AirLoopEconoLockout = false;
4588 563883 : AirLoopNightVent = false;
4589 : }
4590 :
4591 : // Define an outside air signal
4592 23012475 : if (this->MixedAirSPMNum > 0) {
4593 10154 : this->CoolCoilFreezeCheck = GetCoilFreezingCheckFlag(state, this->MixedAirSPMNum);
4594 : } else {
4595 23002321 : this->CoolCoilFreezeCheck = false;
4596 : }
4597 :
4598 23012475 : if (std::abs(this->RetTemp - this->InletTemp) > SmallTempDiff) {
4599 23012050 : OutAirSignal = (this->RetTemp - this->MixSetTemp) / (this->RetTemp - this->InletTemp);
4600 23012050 : if (this->CoolCoilFreezeCheck) {
4601 0 : this->MaxOAFracBySetPoint = 0.0;
4602 0 : MaximumOAFracBySetPoint = OutAirSignal;
4603 : }
4604 : } else {
4605 425 : if (this->RetTemp - this->MixSetTemp < 0.0) {
4606 175 : if (this->RetTemp - this->InletTemp >= 0.0) {
4607 109 : OutAirSignal = -1.0;
4608 : } else {
4609 66 : OutAirSignal = 1.0;
4610 : }
4611 : } else {
4612 250 : if (this->RetTemp - this->InletTemp >= 0.0) {
4613 234 : OutAirSignal = 1.0;
4614 : } else {
4615 16 : OutAirSignal = -1.0;
4616 : }
4617 : }
4618 : }
4619 23012475 : OutAirSignal = min(max(OutAirSignal, OutAirMinFrac), 1.0);
4620 :
4621 : // If no economizer, set to minimum and disable economizer and high humidity control
4622 23012475 : if (this->Econo == EconoOp::NoEconomizer) {
4623 7951550 : OutAirSignal = OutAirMinFrac;
4624 7951550 : EconomizerOperationFlag = false;
4625 7951550 : EconomizerAirFlowScheduleValue = 0.0;
4626 7951550 : HighHumidityOperationFlag = false;
4627 15060925 : } else if (this->MaxOA < SmallAirVolFlow) {
4628 0 : OutAirSignal = OutAirMinFrac;
4629 0 : EconomizerOperationFlag = false;
4630 0 : EconomizerAirFlowScheduleValue = 0.0;
4631 0 : HighHumidityOperationFlag = false;
4632 15060925 : } else if (AirLoopEconoLockout) {
4633 468278 : OutAirSignal = OutAirMinFrac;
4634 468278 : EconomizerOperationFlag = false;
4635 468278 : EconomizerAirFlowScheduleValue = 0.0;
4636 468278 : HighHumidityOperationFlag = false;
4637 : } else {
4638 : // Changed by Amit for new implementation
4639 : // Otherwise do the limit checks
4640 14592647 : EconomizerOperationFlag = true;
4641 : // Outside air temp greater than mix air setpoint
4642 14592647 : if (this->InletTemp > this->MixSetTemp) {
4643 10797729 : OutAirSignal = 1.0;
4644 : }
4645 : // Return air temp limit
4646 14592647 : if (this->Econo == EconoOp::DifferentialDryBulb) {
4647 11438118 : if (this->InletTemp > this->RetTemp) {
4648 4346662 : OutAirSignal = OutAirMinFrac;
4649 4346662 : EconomizerOperationFlag = false;
4650 : }
4651 11438118 : this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
4652 : }
4653 : // Return air enthalpy limit
4654 14592647 : if (this->Econo == EconoOp::DifferentialEnthalpy) {
4655 657767 : if (this->InletEnth > this->RetEnth) {
4656 437692 : OutAirSignal = OutAirMinFrac;
4657 437692 : EconomizerOperationFlag = false;
4658 : }
4659 657767 : this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
4660 : }
4661 : // Outside air temperature limit
4662 14592647 : if (this->Econo == EconoOp::FixedDryBulb) {
4663 2434923 : this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
4664 : }
4665 : // Fixed Enthalpy limit
4666 14592647 : if (this->Econo == EconoOp::FixedEnthalpy) {
4667 0 : this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
4668 : }
4669 : // FIXED DEW POINT AND DRY BULB TEMPERATURE STRATEGY
4670 14592647 : if (this->Econo == EconoOp::FixedDewPointAndDryBulb) {
4671 0 : this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
4672 : }
4673 : // ELECRONIC ENTHALPY, HUMIDITY RATIO CURVE
4674 14592647 : if (this->Econo == EconoOp::ElectronicEnthalpy) {
4675 61839 : this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
4676 : }
4677 : // Differential dry bulb and enthalpy strategy
4678 14592647 : if (this->Econo == EconoOp::DifferentialDryBulbAndEnthalpy) {
4679 0 : if (this->InletTemp > this->RetTemp) {
4680 0 : OutAirSignal = OutAirMinFrac;
4681 0 : EconomizerOperationFlag = false;
4682 : }
4683 0 : if (this->InletEnth > this->RetEnth) {
4684 0 : OutAirSignal = OutAirMinFrac;
4685 0 : EconomizerOperationFlag = false;
4686 : }
4687 0 : this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
4688 : }
4689 :
4690 14592647 : if (this->TempLowLim != BlankNumeric && this->OATemp < this->TempLowLim) {
4691 953766 : OutAirSignal = OutAirMinFrac;
4692 953766 : EconomizerOperationFlag = false;
4693 : }
4694 : // Increase air flow for humidity control
4695 : // (HumidistatZoneNum is greater than 0 IF High Humidity Control Flag = YES, checked in GetInput)
4696 14592647 : if (this->HumidistatZoneNum > 0) {
4697 : // IF humidistat senses a moisture load check to see if modifying air flow is appropriate, otherwise disable modified air flow
4698 58527 : if (state.dataZoneEnergyDemand->ZoneSysMoistureDemand(this->HumidistatZoneNum).TotalOutputRequired < 0.0) {
4699 : // IF OAController is not allowed to modify air flow during high outdoor humrat condition, then disable modified air flow
4700 : // if indoor humrat is less than or equal to outdoor humrat
4701 41300 : if (!this->ModifyDuringHighOAMoisture &&
4702 20650 : (state.dataLoopNodes->Node(this->NodeNumofHumidistatZone).HumRat - this->OAHumRat) <= DataHVACGlobals::SmallHumRatDiff) {
4703 20256 : HighHumidityOperationFlag = false;
4704 : } else {
4705 394 : HighHumidityOperationFlag = true;
4706 : }
4707 : } else {
4708 37877 : HighHumidityOperationFlag = false;
4709 : }
4710 : } else {
4711 14534120 : HighHumidityOperationFlag = false;
4712 : }
4713 :
4714 : // Check time of day economizer schedule, enable economizer if schedule value > 0
4715 14592647 : EconomizerAirFlowScheduleValue = 0.0;
4716 14592647 : if (this->EconomizerOASchedPtr > 0) {
4717 62012 : EconomizerAirFlowScheduleValue = GetCurrentScheduleValue(state, this->EconomizerOASchedPtr);
4718 62012 : if (EconomizerAirFlowScheduleValue > 0.0) {
4719 852 : EconomizerOperationFlag = true;
4720 852 : OutAirSignal = 1.0;
4721 : }
4722 : }
4723 : }
4724 :
4725 : // OutAirSignal will not give exactly the correct mixed air temperature (equal to the setpoint) since
4726 : // it was calculated using the approximate method of sensible energy balance. Now we have to get the
4727 : // accurate result using a full mass, enthalpy and moisture balance and iteration.
4728 24284196 : if (OutAirSignal > OutAirMinFrac && OutAirSignal < 1.0 && this->MixMassFlow > VerySmallMassFlow &&
4729 2543442 : this->ControllerType_Num == MixedAirControllerType::ControllerOutsideAir && !AirLoopNightVent) {
4730 :
4731 1271721 : if (AirLoopNum > 0) {
4732 :
4733 1271721 : if (state.dataAirLoop->OutsideAirSys(state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysNum).NumComponents == 1) {
4734 : // no need to simulate OA System if only a mixer is used in the OutsideAirSystem
4735 :
4736 63999964 : auto f = [&state, this](Real64 const OASignal) {
4737 4571426 : Real64 const OAMassFlowRate = OASignal * this->MixMassFlow;
4738 4571426 : Real64 const RecircMassFlowRate = max(this->MixMassFlow - OAMassFlowRate, 0.0);
4739 9142852 : Real64 const RecircEnth = state.dataLoopNodes->Node(this->RetNode).Enthalpy;
4740 9142852 : Real64 const RecircHumRat = state.dataLoopNodes->Node(this->RetNode).HumRat;
4741 : Real64 const MixEnth =
4742 18285704 : (RecircMassFlowRate * RecircEnth + OAMassFlowRate * state.dataLoopNodes->Node(this->OANode).Enthalpy) / this->MixMassFlow;
4743 : Real64 const MixHumRat =
4744 18285704 : (RecircMassFlowRate * RecircHumRat + OAMassFlowRate * state.dataLoopNodes->Node(this->OANode).HumRat) / this->MixMassFlow;
4745 4571426 : Real64 const MixTemp = Psychrometrics::PsyTdbFnHW(MixEnth, MixHumRat);
4746 9142852 : return state.dataLoopNodes->Node(this->MixNode).TempSetPoint - MixTemp;
4747 1259483 : };
4748 :
4749 1259483 : General::SolveRoot(state, Acc, MaxIte, SolFla, OASignal, f, OutAirMinFrac, 1.0);
4750 1259483 : if (SolFla < 0) {
4751 834 : OASignal = OutAirSignal;
4752 : }
4753 :
4754 : } else {
4755 :
4756 : // simulate OA System if equipment exists other than the mixer (e.g., heating/cooling coil, HX, ect.)
4757 :
4758 : // 1 - check min OA flow result
4759 12238 : if (this->FixedMin) {
4760 12238 : state.dataLoopNodes->Node(this->OANode).MassFlowRate =
4761 12238 : min(max(this->ExhMassFlow, OutAirMinFrac * state.dataAirLoop->AirLoopFlow(AirLoopNum).DesSupply),
4762 12238 : state.dataLoopNodes->Node(this->MixNode).MassFlowRate);
4763 12238 : state.dataLoopNodes->Node(this->RelNode).MassFlowRate =
4764 12238 : max(state.dataLoopNodes->Node(this->OANode).MassFlowRate - this->ExhMassFlow, 0.0);
4765 : // save actual OA flow frac for use as min value for RegulaFalsi call
4766 12238 : minOAFrac = max(OutAirMinFrac, state.dataLoopNodes->Node(this->OANode).MassFlowRate / this->MixMassFlow);
4767 : } else {
4768 0 : state.dataLoopNodes->Node(this->OANode).MassFlowRate =
4769 0 : max(this->ExhMassFlow, OutAirMinFrac * state.dataLoopNodes->Node(this->MixNode).MassFlowRate);
4770 0 : state.dataLoopNodes->Node(this->RelNode).MassFlowRate =
4771 0 : max(state.dataLoopNodes->Node(this->OANode).MassFlowRate - this->ExhMassFlow, 0.0);
4772 : // save actual OA flow frac for use as min value for RegulaFalsi call
4773 0 : minOAFrac = max(OutAirMinFrac, state.dataLoopNodes->Node(this->OANode).MassFlowRate / this->MixMassFlow);
4774 : }
4775 12238 : SimOASysComponents(state, state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysNum, FirstHVACIteration, AirLoopNum);
4776 12238 : lowFlowResiduum = state.dataLoopNodes->Node(this->MixNode).TempSetPoint - state.dataLoopNodes->Node(this->MixNode).Temp;
4777 :
4778 : // 2 - check max OA flow result
4779 12238 : state.dataLoopNodes->Node(this->OANode).MassFlowRate = max(this->ExhMassFlow, state.dataLoopNodes->Node(this->MixNode).MassFlowRate);
4780 12238 : state.dataLoopNodes->Node(this->RelNode).MassFlowRate =
4781 12238 : max(state.dataLoopNodes->Node(this->OANode).MassFlowRate - this->ExhMassFlow, 0.0);
4782 12238 : SimOASysComponents(state, state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysNum, FirstHVACIteration, AirLoopNum);
4783 12238 : highFlowResiduum = state.dataLoopNodes->Node(this->MixNode).TempSetPoint - state.dataLoopNodes->Node(this->MixNode).Temp;
4784 :
4785 : // 3 - test to ensure RegulaFalsi can find an answer
4786 12238 : if ((sign(lowFlowResiduum) == sign(highFlowResiduum))) {
4787 766 : OASignal = OutAirSignal;
4788 : } else {
4789 : // 4 - find result
4790 :
4791 630060 : auto f = [&state, this, FirstHVACIteration, AirLoopNum](Real64 const OASignal) {
4792 42004 : Real64 const MixMassFlowRate = this->MixMassFlow;
4793 84008 : int const OASysNum = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysNum;
4794 84008 : Real64 localExhMassFlow = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).ZoneExhMassFlow;
4795 42004 : Real64 const OAMassFlowRate = max(localExhMassFlow, OASignal * MixMassFlowRate);
4796 126012 : state.dataLoopNodes->Node(this->OANode).MassFlowRate = OAMassFlowRate; // set OA node mass flow rate
4797 84008 : state.dataLoopNodes->Node(this->RelNode).MassFlowRate =
4798 42004 : max(OAMassFlowRate - localExhMassFlow, 0.0); // set relief node mass flow rate to maintain mixer continuity calcs
4799 84008 : SimOASysComponents(state, OASysNum, FirstHVACIteration, AirLoopNum);
4800 168016 : return state.dataLoopNodes->Node(this->MixNode).TempSetPoint - state.dataLoopNodes->Node(this->MixNode).Temp;
4801 11472 : };
4802 :
4803 11472 : SolveRoot(state, (Acc / 10.0), MaxIte, SolFla, OASignal, f, minOAFrac, 1.0);
4804 11472 : if (SolFla < 0) { // if RegulaFalsi fails to find a solution, returns -1 or -2, set to existing OutAirSignal
4805 267 : OASignal = OutAirSignal;
4806 : }
4807 : }
4808 : }
4809 :
4810 : } else {
4811 :
4812 0 : auto f = [&state, this](Real64 const OASignal) {
4813 0 : Real64 const MixMassFlowRate = this->MixMassFlow;
4814 0 : Real64 OAMassFlowRate = OASignal * MixMassFlowRate;
4815 0 : Real64 RecircMassFlowRate = max(MixMassFlowRate - OAMassFlowRate, 0.0);
4816 0 : Real64 RecircEnth = state.dataLoopNodes->Node(this->RetNode).Enthalpy;
4817 0 : Real64 RecircHumRat = state.dataLoopNodes->Node(this->RetNode).HumRat;
4818 : Real64 MixEnth =
4819 0 : (RecircMassFlowRate * RecircEnth + OAMassFlowRate * state.dataLoopNodes->Node(this->OANode).Enthalpy) / MixMassFlowRate;
4820 : Real64 MixHumRat =
4821 0 : (RecircMassFlowRate * RecircHumRat + OAMassFlowRate * state.dataLoopNodes->Node(this->OANode).HumRat) / MixMassFlowRate;
4822 0 : Real64 MixTemp = Psychrometrics::PsyTdbFnHW(MixEnth, MixHumRat);
4823 0 : return state.dataLoopNodes->Node(this->MixNode).TempSetPoint - MixTemp;
4824 0 : };
4825 :
4826 0 : SolveRoot(state, Acc, MaxIte, SolFla, OASignal, f, OutAirMinFrac, 1.0);
4827 0 : if (SolFla < 0) {
4828 0 : OASignal = OutAirSignal;
4829 : }
4830 1271721 : }
4831 :
4832 : } else {
4833 21740754 : OASignal = OutAirSignal;
4834 : }
4835 :
4836 : // Economizer choice "Bypass" forces minimum OA except when high humidity air flow is active based on indoor RH
4837 23012475 : if (this->EconBypass && EconomizerAirFlowScheduleValue == 0.0) {
4838 694763 : OASignal = OutAirMinFrac;
4839 : }
4840 :
4841 : // Set outdoor air signal based on OA flow ratio if high humidity air flow is enabled
4842 23012475 : if (HighHumidityOperationFlag) {
4843 394 : if (this->MixMassFlow > 0.0) {
4844 : // calculate the actual ratio of outside air to mixed air so the magnitude of OA during high humidity control is correct
4845 394 : OASignal = max(OutAirMinFrac, (this->HighRHOAFlowRatio * this->MaxOAMassFlowRate / this->MixMassFlow));
4846 394 : this->OALimitingFactor = limitFactorHighHum;
4847 : }
4848 : }
4849 :
4850 23012475 : if (this->CoolCoilFreezeCheck) {
4851 0 : MaximumOAFracBySetPoint = min(max(MaximumOAFracBySetPoint, 0.0), 1.0);
4852 0 : this->MaxOAFracBySetPoint = MaximumOAFracBySetPoint;
4853 :
4854 : // This should not be messing with OutAirMinFrac, freeze protection should only limit economizer operation
4855 : // if (MaximumOAFracBySetPoint < OutAirMinFrac) {
4856 : // OutAirMinFrac = MaximumOAFracBySetPoint;
4857 : // if (AirLoopNum > 0) AirLoopFlow(AirLoopNum).MinOutAir = OutAirMinFrac * this->MixMassFlow;
4858 : //}
4859 0 : if (MaximumOAFracBySetPoint < OASignal) {
4860 0 : OASignal = MaximumOAFracBySetPoint;
4861 0 : this->OALimitingFactor = limitFactorLimits;
4862 : }
4863 0 : if (OutAirMinFrac > OASignal) {
4864 0 : OASignal = OutAirMinFrac;
4865 0 : this->OALimitingFactor = limitFactorLimits;
4866 : }
4867 : }
4868 :
4869 23012475 : if (AirLoopNum > 0) {
4870 :
4871 : // Set the air loop economizer and high humidity control flags.
4872 22448592 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive = EconomizerOperationFlag;
4873 22448592 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).HighHumCtrlActive = HighHumidityOperationFlag;
4874 22448592 : if (state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconomizerFlowLocked) {
4875 773113 : this->OAMassFlow = state.dataAirLoop->AirLoopFlow(AirLoopNum).MinOutAir;
4876 773113 : state.dataAirLoop->AirLoopFlow(AirLoopNum).OAFrac = this->OAMassFlow / this->MixMassFlow;
4877 773113 : state.dataAirLoop->AirLoopFlow(AirLoopNum).OAFlow = this->OAMassFlow;
4878 : }
4879 :
4880 : // Check heat exchanger bypass control
4881 22448592 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).HeatRecoveryBypass = false;
4882 22448592 : this->HeatRecoveryBypassStatus = 0;
4883 22448592 : if (EconomizerOperationFlag) {
4884 4626885 : if (this->HeatRecoveryBypassControlType == BypassWhenWithinEconomizerLimits) {
4885 4401395 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).HeatRecoveryBypass = true;
4886 4401395 : this->HeatRecoveryBypassStatus = 1;
4887 225490 : } else if (this->HeatRecoveryBypassControlType == BypassWhenOAFlowGreaterThanMinimum) {
4888 225490 : Real64 OAMassFlowMin = OutAirMinFrac * state.dataAirLoop->AirLoopFlow(AirLoopNum).DesSupply;
4889 225490 : Real64 OAMassFlowActual = OASignal * this->MixMassFlow;
4890 225490 : Real64 reasonablySmallMassFlow = 1e-6;
4891 225490 : if (OAMassFlowActual > (OAMassFlowMin + reasonablySmallMassFlow)) {
4892 143578 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).HeatRecoveryBypass = true;
4893 143578 : this->HeatRecoveryBypassStatus = 1;
4894 : }
4895 : }
4896 : }
4897 : }
4898 :
4899 : // Set economizer report variable and status flag
4900 23012475 : if (this->Econo == EconoOp::NoEconomizer) {
4901 : // No economizer
4902 7951550 : this->EconomizerStatus = 0;
4903 7951550 : this->EconoActive = false;
4904 : } else {
4905 : // With economizer.
4906 15060925 : if (EconomizerOperationFlag) {
4907 : // Economizer is enabled
4908 4627737 : this->EconomizerStatus = 1;
4909 4627737 : this->EconoActive = true;
4910 4627737 : if ((OASignal > OutAirMinFrac) && !HighHumidityOperationFlag) {
4911 3281389 : this->OALimitingFactor = limitFactorEconomizer;
4912 : }
4913 : } else {
4914 : // Economizer is disabled
4915 10433188 : this->EconomizerStatus = 0;
4916 10433188 : this->EconoActive = false;
4917 : }
4918 : }
4919 :
4920 : // Night ventilation control overrides economizer and high humidity control.
4921 23012475 : if (AirLoopNightVent) {
4922 0 : OASignal = 1.0;
4923 0 : this->OALimitingFactor = limitFactorNightVent;
4924 : }
4925 :
4926 : // Set high humidity control report variable and status flag
4927 23012475 : if (HighHumidityOperationFlag) {
4928 394 : this->HighHumCtrlStatus = 1;
4929 394 : this->HighHumCtrlActive = true;
4930 : } else {
4931 23012081 : this->HighHumCtrlStatus = 0;
4932 23012081 : this->HighHumCtrlActive = false;
4933 : }
4934 23012475 : }
4935 43707297 : void CalcOAMixer(EnergyPlusData &state, int const OAMixerNum)
4936 : {
4937 :
4938 : // SUBROUTINE INFORMATION:
4939 : // AUTHOR Fred Buhl
4940 : // DATE WRITTEN Oct 1998
4941 : // MODIFIED na
4942 : // RE-ENGINEERED na
4943 :
4944 : // PURPOSE OF THIS SUBROUTINE
4945 : // Calculate the mixed air flow and conditions
4946 :
4947 : // METHODOLOGY EMPLOYED:
4948 :
4949 : // REFERENCES:
4950 :
4951 : // Using/Aliasing
4952 : using Psychrometrics::PsyTdbFnHW;
4953 :
4954 : // Locals
4955 : // SUBROUTINE ARGUMENT DEFINITIONS
4956 :
4957 : // SUBROUTINE PARAMETER DEFINITIONS:
4958 :
4959 : // INTERFACE BLOCK SPECIFICATIONS
4960 : // na
4961 :
4962 : // DERIVED TYPE DEFINITIONS
4963 : // na
4964 :
4965 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4966 : Real64 RecircMassFlowRate;
4967 : Real64 RecircPressure;
4968 : Real64 RecircEnthalpy;
4969 : Real64 RecircHumRat;
4970 :
4971 : // Define a recirculation mass flow rate
4972 43707297 : RecircMassFlowRate = state.dataMixedAir->OAMixer(OAMixerNum).RetMassFlowRate - state.dataMixedAir->OAMixer(OAMixerNum).RelMassFlowRate;
4973 : // In certain low flow conditions the return air mass flow rate can be below the outside air value established
4974 : // by the user. This check will ensure that this condition does not result in unphysical air properties.
4975 43707297 : if (RecircMassFlowRate < 0.0) {
4976 112153 : RecircMassFlowRate = 0.0;
4977 112153 : state.dataMixedAir->OAMixer(OAMixerNum).RelMassFlowRate = state.dataMixedAir->OAMixer(OAMixerNum).RetMassFlowRate;
4978 : }
4979 :
4980 : // Pass through the return air conditions to the relief air stream. The return air is "split" to
4981 : // the relief air and the recirculation air.
4982 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).RelTemp = state.dataMixedAir->OAMixer(OAMixerNum).RetTemp;
4983 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).RelHumRat = state.dataMixedAir->OAMixer(OAMixerNum).RetHumRat;
4984 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).RelEnthalpy = state.dataMixedAir->OAMixer(OAMixerNum).RetEnthalpy;
4985 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).RelPressure = state.dataMixedAir->OAMixer(OAMixerNum).RetPressure;
4986 43707297 : RecircPressure = state.dataMixedAir->OAMixer(OAMixerNum).RetPressure;
4987 43707297 : RecircEnthalpy = state.dataMixedAir->OAMixer(OAMixerNum).RetEnthalpy;
4988 43707297 : RecircHumRat = state.dataMixedAir->OAMixer(OAMixerNum).RetHumRat;
4989 : // The recirculation air and the outside air are mixed to form the mixed air stream
4990 43707297 : state.dataMixedAir->OAMixer(OAMixerNum).MixMassFlowRate = state.dataMixedAir->OAMixer(OAMixerNum).OAMassFlowRate + RecircMassFlowRate;
4991 : // Check for zero flow
4992 43707297 : if (state.dataMixedAir->OAMixer(OAMixerNum).MixMassFlowRate <= VerySmallMassFlow) {
4993 4589260 : state.dataMixedAir->OAMixer(OAMixerNum).MixEnthalpy = state.dataMixedAir->OAMixer(OAMixerNum).RetEnthalpy;
4994 4589260 : state.dataMixedAir->OAMixer(OAMixerNum).MixHumRat = state.dataMixedAir->OAMixer(OAMixerNum).RetHumRat;
4995 4589260 : state.dataMixedAir->OAMixer(OAMixerNum).MixPressure = state.dataMixedAir->OAMixer(OAMixerNum).RetPressure;
4996 4589260 : state.dataMixedAir->OAMixer(OAMixerNum).MixTemp = state.dataMixedAir->OAMixer(OAMixerNum).RetTemp;
4997 4589260 : return;
4998 : }
4999 :
5000 39118037 : state.dataMixedAir->OAMixer(OAMixerNum).MixEnthalpy =
5001 78236074 : (RecircMassFlowRate * RecircEnthalpy +
5002 78236074 : state.dataMixedAir->OAMixer(OAMixerNum).OAMassFlowRate * state.dataMixedAir->OAMixer(OAMixerNum).OAEnthalpy) /
5003 39118037 : state.dataMixedAir->OAMixer(OAMixerNum).MixMassFlowRate;
5004 117354111 : state.dataMixedAir->OAMixer(OAMixerNum).MixHumRat = (RecircMassFlowRate * RecircHumRat + state.dataMixedAir->OAMixer(OAMixerNum).OAMassFlowRate *
5005 78236074 : state.dataMixedAir->OAMixer(OAMixerNum).OAHumRat) /
5006 39118037 : state.dataMixedAir->OAMixer(OAMixerNum).MixMassFlowRate;
5007 39118037 : state.dataMixedAir->OAMixer(OAMixerNum).MixPressure =
5008 78236074 : (RecircMassFlowRate * RecircPressure +
5009 78236074 : state.dataMixedAir->OAMixer(OAMixerNum).OAMassFlowRate * state.dataMixedAir->OAMixer(OAMixerNum).OAPressure) /
5010 39118037 : state.dataMixedAir->OAMixer(OAMixerNum).MixMassFlowRate;
5011 : // Mixed air temperature is calculated from the mixed air enthalpy and humidity ratio.
5012 39118037 : state.dataMixedAir->OAMixer(OAMixerNum).MixTemp =
5013 39118037 : PsyTdbFnHW(state.dataMixedAir->OAMixer(OAMixerNum).MixEnthalpy, state.dataMixedAir->OAMixer(OAMixerNum).MixHumRat);
5014 : }
5015 :
5016 : // End of Calculation/Simulation Section of the Module
5017 : //******************************************************************************
5018 :
5019 : // Beginning Sizing Section of the Module
5020 : //******************************************************************************
5021 :
5022 1125 : void OAControllerProps::SizeOAController(EnergyPlusData &state)
5023 : {
5024 :
5025 : // SUBROUTINE INFORMATION:
5026 : // AUTHOR Fred Buhl
5027 : // DATE WRITTEN September 2001
5028 : // MODIFIED na
5029 : // RE-ENGINEERED na
5030 :
5031 : // PURPOSE OF THIS SUBROUTINE:
5032 : // This subroutine is for sizing OAController Components for which flow rates have not been
5033 : // specified in the input.
5034 :
5035 : // METHODOLOGY EMPLOYED:
5036 : // Obtains flow rates from the zone or system sizing arrays.
5037 :
5038 : // Using/Aliasing
5039 :
5040 : using HVACHXAssistedCoolingCoil::GetHXCoilType;
5041 : using HVACHXAssistedCoolingCoil::GetHXDXCoilName;
5042 : using WaterCoils::SetCoilDesFlow;
5043 :
5044 : // SUBROUTINE PARAMETER DEFINITIONS:
5045 1125 : static std::string const &CurrentModuleObject(CurrentModuleObjects(static_cast<int>(CMO::OAController)));
5046 :
5047 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5048 : Real64 OAFlowRatio; // Used for error checking
5049 2250 : std::string CompType; // Component type
5050 2250 : std::string CompName; // Component name
5051 2250 : std::string CoilName;
5052 2250 : std::string CoilType;
5053 : int CompNum;
5054 : bool ErrorsFound;
5055 :
5056 1125 : ErrorsFound = false;
5057 1125 : if (this->MaxOA == AutoSize) {
5058 :
5059 876 : if (state.dataSize->CurSysNum > 0) {
5060 :
5061 876 : switch (this->ControllerType_Num) {
5062 876 : case MixedAirControllerType::ControllerOutsideAir: {
5063 876 : CheckSysSizing(state, CurrentModuleObject, this->Name);
5064 876 : switch (state.dataSize->CurDuctType) {
5065 0 : case DataHVACGlobals::AirDuctType::Cooling: {
5066 0 : this->MaxOA = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesCoolVolFlow;
5067 0 : } break;
5068 1 : case DataHVACGlobals::AirDuctType::Heating: {
5069 1 : this->MaxOA = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesHeatVolFlow;
5070 1 : } break;
5071 875 : case DataHVACGlobals::AirDuctType::Main:
5072 : case DataHVACGlobals::AirDuctType::Other:
5073 : default: {
5074 875 : this->MaxOA = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
5075 875 : } break;
5076 : }
5077 876 : } break;
5078 0 : case MixedAirControllerType::ControllerStandAloneERV: {
5079 0 : } break;
5080 0 : default:
5081 0 : break;
5082 : }
5083 :
5084 0 : } else if (state.dataSize->CurZoneEqNum > 0) {
5085 :
5086 0 : switch (this->ControllerType_Num) {
5087 0 : case MixedAirControllerType::ControllerOutsideAir: {
5088 0 : CheckZoneSizing(state, CurrentModuleObject, this->Name);
5089 0 : this->MaxOA = max(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow,
5090 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow);
5091 0 : } break;
5092 0 : case MixedAirControllerType::ControllerStandAloneERV: {
5093 0 : } break;
5094 0 : default:
5095 0 : break;
5096 : }
5097 : }
5098 :
5099 876 : if (this->MaxOA < SmallAirVolFlow) {
5100 0 : this->MaxOA = 0.0;
5101 : }
5102 :
5103 876 : BaseSizer::reportSizerOutput(state, CurrentModuleObject, this->Name, "Maximum Outdoor Air Flow Rate [m3/s]", this->MaxOA);
5104 : }
5105 :
5106 1125 : if (this->MinOA == AutoSize) {
5107 :
5108 813 : if (state.dataSize->CurSysNum > 0) {
5109 :
5110 813 : CheckSysSizing(state, CurrentModuleObject, this->Name);
5111 813 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesOutAirVolFlow >= SmallAirVolFlow) {
5112 803 : this->MinOA = min(state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesOutAirVolFlow, this->MaxOA);
5113 : } else {
5114 10 : this->MinOA = 0.0;
5115 : }
5116 : }
5117 :
5118 813 : BaseSizer::reportSizerOutput(state, CurrentModuleObject, this->Name, "Minimum Outdoor Air Flow Rate [m3/s]", this->MinOA);
5119 :
5120 813 : if (this->HumidistatZoneNum > 0 && this->FixedMin) {
5121 1 : if (this->MaxOA > 0.0) {
5122 1 : OAFlowRatio = this->MinOA / this->MaxOA;
5123 1 : if (this->HighRHOAFlowRatio < OAFlowRatio) {
5124 0 : ShowWarningError(state, CurrentModuleObject + " \"" + this->Name + "\"");
5125 0 : ShowContinueError(state, "... A fixed minimum outdoor air flow rate and high humidity control have been specified.");
5126 0 : ShowContinueError(state,
5127 : "... The High Humidity Outdoor Air Flow Ratio is less than the ratio of the outdoor air controllers "
5128 : "minimum to maximum outside air flow rate.");
5129 0 : ShowContinueError(state, format("... Controller minimum flow rate = {:.4T} m3/s.", this->MinOA));
5130 0 : ShowContinueError(state, format("... Controller maximum flow rate = {:.4T} m3/s.", this->MaxOA));
5131 0 : ShowContinueError(state, format("... Controller minimum to maximum flow ratio = {:.4T}.", OAFlowRatio));
5132 0 : ShowContinueError(state, format("... High humidity control flow ratio = {:.4T}.", this->HighRHOAFlowRatio));
5133 : }
5134 : }
5135 : }
5136 : }
5137 : // If there is an outside air system, loop over components in the OA system; pass the design air flow rate
5138 : // to the coil components that don't have design air flow as an input.
5139 1125 : if (state.dataSize->CurOASysNum > 0) {
5140 2162 : for (CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(state.dataSize->CurOASysNum).NumComponents; ++CompNum) {
5141 1141 : CompType = state.dataAirLoop->OutsideAirSys(state.dataSize->CurOASysNum).ComponentType(CompNum);
5142 1141 : CompName = state.dataAirLoop->OutsideAirSys(state.dataSize->CurOASysNum).ComponentName(CompNum);
5143 3423 : if (UtilityRoutines::SameString(CompType, "COIL:COOLING:WATER:DETAILEDGEOMETRY") ||
5144 3396 : UtilityRoutines::SameString(CompType, "COIL:HEATING:WATER") ||
5145 2255 : UtilityRoutines::SameString(CompType, "COILSYSTEM:COOLING:WATER:HEATEXCHANGERASSISTED")) {
5146 27 : if (UtilityRoutines::SameString(CompType, "COILSYSTEM:COOLING:WATER:HEATEXCHANGERASSISTED")) {
5147 0 : CoilName = GetHXDXCoilName(state, CompType, CompName, ErrorsFound);
5148 0 : CoilType = GetHXCoilType(state, CompType, CompName, ErrorsFound);
5149 : } else {
5150 27 : CoilName = CompName;
5151 27 : CoilType = CompType;
5152 : }
5153 27 : SetCoilDesFlow(state, CoilType, CoilName, this->MinOA, ErrorsFound);
5154 : }
5155 : } // End of component loop
5156 : }
5157 1125 : if (ErrorsFound) {
5158 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
5159 : }
5160 1125 : }
5161 :
5162 : // End of Sizing Section of the Module
5163 : //******************************************************************************
5164 :
5165 : // Beginning Update/Reporting Section of the Module
5166 : //******************************************************************************
5167 :
5168 24821703 : void OAControllerProps::UpdateOAController(EnergyPlusData &state)
5169 : {
5170 :
5171 : // SUBROUTINE INFORMATION:
5172 : // AUTHOR Fred Buhl
5173 : // DATE WRITTEN Oct 1998
5174 : // MODIFIED Shirey/Raustad FSEC, June 2003
5175 : // RE-ENGINEERED na
5176 :
5177 : // PURPOSE OF THIS SUBROUTINE
5178 : // Move the results of CalcOAController to the affected nodes
5179 :
5180 : // METHODOLOGY EMPLOYED:
5181 :
5182 : // REFERENCES:
5183 :
5184 : // Using/Aliasing
5185 : using namespace DataLoopNode;
5186 : // Locals
5187 : // SUBROUTINE ARGUMENT DEFINITIONS
5188 :
5189 : // SUBROUTINE PARAMETER DEFINITIONS:
5190 :
5191 : // INTERFACE BLOCK SPECIFICATIONS
5192 : // na
5193 :
5194 : // DERIVED TYPE DEFINITIONS
5195 : // na
5196 :
5197 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5198 : int OutAirNodeNum;
5199 : int InletAirNodeNum;
5200 : int RelAirNodeNum;
5201 : int RetAirNodeNum;
5202 :
5203 24821703 : OutAirNodeNum = this->OANode;
5204 24821703 : InletAirNodeNum = this->InletNode;
5205 24821703 : RelAirNodeNum = this->RelNode;
5206 24821703 : RetAirNodeNum = this->RetNode;
5207 :
5208 24821703 : if (this->ControllerType_Num == MixedAirControllerType::ControllerOutsideAir) {
5209 : // The outside air controller sets the outside air flow rate and the relief air flow rate
5210 24263372 : if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && (this->ManageDemand) &&
5211 5654 : (this->OAMassFlow > this->DemandLimitFlowRate)) {
5212 0 : state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRate = this->DemandLimitFlowRate;
5213 0 : state.dataLoopNodes->Node(InletAirNodeNum).MassFlowRate = this->DemandLimitFlowRate;
5214 0 : state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRateMaxAvail = this->DemandLimitFlowRate;
5215 : } else {
5216 24257718 : state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRate = this->OAMassFlow;
5217 24257718 : state.dataLoopNodes->Node(InletAirNodeNum).MassFlowRate = this->OAMassFlow;
5218 24257718 : state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRateMaxAvail = this->OAMassFlow;
5219 : }
5220 24257718 : state.dataLoopNodes->Node(RelAirNodeNum).MassFlowRate = this->RelMassFlow;
5221 : } else {
5222 : // The ERV controller sets the supply and secondary inlet node information for the Stand Alone ERV
5223 : // Currently, the Stand Alone ERV only has constant air flows (supply and exhaust), and these are
5224 : // already set in HVACStandAloneERV.cc (subroutine init). Therefore, these flow assignments below are
5225 : // currently redundant but may be useful in the future as mass flow rates can vary based on the controller signal.
5226 563985 : if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && (this->ManageDemand) &&
5227 0 : (this->OAMassFlow > this->DemandLimitFlowRate)) {
5228 0 : state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRate = this->DemandLimitFlowRate;
5229 0 : state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRateMaxAvail = this->DemandLimitFlowRate;
5230 : } else {
5231 563985 : state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRate = this->OAMassFlow;
5232 563985 : state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRateMaxAvail = this->OAMassFlow;
5233 : }
5234 563985 : state.dataLoopNodes->Node(RetAirNodeNum).MassFlowRate = state.dataLoopNodes->Node(this->RetNode).MassFlowRate;
5235 563985 : state.dataLoopNodes->Node(RetAirNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(this->RetNode).MassFlowRate;
5236 : }
5237 24821703 : }
5238 :
5239 43707297 : void UpdateOAMixer(EnergyPlusData &state, int const OAMixerNum)
5240 : {
5241 :
5242 : // SUBROUTINE INFORMATION:
5243 : // AUTHOR Fred Buhl
5244 : // DATE WRITTEN Oct 1998
5245 : // MODIFIED na
5246 : // RE-ENGINEERED na
5247 :
5248 : // PURPOSE OF THIS SUBROUTINE
5249 : // Move the results of CalcOAMixer to the affected nodes
5250 :
5251 : // METHODOLOGY EMPLOYED:
5252 :
5253 : // REFERENCES:
5254 :
5255 : // Using/Aliasing
5256 : using namespace DataLoopNode;
5257 :
5258 : // Locals
5259 : // SUBROUTINE ARGUMENT DEFINITIONS
5260 :
5261 : // SUBROUTINE PARAMETER DEFINITIONS:
5262 :
5263 : // INTERFACE BLOCK SPECIFICATIONS
5264 : // na
5265 :
5266 : // DERIVED TYPE DEFINITIONS
5267 : // na
5268 :
5269 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5270 : int MixNode;
5271 : int RelNode;
5272 : int RetNode;
5273 :
5274 43707297 : MixNode = state.dataMixedAir->OAMixer(OAMixerNum).MixNode;
5275 43707297 : RelNode = state.dataMixedAir->OAMixer(OAMixerNum).RelNode;
5276 43707297 : RetNode = state.dataMixedAir->OAMixer(OAMixerNum).RetNode;
5277 : // Move mixed air data to the mixed air node
5278 43707297 : state.dataLoopNodes->Node(MixNode).MassFlowRate = state.dataMixedAir->OAMixer(OAMixerNum).MixMassFlowRate;
5279 43707297 : state.dataLoopNodes->Node(MixNode).Temp = state.dataMixedAir->OAMixer(OAMixerNum).MixTemp;
5280 43707297 : state.dataLoopNodes->Node(MixNode).HumRat = state.dataMixedAir->OAMixer(OAMixerNum).MixHumRat;
5281 43707297 : state.dataLoopNodes->Node(MixNode).Enthalpy = state.dataMixedAir->OAMixer(OAMixerNum).MixEnthalpy;
5282 43707297 : state.dataLoopNodes->Node(MixNode).Press = state.dataMixedAir->OAMixer(OAMixerNum).MixPressure;
5283 43707297 : state.dataLoopNodes->Node(MixNode).MassFlowRateMaxAvail = state.dataMixedAir->OAMixer(OAMixerNum).MixMassFlowRate;
5284 : // Move the relief air data to the relief air node
5285 43707297 : state.dataLoopNodes->Node(RelNode).MassFlowRate = state.dataMixedAir->OAMixer(OAMixerNum).RelMassFlowRate;
5286 43707297 : state.dataLoopNodes->Node(RelNode).Temp = state.dataMixedAir->OAMixer(OAMixerNum).RelTemp;
5287 43707297 : state.dataLoopNodes->Node(RelNode).HumRat = state.dataMixedAir->OAMixer(OAMixerNum).RelHumRat;
5288 43707297 : state.dataLoopNodes->Node(RelNode).Enthalpy = state.dataMixedAir->OAMixer(OAMixerNum).RelEnthalpy;
5289 43707297 : state.dataLoopNodes->Node(RelNode).Press = state.dataMixedAir->OAMixer(OAMixerNum).RelPressure;
5290 43707297 : state.dataLoopNodes->Node(RelNode).MassFlowRateMaxAvail = state.dataMixedAir->OAMixer(OAMixerNum).RelMassFlowRate;
5291 :
5292 43707297 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
5293 66288 : state.dataLoopNodes->Node(RelNode).CO2 = state.dataLoopNodes->Node(RetNode).CO2;
5294 66288 : if (state.dataMixedAir->OAMixer(OAMixerNum).MixMassFlowRate <= VerySmallMassFlow) {
5295 5646 : state.dataLoopNodes->Node(MixNode).CO2 = state.dataLoopNodes->Node(RetNode).CO2;
5296 : } else {
5297 60642 : state.dataLoopNodes->Node(MixNode).CO2 =
5298 121284 : ((state.dataLoopNodes->Node(RetNode).MassFlowRate - state.dataLoopNodes->Node(RelNode).MassFlowRate) *
5299 121284 : state.dataLoopNodes->Node(RetNode).CO2 +
5300 121284 : state.dataMixedAir->OAMixer(OAMixerNum).OAMassFlowRate * state.dataContaminantBalance->OutdoorCO2) /
5301 60642 : state.dataMixedAir->OAMixer(OAMixerNum).MixMassFlowRate;
5302 : }
5303 : }
5304 :
5305 43707297 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
5306 18233 : state.dataLoopNodes->Node(RelNode).GenContam = state.dataLoopNodes->Node(RetNode).GenContam;
5307 18233 : if (state.dataMixedAir->OAMixer(OAMixerNum).MixMassFlowRate <= VerySmallMassFlow) {
5308 1971 : state.dataLoopNodes->Node(MixNode).GenContam = state.dataLoopNodes->Node(RetNode).GenContam;
5309 : } else {
5310 16262 : state.dataLoopNodes->Node(MixNode).GenContam =
5311 32524 : ((state.dataLoopNodes->Node(RetNode).MassFlowRate - state.dataLoopNodes->Node(RelNode).MassFlowRate) *
5312 32524 : state.dataLoopNodes->Node(RetNode).GenContam +
5313 32524 : state.dataMixedAir->OAMixer(OAMixerNum).OAMassFlowRate * state.dataContaminantBalance->OutdoorGC) /
5314 16262 : state.dataMixedAir->OAMixer(OAMixerNum).MixMassFlowRate;
5315 : }
5316 : }
5317 43707297 : }
5318 :
5319 43707297 : void ReportOAMixer([[maybe_unused]] int const OAMixerNum) // unused1208
5320 : {
5321 :
5322 : // SUBROUTINE ARGUMENT DEFINITIONS
5323 43707297 : }
5324 :
5325 : // End of Sizing Section of the Module
5326 : //******************************************************************************
5327 :
5328 : // Beginning Utility Section of the Module
5329 : //******************************************************************************
5330 :
5331 607 : Array1D_int GetOAMixerNodeNumbers(EnergyPlusData &state,
5332 : std::string const &OAMixerName, // must match OA mixer names for the OA mixer type
5333 : bool &ErrorsFound // set to true if problem
5334 : )
5335 : {
5336 :
5337 : // FUNCTION INFORMATION:
5338 : // AUTHOR Richard Raustad
5339 : // DATE WRITTEN June 2006
5340 : // MODIFIED na
5341 : // RE-ENGINEERED na
5342 :
5343 : // PURPOSE OF THIS FUNCTION:
5344 : // This function looks up the given OA mixer and returns the node numbers. If
5345 : // incorrect OA mixer name is given, ErrorsFound is returned as true
5346 : // as zero.
5347 :
5348 : // Return value
5349 607 : Array1D_int OANodeNumbers(4); // return OA mixer nodes
5350 :
5351 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5352 : int WhichOAMixer;
5353 :
5354 : // Obtains and Allocates OA mixer related parameters from input file
5355 607 : if (state.dataMixedAir->GetOAMixerInputFlag) { // First time subroutine has been entered
5356 36 : GetOAMixerInputs(state);
5357 36 : state.dataMixedAir->GetOAMixerInputFlag = false;
5358 : }
5359 :
5360 607 : WhichOAMixer = UtilityRoutines::FindItemInList(OAMixerName, state.dataMixedAir->OAMixer);
5361 607 : if (WhichOAMixer != 0) {
5362 607 : OANodeNumbers(1) = state.dataMixedAir->OAMixer(WhichOAMixer).InletNode;
5363 607 : OANodeNumbers(2) = state.dataMixedAir->OAMixer(WhichOAMixer).RelNode;
5364 607 : OANodeNumbers(3) = state.dataMixedAir->OAMixer(WhichOAMixer).RetNode;
5365 607 : OANodeNumbers(4) = state.dataMixedAir->OAMixer(WhichOAMixer).MixNode;
5366 : }
5367 :
5368 607 : if (WhichOAMixer == 0) {
5369 0 : ShowSevereError(state, "GetOAMixerNodeNumbers: Could not find OA Mixer = \"" + OAMixerName + "\"");
5370 0 : ErrorsFound = true;
5371 0 : OANodeNumbers = 0;
5372 : }
5373 :
5374 607 : return OANodeNumbers;
5375 : }
5376 :
5377 30 : int GetNumOAMixers(EnergyPlusData &state)
5378 : {
5379 :
5380 : // FUNCTION INFORMATION:
5381 : // AUTHOR Linda Lawrie
5382 : // DATE WRITTEN October 2006
5383 : // MODIFIED na
5384 : // RE-ENGINEERED na
5385 :
5386 : // PURPOSE OF THIS FUNCTION:
5387 : // After making sure get input is done, the number of OA mixers is returned.
5388 :
5389 : // METHODOLOGY EMPLOYED:
5390 : // na
5391 :
5392 : // REFERENCES:
5393 : // na
5394 :
5395 : // USE STATEMENTS:
5396 : // na
5397 :
5398 : // Return value
5399 : int NumberOfOAMixers;
5400 :
5401 : // Locals
5402 : // FUNCTION ARGUMENT DEFINITIONS:
5403 :
5404 : // FUNCTION PARAMETER DEFINITIONS:
5405 : // na
5406 :
5407 : // INTERFACE BLOCK SPECIFICATIONS:
5408 : // na
5409 :
5410 : // DERIVED TYPE DEFINITIONS:
5411 : // na
5412 :
5413 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5414 : // na
5415 :
5416 30 : if (state.dataMixedAir->GetOAMixerInputFlag) { // First time subroutine has been entered
5417 0 : GetOAMixerInputs(state);
5418 0 : state.dataMixedAir->GetOAMixerInputFlag = false;
5419 : }
5420 :
5421 30 : NumberOfOAMixers = state.dataMixedAir->NumOAMixers;
5422 :
5423 30 : return NumberOfOAMixers;
5424 : }
5425 :
5426 0 : int GetNumOAControllers(EnergyPlusData &state)
5427 : {
5428 :
5429 : // FUNCTION INFORMATION:
5430 : // AUTHOR Linda Lawrie
5431 : // DATE WRITTEN October 2006
5432 : // MODIFIED na
5433 : // RE-ENGINEERED na
5434 :
5435 : // PURPOSE OF THIS FUNCTION:
5436 : // After making sure get input is done, the number of OA Controllers is returned.
5437 :
5438 : // METHODOLOGY EMPLOYED:
5439 : // na
5440 :
5441 : // REFERENCES:
5442 : // na
5443 :
5444 : // USE STATEMENTS:
5445 : // na
5446 :
5447 : // Return value
5448 : int NumberOfOAControllers;
5449 :
5450 : // Locals
5451 : // FUNCTION ARGUMENT DEFINITIONS:
5452 :
5453 : // FUNCTION PARAMETER DEFINITIONS:
5454 : // na
5455 :
5456 : // INTERFACE BLOCK SPECIFICATIONS:
5457 : // na
5458 :
5459 : // DERIVED TYPE DEFINITIONS:
5460 : // na
5461 :
5462 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5463 : // na
5464 :
5465 0 : if (state.dataMixedAir->AllocateOAControllersFlag) {
5466 : // Make sure OAControllers are allocated
5467 0 : AllocateOAControllers(state);
5468 : }
5469 :
5470 0 : NumberOfOAControllers = state.dataMixedAir->NumOAControllers;
5471 :
5472 0 : return NumberOfOAControllers;
5473 : }
5474 :
5475 15 : int GetOAMixerReliefNodeNumber(EnergyPlusData &state, int const OAMixerNum) // Which Mixer
5476 : {
5477 :
5478 : // FUNCTION INFORMATION:
5479 : // AUTHOR Linda Lawrie
5480 : // DATE WRITTEN October 2006
5481 : // MODIFIED na
5482 : // RE-ENGINEERED na
5483 :
5484 : // PURPOSE OF THIS FUNCTION:
5485 : // After making sure get input is done, the relief node number of indicated
5486 : // mixer is returned.
5487 :
5488 : // METHODOLOGY EMPLOYED:
5489 : // na
5490 :
5491 : // REFERENCES:
5492 : // na
5493 :
5494 : // Using/Aliasing
5495 :
5496 : // Return value
5497 : int ReliefNodeNumber; // Relief Node Number
5498 :
5499 : // Locals
5500 : // FUNCTION ARGUMENT DEFINITIONS:
5501 :
5502 : // FUNCTION PARAMETER DEFINITIONS:
5503 : // na
5504 :
5505 : // INTERFACE BLOCK SPECIFICATIONS:
5506 : // na
5507 :
5508 : // DERIVED TYPE DEFINITIONS:
5509 : // na
5510 :
5511 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5512 : // na
5513 :
5514 15 : if (state.dataMixedAir->GetOAMixerInputFlag) { // First time subroutine has been entered
5515 0 : GetOAMixerInputs(state);
5516 0 : state.dataMixedAir->GetOAMixerInputFlag = false;
5517 : }
5518 :
5519 15 : if (OAMixerNum > state.dataMixedAir->NumOAMixers) {
5520 0 : ShowFatalError(state,
5521 0 : format("GetOAMixerReliefNodeNumber: Requested Mixer #={}, which is > number of OA Mixers={}",
5522 : OAMixerNum,
5523 0 : state.dataMixedAir->NumOAMixers));
5524 : }
5525 :
5526 15 : ReliefNodeNumber = state.dataMixedAir->OAMixer(OAMixerNum).RelNode;
5527 :
5528 15 : return ReliefNodeNumber;
5529 : }
5530 :
5531 1026 : int GetOASysControllerListIndex(EnergyPlusData &state, int const OASysNumber) // OA Sys Number
5532 : {
5533 :
5534 : // FUNCTION INFORMATION:
5535 : // AUTHOR Fred Buhl
5536 : // DATE WRITTEN April 2007
5537 : // MODIFIED na
5538 : // RE-ENGINEERED na
5539 :
5540 : // PURPOSE OF THIS FUNCTION:
5541 : // After making sure get input is done, the Controller List index of the indicated
5542 : // OA System is returned.
5543 :
5544 : // METHODOLOGY EMPLOYED:
5545 : // na
5546 :
5547 : // REFERENCES:
5548 : // na
5549 :
5550 : // USE STATEMENTS:
5551 :
5552 : // Return value
5553 : int OASysControllerListNum; // OA Sys Controller List index
5554 :
5555 : // Locals
5556 : // FUNCTION ARGUMENT DEFINITIONS:
5557 :
5558 : // FUNCTION PARAMETER DEFINITIONS:
5559 : // na
5560 :
5561 : // INTERFACE BLOCK SPECIFICATIONS:
5562 : // na
5563 :
5564 : // DERIVED TYPE DEFINITIONS:
5565 : // na
5566 :
5567 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5568 : // na
5569 :
5570 1026 : if (state.dataMixedAir->GetOASysInputFlag) {
5571 0 : GetOutsideAirSysInputs(state);
5572 0 : state.dataMixedAir->GetOASysInputFlag = false;
5573 : }
5574 :
5575 1026 : OASysControllerListNum = state.dataAirLoop->OutsideAirSys(OASysNumber).ControllerListNum;
5576 :
5577 1026 : return OASysControllerListNum;
5578 : }
5579 :
5580 1026 : int GetOASysNumSimpControllers(EnergyPlusData &state, int const OASysNumber) // OA Sys Number
5581 : {
5582 :
5583 : // FUNCTION INFORMATION:
5584 : // AUTHOR Fred Buhl
5585 : // DATE WRITTEN April 2007
5586 : // MODIFIED na
5587 : // RE-ENGINEERED na
5588 :
5589 : // PURPOSE OF THIS FUNCTION:
5590 : // After making sure get input is done, the number of Controller:Simple objects in the
5591 : // OA System is returned.
5592 :
5593 : // METHODOLOGY EMPLOYED:
5594 : // na
5595 :
5596 : // REFERENCES:
5597 : // na
5598 :
5599 : // USE STATEMENTS:
5600 :
5601 : // Return value
5602 : int OASysNumSimpControllers; // number of Controller:Simple objects in this OA System
5603 :
5604 : // Locals
5605 : // FUNCTION ARGUMENT DEFINITIONS:
5606 :
5607 : // FUNCTION PARAMETER DEFINITIONS:
5608 : // na
5609 :
5610 : // INTERFACE BLOCK SPECIFICATIONS:
5611 : // na
5612 :
5613 : // DERIVED TYPE DEFINITIONS:
5614 : // na
5615 :
5616 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5617 : // na
5618 :
5619 1026 : if (state.dataMixedAir->GetOASysInputFlag) {
5620 0 : GetOutsideAirSysInputs(state);
5621 0 : state.dataMixedAir->GetOASysInputFlag = false;
5622 : }
5623 :
5624 1026 : OASysNumSimpControllers = state.dataAirLoop->OutsideAirSys(OASysNumber).NumSimpleControllers;
5625 :
5626 1026 : return OASysNumSimpControllers;
5627 : }
5628 :
5629 1026 : int GetOASysNumHeatingCoils(EnergyPlusData &state, int const OASysNumber) // OA Sys Number
5630 : {
5631 :
5632 : // FUNCTION INFORMATION:
5633 : // AUTHOR Fred Buhl
5634 : // DATE WRITTEN May 2007
5635 : // MODIFIED na
5636 : // RE-ENGINEERED na
5637 :
5638 : // PURPOSE OF THIS FUNCTION:
5639 : // After making sure get input is done, the number of heating coils in the
5640 : // OA System is returned.
5641 :
5642 : // METHODOLOGY EMPLOYED:
5643 : // na
5644 :
5645 : // REFERENCES:
5646 : // na
5647 :
5648 : // USE STATEMENTS:
5649 :
5650 : // Return value
5651 : int NumHeatingCoils; // number of heating coils in this OA System
5652 :
5653 : // Locals
5654 : // FUNCTION ARGUMENT DEFINITIONS:
5655 :
5656 : // FUNCTION PARAMETER DEFINITIONS:
5657 : // na
5658 :
5659 : // INTERFACE BLOCK SPECIFICATIONS:
5660 : // na
5661 :
5662 : // DERIVED TYPE DEFINITIONS:
5663 : // na
5664 :
5665 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5666 2052 : std::string CompType;
5667 2052 : std::string CompName;
5668 1026 : bool Sim(false);
5669 1026 : bool FirstHVACIteration(false);
5670 1026 : bool OAHeatingCoil(false);
5671 1026 : bool OACoolingCoil(false);
5672 : int CompNum;
5673 1026 : int AirLoopNum(0);
5674 1026 : bool OAHX(false);
5675 :
5676 1026 : if (state.dataMixedAir->GetOASysInputFlag) {
5677 0 : GetOutsideAirSysInputs(state);
5678 0 : state.dataMixedAir->GetOASysInputFlag = false;
5679 : }
5680 :
5681 1026 : NumHeatingCoils = 0;
5682 2172 : for (CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(OASysNumber).NumComponents; ++CompNum) {
5683 1146 : CompType = state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentType(CompNum);
5684 1146 : CompName = state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentName(CompNum);
5685 3438 : SimOAComponent(state,
5686 : CompType,
5687 : CompName,
5688 1146 : state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentTypeEnum(CompNum),
5689 : FirstHVACIteration,
5690 1146 : state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentIndex(CompNum),
5691 : AirLoopNum,
5692 : Sim,
5693 : OASysNumber,
5694 : OAHeatingCoil,
5695 : OACoolingCoil,
5696 : OAHX);
5697 1146 : if (OAHeatingCoil) {
5698 29 : ++NumHeatingCoils;
5699 : }
5700 : }
5701 :
5702 2052 : return NumHeatingCoils;
5703 : }
5704 :
5705 1026 : int GetOASysNumHXs(EnergyPlusData &state, int const OASysNumber)
5706 : {
5707 :
5708 : // FUNCTION INFORMATION:
5709 : // AUTHOR Fred Buhl, Rongpeng Zhang
5710 : // DATE WRITTEN Oct. 2015
5711 : // MODIFIED na
5712 : // RE-ENGINEERED na
5713 :
5714 : // PURPOSE OF THIS FUNCTION:
5715 : // After making sure get input is done, the number of heat recovery exchangers in the
5716 : // OA System is returned.
5717 :
5718 : // METHODOLOGY EMPLOYED:
5719 : // na
5720 :
5721 : // REFERENCES:
5722 : // na
5723 :
5724 : // USE STATEMENTS:
5725 :
5726 : // Return value
5727 : int NumHX; // number of heat exchangers in this OA System
5728 :
5729 : // Locals
5730 : // FUNCTION ARGUMENT DEFINITIONS:
5731 :
5732 : // FUNCTION PARAMETER DEFINITIONS:
5733 : // na
5734 :
5735 : // INTERFACE BLOCK SPECIFICATIONS:
5736 : // na
5737 :
5738 : // DERIVED TYPE DEFINITIONS:
5739 : // na
5740 :
5741 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5742 : int CompNum;
5743 : int CompNum_end;
5744 :
5745 1026 : if (state.dataMixedAir->GetOASysInputFlag) {
5746 0 : GetOutsideAirSysInputs(state);
5747 0 : state.dataMixedAir->GetOASysInputFlag = false;
5748 : }
5749 :
5750 1026 : NumHX = 0;
5751 :
5752 1026 : auto const &componentType_Num = state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentTypeEnum;
5753 2172 : for (CompNum = 1, CompNum_end = state.dataAirLoop->OutsideAirSys(OASysNumber).NumComponents; CompNum <= CompNum_end; ++CompNum) {
5754 1146 : SimAirServingZones::CompType const componentTypeNum = componentType_Num(CompNum);
5755 1146 : if (SimAirServingZones::CompType::HeatXchngr == componentTypeNum || SimAirServingZones::CompType::Desiccant == componentTypeNum) {
5756 31 : ++NumHX;
5757 : }
5758 : }
5759 :
5760 1026 : return NumHX;
5761 : }
5762 :
5763 1026 : int GetOASysNumCoolingCoils(EnergyPlusData &state, int const OASysNumber) // OA Sys Number
5764 : {
5765 :
5766 : // FUNCTION INFORMATION:
5767 : // AUTHOR Fred Buhl
5768 : // DATE WRITTEN May 2007
5769 : // MODIFIED na
5770 : // RE-ENGINEERED na
5771 :
5772 : // PURPOSE OF THIS FUNCTION:
5773 : // After making sure get input is done, the number of cooling coils in the
5774 : // OA System is returned.
5775 :
5776 : // METHODOLOGY EMPLOYED:
5777 : // na
5778 :
5779 : // REFERENCES:
5780 : // na
5781 :
5782 : // USE STATEMENTS:
5783 :
5784 : // Return value
5785 : int NumCoolingCoils; // number of cooling coils in this OA System
5786 :
5787 : // Locals
5788 : // FUNCTION ARGUMENT DEFINITIONS:
5789 :
5790 : // FUNCTION PARAMETER DEFINITIONS:
5791 : // na
5792 :
5793 : // INTERFACE BLOCK SPECIFICATIONS:
5794 : // na
5795 :
5796 : // DERIVED TYPE DEFINITIONS:
5797 : // na
5798 :
5799 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5800 2052 : std::string CompType;
5801 2052 : std::string CompName;
5802 1026 : bool Sim(false);
5803 1026 : bool FirstHVACIteration(false);
5804 1026 : bool OAHeatingCoil(false);
5805 1026 : bool OACoolingCoil(false);
5806 : int CompNum;
5807 1026 : int AirLoopNum(0);
5808 1026 : bool OAHX(false);
5809 :
5810 1026 : if (state.dataMixedAir->GetOASysInputFlag) {
5811 0 : GetOutsideAirSysInputs(state);
5812 0 : state.dataMixedAir->GetOASysInputFlag = false;
5813 : }
5814 :
5815 1026 : NumCoolingCoils = 0;
5816 2172 : for (CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(OASysNumber).NumComponents; ++CompNum) {
5817 1146 : CompType = state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentType(CompNum);
5818 1146 : CompName = state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentName(CompNum);
5819 3438 : SimOAComponent(state,
5820 : CompType,
5821 : CompName,
5822 1146 : state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentTypeEnum(CompNum),
5823 : FirstHVACIteration,
5824 1146 : state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentIndex(CompNum),
5825 : AirLoopNum,
5826 : Sim,
5827 : OASysNumber,
5828 : OAHeatingCoil,
5829 : OACoolingCoil,
5830 : OAHX);
5831 1146 : if (OACoolingCoil) {
5832 29 : ++NumCoolingCoils;
5833 : }
5834 : }
5835 :
5836 2052 : return NumCoolingCoils;
5837 : }
5838 :
5839 1026 : int GetOASystemNumber(EnergyPlusData &state, std::string const &OASysName) // OA Sys Name
5840 : {
5841 :
5842 : // FUNCTION INFORMATION:
5843 : // AUTHOR Linda Lawrie
5844 : // DATE WRITTEN October 2006
5845 : // MODIFIED na
5846 : // RE-ENGINEERED na
5847 :
5848 : // PURPOSE OF THIS FUNCTION:
5849 : // After making sure get input is done, the OA System number of indicated
5850 : // OA System is returned.
5851 :
5852 : // Return value
5853 : int OASysNumber; // OA Sys Number
5854 :
5855 1026 : if (state.dataMixedAir->GetOASysInputFlag) {
5856 202 : GetOutsideAirSysInputs(state);
5857 202 : state.dataMixedAir->GetOASysInputFlag = false;
5858 : }
5859 :
5860 1026 : OASysNumber = UtilityRoutines::FindItemInList(OASysName, state.dataAirLoop->OutsideAirSys);
5861 :
5862 1026 : return OASysNumber;
5863 : }
5864 :
5865 1026 : int FindOAMixerMatchForOASystem(EnergyPlusData &state, int const OASysNumber) // Which OA System
5866 : {
5867 :
5868 : // FUNCTION INFORMATION:
5869 : // AUTHOR Linda Lawrie
5870 : // DATE WRITTEN October 2006
5871 : // MODIFIED na
5872 : // RE-ENGINEERED na
5873 :
5874 : // PURPOSE OF THIS FUNCTION:
5875 : // After making sure get input is done, the matched mixer number is found.
5876 : // Note -- only the first is looked at for an Outside Air System.
5877 :
5878 : // Return value
5879 : int OAMixerNumber; // Mixer Number
5880 :
5881 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5882 : int OACompNum;
5883 :
5884 1026 : if (state.dataMixedAir->GetOAMixerInputFlag) {
5885 373 : GetOAMixerInputs(state);
5886 373 : state.dataMixedAir->GetOAMixerInputFlag = false;
5887 : }
5888 :
5889 1026 : OAMixerNumber = 0;
5890 1026 : if (OASysNumber > 0 && OASysNumber <= state.dataAirLoop->NumOASystems) {
5891 1144 : for (OACompNum = 1; OACompNum <= state.dataAirLoop->OutsideAirSys(OASysNumber).NumComponents; ++OACompNum) {
5892 1144 : if (UtilityRoutines::SameString(state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentType(OACompNum), "OUTDOORAIR:MIXER")) {
5893 1026 : OAMixerNumber = UtilityRoutines::FindItemInList(state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentName(OACompNum),
5894 1026 : state.dataMixedAir->OAMixer);
5895 1026 : break;
5896 : }
5897 : }
5898 : }
5899 :
5900 1026 : return OAMixerNumber;
5901 : }
5902 :
5903 334 : int GetOAMixerIndex(EnergyPlusData &state, std::string const &OAMixerName) // Which Mixer
5904 : {
5905 :
5906 : // FUNCTION INFORMATION:
5907 : // AUTHOR Linda Lawrie
5908 : // DATE WRITTEN December 2010
5909 : // MODIFIED na
5910 : // RE-ENGINEERED na
5911 :
5912 : // PURPOSE OF THIS FUNCTION:
5913 : // After making sure get input is done, the mixer index of indicated
5914 : // mixer is returned.
5915 :
5916 : // Return value
5917 : int OAMixerIndex; // Mixer Index
5918 :
5919 334 : if (state.dataMixedAir->GetOAMixerInputFlag) {
5920 24 : GetOAMixerInputs(state);
5921 24 : state.dataMixedAir->GetOAMixerInputFlag = false;
5922 : }
5923 :
5924 334 : OAMixerIndex = UtilityRoutines::FindItem(OAMixerName, state.dataMixedAir->OAMixer);
5925 :
5926 334 : if (OAMixerIndex == 0) {
5927 0 : ShowSevereError(state, "GetOAMixerIndex: Could not find OutdoorAir:Mixer, Name=\"" + OAMixerName + "\"");
5928 : }
5929 :
5930 334 : return OAMixerIndex;
5931 : }
5932 :
5933 1034 : int GetOAMixerInletNodeNumber(EnergyPlusData &state, int const OAMixerNumber) // Which Mixer
5934 : {
5935 :
5936 : // FUNCTION INFORMATION:
5937 : // AUTHOR Linda Lawrie
5938 : // DATE WRITTEN October 2006
5939 : // MODIFIED na
5940 : // RE-ENGINEERED na
5941 :
5942 : // PURPOSE OF THIS FUNCTION:
5943 : // After making sure get input is done, the mixer inlet node number of indicated
5944 : // mixer is returned.
5945 :
5946 : // METHODOLOGY EMPLOYED:
5947 : // na
5948 :
5949 : // REFERENCES:
5950 : // na
5951 :
5952 : // USE STATEMENTS:
5953 : // na
5954 :
5955 : // Return value
5956 : int OAMixerInletNodeNumber; // Mixer Inlet Node Number
5957 :
5958 : // Locals
5959 : // FUNCTION ARGUMENT DEFINITIONS:
5960 :
5961 : // FUNCTION PARAMETER DEFINITIONS:
5962 : // na
5963 :
5964 : // INTERFACE BLOCK SPECIFICATIONS:
5965 : // na
5966 :
5967 : // DERIVED TYPE DEFINITIONS:
5968 : // na
5969 :
5970 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5971 : // na
5972 :
5973 1034 : if (state.dataMixedAir->GetOAMixerInputFlag) {
5974 0 : GetOAMixerInputs(state);
5975 0 : state.dataMixedAir->GetOAMixerInputFlag = false;
5976 : }
5977 :
5978 1034 : OAMixerInletNodeNumber = 0;
5979 1034 : if (OAMixerNumber > 0 && OAMixerNumber <= state.dataMixedAir->NumOAMixers) {
5980 1034 : OAMixerInletNodeNumber = state.dataMixedAir->OAMixer(OAMixerNumber).InletNode;
5981 : }
5982 :
5983 1034 : return OAMixerInletNodeNumber;
5984 : }
5985 :
5986 40158 : int GetOAMixerReturnNodeNumber(EnergyPlusData &state, int const OAMixerNumber) // Which Mixer
5987 : {
5988 :
5989 : // FUNCTION INFORMATION:
5990 : // AUTHOR Brent Griffith
5991 : // DATE WRITTEN December 2006
5992 : // MODIFIED na
5993 : // RE-ENGINEERED na
5994 :
5995 : // PURPOSE OF THIS FUNCTION:
5996 : // After making sure get input is done, the mixer return node number of indicated
5997 : // mixer is returned.
5998 :
5999 : // METHODOLOGY EMPLOYED:
6000 : // followed Linda Lawrie's GetOAMixerInletNodeNumber
6001 :
6002 : // REFERENCES:
6003 : // na
6004 :
6005 : // USE STATEMENTS:
6006 : // na
6007 :
6008 : // Return value
6009 : int OAMixerReturnNodeNumber; // Mixer Inlet Node Number
6010 :
6011 : // Locals
6012 : // FUNCTION ARGUMENT DEFINITIONS:
6013 :
6014 : // FUNCTION PARAMETER DEFINITIONS:
6015 : // na
6016 :
6017 : // INTERFACE BLOCK SPECIFICATIONS:
6018 : // na
6019 :
6020 : // DERIVED TYPE DEFINITIONS:
6021 : // na
6022 :
6023 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
6024 : // na
6025 :
6026 40158 : if (state.dataMixedAir->GetOAMixerInputFlag) {
6027 0 : GetOAMixerInputs(state);
6028 0 : state.dataMixedAir->GetOAMixerInputFlag = false;
6029 : }
6030 :
6031 40158 : OAMixerReturnNodeNumber = 0;
6032 40158 : if (OAMixerNumber > 0 && OAMixerNumber <= state.dataMixedAir->NumOAMixers) {
6033 40158 : OAMixerReturnNodeNumber = state.dataMixedAir->OAMixer(OAMixerNumber).RetNode;
6034 : }
6035 :
6036 40158 : return OAMixerReturnNodeNumber;
6037 : }
6038 :
6039 40158 : int GetOAMixerMixedNodeNumber(EnergyPlusData &state, int const OAMixerNumber) // Which Mixer
6040 : {
6041 :
6042 : // FUNCTION INFORMATION:
6043 : // AUTHOR Brent Griffith
6044 : // DATE WRITTEN December 2006
6045 : // MODIFIED na
6046 : // RE-ENGINEERED na
6047 :
6048 : // PURPOSE OF THIS FUNCTION:
6049 : // After making sure get input is done, the mixer mixed air node number of indicated
6050 : // mixer is returned.
6051 :
6052 : // METHODOLOGY EMPLOYED:
6053 : // followed Linda Lawrie's GetOAMixerInletNodeNumber
6054 :
6055 : // REFERENCES:
6056 : // na
6057 :
6058 : // USE STATEMENTS:
6059 : // na
6060 :
6061 : // Return value
6062 : int OAMixerMixedNodeNumber; // Mixer Inlet Node Number
6063 :
6064 : // Locals
6065 : // FUNCTION ARGUMENT DEFINITIONS:
6066 :
6067 : // FUNCTION PARAMETER DEFINITIONS:
6068 : // na
6069 :
6070 : // INTERFACE BLOCK SPECIFICATIONS:
6071 : // na
6072 :
6073 : // DERIVED TYPE DEFINITIONS:
6074 : // na
6075 :
6076 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
6077 : // na
6078 :
6079 40158 : if (state.dataMixedAir->GetOAMixerInputFlag) {
6080 0 : GetOAMixerInputs(state);
6081 0 : state.dataMixedAir->GetOAMixerInputFlag = false;
6082 : }
6083 :
6084 40158 : OAMixerMixedNodeNumber = 0;
6085 40158 : if (OAMixerNumber > 0 && OAMixerNumber <= state.dataMixedAir->NumOAMixers) {
6086 40158 : OAMixerMixedNodeNumber = state.dataMixedAir->OAMixer(OAMixerNumber).MixNode;
6087 : }
6088 :
6089 40158 : return OAMixerMixedNodeNumber;
6090 : }
6091 :
6092 822 : bool CheckForControllerWaterCoil(EnergyPlusData &state,
6093 : std::string const &ControllerType, // should be passed in as UPPERCASE
6094 : std::string const &ControllerName // should be passed in as UPPERCASE
6095 : )
6096 : {
6097 :
6098 : // FUNCTION INFORMATION:
6099 : // AUTHOR Linda Lawrie
6100 : // DATE WRITTEN May 2009
6101 : // MODIFIED na
6102 : // RE-ENGINEERED na
6103 :
6104 : // PURPOSE OF THIS FUNCTION:
6105 : // This routine checks the controller list for existance of the
6106 : // reference coil.
6107 :
6108 : // Return value
6109 : bool OnControllerList; // true if found on controller list
6110 :
6111 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
6112 : int Num;
6113 : int CompNum;
6114 :
6115 822 : if (state.dataMixedAir->GetOASysInputFlag) {
6116 273 : GetOutsideAirSysInputs(state);
6117 273 : state.dataMixedAir->GetOASysInputFlag = false;
6118 : }
6119 :
6120 822 : OnControllerList = false;
6121 :
6122 5418 : for (Num = 1; Num <= state.dataMixedAir->NumControllerLists; ++Num) {
6123 11950 : for (CompNum = 1; CompNum <= state.dataMixedAir->ControllerLists(Num).NumControllers; ++CompNum) {
6124 :
6125 8176 : if (!UtilityRoutines::SameString(state.dataMixedAir->ControllerLists(Num).ControllerType(CompNum), ControllerType)) continue;
6126 5789 : if (!UtilityRoutines::SameString(state.dataMixedAir->ControllerLists(Num).ControllerName(CompNum), ControllerName)) continue;
6127 822 : OnControllerList = true;
6128 822 : break;
6129 : }
6130 : }
6131 :
6132 822 : return OnControllerList;
6133 : }
6134 :
6135 769 : void CheckControllerLists(EnergyPlusData &state, bool &ErrFound)
6136 : {
6137 :
6138 : // SUBROUTINE INFORMATION:
6139 : // AUTHOR Linda Lawrie
6140 : // DATE WRITTEN May 2009
6141 : // MODIFIED na
6142 : // RE-ENGINEERED na
6143 :
6144 : // PURPOSE OF THIS SUBROUTINE:
6145 : // This routine checks for a "dangling" controller list (AirLoopHVAC:ControllerList).
6146 : // It must be either found on a AirLoopHVAC or AirLoopHVAC:OutdoorAirSystem.
6147 :
6148 : // Using/Aliasing
6149 :
6150 : // SUBROUTINE PARAMETER DEFINITIONS:
6151 769 : static std::string const CurrentModuleObject("AirLoopHVAC:ControllerList");
6152 769 : static std::string const AirLoopObject("AirLoopHVAC");
6153 :
6154 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6155 : int NumAlphas;
6156 : int NumNumbers;
6157 : int NumControllers;
6158 : int NumAirLoop;
6159 1538 : std::string ControllerListName;
6160 : int Item;
6161 : int IOStat;
6162 : int Found;
6163 : int Count;
6164 : int Loop;
6165 1538 : std::string AirLoopName;
6166 :
6167 769 : if (state.dataMixedAir->GetOASysInputFlag) {
6168 246 : GetOutsideAirSysInputs(state);
6169 246 : state.dataMixedAir->GetOASysInputFlag = false;
6170 : }
6171 :
6172 769 : NumControllers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
6173 769 : NumAirLoop = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, AirLoopObject);
6174 769 : AirLoopName = "";
6175 :
6176 2206 : for (Item = 1; Item <= NumControllers; ++Item) {
6177 :
6178 4311 : state.dataInputProcessing->inputProcessor->getObjectItem(
6179 2874 : state, CurrentModuleObject, Item, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNumbers, IOStat);
6180 1437 : ControllerListName = state.dataIPShortCut->cAlphaArgs(1);
6181 1437 : Count = 0;
6182 :
6183 : // Check AirLoopHVAC -- brute force, get each AirLoopHVAC
6184 :
6185 14123 : for (Loop = 1; Loop <= NumAirLoop; ++Loop) {
6186 38058 : state.dataInputProcessing->inputProcessor->getObjectItem(
6187 25372 : state, AirLoopObject, Loop, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNumbers, IOStat);
6188 12686 : if (state.dataIPShortCut->cAlphaArgs(2) != ControllerListName) continue;
6189 415 : ++Count;
6190 415 : if (Count == 1) AirLoopName = state.dataIPShortCut->cAlphaArgs(1);
6191 : }
6192 :
6193 : // Now check AirLoopHVAC and AirLoopHVAC:OutdoorAirSystem
6194 1437 : Found = 0;
6195 1437 : if (state.dataAirLoop->NumOASystems > 0) {
6196 1356 : Found = UtilityRoutines::FindItemInList(ControllerListName, state.dataAirLoop->OutsideAirSys, &OutsideAirSysProps::ControllerListName);
6197 1356 : if (Found > 0) ++Count;
6198 : }
6199 :
6200 1437 : if (Count == 0) {
6201 0 : ShowSevereError(state,
6202 0 : CurrentModuleObject + "=\"" + ControllerListName +
6203 : "\" is not referenced on a AirLoopHVAC or AirLoopHVAC:OutdoorAirSystem object.");
6204 0 : ErrFound = true;
6205 1437 : } else if (Count > 1) {
6206 0 : ShowSevereError(state,
6207 0 : CurrentModuleObject + "=\"" + ControllerListName +
6208 : "\" has too many references on AirLoopHVAC or AirLoopHVAC:OutdoorAirSystem objects.");
6209 0 : if (Found > 0) {
6210 0 : ShowContinueError(state, "...AirLoopHVAC:OutdoorAirSystem=\"" + state.dataAirLoop->OutsideAirSys(Found).Name + "\".");
6211 : }
6212 0 : ShowContinueError(state, "...also on AirLoopHVAC=\"" + AirLoopName + "\".");
6213 0 : ErrFound = true;
6214 : }
6215 : }
6216 769 : }
6217 :
6218 104 : void CheckOAControllerName(
6219 : EnergyPlusData &state, std::string &OAControllerName, std::string const &ObjectType, std::string const &FieldName, bool &ErrorsFound)
6220 : {
6221 :
6222 : // SUBROUTINE INFORMATION:
6223 : // AUTHOR Linda Lawrie
6224 : // DATE WRITTEN October 2006
6225 : // MODIFIED na
6226 : // RE-ENGINEERED na
6227 :
6228 : // PURPOSE OF THIS SUBROUTINE:
6229 : // When OA Controller data is gotten from other routines, must check to make sure
6230 : // new name doesn't duplicate. (Essentially a pass through to call Verify Name)
6231 : // Currently, this is only called from HVACStandAlongERV::GetStandaloneERV()
6232 :
6233 104 : if (state.dataMixedAir->AllocateOAControllersFlag) {
6234 : // Make sure OAControllers are allocated
6235 3 : AllocateOAControllers(state);
6236 : }
6237 :
6238 208 : GlobalNames::VerifyUniqueInterObjectName(
6239 104 : state, state.dataMixedAir->OAControllerUniqueNames, OAControllerName, ObjectType, FieldName, ErrorsFound);
6240 104 : }
6241 :
6242 14592647 : void OAControllerProps::Checksetpoints(EnergyPlusData &state,
6243 : Real64 const OutAirMinFrac, // Local variable used to calculate min OA fraction
6244 : Real64 &OutAirSignal, // Used to set OA mass flow rate
6245 : bool &EconomizerOperationFlag // logical used to show economizer status
6246 : )
6247 : {
6248 :
6249 : // SUBROUTINE INFORMATION:
6250 : // AUTHOR Amit bhansali
6251 : // DATE WRITTEN August 2008?
6252 : // MODIFIED na
6253 : // RE-ENGINEERED na
6254 :
6255 : // PURPOSE OF THIS SUBROUTINE:
6256 : // This subroutine checks the setpoints of the upper limits of temperatures, limit enthalpy
6257 : // Limit dew point, Enthalpy curve
6258 :
6259 : // METHODOLOGY EMPLOYED:
6260 : // na
6261 :
6262 : // REFERENCES:
6263 : // na
6264 :
6265 : // Using/Aliasing
6266 : using Curve::CurveValue;
6267 : using Psychrometrics::PsyTdpFnWPb;
6268 :
6269 : // Locals
6270 : // SUBROUTINE ARGUMENT DEFINITIONS:
6271 :
6272 : // SUBROUTINE PARAMETER DEFINITIONS:
6273 : // na
6274 :
6275 : // INTERFACE BLOCK SPECIFICATIONS:
6276 : // na
6277 :
6278 : // DERIVED TYPE DEFINITIONS:
6279 : // na
6280 :
6281 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6282 : Real64 OADPTemp; // Dew Point Temperature calculation
6283 :
6284 14592647 : if (this->TempLim != BlankNumeric && this->OATemp > this->TempLim) {
6285 5613950 : OutAirSignal = OutAirMinFrac;
6286 5613950 : EconomizerOperationFlag = false;
6287 : }
6288 : // Outside air enthalpy limit
6289 14592647 : if (this->EnthLim != BlankNumeric && this->OAEnth > this->EnthLim) {
6290 5219287 : OutAirSignal = OutAirMinFrac;
6291 5219287 : EconomizerOperationFlag = false;
6292 : }
6293 :
6294 14592647 : if (this->DPTempLim != BlankNumeric) {
6295 94609 : OADPTemp = PsyTdpFnWPb(state, this->OAHumRat, this->OAPress);
6296 94609 : if (OADPTemp > this->DPTempLim) {
6297 46695 : OutAirSignal = OutAirMinFrac;
6298 46695 : EconomizerOperationFlag = false;
6299 : }
6300 : }
6301 :
6302 14592647 : if (this->EnthalpyCurvePtr > 0) {
6303 65324 : if (this->OAHumRat > CurveValue(state, this->EnthalpyCurvePtr, this->OATemp)) {
6304 36603 : OutAirSignal = OutAirMinFrac;
6305 36603 : EconomizerOperationFlag = false;
6306 : }
6307 : }
6308 14592647 : }
6309 :
6310 583 : int GetNumOASystems(EnergyPlusData &state)
6311 : {
6312 :
6313 : // FUNCTION INFORMATION:
6314 : // AUTHOR Linda Lawrie
6315 : // DATE WRITTEN November 2010
6316 : // MODIFIED na
6317 : // RE-ENGINEERED na
6318 :
6319 : // PURPOSE OF THIS FUNCTION:
6320 : // Get Number of OA Systems, After making sure get input is done
6321 :
6322 : // METHODOLOGY EMPLOYED:
6323 : // na
6324 :
6325 : // REFERENCES:
6326 : // na
6327 :
6328 : // USE STATEMENTS:
6329 : // na
6330 :
6331 : // Return value
6332 : int NumberOfOASystems; // Number of OA Systems
6333 :
6334 : // Locals
6335 : // FUNCTION ARGUMENT DEFINITIONS:
6336 :
6337 : // FUNCTION PARAMETER DEFINITIONS:
6338 : // na
6339 :
6340 : // INTERFACE BLOCK SPECIFICATIONS:
6341 : // na
6342 :
6343 : // DERIVED TYPE DEFINITIONS:
6344 : // na
6345 :
6346 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
6347 : // na
6348 :
6349 583 : if (state.dataMixedAir->GetOASysInputFlag) {
6350 49 : GetOutsideAirSysInputs(state);
6351 49 : state.dataMixedAir->GetOASysInputFlag = false;
6352 : }
6353 :
6354 583 : NumberOfOASystems = state.dataAirLoop->NumOASystems;
6355 :
6356 583 : return NumberOfOASystems;
6357 : }
6358 :
6359 1027 : int GetOACompListNumber(EnergyPlusData &state, int const OASysNum) // OA Sys Number
6360 : {
6361 :
6362 : // FUNCTION INFORMATION:
6363 : // AUTHOR Heejin Cho
6364 : // DATE WRITTEN November 2010
6365 : // MODIFIED na
6366 : // RE-ENGINEERED na
6367 :
6368 : // PURPOSE OF THIS FUNCTION:
6369 : // After making sure get input is done, the OA System number of indicated
6370 : // OA System is returned.
6371 :
6372 : // Return value
6373 : int NumOACompList; // OA Comp Number
6374 :
6375 1027 : if (state.dataMixedAir->GetOASysInputFlag) {
6376 0 : GetOutsideAirSysInputs(state);
6377 0 : state.dataMixedAir->GetOASysInputFlag = false;
6378 : }
6379 :
6380 1027 : NumOACompList = state.dataAirLoop->OutsideAirSys(OASysNum).NumComponents;
6381 :
6382 1027 : return NumOACompList;
6383 : }
6384 :
6385 55 : std::string GetOACompName(EnergyPlusData &state,
6386 : int const OASysNum, // OA Sys Number
6387 : int const InListNum // In-list Number
6388 : )
6389 : {
6390 :
6391 : // FUNCTION INFORMATION:
6392 : // AUTHOR Heejin Cho
6393 : // DATE WRITTEN November 2010
6394 : // MODIFIED na
6395 : // RE-ENGINEERED na
6396 :
6397 : // PURPOSE OF THIS FUNCTION:
6398 : // After making sure get input is done, the number of heating coils in the
6399 : // OA System is returned.
6400 :
6401 : // METHODOLOGY EMPLOYED:
6402 : // na
6403 :
6404 : // REFERENCES:
6405 : // na
6406 :
6407 : // USE STATEMENTS:
6408 :
6409 : // Return value
6410 55 : std::string OACompName;
6411 :
6412 : // Locals
6413 : // FUNCTION ARGUMENT DEFINITIONS:
6414 : // FUNCTION PARAMETER DEFINITIONS:
6415 : // na
6416 :
6417 : // INTERFACE BLOCK SPECIFICATIONS:
6418 : // na
6419 :
6420 : // DERIVED TYPE DEFINITIONS:
6421 : // na
6422 :
6423 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
6424 :
6425 55 : if (state.dataMixedAir->GetOASysInputFlag) {
6426 0 : GetOutsideAirSysInputs(state);
6427 0 : state.dataMixedAir->GetOASysInputFlag = false;
6428 : }
6429 :
6430 55 : OACompName = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(InListNum);
6431 :
6432 55 : return OACompName;
6433 : }
6434 :
6435 55 : std::string GetOACompType(EnergyPlusData &state,
6436 : int const OASysNum, // OA Sys Number
6437 : int const InListNum // In-list Number
6438 : )
6439 : {
6440 :
6441 : // FUNCTION INFORMATION:
6442 : // AUTHOR Heejin Cho
6443 : // DATE WRITTEN November 2010
6444 : // MODIFIED na
6445 : // RE-ENGINEERED na
6446 :
6447 : // PURPOSE OF THIS FUNCTION:
6448 : // After making sure get input is done, the number of heating coils in the
6449 : // OA System is returned.
6450 :
6451 : // METHODOLOGY EMPLOYED:
6452 : // na
6453 :
6454 : // REFERENCES:
6455 : // na
6456 :
6457 : // USE STATEMENTS:
6458 :
6459 : // Return value
6460 55 : std::string OACompType;
6461 :
6462 : // Locals
6463 : // FUNCTION ARGUMENT DEFINITIONS:
6464 : // FUNCTION PARAMETER DEFINITIONS:
6465 : // na
6466 :
6467 : // INTERFACE BLOCK SPECIFICATIONS:
6468 : // na
6469 :
6470 : // DERIVED TYPE DEFINITIONS:
6471 : // na
6472 :
6473 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
6474 :
6475 55 : if (state.dataMixedAir->GetOASysInputFlag) {
6476 0 : GetOutsideAirSysInputs(state);
6477 0 : state.dataMixedAir->GetOASysInputFlag = false;
6478 : }
6479 :
6480 55 : OACompType = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(InListNum);
6481 :
6482 55 : return OACompType;
6483 : }
6484 :
6485 1149 : SimAirServingZones::CompType GetOACompTypeNum(EnergyPlusData &state,
6486 : int const OASysNum, // OA Sys Number
6487 : int const InListNum // In-list Number
6488 : )
6489 : {
6490 :
6491 : // FUNCTION INFORMATION:
6492 : // AUTHOR Heejin Cho
6493 : // DATE WRITTEN November 2010
6494 : // MODIFIED na
6495 : // RE-ENGINEERED na
6496 :
6497 : // PURPOSE OF THIS FUNCTION:
6498 : // After making sure get input is done, the number of heating coils in the
6499 : // OA System is returned.
6500 :
6501 : // METHODOLOGY EMPLOYED:
6502 : // na
6503 :
6504 : // REFERENCES:
6505 : // na
6506 :
6507 : // USE STATEMENTS:
6508 :
6509 : // Return value
6510 : SimAirServingZones::CompType OACompTypeNum;
6511 :
6512 : // Locals
6513 : // FUNCTION ARGUMENT DEFINITIONS:
6514 : // FUNCTION PARAMETER DEFINITIONS:
6515 : // na
6516 :
6517 : // INTERFACE BLOCK SPECIFICATIONS:
6518 : // na
6519 :
6520 : // DERIVED TYPE DEFINITIONS:
6521 : // na
6522 :
6523 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
6524 :
6525 1149 : if (state.dataMixedAir->GetOASysInputFlag) {
6526 0 : GetOutsideAirSysInputs(state);
6527 0 : state.dataMixedAir->GetOASysInputFlag = false;
6528 : }
6529 :
6530 1149 : OACompTypeNum = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(InListNum);
6531 :
6532 1149 : return OACompTypeNum;
6533 : }
6534 :
6535 4 : int GetOAMixerNumber(EnergyPlusData &state, std::string const &OAMixerName // must match OA mixer names for the OA mixer type
6536 : )
6537 : {
6538 :
6539 : // FUNCTION INFORMATION:
6540 : // AUTHOR Lixing Gu
6541 : // DATE WRITTEN Feb. 2018
6542 :
6543 : // PURPOSE OF THIS FUNCTION:
6544 : // This function looks up the given OA mixer and returns the OAMixer number. If
6545 : // incorrect OA mixer name is given, ErrorsFound is returned as true
6546 :
6547 : int WhichOAMixer;
6548 :
6549 : // Obtains and Allocates OA mixer related parameters from input file
6550 4 : if (state.dataMixedAir->GetOAMixerInputFlag) { // First time subroutine has been entered
6551 2 : GetOAMixerInputs(state);
6552 2 : state.dataMixedAir->GetOAMixerInputFlag = false;
6553 : }
6554 :
6555 4 : WhichOAMixer = UtilityRoutines::FindItemInList(OAMixerName, state.dataMixedAir->OAMixer);
6556 :
6557 4 : return WhichOAMixer;
6558 : }
6559 : // End of Utility Section of the Module
6560 : //******************************************************************************
6561 :
6562 2313 : } // namespace EnergyPlus::MixedAir
|