LCOV - code coverage report
Current view: top level - EnergyPlus - ZoneContaminantPredictorCorrector.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 21.1 % 1315 277
Test Date: 2025-05-22 16:09:37 Functions: 30.0 % 10 3

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

Generated by: LCOV version 2.0-1