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