LCOV - code coverage report
Current view: top level - EnergyPlus - ZoneContaminantPredictorCorrector.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 21.0 % 1328 279
Test Date: 2025-06-02 12:03:30 Functions: 30.0 % 10 3

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/Array.functions.hh>
      53              : #include <ObjexxFCL/Array1D.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <AirflowNetwork/Elements.hpp>
      57              : #include <AirflowNetwork/Solver.hpp>
      58              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59              : #include <EnergyPlus/DataDefineEquip.hh>
      60              : #include <EnergyPlus/DataEnvironment.hh>
      61              : #include <EnergyPlus/DataHVACGlobals.hh>
      62              : #include <EnergyPlus/DataHeatBalFanSys.hh>
      63              : #include <EnergyPlus/DataHeatBalance.hh>
      64              : #include <EnergyPlus/DataIPShortCuts.hh>
      65              : #include <EnergyPlus/DataLoopNode.hh>
      66              : #include <EnergyPlus/DataSurfaces.hh>
      67              : #include <EnergyPlus/DataZoneEquipment.hh>
      68              : #include <EnergyPlus/General.hh>
      69              : #include <EnergyPlus/HeatBalanceInternalHeatGains.hh>
      70              : #include <EnergyPlus/HybridModel.hh>
      71              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      72              : #include <EnergyPlus/InternalHeatGains.hh>
      73              : #include <EnergyPlus/OutputProcessor.hh>
      74              : #include <EnergyPlus/Psychrometrics.hh>
      75              : #include <EnergyPlus/ScheduleManager.hh>
      76              : #include <EnergyPlus/UtilityRoutines.hh>
      77              : #include <EnergyPlus/ZoneContaminantPredictorCorrector.hh>
      78              : #include <EnergyPlus/ZonePlenum.hh>
      79              : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      80              : 
      81              : namespace EnergyPlus::ZoneContaminantPredictorCorrector {
      82              : 
      83              : // MODULE INFORMATION:
      84              : //       AUTHOR         Lixing Gu
      85              : //       DATE WRITTEN   May, 2010
      86              : 
      87              : // PURPOSE OF THIS MODULE:
      88              : // This module contains routines to predict and correct zone contaminants.
      89              : //  also includes zone contaminant controlling
      90              : 
      91              : // METHODOLOGY EMPLOYED:
      92              : // Similar approach to ZoneTempPredictorCorrector
      93              : 
      94              : // Using/Aliasing
      95              : using namespace DataHeatBalance;
      96              : using namespace Psychrometrics;
      97              : using namespace HybridModel;
      98              : 
      99            0 : void ManageZoneContaminanUpdates(EnergyPlusData &state,
     100              :                                  DataHeatBalFanSys::PredictorCorrectorCtrl const UpdateType, // Can be iGetZoneSetPoints, iPredictStep, iCorrectStep
     101              :                                  bool const ShortenTimeStepSys,
     102              :                                  bool const UseZoneTimeStepHistory, // if true then use zone timestep history, if false use system time step
     103              :                                  Real64 const PriorTimeStep         // the old value for timestep length is passed for possible use in interpolating
     104              : )
     105              : {
     106              : 
     107              :     // SUBROUTINE INFORMATION
     108              :     //       AUTHOR         Lixing Gu
     109              :     //       DATE WRITTEN   July, 2010
     110              : 
     111              :     // PURPOSE OF THIS SUBROUTINE:
     112              :     // This subroutine predicts or corrects the zone air temperature
     113              :     // depending on the simulation status and determines the correct
     114              :     // temperature setpoint for each zone from the schedule manager.
     115              :     // This module is revised from subroutine ManageZoneAirUpdates in
     116              :     // ZoneTempPredictorCorrector module.
     117              : 
     118            0 :     if (state.dataZoneContaminantPredictorCorrector->GetZoneAirContamInputFlag) {
     119            0 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     120            0 :             GetZoneContaminanInputs(state);
     121              :         }
     122            0 :         GetZoneContaminanSetPoints(state);
     123            0 :         state.dataZoneContaminantPredictorCorrector->GetZoneAirContamInputFlag = false;
     124              :     }
     125              : 
     126            0 :     if (!state.dataContaminantBalance->Contaminant.SimulateContaminants) {
     127            0 :         return;
     128              :     }
     129              : 
     130            0 :     switch (UpdateType) {
     131            0 :     case DataHeatBalFanSys::PredictorCorrectorCtrl::GetZoneSetPoints: {
     132            0 :         InitZoneContSetPoints(state);
     133            0 :     } break;
     134            0 :     case DataHeatBalFanSys::PredictorCorrectorCtrl::PredictStep: {
     135            0 :         PredictZoneContaminants(state, ShortenTimeStepSys, UseZoneTimeStepHistory, PriorTimeStep);
     136            0 :     } break;
     137            0 :     case DataHeatBalFanSys::PredictorCorrectorCtrl::CorrectStep: {
     138            0 :         CorrectZoneContaminants(state, UseZoneTimeStepHistory);
     139            0 :     } break;
     140            0 :     case DataHeatBalFanSys::PredictorCorrectorCtrl::RevertZoneTimestepHistories: {
     141            0 :         RevertZoneTimestepHistories(state);
     142            0 :     } break;
     143            0 :     case DataHeatBalFanSys::PredictorCorrectorCtrl::PushZoneTimestepHistories: {
     144            0 :         PushZoneTimestepHistories(state);
     145            0 :     } break;
     146            0 :     case DataHeatBalFanSys::PredictorCorrectorCtrl::PushSystemTimestepHistories: {
     147            0 :         PushSystemTimestepHistories(state);
     148            0 :     } break;
     149            0 :     default:
     150            0 :         break;
     151              :     }
     152              : }
     153              : 
     154            0 : 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            0 :     Array1D_string AlphaName;
     173            0 :     Array1D<Real64> IHGNumbers;
     174              :     int IOStat;
     175              :     int Loop;
     176              :     int ZonePtr;
     177            0 :     bool ErrorsFound(false);
     178            0 :     Array1D_bool RepVarSet;
     179            0 :     std::string CurrentModuleObject;
     180              : 
     181            0 :     RepVarSet.dimension(state.dataGlobal->NumOfZones, true);
     182              : 
     183            0 :     int NumAlpha = 0;
     184            0 :     int NumNumber = 0;
     185            0 :     int MaxAlpha = -100;
     186            0 :     int MaxNumber = -100;
     187            0 :     CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:Constant";
     188            0 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
     189            0 :     MaxAlpha = max(MaxAlpha, NumAlpha);
     190            0 :     MaxNumber = max(MaxNumber, NumNumber);
     191            0 :     CurrentModuleObject = "SurfaceContaminantSourceAndSink:Generic:PressureDriven";
     192            0 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
     193            0 :     MaxAlpha = max(MaxAlpha, NumAlpha);
     194            0 :     MaxNumber = max(MaxNumber, NumNumber);
     195            0 :     CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:CutoffModel";
     196            0 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
     197            0 :     MaxAlpha = max(MaxAlpha, NumAlpha);
     198            0 :     MaxNumber = max(MaxNumber, NumNumber);
     199            0 :     CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:DecaySource";
     200            0 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
     201            0 :     MaxAlpha = max(MaxAlpha, NumAlpha);
     202            0 :     MaxNumber = max(MaxNumber, NumNumber);
     203            0 :     CurrentModuleObject = "SurfaceContaminantSourceAndSink:Generic:BoundaryLayerDiffusion";
     204            0 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
     205            0 :     MaxAlpha = max(MaxAlpha, NumAlpha);
     206            0 :     MaxNumber = max(MaxNumber, NumNumber);
     207            0 :     CurrentModuleObject = "SurfaceContaminantSourceAndSink:Generic:DepositionVelocitySink";
     208            0 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
     209            0 :     MaxAlpha = max(MaxAlpha, NumAlpha);
     210            0 :     MaxNumber = max(MaxNumber, NumNumber);
     211            0 :     CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:DepositionRateSink";
     212            0 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Loop, NumAlpha, NumNumber);
     213            0 :     MaxAlpha = max(MaxAlpha, NumAlpha);
     214            0 :     MaxNumber = max(MaxNumber, NumNumber);
     215            0 :     IHGNumbers.allocate(MaxNumber);
     216            0 :     AlphaName.allocate(MaxAlpha);
     217            0 :     IHGNumbers = 0.0;
     218            0 :     AlphaName = "";
     219              : 
     220            0 :     CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:Constant";
     221            0 :     int TotGCGenConstant = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     222            0 :     state.dataContaminantBalance->ZoneContamGenericConstant.allocate(TotGCGenConstant);
     223              : 
     224            0 :     for (Loop = 1; Loop <= TotGCGenConstant; ++Loop) {
     225            0 :         AlphaName = "";
     226            0 :         IHGNumbers = 0.0;
     227            0 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     228              :                                                                  CurrentModuleObject,
     229              :                                                                  Loop,
     230              :                                                                  AlphaName,
     231              :                                                                  NumAlpha,
     232              :                                                                  IHGNumbers,
     233              :                                                                  NumNumber,
     234              :                                                                  IOStat,
     235            0 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
     236            0 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     237            0 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     238            0 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     239              : 
     240            0 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
     241              : 
     242            0 :         Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
     243              : 
     244            0 :         auto &contam = state.dataContaminantBalance->ZoneContamGenericConstant(Loop);
     245            0 :         contam.Name = AlphaName(1);
     246            0 :         contam.ZoneName = AlphaName(2);
     247            0 :         contam.ActualZoneNum = Util::FindItemInList(AlphaName(2), state.dataHeatBal->Zone);
     248            0 :         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            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
     260            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
     261            0 :             ErrorsFound = true;
     262            0 :         } 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            0 :         } 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            0 :         contam.GenerateRate = IHGNumbers(1);
     271            0 :         contam.RemovalCoef = IHGNumbers(2);
     272              : 
     273            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
     274            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4));
     275            0 :             ErrorsFound = true;
     276            0 :         } 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            0 :         } 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            0 :         if (contam.ActualZoneNum <= 0) {
     285            0 :             continue; // Error, will be caught and terminated later
     286              :         }
     287              : 
     288              :         // Object report variables
     289            0 :         SetupOutputVariable(state,
     290              :                             "Generic Air Contaminant Constant Source Generation Volume Flow Rate",
     291              :                             Constant::Units::m3_s,
     292            0 :                             contam.GenRate,
     293              :                             OutputProcessor::TimeStepType::Zone,
     294              :                             OutputProcessor::StoreType::Average,
     295            0 :                             contam.Name);
     296              : 
     297              :         // Zone total report variables
     298            0 :         ZonePtr = contam.ActualZoneNum;
     299            0 :         if (RepVarSet(ZonePtr)) {
     300            0 :             RepVarSet(ZonePtr) = false;
     301            0 :             SetupOutputVariable(state,
     302              :                                 "Zone Generic Air Contaminant Generation Volume Flow Rate",
     303              :                                 Constant::Units::m3_s,
     304            0 :                                 state.dataHeatBal->ZoneRpt(ZonePtr).GCRate,
     305              :                                 OutputProcessor::TimeStepType::Zone,
     306              :                                 OutputProcessor::StoreType::Average,
     307            0 :                                 state.dataHeatBal->Zone(ZonePtr).Name);
     308              :         }
     309            0 :         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            0 :     CurrentModuleObject = "SurfaceContaminantSourceAndSink:Generic:PressureDriven";
     323            0 :     int TotGCGenPDriven = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     324            0 :     state.dataContaminantBalance->ZoneContamGenericPDriven.allocate(TotGCGenPDriven);
     325              : 
     326            0 :     for (Loop = 1; Loop <= TotGCGenPDriven; ++Loop) {
     327            0 :         AlphaName = "";
     328            0 :         IHGNumbers = 0.0;
     329            0 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     330              :                                                                  CurrentModuleObject,
     331              :                                                                  Loop,
     332              :                                                                  AlphaName,
     333              :                                                                  NumAlpha,
     334              :                                                                  IHGNumbers,
     335              :                                                                  NumNumber,
     336              :                                                                  IOStat,
     337            0 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
     338            0 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     339            0 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     340            0 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     341              : 
     342            0 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
     343              : 
     344            0 :         Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
     345              : 
     346            0 :         auto &contam = state.dataContaminantBalance->ZoneContamGenericPDriven(Loop);
     347            0 :         contam.Name = AlphaName(1);
     348              : 
     349            0 :         contam.SurfName = AlphaName(2);
     350            0 :         contam.SurfNum = Util::FindItemInList(AlphaName(2), state.afn->MultizoneSurfaceData, &AirflowNetwork::MultizoneSurfaceProp::SurfName);
     351            0 :         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            0 :         if (contam.SurfNum > 0 &&
     364            0 :             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            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
     373            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
     374            0 :             ErrorsFound = true;
     375            0 :         } 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            0 :         } 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            0 :         contam.GenRateCoef = IHGNumbers(1);
     384            0 :         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            0 :         contam.Expo = IHGNumbers(2);
     396            0 :         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            0 :         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            0 :         SetupOutputVariable(state,
     419              :                             "Generic Air Contaminant Pressure Driven Generation Volume Flow Rate",
     420              :                             Constant::Units::m3_s,
     421            0 :                             contam.GenRate,
     422              :                             OutputProcessor::TimeStepType::Zone,
     423              :                             OutputProcessor::StoreType::Average,
     424            0 :                             contam.Name);
     425              : 
     426            0 :         if (contam.SurfNum > 0) {
     427            0 :             ZonePtr = state.dataSurface->Surface(state.afn->MultizoneSurfaceData(contam.SurfNum).SurfNum).Zone;
     428              :         } else {
     429            0 :             ZonePtr = 0;
     430              :         }
     431              :         // Zone total report variables
     432            0 :         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            0 :         if (ZonePtr > 0) {
     443            0 :             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            0 :     CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:CutoffModel";
     458            0 :     int TotGCGenCutoff = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     459            0 :     state.dataContaminantBalance->ZoneContamGenericCutoff.allocate(TotGCGenCutoff);
     460              : 
     461            0 :     for (Loop = 1; Loop <= TotGCGenCutoff; ++Loop) {
     462            0 :         AlphaName = "";
     463            0 :         IHGNumbers = 0.0;
     464            0 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     465              :                                                                  CurrentModuleObject,
     466              :                                                                  Loop,
     467              :                                                                  AlphaName,
     468              :                                                                  NumAlpha,
     469              :                                                                  IHGNumbers,
     470              :                                                                  NumNumber,
     471              :                                                                  IOStat,
     472            0 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
     473            0 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     474            0 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     475            0 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     476              : 
     477            0 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
     478              : 
     479            0 :         Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
     480              : 
     481            0 :         auto &contam = state.dataContaminantBalance->ZoneContamGenericCutoff(Loop);
     482            0 :         contam.Name = AlphaName(1);
     483              : 
     484            0 :         contam.ZoneName = AlphaName(2);
     485            0 :         contam.ActualZoneNum = Util::FindItemInList(AlphaName(2), state.dataHeatBal->Zone);
     486            0 :         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            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
     498            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
     499            0 :             ErrorsFound = true;
     500            0 :         } 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            0 :         } 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            0 :         contam.GenerateRate = IHGNumbers(1);
     509            0 :         contam.CutoffValue = IHGNumbers(2);
     510              : 
     511            0 :         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            0 :         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            0 :         SetupOutputVariable(state,
     534              :                             "Generic Air Contaminant Cutoff Model Generation Volume Flow Rate",
     535              :                             Constant::Units::m3_s,
     536            0 :                             contam.GenRate,
     537              :                             OutputProcessor::TimeStepType::Zone,
     538              :                             OutputProcessor::StoreType::Average,
     539            0 :                             contam.Name);
     540              : 
     541              :         // Zone total report variables
     542            0 :         ZonePtr = contam.ActualZoneNum;
     543            0 :         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            0 :         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            0 :     CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:DecaySource";
     567            0 :     int TotGCGenDecay = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     568            0 :     state.dataContaminantBalance->ZoneContamGenericDecay.allocate(TotGCGenDecay);
     569              : 
     570            0 :     for (Loop = 1; Loop <= TotGCGenDecay; ++Loop) {
     571            0 :         AlphaName = "";
     572            0 :         IHGNumbers = 0.0;
     573            0 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     574              :                                                                  CurrentModuleObject,
     575              :                                                                  Loop,
     576              :                                                                  AlphaName,
     577              :                                                                  NumAlpha,
     578              :                                                                  IHGNumbers,
     579              :                                                                  NumNumber,
     580              :                                                                  IOStat,
     581            0 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
     582            0 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     583            0 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     584            0 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     585              : 
     586            0 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
     587              : 
     588            0 :         auto &contam = state.dataContaminantBalance->ZoneContamGenericDecay(Loop);
     589              : 
     590            0 :         Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
     591            0 :         contam.Name = AlphaName(1);
     592              : 
     593            0 :         contam.ZoneName = AlphaName(2);
     594            0 :         contam.ActualZoneNum = Util::FindItemInList(AlphaName(2), state.dataHeatBal->Zone);
     595            0 :         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            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
     607            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
     608            0 :             ErrorsFound = true;
     609            0 :         } 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            0 :         } 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            0 :         contam.InitEmitRate = IHGNumbers(1);
     618            0 :         contam.DelayTime = IHGNumbers(2);
     619              : 
     620            0 :         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            0 :         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            0 :         SetupOutputVariable(state,
     643              :                             "Generic Air Contaminant Decay Model Generation Volume Flow Rate",
     644              :                             Constant::Units::m3_s,
     645            0 :                             contam.GenRate,
     646              :                             OutputProcessor::TimeStepType::Zone,
     647              :                             OutputProcessor::StoreType::Average,
     648            0 :                             contam.Name);
     649            0 :         SetupOutputVariable(state,
     650              :                             "Generic Air Contaminant Decay Model Generation Emission Start Elapsed Time",
     651              :                             Constant::Units::s,
     652            0 :                             contam.Time,
     653              :                             OutputProcessor::TimeStepType::Zone,
     654              :                             OutputProcessor::StoreType::Average,
     655            0 :                             contam.Name);
     656              : 
     657              :         // Zone total report variables
     658            0 :         ZonePtr = contam.ActualZoneNum;
     659            0 :         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            0 :         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            0 :     CurrentModuleObject = "SurfaceContaminantSourceAndSink:Generic:BoundaryLayerDiffusion";
     683            0 :     int TotGCBLDiff = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     684            0 :     state.dataContaminantBalance->ZoneContamGenericBLDiff.allocate(TotGCBLDiff);
     685              : 
     686            0 :     for (Loop = 1; Loop <= TotGCBLDiff; ++Loop) {
     687            0 :         AlphaName = "";
     688            0 :         IHGNumbers = 0.0;
     689            0 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     690              :                                                                  CurrentModuleObject,
     691              :                                                                  Loop,
     692              :                                                                  AlphaName,
     693              :                                                                  NumAlpha,
     694              :                                                                  IHGNumbers,
     695              :                                                                  NumNumber,
     696              :                                                                  IOStat,
     697            0 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
     698            0 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     699            0 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     700            0 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     701              : 
     702            0 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
     703              : 
     704            0 :         Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
     705              : 
     706            0 :         auto &contam = state.dataContaminantBalance->ZoneContamGenericBLDiff(Loop);
     707            0 :         contam.Name = AlphaName(1);
     708            0 :         contam.SurfName = AlphaName(2);
     709            0 :         contam.SurfNum = Util::FindItemInList(AlphaName(2), state.dataSurface->Surface);
     710            0 :         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            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
     722            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
     723            0 :             ErrorsFound = true;
     724            0 :         } 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            0 :         } 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            0 :         contam.TransCoef = IHGNumbers(1);
     733            0 :         contam.HenryCoef = IHGNumbers(2);
     734            0 :         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            0 :         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            0 :         SetupOutputVariable(state,
     757              :                             "Generic Air Contaminant Boundary Layer Diffusion Generation Volume Flow Rate",
     758              :                             Constant::Units::m3_s,
     759            0 :                             contam.GenRate,
     760              :                             OutputProcessor::TimeStepType::Zone,
     761              :                             OutputProcessor::StoreType::Average,
     762            0 :                             contam.Name);
     763            0 :         if (contam.SurfNum > 0) {
     764            0 :             SetupOutputVariable(state,
     765              :                                 "Generic Air Contaminant Boundary Layer Diffusion Inside Face Concentration",
     766              :                                 Constant::Units::ppm,
     767            0 :                                 state.dataSurface->SurfGenericContam(contam.SurfNum),
     768              :                                 OutputProcessor::TimeStepType::Zone,
     769              :                                 OutputProcessor::StoreType::Average,
     770            0 :                                 contam.SurfName);
     771              :         }
     772              : 
     773            0 :         ZonePtr = state.dataSurface->Surface(contam.SurfNum).Zone;
     774              :         // Zone total report variables
     775            0 :         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            0 :         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            0 :     CurrentModuleObject = "SurfaceContaminantSourceAndSink:Generic:DepositionVelocitySink";
     799            0 :     int TotGCDVS = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     800            0 :     state.dataContaminantBalance->ZoneContamGenericDVS.allocate(TotGCDVS);
     801              : 
     802            0 :     for (Loop = 1; Loop <= TotGCDVS; ++Loop) {
     803            0 :         AlphaName = "";
     804            0 :         IHGNumbers = 0.0;
     805            0 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     806              :                                                                  CurrentModuleObject,
     807              :                                                                  Loop,
     808              :                                                                  AlphaName,
     809              :                                                                  NumAlpha,
     810              :                                                                  IHGNumbers,
     811              :                                                                  NumNumber,
     812              :                                                                  IOStat,
     813            0 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
     814            0 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     815            0 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     816            0 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     817              : 
     818            0 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
     819              : 
     820            0 :         Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
     821            0 :         auto &contam = state.dataContaminantBalance->ZoneContamGenericDVS(Loop);
     822            0 :         contam.Name = AlphaName(1);
     823              : 
     824            0 :         contam.SurfName = AlphaName(2);
     825            0 :         contam.SurfNum = Util::FindItemInList(AlphaName(2), state.dataSurface->Surface);
     826            0 :         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            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
     838            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
     839            0 :             ErrorsFound = true;
     840            0 :         } 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            0 :         } 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            0 :         contam.DepoVelo = IHGNumbers(1);
     849            0 :         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            0 :         SetupOutputVariable(state,
     862              :                             "Generic Air Contaminant Deposition Velocity Removal Volume Flow Rate",
     863              :                             Constant::Units::m3_s,
     864            0 :                             contam.GenRate,
     865              :                             OutputProcessor::TimeStepType::Zone,
     866              :                             OutputProcessor::StoreType::Average,
     867            0 :                             contam.Name);
     868              : 
     869            0 :         ZonePtr = state.dataSurface->Surface(contam.SurfNum).Zone;
     870              :         // Zone total report variables
     871            0 :         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            0 :         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            0 :     CurrentModuleObject = "ZoneContaminantSourceAndSink:Generic:DepositionRateSink";
     895            0 :     int TotGCDRS = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     896            0 :     state.dataContaminantBalance->ZoneContamGenericDRS.allocate(TotGCDRS);
     897              : 
     898            0 :     for (Loop = 1; Loop <= TotGCDRS; ++Loop) {
     899            0 :         AlphaName = "";
     900            0 :         IHGNumbers = 0.0;
     901            0 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     902              :                                                                  CurrentModuleObject,
     903              :                                                                  Loop,
     904              :                                                                  AlphaName,
     905              :                                                                  NumAlpha,
     906              :                                                                  IHGNumbers,
     907              :                                                                  NumNumber,
     908              :                                                                  IOStat,
     909            0 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
     910            0 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     911            0 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     912            0 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     913              : 
     914            0 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphaName(1)};
     915              : 
     916            0 :         Util::IsNameEmpty(state, AlphaName(1), CurrentModuleObject, ErrorsFound);
     917              : 
     918            0 :         auto &contam = state.dataContaminantBalance->ZoneContamGenericDRS(Loop);
     919            0 :         contam.Name = AlphaName(1);
     920              : 
     921            0 :         contam.ZoneName = AlphaName(2);
     922            0 :         contam.ActualZoneNum = Util::FindItemInList(AlphaName(2), state.dataHeatBal->Zone);
     923            0 :         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            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
     935            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
     936            0 :             ErrorsFound = true;
     937            0 :         } 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            0 :         } 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            0 :         contam.DepoRate = IHGNumbers(1);
     946              : 
     947            0 :         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            0 :         SetupOutputVariable(state,
     960              :                             "Generic Air Contaminant Deposition Rate Removal Volume Flow Rate",
     961              :                             Constant::Units::m3_s,
     962            0 :                             contam.GenRate,
     963              :                             OutputProcessor::TimeStepType::Zone,
     964              :                             OutputProcessor::StoreType::Average,
     965            0 :                             contam.Name);
     966              : 
     967            0 :         ZonePtr = contam.ActualZoneNum;
     968              :         // Zone total report variables
     969            0 :         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            0 :         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            0 :     RepVarSet.deallocate();
     993            0 :     IHGNumbers.deallocate();
     994            0 :     AlphaName.deallocate();
     995              : 
     996            0 :     if (ErrorsFound) {
     997            0 :         ShowFatalError(state, "Errors getting Zone Contaminant Sources and Sinks input data.  Preceding condition(s) cause termination.");
     998              :     }
     999            0 : }
    1000              : 
    1001            0 : 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            0 :     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            0 :     auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
    1047            0 :     cCurrentModuleObject = "ZoneControl:ContaminantController";
    1048            0 :     int NumContControlledZones = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1049              : 
    1050            0 :     if (NumContControlledZones > 0) {
    1051            0 :         state.dataContaminantBalance->ContaminantControlledZone.allocate(NumContControlledZones);
    1052              :     }
    1053              : 
    1054            0 :     for (ContControlledZoneNum = 1; ContControlledZoneNum <= NumContControlledZones; ++ContControlledZoneNum) {
    1055            0 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1056              :                                                                  cCurrentModuleObject,
    1057              :                                                                  ContControlledZoneNum,
    1058            0 :                                                                  state.dataIPShortCut->cAlphaArgs,
    1059              :                                                                  NumAlphas,
    1060            0 :                                                                  state.dataIPShortCut->rNumericArgs,
    1061              :                                                                  NumNums,
    1062              :                                                                  IOStat,
    1063            0 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    1064            0 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    1065            0 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    1066            0 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    1067              : 
    1068            0 :         ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    1069              : 
    1070            0 :         Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
    1071              : 
    1072            0 :         auto &controlledZone = state.dataContaminantBalance->ContaminantControlledZone(ContControlledZoneNum);
    1073            0 :         controlledZone.Name = state.dataIPShortCut->cAlphaArgs(1);
    1074            0 :         controlledZone.ZoneName = state.dataIPShortCut->cAlphaArgs(2);
    1075            0 :         controlledZone.ActualZoneNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->Zone);
    1076            0 :         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            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
    1089            0 :             controlledZone.availSched = Sched::GetScheduleAlwaysOn(state);
    1090            0 :         } 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            0 :         } 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            0 :             state.dataHeatBal->Zone(controlledZone.ActualZoneNum).zoneContamControllerSched = controlledZone.availSched;
    1099              :         }
    1100              : 
    1101            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
    1102            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4));
    1103            0 :             ErrorsFound = true;
    1104            0 :         } 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            0 :         } 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            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
    1114            0 :             controlledZone.zoneMinCO2Sched = nullptr; // This needs to be nullptr because an empty schedule means outdoorCO2 not zero CO2
    1115            0 :         } 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            0 :         } 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            0 :             state.dataHeatBal->Zone(controlledZone.ActualZoneNum).zoneMinCO2Sched = controlledZone.zoneMinCO2Sched;
    1124              :         }
    1125              : 
    1126            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
    1127            0 :             controlledZone.zoneMaxCO2Sched = nullptr; // This needs to be nullptr because an empty schedule means outdoorCO2, not zero CO2
    1128            0 :         } 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            0 :         } 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            0 :             state.dataHeatBal->Zone(controlledZone.ActualZoneNum).zoneMaxCO2Sched = controlledZone.zoneMaxCO2Sched;
    1137              :         }
    1138              : 
    1139            0 :         if (NumAlphas <= 6) {
    1140            0 :             controlledZone.genericContamAvailSched = Sched::GetScheduleAlwaysOn(state);
    1141            0 :             continue;
    1142              :         }
    1143              : 
    1144            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(7)) {
    1145            0 :             controlledZone.genericContamAvailSched = Sched::GetScheduleAlwaysOn(state);
    1146            0 :         } 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            0 :         } 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            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(8)) {
    1156            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaArgs(8));
    1157            0 :             ErrorsFound = true;
    1158            0 :         } 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            0 :     if (ErrorsFound) {
    1166            0 :         ShowFatalError(state, "Errors getting Zone Contaminant Control input data.  Preceding condition(s) cause termination.");
    1167              :     }
    1168            0 : }
    1169              : 
    1170            0 : 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            0 :     if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1190            0 :         state.dataContaminantBalance->OutdoorCO2 = state.dataContaminantBalance->Contaminant.CO2OutdoorSched->getCurrentVal();
    1191              :     }
    1192              : 
    1193            0 :     if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1194            0 :         state.dataContaminantBalance->OutdoorGC = state.dataContaminantBalance->Contaminant.genericOutdoorSched->getCurrentVal();
    1195              :     }
    1196              : 
    1197            0 :     if (state.dataZoneContaminantPredictorCorrector->MyOneTimeFlag) {
    1198              :         // CO2
    1199            0 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1200            0 :             state.dataContaminantBalance->ZoneCO2SetPoint.dimension(state.dataGlobal->NumOfZones, 0.0);
    1201            0 :             state.dataContaminantBalance->CO2PredictedRate.dimension(state.dataGlobal->NumOfZones, 0.0);
    1202            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus1.dimension(state.dataGlobal->NumOfZones, 0.0);
    1203            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus2.dimension(state.dataGlobal->NumOfZones, 0.0);
    1204            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus3.dimension(state.dataGlobal->NumOfZones, 0.0);
    1205            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus4.dimension(state.dataGlobal->NumOfZones, 0.0);
    1206            0 :             state.dataContaminantBalance->DSCO2ZoneTimeMinus1.dimension(state.dataGlobal->NumOfZones, 0.0);
    1207            0 :             state.dataContaminantBalance->DSCO2ZoneTimeMinus2.dimension(state.dataGlobal->NumOfZones, 0.0);
    1208            0 :             state.dataContaminantBalance->DSCO2ZoneTimeMinus3.dimension(state.dataGlobal->NumOfZones, 0.0);
    1209            0 :             state.dataContaminantBalance->DSCO2ZoneTimeMinus4.dimension(state.dataGlobal->NumOfZones, 0.0);
    1210            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus1Temp.dimension(state.dataGlobal->NumOfZones, 0.0);
    1211            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus2Temp.dimension(state.dataGlobal->NumOfZones, 0.0);
    1212            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus3Temp.dimension(state.dataGlobal->NumOfZones, 0.0);
    1213            0 :             state.dataContaminantBalance->ZoneCO2MX.dimension(state.dataGlobal->NumOfZones, 0.0);
    1214            0 :             state.dataContaminantBalance->ZoneCO2M2.dimension(state.dataGlobal->NumOfZones, 0.0);
    1215            0 :             state.dataContaminantBalance->ZoneCO21.dimension(state.dataGlobal->NumOfZones, 0.0);
    1216              : 
    1217            0 :             state.dataContaminantBalance->ZoneSysContDemand.allocate(state.dataGlobal->NumOfZones);
    1218            0 :             state.dataContaminantBalance->ZoneCO2Gain.dimension(state.dataGlobal->NumOfZones, 0.0);
    1219            0 :             state.dataContaminantBalance->ZoneCO2GainFromPeople.dimension(state.dataGlobal->NumOfZones, 0.0);
    1220            0 :             state.dataContaminantBalance->ZoneCO2GainExceptPeople.dimension(state.dataGlobal->NumOfZones, 0.0); // Added for hybrid model
    1221            0 :             state.dataContaminantBalance->MixingMassFlowCO2.dimension(state.dataGlobal->NumOfZones, 0.0);
    1222            0 :             state.dataContaminantBalance->ZoneAirDensityCO.dimension(state.dataGlobal->NumOfZones, 0.0);
    1223            0 :             state.dataContaminantBalance->AZ.dimension(state.dataGlobal->NumOfZones, 0.0);
    1224            0 :             state.dataContaminantBalance->BZ.dimension(state.dataGlobal->NumOfZones, 0.0);
    1225            0 :             state.dataContaminantBalance->CZ.dimension(state.dataGlobal->NumOfZones, 0.0);
    1226              :         }
    1227              : 
    1228            0 :         state.dataContaminantBalance->CONTRAT.dimension(state.dataGlobal->NumOfZones, 0.0);
    1229              : 
    1230              :         // Allocate Derived Types
    1231              : 
    1232            0 :         for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
    1233              :             // Zone CO2
    1234            0 :             if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1235            0 :                 SetupOutputVariable(state,
    1236              :                                     "Zone Air CO2 Concentration",
    1237              :                                     Constant::Units::ppm,
    1238            0 :                                     state.dataContaminantBalance->ZoneAirCO2(Loop),
    1239              :                                     OutputProcessor::TimeStepType::System,
    1240              :                                     OutputProcessor::StoreType::Average,
    1241            0 :                                     state.dataHeatBal->Zone(Loop).Name);
    1242            0 :                 SetupOutputVariable(state,
    1243              :                                     "Zone Air CO2 Predicted Load to Setpoint Mass Flow Rate",
    1244              :                                     Constant::Units::kg_s,
    1245            0 :                                     state.dataContaminantBalance->CO2PredictedRate(Loop),
    1246              :                                     OutputProcessor::TimeStepType::System,
    1247              :                                     OutputProcessor::StoreType::Average,
    1248            0 :                                     state.dataHeatBal->Zone(Loop).Name);
    1249            0 :                 SetupOutputVariable(state,
    1250              :                                     "Zone Air CO2 Setpoint Concentration",
    1251              :                                     Constant::Units::ppm,
    1252            0 :                                     state.dataContaminantBalance->ZoneCO2SetPoint(Loop),
    1253              :                                     OutputProcessor::TimeStepType::System,
    1254              :                                     OutputProcessor::StoreType::Average,
    1255            0 :                                     state.dataHeatBal->Zone(Loop).Name);
    1256            0 :                 SetupOutputVariable(state,
    1257              :                                     "Zone Air CO2 Internal Gain Volume Flow Rate",
    1258              :                                     Constant::Units::m3_s,
    1259            0 :                                     state.dataContaminantBalance->ZoneCO2Gain(Loop),
    1260              :                                     OutputProcessor::TimeStepType::System,
    1261              :                                     OutputProcessor::StoreType::Average,
    1262            0 :                                     state.dataHeatBal->Zone(Loop).Name);
    1263              :             }
    1264              : 
    1265              :         } // Loop
    1266              : 
    1267              :         // Generic contaminant
    1268            0 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1269            0 :             state.dataContaminantBalance->ZoneGCSetPoint.dimension(state.dataGlobal->NumOfZones, 0.0);
    1270            0 :             state.dataContaminantBalance->GCPredictedRate.dimension(state.dataGlobal->NumOfZones, 0.0);
    1271            0 :             state.dataContaminantBalance->GCZoneTimeMinus1.dimension(state.dataGlobal->NumOfZones, 0.0);
    1272            0 :             state.dataContaminantBalance->GCZoneTimeMinus2.dimension(state.dataGlobal->NumOfZones, 0.0);
    1273            0 :             state.dataContaminantBalance->GCZoneTimeMinus3.dimension(state.dataGlobal->NumOfZones, 0.0);
    1274            0 :             state.dataContaminantBalance->GCZoneTimeMinus4.dimension(state.dataGlobal->NumOfZones, 0.0);
    1275            0 :             state.dataContaminantBalance->DSGCZoneTimeMinus1.dimension(state.dataGlobal->NumOfZones, 0.0);
    1276            0 :             state.dataContaminantBalance->DSGCZoneTimeMinus2.dimension(state.dataGlobal->NumOfZones, 0.0);
    1277            0 :             state.dataContaminantBalance->DSGCZoneTimeMinus3.dimension(state.dataGlobal->NumOfZones, 0.0);
    1278            0 :             state.dataContaminantBalance->DSGCZoneTimeMinus4.dimension(state.dataGlobal->NumOfZones, 0.0);
    1279            0 :             state.dataContaminantBalance->GCZoneTimeMinus1Temp.dimension(state.dataGlobal->NumOfZones, 0.0);
    1280            0 :             state.dataContaminantBalance->GCZoneTimeMinus2Temp.dimension(state.dataGlobal->NumOfZones, 0.0);
    1281            0 :             state.dataContaminantBalance->GCZoneTimeMinus3Temp.dimension(state.dataGlobal->NumOfZones, 0.0);
    1282            0 :             state.dataContaminantBalance->ZoneGCMX.dimension(state.dataGlobal->NumOfZones, 0.0);
    1283            0 :             state.dataContaminantBalance->ZoneGCM2.dimension(state.dataGlobal->NumOfZones, 0.0);
    1284            0 :             state.dataContaminantBalance->ZoneGC1.dimension(state.dataGlobal->NumOfZones, 0.0);
    1285              : 
    1286            0 :             if (!allocated(state.dataContaminantBalance->ZoneSysContDemand)) {
    1287            0 :                 state.dataContaminantBalance->ZoneSysContDemand.allocate(state.dataGlobal->NumOfZones);
    1288              :             }
    1289            0 :             state.dataContaminantBalance->ZoneGCGain.dimension(state.dataGlobal->NumOfZones, 0.0);
    1290            0 :             state.dataContaminantBalance->MixingMassFlowGC.dimension(state.dataGlobal->NumOfZones, 0.0);
    1291            0 :             state.dataContaminantBalance->ZoneAirDensityGC.dimension(state.dataGlobal->NumOfZones, 0.0);
    1292            0 :             state.dataContaminantBalance->AZGC.dimension(state.dataGlobal->NumOfZones, 0.0);
    1293            0 :             state.dataContaminantBalance->BZGC.dimension(state.dataGlobal->NumOfZones, 0.0);
    1294            0 :             state.dataContaminantBalance->CZGC.dimension(state.dataGlobal->NumOfZones, 0.0);
    1295              :         }
    1296              : 
    1297            0 :         state.dataContaminantBalance->CONTRATGC.dimension(state.dataGlobal->NumOfZones, 0.0);
    1298              : 
    1299              :         // Allocate Derived Types
    1300              : 
    1301            0 :         for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
    1302              :             // Zone CO2
    1303            0 :             if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1304            0 :                 SetupOutputVariable(state,
    1305              :                                     "Zone Air Generic Air Contaminant Concentration",
    1306              :                                     Constant::Units::ppm,
    1307            0 :                                     state.dataContaminantBalance->ZoneAirGC(Loop),
    1308              :                                     OutputProcessor::TimeStepType::System,
    1309              :                                     OutputProcessor::StoreType::Average,
    1310            0 :                                     state.dataHeatBal->Zone(Loop).Name);
    1311            0 :                 SetupOutputVariable(state,
    1312              :                                     "Zone Generic Air Contaminant Predicted Load to Setpoint Mass Flow Rate",
    1313              :                                     Constant::Units::kg_s,
    1314            0 :                                     state.dataContaminantBalance->GCPredictedRate(Loop),
    1315              :                                     OutputProcessor::TimeStepType::System,
    1316              :                                     OutputProcessor::StoreType::Average,
    1317            0 :                                     state.dataHeatBal->Zone(Loop).Name);
    1318            0 :                 SetupOutputVariable(state,
    1319              :                                     "Zone Generic Air Contaminant Setpoint Concentration",
    1320              :                                     Constant::Units::ppm,
    1321            0 :                                     state.dataContaminantBalance->ZoneGCSetPoint(Loop),
    1322              :                                     OutputProcessor::TimeStepType::System,
    1323              :                                     OutputProcessor::StoreType::Average,
    1324            0 :                                     state.dataHeatBal->Zone(Loop).Name);
    1325              :             }
    1326              :         } // Loop
    1327              : 
    1328            0 :         state.dataZoneContaminantPredictorCorrector->MyOneTimeFlag = false;
    1329              :     }
    1330              : 
    1331              :     // Do the Begin Environment initializations
    1332            0 :     if (state.dataZoneContaminantPredictorCorrector->MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
    1333            0 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1334            0 :             state.dataContaminantBalance->CONTRAT = 0.0;
    1335            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus1 = state.dataContaminantBalance->OutdoorCO2;
    1336            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus2 = state.dataContaminantBalance->OutdoorCO2;
    1337            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus3 = state.dataContaminantBalance->OutdoorCO2;
    1338            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus4 = state.dataContaminantBalance->OutdoorCO2;
    1339            0 :             state.dataContaminantBalance->DSCO2ZoneTimeMinus1 = state.dataContaminantBalance->OutdoorCO2;
    1340            0 :             state.dataContaminantBalance->DSCO2ZoneTimeMinus2 = state.dataContaminantBalance->OutdoorCO2;
    1341            0 :             state.dataContaminantBalance->DSCO2ZoneTimeMinus3 = state.dataContaminantBalance->OutdoorCO2;
    1342            0 :             state.dataContaminantBalance->DSCO2ZoneTimeMinus4 = state.dataContaminantBalance->OutdoorCO2;
    1343            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus1Temp = 0.0;
    1344            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus2Temp = 0.0;
    1345            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus3Temp = 0.0;
    1346            0 :             state.dataContaminantBalance->ZoneAirCO2Temp = state.dataContaminantBalance->OutdoorCO2;
    1347            0 :             state.dataContaminantBalance->ZoneCO2SetPoint = 0.0;
    1348            0 :             state.dataContaminantBalance->CO2PredictedRate = 0.0;
    1349            0 :             state.dataContaminantBalance->ZoneAirCO2 = state.dataContaminantBalance->OutdoorCO2;
    1350            0 :             state.dataContaminantBalance->ZoneCO21 = state.dataContaminantBalance->OutdoorCO2;
    1351            0 :             state.dataContaminantBalance->ZoneCO2MX = state.dataContaminantBalance->OutdoorCO2;
    1352            0 :             state.dataContaminantBalance->ZoneCO2M2 = state.dataContaminantBalance->OutdoorCO2;
    1353              :         }
    1354            0 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1355            0 :             state.dataContaminantBalance->CONTRAT = 0.0;
    1356            0 :             state.dataContaminantBalance->GCZoneTimeMinus1 = state.dataContaminantBalance->OutdoorGC;
    1357            0 :             state.dataContaminantBalance->GCZoneTimeMinus2 = state.dataContaminantBalance->OutdoorGC;
    1358            0 :             state.dataContaminantBalance->GCZoneTimeMinus3 = state.dataContaminantBalance->OutdoorGC;
    1359            0 :             state.dataContaminantBalance->GCZoneTimeMinus4 = state.dataContaminantBalance->OutdoorGC;
    1360            0 :             state.dataContaminantBalance->DSGCZoneTimeMinus1 = state.dataContaminantBalance->OutdoorGC;
    1361            0 :             state.dataContaminantBalance->DSGCZoneTimeMinus2 = state.dataContaminantBalance->OutdoorGC;
    1362            0 :             state.dataContaminantBalance->DSGCZoneTimeMinus3 = state.dataContaminantBalance->OutdoorGC;
    1363            0 :             state.dataContaminantBalance->DSGCZoneTimeMinus4 = state.dataContaminantBalance->OutdoorGC;
    1364            0 :             state.dataContaminantBalance->GCZoneTimeMinus1Temp = 0.0;
    1365            0 :             state.dataContaminantBalance->GCZoneTimeMinus2Temp = 0.0;
    1366            0 :             state.dataContaminantBalance->GCZoneTimeMinus3Temp = 0.0;
    1367            0 :             state.dataContaminantBalance->ZoneAirGCTemp = state.dataContaminantBalance->OutdoorGC;
    1368            0 :             state.dataContaminantBalance->ZoneGCSetPoint = 0.0;
    1369            0 :             state.dataContaminantBalance->GCPredictedRate = 0.0;
    1370            0 :             state.dataContaminantBalance->ZoneAirGC = state.dataContaminantBalance->OutdoorGC;
    1371            0 :             state.dataContaminantBalance->ZoneGC1 = state.dataContaminantBalance->OutdoorGC;
    1372            0 :             state.dataContaminantBalance->ZoneGCMX = state.dataContaminantBalance->OutdoorGC;
    1373            0 :             state.dataContaminantBalance->ZoneGCM2 = state.dataContaminantBalance->OutdoorGC;
    1374            0 :             for (auto &con : state.dataContaminantBalance->ZoneContamGenericBLDiff) {
    1375            0 :                 state.dataSurface->SurfGenericContam(con.SurfNum) = state.dataContaminantBalance->OutdoorGC;
    1376              :             }
    1377            0 :             if (!state.dataContaminantBalance->ZoneContamGenericDecay.empty()) {
    1378            0 :                 for (auto &e : state.dataContaminantBalance->ZoneContamGenericDecay) {
    1379            0 :                     e.Time = 0.0;
    1380              :                 }
    1381              :             }
    1382              :         }
    1383            0 :         state.dataZoneContaminantPredictorCorrector->MyEnvrnFlag = false;
    1384              :     }
    1385              : 
    1386            0 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    1387            0 :         state.dataZoneContaminantPredictorCorrector->MyEnvrnFlag = true;
    1388              :     }
    1389              : 
    1390            0 :     if (allocated(state.dataZoneEquip->ZoneEquipConfig) && state.dataZoneContaminantPredictorCorrector->MyConfigOneTimeFlag) {
    1391            0 :         bool ErrorsFound = false;
    1392            0 :         for (int ContZoneNum = 1; ContZoneNum <= (int)state.dataContaminantBalance->ContaminantControlledZone.size(); ++ContZoneNum) {
    1393            0 :             int ZoneNum = state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum).ActualZoneNum;
    1394            0 :             for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumInletNodes; ++zoneInNode) {
    1395            0 :                 int AirLoopNum = state.dataZoneEquip->ZoneEquipConfig(ZoneNum).InletNodeAirLoopNum(zoneInNode);
    1396            0 :                 state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum).NumOfZones = 0;
    1397            0 :                 for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
    1398            0 :                     if (!state.dataZoneEquip->ZoneEquipConfig(Loop).IsControlled) {
    1399            0 :                         continue;
    1400              :                     }
    1401            0 :                     for (int zoneInNode2 = 1; zoneInNode2 <= state.dataZoneEquip->ZoneEquipConfig(Loop).NumInletNodes; ++zoneInNode2) {
    1402            0 :                         if (AirLoopNum == state.dataZoneEquip->ZoneEquipConfig(Loop).InletNodeAirLoopNum(zoneInNode2)) {
    1403            0 :                             ++state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum).NumOfZones;
    1404            0 :                             break; // only count a zone once
    1405              :                         }
    1406              :                     }
    1407              :                 }
    1408            0 :                 if (state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum).NumOfZones > 0) {
    1409            0 :                     state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum)
    1410            0 :                         .ControlZoneNum.allocate(state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum).NumOfZones);
    1411            0 :                     int I = 1;
    1412            0 :                     for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
    1413            0 :                         if (!state.dataZoneEquip->ZoneEquipConfig(Loop).IsControlled) {
    1414            0 :                             continue;
    1415              :                         }
    1416            0 :                         for (int zoneInNode2 = 1; zoneInNode2 <= state.dataZoneEquip->ZoneEquipConfig(Loop).NumInletNodes; ++zoneInNode2) {
    1417            0 :                             if (AirLoopNum == state.dataZoneEquip->ZoneEquipConfig(Loop).InletNodeAirLoopNum(zoneInNode2)) {
    1418            0 :                                 state.dataContaminantBalance->ContaminantControlledZone(ContZoneNum).ControlZoneNum(I) = Loop;
    1419            0 :                                 ++I;
    1420            0 :                                 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            0 :         state.dataZoneContaminantPredictorCorrector->MyConfigOneTimeFlag = false;
    1433            0 :         if (ErrorsFound) {
    1434            0 :             ShowFatalError(state, "ZoneControl:ContaminantController: Program terminates for preceding reason(s).");
    1435              :         }
    1436              :     }
    1437              : 
    1438            0 :     for (int Loop = 1; Loop <= (int)state.dataContaminantBalance->ContaminantControlledZone.size(); ++Loop) {
    1439            0 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1440            0 :             int ZoneNum = state.dataContaminantBalance->ContaminantControlledZone(Loop).ActualZoneNum;
    1441            0 :             state.dataContaminantBalance->ZoneCO2SetPoint(ZoneNum) =
    1442            0 :                 state.dataContaminantBalance->ContaminantControlledZone(Loop).setptSched->getCurrentVal();
    1443              :         }
    1444            0 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1445            0 :             int ZoneNum = state.dataContaminantBalance->ContaminantControlledZone(Loop).ActualZoneNum;
    1446            0 :             state.dataContaminantBalance->ZoneGCSetPoint(ZoneNum) =
    1447            0 :                 state.dataContaminantBalance->ContaminantControlledZone(Loop).genericContamSetptSched->getCurrentVal();
    1448              :         }
    1449              :     }
    1450              : 
    1451              :     // CO2 gain
    1452            0 :     if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1453            0 :         for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
    1454            0 :             state.dataContaminantBalance->ZoneCO2Gain(Loop) = InternalHeatGains::SumAllInternalCO2Gains(state, Loop);
    1455            0 :             if (state.dataHybridModel->FlagHybridModel_PC) {
    1456            0 :                 state.dataContaminantBalance->ZoneCO2GainExceptPeople(Loop) = InternalHeatGains::SumAllInternalCO2GainsExceptPeople(state, Loop);
    1457              :             }
    1458            0 :             std::array<DataHeatBalance::IntGainType, 1> IntGainPeopleArray = {DataHeatBalance::IntGainType::People};
    1459            0 :             state.dataContaminantBalance->ZoneCO2GainFromPeople(Loop) =
    1460            0 :                 InternalHeatGains::SumInternalCO2GainsByTypes(state, Loop, IntGainPeopleArray);
    1461              :         }
    1462              :     }
    1463              : 
    1464              :     // Generic contaminant gain
    1465            0 :     if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1466            0 :         state.dataContaminantBalance->ZoneGCGain = 0.0;
    1467              :         // from constant model
    1468            0 :         for (auto &con : state.dataContaminantBalance->ZoneContamGenericConstant) {
    1469            0 :             int ZoneNum = con.ActualZoneNum;
    1470            0 :             GCGain = con.GenerateRate * con.generateRateSched->getCurrentVal() -
    1471            0 :                      con.RemovalCoef * con.removalCoefSched->getCurrentVal() * state.dataContaminantBalance->ZoneAirGC(ZoneNum) * 1.0e-6;
    1472            0 :             con.GenRate = GCGain;
    1473              :         }
    1474              : 
    1475              :         // from pressure driven model
    1476            0 :         if (state.afn->simulation_control.type != AirflowNetwork::ControlType::NoMultizoneOrDistribution) {
    1477            0 :             for (auto &con : state.dataContaminantBalance->ZoneContamGenericPDriven) {
    1478            0 :                 int SurfNum = con.SurfNum;
    1479            0 :                 Pi = state.afn->AirflowNetworkNodeSimu(state.afn->MultizoneSurfaceData(SurfNum).NodeNums[0]).PZ;
    1480            0 :                 Pj = state.afn->AirflowNetworkNodeSimu(state.afn->MultizoneSurfaceData(SurfNum).NodeNums[1]).PZ;
    1481            0 :                 if (Pj >= Pi) {
    1482            0 :                     GCGain = con.GenRateCoef * con.generateRateCoefSched->getCurrentVal() * std::pow(Pj - Pi, con.Expo);
    1483              :                 } else {
    1484            0 :                     GCGain = 0.0;
    1485              :                 }
    1486            0 :                 con.GenRate = GCGain;
    1487              :             }
    1488              :         }
    1489              : 
    1490              :         // from cutoff model
    1491            0 :         for (auto &con : state.dataContaminantBalance->ZoneContamGenericCutoff) {
    1492            0 :             int ZoneNum = con.ActualZoneNum;
    1493            0 :             if (state.dataContaminantBalance->ZoneAirGC(ZoneNum) < con.CutoffValue) {
    1494            0 :                 GCGain = con.GenerateRate * con.generateRateSched->getCurrentVal() *
    1495            0 :                          (1.0 - state.dataContaminantBalance->ZoneAirGC(ZoneNum) / con.CutoffValue);
    1496              :             } else {
    1497            0 :                 GCGain = 0.0;
    1498              :             }
    1499            0 :             con.GenRate = GCGain;
    1500              :         }
    1501              : 
    1502              :         // From decay model
    1503            0 :         for (auto &con : state.dataContaminantBalance->ZoneContamGenericDecay) {
    1504            0 :             int schVal = con.emitRateSched->getCurrentVal();
    1505            0 :             if (schVal == 0 || state.dataGlobal->BeginEnvrnFlag || state.dataGlobal->WarmupFlag) {
    1506            0 :                 con.Time = 0.0;
    1507              :             } else {
    1508            0 :                 con.Time += state.dataGlobal->TimeStepZoneSec;
    1509              :             }
    1510              : 
    1511            0 :             GCGain = con.InitEmitRate * schVal * std::exp(-con.Time / con.DelayTime);
    1512            0 :             con.GenRate = GCGain;
    1513              :         }
    1514              : 
    1515              :         // From boudary layer diffusion
    1516            0 :         for (auto &con : state.dataContaminantBalance->ZoneContamGenericBLDiff) {
    1517            0 :             int SurfNum = con.SurfNum;
    1518            0 :             int ZoneNum = state.dataSurface->Surface(SurfNum).Zone;
    1519              :             // Surface concentration level for the Boundary Layer Diffusion Controlled Model
    1520            0 :             Real64 Cs = state.dataSurface->SurfGenericContam(SurfNum);
    1521            0 :             Sch = con.transCoefSched->getCurrentVal();
    1522            0 :             GCGain = con.TransCoef * Sch * state.dataSurface->Surface(SurfNum).Area * state.dataSurface->Surface(SurfNum).Multiplier *
    1523            0 :                      (Cs / con.HenryCoef - state.dataContaminantBalance->ZoneAirGC(ZoneNum)) * 1.0e-6;
    1524            0 :             con.GenRate = GCGain;
    1525              :             // Surface concentration level based on steady-state assumption
    1526            0 :             state.dataSurface->SurfGenericContam(SurfNum) =
    1527            0 :                 Cs - GCGain * 1.0e6 / state.dataSurface->Surface(SurfNum).Multiplier / state.dataSurface->Surface(SurfNum).Area;
    1528              :         }
    1529              : 
    1530              :         // From deposition velocity sink model
    1531            0 :         for (auto &con : state.dataContaminantBalance->ZoneContamGenericDVS) {
    1532            0 :             int SurfNum = con.SurfNum;
    1533            0 :             int ZoneNum = state.dataSurface->Surface(SurfNum).Zone;
    1534            0 :             Sch = con.depoVeloSched->getCurrentVal();
    1535            0 :             GCGain = -con.DepoVelo * state.dataSurface->Surface(SurfNum).Area * Sch * state.dataContaminantBalance->ZoneAirGC(ZoneNum) *
    1536            0 :                      state.dataSurface->Surface(SurfNum).Multiplier * 1.0e-6;
    1537            0 :             con.GenRate = GCGain;
    1538              :         }
    1539              : 
    1540              :         // From deposition rate sink model
    1541            0 :         for (auto &con : state.dataContaminantBalance->ZoneContamGenericDRS) {
    1542            0 :             int ZoneNum = con.ActualZoneNum;
    1543            0 :             Sch = con.depoRateSched->getCurrentVal();
    1544            0 :             GCGain = -con.DepoRate * state.dataHeatBal->Zone(ZoneNum).Volume * Sch * state.dataContaminantBalance->ZoneAirGC(ZoneNum) * 1.0e-6;
    1545            0 :             con.GenRate = GCGain;
    1546              :         }
    1547              :     }
    1548            0 : }
    1549              : 
    1550            3 : 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            3 :     Real64 timeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    1579              :     // Update zone CO2
    1580           10 :     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1581            7 :         auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
    1582              : 
    1583            7 :         if (ShortenTimeStepSys) {
    1584              : 
    1585            0 :             if (state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber > 0) { // roll back result for zone air node,
    1586            0 :                 if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1587            0 :                     state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber).CO2 =
    1588            0 :                         state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum);
    1589              :                 }
    1590            0 :                 if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1591            0 :                     state.dataLoopNodes->Node(state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber).GenContam =
    1592            0 :                         state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum);
    1593              :                 }
    1594              :             }
    1595              : 
    1596            0 :             if (state.dataHVACGlobal->NumOfSysTimeSteps !=
    1597            0 :                 state.dataHVACGlobal->NumOfSysTimeStepsLastZoneTimeStep) { // cannot reuse existing DS data, interpolate from zone time
    1598              : 
    1599            0 :                 if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1600            0 :                     ZoneTempPredictorCorrector::DownInterpolate4HistoryValues(PriorTimeStep,
    1601            0 :                                                                               state.dataHVACGlobal->TimeStepSys,
    1602            0 :                                                                               state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum),
    1603            0 :                                                                               state.dataContaminantBalance->CO2ZoneTimeMinus2(ZoneNum),
    1604            0 :                                                                               state.dataContaminantBalance->CO2ZoneTimeMinus3(ZoneNum),
    1605            0 :                                                                               state.dataContaminantBalance->ZoneAirCO2(ZoneNum),
    1606            0 :                                                                               state.dataContaminantBalance->DSCO2ZoneTimeMinus1(ZoneNum),
    1607            0 :                                                                               state.dataContaminantBalance->DSCO2ZoneTimeMinus2(ZoneNum),
    1608            0 :                                                                               state.dataContaminantBalance->DSCO2ZoneTimeMinus3(ZoneNum),
    1609            0 :                                                                               state.dataContaminantBalance->DSCO2ZoneTimeMinus4(ZoneNum));
    1610              :                 }
    1611            0 :                 if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1612            0 :                     ZoneTempPredictorCorrector::DownInterpolate4HistoryValues(PriorTimeStep,
    1613            0 :                                                                               state.dataHVACGlobal->TimeStepSys,
    1614            0 :                                                                               state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum),
    1615            0 :                                                                               state.dataContaminantBalance->GCZoneTimeMinus2(ZoneNum),
    1616            0 :                                                                               state.dataContaminantBalance->GCZoneTimeMinus3(ZoneNum),
    1617            0 :                                                                               state.dataContaminantBalance->ZoneAirGC(ZoneNum),
    1618            0 :                                                                               state.dataContaminantBalance->DSGCZoneTimeMinus1(ZoneNum),
    1619            0 :                                                                               state.dataContaminantBalance->DSGCZoneTimeMinus2(ZoneNum),
    1620            0 :                                                                               state.dataContaminantBalance->DSGCZoneTimeMinus3(ZoneNum),
    1621            0 :                                                                               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            7 :         if (UseZoneTimeStepHistory) {
    1630              : 
    1631            0 :             if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1632            0 :                 state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum);
    1633            0 :                 state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus2(ZoneNum);
    1634            0 :                 state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus3(ZoneNum);
    1635              :             }
    1636            0 :             if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1637            0 :                 state.dataContaminantBalance->GCZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum);
    1638            0 :                 state.dataContaminantBalance->GCZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus2(ZoneNum);
    1639            0 :                 state.dataContaminantBalance->GCZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus3(ZoneNum);
    1640              :             }
    1641              : 
    1642              :         } else { // use down-stepped history
    1643              : 
    1644            7 :             if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1645            4 :                 state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus1(ZoneNum);
    1646            4 :                 state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus2(ZoneNum);
    1647            4 :                 state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus3(ZoneNum);
    1648              :             }
    1649            7 :             if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1650            4 :                 state.dataContaminantBalance->GCZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus1(ZoneNum);
    1651            4 :                 state.dataContaminantBalance->GCZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus2(ZoneNum);
    1652            4 :                 state.dataContaminantBalance->GCZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus3(ZoneNum);
    1653              :             }
    1654              :         }
    1655              : 
    1656            7 :         if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
    1657            7 :             if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1658            4 :                 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            4 :                     state.dataContaminantBalance->ZoneCO21(ZoneNum) = state.dataContaminantBalance->ZoneAirCO2(ZoneNum);
    1667              :                 }
    1668              :             }
    1669            7 :             if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1670            4 :                 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            4 :                     state.dataContaminantBalance->ZoneGC1(ZoneNum) = state.dataContaminantBalance->ZoneAirGC(ZoneNum);
    1679              :                 }
    1680              :             }
    1681              :         }
    1682              : 
    1683            7 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1684              : 
    1685            4 :             state.dataContaminantBalance->CO2PredictedRate(ZoneNum) = 0.0;
    1686            4 :             LoadToCO2SetPoint = 0.0;
    1687            4 :             state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP = 0.0;
    1688              : 
    1689              :             // Check to see if this is a "CO2 controlled zone"
    1690            4 :             bool ControlledCO2ZoneFlag = false;
    1691              :             // Check all the controlled zones to see if it matches the zone simulated
    1692            7 :             for (auto const &contaminantControlledZone : state.dataContaminantBalance->ContaminantControlledZone) {
    1693            7 :                 if (contaminantControlledZone.ActualZoneNum == ZoneNum) {
    1694            4 :                     if (contaminantControlledZone.availSched->getCurrentVal() > 0.0) {
    1695            4 :                         ZoneAirCO2SetPoint = state.dataContaminantBalance->ZoneCO2SetPoint(contaminantControlledZone.ActualZoneNum);
    1696            4 :                         if (contaminantControlledZone.EMSOverrideCO2SetPointOn) {
    1697            0 :                             ZoneAirCO2SetPoint = contaminantControlledZone.EMSOverrideCO2SetPointValue;
    1698              :                         }
    1699            4 :                         ControlledCO2ZoneFlag = true;
    1700            4 :                         break;
    1701              :                     }
    1702              :                 }
    1703              :             }
    1704            4 :             if (!ControlledCO2ZoneFlag) {
    1705            0 :                 for (auto const &contaminantControlledZone : state.dataContaminantBalance->ContaminantControlledZone) {
    1706            0 :                     if (contaminantControlledZone.availSched->getCurrentVal() > 0.0) {
    1707            0 :                         ZoneAirCO2SetPoint = state.dataContaminantBalance->ZoneCO2SetPoint(contaminantControlledZone.ActualZoneNum);
    1708            0 :                         if (contaminantControlledZone.EMSOverrideCO2SetPointOn) {
    1709            0 :                             ZoneAirCO2SetPoint = contaminantControlledZone.EMSOverrideCO2SetPointValue;
    1710              :                         }
    1711            0 :                         if (contaminantControlledZone.NumOfZones >= 1) {
    1712            0 :                             if (contaminantControlledZone.ActualZoneNum != ZoneNum) {
    1713            0 :                                 for (int I = 1; I <= contaminantControlledZone.NumOfZones; ++I) {
    1714            0 :                                     if (contaminantControlledZone.ControlZoneNum(I) == ZoneNum) {
    1715            0 :                                         ControlledCO2ZoneFlag = true;
    1716            0 :                                         break;
    1717              :                                     }
    1718              :                                 }
    1719            0 :                                 if (ControlledCO2ZoneFlag) {
    1720            0 :                                     break;
    1721              :                                 }
    1722              :                             } else {
    1723            0 :                                 ControlledCO2ZoneFlag = true;
    1724            0 :                                 break;
    1725              :                             }
    1726              :                         }
    1727              :                     }
    1728              :                 }
    1729              :             } // CO2ControlledZoneNum
    1730              : 
    1731            4 :             if (ControlledCO2ZoneFlag) {
    1732            4 :                 Real64 RhoAir = PsyRhoAirFnPbTdbW(state,
    1733            4 :                                                   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            4 :                 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            8 :                 if (state.afn->multizone_always_simulated ||
    1745            4 :                     (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
    1746            0 :                      state.afn->AirflowNetworkFanActivated)) {
    1747              :                     // Multizone airflow calculated in AirflowNetwork
    1748            0 :                     B = CO2Gain + state.afn->exchangeData(ZoneNum).SumMHrCO + state.afn->exchangeData(ZoneNum).SumMMHrCO;
    1749            0 :                     A = state.afn->exchangeData(ZoneNum).SumMHr + state.afn->exchangeData(ZoneNum).SumMMHr;
    1750              :                 } else {
    1751            8 :                     B = CO2Gain +
    1752            4 :                         ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorCO2) +
    1753            4 :                         state.dataContaminantBalance->MixingMassFlowCO2(ZoneNum) + thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorCO2;
    1754            4 :                     A = thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
    1755              :                 }
    1756            4 :                 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            4 :                 switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    1763            0 :                 case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    1764            0 :                     LoadToCO2SetPoint = ((11.0 / 6.0) * C + A) * ZoneAirCO2SetPoint -
    1765            0 :                                         (B + C * (3.0 * state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) -
    1766            0 :                                                   (3.0 / 2.0) * state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) +
    1767            0 :                                                   (1.0 / 3.0) * state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum)));
    1768              :                     // Exact solution
    1769            0 :                 } 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            4 :                 case DataHeatBalance::SolutionAlgo::EulerMethod: {
    1781            4 :                     LoadToCO2SetPoint = C * (ZoneAirCO2SetPoint - state.dataContaminantBalance->ZoneCO21(ZoneNum)) + A * ZoneAirCO2SetPoint - B;
    1782            4 :                 } break;
    1783            0 :                 default:
    1784            0 :                     break;
    1785              :                 }
    1786            4 :                 if (ZoneAirCO2SetPoint > state.dataContaminantBalance->OutdoorCO2 && LoadToCO2SetPoint < 0.0) {
    1787            4 :                     state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP =
    1788            4 :                         LoadToCO2SetPoint / (state.dataContaminantBalance->OutdoorCO2 - ZoneAirCO2SetPoint);
    1789              :                 }
    1790              :             }
    1791              : 
    1792              :             // Apply the Zone Multiplier to the total zone moisture load
    1793            4 :             state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP *=
    1794            4 :                 state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier;
    1795            4 :             state.dataContaminantBalance->CO2PredictedRate(ZoneNum) = state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP;
    1796              :         }
    1797              : 
    1798            7 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1799              : 
    1800            4 :             state.dataContaminantBalance->GCPredictedRate(ZoneNum) = 0.0;
    1801            4 :             LoadToGCSetPoint = 0.0;
    1802            4 :             state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToGCSP = 0.0;
    1803              : 
    1804              :             // Check to see if this is a "GC controlled zone"
    1805            4 :             bool ControlledGCZoneFlag = false;
    1806              :             // Check all the controlled zones to see if it matches the zone simulated
    1807            7 :             for (auto const &contaminantControlledZone : state.dataContaminantBalance->ContaminantControlledZone) {
    1808            7 :                 if (contaminantControlledZone.ActualZoneNum == ZoneNum) {
    1809            4 :                     if (contaminantControlledZone.genericContamAvailSched->getCurrentVal() > 0.0) {
    1810            4 :                         ZoneAirGCSetPoint = state.dataContaminantBalance->ZoneGCSetPoint(contaminantControlledZone.ActualZoneNum);
    1811            4 :                         if (contaminantControlledZone.EMSOverrideCO2SetPointOn) {
    1812            0 :                             ZoneAirGCSetPoint = contaminantControlledZone.EMSOverrideGCSetPointValue;
    1813              :                         }
    1814            4 :                         ControlledGCZoneFlag = true;
    1815            4 :                         break;
    1816              :                     }
    1817              :                 }
    1818              :             }
    1819            4 :             if (!ControlledGCZoneFlag) {
    1820            0 :                 for (auto const &contaminantControlledZone : state.dataContaminantBalance->ContaminantControlledZone) {
    1821            0 :                     if (contaminantControlledZone.genericContamAvailSched->getCurrentVal() > 0.0) {
    1822            0 :                         ZoneAirGCSetPoint = state.dataContaminantBalance->ZoneGCSetPoint(contaminantControlledZone.ActualZoneNum);
    1823            0 :                         if (contaminantControlledZone.EMSOverrideCO2SetPointOn) {
    1824            0 :                             ZoneAirGCSetPoint = contaminantControlledZone.EMSOverrideGCSetPointValue;
    1825              :                         }
    1826            0 :                         if (contaminantControlledZone.NumOfZones >= 1) {
    1827            0 :                             if (contaminantControlledZone.ActualZoneNum != ZoneNum) {
    1828            0 :                                 for (int I = 1; I <= contaminantControlledZone.NumOfZones; ++I) {
    1829            0 :                                     if (contaminantControlledZone.ControlZoneNum(I) == ZoneNum) {
    1830            0 :                                         ControlledGCZoneFlag = true;
    1831            0 :                                         break;
    1832              :                                     }
    1833              :                                 }
    1834            0 :                                 if (ControlledGCZoneFlag) {
    1835            0 :                                     break;
    1836              :                                 }
    1837              :                             } else {
    1838            0 :                                 ControlledGCZoneFlag = true;
    1839            0 :                                 break;
    1840              :                             }
    1841              :                         }
    1842              :                     }
    1843              :                 }
    1844              :             }
    1845              : 
    1846            4 :             if (ControlledGCZoneFlag) {
    1847              :                 // The density of air
    1848            4 :                 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            4 :                 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            8 :                 if (state.afn->multizone_always_simulated ||
    1858            4 :                     (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            8 :                     B = GCGain +
    1865            4 :                         ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorGC) +
    1866            4 :                         state.dataContaminantBalance->MixingMassFlowGC(ZoneNum) + thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorGC;
    1867            4 :                     A = thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
    1868              :                 }
    1869            4 :                 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            4 :                 switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    1876            0 :                 case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    1877            0 :                     LoadToGCSetPoint = ((11.0 / 6.0) * C + A) * ZoneAirGCSetPoint -
    1878            0 :                                        (B + C * (3.0 * state.dataContaminantBalance->GCZoneTimeMinus1Temp(ZoneNum) -
    1879            0 :                                                  (3.0 / 2.0) * state.dataContaminantBalance->GCZoneTimeMinus2Temp(ZoneNum) +
    1880            0 :                                                  (1.0 / 3.0) * state.dataContaminantBalance->GCZoneTimeMinus3Temp(ZoneNum)));
    1881              :                     // Exact solution
    1882            0 :                 } 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            4 :                 case DataHeatBalance::SolutionAlgo::EulerMethod: {
    1893            4 :                     LoadToGCSetPoint = C * (ZoneAirGCSetPoint - state.dataContaminantBalance->ZoneGC1(ZoneNum)) + A * ZoneAirGCSetPoint - B;
    1894            4 :                 } break;
    1895            0 :                 default:
    1896            0 :                     break;
    1897              :                 }
    1898            4 :                 if (ZoneAirGCSetPoint > state.dataContaminantBalance->OutdoorGC && LoadToGCSetPoint < 0.0) {
    1899            4 :                     state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToGCSP =
    1900            4 :                         LoadToGCSetPoint / (state.dataContaminantBalance->OutdoorGC - ZoneAirGCSetPoint);
    1901              :                 }
    1902              :             }
    1903              : 
    1904              :             // Apply the Zone Multiplier to the total zone moisture load
    1905            4 :             state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToGCSP *=
    1906            4 :                 state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier;
    1907            4 :             state.dataContaminantBalance->GCPredictedRate(ZoneNum) = state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToGCSP;
    1908              :         }
    1909              :     }
    1910            3 : }
    1911              : 
    1912            0 : 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            0 :     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1924            0 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1925            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus4(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus3(ZoneNum);
    1926            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus3(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus2(ZoneNum);
    1927            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus2(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum);
    1928            0 :             state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum) =
    1929            0 :                 state.dataContaminantBalance->ZoneAirCO2Avg(ZoneNum); // using average for whole zone time step.
    1930            0 :             state.dataContaminantBalance->ZoneAirCO2(ZoneNum) = state.dataContaminantBalance->ZoneAirCO2Temp(ZoneNum);
    1931              : 
    1932            0 :             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            0 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1940            0 :             state.dataContaminantBalance->GCZoneTimeMinus4(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus3(ZoneNum);
    1941            0 :             state.dataContaminantBalance->GCZoneTimeMinus3(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus2(ZoneNum);
    1942            0 :             state.dataContaminantBalance->GCZoneTimeMinus2(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum);
    1943            0 :             state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum) =
    1944            0 :                 state.dataContaminantBalance->ZoneAirGCAvg(ZoneNum); // using average for whole zone time step.
    1945            0 :             state.dataContaminantBalance->ZoneAirGC(ZoneNum) = state.dataContaminantBalance->ZoneAirGCTemp(ZoneNum);
    1946              : 
    1947            0 :             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            0 : }
    1955              : 
    1956            0 : 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            0 :     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1968            0 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1969            0 :             state.dataContaminantBalance->DSCO2ZoneTimeMinus4(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus3(ZoneNum);
    1970            0 :             state.dataContaminantBalance->DSCO2ZoneTimeMinus3(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus2(ZoneNum);
    1971            0 :             state.dataContaminantBalance->DSCO2ZoneTimeMinus2(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus1(ZoneNum);
    1972            0 :             state.dataContaminantBalance->DSCO2ZoneTimeMinus1(ZoneNum) = state.dataContaminantBalance->ZoneAirCO2(ZoneNum);
    1973              :         }
    1974            0 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1975            0 :             state.dataContaminantBalance->DSGCZoneTimeMinus4(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus3(ZoneNum);
    1976            0 :             state.dataContaminantBalance->DSGCZoneTimeMinus3(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus2(ZoneNum);
    1977            0 :             state.dataContaminantBalance->DSGCZoneTimeMinus2(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus1(ZoneNum);
    1978            0 :             state.dataContaminantBalance->DSGCZoneTimeMinus1(ZoneNum) = state.dataContaminantBalance->ZoneAirGC(ZoneNum);
    1979              :         }
    1980              :     }
    1981              : 
    1982            0 :     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            0 : }
    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            4 : 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            4 :     Real64 AA(0.0);
    2040            4 :     Real64 BB(0.0);
    2041            4 :     Real64 M_inf(0.0); // Reversely solved infiltration mass flow rate
    2042              : 
    2043            4 :     Real64 timeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    2044              : 
    2045            4 :     auto &hmZone = state.dataHybridModel->hybridModelZones(ZoneNum);
    2046              : 
    2047            4 :     state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredCO2Concentration = hmZone.measuredCO2ConcSched->getCurrentVal();
    2048              : 
    2049            4 :     if (state.dataEnvrn->DayOfYear >= hmZone.HybridStartDayOfYear && state.dataEnvrn->DayOfYear <= hmZone.HybridEndDayOfYear) {
    2050            4 :         state.dataContaminantBalance->ZoneAirCO2(ZoneNum) = state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredCO2Concentration;
    2051              : 
    2052            4 :         auto const &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
    2053            4 :         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            2 :             if (hmZone.IncludeSystemSupplyParameters) {
    2057            1 :                 state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirFlowRate = hmZone.supplyAirMassFlowRateSched->getCurrentVal();
    2058            1 :                 state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirCO2Concentration = hmZone.supplyAirCO2ConcSched->getCurrentVal();
    2059              : 
    2060            1 :                 Real64 SumSysM_HM = state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirFlowRate;
    2061            1 :                 Real64 SumSysMxCO2_HM = state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirFlowRate *
    2062            1 :                                         state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirCO2Concentration;
    2063              : 
    2064            1 :                 AA = SumSysM_HM + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
    2065            3 :                 BB = SumSysMxCO2_HM + CO2Gain +
    2066            1 :                      ((thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorCO2) +
    2067            1 :                      state.dataContaminantBalance->MixingMassFlowCO2(ZoneNum) + thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorCO2;
    2068              : 
    2069              :             } else {
    2070            1 :                 AA = thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
    2071            1 :                 BB = CO2Gain + ((thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorCO2) +
    2072            1 :                      state.dataContaminantBalance->MixingMassFlowCO2(ZoneNum) + thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorCO2;
    2073              :             }
    2074              : 
    2075            2 :             Real64 CC = RhoAir * state.dataHeatBal->Zone(ZoneNum).Volume * state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpCO2 / timeStepSysSec;
    2076            2 :             Real64 DD = (3.0 * state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) -
    2077            2 :                          (3.0 / 2.0) * state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) +
    2078            2 :                          (1.0 / 3.0) * state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum));
    2079              : 
    2080            2 :             Real64 delta_CO2 = (state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredCO2Concentration - state.dataContaminantBalance->OutdoorCO2) / 1000;
    2081            2 :             Real64 CpAir = PsyCpAirFnW(state.dataEnvrn->OutHumRat);
    2082            2 :             Real64 AirDensity = PsyRhoAirFnPbTdbW(state,
    2083            2 :                                                   state.dataEnvrn->OutBaroPress,
    2084            2 :                                                   state.dataHeatBal->Zone(ZoneNum).OutDryBulbTemp,
    2085            2 :                                                   state.dataEnvrn->OutHumRat,
    2086              :                                                   RoutineNameInfiltration);
    2087              : 
    2088            2 :             if (state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredCO2Concentration == state.dataContaminantBalance->OutdoorCO2) {
    2089            0 :                 M_inf = 0.0;
    2090              :             } else {
    2091            2 :                 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            2 :             Real64 ACH_inf = max(0.0, min(10.0, M_inf / (CpAir * AirDensity / Constant::rSecsInHour * state.dataHeatBal->Zone(ZoneNum).Volume)));
    2096            2 :             M_inf = ACH_inf * state.dataHeatBal->Zone(ZoneNum).Volume * AirDensity / Constant::rSecsInHour;
    2097            2 :             state.dataHeatBal->Zone(ZoneNum).MCPIHM = M_inf;
    2098            2 :             state.dataHeatBal->Zone(ZoneNum).InfilOAAirChangeRateHM = ACH_inf;
    2099              :         }
    2100              : 
    2101              :         // Hybrid Model calculate people count
    2102            4 :         if (hmZone.PeopleCountCalc_C && state.dataHVACGlobal->UseZoneTimeStepHistory) {
    2103            2 :             state.dataHeatBal->Zone(ZoneNum).ZonePeopleActivityLevel =
    2104            2 :                 hmZone.peopleActivityLevelSched ? hmZone.peopleActivityLevelSched->getCurrentVal() : 0.0;
    2105            2 :             Real64 ActivityLevel = hmZone.peopleActivityLevelSched ? hmZone.peopleActivityLevelSched->getCurrentVal() : 0.0;
    2106            2 :             Real64 CO2GenRate = hmZone.peopleCO2GenRateSched ? hmZone.peopleCO2GenRateSched->getCurrentVal() : 0.0;
    2107            2 :             if (ActivityLevel <= 0.0) {
    2108            1 :                 ActivityLevel = 130.0; // 130.0 is the default people activity level [W]
    2109              :             }
    2110            2 :             if (CO2GenRate <= 0.0) {
    2111            1 :                 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            2 :             if (hmZone.IncludeSystemSupplyParameters) {
    2116            1 :                 state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirFlowRate = hmZone.supplyAirMassFlowRateSched->getCurrentVal();
    2117            1 :                 state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirCO2Concentration = hmZone.supplyAirCO2ConcSched->getCurrentVal();
    2118              : 
    2119            1 :                 Real64 SumSysM_HM = state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirFlowRate;
    2120            1 :                 Real64 SumSysMxCO2_HM = state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirFlowRate *
    2121            1 :                                         state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredSupplyAirCO2Concentration;
    2122              : 
    2123            1 :                 AA = SumSysM_HM + thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone +
    2124            1 :                      thisZoneHB.MDotOA;
    2125            2 :                 BB = CO2GainExceptPeople +
    2126            1 :                      ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorCO2) +
    2127            1 :                      (SumSysMxCO2_HM) + state.dataContaminantBalance->MixingMassFlowCO2(ZoneNum) +
    2128            1 :                      thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorCO2;
    2129              : 
    2130              :             } else {
    2131            1 :                 AA = ZoneMassFlowRate + thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone +
    2132            1 :                      thisZoneHB.MDotOA;
    2133            2 :                 BB = CO2GainExceptPeople +
    2134            1 :                      ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorCO2) +
    2135            1 :                      (CO2MassFlowRate) + state.dataContaminantBalance->MixingMassFlowCO2(ZoneNum) +
    2136            1 :                      thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorCO2;
    2137              :             }
    2138              : 
    2139            2 :             Real64 CC = RhoAir * state.dataHeatBal->Zone(ZoneNum).Volume * state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpCO2 / timeStepSysSec;
    2140            2 :             Real64 DD = (3.0 * state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) -
    2141            2 :                          (3.0 / 2.0) * state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) +
    2142            2 :                          (1.0 / 3.0) * state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum));
    2143              : 
    2144              :             Real64 CO2GainPeople =
    2145            2 :                 (((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            2 :             Real64 UpperBound = CO2Gain / (1000000 * RhoAir * CO2GenRate * ActivityLevel);
    2149            2 :             Real64 NumPeople = min(UpperBound, CO2GainPeople / (CO2GenRate * ActivityLevel));
    2150              : 
    2151            2 :             NumPeople = floor(NumPeople * 100.00 + 0.5) / 100.00;
    2152            2 :             if (NumPeople < 0.05) {
    2153            0 :                 NumPeople = 0;
    2154              :             }
    2155            2 :             state.dataHeatBal->Zone(ZoneNum).NumOccHM = NumPeople;
    2156              :         }
    2157              :     }
    2158              : 
    2159              :     // Update zone humidity ratio in the previous steps
    2160            4 :     state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum);
    2161            4 :     state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum);
    2162            4 :     state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) = state.dataHeatBal->Zone(ZoneNum).ZoneMeasuredCO2Concentration;
    2163            4 : }
    2164              : 
    2165            6 : 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           12 :     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    2192              : 
    2193            6 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2194            6 :             state.dataContaminantBalance->AZ(ZoneNum) = 0.0;
    2195            6 :             state.dataContaminantBalance->BZ(ZoneNum) = 0.0;
    2196            6 :             state.dataContaminantBalance->CZ(ZoneNum) = 0.0;
    2197              :         }
    2198            6 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    2199            2 :             state.dataContaminantBalance->AZGC(ZoneNum) = 0.0;
    2200            2 :             state.dataContaminantBalance->BZGC(ZoneNum) = 0.0;
    2201            2 :             state.dataContaminantBalance->CZGC(ZoneNum) = 0.0;
    2202              :         }
    2203              : 
    2204              :         // update the variables actually used in the balance equations.
    2205            6 :         if (!UseZoneTimeStepHistory) {
    2206            2 :             if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2207            2 :                 state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus1(ZoneNum);
    2208            2 :                 state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus2(ZoneNum);
    2209            2 :                 state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->DSCO2ZoneTimeMinus3(ZoneNum);
    2210              :             }
    2211            2 :             if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    2212            2 :                 state.dataContaminantBalance->GCZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus1(ZoneNum);
    2213            2 :                 state.dataContaminantBalance->GCZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus2(ZoneNum);
    2214            2 :                 state.dataContaminantBalance->GCZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->DSGCZoneTimeMinus3(ZoneNum);
    2215              :             }
    2216              :         } else {
    2217            4 :             if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2218            4 :                 state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus1(ZoneNum);
    2219            4 :                 state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus2(ZoneNum);
    2220            4 :                 state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->CO2ZoneTimeMinus3(ZoneNum);
    2221              :             }
    2222            4 :             if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    2223            0 :                 state.dataContaminantBalance->GCZoneTimeMinus1Temp(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus1(ZoneNum);
    2224            0 :                 state.dataContaminantBalance->GCZoneTimeMinus2Temp(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus2(ZoneNum);
    2225            0 :                 state.dataContaminantBalance->GCZoneTimeMinus3Temp(ZoneNum) = state.dataContaminantBalance->GCZoneTimeMinus3(ZoneNum);
    2226              :             }
    2227              :         }
    2228              : 
    2229              :         // Start to calculate zone CO2 and genric contaminant levels
    2230            6 :         Real64 CO2MassFlowRate = 0.0;
    2231            6 :         Real64 GCMassFlowRate = 0.0;
    2232            6 :         Real64 ZoneMassFlowRate = 0.0;
    2233            6 :         int ZoneMult = state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier;
    2234              : 
    2235              :         // Check to see if this is a controlled zone
    2236            6 :         const bool ControlledZoneAirFlag = state.dataHeatBal->Zone(ZoneNum).IsControlled;
    2237              : 
    2238              :         // Check to see if this is a plenum zone
    2239            6 :         bool ZoneRetPlenumAirFlag = false;
    2240            6 :         int ZoneRetPlenumNum = 0;
    2241            6 :         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            6 :         bool ZoneSupPlenumAirFlag = false;
    2249            6 :         int ZoneSupPlenumNum = 0;
    2250            6 :         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            6 :         if (ControlledZoneAirFlag) { // If there is system flow then calculate the flow rates
    2259              : 
    2260              :             // Calculate moisture flow rate into each zone
    2261            4 :             for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumInletNodes; ++NodeNum) {
    2262            0 :                 auto const &node = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(ZoneNum).InletNode(NodeNum));
    2263            0 :                 if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2264            0 :                     CO2MassFlowRate += (node.MassFlowRate * node.CO2) / ZoneMult;
    2265              :                 }
    2266            0 :                 if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    2267            0 :                     GCMassFlowRate += (node.MassFlowRate * node.GenContam) / ZoneMult;
    2268              :                 }
    2269            0 :                 ZoneMassFlowRate += node.MassFlowRate / ZoneMult;
    2270              :             }
    2271              : 
    2272              :             // Do the calculations for the plenum zone
    2273            2 :         } 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            2 :         } 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            6 :         Real64 timeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    2323            6 :         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            6 :         Real64 RhoAir = PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisZoneHB.ZT, thisZoneHB.airHumRat, RoutineName);
    2330              : 
    2331            6 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2332            6 :             state.dataContaminantBalance->ZoneAirDensityCO(ZoneNum) = RhoAir;
    2333              :         }
    2334              :         // Calculate Co2 internal gain
    2335            6 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2336            6 :             CO2Gain = state.dataContaminantBalance->ZoneCO2Gain(ZoneNum) * RhoAir * 1.0e6;
    2337              :         }
    2338            6 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2339            6 :             CO2GainExceptPeople = state.dataContaminantBalance->ZoneCO2GainExceptPeople(ZoneNum) * RhoAir * 1.0e6; // Addded for hybrid model
    2340              :         }
    2341            6 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    2342            2 :             GCGain = state.dataContaminantBalance->ZoneGCGain(ZoneNum) * RhoAir * 1.0e6;
    2343              :         }
    2344              : 
    2345            6 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2346            6 :             B = CO2Gain + ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorCO2) +
    2347            6 :                 (CO2MassFlowRate) + state.dataContaminantBalance->MixingMassFlowCO2(ZoneNum) +
    2348            6 :                 thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorCO2;
    2349            6 :             A = ZoneMassFlowRate + thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone +
    2350            6 :                 thisZoneHB.MDotOA;
    2351           12 :             if (state.afn->multizone_always_simulated ||
    2352            6 :                 (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
    2353            0 :                  state.afn->AirflowNetworkFanActivated)) {
    2354              :                 // Multizone airflow calculated in AirflowNetwork
    2355            0 :                 B = CO2Gain + (state.afn->exchangeData(ZoneNum).SumMHrCO + state.afn->exchangeData(ZoneNum).SumMMHrCO) + CO2MassFlowRate;
    2356            0 :                 A = ZoneMassFlowRate + state.afn->exchangeData(ZoneNum).SumMHr + state.afn->exchangeData(ZoneNum).SumMMHr;
    2357              :             }
    2358            6 :             C = RhoAir * state.dataHeatBal->Zone(ZoneNum).Volume * state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpCO2 / timeStepSysSec;
    2359              :         }
    2360              : 
    2361            6 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2362            6 :             auto &zoneAirCO2Temp = state.dataContaminantBalance->ZoneAirCO2Temp(ZoneNum);
    2363            6 :             if (state.afn->distribution_simulated) {
    2364            0 :                 B += state.afn->exchangeData(ZoneNum).TotalCO2;
    2365              :             }
    2366            6 :             state.dataContaminantBalance->AZ(ZoneNum) = A;
    2367            6 :             state.dataContaminantBalance->BZ(ZoneNum) = B;
    2368            6 :             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            6 :             switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    2373            4 :             case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    2374            4 :                 zoneAirCO2Temp = (B + C * (3.0 * state.dataContaminantBalance->CO2ZoneTimeMinus1Temp(ZoneNum) -
    2375            4 :                                            (3.0 / 2.0) * state.dataContaminantBalance->CO2ZoneTimeMinus2Temp(ZoneNum) +
    2376            4 :                                            (1.0 / 3.0) * state.dataContaminantBalance->CO2ZoneTimeMinus3Temp(ZoneNum))) /
    2377            4 :                                  ((11.0 / 6.0) * C + A);
    2378              :                 // Exact solution
    2379            4 :             } 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            2 :             case DataHeatBalance::SolutionAlgo::EulerMethod: {
    2388            2 :                 zoneAirCO2Temp = (C * state.dataContaminantBalance->ZoneCO21(ZoneNum) + B) / (C + A);
    2389            2 :             } break;
    2390            0 :             default:
    2391            0 :                 break;
    2392              :             }
    2393              : 
    2394              :             // Set the CO2 to zero if the zone has been large sinks
    2395            6 :             if (zoneAirCO2Temp < 0.0) {
    2396            0 :                 zoneAirCO2Temp = 0.0;
    2397              :             }
    2398            6 :             state.dataContaminantBalance->ZoneAirCO2(ZoneNum) = zoneAirCO2Temp;
    2399              : 
    2400            6 :             if (state.dataHybridModel->FlagHybridModel) {
    2401            4 :                 auto &hmZone = state.dataHybridModel->hybridModelZones(ZoneNum);
    2402            4 :                 if ((hmZone.InfiltrationCalc_C || hmZone.PeopleCountCalc_C) && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing)) {
    2403            4 :                     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            6 :             const int ZoneNodeNum = state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber;
    2408            6 :             if (ZoneNodeNum > 0) {
    2409            6 :                 state.dataLoopNodes->Node(ZoneNodeNum).CO2 = zoneAirCO2Temp;
    2410              :             }
    2411              :         }
    2412              : 
    2413            6 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    2414            2 :             B = GCGain + ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL) * state.dataContaminantBalance->OutdoorGC) +
    2415            2 :                 (GCMassFlowRate) + state.dataContaminantBalance->MixingMassFlowGC(ZoneNum) +
    2416            2 :                 thisZoneHB.MDotOA * state.dataContaminantBalance->OutdoorGC;
    2417            2 :             A = ZoneMassFlowRate + thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.MixingMassFlowZone +
    2418            2 :                 thisZoneHB.MDotOA;
    2419            4 :             if (state.afn->multizone_always_simulated ||
    2420            2 :                 (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
    2421            0 :                  state.afn->AirflowNetworkFanActivated)) {
    2422              :                 // Multizone airflow calculated in AirflowNetwork
    2423            0 :                 B = GCGain + (state.afn->exchangeData(ZoneNum).SumMHrGC + state.afn->exchangeData(ZoneNum).SumMMHrGC) + GCMassFlowRate;
    2424            0 :                 A = ZoneMassFlowRate + state.afn->exchangeData(ZoneNum).SumMHr + state.afn->exchangeData(ZoneNum).SumMMHr;
    2425              :             }
    2426            2 :             C = RhoAir * state.dataHeatBal->Zone(ZoneNum).Volume * state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpGenContam / timeStepSysSec;
    2427              :         }
    2428              : 
    2429            6 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    2430            2 :             auto &zoneAirGCTemp = state.dataContaminantBalance->ZoneAirGCTemp(ZoneNum);
    2431            2 :             if (state.afn->distribution_simulated) {
    2432            0 :                 B += state.afn->exchangeData(ZoneNum).TotalGC;
    2433              :             }
    2434              : 
    2435            2 :             state.dataContaminantBalance->AZGC(ZoneNum) = A;
    2436            2 :             state.dataContaminantBalance->BZGC(ZoneNum) = B;
    2437            2 :             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            2 :             switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    2442            0 :             case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    2443            0 :                 zoneAirGCTemp = (B + C * (3.0 * state.dataContaminantBalance->GCZoneTimeMinus1Temp(ZoneNum) -
    2444            0 :                                           (3.0 / 2.0) * state.dataContaminantBalance->GCZoneTimeMinus2Temp(ZoneNum) +
    2445            0 :                                           (1.0 / 3.0) * state.dataContaminantBalance->GCZoneTimeMinus3Temp(ZoneNum))) /
    2446            0 :                                 ((11.0 / 6.0) * C + A);
    2447              :                 // Exact solution
    2448            0 :             } 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            2 :             case DataHeatBalance::SolutionAlgo::EulerMethod: {
    2457            2 :                 zoneAirGCTemp = (C * state.dataContaminantBalance->ZoneGC1(ZoneNum) + B) / (C + A);
    2458            2 :             } break;
    2459            0 :             default:
    2460            0 :                 break;
    2461              :             }
    2462              : 
    2463              :             // Set the generic contaminant to zero if the zone has been large sinks
    2464            2 :             if (zoneAirGCTemp < 0.0) {
    2465            0 :                 zoneAirGCTemp = 0.0;
    2466              :             }
    2467            2 :             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            2 :             const int ZoneNodeNum = state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber;
    2471            2 :             if (ZoneNodeNum > 0) {
    2472            2 :                 state.dataLoopNodes->Node(ZoneNodeNum).GenContam = zoneAirGCTemp;
    2473              :             }
    2474              :         }
    2475              :     }
    2476            6 : }
    2477              : 
    2478              : } // namespace EnergyPlus::ZoneContaminantPredictorCorrector
        

Generated by: LCOV version 2.0-1