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