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