Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Array1D.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <AirflowNetwork/Elements.hpp>
57 : #include <AirflowNetwork/Solver.hpp>
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataDefineEquip.hh>
60 : #include <EnergyPlus/DataEnvironment.hh>
61 : #include <EnergyPlus/DataHVACGlobals.hh>
62 : #include <EnergyPlus/DataHeatBalFanSys.hh>
63 : #include <EnergyPlus/DataHeatBalance.hh>
64 : #include <EnergyPlus/DataIPShortCuts.hh>
65 : #include <EnergyPlus/DataLoopNode.hh>
66 : #include <EnergyPlus/DataSurfaces.hh>
67 : #include <EnergyPlus/DataZoneEquipment.hh>
68 : #include <EnergyPlus/General.hh>
69 : #include <EnergyPlus/HeatBalanceInternalHeatGains.hh>
70 : #include <EnergyPlus/HybridModel.hh>
71 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
72 : #include <EnergyPlus/InternalHeatGains.hh>
73 : #include <EnergyPlus/OutputProcessor.hh>
74 : #include <EnergyPlus/Psychrometrics.hh>
75 : #include <EnergyPlus/ScheduleManager.hh>
76 : #include <EnergyPlus/UtilityRoutines.hh>
77 : #include <EnergyPlus/ZoneContaminantPredictorCorrector.hh>
78 : #include <EnergyPlus/ZonePlenum.hh>
79 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
80 :
81 : namespace EnergyPlus::ZoneContaminantPredictorCorrector {
82 :
83 : // MODULE INFORMATION:
84 : // AUTHOR Lixing Gu
85 : // DATE WRITTEN May, 2010
86 :
87 : // PURPOSE OF THIS MODULE:
88 : // This module contains routines to predict and correct zone contaminants.
89 : // also includes zone contaminant controlling
90 :
91 : // METHODOLOGY EMPLOYED:
92 : // Similar approach to ZoneTempPredictorCorrector
93 :
94 : // Using/Aliasing
95 : using namespace DataHeatBalance;
96 : using namespace Psychrometrics;
97 : using namespace HybridModel;
98 :
99 0 : void ManageZoneContaminanUpdates(EnergyPlusData &state,
100 : DataHeatBalFanSys::PredictorCorrectorCtrl const UpdateType, // Can be iGetZoneSetPoints, iPredictStep, iCorrectStep
101 : bool const ShortenTimeStepSys,
102 : bool const UseZoneTimeStepHistory, // if true then use zone timestep history, if false use system time step
103 : Real64 const PriorTimeStep // the old value for timestep length is passed for possible use in interpolating
104 : )
105 : {
106 :
107 : // SUBROUTINE INFORMATION
108 : // AUTHOR Lixing Gu
109 : // DATE WRITTEN July, 2010
110 :
111 : // PURPOSE OF THIS SUBROUTINE:
112 : // This subroutine predicts or corrects the zone air temperature
113 : // depending on the simulation status and determines the correct
114 : // temperature setpoint for each zone from the schedule manager.
115 : // This module is revised from subroutine ManageZoneAirUpdates in
116 : // ZoneTempPredictorCorrector module.
117 :
118 0 : if (state.dataZoneContaminantPredictorCorrector->GetZoneAirContamInputFlag) {
119 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) GetZoneContaminanInputs(state);
120 0 : GetZoneContaminanSetPoints(state);
121 0 : state.dataZoneContaminantPredictorCorrector->GetZoneAirContamInputFlag = false;
122 : }
123 :
124 0 : if (!state.dataContaminantBalance->Contaminant.SimulateContaminants) return;
125 :
126 0 : switch (UpdateType) {
127 0 : case DataHeatBalFanSys::PredictorCorrectorCtrl::GetZoneSetPoints: {
128 0 : InitZoneContSetPoints(state);
129 0 : } break;
130 0 : case DataHeatBalFanSys::PredictorCorrectorCtrl::PredictStep: {
131 0 : PredictZoneContaminants(state, ShortenTimeStepSys, UseZoneTimeStepHistory, PriorTimeStep);
132 0 : } break;
133 0 : case DataHeatBalFanSys::PredictorCorrectorCtrl::CorrectStep: {
134 0 : CorrectZoneContaminants(state, UseZoneTimeStepHistory);
135 0 : } break;
136 0 : case DataHeatBalFanSys::PredictorCorrectorCtrl::RevertZoneTimestepHistories: {
137 0 : RevertZoneTimestepHistories(state);
138 0 : } break;
139 0 : case DataHeatBalFanSys::PredictorCorrectorCtrl::PushZoneTimestepHistories: {
140 0 : PushZoneTimestepHistories(state);
141 0 : } break;
142 0 : case DataHeatBalFanSys::PredictorCorrectorCtrl::PushSystemTimestepHistories: {
143 0 : PushSystemTimestepHistories(state);
144 0 : } break;
145 0 : default:
146 0 : break;
147 : }
148 : }
149 :
150 0 : void GetZoneContaminanInputs(EnergyPlusData &state)
151 : {
152 :
153 : // SUBROUTINE INFORMATION:
154 : // AUTHOR Lixing Gu
155 : // DATE WRITTEN Dec. 2011
156 :
157 : // PURPOSE OF THIS SUBROUTINE:
158 : // This subroutine gets the inputs related to generic contaminant internal gain.
159 :
160 : // METHODOLOGY EMPLOYED:
161 : // Uses the status flags to trigger events.
162 :
163 : // SUBROUTINE PARAMETER DEFINITIONS:
164 : static constexpr std::string_view RoutineName("GetSourcesAndSinks: ");
165 : static constexpr std::string_view routineName = "GetSourcesAndSinks";
166 :
167 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
168 0 : Array1D_string AlphaName;
169 0 : Array1D<Real64> IHGNumbers;
170 : int IOStat;
171 : int Loop;
172 : int ZonePtr;
173 0 : bool ErrorsFound(false);
174 0 : Array1D_bool RepVarSet;
175 0 : std::string CurrentModuleObject;
176 :
177 0 : RepVarSet.dimension(state.dataGlobal->NumOfZones, true);
178 :
179 0 : int NumAlpha = 0;
180 0 : int NumNumber = 0;
181 0 : int MaxAlpha = -100;
182 0 : int MaxNumber = -100;
183 0 : CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:Constant";
184 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
185 0 : MaxAlpha = max(MaxAlpha, NumAlpha);
186 0 : MaxNumber = max(MaxNumber, NumNumber);
187 0 : CurrentModuleObject = "SurfaceContaminantSourceAndSink:Generic:PressureDriven";
188 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
189 0 : MaxAlpha = max(MaxAlpha, NumAlpha);
190 0 : MaxNumber = max(MaxNumber, NumNumber);
191 0 : CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:CutoffModel";
192 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
193 0 : MaxAlpha = max(MaxAlpha, NumAlpha);
194 0 : MaxNumber = max(MaxNumber, NumNumber);
195 0 : CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:DecaySource";
196 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
197 0 : MaxAlpha = max(MaxAlpha, NumAlpha);
198 0 : MaxNumber = max(MaxNumber, NumNumber);
199 0 : CurrentModuleObject = "SurfaceContaminantSourceAndSink:Generic:BoundaryLayerDiffusion";
200 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
201 0 : MaxAlpha = max(MaxAlpha, NumAlpha);
202 0 : MaxNumber = max(MaxNumber, NumNumber);
203 0 : CurrentModuleObject = "SurfaceContaminantSourceAndSink:Generic:DepositionVelocitySink";
204 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
205 0 : MaxAlpha = max(MaxAlpha, NumAlpha);
206 0 : MaxNumber = max(MaxNumber, NumNumber);
207 0 : CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:DepositionRateSink";
208 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
209 0 : MaxAlpha = max(MaxAlpha, NumAlpha);
210 0 : MaxNumber = max(MaxNumber, NumNumber);
211 0 : IHGNumbers.allocate(MaxNumber);
212 0 : AlphaName.allocate(MaxAlpha);
213 0 : IHGNumbers = 0.0;
214 0 : AlphaName = "";
215 :
216 0 : CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:Constant";
217 0 : int TotGCGenConstant = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
218 0 : state.dataContaminantBalance->ZoneContamGenericConstant.allocate(TotGCGenConstant);
219 :
220 0 : for (Loop = 1; Loop <= TotGCGenConstant; ++Loop) {
221 0 : AlphaName = "";
222 0 : IHGNumbers = 0.0;
223 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
224 : CurrentModuleObject,
225 : Loop,
226 : AlphaName,
227 : NumAlpha,
228 : IHGNumbers,
229 : NumNumber,
230 : IOStat,
231 0 : state.dataIPShortCut->lNumericFieldBlanks,
232 0 : state.dataIPShortCut->lAlphaFieldBlanks,
233 0 : state.dataIPShortCut->cAlphaFieldNames,
234 0 : state.dataIPShortCut->cNumericFieldNames);
235 :
236 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
237 :
238 0 : Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
239 :
240 0 : auto &contam = state.dataContaminantBalance->ZoneContamGenericConstant(Loop);
241 0 : contam.Name = AlphaName(1);
242 0 : contam.ZoneName = AlphaName(2);
243 0 : contam.ActualZoneNum = Util::FindItemInList(AlphaName(2), state.dataHeatBal->Zone);
244 0 : if (contam.ActualZoneNum == 0) {
245 0 : ShowSevereError(state,
246 0 : format("{}{}=\"{}\", invalid {} entered={}",
247 : RoutineName,
248 : CurrentModuleObject,
249 : AlphaName(1),
250 0 : state.dataIPShortCut->cAlphaFieldNames(2),
251 : AlphaName(2)));
252 0 : ErrorsFound = true;
253 : }
254 :
255 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
256 0 : ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
257 0 : ErrorsFound = true;
258 0 : } else if ((contam.generateRateSched = Sched::GetSchedule(state, AlphaName(3))) == nullptr) {
259 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3));
260 0 : ErrorsFound = true;
261 0 : } else if (!contam.generateRateSched->checkMinVal(state, Clusive::In, 0.0)) {
262 0 : Sched::ShowSevereBadMin(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3), Clusive::In, 0.0);
263 0 : ErrorsFound = true;
264 : }
265 :
266 0 : contam.GenerateRate = IHGNumbers(1);
267 0 : contam.RemovalCoef = IHGNumbers(2);
268 :
269 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
270 0 : ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4));
271 0 : ErrorsFound = true;
272 0 : } else if ((contam.removalCoefSched = Sched::GetSchedule(state, AlphaName(4))) == nullptr) {
273 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4), AlphaName(4));
274 0 : ErrorsFound = true;
275 0 : } else if (!contam.removalCoefSched->checkMinVal(state, Clusive::In, 0.0)) {
276 0 : Sched::ShowSevereBadMin(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3), Clusive::In, 0.0);
277 0 : ErrorsFound = true;
278 : }
279 :
280 0 : if (contam.ActualZoneNum <= 0) continue; // Error, will be caught and terminated later
281 :
282 : // Object report variables
283 0 : SetupOutputVariable(state,
284 : "Generic Air Contaminant Constant Source Generation Volume Flow Rate",
285 : Constant::Units::m3_s,
286 0 : contam.GenRate,
287 : OutputProcessor::TimeStepType::Zone,
288 : OutputProcessor::StoreType::Average,
289 0 : contam.Name);
290 :
291 : // Zone total report variables
292 0 : ZonePtr = contam.ActualZoneNum;
293 0 : if (RepVarSet(ZonePtr)) {
294 0 : RepVarSet(ZonePtr) = false;
295 0 : SetupOutputVariable(state,
296 : "Zone Generic Air Contaminant Generation Volume Flow Rate",
297 : Constant::Units::m3_s,
298 0 : state.dataHeatBal->ZoneRpt(ZonePtr).GCRate,
299 : OutputProcessor::TimeStepType::Zone,
300 : OutputProcessor::StoreType::Average,
301 0 : state.dataHeatBal->Zone(ZonePtr).Name);
302 : }
303 0 : SetupZoneInternalGain(state,
304 : ZonePtr,
305 : contam.Name,
306 : DataHeatBalance::IntGainType::ZoneContaminantSourceAndSinkGenericContam,
307 : nullptr,
308 : nullptr,
309 : nullptr,
310 : nullptr,
311 : nullptr,
312 : nullptr,
313 : &contam.GenRate);
314 : }
315 :
316 0 : CurrentModuleObject = "SurfaceContaminantSourceAndSink:Generic:PressureDriven";
317 0 : int TotGCGenPDriven = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
318 0 : state.dataContaminantBalance->ZoneContamGenericPDriven.allocate(TotGCGenPDriven);
319 :
320 0 : for (Loop = 1; Loop <= TotGCGenPDriven; ++Loop) {
321 0 : AlphaName = "";
322 0 : IHGNumbers = 0.0;
323 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
324 : CurrentModuleObject,
325 : Loop,
326 : AlphaName,
327 : NumAlpha,
328 : IHGNumbers,
329 : NumNumber,
330 : IOStat,
331 0 : state.dataIPShortCut->lNumericFieldBlanks,
332 0 : state.dataIPShortCut->lAlphaFieldBlanks,
333 0 : state.dataIPShortCut->cAlphaFieldNames,
334 0 : state.dataIPShortCut->cNumericFieldNames);
335 :
336 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
337 :
338 0 : Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
339 :
340 0 : auto &contam = state.dataContaminantBalance->ZoneContamGenericPDriven(Loop);
341 0 : contam.Name = AlphaName(1);
342 :
343 0 : contam.SurfName = AlphaName(2);
344 0 : contam.SurfNum = Util::FindItemInList(AlphaName(2), state.afn->MultizoneSurfaceData, &AirflowNetwork::MultizoneSurfaceProp::SurfName);
345 0 : if (contam.SurfNum == 0) {
346 0 : ShowSevereError(state,
347 0 : format("{}{}=\"{}\", invalid {} entered={}",
348 : RoutineName,
349 : CurrentModuleObject,
350 : AlphaName(1),
351 0 : state.dataIPShortCut->cAlphaFieldNames(2),
352 : AlphaName(2)));
353 0 : ShowContinueError(state, "which is not listed in AirflowNetwork:MultiZone:Surface.");
354 0 : ErrorsFound = true;
355 : }
356 : // Ensure external surface
357 0 : if (contam.SurfNum > 0 &&
358 0 : state.dataSurface->Surface(state.afn->MultizoneSurfaceData(contam.SurfNum).SurfNum).ExtBoundCond != DataSurfaces::ExternalEnvironment) {
359 0 : ShowSevereError(
360 : state,
361 0 : format(
362 : "{}{}=\"{}. The entered surface ({}) is not an exterior surface", RoutineName, CurrentModuleObject, AlphaName(1), AlphaName(2)));
363 0 : ErrorsFound = true;
364 : }
365 :
366 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
367 0 : ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
368 0 : ErrorsFound = true;
369 0 : } else if ((contam.generateRateCoefSched = Sched::GetSchedule(state, AlphaName(3))) == nullptr) {
370 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3));
371 0 : ErrorsFound = true;
372 0 : } else if (!contam.generateRateCoefSched->checkMinVal(state, Clusive::In, 0.0)) {
373 0 : Sched::ShowSevereBadMin(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3), Clusive::In, 0.0);
374 0 : ErrorsFound = true;
375 : }
376 :
377 0 : contam.GenRateCoef = IHGNumbers(1);
378 0 : if (IHGNumbers(1) < 0.0) {
379 0 : ShowSevereError(state,
380 0 : format("{}Negative values are not allowed for {} in {} = {}",
381 : RoutineName,
382 0 : state.dataIPShortCut->cNumericFieldNames(1),
383 : CurrentModuleObject,
384 : AlphaName(1)));
385 0 : ShowContinueError(state, format("The input value is {:.2R}", IHGNumbers(1)));
386 0 : ErrorsFound = true;
387 : }
388 :
389 0 : contam.Expo = IHGNumbers(2);
390 0 : if (IHGNumbers(2) <= 0.0) {
391 0 : ShowSevereError(state,
392 0 : format("{}Negative or zero value is not allowed for {} in {} = {}",
393 : RoutineName,
394 0 : state.dataIPShortCut->cNumericFieldNames(2),
395 : CurrentModuleObject,
396 : AlphaName(1)));
397 0 : ShowContinueError(state, format("The input value is {:.2R}", IHGNumbers(2)));
398 0 : ErrorsFound = true;
399 : }
400 0 : if (IHGNumbers(2) > 1.0) {
401 0 : ShowSevereError(state,
402 0 : format("{}The value greater than 1.0 is not allowed for {} in {} = {}",
403 : RoutineName,
404 0 : state.dataIPShortCut->cNumericFieldNames(2),
405 : CurrentModuleObject,
406 : AlphaName(1)));
407 0 : ShowContinueError(state, format("The input value is {:.2R}", IHGNumbers(2)));
408 0 : ErrorsFound = true;
409 : }
410 :
411 : // Object report variables
412 0 : SetupOutputVariable(state,
413 : "Generic Air Contaminant Pressure Driven Generation Volume Flow Rate",
414 : Constant::Units::m3_s,
415 0 : contam.GenRate,
416 : OutputProcessor::TimeStepType::Zone,
417 : OutputProcessor::StoreType::Average,
418 0 : contam.Name);
419 :
420 0 : if (contam.SurfNum > 0) {
421 0 : ZonePtr = state.dataSurface->Surface(state.afn->MultizoneSurfaceData(contam.SurfNum).SurfNum).Zone;
422 : } else {
423 0 : ZonePtr = 0;
424 : }
425 : // Zone total report variables
426 0 : if (ZonePtr > 0 && RepVarSet(ZonePtr)) {
427 0 : RepVarSet(ZonePtr) = false;
428 0 : SetupOutputVariable(state,
429 : "Zone Generic Air Contaminant Generation Volume Flow Rate",
430 : Constant::Units::m3_s,
431 0 : state.dataHeatBal->ZoneRpt(ZonePtr).GCRate,
432 : OutputProcessor::TimeStepType::Zone,
433 : OutputProcessor::StoreType::Average,
434 0 : state.dataHeatBal->Zone(ZonePtr).Name);
435 : }
436 0 : if (ZonePtr > 0)
437 0 : SetupZoneInternalGain(state,
438 : ZonePtr,
439 : contam.Name,
440 : DataHeatBalance::IntGainType::ZoneContaminantSourceAndSinkGenericContam,
441 : nullptr,
442 : nullptr,
443 : nullptr,
444 : nullptr,
445 : nullptr,
446 : nullptr,
447 : &contam.GenRate);
448 : }
449 :
450 0 : CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:CutoffModel";
451 0 : int TotGCGenCutoff = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
452 0 : state.dataContaminantBalance->ZoneContamGenericCutoff.allocate(TotGCGenCutoff);
453 :
454 0 : for (Loop = 1; Loop <= TotGCGenCutoff; ++Loop) {
455 0 : AlphaName = "";
456 0 : IHGNumbers = 0.0;
457 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
458 : CurrentModuleObject,
459 : Loop,
460 : AlphaName,
461 : NumAlpha,
462 : IHGNumbers,
463 : NumNumber,
464 : IOStat,
465 0 : state.dataIPShortCut->lNumericFieldBlanks,
466 0 : state.dataIPShortCut->lAlphaFieldBlanks,
467 0 : state.dataIPShortCut->cAlphaFieldNames,
468 0 : state.dataIPShortCut->cNumericFieldNames);
469 :
470 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
471 :
472 0 : Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
473 :
474 0 : auto &contam = state.dataContaminantBalance->ZoneContamGenericCutoff(Loop);
475 0 : contam.Name = AlphaName(1);
476 :
477 0 : contam.ZoneName = AlphaName(2);
478 0 : contam.ActualZoneNum = Util::FindItemInList(AlphaName(2), state.dataHeatBal->Zone);
479 0 : if (contam.ActualZoneNum == 0) {
480 0 : ShowSevereError(state,
481 0 : format("{}{}=\"{}\", invalid {} entered={}",
482 : RoutineName,
483 : CurrentModuleObject,
484 : AlphaName(1),
485 0 : state.dataIPShortCut->cAlphaFieldNames(2),
486 : AlphaName(2)));
487 0 : ErrorsFound = true;
488 : }
489 :
490 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
491 0 : ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
492 0 : ErrorsFound = true;
493 0 : } else if ((contam.generateRateSched = Sched::GetSchedule(state, AlphaName(3))) == nullptr) {
494 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3));
495 0 : ErrorsFound = true;
496 0 : } else if (!contam.generateRateSched->checkMinVal(state, Clusive::In, 0.0)) {
497 0 : Sched::ShowSevereBadMin(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3), Clusive::In, 0.0);
498 0 : ErrorsFound = true;
499 : }
500 :
501 0 : contam.GenerateRate = IHGNumbers(1);
502 0 : contam.CutoffValue = IHGNumbers(2);
503 :
504 0 : if (IHGNumbers(1) < 0.0) {
505 0 : ShowSevereError(state,
506 0 : format("{}Negative values are not allowed for {} in {} = {}",
507 : RoutineName,
508 0 : state.dataIPShortCut->cNumericFieldNames(1),
509 : CurrentModuleObject,
510 : AlphaName(1)));
511 0 : ShowContinueError(state, format("The input value is {:.2R}", IHGNumbers(1)));
512 0 : ErrorsFound = true;
513 : }
514 0 : if (IHGNumbers(2) <= 0.0) {
515 0 : ShowSevereError(state,
516 0 : format("{}Negative values or zero are not allowed for {} in {} = {}",
517 : RoutineName,
518 0 : state.dataIPShortCut->cNumericFieldNames(2),
519 : CurrentModuleObject,
520 : AlphaName(1)));
521 0 : ShowContinueError(state, format("The input value is {:.2R}", IHGNumbers(2)));
522 0 : ErrorsFound = true;
523 : }
524 :
525 : // Object report variables
526 0 : SetupOutputVariable(state,
527 : "Generic Air Contaminant Cutoff Model Generation Volume Flow Rate",
528 : Constant::Units::m3_s,
529 0 : contam.GenRate,
530 : OutputProcessor::TimeStepType::Zone,
531 : OutputProcessor::StoreType::Average,
532 0 : contam.Name);
533 :
534 : // Zone total report variables
535 0 : ZonePtr = contam.ActualZoneNum;
536 0 : if (RepVarSet(ZonePtr)) {
537 0 : RepVarSet(ZonePtr) = false;
538 0 : SetupOutputVariable(state,
539 : "Zone Generic Air Contaminant Generation Volume Flow Rate",
540 : Constant::Units::m3_s,
541 0 : state.dataHeatBal->ZoneRpt(ZonePtr).GCRate,
542 : OutputProcessor::TimeStepType::Zone,
543 : OutputProcessor::StoreType::Average,
544 0 : state.dataHeatBal->Zone(ZonePtr).Name);
545 : }
546 0 : SetupZoneInternalGain(state,
547 : ZonePtr,
548 : contam.Name,
549 : DataHeatBalance::IntGainType::ZoneContaminantSourceAndSinkGenericContam,
550 : nullptr,
551 : nullptr,
552 : nullptr,
553 : nullptr,
554 : nullptr,
555 : nullptr,
556 : &contam.GenRate);
557 : }
558 :
559 0 : CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:DecaySource";
560 0 : int TotGCGenDecay = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
561 0 : state.dataContaminantBalance->ZoneContamGenericDecay.allocate(TotGCGenDecay);
562 :
563 0 : for (Loop = 1; Loop <= TotGCGenDecay; ++Loop) {
564 0 : AlphaName = "";
565 0 : IHGNumbers = 0.0;
566 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
567 : CurrentModuleObject,
568 : Loop,
569 : AlphaName,
570 : NumAlpha,
571 : IHGNumbers,
572 : NumNumber,
573 : IOStat,
574 0 : state.dataIPShortCut->lNumericFieldBlanks,
575 0 : state.dataIPShortCut->lAlphaFieldBlanks,
576 0 : state.dataIPShortCut->cAlphaFieldNames,
577 0 : state.dataIPShortCut->cNumericFieldNames);
578 :
579 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
580 :
581 0 : auto &contam = state.dataContaminantBalance->ZoneContamGenericDecay(Loop);
582 :
583 0 : Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
584 0 : contam.Name = AlphaName(1);
585 :
586 0 : contam.ZoneName = AlphaName(2);
587 0 : contam.ActualZoneNum = Util::FindItemInList(AlphaName(2), state.dataHeatBal->Zone);
588 0 : if (contam.ActualZoneNum == 0) {
589 0 : ShowSevereError(state,
590 0 : format("{}{}=\"{}\", invalid {} entered={}",
591 : RoutineName,
592 : CurrentModuleObject,
593 : AlphaName(1),
594 0 : state.dataIPShortCut->cAlphaFieldNames(2),
595 : AlphaName(2)));
596 0 : ErrorsFound = true;
597 : }
598 :
599 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
600 0 : ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
601 0 : ErrorsFound = true;
602 0 : } else if ((contam.emitRateSched = Sched::GetSchedule(state, AlphaName(3))) == nullptr) {
603 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3));
604 0 : ErrorsFound = true;
605 0 : } else if (!contam.emitRateSched->checkMinVal(state, Clusive::In, 0.0)) {
606 0 : Sched::ShowSevereBadMin(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3), Clusive::In, 0.0);
607 0 : ErrorsFound = true;
608 : }
609 :
610 0 : contam.InitEmitRate = IHGNumbers(1);
611 0 : contam.DelayTime = IHGNumbers(2);
612 :
613 0 : if (IHGNumbers(1) < 0.0) {
614 0 : ShowSevereError(state,
615 0 : format("{}Negative values are not allowed for {} in {} = {}",
616 : RoutineName,
617 0 : state.dataIPShortCut->cNumericFieldNames(1),
618 : CurrentModuleObject,
619 : AlphaName(1)));
620 0 : ShowContinueError(state, format("The input value is {:.2R}", IHGNumbers(1)));
621 0 : ErrorsFound = true;
622 : }
623 0 : if (IHGNumbers(2) <= 0.0) {
624 0 : ShowSevereError(state,
625 0 : format("{}Negative values or zero are not allowed for {} in {} = {}",
626 : RoutineName,
627 0 : state.dataIPShortCut->cNumericFieldNames(2),
628 : CurrentModuleObject,
629 : AlphaName(1)));
630 0 : ShowContinueError(state, format("The input value is {:.2R}", IHGNumbers(2)));
631 0 : ErrorsFound = true;
632 : }
633 :
634 : // Object report variables
635 0 : SetupOutputVariable(state,
636 : "Generic Air Contaminant Decay Model Generation Volume Flow Rate",
637 : Constant::Units::m3_s,
638 0 : contam.GenRate,
639 : OutputProcessor::TimeStepType::Zone,
640 : OutputProcessor::StoreType::Average,
641 0 : contam.Name);
642 0 : SetupOutputVariable(state,
643 : "Generic Air Contaminant Decay Model Generation Emission Start Elapsed Time",
644 : Constant::Units::s,
645 0 : contam.Time,
646 : OutputProcessor::TimeStepType::Zone,
647 : OutputProcessor::StoreType::Average,
648 0 : contam.Name);
649 :
650 : // Zone total report variables
651 0 : ZonePtr = contam.ActualZoneNum;
652 0 : if (RepVarSet(ZonePtr)) {
653 0 : RepVarSet(ZonePtr) = false;
654 0 : SetupOutputVariable(state,
655 : "Zone Generic Air Contaminant Generation Volume Flow Rate",
656 : Constant::Units::m3_s,
657 0 : state.dataHeatBal->ZoneRpt(ZonePtr).GCRate,
658 : OutputProcessor::TimeStepType::Zone,
659 : OutputProcessor::StoreType::Average,
660 0 : state.dataHeatBal->Zone(ZonePtr).Name);
661 : }
662 0 : SetupZoneInternalGain(state,
663 : ZonePtr,
664 : contam.Name,
665 : DataHeatBalance::IntGainType::ZoneContaminantSourceAndSinkGenericContam,
666 : nullptr,
667 : nullptr,
668 : nullptr,
669 : nullptr,
670 : nullptr,
671 : nullptr,
672 : &contam.GenRate);
673 : }
674 :
675 0 : CurrentModuleObject = "SurfaceContaminantSourceAndSink:Generic:BoundaryLayerDiffusion";
676 0 : int TotGCBLDiff = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
677 0 : state.dataContaminantBalance->ZoneContamGenericBLDiff.allocate(TotGCBLDiff);
678 :
679 0 : for (Loop = 1; Loop <= TotGCBLDiff; ++Loop) {
680 0 : AlphaName = "";
681 0 : IHGNumbers = 0.0;
682 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
683 : CurrentModuleObject,
684 : Loop,
685 : AlphaName,
686 : NumAlpha,
687 : IHGNumbers,
688 : NumNumber,
689 : IOStat,
690 0 : state.dataIPShortCut->lNumericFieldBlanks,
691 0 : state.dataIPShortCut->lAlphaFieldBlanks,
692 0 : state.dataIPShortCut->cAlphaFieldNames,
693 0 : state.dataIPShortCut->cNumericFieldNames);
694 :
695 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
696 :
697 0 : Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
698 :
699 0 : auto &contam = state.dataContaminantBalance->ZoneContamGenericBLDiff(Loop);
700 0 : contam.Name = AlphaName(1);
701 0 : contam.SurfName = AlphaName(2);
702 0 : contam.SurfNum = Util::FindItemInList(AlphaName(2), state.dataSurface->Surface);
703 0 : if (contam.SurfNum == 0) {
704 0 : ShowSevereError(state,
705 0 : format("{}{}=\"{}\", invalid {} entered={}",
706 : RoutineName,
707 : CurrentModuleObject,
708 : AlphaName(1),
709 0 : state.dataIPShortCut->cAlphaFieldNames(2),
710 : AlphaName(2)));
711 0 : ErrorsFound = true;
712 : }
713 :
714 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
715 0 : ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
716 0 : ErrorsFound = true;
717 0 : } else if ((contam.transCoefSched = Sched::GetSchedule(state, AlphaName(3))) == nullptr) {
718 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3));
719 0 : ErrorsFound = true;
720 0 : } else if (!contam.transCoefSched->checkMinVal(state, Clusive::In, 0.0)) {
721 0 : Sched::ShowSevereBadMin(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3), Clusive::In, 0.0);
722 0 : ErrorsFound = true;
723 : }
724 :
725 0 : contam.TransCoef = IHGNumbers(1);
726 0 : contam.HenryCoef = IHGNumbers(2);
727 0 : if (IHGNumbers(1) < 0.0) {
728 0 : ShowSevereError(state,
729 0 : format("{}Negative values are not allowed for {} in {} = {}",
730 : RoutineName,
731 0 : state.dataIPShortCut->cNumericFieldNames(1),
732 : CurrentModuleObject,
733 : AlphaName(1)));
734 0 : ShowContinueError(state, format("The input value is {:.2R}", IHGNumbers(1)));
735 0 : ErrorsFound = true;
736 : }
737 0 : if (IHGNumbers(2) <= 0.0) {
738 0 : ShowSevereError(state,
739 0 : format("{}Negative values or zero are not allowed for {} in {} = {}",
740 : RoutineName,
741 0 : state.dataIPShortCut->cNumericFieldNames(2),
742 : CurrentModuleObject,
743 : AlphaName(1)));
744 0 : ShowContinueError(state, format("The input value is {:.2R}", IHGNumbers(2)));
745 0 : ErrorsFound = true;
746 : }
747 :
748 : // Object report variables
749 0 : SetupOutputVariable(state,
750 : "Generic Air Contaminant Boundary Layer Diffusion Generation Volume Flow Rate",
751 : Constant::Units::m3_s,
752 0 : contam.GenRate,
753 : OutputProcessor::TimeStepType::Zone,
754 : OutputProcessor::StoreType::Average,
755 0 : contam.Name);
756 0 : if (contam.SurfNum > 0) {
757 0 : SetupOutputVariable(state,
758 : "Generic Air Contaminant Boundary Layer Diffusion Inside Face Concentration",
759 : Constant::Units::ppm,
760 0 : state.dataSurface->SurfGenericContam(contam.SurfNum),
761 : OutputProcessor::TimeStepType::Zone,
762 : OutputProcessor::StoreType::Average,
763 0 : contam.SurfName);
764 : }
765 :
766 0 : ZonePtr = state.dataSurface->Surface(contam.SurfNum).Zone;
767 : // Zone total report variables
768 0 : if (RepVarSet(ZonePtr)) {
769 0 : RepVarSet(ZonePtr) = false;
770 0 : SetupOutputVariable(state,
771 : "Zone Generic Air Contaminant Generation Volume Flow Rate",
772 : Constant::Units::m3_s,
773 0 : state.dataHeatBal->ZoneRpt(ZonePtr).GCRate,
774 : OutputProcessor::TimeStepType::Zone,
775 : OutputProcessor::StoreType::Average,
776 0 : state.dataHeatBal->Zone(ZonePtr).Name);
777 : }
778 0 : SetupZoneInternalGain(state,
779 : ZonePtr,
780 : contam.Name,
781 : DataHeatBalance::IntGainType::ZoneContaminantSourceAndSinkGenericContam,
782 : nullptr,
783 : nullptr,
784 : nullptr,
785 : nullptr,
786 : nullptr,
787 : nullptr,
788 : &contam.GenRate);
789 : }
790 :
791 0 : CurrentModuleObject = "SurfaceContaminantSourceAndSink:Generic:DepositionVelocitySink";
792 0 : int TotGCDVS = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
793 0 : state.dataContaminantBalance->ZoneContamGenericDVS.allocate(TotGCDVS);
794 :
795 0 : for (Loop = 1; Loop <= TotGCDVS; ++Loop) {
796 0 : AlphaName = "";
797 0 : IHGNumbers = 0.0;
798 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
799 : CurrentModuleObject,
800 : Loop,
801 : AlphaName,
802 : NumAlpha,
803 : IHGNumbers,
804 : NumNumber,
805 : IOStat,
806 0 : state.dataIPShortCut->lNumericFieldBlanks,
807 0 : state.dataIPShortCut->lAlphaFieldBlanks,
808 0 : state.dataIPShortCut->cAlphaFieldNames,
809 0 : state.dataIPShortCut->cNumericFieldNames);
810 :
811 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
812 :
813 0 : Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
814 0 : auto &contam = state.dataContaminantBalance->ZoneContamGenericDVS(Loop);
815 0 : contam.Name = AlphaName(1);
816 :
817 0 : contam.SurfName = AlphaName(2);
818 0 : contam.SurfNum = Util::FindItemInList(AlphaName(2), state.dataSurface->Surface);
819 0 : if (contam.SurfNum == 0) {
820 0 : ShowSevereError(state,
821 0 : format("{}{}=\"{}\", invalid {} entered={}",
822 : RoutineName,
823 : CurrentModuleObject,
824 : AlphaName(1),
825 0 : state.dataIPShortCut->cAlphaFieldNames(2),
826 : AlphaName(2)));
827 0 : ErrorsFound = true;
828 : }
829 :
830 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
831 0 : ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
832 0 : ErrorsFound = true;
833 0 : } else if ((contam.depoVeloSched = Sched::GetSchedule(state, AlphaName(3))) == nullptr) {
834 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3));
835 0 : ErrorsFound = true;
836 0 : } else if (!contam.depoVeloSched->checkMinVal(state, Clusive::In, 0.0)) {
837 0 : Sched::ShowSevereBadMin(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3), Clusive::In, 0.0);
838 0 : ErrorsFound = true;
839 : }
840 :
841 0 : contam.DepoVelo = IHGNumbers(1);
842 0 : if (IHGNumbers(1) < 0.0) {
843 0 : ShowSevereError(state,
844 0 : format("{}Negative values are not allowed for {} in {} = {}",
845 : RoutineName,
846 0 : state.dataIPShortCut->cNumericFieldNames(1),
847 : CurrentModuleObject,
848 : AlphaName(1)));
849 0 : ShowContinueError(state, format("The input value is {:.2R}", IHGNumbers(1)));
850 0 : ErrorsFound = true;
851 : }
852 :
853 : // Object report variables
854 0 : SetupOutputVariable(state,
855 : "Generic Air Contaminant Deposition Velocity Removal Volume Flow Rate",
856 : Constant::Units::m3_s,
857 0 : contam.GenRate,
858 : OutputProcessor::TimeStepType::Zone,
859 : OutputProcessor::StoreType::Average,
860 0 : contam.Name);
861 :
862 0 : ZonePtr = state.dataSurface->Surface(contam.SurfNum).Zone;
863 : // Zone total report variables
864 0 : if (RepVarSet(ZonePtr)) {
865 0 : RepVarSet(ZonePtr) = false;
866 0 : SetupOutputVariable(state,
867 : "Zone Generic Air Contaminant Generation Volume Flow Rate",
868 : Constant::Units::m3_s,
869 0 : state.dataHeatBal->ZoneRpt(ZonePtr).GCRate,
870 : OutputProcessor::TimeStepType::Zone,
871 : OutputProcessor::StoreType::Average,
872 0 : state.dataHeatBal->Zone(ZonePtr).Name);
873 : }
874 0 : SetupZoneInternalGain(state,
875 : ZonePtr,
876 : contam.Name,
877 : DataHeatBalance::IntGainType::ZoneContaminantSourceAndSinkGenericContam,
878 : nullptr,
879 : nullptr,
880 : nullptr,
881 : nullptr,
882 : nullptr,
883 : nullptr,
884 : &contam.GenRate);
885 : }
886 :
887 0 : CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:DepositionRateSink";
888 0 : int TotGCDRS = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
889 0 : state.dataContaminantBalance->ZoneContamGenericDRS.allocate(TotGCDRS);
890 :
891 0 : for (Loop = 1; Loop <= TotGCDRS; ++Loop) {
892 0 : AlphaName = "";
893 0 : IHGNumbers = 0.0;
894 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
895 : CurrentModuleObject,
896 : Loop,
897 : AlphaName,
898 : NumAlpha,
899 : IHGNumbers,
900 : NumNumber,
901 : IOStat,
902 0 : state.dataIPShortCut->lNumericFieldBlanks,
903 0 : state.dataIPShortCut->lAlphaFieldBlanks,
904 0 : state.dataIPShortCut->cAlphaFieldNames,
905 0 : state.dataIPShortCut->cNumericFieldNames);
906 :
907 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
908 :
909 0 : Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
910 :
911 0 : auto &contam = state.dataContaminantBalance->ZoneContamGenericDRS(Loop);
912 0 : contam.Name = AlphaName(1);
913 :
914 0 : contam.ZoneName = AlphaName(2);
915 0 : contam.ActualZoneNum = Util::FindItemInList(AlphaName(2), state.dataHeatBal->Zone);
916 0 : if (contam.ActualZoneNum == 0) {
917 0 : ShowSevereError(state,
918 0 : format("{}{}=\"{}\", invalid {} entered={}",
919 : RoutineName,
920 : CurrentModuleObject,
921 : AlphaName(1),
922 0 : state.dataIPShortCut->cAlphaFieldNames(2),
923 : AlphaName(2)));
924 0 : ErrorsFound = true;
925 : }
926 :
927 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
928 0 : ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
929 0 : ErrorsFound = true;
930 0 : } else if ((contam.depoRateSched = Sched::GetSchedule(state, AlphaName(3))) == nullptr) {
931 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3));
932 0 : ErrorsFound = true;
933 0 : } else if (!contam.depoRateSched->checkMinVal(state, Clusive::In, 0.0)) {
934 0 : Sched::ShowSevereBadMin(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), AlphaName(3), Clusive::In, 0.0);
935 0 : ErrorsFound = true;
936 : }
937 :
938 0 : contam.DepoRate = IHGNumbers(1);
939 :
940 0 : if (IHGNumbers(1) < 0.0) {
941 0 : ShowSevereError(state,
942 0 : format("{}Negative values are not allowed for {} in {} = {}",
943 : RoutineName,
944 0 : state.dataIPShortCut->cNumericFieldNames(1),
945 : CurrentModuleObject,
946 : AlphaName(1)));
947 0 : ShowContinueError(state, format("The input value is {:.2R}", IHGNumbers(1)));
948 0 : ErrorsFound = true;
949 : }
950 :
951 : // Object report variables
952 0 : SetupOutputVariable(state,
953 : "Generic Air Contaminant Deposition Rate Removal Volume Flow Rate",
954 : Constant::Units::m3_s,
955 0 : contam.GenRate,
956 : OutputProcessor::TimeStepType::Zone,
957 : OutputProcessor::StoreType::Average,
958 0 : contam.Name);
959 :
960 0 : ZonePtr = contam.ActualZoneNum;
961 : // Zone total report variables
962 0 : if (RepVarSet(ZonePtr)) {
963 0 : RepVarSet(ZonePtr) = false;
964 0 : SetupOutputVariable(state,
965 : "Zone Generic Air Contaminant Generation Volume Flow Rate",
966 : Constant::Units::m3_s,
967 0 : state.dataHeatBal->ZoneRpt(ZonePtr).GCRate,
968 : OutputProcessor::TimeStepType::Zone,
969 : OutputProcessor::StoreType::Average,
970 0 : state.dataHeatBal->Zone(ZonePtr).Name);
971 : }
972 0 : SetupZoneInternalGain(state,
973 : ZonePtr,
974 : contam.Name,
975 : DataHeatBalance::IntGainType::ZoneContaminantSourceAndSinkGenericContam,
976 : nullptr,
977 : nullptr,
978 : nullptr,
979 : nullptr,
980 : nullptr,
981 : nullptr,
982 : &contam.GenRate);
983 : }
984 :
985 0 : RepVarSet.deallocate();
986 0 : IHGNumbers.deallocate();
987 0 : AlphaName.deallocate();
988 :
989 0 : if (ErrorsFound) {
990 0 : ShowFatalError(state, "Errors getting Zone Contaminant Sources and Sinks input data. Preceding condition(s) cause termination.");
991 : }
992 0 : }
993 :
994 0 : void GetZoneContaminanSetPoints(EnergyPlusData &state)
995 : {
996 :
997 : // SUBROUTINE INFORMATION:
998 : // AUTHOR Lixing Gu
999 : // DATE WRITTEN May 2010
1000 :
1001 : // PURPOSE OF THIS SUBROUTINE:
1002 : // This subroutine gets the inputs related to contaminant control.
1003 :
1004 : // METHODOLOGY EMPLOYED:
1005 : // Uses the status flags to trigger events.
1006 :
1007 : static constexpr std::string_view routineName = "GetZoneContaminantSetPoints";
1008 :
1009 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1010 : int ContControlledZoneNum; // The Splitter that you are currently loading input into
1011 : int NumAlphas;
1012 : int NumNums;
1013 : int IOStat;
1014 0 : bool ErrorsFound(false);
1015 :
1016 : struct NeededControlTypes
1017 : {
1018 : // Members
1019 : Array1D_bool MustHave; // 4= the four control types
1020 : Array1D_bool DidHave;
1021 :
1022 : // Default Constructor
1023 : NeededControlTypes() : MustHave(4, false), DidHave(4, false)
1024 : {
1025 : }
1026 : };
1027 :
1028 : struct NeededComfortControlTypes
1029 : {
1030 : // Members
1031 : Array1D_bool MustHave; // 4= the four control types
1032 : Array1D_bool DidHave;
1033 :
1034 : // Default Constructor
1035 : NeededComfortControlTypes() : MustHave(12, false), DidHave(12, false)
1036 : {
1037 : }
1038 : };
1039 0 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
1040 0 : cCurrentModuleObject = "ZoneControl:ContaminantController";
1041 0 : int NumContControlledZones = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1042 :
1043 0 : if (NumContControlledZones > 0) {
1044 0 : state.dataContaminantBalance->ContaminantControlledZone.allocate(NumContControlledZones);
1045 : }
1046 :
1047 0 : for (ContControlledZoneNum = 1; ContControlledZoneNum <= NumContControlledZones; ++ContControlledZoneNum) {
1048 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1049 : cCurrentModuleObject,
1050 : ContControlledZoneNum,
1051 0 : state.dataIPShortCut->cAlphaArgs,
1052 : NumAlphas,
1053 0 : state.dataIPShortCut->rNumericArgs,
1054 : NumNums,
1055 : IOStat,
1056 0 : state.dataIPShortCut->lNumericFieldBlanks,
1057 0 : state.dataIPShortCut->lAlphaFieldBlanks,
1058 0 : state.dataIPShortCut->cAlphaFieldNames,
1059 0 : state.dataIPShortCut->cNumericFieldNames);
1060 :
1061 0 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
1062 :
1063 0 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
1064 :
1065 0 : auto &controlledZone = state.dataContaminantBalance->ContaminantControlledZone(ContControlledZoneNum);
1066 0 : controlledZone.Name = state.dataIPShortCut->cAlphaArgs(1);
1067 0 : controlledZone.ZoneName = state.dataIPShortCut->cAlphaArgs(2);
1068 0 : controlledZone.ActualZoneNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->Zone);
1069 0 : if (controlledZone.ActualZoneNum == 0) {
1070 0 : ShowSevereError(state,
1071 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
1072 : cCurrentModuleObject,
1073 0 : state.dataIPShortCut->cAlphaArgs(1),
1074 0 : state.dataIPShortCut->cAlphaFieldNames(2),
1075 0 : state.dataIPShortCut->cAlphaArgs(2)));
1076 0 : ErrorsFound = true;
1077 : } else {
1078 : // Zone(ContaminantControlledZone(ContControlledZoneNum)%ActualZoneNum)%TempControlledZoneIndex = ContControlledZoneNum
1079 : }
1080 :
1081 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
1082 0 : controlledZone.availSched = Sched::GetScheduleAlwaysOn(state);
1083 0 : } else if ((controlledZone.availSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(3))) == nullptr) {
1084 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), state.dataIPShortCut->cAlphaArgs(3));
1085 0 : ErrorsFound = true;
1086 0 : } else if (!controlledZone.availSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
1087 0 : Sched::ShowSevereBadMinMax(
1088 0 : state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), state.dataIPShortCut->cAlphaArgs(3), Clusive::In, 0.0, Clusive::In, 1.0);
1089 0 : ErrorsFound = true;
1090 : } else {
1091 0 : state.dataHeatBal->Zone(controlledZone.ActualZoneNum).zoneContamControllerSched = controlledZone.availSched;
1092 : }
1093 :
1094 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
1095 0 : ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4));
1096 0 : ErrorsFound = true;
1097 0 : } else if ((controlledZone.setptSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(4))) == nullptr) {
1098 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4), state.dataIPShortCut->cAlphaArgs(4));
1099 0 : ErrorsFound = true;
1100 0 : } else if (!controlledZone.setptSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 2000.0)) {
1101 0 : Sched::ShowSevereBadMinMax(
1102 0 : state, eoh, state.dataIPShortCut->cAlphaFieldNames(4), state.dataIPShortCut->cAlphaArgs(4), Clusive::In, 0.0, Clusive::In, 2000.0);
1103 0 : ErrorsFound = true;
1104 : }
1105 :
1106 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
1107 0 : controlledZone.zoneMinCO2Sched = nullptr; // This needs to be nullptr because an empty schedule means outdoorCO2 not zero CO2
1108 0 : } else if ((controlledZone.zoneMinCO2Sched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(5))) == nullptr) {
1109 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5));
1110 0 : ErrorsFound = true;
1111 0 : } else if (!controlledZone.zoneMinCO2Sched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 2000.0)) {
1112 0 : Sched::ShowSevereBadMinMax(
1113 0 : state, eoh, state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5), Clusive::In, 0.0, Clusive::In, 2000.0);
1114 0 : ErrorsFound = true;
1115 : } else {
1116 0 : state.dataHeatBal->Zone(controlledZone.ActualZoneNum).zoneMinCO2Sched = controlledZone.zoneMinCO2Sched;
1117 : }
1118 :
1119 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
1120 0 : controlledZone.zoneMaxCO2Sched = nullptr; // This needs to be nullptr because an empty schedule means outdoorCO2, not zero CO2
1121 0 : } else if ((controlledZone.zoneMaxCO2Sched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(6))) == nullptr) {
1122 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6));
1123 0 : ErrorsFound = true;
1124 0 : } else if (!controlledZone.zoneMaxCO2Sched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 2000.0)) {
1125 0 : Sched::ShowSevereBadMinMax(
1126 0 : state, eoh, state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6), Clusive::In, 0.0, Clusive::In, 2000.0);
1127 0 : ErrorsFound = true;
1128 : } else {
1129 0 : state.dataHeatBal->Zone(controlledZone.ActualZoneNum).zoneMaxCO2Sched = controlledZone.zoneMaxCO2Sched;
1130 : }
1131 :
1132 0 : if (NumAlphas <= 6) {
1133 0 : controlledZone.genericContamAvailSched = Sched::GetScheduleAlwaysOn(state);
1134 0 : continue;
1135 : }
1136 :
1137 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(7)) {
1138 0 : controlledZone.genericContamAvailSched = Sched::GetScheduleAlwaysOn(state);
1139 0 : } else if ((controlledZone.genericContamAvailSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(7))) == nullptr) {
1140 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7));
1141 0 : ErrorsFound = true;
1142 0 : } else if (!controlledZone.genericContamAvailSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
1143 0 : Sched::ShowSevereBadMinMax(
1144 0 : state, eoh, state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7), Clusive::In, 0.0, Clusive::In, 1.0);
1145 0 : ErrorsFound = true;
1146 : }
1147 :
1148 0 : if (state.dataIPShortCut->lAlphaFieldBlanks(8)) {
1149 0 : ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaArgs(8));
1150 0 : ErrorsFound = true;
1151 0 : } else if ((controlledZone.genericContamSetptSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(8))) == nullptr) {
1152 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8));
1153 0 : ErrorsFound = true;
1154 : }
1155 :
1156 : } // ContControlledZoneNum
1157 :
1158 0 : if (ErrorsFound) {
1159 0 : ShowFatalError(state, "Errors getting Zone Contaminant Control input data. Preceding condition(s) cause termination.");
1160 : }
1161 0 : }
1162 :
1163 0 : void InitZoneContSetPoints(EnergyPlusData &state)
1164 : {
1165 :
1166 : // SUBROUTINE INFORMATION:
1167 : // AUTHOR Lixing Gu
1168 : // DATE WRITTEN May 2010
1169 :
1170 : // PURPOSE OF THIS SUBROUTINE:
1171 : // This subroutine initializes the data for the zone air contaminant setpoints.
1172 :
1173 : // METHODOLOGY EMPLOYED:
1174 : // Uses the status flags to trigger events.
1175 :
1176 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1177 : Real64 GCGain; // Zone generic contaminant gain
1178 : Real64 Pi; // Pressue at zone i
1179 : Real64 Pj; // Pressue at zone j
1180 : Real64 Sch; // Schedule value
1181 :
1182 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1183 0 : state.dataContaminantBalance->OutdoorCO2 = state.dataContaminantBalance->Contaminant.CO2OutdoorSched->getCurrentVal();
1184 : }
1185 :
1186 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1187 0 : state.dataContaminantBalance->OutdoorGC = state.dataContaminantBalance->Contaminant.genericOutdoorSched->getCurrentVal();
1188 : }
1189 :
1190 0 : if (state.dataZoneContaminantPredictorCorrector->MyOneTimeFlag) {
1191 : // CO2
1192 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1193 0 : state.dataContaminantBalance->ZoneCO2SetPoint.dimension(state.dataGlobal->NumOfZones, 0.0);
1194 0 : state.dataContaminantBalance->CO2PredictedRate.dimension(state.dataGlobal->NumOfZones, 0.0);
1195 0 : state.dataContaminantBalance->CO2ZoneTimeMinus1.dimension(state.dataGlobal->NumOfZones, 0.0);
1196 0 : state.dataContaminantBalance->CO2ZoneTimeMinus2.dimension(state.dataGlobal->NumOfZones, 0.0);
1197 0 : state.dataContaminantBalance->CO2ZoneTimeMinus3.dimension(state.dataGlobal->NumOfZones, 0.0);
1198 0 : state.dataContaminantBalance->CO2ZoneTimeMinus4.dimension(state.dataGlobal->NumOfZones, 0.0);
1199 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus1.dimension(state.dataGlobal->NumOfZones, 0.0);
1200 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus2.dimension(state.dataGlobal->NumOfZones, 0.0);
1201 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus3.dimension(state.dataGlobal->NumOfZones, 0.0);
1202 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus4.dimension(state.dataGlobal->NumOfZones, 0.0);
1203 0 : state.dataContaminantBalance->CO2ZoneTimeMinus1Temp.dimension(state.dataGlobal->NumOfZones, 0.0);
1204 0 : state.dataContaminantBalance->CO2ZoneTimeMinus2Temp.dimension(state.dataGlobal->NumOfZones, 0.0);
1205 0 : state.dataContaminantBalance->CO2ZoneTimeMinus3Temp.dimension(state.dataGlobal->NumOfZones, 0.0);
1206 0 : state.dataContaminantBalance->ZoneCO2MX.dimension(state.dataGlobal->NumOfZones, 0.0);
1207 0 : state.dataContaminantBalance->ZoneCO2M2.dimension(state.dataGlobal->NumOfZones, 0.0);
1208 0 : state.dataContaminantBalance->ZoneCO21.dimension(state.dataGlobal->NumOfZones, 0.0);
1209 :
1210 0 : state.dataContaminantBalance->ZoneSysContDemand.allocate(state.dataGlobal->NumOfZones);
1211 0 : state.dataContaminantBalance->ZoneCO2Gain.dimension(state.dataGlobal->NumOfZones, 0.0);
1212 0 : state.dataContaminantBalance->ZoneCO2GainFromPeople.dimension(state.dataGlobal->NumOfZones, 0.0);
1213 0 : state.dataContaminantBalance->ZoneCO2GainExceptPeople.dimension(state.dataGlobal->NumOfZones, 0.0); // Added for hybrid model
1214 0 : state.dataContaminantBalance->MixingMassFlowCO2.dimension(state.dataGlobal->NumOfZones, 0.0);
1215 0 : state.dataContaminantBalance->ZoneAirDensityCO.dimension(state.dataGlobal->NumOfZones, 0.0);
1216 0 : state.dataContaminantBalance->AZ.dimension(state.dataGlobal->NumOfZones, 0.0);
1217 0 : state.dataContaminantBalance->BZ.dimension(state.dataGlobal->NumOfZones, 0.0);
1218 0 : state.dataContaminantBalance->CZ.dimension(state.dataGlobal->NumOfZones, 0.0);
1219 : }
1220 :
1221 0 : state.dataContaminantBalance->CONTRAT.dimension(state.dataGlobal->NumOfZones, 0.0);
1222 :
1223 : // Allocate Derived Types
1224 :
1225 0 : for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
1226 : // Zone CO2
1227 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1228 0 : SetupOutputVariable(state,
1229 : "Zone Air CO2 Concentration",
1230 : Constant::Units::ppm,
1231 0 : state.dataContaminantBalance->ZoneAirCO2(Loop),
1232 : OutputProcessor::TimeStepType::System,
1233 : OutputProcessor::StoreType::Average,
1234 0 : state.dataHeatBal->Zone(Loop).Name);
1235 0 : SetupOutputVariable(state,
1236 : "Zone Air CO2 Predicted Load to Setpoint Mass Flow Rate",
1237 : Constant::Units::kg_s,
1238 0 : state.dataContaminantBalance->CO2PredictedRate(Loop),
1239 : OutputProcessor::TimeStepType::System,
1240 : OutputProcessor::StoreType::Average,
1241 0 : state.dataHeatBal->Zone(Loop).Name);
1242 0 : SetupOutputVariable(state,
1243 : "Zone Air CO2 Setpoint Concentration",
1244 : Constant::Units::ppm,
1245 0 : state.dataContaminantBalance->ZoneCO2SetPoint(Loop),
1246 : OutputProcessor::TimeStepType::System,
1247 : OutputProcessor::StoreType::Average,
1248 0 : state.dataHeatBal->Zone(Loop).Name);
1249 0 : SetupOutputVariable(state,
1250 : "Zone Air CO2 Internal Gain Volume Flow Rate",
1251 : Constant::Units::m3_s,
1252 0 : state.dataContaminantBalance->ZoneCO2Gain(Loop),
1253 : OutputProcessor::TimeStepType::System,
1254 : OutputProcessor::StoreType::Average,
1255 0 : state.dataHeatBal->Zone(Loop).Name);
1256 : }
1257 :
1258 : } // Loop
1259 :
1260 : // Generic contaminant
1261 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1262 0 : state.dataContaminantBalance->ZoneGCSetPoint.dimension(state.dataGlobal->NumOfZones, 0.0);
1263 0 : state.dataContaminantBalance->GCPredictedRate.dimension(state.dataGlobal->NumOfZones, 0.0);
1264 0 : state.dataContaminantBalance->GCZoneTimeMinus1.dimension(state.dataGlobal->NumOfZones, 0.0);
1265 0 : state.dataContaminantBalance->GCZoneTimeMinus2.dimension(state.dataGlobal->NumOfZones, 0.0);
1266 0 : state.dataContaminantBalance->GCZoneTimeMinus3.dimension(state.dataGlobal->NumOfZones, 0.0);
1267 0 : state.dataContaminantBalance->GCZoneTimeMinus4.dimension(state.dataGlobal->NumOfZones, 0.0);
1268 0 : state.dataContaminantBalance->DSGCZoneTimeMinus1.dimension(state.dataGlobal->NumOfZones, 0.0);
1269 0 : state.dataContaminantBalance->DSGCZoneTimeMinus2.dimension(state.dataGlobal->NumOfZones, 0.0);
1270 0 : state.dataContaminantBalance->DSGCZoneTimeMinus3.dimension(state.dataGlobal->NumOfZones, 0.0);
1271 0 : state.dataContaminantBalance->DSGCZoneTimeMinus4.dimension(state.dataGlobal->NumOfZones, 0.0);
1272 0 : state.dataContaminantBalance->GCZoneTimeMinus1Temp.dimension(state.dataGlobal->NumOfZones, 0.0);
1273 0 : state.dataContaminantBalance->GCZoneTimeMinus2Temp.dimension(state.dataGlobal->NumOfZones, 0.0);
1274 0 : state.dataContaminantBalance->GCZoneTimeMinus3Temp.dimension(state.dataGlobal->NumOfZones, 0.0);
1275 0 : state.dataContaminantBalance->ZoneGCMX.dimension(state.dataGlobal->NumOfZones, 0.0);
1276 0 : state.dataContaminantBalance->ZoneGCM2.dimension(state.dataGlobal->NumOfZones, 0.0);
1277 0 : state.dataContaminantBalance->ZoneGC1.dimension(state.dataGlobal->NumOfZones, 0.0);
1278 :
1279 0 : if (!allocated(state.dataContaminantBalance->ZoneSysContDemand))
1280 0 : state.dataContaminantBalance->ZoneSysContDemand.allocate(state.dataGlobal->NumOfZones);
1281 0 : state.dataContaminantBalance->ZoneGCGain.dimension(state.dataGlobal->NumOfZones, 0.0);
1282 0 : state.dataContaminantBalance->MixingMassFlowGC.dimension(state.dataGlobal->NumOfZones, 0.0);
1283 0 : state.dataContaminantBalance->ZoneAirDensityGC.dimension(state.dataGlobal->NumOfZones, 0.0);
1284 0 : state.dataContaminantBalance->AZGC.dimension(state.dataGlobal->NumOfZones, 0.0);
1285 0 : state.dataContaminantBalance->BZGC.dimension(state.dataGlobal->NumOfZones, 0.0);
1286 0 : state.dataContaminantBalance->CZGC.dimension(state.dataGlobal->NumOfZones, 0.0);
1287 : }
1288 :
1289 0 : state.dataContaminantBalance->CONTRATGC.dimension(state.dataGlobal->NumOfZones, 0.0);
1290 :
1291 : // Allocate Derived Types
1292 :
1293 0 : for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
1294 : // Zone CO2
1295 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1296 0 : SetupOutputVariable(state,
1297 : "Zone Air Generic Air Contaminant Concentration",
1298 : Constant::Units::ppm,
1299 0 : state.dataContaminantBalance->ZoneAirGC(Loop),
1300 : OutputProcessor::TimeStepType::System,
1301 : OutputProcessor::StoreType::Average,
1302 0 : state.dataHeatBal->Zone(Loop).Name);
1303 0 : SetupOutputVariable(state,
1304 : "Zone Generic Air Contaminant Predicted Load to Setpoint Mass Flow Rate",
1305 : Constant::Units::kg_s,
1306 0 : state.dataContaminantBalance->GCPredictedRate(Loop),
1307 : OutputProcessor::TimeStepType::System,
1308 : OutputProcessor::StoreType::Average,
1309 0 : state.dataHeatBal->Zone(Loop).Name);
1310 0 : SetupOutputVariable(state,
1311 : "Zone Generic Air Contaminant Setpoint Concentration",
1312 : Constant::Units::ppm,
1313 0 : state.dataContaminantBalance->ZoneGCSetPoint(Loop),
1314 : OutputProcessor::TimeStepType::System,
1315 : OutputProcessor::StoreType::Average,
1316 0 : state.dataHeatBal->Zone(Loop).Name);
1317 : }
1318 : } // Loop
1319 :
1320 0 : state.dataZoneContaminantPredictorCorrector->MyOneTimeFlag = false;
1321 : }
1322 :
1323 : // Do the Begin Environment initializations
1324 0 : if (state.dataZoneContaminantPredictorCorrector->MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
1325 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1326 0 : state.dataContaminantBalance->CONTRAT = 0.0;
1327 0 : state.dataContaminantBalance->CO2ZoneTimeMinus1 = state.dataContaminantBalance->OutdoorCO2;
1328 0 : state.dataContaminantBalance->CO2ZoneTimeMinus2 = state.dataContaminantBalance->OutdoorCO2;
1329 0 : state.dataContaminantBalance->CO2ZoneTimeMinus3 = state.dataContaminantBalance->OutdoorCO2;
1330 0 : state.dataContaminantBalance->CO2ZoneTimeMinus4 = state.dataContaminantBalance->OutdoorCO2;
1331 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus1 = state.dataContaminantBalance->OutdoorCO2;
1332 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus2 = state.dataContaminantBalance->OutdoorCO2;
1333 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus3 = state.dataContaminantBalance->OutdoorCO2;
1334 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus4 = state.dataContaminantBalance->OutdoorCO2;
1335 0 : state.dataContaminantBalance->CO2ZoneTimeMinus1Temp = 0.0;
1336 0 : state.dataContaminantBalance->CO2ZoneTimeMinus2Temp = 0.0;
1337 0 : state.dataContaminantBalance->CO2ZoneTimeMinus3Temp = 0.0;
1338 0 : state.dataContaminantBalance->ZoneAirCO2Temp = state.dataContaminantBalance->OutdoorCO2;
1339 0 : state.dataContaminantBalance->ZoneCO2SetPoint = 0.0;
1340 0 : state.dataContaminantBalance->CO2PredictedRate = 0.0;
1341 0 : state.dataContaminantBalance->ZoneAirCO2 = state.dataContaminantBalance->OutdoorCO2;
1342 0 : state.dataContaminantBalance->ZoneCO21 = state.dataContaminantBalance->OutdoorCO2;
1343 0 : state.dataContaminantBalance->ZoneCO2MX = state.dataContaminantBalance->OutdoorCO2;
1344 0 : state.dataContaminantBalance->ZoneCO2M2 = state.dataContaminantBalance->OutdoorCO2;
1345 : }
1346 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1347 0 : state.dataContaminantBalance->CONTRAT = 0.0;
1348 0 : state.dataContaminantBalance->GCZoneTimeMinus1 = state.dataContaminantBalance->OutdoorGC;
1349 0 : state.dataContaminantBalance->GCZoneTimeMinus2 = state.dataContaminantBalance->OutdoorGC;
1350 0 : state.dataContaminantBalance->GCZoneTimeMinus3 = state.dataContaminantBalance->OutdoorGC;
1351 0 : state.dataContaminantBalance->GCZoneTimeMinus4 = state.dataContaminantBalance->OutdoorGC;
1352 0 : state.dataContaminantBalance->DSGCZoneTimeMinus1 = state.dataContaminantBalance->OutdoorGC;
1353 0 : state.dataContaminantBalance->DSGCZoneTimeMinus2 = state.dataContaminantBalance->OutdoorGC;
1354 0 : state.dataContaminantBalance->DSGCZoneTimeMinus3 = state.dataContaminantBalance->OutdoorGC;
1355 0 : state.dataContaminantBalance->DSGCZoneTimeMinus4 = state.dataContaminantBalance->OutdoorGC;
1356 0 : state.dataContaminantBalance->GCZoneTimeMinus1Temp = 0.0;
1357 0 : state.dataContaminantBalance->GCZoneTimeMinus2Temp = 0.0;
1358 0 : state.dataContaminantBalance->GCZoneTimeMinus3Temp = 0.0;
1359 0 : state.dataContaminantBalance->ZoneAirGCTemp = state.dataContaminantBalance->OutdoorGC;
1360 0 : state.dataContaminantBalance->ZoneGCSetPoint = 0.0;
1361 0 : state.dataContaminantBalance->GCPredictedRate = 0.0;
1362 0 : state.dataContaminantBalance->ZoneAirGC = state.dataContaminantBalance->OutdoorGC;
1363 0 : state.dataContaminantBalance->ZoneGC1 = state.dataContaminantBalance->OutdoorGC;
1364 0 : state.dataContaminantBalance->ZoneGCMX = state.dataContaminantBalance->OutdoorGC;
1365 0 : state.dataContaminantBalance->ZoneGCM2 = state.dataContaminantBalance->OutdoorGC;
1366 0 : for (auto &con : state.dataContaminantBalance->ZoneContamGenericBLDiff) {
1367 0 : state.dataSurface->SurfGenericContam(con.SurfNum) = state.dataContaminantBalance->OutdoorGC;
1368 : }
1369 0 : if (!state.dataContaminantBalance->ZoneContamGenericDecay.empty())
1370 0 : for (auto &e : state.dataContaminantBalance->ZoneContamGenericDecay)
1371 0 : e.Time = 0.0;
1372 : }
1373 0 : state.dataZoneContaminantPredictorCorrector->MyEnvrnFlag = false;
1374 : }
1375 :
1376 0 : if (!state.dataGlobal->BeginEnvrnFlag) {
1377 0 : state.dataZoneContaminantPredictorCorrector->MyEnvrnFlag = true;
1378 : }
1379 :
1380 0 : if (allocated(state.dataZoneEquip->ZoneEquipConfig) && state.dataZoneContaminantPredictorCorrector->MyConfigOneTimeFlag) {
1381 0 : bool ErrorsFound = false;
1382 0 : for (int ContZoneNum = 1; ContZoneNum <= (int)state.dataContaminantBalance->ContaminantControlledZone.size(); ++ContZoneNum) {
1383 0 : int ZoneNum = state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum).ActualZoneNum;
1384 0 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumInletNodes; ++zoneInNode) {
1385 0 : int AirLoopNum = state.dataZoneEquip->ZoneEquipConfig(ZoneNum).InletNodeAirLoopNum(zoneInNode);
1386 0 : state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum).NumOfZones = 0;
1387 0 : for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
1388 0 : if (!state.dataZoneEquip->ZoneEquipConfig(Loop).IsControlled) continue;
1389 0 : for (int zoneInNode2 = 1; zoneInNode2 <= state.dataZoneEquip->ZoneEquipConfig(Loop).NumInletNodes; ++zoneInNode2) {
1390 0 : if (AirLoopNum == state.dataZoneEquip->ZoneEquipConfig(Loop).InletNodeAirLoopNum(zoneInNode2)) {
1391 0 : ++state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum).NumOfZones;
1392 0 : break; // only count a zone once
1393 : }
1394 : }
1395 : }
1396 0 : if (state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum).NumOfZones > 0) {
1397 0 : state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum)
1398 0 : .ControlZoneNum.allocate(state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum).NumOfZones);
1399 0 : int I = 1;
1400 0 : for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
1401 0 : if (!state.dataZoneEquip->ZoneEquipConfig(Loop).IsControlled) continue;
1402 0 : for (int zoneInNode2 = 1; zoneInNode2 <= state.dataZoneEquip->ZoneEquipConfig(Loop).NumInletNodes; ++zoneInNode2) {
1403 0 : if (AirLoopNum == state.dataZoneEquip->ZoneEquipConfig(Loop).InletNodeAirLoopNum(zoneInNode2)) {
1404 0 : state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum).ControlZoneNum(I) = Loop;
1405 0 : ++I;
1406 0 : break; // only count a zone once
1407 : }
1408 : }
1409 : }
1410 : } else {
1411 0 : ShowSevereError(state,
1412 0 : format("ZoneControl:ContaminantController: a corresponding AirLoopHVAC is not found for the controlled zone ={}",
1413 0 : state.dataHeatBal->Zone(ZoneNum).Name));
1414 0 : ErrorsFound = true;
1415 : }
1416 : }
1417 : }
1418 0 : state.dataZoneContaminantPredictorCorrector->MyConfigOneTimeFlag = false;
1419 0 : if (ErrorsFound) {
1420 0 : ShowFatalError(state, "ZoneControl:ContaminantController: Program terminates for preceding reason(s).");
1421 : }
1422 : }
1423 :
1424 0 : for (int Loop = 1; Loop <= (int)state.dataContaminantBalance->ContaminantControlledZone.size(); ++Loop) {
1425 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1426 0 : int ZoneNum = state.dataContaminantBalance->ContaminantControlledZone(Loop).ActualZoneNum;
1427 0 : state.dataContaminantBalance->ZoneCO2SetPoint(ZoneNum) =
1428 0 : state.dataContaminantBalance->ContaminantControlledZone(Loop).setptSched->getCurrentVal();
1429 : }
1430 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1431 0 : int ZoneNum = state.dataContaminantBalance->ContaminantControlledZone(Loop).ActualZoneNum;
1432 0 : state.dataContaminantBalance->ZoneGCSetPoint(ZoneNum) =
1433 0 : state.dataContaminantBalance->ContaminantControlledZone(Loop).genericContamSetptSched->getCurrentVal();
1434 : }
1435 : }
1436 :
1437 : // CO2 gain
1438 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1439 0 : for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
1440 0 : state.dataContaminantBalance->ZoneCO2Gain(Loop) = InternalHeatGains::SumAllInternalCO2Gains(state, Loop);
1441 0 : if (state.dataHybridModel->FlagHybridModel_PC) {
1442 0 : state.dataContaminantBalance->ZoneCO2GainExceptPeople(Loop) = InternalHeatGains::SumAllInternalCO2GainsExceptPeople(state, Loop);
1443 : }
1444 0 : std::array<DataHeatBalance::IntGainType, 1> IntGainPeopleArray = {DataHeatBalance::IntGainType::People};
1445 0 : state.dataContaminantBalance->ZoneCO2GainFromPeople(Loop) =
1446 0 : InternalHeatGains::SumInternalCO2GainsByTypes(state, Loop, IntGainPeopleArray);
1447 : }
1448 : }
1449 :
1450 : // Generic contaminant gain
1451 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1452 0 : state.dataContaminantBalance->ZoneGCGain = 0.0;
1453 : // from constant model
1454 0 : for (auto &con : state.dataContaminantBalance->ZoneContamGenericConstant) {
1455 0 : int ZoneNum = con.ActualZoneNum;
1456 0 : GCGain = con.GenerateRate * con.generateRateSched->getCurrentVal() -
1457 0 : con.RemovalCoef * con.removalCoefSched->getCurrentVal() * state.dataContaminantBalance->ZoneAirGC(ZoneNum) * 1.0e-6;
1458 0 : con.GenRate = GCGain;
1459 : }
1460 :
1461 : // from pressure driven model
1462 0 : if (state.afn->simulation_control.type != AirflowNetwork::ControlType::NoMultizoneOrDistribution) {
1463 0 : for (auto &con : state.dataContaminantBalance->ZoneContamGenericPDriven) {
1464 0 : int SurfNum = con.SurfNum;
1465 0 : Pi = state.afn->AirflowNetworkNodeSimu(state.afn->MultizoneSurfaceData(SurfNum).NodeNums[0]).PZ;
1466 0 : Pj = state.afn->AirflowNetworkNodeSimu(state.afn->MultizoneSurfaceData(SurfNum).NodeNums[1]).PZ;
1467 0 : if (Pj >= Pi) {
1468 0 : GCGain = con.GenRateCoef * con.generateRateCoefSched->getCurrentVal() * std::pow(Pj - Pi, con.Expo);
1469 : } else {
1470 0 : GCGain = 0.0;
1471 : }
1472 0 : con.GenRate = GCGain;
1473 : }
1474 : }
1475 :
1476 : // from cutoff model
1477 0 : for (auto &con : state.dataContaminantBalance->ZoneContamGenericCutoff) {
1478 0 : int ZoneNum = con.ActualZoneNum;
1479 0 : if (state.dataContaminantBalance->ZoneAirGC(ZoneNum) < con.CutoffValue) {
1480 0 : GCGain = con.GenerateRate * con.generateRateSched->getCurrentVal() *
1481 0 : (1.0 - state.dataContaminantBalance->ZoneAirGC(ZoneNum) / con.CutoffValue);
1482 : } else {
1483 0 : GCGain = 0.0;
1484 : }
1485 0 : con.GenRate = GCGain;
1486 : }
1487 :
1488 : // From decay model
1489 0 : for (auto &con : state.dataContaminantBalance->ZoneContamGenericDecay) {
1490 0 : int schVal = con.emitRateSched->getCurrentVal();
1491 0 : if (schVal == 0 || state.dataGlobal->BeginEnvrnFlag || state.dataGlobal->WarmupFlag) {
1492 0 : con.Time = 0.0;
1493 : } else {
1494 0 : con.Time += state.dataGlobal->TimeStepZoneSec;
1495 : }
1496 :
1497 0 : GCGain = con.InitEmitRate * schVal * std::exp(-con.Time / con.DelayTime);
1498 0 : con.GenRate = GCGain;
1499 : }
1500 :
1501 : // From boudary layer diffusion
1502 0 : for (auto &con : state.dataContaminantBalance->ZoneContamGenericBLDiff) {
1503 0 : int SurfNum = con.SurfNum;
1504 0 : int ZoneNum = state.dataSurface->Surface(SurfNum).Zone;
1505 : // Surface concentration level for the Boundary Layer Diffusion Controlled Model
1506 0 : Real64 Cs = state.dataSurface->SurfGenericContam(SurfNum);
1507 0 : Sch = con.transCoefSched->getCurrentVal();
1508 0 : GCGain = con.TransCoef * Sch * state.dataSurface->Surface(SurfNum).Area * state.dataSurface->Surface(SurfNum).Multiplier *
1509 0 : (Cs / con.HenryCoef - state.dataContaminantBalance->ZoneAirGC(ZoneNum)) * 1.0e-6;
1510 0 : con.GenRate = GCGain;
1511 : // Surface concentration level based on steady-state assumption
1512 0 : state.dataSurface->SurfGenericContam(SurfNum) =
1513 0 : Cs - GCGain * 1.0e6 / state.dataSurface->Surface(SurfNum).Multiplier / state.dataSurface->Surface(SurfNum).Area;
1514 : }
1515 :
1516 : // From deposition velocity sink model
1517 0 : for (auto &con : state.dataContaminantBalance->ZoneContamGenericDVS) {
1518 0 : int SurfNum = con.SurfNum;
1519 0 : int ZoneNum = state.dataSurface->Surface(SurfNum).Zone;
1520 0 : Sch = con.depoVeloSched->getCurrentVal();
1521 0 : GCGain = -con.DepoVelo * state.dataSurface->Surface(SurfNum).Area * Sch * state.dataContaminantBalance->ZoneAirGC(ZoneNum) *
1522 0 : state.dataSurface->Surface(SurfNum).Multiplier * 1.0e-6;
1523 0 : con.GenRate = GCGain;
1524 : }
1525 :
1526 : // From deposition rate sink model
1527 0 : for (auto &con : state.dataContaminantBalance->ZoneContamGenericDRS) {
1528 0 : int ZoneNum = con.ActualZoneNum;
1529 0 : Sch = con.depoRateSched->getCurrentVal();
1530 0 : GCGain = -con.DepoRate * state.dataHeatBal->Zone(ZoneNum).Volume * Sch * state.dataContaminantBalance->ZoneAirGC(ZoneNum) * 1.0e-6;
1531 0 : con.GenRate = GCGain;
1532 : }
1533 : }
1534 0 : }
1535 :
1536 3 : void PredictZoneContaminants(EnergyPlusData &state,
1537 : bool const ShortenTimeStepSys,
1538 : bool const UseZoneTimeStepHistory, // if true then use zone timestep history, if false use system time step
1539 : Real64 const PriorTimeStep // the old value for timestep length is passed for possible use in interpolating
1540 : )
1541 : {
1542 :
1543 : // SUBROUTINE INFORMATION:
1544 : // AUTHOR Lixing Gu
1545 : // DATE WRITTEN May 2010
1546 :
1547 : // PURPOSE OF THIS SUBROUTINE:
1548 : // This subroutine does the prediction step for contaminant control
1549 :
1550 : // METHODOLOGY EMPLOYED:
1551 : // This solves for the required outdoor airflow to achieve the desired contaminant setpoint in the Zone
1552 :
1553 : static constexpr std::string_view RoutineName("PredictZoneContaminants");
1554 :
1555 : Real64 A; // Coefficient of storage term in a zone balance equation
1556 : Real64 B; // Coefficient of variable term in a zone balance equation
1557 : Real64 C; // Coefficient of constnat term in a zone balance equation
1558 : Real64 LoadToCO2SetPoint; // CO2 load at CO2 set point
1559 : Real64 ZoneAirCO2SetPoint; // Zone CO2 setpoint
1560 : Real64 LoadToGCSetPoint; // Generic contaminant load at generic contaminant set point
1561 : Real64 ZoneAirGCSetPoint; // Zone generic contaminant setpoint
1562 : Real64 GCGain; // Zone generic contaminant internal load
1563 :
1564 3 : Real64 timeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
1565 : // Update zone CO2
1566 10 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1567 7 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
1568 :
1569 7 : if (ShortenTimeStepSys) {
1570 :
1571 0 : if (state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber > 0) { // roll back result for zone air node,
1572 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation)
1573 0 : state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber).CO2 =
1574 0 : state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum);
1575 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation)
1576 0 : state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber).GenContam =
1577 0 : state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum);
1578 : }
1579 :
1580 0 : if (state.dataHVACGlobal->NumOfSysTimeSteps !=
1581 0 : state.dataHVACGlobal->NumOfSysTimeStepsLastZoneTimeStep) { // cannot reuse existing DS data, interpolate from zone time
1582 :
1583 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation)
1584 0 : ZoneTempPredictorCorrector::DownInterpolate4HistoryValues(PriorTimeStep,
1585 0 : state.dataHVACGlobal->TimeStepSys,
1586 0 : state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum),
1587 0 : state.dataContaminantBalance->CO2ZoneTimeMinus2(ZoneNum),
1588 0 : state.dataContaminantBalance->CO2ZoneTimeMinus3(ZoneNum),
1589 0 : state.dataContaminantBalance->ZoneAirCO2(ZoneNum),
1590 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus1(ZoneNum),
1591 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus2(ZoneNum),
1592 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus3(ZoneNum),
1593 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus4(ZoneNum));
1594 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation)
1595 0 : ZoneTempPredictorCorrector::DownInterpolate4HistoryValues(PriorTimeStep,
1596 0 : state.dataHVACGlobal->TimeStepSys,
1597 0 : state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum),
1598 0 : state.dataContaminantBalance->GCZoneTimeMinus2(ZoneNum),
1599 0 : state.dataContaminantBalance->GCZoneTimeMinus3(ZoneNum),
1600 0 : state.dataContaminantBalance->ZoneAirGC(ZoneNum),
1601 0 : state.dataContaminantBalance->DSGCZoneTimeMinus1(ZoneNum),
1602 0 : state.dataContaminantBalance->DSGCZoneTimeMinus2(ZoneNum),
1603 0 : state.dataContaminantBalance->DSGCZoneTimeMinus3(ZoneNum),
1604 0 : state.dataContaminantBalance->DSGCZoneTimeMinus4(ZoneNum));
1605 :
1606 : } else { // reuse history data in DS terms from last zone time step to preserve information that would be lost
1607 : // do nothing because DS history would have been pushed prior and should be ready
1608 : }
1609 : }
1610 : // now update the variables actually used in the balance equations.
1611 7 : if (UseZoneTimeStepHistory) {
1612 :
1613 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1614 0 : state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum);
1615 0 : state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus2(ZoneNum);
1616 0 : state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus3(ZoneNum);
1617 : }
1618 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1619 0 : state.dataContaminantBalance->GCZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum);
1620 0 : state.dataContaminantBalance->GCZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus2(ZoneNum);
1621 0 : state.dataContaminantBalance->GCZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus3(ZoneNum);
1622 : }
1623 :
1624 : } else { // use down-stepped history
1625 :
1626 7 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1627 4 : state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus1(ZoneNum);
1628 4 : state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus2(ZoneNum);
1629 4 : state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus3(ZoneNum);
1630 : }
1631 7 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1632 4 : state.dataContaminantBalance->GCZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus1(ZoneNum);
1633 4 : state.dataContaminantBalance->GCZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus2(ZoneNum);
1634 4 : state.dataContaminantBalance->GCZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus3(ZoneNum);
1635 : }
1636 : }
1637 :
1638 7 : if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
1639 7 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1640 4 : if (ShortenTimeStepSys && state.dataHVACGlobal->TimeStepSys < state.dataGlobal->TimeStepZone) {
1641 0 : if (state.dataHVACGlobal->PreviousTimeStep < state.dataGlobal->TimeStepZone) {
1642 0 : state.dataContaminantBalance->ZoneCO21(ZoneNum) = state.dataContaminantBalance->ZoneCO2M2(ZoneNum);
1643 : } else {
1644 0 : state.dataContaminantBalance->ZoneCO21(ZoneNum) = state.dataContaminantBalance->ZoneCO2MX(ZoneNum);
1645 : }
1646 0 : state.dataHVACGlobal->ShortenTimeStepSysRoomAir = true;
1647 : } else {
1648 4 : state.dataContaminantBalance->ZoneCO21(ZoneNum) = state.dataContaminantBalance->ZoneAirCO2(ZoneNum);
1649 : }
1650 : }
1651 7 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1652 4 : if (ShortenTimeStepSys && state.dataHVACGlobal->TimeStepSys < state.dataGlobal->TimeStepZone) {
1653 0 : if (state.dataHVACGlobal->PreviousTimeStep < state.dataGlobal->TimeStepZone) {
1654 0 : state.dataContaminantBalance->ZoneGC1(ZoneNum) = state.dataContaminantBalance->ZoneGCM2(ZoneNum);
1655 : } else {
1656 0 : state.dataContaminantBalance->ZoneGC1(ZoneNum) = state.dataContaminantBalance->ZoneGCMX(ZoneNum);
1657 : }
1658 0 : state.dataHVACGlobal->ShortenTimeStepSysRoomAir = true;
1659 : } else {
1660 4 : state.dataContaminantBalance->ZoneGC1(ZoneNum) = state.dataContaminantBalance->ZoneAirGC(ZoneNum);
1661 : }
1662 : }
1663 : }
1664 :
1665 7 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1666 :
1667 4 : state.dataContaminantBalance->CO2PredictedRate(ZoneNum) = 0.0;
1668 4 : LoadToCO2SetPoint = 0.0;
1669 4 : state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP = 0.0;
1670 :
1671 : // Check to see if this is a "CO2 controlled zone"
1672 4 : bool ControlledCO2ZoneFlag = false;
1673 : // Check all the controlled zones to see if it matches the zone simulated
1674 7 : for (auto const &contaminantControlledZone : state.dataContaminantBalance->ContaminantControlledZone) {
1675 7 : if (contaminantControlledZone.ActualZoneNum == ZoneNum) {
1676 4 : if (contaminantControlledZone.availSched->getCurrentVal() > 0.0) {
1677 4 : ZoneAirCO2SetPoint = state.dataContaminantBalance->ZoneCO2SetPoint(contaminantControlledZone.ActualZoneNum);
1678 4 : if (contaminantControlledZone.EMSOverrideCO2SetPointOn) {
1679 0 : ZoneAirCO2SetPoint = contaminantControlledZone.EMSOverrideCO2SetPointValue;
1680 : }
1681 4 : ControlledCO2ZoneFlag = true;
1682 4 : break;
1683 : }
1684 : }
1685 : }
1686 4 : if (!ControlledCO2ZoneFlag) {
1687 0 : for (auto const &contaminantControlledZone : state.dataContaminantBalance->ContaminantControlledZone) {
1688 0 : if (contaminantControlledZone.availSched->getCurrentVal() > 0.0) {
1689 0 : ZoneAirCO2SetPoint = state.dataContaminantBalance->ZoneCO2SetPoint(contaminantControlledZone.ActualZoneNum);
1690 0 : if (contaminantControlledZone.EMSOverrideCO2SetPointOn) {
1691 0 : ZoneAirCO2SetPoint = contaminantControlledZone.EMSOverrideCO2SetPointValue;
1692 : }
1693 0 : if (contaminantControlledZone.NumOfZones >= 1) {
1694 0 : if (contaminantControlledZone.ActualZoneNum != ZoneNum) {
1695 0 : for (int I = 1; I <= contaminantControlledZone.NumOfZones; ++I) {
1696 0 : if (contaminantControlledZone.ControlZoneNum(I) == ZoneNum) {
1697 0 : ControlledCO2ZoneFlag = true;
1698 0 : break;
1699 : }
1700 : }
1701 0 : if (ControlledCO2ZoneFlag) break;
1702 : } else {
1703 0 : ControlledCO2ZoneFlag = true;
1704 0 : break;
1705 : }
1706 : }
1707 : }
1708 : }
1709 : } // CO2ControlledZoneNum
1710 :
1711 4 : if (ControlledCO2ZoneFlag) {
1712 4 : Real64 RhoAir = PsyRhoAirFnPbTdbW(state,
1713 4 : state.dataEnvrn->OutBaroPress,
1714 : thisZoneHB.ZT,
1715 : thisZoneHB.airHumRat,
1716 : RoutineName); // The density of air
1717 :
1718 : // Calculate Co2 from infiltration + humidity added from latent load to determine system added/subtracted moisture.
1719 4 : Real64 CO2Gain = state.dataContaminantBalance->ZoneCO2Gain(ZoneNum) * RhoAir * 1.0e6;
1720 :
1721 : // Calculate the coefficients for the 3rd Order derivative for final
1722 : // zone CO2. The A, B, C coefficients are analogous to the CO2 balance.
1723 : // Assume that the system will have flow
1724 8 : if (state.afn->multizone_always_simulated ||
1725 4 : (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
1726 0 : state.afn->AirflowNetworkFanActivated)) {
1727 : // Multizone airflow calculated in AirflowNetwork
1728 0 : B = CO2Gain + state.afn->exchangeData(ZoneNum).SumMHrCO + state.afn->exchangeData(ZoneNum).SumMMHrCO;
1729 0 : A = state.afn->exchangeData(ZoneNum).SumMHr + state.afn->exchangeData(ZoneNum).SumMMHr;
1730 : } else {
1731 8 : B = CO2Gain +
1732 4 : ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorCO2) +
1733 4 : state.dataContaminantBalance->MixingMassFlowCO2(ZoneNum) + thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorCO2;
1734 4 : A = thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
1735 : }
1736 4 : C = RhoAir * state.dataHeatBal->Zone(ZoneNum).Volume * state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpCO2 / timeStepSysSec;
1737 :
1738 : // Use a 3rd Order derivative to predict zone moisture addition or removal and
1739 : // smooth the changes using the zone air capacitance. Positive values of CO2 Load means that
1740 : // this amount of CO2 must be added to the zone to reach the setpoint. Negative values represent
1741 : // the amount of CO2 that must be removed by the system.
1742 4 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
1743 0 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
1744 0 : LoadToCO2SetPoint = ((11.0 / 6.0) * C + A) * ZoneAirCO2SetPoint -
1745 0 : (B + C * (3.0 * state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) -
1746 0 : (3.0 / 2.0) * state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) +
1747 0 : (1.0 / 3.0) * state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum)));
1748 : // Exact solution
1749 0 : } break;
1750 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
1751 0 : if (A == 0.0) { // B=0
1752 0 : LoadToCO2SetPoint = C * (ZoneAirCO2SetPoint - state.dataContaminantBalance->ZoneCO21(ZoneNum)) - B;
1753 : } else {
1754 0 : LoadToCO2SetPoint =
1755 0 : A * (ZoneAirCO2SetPoint - state.dataContaminantBalance->ZoneCO21(ZoneNum) * std::exp(min(700.0, -A / C))) /
1756 0 : (1.0 - std::exp(min(700.0, -A / C))) -
1757 : B;
1758 : }
1759 0 : } break;
1760 4 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
1761 4 : LoadToCO2SetPoint = C * (ZoneAirCO2SetPoint - state.dataContaminantBalance->ZoneCO21(ZoneNum)) + A * ZoneAirCO2SetPoint - B;
1762 4 : } break;
1763 0 : default:
1764 0 : break;
1765 : }
1766 4 : if (ZoneAirCO2SetPoint > state.dataContaminantBalance->OutdoorCO2 && LoadToCO2SetPoint < 0.0) {
1767 4 : state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP =
1768 4 : LoadToCO2SetPoint / (state.dataContaminantBalance->OutdoorCO2 - ZoneAirCO2SetPoint);
1769 : }
1770 : }
1771 :
1772 : // Apply the Zone Multiplier to the total zone moisture load
1773 4 : state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP *=
1774 4 : state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier;
1775 4 : state.dataContaminantBalance->CO2PredictedRate(ZoneNum) = state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP;
1776 : }
1777 :
1778 7 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1779 :
1780 4 : state.dataContaminantBalance->GCPredictedRate(ZoneNum) = 0.0;
1781 4 : LoadToGCSetPoint = 0.0;
1782 4 : state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToGCSP = 0.0;
1783 :
1784 : // Check to see if this is a "GC controlled zone"
1785 4 : bool ControlledGCZoneFlag = false;
1786 : // Check all the controlled zones to see if it matches the zone simulated
1787 7 : for (auto const &contaminantControlledZone : state.dataContaminantBalance->ContaminantControlledZone) {
1788 7 : if (contaminantControlledZone.ActualZoneNum == ZoneNum) {
1789 4 : if (contaminantControlledZone.genericContamAvailSched->getCurrentVal() > 0.0) {
1790 4 : ZoneAirGCSetPoint = state.dataContaminantBalance->ZoneGCSetPoint(contaminantControlledZone.ActualZoneNum);
1791 4 : if (contaminantControlledZone.EMSOverrideCO2SetPointOn) {
1792 0 : ZoneAirGCSetPoint = contaminantControlledZone.EMSOverrideGCSetPointValue;
1793 : }
1794 4 : ControlledGCZoneFlag = true;
1795 4 : break;
1796 : }
1797 : }
1798 : }
1799 4 : if (!ControlledGCZoneFlag) {
1800 0 : for (auto const &contaminantControlledZone : state.dataContaminantBalance->ContaminantControlledZone) {
1801 0 : if (contaminantControlledZone.genericContamAvailSched->getCurrentVal() > 0.0) {
1802 0 : ZoneAirGCSetPoint = state.dataContaminantBalance->ZoneGCSetPoint(contaminantControlledZone.ActualZoneNum);
1803 0 : if (contaminantControlledZone.EMSOverrideCO2SetPointOn) {
1804 0 : ZoneAirGCSetPoint = contaminantControlledZone.EMSOverrideGCSetPointValue;
1805 : }
1806 0 : if (contaminantControlledZone.NumOfZones >= 1) {
1807 0 : if (contaminantControlledZone.ActualZoneNum != ZoneNum) {
1808 0 : for (int I = 1; I <= contaminantControlledZone.NumOfZones; ++I) {
1809 0 : if (contaminantControlledZone.ControlZoneNum(I) == ZoneNum) {
1810 0 : ControlledGCZoneFlag = true;
1811 0 : break;
1812 : }
1813 : }
1814 0 : if (ControlledGCZoneFlag) break;
1815 : } else {
1816 0 : ControlledGCZoneFlag = true;
1817 0 : break;
1818 : }
1819 : }
1820 : }
1821 : }
1822 : }
1823 :
1824 4 : if (ControlledGCZoneFlag) {
1825 : // The density of air
1826 4 : Real64 RhoAir = PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisZoneHB.ZT, thisZoneHB.airHumRat, RoutineName);
1827 :
1828 : // Calculate generic contaminant from infiltration + humidity added from latent load
1829 : // to determine system added/subtracted moisture.
1830 4 : GCGain = state.dataContaminantBalance->ZoneGCGain(ZoneNum) * RhoAir * 1.0e6;
1831 :
1832 : // Calculate the coefficients for the 3rd Order derivative for final
1833 : // zone GC. The A, B, C coefficients are analogous to the GC balance.
1834 : // Assume that the system will have flow
1835 8 : if (state.afn->multizone_always_simulated ||
1836 4 : (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
1837 0 : state.afn->AirflowNetworkFanActivated)) {
1838 : // Multizone airflow calculated in AirflowNetwork
1839 0 : B = GCGain + state.afn->exchangeData(ZoneNum).SumMHrGC + state.afn->exchangeData(ZoneNum).SumMMHrGC;
1840 0 : A = state.afn->exchangeData(ZoneNum).SumMHr + state.afn->exchangeData(ZoneNum).SumMMHr;
1841 : } else {
1842 8 : B = GCGain +
1843 4 : ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorGC) +
1844 4 : state.dataContaminantBalance->MixingMassFlowGC(ZoneNum) + thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorGC;
1845 4 : A = thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
1846 : }
1847 4 : C = RhoAir * state.dataHeatBal->Zone(ZoneNum).Volume * state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpGenContam / timeStepSysSec;
1848 :
1849 : // Use a 3rd Order derivative to predict zone moisture addition or removal and
1850 : // smooth the changes using the zone air capacitance. Positive values of GC Load means that
1851 : // this amount of GC must be added to the zone to reach the setpoint. Negative values represent
1852 : // the amount of GC that must be removed by the system.
1853 4 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
1854 0 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
1855 0 : LoadToGCSetPoint = ((11.0 / 6.0) * C + A) * ZoneAirGCSetPoint -
1856 0 : (B + C * (3.0 * state.dataContaminantBalance->GCZoneTimeMinus1Temp(ZoneNum) -
1857 0 : (3.0 / 2.0) * state.dataContaminantBalance->GCZoneTimeMinus2Temp(ZoneNum) +
1858 0 : (1.0 / 3.0) * state.dataContaminantBalance->GCZoneTimeMinus3Temp(ZoneNum)));
1859 : // Exact solution
1860 0 : } break;
1861 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
1862 0 : if (A == 0.0) { // B=0
1863 0 : LoadToGCSetPoint = C * (ZoneAirGCSetPoint - state.dataContaminantBalance->ZoneGC1(ZoneNum)) - B;
1864 : } else {
1865 0 : LoadToGCSetPoint = A * (ZoneAirGCSetPoint - state.dataContaminantBalance->ZoneGC1(ZoneNum) * std::exp(min(700.0, -A / C))) /
1866 0 : (1.0 - std::exp(min(700.0, -A / C))) -
1867 : B;
1868 : }
1869 0 : } break;
1870 4 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
1871 4 : LoadToGCSetPoint = C * (ZoneAirGCSetPoint - state.dataContaminantBalance->ZoneGC1(ZoneNum)) + A * ZoneAirGCSetPoint - B;
1872 4 : } break;
1873 0 : default:
1874 0 : break;
1875 : }
1876 4 : if (ZoneAirGCSetPoint > state.dataContaminantBalance->OutdoorGC && LoadToGCSetPoint < 0.0) {
1877 4 : state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToGCSP =
1878 4 : LoadToGCSetPoint / (state.dataContaminantBalance->OutdoorGC - ZoneAirGCSetPoint);
1879 : }
1880 : }
1881 :
1882 : // Apply the Zone Multiplier to the total zone moisture load
1883 4 : state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToGCSP *=
1884 4 : state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier;
1885 4 : state.dataContaminantBalance->GCPredictedRate(ZoneNum) = state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToGCSP;
1886 : }
1887 : }
1888 3 : }
1889 :
1890 0 : void PushZoneTimestepHistories(EnergyPlusData &state)
1891 : {
1892 :
1893 : // SUBROUTINE INFORMATION:
1894 : // AUTHOR Lixing Gu
1895 : // DATE WRITTEN July, 2010
1896 :
1897 : // PURPOSE OF THIS SUBROUTINE:
1898 : // Push the temperature and humidity ratio histories
1899 : // This subroutine is modified from PushZoneTimestepHistories in ZoneTempPredictorCorrector module
1900 :
1901 0 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1902 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1903 0 : state.dataContaminantBalance->CO2ZoneTimeMinus4(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus3(ZoneNum);
1904 0 : state.dataContaminantBalance->CO2ZoneTimeMinus3(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus2(ZoneNum);
1905 0 : state.dataContaminantBalance->CO2ZoneTimeMinus2(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum);
1906 0 : state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum) =
1907 0 : state.dataContaminantBalance->ZoneAirCO2Avg(ZoneNum); // using average for whole zone time step.
1908 0 : state.dataContaminantBalance->ZoneAirCO2(ZoneNum) = state.dataContaminantBalance->ZoneAirCO2Temp(ZoneNum);
1909 :
1910 0 : if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
1911 0 : state.dataContaminantBalance->ZoneCO2M2(ZoneNum) = state.dataContaminantBalance->ZoneCO2MX(ZoneNum);
1912 0 : state.dataContaminantBalance->ZoneCO2MX(ZoneNum) =
1913 0 : state.dataContaminantBalance->ZoneAirCO2Avg(ZoneNum); // using average for whole zone time step.
1914 : }
1915 : }
1916 :
1917 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1918 0 : state.dataContaminantBalance->GCZoneTimeMinus4(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus3(ZoneNum);
1919 0 : state.dataContaminantBalance->GCZoneTimeMinus3(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus2(ZoneNum);
1920 0 : state.dataContaminantBalance->GCZoneTimeMinus2(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum);
1921 0 : state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum) =
1922 0 : state.dataContaminantBalance->ZoneAirGCAvg(ZoneNum); // using average for whole zone time step.
1923 0 : state.dataContaminantBalance->ZoneAirGC(ZoneNum) = state.dataContaminantBalance->ZoneAirGCTemp(ZoneNum);
1924 :
1925 0 : if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
1926 0 : state.dataContaminantBalance->ZoneGCM2(ZoneNum) = state.dataContaminantBalance->ZoneGCMX(ZoneNum);
1927 0 : state.dataContaminantBalance->ZoneGCMX(ZoneNum) =
1928 0 : state.dataContaminantBalance->ZoneAirGCAvg(ZoneNum); // using average for whole zone time step.
1929 : }
1930 : }
1931 : }
1932 0 : }
1933 :
1934 0 : void PushSystemTimestepHistories(EnergyPlusData &state)
1935 : {
1936 :
1937 : // SUBROUTINE INFORMATION:
1938 : // AUTHOR Lixing Gu
1939 : // DATE WRITTEN July, 2010
1940 :
1941 : // PURPOSE OF THIS SUBROUTINE:
1942 : // push histories back in time
1943 : // This subroutine is modified from PushSystemTimestepHistories in ZoneTempPredictorCorrector module
1944 :
1945 0 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1946 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1947 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus4(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus3(ZoneNum);
1948 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus3(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus2(ZoneNum);
1949 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus2(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus1(ZoneNum);
1950 0 : state.dataContaminantBalance->DSCO2ZoneTimeMinus1(ZoneNum) = state.dataContaminantBalance->ZoneAirCO2(ZoneNum);
1951 : }
1952 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1953 0 : state.dataContaminantBalance->DSGCZoneTimeMinus4(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus3(ZoneNum);
1954 0 : state.dataContaminantBalance->DSGCZoneTimeMinus3(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus2(ZoneNum);
1955 0 : state.dataContaminantBalance->DSGCZoneTimeMinus2(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus1(ZoneNum);
1956 0 : state.dataContaminantBalance->DSGCZoneTimeMinus1(ZoneNum) = state.dataContaminantBalance->ZoneAirGC(ZoneNum);
1957 : }
1958 : }
1959 :
1960 0 : if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
1961 0 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1962 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1963 0 : state.dataContaminantBalance->ZoneCO2M2(ZoneNum) = state.dataContaminantBalance->ZoneCO2MX(ZoneNum);
1964 0 : state.dataContaminantBalance->ZoneCO2MX(ZoneNum) =
1965 0 : state.dataContaminantBalance->ZoneAirCO2Temp(ZoneNum); // using average for whole zone time step.
1966 : }
1967 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1968 0 : state.dataContaminantBalance->ZoneGCM2(ZoneNum) = state.dataContaminantBalance->ZoneGCMX(ZoneNum);
1969 0 : state.dataContaminantBalance->ZoneGCMX(ZoneNum) =
1970 0 : state.dataContaminantBalance->ZoneAirGCTemp(ZoneNum); // using average for whole zone time step.
1971 : }
1972 : }
1973 : }
1974 0 : }
1975 :
1976 0 : void RevertZoneTimestepHistories(EnergyPlusData &state)
1977 : {
1978 :
1979 : // SUBROUTINE INFORMATION:
1980 : // AUTHOR Lixing Gu
1981 : // DATE WRITTEN July, 2010
1982 :
1983 : // PURPOSE OF THIS SUBROUTINE:
1984 : // rewind histories to undo inadvertent pushing
1985 : // This subroutine is modified from RevertZoneTimestepHistories in ZoneTempPredictorCorrector module
1986 :
1987 0 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1988 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1989 0 : state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus2(ZoneNum);
1990 0 : state.dataContaminantBalance->CO2ZoneTimeMinus2(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus3(ZoneNum);
1991 0 : state.dataContaminantBalance->CO2ZoneTimeMinus3(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus4(ZoneNum);
1992 : }
1993 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1994 0 : state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus2(ZoneNum);
1995 0 : state.dataContaminantBalance->GCZoneTimeMinus2(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus3(ZoneNum);
1996 0 : state.dataContaminantBalance->GCZoneTimeMinus3(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus4(ZoneNum);
1997 : }
1998 : }
1999 0 : }
2000 :
2001 4 : void InverseModelCO2(EnergyPlusData &state,
2002 : int const ZoneNum, // Zone number
2003 : Real64 const CO2Gain, // Zone total CO2 gain
2004 : Real64 const CO2GainExceptPeople, // ZOne total CO2 gain from sources except for people
2005 : Real64 const ZoneMassFlowRate, // Zone air mass flow rate
2006 : Real64 const CO2MassFlowRate, // Zone air CO2 mass flow rate
2007 : Real64 const RhoAir // Air density
2008 : )
2009 : {
2010 : // SUBROUTINE INFORMATION:
2011 : // AUTHOR Han Li
2012 : // DATE WRITTEN February 2019
2013 :
2014 : // PURPOSE OF THIS SUBROUTINE:
2015 : // This subroutine inversely solve infiltration airflow rate or people count with zone air CO2 concentration measurements.
2016 :
2017 4 : Real64 AA(0.0);
2018 4 : Real64 BB(0.0);
2019 4 : Real64 M_inf(0.0); // Reversely solved infiltration mass flow rate
2020 :
2021 4 : Real64 timeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
2022 :
2023 4 : auto &hmZone = state.dataHybridModel->hybridModelZones(ZoneNum);
2024 :
2025 4 : state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredCO2Concentration = hmZone.measuredCO2ConcSched->getCurrentVal();
2026 :
2027 4 : if (state.dataEnvrn->DayOfYear >= hmZone.HybridStartDayOfYear && state.dataEnvrn->DayOfYear <= hmZone.HybridEndDayOfYear) {
2028 4 : state.dataContaminantBalance->ZoneAirCO2(ZoneNum) = state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredCO2Concentration;
2029 :
2030 4 : auto const &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
2031 4 : if (hmZone.InfiltrationCalc_C && state.dataHVACGlobal->UseZoneTimeStepHistory) {
2032 : static constexpr std::string_view RoutineNameInfiltration("CalcAirFlowSimple:Infiltration");
2033 : // Conditionally calculate the CO2-dependent and CO2-independent terms.
2034 2 : if (hmZone.IncludeSystemSupplyParameters) {
2035 1 : state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirFlowRate = hmZone.supplyAirMassFlowRateSched->getCurrentVal();
2036 1 : state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirCO2Concentration = hmZone.supplyAirCO2ConcSched->getCurrentVal();
2037 :
2038 1 : Real64 SumSysM_HM = state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirFlowRate;
2039 1 : Real64 SumSysMxCO2_HM = state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirFlowRate *
2040 1 : state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirCO2Concentration;
2041 :
2042 1 : AA = SumSysM_HM + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
2043 3 : BB = SumSysMxCO2_HM + CO2Gain +
2044 1 : ((thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorCO2) +
2045 1 : state.dataContaminantBalance->MixingMassFlowCO2(ZoneNum) + thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorCO2;
2046 :
2047 : } else {
2048 1 : AA = thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
2049 1 : BB = CO2Gain + ((thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorCO2) +
2050 1 : state.dataContaminantBalance->MixingMassFlowCO2(ZoneNum) + thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorCO2;
2051 : }
2052 :
2053 2 : Real64 CC = RhoAir * state.dataHeatBal->Zone(ZoneNum).Volume * state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpCO2 / timeStepSysSec;
2054 2 : Real64 DD = (3.0 * state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) -
2055 2 : (3.0 / 2.0) * state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) +
2056 2 : (1.0 / 3.0) * state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum));
2057 :
2058 2 : Real64 delta_CO2 = (state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredCO2Concentration - state.dataContaminantBalance->OutdoorCO2) / 1000;
2059 2 : Real64 CpAir = PsyCpAirFnW(state.dataEnvrn->OutHumRat);
2060 2 : Real64 AirDensity = PsyRhoAirFnPbTdbW(state,
2061 2 : state.dataEnvrn->OutBaroPress,
2062 2 : state.dataHeatBal->Zone(ZoneNum).OutDryBulbTemp,
2063 2 : state.dataEnvrn->OutHumRat,
2064 : RoutineNameInfiltration);
2065 :
2066 2 : if (state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredCO2Concentration == state.dataContaminantBalance->OutdoorCO2) {
2067 0 : M_inf = 0.0;
2068 : } else {
2069 2 : M_inf = (CC * DD + BB - ((11.0 / 6.0) * CC + AA) * state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredCO2Concentration) / delta_CO2;
2070 : }
2071 :
2072 : // Add threshold for air change rate
2073 2 : Real64 ACH_inf = max(0.0, min(10.0, M_inf / (CpAir * AirDensity / Constant::rSecsInHour * state.dataHeatBal->Zone(ZoneNum).Volume)));
2074 2 : M_inf = ACH_inf * state.dataHeatBal->Zone(ZoneNum).Volume * AirDensity / Constant::rSecsInHour;
2075 2 : state.dataHeatBal->Zone(ZoneNum).MCPIHM = M_inf;
2076 2 : state.dataHeatBal->Zone(ZoneNum).InfilOAAirChangeRateHM = ACH_inf;
2077 : }
2078 :
2079 : // Hybrid Model calculate people count
2080 4 : if (hmZone.PeopleCountCalc_C && state.dataHVACGlobal->UseZoneTimeStepHistory) {
2081 2 : state.dataHeatBal->Zone(ZoneNum).ZonePeopleActivityLevel =
2082 2 : hmZone.peopleActivityLevelSched ? hmZone.peopleActivityLevelSched->getCurrentVal() : 0.0;
2083 2 : Real64 ActivityLevel = hmZone.peopleActivityLevelSched ? hmZone.peopleActivityLevelSched->getCurrentVal() : 0.0;
2084 2 : Real64 CO2GenRate = hmZone.peopleCO2GenRateSched ? hmZone.peopleCO2GenRateSched->getCurrentVal() : 0.0;
2085 2 : if (ActivityLevel <= 0.0) {
2086 1 : ActivityLevel = 130.0; // 130.0 is the default people activity level [W]
2087 : }
2088 2 : if (CO2GenRate <= 0.0) {
2089 1 : CO2GenRate = 0.0000000382; // 0.0000000382 is the default CO2, generation rate [m3/(s*W)]
2090 : }
2091 :
2092 : // Conditionally calculate the CO2-dependent and CO2-independent terms.
2093 2 : if (hmZone.IncludeSystemSupplyParameters) {
2094 1 : state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirFlowRate = hmZone.supplyAirMassFlowRateSched->getCurrentVal();
2095 1 : state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirCO2Concentration = hmZone.supplyAirCO2ConcSched->getCurrentVal();
2096 :
2097 1 : Real64 SumSysM_HM = state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirFlowRate;
2098 1 : Real64 SumSysMxCO2_HM = state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirFlowRate *
2099 1 : state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirCO2Concentration;
2100 :
2101 1 : AA = SumSysM_HM + thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone +
2102 1 : thisZoneHB.MDotOA;
2103 2 : BB = CO2GainExceptPeople +
2104 1 : ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorCO2) +
2105 1 : (SumSysMxCO2_HM) + state.dataContaminantBalance->MixingMassFlowCO2(ZoneNum) +
2106 1 : thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorCO2;
2107 :
2108 : } else {
2109 1 : AA = ZoneMassFlowRate + thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone +
2110 1 : thisZoneHB.MDotOA;
2111 2 : BB = CO2GainExceptPeople +
2112 1 : ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorCO2) +
2113 1 : (CO2MassFlowRate) + state.dataContaminantBalance->MixingMassFlowCO2(ZoneNum) +
2114 1 : thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorCO2;
2115 : }
2116 :
2117 2 : Real64 CC = RhoAir * state.dataHeatBal->Zone(ZoneNum).Volume * state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpCO2 / timeStepSysSec;
2118 2 : Real64 DD = (3.0 * state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) -
2119 2 : (3.0 / 2.0) * state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) +
2120 2 : (1.0 / 3.0) * state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum));
2121 :
2122 : Real64 CO2GainPeople =
2123 2 : (((11.0 / 6.0) * CC + AA) * state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredCO2Concentration - BB - CC * DD) / (1000000 * RhoAir);
2124 :
2125 : // Make sure the results are reasonable
2126 2 : Real64 UpperBound = CO2Gain / (1000000 * RhoAir * CO2GenRate * ActivityLevel);
2127 2 : Real64 NumPeople = min(UpperBound, CO2GainPeople / (CO2GenRate * ActivityLevel));
2128 :
2129 2 : NumPeople = floor(NumPeople * 100.00 + 0.5) / 100.00;
2130 2 : if (NumPeople < 0.05) {
2131 0 : NumPeople = 0;
2132 : }
2133 2 : state.dataHeatBal->Zone(ZoneNum).NumOccHM = NumPeople;
2134 : }
2135 : }
2136 :
2137 : // Update zone humidity ratio in the previous steps
2138 4 : state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum);
2139 4 : state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum);
2140 4 : state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) = state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredCO2Concentration;
2141 4 : }
2142 :
2143 6 : void CorrectZoneContaminants(EnergyPlusData &state,
2144 : bool const UseZoneTimeStepHistory // if true then use zone timestep history, if false use system time step history
2145 : )
2146 : {
2147 :
2148 : // SUBROUTINE INFORMATION:
2149 : // AUTHOR Lixing Gu
2150 : // DATE WRITTEN July, 2010
2151 :
2152 : // PURPOSE OF THIS SUBROUTINE:
2153 : // This subroutine updates the zone contaminants.
2154 : // This subroutine is modified from CorrectZoneHumRat in ZoneTempPredictorCorrector module
2155 :
2156 : // REFERENCES:
2157 : // Routine FinalZnCalcs - FINAL ZONE CALCULATIONS, authored by Dale Herron for BLAST.
2158 :
2159 : static constexpr std::string_view RoutineName("CorrectZoneContaminants");
2160 :
2161 : Real64 CO2Gain; // Zone CO2 internal gain
2162 : Real64 CO2GainExceptPeople; // Added for hybrid model, Zone CO2 internal gain
2163 : Real64 GCGain; // Zone generic contaminant internal gain
2164 : Real64 A;
2165 : Real64 B;
2166 : Real64 C;
2167 :
2168 : // Update zone CO2
2169 12 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
2170 :
2171 6 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2172 6 : state.dataContaminantBalance->AZ(ZoneNum) = 0.0;
2173 6 : state.dataContaminantBalance->BZ(ZoneNum) = 0.0;
2174 6 : state.dataContaminantBalance->CZ(ZoneNum) = 0.0;
2175 : }
2176 6 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2177 2 : state.dataContaminantBalance->AZGC(ZoneNum) = 0.0;
2178 2 : state.dataContaminantBalance->BZGC(ZoneNum) = 0.0;
2179 2 : state.dataContaminantBalance->CZGC(ZoneNum) = 0.0;
2180 : }
2181 :
2182 : // update the variables actually used in the balance equations.
2183 6 : if (!UseZoneTimeStepHistory) {
2184 2 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2185 2 : state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus1(ZoneNum);
2186 2 : state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus2(ZoneNum);
2187 2 : state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus3(ZoneNum);
2188 : }
2189 2 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2190 2 : state.dataContaminantBalance->GCZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus1(ZoneNum);
2191 2 : state.dataContaminantBalance->GCZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus2(ZoneNum);
2192 2 : state.dataContaminantBalance->GCZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus3(ZoneNum);
2193 : }
2194 : } else {
2195 4 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2196 4 : state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum);
2197 4 : state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus2(ZoneNum);
2198 4 : state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus3(ZoneNum);
2199 : }
2200 4 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2201 0 : state.dataContaminantBalance->GCZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum);
2202 0 : state.dataContaminantBalance->GCZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus2(ZoneNum);
2203 0 : state.dataContaminantBalance->GCZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus3(ZoneNum);
2204 : }
2205 : }
2206 :
2207 : // Start to calculate zone CO2 and genric contaminant levels
2208 6 : Real64 CO2MassFlowRate = 0.0;
2209 6 : Real64 GCMassFlowRate = 0.0;
2210 6 : Real64 ZoneMassFlowRate = 0.0;
2211 6 : int ZoneMult = state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier;
2212 :
2213 : // Check to see if this is a controlled zone
2214 6 : const bool ControlledZoneAirFlag = state.dataHeatBal->Zone(ZoneNum).IsControlled;
2215 :
2216 : // Check to see if this is a plenum zone
2217 6 : bool ZoneRetPlenumAirFlag = false;
2218 6 : int ZoneRetPlenumNum = 0;
2219 6 : for (ZoneRetPlenumNum = 1; ZoneRetPlenumNum <= state.dataZonePlenum->NumZoneReturnPlenums; ++ZoneRetPlenumNum) {
2220 0 : if (state.dataZonePlenum->ZoneRetPlenCond(ZoneRetPlenumNum).ActualZoneNum != ZoneNum) continue;
2221 0 : ZoneRetPlenumAirFlag = true;
2222 0 : break;
2223 : }
2224 6 : bool ZoneSupPlenumAirFlag = false;
2225 6 : int ZoneSupPlenumNum = 0;
2226 6 : for (ZoneSupPlenumNum = 1; ZoneSupPlenumNum <= state.dataZonePlenum->NumZoneSupplyPlenums; ++ZoneSupPlenumNum) {
2227 0 : if (state.dataZonePlenum->ZoneSupPlenCond(ZoneSupPlenumNum).ActualZoneNum != ZoneNum) continue;
2228 0 : ZoneSupPlenumAirFlag = true;
2229 0 : break;
2230 : }
2231 :
2232 6 : if (ControlledZoneAirFlag) { // If there is system flow then calculate the flow rates
2233 :
2234 : // Calculate moisture flow rate into each zone
2235 4 : for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumInletNodes; ++NodeNum) {
2236 0 : auto const &node = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(ZoneNum).InletNode(NodeNum));
2237 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2238 0 : CO2MassFlowRate += (node.MassFlowRate * node.CO2) / ZoneMult;
2239 : }
2240 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2241 0 : GCMassFlowRate += (node.MassFlowRate * node.GenContam) / ZoneMult;
2242 : }
2243 0 : ZoneMassFlowRate += node.MassFlowRate / ZoneMult;
2244 : }
2245 :
2246 : // Do the calculations for the plenum zone
2247 2 : } else if (ZoneRetPlenumAirFlag) {
2248 0 : for (int NodeNum = 1; NodeNum <= state.dataZonePlenum->ZoneRetPlenCond(ZoneRetPlenumNum).NumInletNodes; ++NodeNum) {
2249 0 : auto const &node = state.dataLoopNodes->Node(state.dataZonePlenum->ZoneRetPlenCond(ZoneRetPlenumNum).InletNode(NodeNum));
2250 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2251 0 : CO2MassFlowRate += (node.MassFlowRate * node.CO2) / ZoneMult;
2252 : }
2253 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2254 0 : GCMassFlowRate += (node.MassFlowRate * node.GenContam) / ZoneMult;
2255 : }
2256 0 : ZoneMassFlowRate += node.MassFlowRate / ZoneMult;
2257 : }
2258 : // add in the leak flow
2259 0 : for (int ADUListIndex = 1; ADUListIndex <= state.dataZonePlenum->ZoneRetPlenCond(ZoneRetPlenumNum).NumADUs; ++ADUListIndex) {
2260 0 : int ADUNum = state.dataZonePlenum->ZoneRetPlenCond(ZoneRetPlenumNum).ADUIndex(ADUListIndex);
2261 0 : if (state.dataDefineEquipment->AirDistUnit(ADUNum).UpStreamLeak) {
2262 0 : auto &airDistUnit = state.dataDefineEquipment->AirDistUnit(ADUNum);
2263 0 : auto const &node = state.dataLoopNodes->Node(airDistUnit.InletNodeNum);
2264 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2265 0 : CO2MassFlowRate += (airDistUnit.MassFlowRateUpStrLk * node.CO2) / ZoneMult;
2266 : }
2267 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2268 0 : GCMassFlowRate += (airDistUnit.MassFlowRateUpStrLk * node.GenContam) / ZoneMult;
2269 : }
2270 0 : ZoneMassFlowRate += airDistUnit.MassFlowRateUpStrLk / ZoneMult;
2271 : }
2272 0 : if (state.dataDefineEquipment->AirDistUnit(ADUNum).DownStreamLeak) {
2273 0 : auto &airDistUnit = state.dataDefineEquipment->AirDistUnit(ADUNum);
2274 0 : auto const &node = state.dataLoopNodes->Node(airDistUnit.OutletNodeNum);
2275 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2276 0 : CO2MassFlowRate += (airDistUnit.MassFlowRateDnStrLk * node.CO2) / ZoneMult;
2277 : }
2278 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2279 0 : GCMassFlowRate += (airDistUnit.MassFlowRateDnStrLk * node.GenContam) / ZoneMult;
2280 : }
2281 0 : ZoneMassFlowRate += airDistUnit.MassFlowRateDnStrLk / ZoneMult;
2282 : }
2283 : }
2284 :
2285 2 : } else if (ZoneSupPlenumAirFlag) {
2286 0 : auto const &node = state.dataLoopNodes->Node(state.dataZonePlenum->ZoneSupPlenCond(ZoneSupPlenumNum).InletNode);
2287 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2288 0 : CO2MassFlowRate += (node.MassFlowRate * node.CO2) / ZoneMult;
2289 : }
2290 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2291 0 : GCMassFlowRate += (node.MassFlowRate * node.GenContam) / ZoneMult;
2292 : }
2293 0 : ZoneMassFlowRate += node.MassFlowRate / ZoneMult;
2294 : }
2295 :
2296 6 : Real64 timeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
2297 6 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
2298 :
2299 : // Calculate the coefficients for the 3rd order derivative for final
2300 : // zone humidity ratio. The A, B, C coefficients are analogous to the
2301 : // CO2 balance. There are 2 cases that should be considered, system operating and system shutdown.
2302 :
2303 6 : Real64 RhoAir = PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisZoneHB.ZT, thisZoneHB.airHumRat, RoutineName);
2304 :
2305 6 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) state.dataContaminantBalance->ZoneAirDensityCO(ZoneNum) = RhoAir;
2306 : // Calculate Co2 internal gain
2307 6 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) CO2Gain = state.dataContaminantBalance->ZoneCO2Gain(ZoneNum) * RhoAir * 1.0e6;
2308 6 : if (state.dataContaminantBalance->Contaminant.CO2Simulation)
2309 6 : CO2GainExceptPeople = state.dataContaminantBalance->ZoneCO2GainExceptPeople(ZoneNum) * RhoAir * 1.0e6; // Addded for hybrid model
2310 6 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation)
2311 2 : GCGain = state.dataContaminantBalance->ZoneGCGain(ZoneNum) * RhoAir * 1.0e6;
2312 :
2313 6 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2314 6 : B = CO2Gain + ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorCO2) +
2315 6 : (CO2MassFlowRate) + state.dataContaminantBalance->MixingMassFlowCO2(ZoneNum) +
2316 6 : thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorCO2;
2317 6 : A = ZoneMassFlowRate + thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone +
2318 6 : thisZoneHB.MDotOA;
2319 12 : if (state.afn->multizone_always_simulated ||
2320 6 : (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
2321 0 : state.afn->AirflowNetworkFanActivated)) {
2322 : // Multizone airflow calculated in AirflowNetwork
2323 0 : B = CO2Gain + (state.afn->exchangeData(ZoneNum).SumMHrCO + state.afn->exchangeData(ZoneNum).SumMMHrCO) + CO2MassFlowRate;
2324 0 : A = ZoneMassFlowRate + state.afn->exchangeData(ZoneNum).SumMHr + state.afn->exchangeData(ZoneNum).SumMMHr;
2325 : }
2326 6 : C = RhoAir * state.dataHeatBal->Zone(ZoneNum).Volume * state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpCO2 / timeStepSysSec;
2327 : }
2328 :
2329 6 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2330 6 : auto &zoneAirCO2Temp = state.dataContaminantBalance->ZoneAirCO2Temp(ZoneNum);
2331 6 : if (state.afn->distribution_simulated) {
2332 0 : B += state.afn->exchangeData(ZoneNum).TotalCO2;
2333 : }
2334 6 : state.dataContaminantBalance->AZ(ZoneNum) = A;
2335 6 : state.dataContaminantBalance->BZ(ZoneNum) = B;
2336 6 : state.dataContaminantBalance->CZ(ZoneNum) = C;
2337 :
2338 : // Use a 3rd order derivative to predict final zone CO2 and
2339 : // smooth the changes using the zone air capacitance.
2340 6 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
2341 4 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
2342 4 : zoneAirCO2Temp = (B + C * (3.0 * state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) -
2343 4 : (3.0 / 2.0) * state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) +
2344 4 : (1.0 / 3.0) * state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum))) /
2345 4 : ((11.0 / 6.0) * C + A);
2346 : // Exact solution
2347 4 : } break;
2348 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
2349 0 : if (A == 0.0) { // B=0
2350 0 : zoneAirCO2Temp = state.dataContaminantBalance->ZoneCO21(ZoneNum) + B / C;
2351 : } else {
2352 0 : zoneAirCO2Temp = (state.dataContaminantBalance->ZoneCO21(ZoneNum) - B / A) * std::exp(min(700.0, -A / C)) + B / A;
2353 : }
2354 0 : } break;
2355 2 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
2356 2 : zoneAirCO2Temp = (C * state.dataContaminantBalance->ZoneCO21(ZoneNum) + B) / (C + A);
2357 2 : } break;
2358 0 : default:
2359 0 : break;
2360 : }
2361 :
2362 : // Set the CO2 to zero if the zone has been large sinks
2363 6 : if (zoneAirCO2Temp < 0.0) zoneAirCO2Temp = 0.0;
2364 6 : state.dataContaminantBalance->ZoneAirCO2(ZoneNum) = zoneAirCO2Temp;
2365 :
2366 6 : if (state.dataHybridModel->FlagHybridModel) {
2367 4 : auto &hmZone = state.dataHybridModel->hybridModelZones(ZoneNum);
2368 4 : if ((hmZone.InfiltrationCalc_C || hmZone.PeopleCountCalc_C) && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing)) {
2369 4 : InverseModelCO2(state, ZoneNum, CO2Gain, CO2GainExceptPeople, ZoneMassFlowRate, CO2MassFlowRate, RhoAir);
2370 : }
2371 : }
2372 : // Now put the calculated info into the actual zone nodes; ONLY if there is zone air flow, i.e. controlled zone or plenum zone
2373 6 : const int ZoneNodeNum = state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber;
2374 6 : if (ZoneNodeNum > 0) {
2375 6 : state.dataLoopNodes->Node(ZoneNodeNum).CO2 = zoneAirCO2Temp;
2376 : }
2377 : }
2378 :
2379 6 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2380 2 : B = GCGain + ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorGC) +
2381 2 : (GCMassFlowRate) + state.dataContaminantBalance->MixingMassFlowGC(ZoneNum) +
2382 2 : thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorGC;
2383 2 : A = ZoneMassFlowRate + thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone +
2384 2 : thisZoneHB.MDotOA;
2385 4 : if (state.afn->multizone_always_simulated ||
2386 2 : (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
2387 0 : state.afn->AirflowNetworkFanActivated)) {
2388 : // Multizone airflow calculated in AirflowNetwork
2389 0 : B = GCGain + (state.afn->exchangeData(ZoneNum).SumMHrGC + state.afn->exchangeData(ZoneNum).SumMMHrGC) + GCMassFlowRate;
2390 0 : A = ZoneMassFlowRate + state.afn->exchangeData(ZoneNum).SumMHr + state.afn->exchangeData(ZoneNum).SumMMHr;
2391 : }
2392 2 : C = RhoAir * state.dataHeatBal->Zone(ZoneNum).Volume * state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpGenContam / timeStepSysSec;
2393 : }
2394 :
2395 6 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2396 2 : auto &zoneAirGCTemp = state.dataContaminantBalance->ZoneAirGCTemp(ZoneNum);
2397 2 : if (state.afn->distribution_simulated) {
2398 0 : B += state.afn->exchangeData(ZoneNum).TotalGC;
2399 : }
2400 :
2401 2 : state.dataContaminantBalance->AZGC(ZoneNum) = A;
2402 2 : state.dataContaminantBalance->BZGC(ZoneNum) = B;
2403 2 : state.dataContaminantBalance->CZGC(ZoneNum) = C;
2404 :
2405 : // Use a 3rd order derivative to predict final zone generic contaminant and
2406 : // smooth the changes using the zone air capacitance.
2407 2 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
2408 0 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
2409 0 : zoneAirGCTemp = (B + C * (3.0 * state.dataContaminantBalance->GCZoneTimeMinus1Temp(ZoneNum) -
2410 0 : (3.0 / 2.0) * state.dataContaminantBalance->GCZoneTimeMinus2Temp(ZoneNum) +
2411 0 : (1.0 / 3.0) * state.dataContaminantBalance->GCZoneTimeMinus3Temp(ZoneNum))) /
2412 0 : ((11.0 / 6.0) * C + A);
2413 : // Exact solution
2414 0 : } break;
2415 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
2416 0 : if (A == 0.0) { // B=0
2417 0 : zoneAirGCTemp = state.dataContaminantBalance->ZoneGC1(ZoneNum) + B / C;
2418 : } else {
2419 0 : zoneAirGCTemp = (state.dataContaminantBalance->ZoneGC1(ZoneNum) - B / A) * std::exp(min(700.0, -A / C)) + B / A;
2420 : }
2421 0 : } break;
2422 2 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
2423 2 : zoneAirGCTemp = (C * state.dataContaminantBalance->ZoneGC1(ZoneNum) + B) / (C + A);
2424 2 : } break;
2425 0 : default:
2426 0 : break;
2427 : }
2428 :
2429 : // Set the generic contaminant to zero if the zone has been large sinks
2430 2 : if (zoneAirGCTemp < 0.0) zoneAirGCTemp = 0.0;
2431 2 : state.dataContaminantBalance->ZoneAirGC(ZoneNum) = zoneAirGCTemp;
2432 :
2433 : // Now put the calculated info into the actual zone nodes; ONLY if there is zone air flow, i.e. controlled zone or plenum zone
2434 2 : const int ZoneNodeNum = state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber;
2435 2 : if (ZoneNodeNum > 0) {
2436 2 : state.dataLoopNodes->Node(ZoneNodeNum).GenContam = zoneAirGCTemp;
2437 : }
2438 : }
2439 : }
2440 6 : }
2441 :
2442 : } // namespace EnergyPlus::ZoneContaminantPredictorCorrector
|