LCOV - code coverage report
Current view: top level - EnergyPlus - ZoneContaminantPredictorCorrector.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 72.1 % 1328 958
Test Date: 2025-06-02 07:23:51 Functions: 90.0 % 10 9

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

Generated by: LCOV version 2.0-1