LCOV - code coverage report
Current view: top level - EnergyPlus - ZoneTempPredictorCorrector.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 2963 4316 68.7 %
Date: 2024-08-24 18:31:18 Functions: 42 44 95.5 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cmath>
      50             : #include <string>
      51             : 
      52             : // ObjexxFCL Headers
      53             : #include <ObjexxFCL/Array.functions.hh>
      54             : #include <ObjexxFCL/Fmath.hh>
      55             : 
      56             : // EnergyPlus Headers
      57             : #include <AirflowNetwork/Elements.hpp>
      58             : #include <AirflowNetwork/Solver.hpp>
      59             : #include <EnergyPlus/Construction.hh>
      60             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      61             : #include <EnergyPlus/DataDefineEquip.hh>
      62             : #include <EnergyPlus/DataEnvironment.hh>
      63             : #include <EnergyPlus/DataHVACGlobals.hh>
      64             : #include <EnergyPlus/DataHeatBalFanSys.hh>
      65             : #include <EnergyPlus/DataHeatBalSurface.hh>
      66             : #include <EnergyPlus/DataHeatBalance.hh>
      67             : #include <EnergyPlus/DataIPShortCuts.hh>
      68             : #include <EnergyPlus/DataLoopNode.hh>
      69             : #include <EnergyPlus/DataPrecisionGlobals.hh>
      70             : #include <EnergyPlus/DataRoomAirModel.hh>
      71             : #include <EnergyPlus/DataSizing.hh>
      72             : #include <EnergyPlus/DataStringGlobals.hh>
      73             : #include <EnergyPlus/DataSurfaces.hh>
      74             : #include <EnergyPlus/DataZoneControls.hh>
      75             : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      76             : #include <EnergyPlus/DataZoneEquipment.hh>
      77             : #include <EnergyPlus/FaultsManager.hh>
      78             : #include <EnergyPlus/FileSystem.hh>
      79             : #include <EnergyPlus/General.hh>
      80             : #include <EnergyPlus/GeneralRoutines.hh>
      81             : #include <EnergyPlus/GlobalNames.hh>
      82             : #include <EnergyPlus/HeatBalFiniteDiffManager.hh>
      83             : #include <EnergyPlus/HeatBalanceSurfaceManager.hh>
      84             : #include <EnergyPlus/HybridModel.hh>
      85             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      86             : #include <EnergyPlus/InternalHeatGains.hh>
      87             : #include <EnergyPlus/OutputProcessor.hh>
      88             : #include <EnergyPlus/OutputReportPredefined.hh>
      89             : #include <EnergyPlus/OutputReportTabular.hh>
      90             : #include <EnergyPlus/Psychrometrics.hh>
      91             : #include <EnergyPlus/RoomAirModelAirflowNetwork.hh>
      92             : #include <EnergyPlus/RoomAirModelManager.hh>
      93             : #include <EnergyPlus/ScheduleManager.hh>
      94             : #include <EnergyPlus/ThermalComfort.hh>
      95             : #include <EnergyPlus/UtilityRoutines.hh>
      96             : #include <EnergyPlus/WeatherManager.hh>
      97             : #include <EnergyPlus/ZonePlenum.hh>
      98             : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      99             : 
     100             : namespace EnergyPlus::ZoneTempPredictorCorrector {
     101             : 
     102             : // MODULE INFORMATION:
     103             : //       AUTHOR         Russell D. Taylor
     104             : //       DATE WRITTEN   1997
     105             : //       MODIFIED       Aug 2001(FW): make SNLoadHeatRate public
     106             : //                      Nov 2010  BN(FSEC) added TemperatureAndHumidity Control
     107             : //       RE-ENGINEERED  July 2003 (Peter Graham Ellis)
     108             : //                      July 2006 (BG) added operative temp control
     109             : //                      February 2008 (BG) reworked zone air temp histories
     110             : 
     111             : // PURPOSE OF THIS MODULE:
     112             : // This module contains routines to predict and correct zone temperatures.
     113             : //  also includes zone thermostatic controlling
     114             : //  Model the "Air Heat Balance" part of the the "Zone Heat Balance Method."
     115             : 
     116             : // METHODOLOGY EMPLOYED:
     117             : // apply model equations for air heat balance solved for zone air temp.
     118             : //    sum up values for the terms (e.g SUMHAT, SUMHA etc. )
     119             : //    "Predict" step is used to get zone loads for HVAC equipment
     120             : //    "correct" step determines zone air temp with available HVAC
     121             : 
     122             : enum class ZoneControlTypes
     123             : {
     124             :     Invalid = -1,
     125             :     TStat = 1,
     126             :     TCTStat = 2,
     127             :     OTTStat = 3,
     128             :     HStat = 4,
     129             :     TandHStat = 5,
     130             :     StagedDual = 6,
     131             :     Num
     132             : };
     133             : 
     134             : enum class AdaptiveComfortModel
     135             : {
     136             :     Invalid = -1,
     137             :     ADAP_NONE = 1,
     138             :     ASH55_CENTRAL = 2,
     139             :     ASH55_UPPER_90 = 3,
     140             :     ASH55_UPPER_80 = 4,
     141             :     CEN15251_CENTRAL = 5,
     142             :     CEN15251_UPPER_I = 6,
     143             :     CEN15251_UPPER_II = 7,
     144             :     CEN15251_UPPER_III = 8,
     145             :     Num
     146             : };
     147             : 
     148             : static constexpr std::array<std::string_view, static_cast<int>(HVAC::ThermostatType::Num)> ValidControlTypes = {
     149             :     "Uncontrolled",
     150             :     "ThermostatSetpoint:SingleHeating",
     151             :     "ThermostatSetpoint:SingleCooling",
     152             :     "ThermostatSetpoint:SingleHeatingOrCooling",
     153             :     "ThermostatSetpoint:DualSetpoint"};
     154             : 
     155             : static constexpr std::array<std::string_view, static_cast<int>(HVAC::ThermostatType::Num)> ValidControlTypesUC = {
     156             :     "UNCONTROLLED",
     157             :     "THERMOSTATSETPOINT:SINGLEHEATING",
     158             :     "THERMOSTATSETPOINT:SINGLECOOLING",
     159             :     "THERMOSTATSETPOINT:SINGLEHEATINGORCOOLING",
     160             :     "THERMOSTATSETPOINT:DUALSETPOINT"};
     161             : 
     162             : static constexpr std::array<std::string_view, static_cast<int>(HVAC::ThermostatType::Num)> ValidComfortControlTypes = {
     163             :     "Uncontrolled",
     164             :     "ThermostatSetpoint:ThermalComfort:Fanger:SingleHeating",
     165             :     "ThermostatSetpoint:ThermalComfort:Fanger:SingleCooling",
     166             :     "ThermostatSetpoint:ThermalComfort:Fanger:SingleHeatingOrCooling",
     167             :     "ThermostatSetpoint:ThermalComfort:Fanger:DualSetpoint"};
     168             : 
     169             : static constexpr std::array<std::string_view, static_cast<int>(HVAC::ThermostatType::Num)> ValidComfortControlTypesUC = {
     170             :     "UNCONTROLLED",
     171             :     "THERMOSTATSETPOINT:THERMALCOMFORT:FANGER:SINGLEHEATING",
     172             :     "THERMOSTATSETPOINT:THERMALCOMFORT:FANGER:SINGLECOOLING",
     173             :     "THERMOSTATSETPOINT:THERMALCOMFORT:FANGER:SINGLEHEATINGORCOOLING",
     174             :     "THERMOSTATSETPOINT:THERMALCOMFORT:FANGER:DUALSETPOINT"};
     175             : 
     176             : Array1D_string const cZControlTypes(6,
     177             :                                     {"ZoneControl:Thermostat",
     178             :                                      "ZoneControl:Thermostat:ThermalComfort",
     179             :                                      "ZoneControl:Thermostat:OperativeTemperature",
     180             :                                      "ZoneControl:Humidistat",
     181             :                                      "ZoneControl:Thermostat:TemperatureAndHumidity",
     182             :                                      "ZoneControl:Thermostat:StagedDualSetpoint"});
     183             : 
     184             : Array1D_string const AdaptiveComfortModelTypes(8,
     185             :                                                {"None",
     186             :                                                 "AdaptiveASH55CentralLine",
     187             :                                                 "AdaptiveASH5590PercentUpperLine",
     188             :                                                 "AdaptiveASH5580PercentUpperLine",
     189             :                                                 "AdaptiveCEN15251CentralLine",
     190             :                                                 "AdaptiveCEN15251CategoryIUpperLine",
     191             :                                                 "AdaptiveCEN15251CategoryIIUpperLine",
     192             :                                                 "AdaptiveCEN15251CategoryIIIUpperLine"});
     193             : 
     194             : // Functions
     195    14404425 : void ManageZoneAirUpdates(EnergyPlusData &state,
     196             :                           DataHeatBalFanSys::PredictorCorrectorCtrl const UpdateType, // Can be iGetZoneSetPoints, iPredictStep, iCorrectStep
     197             :                           Real64 &ZoneTempChange,                                     // Temp change in zone air btw previous and current timestep
     198             :                           bool const ShortenTimeStepSys,
     199             :                           bool const UseZoneTimeStepHistory, // if true then use zone timestep history, if false use system time step
     200             :                           Real64 const PriorTimeStep         // the old value for timestep length is passed for possible use in interpolating
     201             : )
     202             : {
     203             : 
     204             :     // SUBROUTINE INFORMATION
     205             :     //       AUTHOR         Russ Taylor
     206             :     //       DATE WRITTEN   September 1998
     207             :     //       MODIFIED       na
     208             :     //       RE-ENGINEERED  Brent Griffith Feb. 2008,  added arguments
     209             : 
     210             :     // PURPOSE OF THIS SUBROUTINE:
     211             :     // This subroutine predicts or corrects the zone air temperature
     212             :     // depending on the simulation status and determines the correct
     213             :     // temperature setpoint for each zone from the schedule manager.
     214             : 
     215    14404425 :     if (state.dataZoneCtrls->GetZoneAirStatsInputFlag) {
     216         787 :         GetZoneAirSetPoints(state);
     217         787 :         state.dataZoneCtrls->GetZoneAirStatsInputFlag = false;
     218             :     }
     219             : 
     220    14404425 :     InitZoneAirSetPoints(state);
     221             : 
     222    14404425 :     switch (UpdateType) {
     223     2804720 :     case DataHeatBalFanSys::PredictorCorrectorCtrl::GetZoneSetPoints: {
     224     2804720 :         CalcZoneAirTempSetPoints(state);
     225     2804720 :     } break;
     226     3866727 :     case DataHeatBalFanSys::PredictorCorrectorCtrl::PredictStep: {
     227     3866727 :         PredictSystemLoads(state, ShortenTimeStepSys, UseZoneTimeStepHistory, PriorTimeStep);
     228     3866727 :     } break;
     229     3866489 :     case DataHeatBalFanSys::PredictorCorrectorCtrl::CorrectStep: {
     230     3866489 :         ZoneTempChange = correctZoneAirTemps(state, UseZoneTimeStepHistory);
     231     3866489 :     } break;
     232           0 :     case DataHeatBalFanSys::PredictorCorrectorCtrl::RevertZoneTimestepHistories: {
     233           0 :         RevertZoneTimestepHistories(state);
     234           0 :     } break;
     235     2804482 :     case DataHeatBalFanSys::PredictorCorrectorCtrl::PushZoneTimestepHistories: {
     236     2804482 :         PushZoneTimestepHistories(state);
     237     2804482 :     } break;
     238     1062007 :     case DataHeatBalFanSys::PredictorCorrectorCtrl::PushSystemTimestepHistories: {
     239     1062007 :         PushSystemTimestepHistories(state);
     240     1062007 :     } break;
     241           0 :     default:
     242           0 :         break;
     243             :     }
     244    14404425 : }
     245             : 
     246         796 : void GetZoneAirSetPoints(EnergyPlusData &state)
     247             : {
     248             : 
     249             :     // SUBROUTINE INFORMATION:
     250             :     //       AUTHOR         Russell Taylor
     251             :     //       DATE WRITTEN   September 1998
     252             :     //       MODIFIED       L.Gu, May 2006, B. Griffith June 2006
     253             :     //       RE-ENGINEERED  na
     254             : 
     255             :     // PURPOSE OF THIS SUBROUTINE:
     256             :     // This subroutine gets the inputs related to thermostatic control.
     257             : 
     258             :     // METHODOLOGY EMPLOYED:
     259             :     // Uses the status flags to trigger events.
     260             : 
     261             :     // Using/Aliasing
     262             :     using General::CheckCreatedZoneItemName;
     263             :     using General::FindNumberInList;
     264             : 
     265             :     using ScheduleManager::CheckScheduleValue;
     266             :     using ScheduleManager::CheckScheduleValueMinMax;
     267             :     using ScheduleManager::GetScheduleIndex;
     268             :     using ScheduleManager::GetScheduleMaxValue;
     269             :     using ScheduleManager::GetScheduleMinValue;
     270             : 
     271             :     // SUBROUTINE PARAMETER DEFINITIONS:
     272             :     static constexpr std::string_view RoutineName("GetZoneAirSetpoints: ");
     273             : 
     274             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     275             :     int TempControlledZoneNum; // The Splitter that you are currently loading input into
     276             :     int NumAlphas;
     277             :     int NumNums;
     278             :     int ControlTypeNum;
     279             :     int IOStat;
     280         796 :     bool ErrorsFound(false);
     281             :     bool errFlag;
     282             :     int CTIndex;
     283             :     int HumidControlledZoneNum; // The Humidity Controller that information is being loaded into
     284             :     bool ValidScheduleControlType;
     285             :     bool ValidRadFractSched;          // check for if radiative fraction schedule has valid numbers
     286             :     bool ValidZoneOvercoolRangeSched; // check for if Zone Overcool range schedule has valid numbers
     287             :     int SchedMin;
     288             :     int SchedMax;
     289             :     int ActualZoneNum;
     290             :     int SchedTypeIndex;
     291             : 
     292             :     int ComfortControlledZoneNum; // The Splitter that you are currently loading input into
     293             :     int i;
     294             :     int IZoneCount;
     295             :     int found;
     296             :     int NumStageControlledZones; // Number of staged controlled objects
     297             :     int StageControlledZoneNum;  // Index for staged controlled zones
     298             : 
     299         796 :     Array1D_int CTSchedMapToControlledZone;
     300         796 :     Array1D_int CCmSchedMapToControlledZone;
     301             :     int Item;
     302             :     int Item1;
     303             :     int ZLItem;
     304             : 
     305             :     struct NeededControlTypes
     306             :     {
     307             :         // Members 4= the four control types + uncontrolled
     308             :         std::array<bool, static_cast<int>(HVAC::ThermostatType::Num)> MustHave = {false, false, false, false, false};
     309             :         std::array<bool, static_cast<int>(HVAC::ThermostatType::Num)> DidHave = {false, false, false, false, false};
     310             :     };
     311             : 
     312             :     struct NeededComfortControlTypes
     313             :     {
     314             :         // Members 4= the four control types + uncontrolled
     315             :         std::array<bool, static_cast<int>(HVAC::ThermostatType::Num)> MustHave = {false, false, false, false, false};
     316             :         std::array<bool, static_cast<int>(HVAC::ThermostatType::Num)> DidHave = {false, false, false, false, false};
     317             :     };
     318             : 
     319             :     // Object Data
     320         796 :     Array1D<NeededControlTypes> TStatControlTypes;
     321         796 :     Array1D<NeededComfortControlTypes> TComfortControlTypes;
     322             : 
     323             :     // Formats
     324             :     static constexpr std::string_view Header(
     325             :         "! <Zone Volume Capacitance Multiplier>, Sensible Heat Capacity Multiplier, Moisture Capacity Multiplier, Carbon "
     326             :         "Dioxide Capacity Multiplier, Generic Contaminant Capacity Multiplier\n");
     327             :     static constexpr std::string_view Format_701("Zone Volume Capacitance Multiplier,{:8.3F} ,{:8.3F},{:8.3F},{:8.3F}\n");
     328             : 
     329         796 :     auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
     330         796 :     auto &TStatObjects = state.dataZoneCtrls->TStatObjects;
     331         796 :     auto &Zone = state.dataHeatBal->Zone;
     332         796 :     auto &ZoneList = state.dataHeatBal->ZoneList;
     333         796 :     auto &TempControlledZone = state.dataZoneCtrls->TempControlledZone;
     334         796 :     auto &HumidityControlZone = state.dataZoneCtrls->HumidityControlZone;
     335         796 :     auto &ComfortTStatObjects = state.dataZoneCtrls->ComfortTStatObjects;
     336         796 :     auto &ComfortControlledZone = state.dataZoneCtrls->ComfortControlledZone;
     337         796 :     int NumOfZones = state.dataGlobal->NumOfZones;
     338         796 :     auto &StageControlledZone = state.dataZoneCtrls->StageControlledZone;
     339         796 :     auto &SetPointSingleHeating = state.dataZoneTempPredictorCorrector->SetPointSingleHeating;
     340         796 :     auto &SetPointSingleCooling = state.dataZoneTempPredictorCorrector->SetPointSingleCooling;
     341         796 :     auto &cAlphaArgs = state.dataIPShortCut->cAlphaArgs;
     342         796 :     auto &rNumericArgs = state.dataIPShortCut->rNumericArgs;
     343         796 :     auto &lNumericFieldBlanks = state.dataIPShortCut->lNumericFieldBlanks;
     344         796 :     auto &lAlphaFieldBlanks = state.dataIPShortCut->lAlphaFieldBlanks;
     345         796 :     auto &cAlphaFieldNames = state.dataIPShortCut->cAlphaFieldNames;
     346         796 :     auto &cNumericFieldNames = state.dataIPShortCut->cNumericFieldNames;
     347         796 :     auto &inputProcessor = state.dataInputProcessing->inputProcessor;
     348         796 :     auto &SetPointDualHeatCool = state.dataZoneTempPredictorCorrector->SetPointDualHeatCool;
     349             : 
     350         796 :     cCurrentModuleObject = cZControlTypes(static_cast<int>(ZoneControlTypes::TStat));
     351             :     // Update Num in state and make local convenience copy
     352         796 :     int NumTStatStatements = state.dataZoneCtrls->NumTStatStatements = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     353         796 :     TStatObjects.allocate(NumTStatStatements);
     354             : 
     355             :     // Pre-scan for use of Zone lists in TStat statements (i.e. Global application of TStat)
     356         796 :     state.dataZoneCtrls->NumTempControlledZones = 0;
     357        4953 :     for (Item = 1; Item <= NumTStatStatements; ++Item) {
     358        4157 :         inputProcessor->getObjectItem(state,
     359             :                                       cCurrentModuleObject,
     360             :                                       Item,
     361             :                                       cAlphaArgs,
     362             :                                       NumAlphas,
     363             :                                       rNumericArgs,
     364             :                                       NumNums,
     365             :                                       IOStat,
     366             :                                       lNumericFieldBlanks,
     367             :                                       lAlphaFieldBlanks,
     368             :                                       cAlphaFieldNames,
     369             :                                       cNumericFieldNames);
     370        4157 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
     371             : 
     372        4157 :         TStatObjects(Item).Name = cAlphaArgs(1);
     373        4157 :         Item1 = Util::FindItemInList(cAlphaArgs(2), Zone);
     374        4157 :         ZLItem = 0;
     375        4157 :         if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) ZLItem = Util::FindItemInList(cAlphaArgs(2), ZoneList);
     376        4157 :         if (Item1 > 0) {
     377        4148 :             TStatObjects(Item).TempControlledZoneStartPtr = state.dataZoneCtrls->NumTempControlledZones + 1;
     378        4148 :             ++state.dataZoneCtrls->NumTempControlledZones;
     379        4148 :             TStatObjects(Item).NumOfZones = 1;
     380        4148 :             TStatObjects(Item).ZoneListActive = false;
     381        4148 :             TStatObjects(Item).ZoneOrZoneListPtr = Item1;
     382           9 :         } else if (ZLItem > 0) {
     383           9 :             TStatObjects(Item).TempControlledZoneStartPtr = state.dataZoneCtrls->NumTempControlledZones + 1;
     384           9 :             state.dataZoneCtrls->NumTempControlledZones += ZoneList(ZLItem).NumOfZones;
     385           9 :             TStatObjects(Item).NumOfZones = ZoneList(ZLItem).NumOfZones;
     386           9 :             TStatObjects(Item).ZoneListActive = true;
     387           9 :             TStatObjects(Item).ZoneOrZoneListPtr = ZLItem;
     388             :         } else {
     389           0 :             ShowSevereError(
     390           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
     391           0 :             ErrorsFound = true;
     392             :         }
     393             :     }
     394             : 
     395         796 :     if (ErrorsFound) {
     396           0 :         ShowSevereError(state, format("GetZoneAirSetpoints: Errors with invalid names in {} objects.", cCurrentModuleObject));
     397           0 :         ShowContinueError(state, "...These will not be read in.  Other errors may occur.");
     398           0 :         state.dataZoneCtrls->NumTempControlledZones = 0;
     399             :     }
     400             : 
     401         796 :     if (state.dataZoneCtrls->NumTempControlledZones > 0) {
     402         685 :         TempControlledZone.allocate(state.dataZoneCtrls->NumTempControlledZones);
     403         685 :         TStatControlTypes.allocate(state.dataZoneCtrls->NumTempControlledZones); // Number of set point types
     404         685 :         CTSchedMapToControlledZone.dimension(state.dataZoneCtrls->NumTempControlledZones, 0);
     405             : 
     406         685 :         TempControlledZoneNum = 0;
     407         685 :         state.dataZoneTempPredictorCorrector->NumOnOffCtrZone = 0;
     408        4842 :         for (Item = 1; Item <= NumTStatStatements; ++Item) {
     409        4157 :             inputProcessor->getObjectItem(state,
     410             :                                           cCurrentModuleObject,
     411             :                                           Item,
     412             :                                           cAlphaArgs,
     413             :                                           NumAlphas,
     414             :                                           rNumericArgs,
     415             :                                           NumNums,
     416             :                                           IOStat,
     417             :                                           lNumericFieldBlanks,
     418             :                                           lAlphaFieldBlanks,
     419             :                                           cAlphaFieldNames,
     420             :                                           cNumericFieldNames);
     421        8348 :             for (Item1 = 1; Item1 <= TStatObjects(Item).NumOfZones; ++Item1) {
     422        4191 :                 ++TempControlledZoneNum;
     423        4191 :                 if (TStatObjects(Item).ZoneListActive) {
     424          43 :                     cAlphaArgs(2) = Zone(ZoneList(TStatObjects(Item).ZoneOrZoneListPtr).Zone(Item1)).Name;
     425             :                 }
     426             :                 int ZoneAssigned =
     427        4191 :                     Util::FindItemInList(cAlphaArgs(2), TempControlledZone, &DataZoneControls::ZoneTempControls::ZoneName, TempControlledZoneNum - 1);
     428        4191 :                 if (ZoneAssigned == 0) {
     429        4191 :                     TempControlledZone(TempControlledZoneNum).ZoneName = cAlphaArgs(2);
     430        4191 :                     TempControlledZone(TempControlledZoneNum).ActualZoneNum = Util::FindItemInList(cAlphaArgs(2), Zone);
     431        4191 :                     if (TempControlledZone(TempControlledZoneNum).ActualZoneNum == 0) {
     432           0 :                         ShowSevereError(
     433             :                             state,
     434           0 :                             format(
     435             :                                 "{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
     436           0 :                         ErrorsFound = true;
     437             :                     } else {
     438        4191 :                         Zone(TempControlledZone(TempControlledZoneNum).ActualZoneNum).TempControlledZoneIndex = TempControlledZoneNum;
     439             :                     }
     440             :                 } else {
     441           0 :                     TempControlledZone(TempControlledZoneNum).ZoneName = cAlphaArgs(2); // for continuity
     442           0 :                     ShowSevereError(state,
     443           0 :                                     format("{}=\"{}\" invalid {}=\"{}\" zone previously assigned.",
     444             :                                            cCurrentModuleObject,
     445             :                                            cAlphaArgs(1),
     446             :                                            cAlphaFieldNames(2),
     447             :                                            cAlphaArgs(2)));
     448           0 :                     ShowContinueError(state, format("...Zone was previously assigned to Thermostat=\"{}\".", TempControlledZone(ZoneAssigned).Name));
     449           0 :                     ErrorsFound = true;
     450           0 :                     continue;
     451             :                 }
     452             : 
     453        4191 :                 if (!TStatObjects(Item).ZoneListActive) {
     454        4148 :                     TempControlledZone(TempControlledZoneNum).Name = cAlphaArgs(1);
     455             :                 } else {
     456         129 :                     CheckCreatedZoneItemName(state,
     457             :                                              RoutineName,
     458             :                                              cCurrentModuleObject,
     459          43 :                                              Zone(ZoneList(TStatObjects(Item).ZoneOrZoneListPtr).Zone(Item1)).Name,
     460          43 :                                              ZoneList(TStatObjects(Item).ZoneOrZoneListPtr).MaxZoneNameLength,
     461          43 :                                              TStatObjects(Item).Name,
     462             :                                              TempControlledZone,
     463             :                                              TempControlledZoneNum - 1,
     464          43 :                                              TempControlledZone(TempControlledZoneNum).Name,
     465             :                                              errFlag);
     466          43 :                     if (errFlag) ErrorsFound = true;
     467             :                 }
     468             : 
     469        4191 :                 TempControlledZone(TempControlledZoneNum).ControlTypeSchedName = cAlphaArgs(3);
     470        4191 :                 TempControlledZone(TempControlledZoneNum).CTSchedIndex = GetScheduleIndex(state, cAlphaArgs(3));
     471        4191 :                 if (Item1 == 1) { // only show error on first of several if zone list
     472        4157 :                     if (TempControlledZone(TempControlledZoneNum).CTSchedIndex == 0) {
     473           0 :                         ShowSevereError(
     474             :                             state,
     475           0 :                             format(
     476             :                                 "{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(3), cAlphaArgs(3)));
     477           0 :                         ErrorsFound = true;
     478             :                     } else {
     479             :                         // Check validity of control types.
     480             :                         ValidScheduleControlType =
     481        4157 :                             CheckScheduleValueMinMax(state, TempControlledZone(TempControlledZoneNum).CTSchedIndex, ">=", 0.0, "<=", 4.0);
     482        4157 :                         if (!ValidScheduleControlType) {
     483           0 :                             ShowSevereError(
     484             :                                 state,
     485           0 :                                 format("{}=\"{}\" invalid range {}=\"{}\"", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
     486           0 :                             ShowContinueError(state, "..contains values outside of range [0,4].");
     487           0 :                             ErrorsFound = true;
     488             :                         }
     489             :                     }
     490             :                 }
     491             : 
     492        4191 :                 if (lAlphaFieldBlanks(7)) {
     493        3050 :                     NumAlphas = 5;
     494        1141 :                 } else if (lAlphaFieldBlanks(9)) {
     495         474 :                     NumAlphas = 7;
     496         667 :                 } else if (lAlphaFieldBlanks(11)) {
     497         667 :                     NumAlphas = 9;
     498             :                 }
     499             : 
     500        4191 :                 TempControlledZone(TempControlledZoneNum).NumControlTypes = nint((NumAlphas - 3.0) / 2.0);
     501        4191 :                 TempControlledZone(TempControlledZoneNum).ControlType.allocate(TempControlledZone(TempControlledZoneNum).NumControlTypes);
     502        4191 :                 TempControlledZone(TempControlledZoneNum).ControlTypeName.allocate(TempControlledZone(TempControlledZoneNum).NumControlTypes);
     503        4191 :                 TempControlledZone(TempControlledZoneNum).ControlTypeEnum.allocate(TempControlledZone(TempControlledZoneNum).NumControlTypes);
     504             : 
     505       10190 :                 for (ControlTypeNum = 1; ControlTypeNum <= TempControlledZone(TempControlledZoneNum).NumControlTypes; ++ControlTypeNum) {
     506             : 
     507        5999 :                     TempControlledZone(TempControlledZoneNum).ControlType(ControlTypeNum) = cAlphaArgs(nint(2.0 * ControlTypeNum - 1 + 3));
     508        5999 :                     TempControlledZone(TempControlledZoneNum).ControlTypeName(ControlTypeNum) = cAlphaArgs(nint(2.0 * ControlTypeNum + 3));
     509             : 
     510        5999 :                     if (!TempControlledZone(TempControlledZoneNum).ControlType(ControlTypeNum).empty()) {
     511             :                         HVAC::ThermostatType ctrlType = static_cast<HVAC::ThermostatType>(
     512        5999 :                             getEnumValue(ValidControlTypesUC, TempControlledZone(TempControlledZoneNum).ControlType(ControlTypeNum)));
     513        5999 :                         TempControlledZone(TempControlledZoneNum).ControlTypeEnum(ControlTypeNum) = ctrlType;
     514        5999 :                         if (ctrlType == HVAC::ThermostatType::Invalid) {
     515           0 :                             ShowSevereError(state,
     516           0 :                                             format("{}=\"{}\" invalid {}=\"{}\"",
     517             :                                                    cCurrentModuleObject,
     518             :                                                    cAlphaArgs(1),
     519           0 :                                                    cAlphaFieldNames(nint(2.0 * ControlTypeNum - 1 + 3)),
     520           0 :                                                    cAlphaArgs(nint(2.0 * ControlTypeNum - 1 + 3))));
     521           0 :                             ErrorsFound = true;
     522             :                         }
     523             :                     } else {
     524           0 :                         ShowSevereError(state,
     525           0 :                                         format("{}=\"{}\" invalid {}=\"<blank>\"",
     526             :                                                cCurrentModuleObject,
     527             :                                                cAlphaArgs(1),
     528           0 :                                                cAlphaFieldNames(nint(2.0 * ControlTypeNum - 1 + 3))));
     529           0 :                         ErrorsFound = true;
     530             :                     }
     531             :                 }
     532        4191 :                 if (NumNums > 0) {
     533           9 :                     if (rNumericArgs(1) >= 0.0) {
     534           9 :                         TempControlledZone(TempControlledZoneNum).DeltaTCutSet = rNumericArgs(1);
     535           9 :                         if (rNumericArgs(1) > 0.0) state.dataZoneTempPredictorCorrector->NumOnOffCtrZone++;
     536             :                     } else {
     537           0 :                         ShowSevereError(
     538             :                             state,
     539           0 :                             format("{}=\"{} invalid {}=[{:.0T}].", cCurrentModuleObject, cAlphaArgs(1), cNumericFieldNames(1), rNumericArgs(1)));
     540           0 :                         ShowContinueError(state, "..Allowable values must be greater or equal to 0");
     541           0 :                         ErrorsFound = true;
     542             :                     }
     543             :                 }
     544        4191 :                 if (TempControlledZone(TempControlledZoneNum).DeltaTCutSet > 0.0) {
     545          14 :                     for (ControlTypeNum = 1; ControlTypeNum <= TempControlledZone(TempControlledZoneNum).NumControlTypes; ++ControlTypeNum) {
     546           7 :                         if (Util::SameString(TempControlledZone(TempControlledZoneNum).ControlType(ControlTypeNum),
     547             :                                              "ThermostatSetpoint:SingleHeatingOrCooling")) {
     548           0 :                             ShowWarningError(state,
     549           0 :                                              format("{}=\"{}: The choice of Temperature Difference Between Cutout And Setpoint will not be applied "
     550             :                                                     "to ThermostatSetpoint:SingleHeatingOrCooling.",
     551             :                                                     cCurrentModuleObject,
     552             :                                                     cAlphaArgs(1)));
     553             :                         }
     554             :                     }
     555             :                 }
     556             :             }
     557             :         } // NumTStatStatements
     558             :     }     // Check on number of TempControlledZones
     559             : 
     560         796 :     cCurrentModuleObject = ValidControlTypesUC[static_cast<int>(HVAC::ThermostatType::SingleHeating)];
     561         796 :     state.dataZoneTempPredictorCorrector->NumSingleTempHeatingControls = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     562             : 
     563         796 :     if (state.dataZoneTempPredictorCorrector->NumSingleTempHeatingControls > 0)
     564         326 :         SetPointSingleHeating.allocate(state.dataZoneTempPredictorCorrector->NumSingleTempHeatingControls);
     565             : 
     566        1250 :     for (int idx = 1; idx <= state.dataZoneTempPredictorCorrector->NumSingleTempHeatingControls; ++idx) {
     567         454 :         inputProcessor->getObjectItem(state,
     568             :                                       cCurrentModuleObject,
     569             :                                       idx,
     570             :                                       cAlphaArgs,
     571             :                                       NumAlphas,
     572             :                                       rNumericArgs,
     573             :                                       NumNums,
     574             :                                       IOStat,
     575             :                                       lNumericFieldBlanks,
     576             :                                       lAlphaFieldBlanks,
     577             :                                       cAlphaFieldNames,
     578             :                                       cNumericFieldNames);
     579         454 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
     580         454 :         auto &singleHtgSetpoint = SetPointSingleHeating(idx);
     581         454 :         singleHtgSetpoint.Name = cAlphaArgs(1);
     582         454 :         singleHtgSetpoint.TempSchedName = cAlphaArgs(2);
     583         454 :         singleHtgSetpoint.TempSchedIndex = GetScheduleIndex(state, cAlphaArgs(2));
     584         454 :         if (singleHtgSetpoint.TempSchedIndex == 0) {
     585           0 :             ShowSevereError(
     586           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
     587           0 :             ErrorsFound = true;
     588             :         }
     589             : 
     590             :     } // SingleTempHeatingControlNum
     591             : 
     592         796 :     cCurrentModuleObject = ValidControlTypesUC[static_cast<int>(HVAC::ThermostatType::SingleCooling)];
     593         796 :     state.dataZoneTempPredictorCorrector->NumSingleTempCoolingControls = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     594             : 
     595         796 :     if (state.dataZoneTempPredictorCorrector->NumSingleTempCoolingControls > 0)
     596         320 :         SetPointSingleCooling.allocate(state.dataZoneTempPredictorCorrector->NumSingleTempCoolingControls);
     597             : 
     598        1244 :     for (int idx = 1; idx <= state.dataZoneTempPredictorCorrector->NumSingleTempCoolingControls; ++idx) {
     599         448 :         inputProcessor->getObjectItem(state,
     600             :                                       cCurrentModuleObject,
     601             :                                       idx,
     602             :                                       cAlphaArgs,
     603             :                                       NumAlphas,
     604             :                                       rNumericArgs,
     605             :                                       NumNums,
     606             :                                       IOStat,
     607             :                                       lNumericFieldBlanks,
     608             :                                       lAlphaFieldBlanks,
     609             :                                       cAlphaFieldNames,
     610             :                                       cNumericFieldNames);
     611         448 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
     612         448 :         auto &singleClgSetpoint = SetPointSingleCooling(idx);
     613         448 :         singleClgSetpoint.Name = cAlphaArgs(1);
     614         448 :         singleClgSetpoint.TempSchedName = cAlphaArgs(2);
     615         448 :         singleClgSetpoint.TempSchedIndex = GetScheduleIndex(state, cAlphaArgs(2));
     616         448 :         if (singleClgSetpoint.TempSchedIndex == 0) {
     617           0 :             ShowSevereError(
     618           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
     619           0 :             ErrorsFound = true;
     620             :         }
     621             : 
     622             :     } // SingleTempCoolingControlNum
     623             : 
     624         796 :     cCurrentModuleObject = ValidControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeatCool)];
     625         796 :     state.dataZoneTempPredictorCorrector->NumSingleTempHeatCoolControls = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     626             : 
     627         796 :     if (state.dataZoneTempPredictorCorrector->NumSingleTempHeatCoolControls > 0)
     628          11 :         state.dataZoneTempPredictorCorrector->SetPointSingleHeatCool.allocate(state.dataZoneTempPredictorCorrector->NumSingleTempHeatCoolControls);
     629             : 
     630         807 :     for (int idx = 1; idx <= state.dataZoneTempPredictorCorrector->NumSingleTempHeatCoolControls; ++idx) {
     631          11 :         inputProcessor->getObjectItem(state,
     632             :                                       cCurrentModuleObject,
     633             :                                       idx,
     634             :                                       cAlphaArgs,
     635             :                                       NumAlphas,
     636             :                                       rNumericArgs,
     637             :                                       NumNums,
     638             :                                       IOStat,
     639             :                                       lNumericFieldBlanks,
     640             :                                       lAlphaFieldBlanks,
     641             :                                       cAlphaFieldNames,
     642             :                                       cNumericFieldNames);
     643          11 :         auto &singleHeatCoolSetpoint = state.dataZoneTempPredictorCorrector->SetPointSingleHeatCool(idx);
     644          11 :         singleHeatCoolSetpoint.Name = cAlphaArgs(1);
     645          11 :         singleHeatCoolSetpoint.TempSchedName = cAlphaArgs(2);
     646          11 :         singleHeatCoolSetpoint.TempSchedIndex = GetScheduleIndex(state, cAlphaArgs(2));
     647          11 :         if (singleHeatCoolSetpoint.TempSchedIndex == 0) {
     648           0 :             ShowSevereError(
     649           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
     650           0 :             ErrorsFound = true;
     651             :         }
     652             : 
     653             :     } // SingleTempHeatCoolControlNum
     654             : 
     655         796 :     cCurrentModuleObject = ValidControlTypes[static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand)];
     656         796 :     state.dataZoneTempPredictorCorrector->NumDualTempHeatCoolControls = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     657             : 
     658         796 :     if (state.dataZoneTempPredictorCorrector->NumDualTempHeatCoolControls > 0)
     659         494 :         SetPointDualHeatCool.allocate(state.dataZoneTempPredictorCorrector->NumDualTempHeatCoolControls);
     660             : 
     661        3259 :     for (int idx = 1; idx <= state.dataZoneTempPredictorCorrector->NumDualTempHeatCoolControls; ++idx) {
     662        2463 :         inputProcessor->getObjectItem(state,
     663             :                                       cCurrentModuleObject,
     664             :                                       idx,
     665             :                                       cAlphaArgs,
     666             :                                       NumAlphas,
     667             :                                       rNumericArgs,
     668             :                                       NumNums,
     669             :                                       IOStat,
     670             :                                       lNumericFieldBlanks,
     671             :                                       lAlphaFieldBlanks,
     672             :                                       cAlphaFieldNames,
     673             :                                       cNumericFieldNames);
     674        2463 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
     675        2463 :         auto &dualHeatCoolSetpoint = SetPointDualHeatCool(idx);
     676        2463 :         dualHeatCoolSetpoint.Name = cAlphaArgs(1);
     677        2463 :         dualHeatCoolSetpoint.HeatTempSetptSchedName = cAlphaArgs(2);
     678        2463 :         dualHeatCoolSetpoint.HeatTempSchedIndex = GetScheduleIndex(state, cAlphaArgs(2));
     679        2463 :         if (dualHeatCoolSetpoint.HeatTempSchedIndex == 0) {
     680           0 :             ShowSevereError(
     681           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
     682           0 :             ErrorsFound = true;
     683             :         }
     684        2463 :         dualHeatCoolSetpoint.CoolTempSetptSchedName = cAlphaArgs(3);
     685        2463 :         dualHeatCoolSetpoint.CoolTempSchedIndex = GetScheduleIndex(state, cAlphaArgs(3));
     686        2463 :         if (dualHeatCoolSetpoint.CoolTempSchedIndex == 0) {
     687           0 :             ShowSevereError(
     688           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(3), cAlphaArgs(3)));
     689           0 :             ErrorsFound = true;
     690             :         }
     691             : 
     692             :     } // DualTempHeatCoolControlNum
     693             : 
     694             :     // Finish filling in Schedule pointing indexes
     695             :     int setPointObjectArrayIndex;
     696        4987 :     for (TempControlledZoneNum = 1; TempControlledZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TempControlledZoneNum) {
     697       10190 :         for (int ct = 1; ct <= state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum).NumControlTypes; ct++) {
     698        5999 :             switch (state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum).ControlTypeEnum(ct)) {
     699        1158 :             case HVAC::ThermostatType::SingleHeating:
     700        1158 :                 setPointObjectArrayIndex = Util::FindItem(TempControlledZone(TempControlledZoneNum).ControlTypeName(ct), SetPointSingleHeating);
     701        2316 :                 TempControlledZone(TempControlledZoneNum).SchIndx_SingleHeatSetPoint =
     702        1158 :                     state.dataZoneTempPredictorCorrector->SetPointSingleHeating(setPointObjectArrayIndex).TempSchedIndex;
     703        1158 :                 break;
     704        1144 :             case HVAC::ThermostatType::SingleCooling:
     705        1144 :                 setPointObjectArrayIndex = Util::FindItem(TempControlledZone(TempControlledZoneNum).ControlTypeName(ct), SetPointSingleCooling);
     706        2288 :                 TempControlledZone(TempControlledZoneNum).SchIndx_SingleCoolSetPoint =
     707        1144 :                     state.dataZoneTempPredictorCorrector->SetPointSingleCooling(setPointObjectArrayIndex).TempSchedIndex;
     708        1144 :                 break;
     709          25 :             case HVAC::ThermostatType::SingleHeatCool:
     710          25 :                 setPointObjectArrayIndex = Util::FindItem(TempControlledZone(TempControlledZoneNum).ControlTypeName(ct),
     711          25 :                                                           state.dataZoneTempPredictorCorrector->SetPointSingleHeatCool);
     712          50 :                 TempControlledZone(TempControlledZoneNum).SchIndx_SingleHeatCoolSetPoint =
     713          25 :                     state.dataZoneTempPredictorCorrector->SetPointSingleHeatCool(setPointObjectArrayIndex).TempSchedIndex;
     714          25 :                 break;
     715        3672 :             case HVAC::ThermostatType::DualSetPointWithDeadBand:
     716        3672 :                 setPointObjectArrayIndex = Util::FindItem(TempControlledZone(TempControlledZoneNum).ControlTypeName(ct),
     717        3672 :                                                           state.dataZoneTempPredictorCorrector->SetPointDualHeatCool);
     718        7344 :                 TempControlledZone(TempControlledZoneNum).SchIndx_DualSetPointWDeadBandHeat =
     719        3672 :                     state.dataZoneTempPredictorCorrector->SetPointDualHeatCool(setPointObjectArrayIndex).HeatTempSchedIndex;
     720        7344 :                 TempControlledZone(TempControlledZoneNum).SchIndx_DualSetPointWDeadBandCool =
     721        3672 :                     state.dataZoneTempPredictorCorrector->SetPointDualHeatCool(setPointObjectArrayIndex).CoolTempSchedIndex;
     722        3672 :                 break;
     723           0 :             default:
     724           0 :                 assert(false);
     725             :             }
     726             :         }
     727             :     }
     728             : 
     729             :     // Now, Check the schedule values/indices for validity
     730             : 
     731        4987 :     for (TempControlledZoneNum = 1; TempControlledZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TempControlledZoneNum) {
     732             : 
     733        4191 :         ActualZoneNum = TempControlledZone(TempControlledZoneNum).ActualZoneNum;
     734        4191 :         CTIndex = TempControlledZone(TempControlledZoneNum).CTSchedIndex;
     735        4191 :         if (CTIndex == 0) continue; // error will be caught elsewhere
     736        4191 :         SchedMin = GetScheduleMinValue(state, CTIndex);
     737        4191 :         SchedMax = GetScheduleMaxValue(state, CTIndex);
     738             : 
     739        4191 :         if (SchedMin == 0 && SchedMax == 0) {
     740           0 :             if (FindNumberInList(CTIndex, CTSchedMapToControlledZone, state.dataZoneCtrls->NumTempControlledZones) == 0) {
     741           0 :                 ShowSevereError(state, format("Control Type Schedule={}", TempControlledZone(TempControlledZoneNum).ControlTypeSchedName));
     742           0 :                 ShowContinueError(state, "..specifies control type 0 for all entries.");
     743           0 :                 ShowContinueError(state, "All zones using this Control Type Schedule have no heating or cooling available.");
     744             :             }
     745           0 :             CTSchedMapToControlledZone(TempControlledZoneNum) = CTIndex;
     746             :         }
     747             : 
     748       10869 :         for (ControlTypeNum = SchedMin; ControlTypeNum <= SchedMax; ++ControlTypeNum) {
     749             : 
     750        6678 :             int TempIndex = 0;
     751        6678 :             switch (static_cast<HVAC::ThermostatType>(ControlTypeNum)) {
     752           9 :             case HVAC::ThermostatType::Uncontrolled:
     753           9 :                 break;
     754        1161 :             case HVAC::ThermostatType::SingleHeating:
     755        1161 :                 TempIndex = TempControlledZone(TempControlledZoneNum).SchIndx_SingleHeatSetPoint;
     756        1161 :                 if (TempIndex == 0) {
     757           3 :                     if (CheckScheduleValue(state, CTIndex, static_cast<int>(HVAC::ThermostatType::SingleHeating))) {
     758           0 :                         ShowSevereError(state, format("Control Type Schedule={}", TempControlledZone(TempControlledZoneNum).ControlTypeSchedName));
     759           0 :                         ShowContinueError(state,
     760           0 :                                           format("..specifies control type 1 ({}) as the control type. Not valid for this zone.",
     761           0 :                                                  ValidControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeating)]));
     762           0 :                         ShowContinueError(state,
     763           0 :                                           format("..reference {}={}",
     764             :                                                  cZControlTypes(static_cast<int>(ZoneControlTypes::TStat)),
     765           0 :                                                  TempControlledZone(TempControlledZoneNum).Name));
     766           0 :                         ShowContinueError(state, format("..reference ZONE={}", TempControlledZone(TempControlledZoneNum).ZoneName));
     767           0 :                         ErrorsFound = true;
     768             :                     }
     769             :                 }
     770        1161 :                 break;
     771        1144 :             case HVAC::ThermostatType::SingleCooling:
     772        1144 :                 TempIndex = TempControlledZone(TempControlledZoneNum).SchIndx_SingleCoolSetPoint;
     773        1144 :                 if (TempIndex == 0) {
     774           0 :                     if (CheckScheduleValue(state, CTIndex, static_cast<int>(HVAC::ThermostatType::SingleCooling))) {
     775           0 :                         ShowSevereError(state, format("Control Type Schedule={}", TempControlledZone(TempControlledZoneNum).ControlTypeSchedName));
     776           0 :                         ShowContinueError(state,
     777           0 :                                           format("..specifies control type 2 ({}) as the control type. Not valid for this zone.",
     778           0 :                                                  ValidControlTypes[static_cast<int>(HVAC::ThermostatType::SingleCooling)]));
     779           0 :                         ShowContinueError(state,
     780           0 :                                           format("..reference {}={}",
     781             :                                                  cZControlTypes(static_cast<int>(ZoneControlTypes::TStat)),
     782           0 :                                                  TempControlledZone(TempControlledZoneNum).Name));
     783           0 :                         ShowContinueError(state, format("..reference ZONE={}", TempControlledZone(TempControlledZoneNum).ZoneName));
     784           0 :                         ErrorsFound = true;
     785             :                     }
     786             :                 }
     787        1144 :                 break;
     788         692 :             case HVAC::ThermostatType::SingleHeatCool:
     789         692 :                 TempIndex = TempControlledZone(TempControlledZoneNum).SchIndx_SingleHeatCoolSetPoint;
     790         692 :                 if (TempIndex == 0) {
     791         667 :                     if (CheckScheduleValue(state, CTIndex, static_cast<int>(HVAC::ThermostatType::SingleHeatCool))) {
     792           0 :                         ShowSevereError(state, format("Schedule={}", TempControlledZone(TempControlledZoneNum).ControlTypeSchedName));
     793           0 :                         ShowContinueError(state,
     794           0 :                                           format("..specifies control type 3 ({}) as the control type. Not valid for this zone.",
     795           0 :                                                  ValidControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeatCool)]));
     796           0 :                         ShowContinueError(state,
     797           0 :                                           format("..reference {}={}",
     798             :                                                  cZControlTypes(static_cast<int>(ZoneControlTypes::TStat)),
     799           0 :                                                  TempControlledZone(TempControlledZoneNum).Name));
     800           0 :                         ShowContinueError(state, format("..reference ZONE={}", TempControlledZone(TempControlledZoneNum).ZoneName));
     801           0 :                         ErrorsFound = true;
     802             :                     }
     803             :                 }
     804         692 :                 break;
     805        3672 :             case HVAC::ThermostatType::DualSetPointWithDeadBand:
     806        3672 :                 TempIndex = TempControlledZone(TempControlledZoneNum)
     807             :                                 .SchIndx_DualSetPointWDeadBandHeat; // using "Heat" as a sentinel that dualsetpoint is on this zone control object
     808        3672 :                 if (TempIndex == 0) {
     809           0 :                     if (CheckScheduleValue(state, CTIndex, static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand))) {
     810           0 :                         ShowSevereError(state, format("Schedule={}", TempControlledZone(TempControlledZoneNum).ControlTypeSchedName));
     811           0 :                         ShowContinueError(state,
     812           0 :                                           format("..specifies control type 4 ({}) as the control type. Not valid for this zone.",
     813           0 :                                                  ValidControlTypes[static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand)]));
     814           0 :                         ShowContinueError(state,
     815           0 :                                           format("..reference {}={}",
     816             :                                                  cZControlTypes(static_cast<int>(ZoneControlTypes::TStat)),
     817           0 :                                                  TempControlledZone(TempControlledZoneNum).Name));
     818           0 :                         ShowContinueError(state, format("..reference ZONE={}", TempControlledZone(TempControlledZoneNum).ZoneName));
     819           0 :                         ErrorsFound = true;
     820             :                     }
     821             :                 }
     822        3672 :                 break;
     823           0 :             default:
     824           0 :                 ShowSevereError(state,
     825           0 :                                 format("GetZoneAirSetpoints: Illegal control type for Zone={}, Found value={}, in Schedule={}",
     826           0 :                                        Zone(ActualZoneNum).Name,
     827             :                                        ControlTypeNum,
     828           0 :                                        TempControlledZone(TempControlledZoneNum).ControlTypeSchedName));
     829           0 :                 ShowContinueError(state, "..valid range values are [0,4].");
     830           0 :                 ErrorsFound = true;
     831             :             }
     832             :         }
     833             :     }
     834             : 
     835        4987 :     for (TempControlledZoneNum = 1; TempControlledZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TempControlledZoneNum) {
     836             : 
     837        4191 :         ActualZoneNum = TempControlledZone(TempControlledZoneNum).ActualZoneNum;
     838        4191 :         CTIndex = TempControlledZone(TempControlledZoneNum).CTSchedIndex;
     839        4191 :         if (CTIndex == 0) continue; // error caught elsewhere -- would just be confusing here
     840             : 
     841       20955 :         for (ControlTypeNum = 1; ControlTypeNum <= 4; ++ControlTypeNum) {
     842       16764 :             if (TStatControlTypes(TempControlledZoneNum).MustHave[ControlTypeNum] && TStatControlTypes(TempControlledZoneNum).DidHave[ControlTypeNum])
     843           0 :                 continue;
     844             : 
     845       16764 :             switch (static_cast<HVAC::ThermostatType>(ControlTypeNum)) {
     846        4191 :             case HVAC::ThermostatType::SingleHeating:
     847        4191 :                 if (!TStatControlTypes(TempControlledZoneNum).MustHave[ControlTypeNum]) continue;
     848           0 :                 ShowWarningError(state, format("Schedule={}", TempControlledZone(TempControlledZoneNum).ControlTypeSchedName));
     849           0 :                 ShowContinueError(state,
     850           0 :                                   format("...should include control type 1 ({}) but does not.",
     851           0 :                                          ValidControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeating)]));
     852           0 :                 ShowContinueError(state,
     853           0 :                                   format("..reference {}={}",
     854             :                                          cZControlTypes(static_cast<int>(ZoneControlTypes::TStat)),
     855           0 :                                          TempControlledZone(TempControlledZoneNum).Name));
     856           0 :                 ShowContinueError(state, format("..reference ZONE={}", TempControlledZone(TempControlledZoneNum).ZoneName));
     857           0 :                 break;
     858        4191 :             case HVAC::ThermostatType::SingleCooling:
     859        4191 :                 if (!TStatControlTypes(TempControlledZoneNum).MustHave[ControlTypeNum]) continue;
     860           0 :                 ShowWarningError(state, format("Schedule={}", TempControlledZone(TempControlledZoneNum).ControlTypeSchedName));
     861           0 :                 ShowContinueError(state,
     862           0 :                                   format("...should include control type 2 ({}) but does not.",
     863           0 :                                          ValidControlTypes[static_cast<int>(HVAC::ThermostatType::SingleCooling)]));
     864           0 :                 ShowContinueError(state,
     865           0 :                                   format("..reference {}={}",
     866             :                                          cZControlTypes(static_cast<int>(ZoneControlTypes::TStat)),
     867           0 :                                          TempControlledZone(TempControlledZoneNum).Name));
     868           0 :                 ShowContinueError(state, format("..reference ZONE={}", TempControlledZone(TempControlledZoneNum).ZoneName));
     869           0 :                 break;
     870        4191 :             case HVAC::ThermostatType::SingleHeatCool:
     871        4191 :                 if (!TStatControlTypes(TempControlledZoneNum).MustHave[ControlTypeNum]) continue;
     872           0 :                 ShowWarningError(state, format("Schedule={}", TempControlledZone(TempControlledZoneNum).ControlTypeSchedName));
     873           0 :                 ShowContinueError(state,
     874           0 :                                   format("...should include control type 3 ({}) but does not.",
     875           0 :                                          ValidControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeating)]));
     876           0 :                 ShowContinueError(state,
     877           0 :                                   format("..reference {}={}",
     878             :                                          cZControlTypes(static_cast<int>(ZoneControlTypes::TStat)),
     879           0 :                                          TempControlledZone(TempControlledZoneNum).Name));
     880           0 :                 ShowContinueError(state, format("..reference ZONE={}", TempControlledZone(TempControlledZoneNum).ZoneName));
     881           0 :                 break;
     882        4191 :             case HVAC::ThermostatType::DualSetPointWithDeadBand:
     883        4191 :                 if (!TStatControlTypes(TempControlledZoneNum).MustHave[ControlTypeNum]) continue;
     884           0 :                 ShowWarningError(state, format("Schedule={}", TempControlledZone(TempControlledZoneNum).ControlTypeSchedName));
     885           0 :                 ShowContinueError(state,
     886           0 :                                   format("...should include control type 4 ({}) but does not.",
     887           0 :                                          ValidControlTypes[static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand)]));
     888           0 :                 ShowContinueError(state,
     889           0 :                                   format("..reference {}={}",
     890             :                                          cZControlTypes(static_cast<int>(ZoneControlTypes::TStat)),
     891           0 :                                          TempControlledZone(TempControlledZoneNum).Name));
     892           0 :                 ShowContinueError(state, format("..reference ZONE={}", TempControlledZone(TempControlledZoneNum).ZoneName));
     893           0 :                 break;
     894           0 :             default:
     895           0 :                 break;
     896             :             }
     897             :         }
     898             :     }
     899             : 
     900         796 :     if (allocated(TStatControlTypes)) TStatControlTypes.deallocate();
     901             :     // This starts the Humidity Control Get Input section
     902         796 :     cCurrentModuleObject = cZControlTypes(static_cast<int>(ZoneControlTypes::HStat));
     903         796 :     state.dataZoneCtrls->NumHumidityControlZones = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     904             : 
     905         796 :     if (state.dataZoneCtrls->NumHumidityControlZones > 0) {
     906          91 :         HumidityControlZone.allocate(state.dataZoneCtrls->NumHumidityControlZones);
     907          91 :         state.dataZoneTempPredictorCorrector->HumidityControlZoneUniqueNames.reserve(
     908          91 :             static_cast<unsigned>(state.dataZoneCtrls->NumHumidityControlZones));
     909             :     }
     910             : 
     911         977 :     for (HumidControlledZoneNum = 1; HumidControlledZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HumidControlledZoneNum) {
     912         181 :         inputProcessor->getObjectItem(state,
     913             :                                       cCurrentModuleObject,
     914             :                                       HumidControlledZoneNum,
     915             :                                       cAlphaArgs,
     916             :                                       NumAlphas,
     917             :                                       rNumericArgs,
     918             :                                       NumNums,
     919             :                                       IOStat,
     920             :                                       lNumericFieldBlanks,
     921             :                                       lAlphaFieldBlanks,
     922             :                                       cAlphaFieldNames,
     923             :                                       cNumericFieldNames);
     924         181 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
     925             : 
     926         181 :         HumidityControlZone(HumidControlledZoneNum).ControlName = cAlphaArgs(1);
     927         181 :         GlobalNames::IntraObjUniquenessCheck(state,
     928         181 :                                              cAlphaArgs(2),
     929             :                                              cCurrentModuleObject,
     930         181 :                                              cAlphaFieldNames(2),
     931         181 :                                              state.dataZoneTempPredictorCorrector->HumidityControlZoneUniqueNames,
     932             :                                              ErrorsFound);
     933             : 
     934         181 :         HumidityControlZone(HumidControlledZoneNum).ZoneName = cAlphaArgs(2);
     935         181 :         HumidityControlZone(HumidControlledZoneNum).ActualZoneNum = Util::FindItem(cAlphaArgs(2), Zone);
     936         181 :         if (HumidityControlZone(HumidControlledZoneNum).ActualZoneNum == 0) {
     937           0 :             ShowSevereError(state,
     938           0 :                             format("{}=\"{} invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
     939           0 :             ErrorsFound = true;
     940             :         } else {
     941         181 :             state.dataHeatBal->Zone(HumidityControlZone(HumidControlledZoneNum).ActualZoneNum).humidityControlZoneIndex = HumidControlledZoneNum;
     942             :         }
     943         181 :         HumidityControlZone(HumidControlledZoneNum).HumidifyingSched = cAlphaArgs(3);
     944         181 :         HumidityControlZone(HumidControlledZoneNum).HumidifyingSchedIndex = GetScheduleIndex(state, cAlphaArgs(3));
     945         181 :         if (HumidityControlZone(HumidControlledZoneNum).HumidifyingSchedIndex == 0) {
     946           0 :             ShowSevereError(state,
     947           0 :                             format("{}=\"{} invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(3), cAlphaArgs(3)));
     948           0 :             ErrorsFound = true;
     949             :         }
     950         181 :         if (NumAlphas == 4) {
     951         111 :             HumidityControlZone(HumidControlledZoneNum).DehumidifyingSched = cAlphaArgs(4);
     952         111 :             HumidityControlZone(HumidControlledZoneNum).DehumidifyingSchedIndex = GetScheduleIndex(state, cAlphaArgs(4));
     953         111 :             if (HumidityControlZone(HumidControlledZoneNum).DehumidifyingSchedIndex == 0) {
     954           0 :                 ShowSevereError(
     955           0 :                     state, format("{}=\"{} invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4)));
     956           0 :                 ErrorsFound = true;
     957             :             }
     958             :         } else {
     959          70 :             HumidityControlZone(HumidControlledZoneNum).DehumidifyingSched = cAlphaArgs(3);
     960          70 :             HumidityControlZone(HumidControlledZoneNum).DehumidifyingSchedIndex = GetScheduleIndex(state, cAlphaArgs(3));
     961             :         }
     962             : 
     963             :     } // HumidControlledZoneNum
     964             : 
     965             :     // Start to read Thermal comfort control objects
     966         796 :     cCurrentModuleObject = cZControlTypes(static_cast<int>(ZoneControlTypes::TCTStat));
     967         796 :     state.dataZoneCtrls->NumComfortTStatStatements = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     968         796 :     ComfortTStatObjects.allocate(state.dataZoneCtrls->NumComfortTStatStatements);
     969             : 
     970             :     // Pre-scan for use of Zone lists in TStat statements (i.e. Global application of TStat)
     971         796 :     state.dataZoneCtrls->NumComfortControlledZones = 0;
     972         796 :     errFlag = false;
     973         797 :     for (Item = 1; Item <= state.dataZoneCtrls->NumComfortTStatStatements; ++Item) {
     974           1 :         inputProcessor->getObjectItem(state,
     975             :                                       cCurrentModuleObject,
     976             :                                       Item,
     977             :                                       cAlphaArgs,
     978             :                                       NumAlphas,
     979             :                                       rNumericArgs,
     980             :                                       NumNums,
     981             :                                       IOStat,
     982             :                                       lNumericFieldBlanks,
     983             :                                       lAlphaFieldBlanks,
     984             :                                       cAlphaFieldNames,
     985             :                                       cNumericFieldNames);
     986           1 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
     987             : 
     988           1 :         Item1 = Util::FindItemInList(cAlphaArgs(2), Zone);
     989           1 :         ZLItem = 0;
     990           1 :         if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) ZLItem = Util::FindItemInList(cAlphaArgs(2), ZoneList);
     991           1 :         ComfortTStatObjects(Item).Name = cAlphaArgs(1);
     992           1 :         if (Item1 > 0) {
     993           1 :             ComfortTStatObjects(Item).ComfortControlledZoneStartPtr = state.dataZoneCtrls->NumComfortControlledZones + 1;
     994           1 :             ++state.dataZoneCtrls->NumComfortControlledZones;
     995           1 :             ComfortTStatObjects(Item).NumOfZones = 1;
     996           1 :             ComfortTStatObjects(Item).ZoneListActive = false;
     997           1 :             ComfortTStatObjects(Item).ZoneOrZoneListPtr = Item1;
     998           0 :         } else if (ZLItem > 0) {
     999           0 :             ComfortTStatObjects(Item).ComfortControlledZoneStartPtr = state.dataZoneCtrls->NumComfortControlledZones + 1;
    1000           0 :             state.dataZoneCtrls->NumComfortControlledZones += ZoneList(ZLItem).NumOfZones;
    1001           0 :             ComfortTStatObjects(Item).NumOfZones = ZoneList(ZLItem).NumOfZones;
    1002           0 :             ComfortTStatObjects(Item).ZoneListActive = true;
    1003           0 :             ComfortTStatObjects(Item).ZoneOrZoneListPtr = ZLItem;
    1004             :         } else {
    1005           0 :             ShowSevereError(
    1006           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1007           0 :             errFlag = true;
    1008           0 :             ErrorsFound = true;
    1009             :         }
    1010             :     }
    1011             : 
    1012         796 :     if (errFlag) {
    1013           0 :         ShowSevereError(state, format("GetZoneAirSetpoints: Errors with invalid names in {} objects.", cCurrentModuleObject));
    1014           0 :         ShowContinueError(state, "...These will not be read in.  Other errors may occur.");
    1015           0 :         state.dataZoneCtrls->NumComfortControlledZones = 0;
    1016             :     }
    1017             : 
    1018         796 :     if (state.dataZoneCtrls->NumComfortControlledZones > 0) {
    1019           1 :         ComfortControlledZone.allocate(state.dataZoneCtrls->NumComfortControlledZones);
    1020           1 :         TComfortControlTypes.allocate(state.dataZoneCtrls->NumComfortControlledZones); // Number of set point types
    1021           1 :         CCmSchedMapToControlledZone.dimension(state.dataZoneCtrls->NumComfortControlledZones, 0);
    1022             : 
    1023           1 :         ComfortControlledZoneNum = 0;
    1024           2 :         for (Item = 1; Item <= state.dataZoneCtrls->NumComfortTStatStatements; ++Item) {
    1025           1 :             inputProcessor->getObjectItem(state,
    1026             :                                           cCurrentModuleObject,
    1027             :                                           Item,
    1028             :                                           cAlphaArgs,
    1029             :                                           NumAlphas,
    1030             :                                           rNumericArgs,
    1031             :                                           NumNums,
    1032             :                                           IOStat,
    1033             :                                           lNumericFieldBlanks,
    1034             :                                           lAlphaFieldBlanks,
    1035             :                                           cAlphaFieldNames,
    1036             :                                           cNumericFieldNames);
    1037           2 :             for (Item1 = 1; Item1 <= ComfortTStatObjects(Item).NumOfZones; ++Item1) {
    1038           1 :                 ++ComfortControlledZoneNum;
    1039           1 :                 if (ComfortTStatObjects(Item).ZoneListActive) {
    1040           0 :                     cAlphaArgs(2) = state.dataHeatBal->Zone(ZoneList(ComfortTStatObjects(Item).ZoneOrZoneListPtr).Zone(Item1)).Name;
    1041             :                 }
    1042           1 :                 int ZoneAssigned = Util::FindItemInList(
    1043           1 :                     cAlphaArgs(2), ComfortControlledZone, &DataZoneControls::ZoneComfortControls::ZoneName, ComfortControlledZoneNum - 1);
    1044           1 :                 if (ZoneAssigned == 0) {
    1045           1 :                     ComfortControlledZone(ComfortControlledZoneNum).ZoneName = cAlphaArgs(2);
    1046           1 :                     ComfortControlledZone(ComfortControlledZoneNum).ActualZoneNum = Util::FindItemInList(cAlphaArgs(2), Zone);
    1047           1 :                     if (ComfortControlledZone(ComfortControlledZoneNum).ActualZoneNum == 0) {
    1048           0 :                         ShowSevereError(
    1049             :                             state,
    1050           0 :                             format(
    1051             :                                 "{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1052           0 :                         ErrorsFound = true;
    1053             :                     }
    1054             :                 } else {
    1055           0 :                     ComfortControlledZone(ComfortControlledZoneNum).ZoneName = cAlphaArgs(2); // for continuity
    1056           0 :                     ShowSevereError(state,
    1057           0 :                                     format("{}=\"{}\" invalid {}=\"{}\" zone previously assigned.",
    1058             :                                            cCurrentModuleObject,
    1059             :                                            cAlphaArgs(1),
    1060             :                                            cAlphaFieldNames(2),
    1061             :                                            cAlphaArgs(2)));
    1062           0 :                     ShowContinueError(state,
    1063           0 :                                       format("...Zone was previously assigned to Thermostat=\"{}\".", ComfortControlledZone(ZoneAssigned).Name));
    1064           0 :                     ErrorsFound = true;
    1065           0 :                     continue;
    1066             :                 }
    1067             : 
    1068           1 :                 if (!ComfortTStatObjects(Item).ZoneListActive) {
    1069           1 :                     ComfortControlledZone(ComfortControlledZoneNum).Name = cAlphaArgs(1);
    1070             :                 } else {
    1071           0 :                     ComfortControlledZone(ComfortControlledZoneNum).Name =
    1072           0 :                         state.dataHeatBal->Zone(ZoneList(ComfortTStatObjects(Item).ZoneOrZoneListPtr).Zone(Item1)).Name + ' ' +
    1073           0 :                         ComfortTStatObjects(Item).Name;
    1074             :                 }
    1075             : 
    1076             :                 // Read Fields A3 and A4 for averaging method
    1077           1 :                 IZoneCount = 0;
    1078           4 :                 for (i = 1; i <= state.dataHeatBal->TotPeople; ++i) {
    1079           3 :                     if (ComfortControlledZone(ComfortControlledZoneNum).ActualZoneNum == state.dataHeatBal->People(i).ZonePtr) {
    1080           1 :                         ++IZoneCount;
    1081             :                     }
    1082             :                 }
    1083             :                 // Could not find a people object for this particular zone
    1084           1 :                 if (IZoneCount == 0 && ComfortControlledZone(ComfortControlledZoneNum).ActualZoneNum > 0) {
    1085           0 :                     ShowSevereError(state,
    1086           0 :                                     format("{}=\"{} no PEOPLE in {}=\"{}\" - cannot use Comfort Control.",
    1087             :                                            cCurrentModuleObject,
    1088             :                                            cAlphaArgs(1),
    1089             :                                            cAlphaFieldNames(2),
    1090             :                                            cAlphaArgs(2)));
    1091           0 :                     ErrorsFound = true;
    1092             :                 }
    1093           1 :                 ComfortControlledZone(ComfortControlledZoneNum).AverageMethod = DataZoneControls::AverageMethod::NO;
    1094           1 :                 if (IZoneCount > 1) {
    1095           0 :                     ComfortControlledZone(ComfortControlledZoneNum).AverageMethodName = cAlphaArgs(3);
    1096           0 :                     if (Util::SameString(cAlphaArgs(3), "SpecificObject")) {
    1097           0 :                         ComfortControlledZone(ComfortControlledZoneNum).AverageMethod = DataZoneControls::AverageMethod::SPE;
    1098             :                     }
    1099           0 :                     if (Util::SameString(cAlphaArgs(3), "ObjectAverage")) {
    1100           0 :                         ComfortControlledZone(ComfortControlledZoneNum).AverageMethod = DataZoneControls::AverageMethod::OBJ;
    1101             :                     }
    1102           0 :                     if (Util::SameString(cAlphaArgs(3), "PeopleAverage")) {
    1103           0 :                         ComfortControlledZone(ComfortControlledZoneNum).AverageMethod = DataZoneControls::AverageMethod::PEO;
    1104             :                     }
    1105           0 :                     if (ComfortControlledZone(ComfortControlledZoneNum).AverageMethod == DataZoneControls::AverageMethod::NO) {
    1106           0 :                         ShowSevereError(
    1107           0 :                             state, format("{}=\"{} invalid {}=\"{}\".", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(3), cAlphaArgs(3)));
    1108           0 :                         ShowContinueError(state, "Allowed keys are SpecificObject, ObjectAverage, or PeopleAverage");
    1109           0 :                         ErrorsFound = true;
    1110             :                     }
    1111           0 :                     if (ComfortControlledZone(ComfortControlledZoneNum).AverageMethod == DataZoneControls::AverageMethod::SPE) {
    1112           0 :                         ComfortControlledZone(ComfortControlledZoneNum).AverageObjectName = cAlphaArgs(4);
    1113           0 :                         if (Util::FindItem(cAlphaArgs(4), state.dataHeatBal->People) == 0) {
    1114           0 :                             ShowSevereError(
    1115           0 :                                 state, format("{}=\"{} invalid {}=\"{}\".", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4)));
    1116           0 :                             ErrorsFound = true;
    1117             :                         } else {
    1118           0 :                             ComfortControlledZone(ComfortControlledZoneNum).SpecificObjectNum =
    1119           0 :                                 Util::FindItem(cAlphaArgs(4), state.dataHeatBal->People);
    1120             :                         }
    1121             :                     }
    1122             :                 } else {
    1123           2 :                     for (i = 1; i <= state.dataHeatBal->TotPeople; ++i) {
    1124           2 :                         if (ComfortControlledZone(ComfortControlledZoneNum).ActualZoneNum == state.dataHeatBal->People(i).ZonePtr) break;
    1125             :                     }
    1126           1 :                     ComfortControlledZone(ComfortControlledZoneNum).SpecificObjectNum = i;
    1127             :                 }
    1128             :                 // Check values used for thermal comfort calculation
    1129           4 :                 for (i = 1; i <= state.dataHeatBal->TotPeople; ++i) {
    1130           3 :                     if (ComfortControlledZone(ComfortControlledZoneNum).ActualZoneNum == state.dataHeatBal->People(i).ZonePtr) {
    1131             :                         // Check activity level
    1132           1 :                         if (state.dataHeatBal->People(i).ActivityLevelPtr > 0) {
    1133             :                             ValidScheduleControlType =
    1134           1 :                                 CheckScheduleValueMinMax(state, state.dataHeatBal->People(i).ActivityLevelPtr, ">=", 72.0, "<=", 909.0);
    1135           1 :                             if (!ValidScheduleControlType) {
    1136           0 :                                 ShowSevereError(state,
    1137             :                                                 "GetPeople Activity Level: Invalid activity level values entered for thermal comfort calculation");
    1138           0 :                                 ShowContinueError(state,
    1139           0 :                                                   format("Outside of range values [72,909], Reference object={}", state.dataHeatBal->People(i).Name));
    1140           0 :                                 ErrorsFound = true;
    1141             :                             }
    1142             :                         } else {
    1143           0 :                             ShowSevereError(
    1144             :                                 state,
    1145           0 :                                 format("GetPeople Activity Level: Activity level schedule is not found={}", state.dataHeatBal->People(i).Name));
    1146           0 :                             ShowContinueError(state, "Required when the zone has Thermal Comfort Controls.");
    1147           0 :                             ErrorsFound = true;
    1148             :                         }
    1149             :                         // Check Work Efficiency
    1150           1 :                         if (state.dataHeatBal->People(i).WorkEffPtr > 0) {
    1151           1 :                             ValidScheduleControlType = CheckScheduleValueMinMax(state, state.dataHeatBal->People(i).WorkEffPtr, ">=", 0.0, "<=", 1.0);
    1152           1 :                             if (!ValidScheduleControlType) {
    1153           0 :                                 ShowSevereError(state,
    1154             :                                                 "GetPeople work efficiency: Invalid work efficiency values entered for thermal comfort calculation");
    1155           0 :                                 ShowContinueError(state,
    1156           0 :                                                   format("Outside of range values [0,1], Reference object={}", state.dataHeatBal->People(i).Name));
    1157           0 :                                 ErrorsFound = true;
    1158             :                             }
    1159             :                         } else {
    1160           0 :                             ShowSevereError(
    1161             :                                 state,
    1162           0 :                                 format("GetPeople work efficiency: Work efficiency schedule is not found={}", state.dataHeatBal->People(i).Name));
    1163           0 :                             ShowContinueError(state, "Required when the zone has Thermal Comfort Controls.");
    1164           0 :                             ErrorsFound = true;
    1165             :                         }
    1166             :                         // Check Clothing Insulation
    1167           1 :                         if (state.dataHeatBal->People(i).ClothingPtr > 0) {
    1168           1 :                             ValidScheduleControlType = CheckScheduleValueMinMax(state, state.dataHeatBal->People(i).ClothingPtr, ">", 0.0, "<=", 2.0);
    1169           1 :                             if (!ValidScheduleControlType) {
    1170           0 :                                 ShowSevereError(
    1171             :                                     state,
    1172             :                                     "GetPeople Clothing Insulation: Invalid Clothing Insulation values entered for thermal comfort calculation");
    1173           0 :                                 ShowContinueError(
    1174           0 :                                     state, format("Outside of range values [0.0,2.0], Reference object={}", state.dataHeatBal->People(i).Name));
    1175           0 :                                 ErrorsFound = true;
    1176             :                             }
    1177             :                         } else {
    1178           0 :                             ShowSevereError(state,
    1179           0 :                                             format("GetPeople Clothing Insulation: Clothing Insulation schedule is not found={}",
    1180           0 :                                                    state.dataHeatBal->People(i).Name));
    1181           0 :                             ShowContinueError(state, "Required when the zone has Thermal Comfort Controls.");
    1182           0 :                             ErrorsFound = true;
    1183             :                         }
    1184             :                         // Check Air velocity
    1185           1 :                         if (state.dataHeatBal->People(i).AirVelocityPtr <= 0) {
    1186           0 :                             ShowSevereError(
    1187           0 :                                 state, format("GetPeople Air Velocity: Air velocity schedule is not found={}", state.dataHeatBal->People(i).Name));
    1188           0 :                             ShowContinueError(state, "Required when the zone has Thermal Comfort Controls.");
    1189           0 :                             ErrorsFound = true;
    1190             :                         }
    1191             :                     }
    1192             :                 }
    1193             : 
    1194             :                 // Read Max and Min temperature setpoint
    1195           1 :                 if (NumNums > 0) {
    1196           1 :                     ComfortControlledZone(ComfortControlledZoneNum).TdbMinSetPoint = rNumericArgs(1);
    1197           1 :                     if (rNumericArgs(1) > 50 || rNumericArgs(1) < 0) {
    1198           0 :                         ShowSevereError(
    1199             :                             state,
    1200           0 :                             format("{}=\"{} invalid {}=[{:.0T}].", cCurrentModuleObject, cAlphaArgs(1), cNumericFieldNames(1), rNumericArgs(1)));
    1201           0 :                         ShowContinueError(state, "..Allowable values must be between 0 C and 50 C");
    1202           0 :                         ErrorsFound = true;
    1203             :                     }
    1204             :                 }
    1205           1 :                 if (NumNums > 1) {
    1206           1 :                     ComfortControlledZone(ComfortControlledZoneNum).TdbMaxSetPoint = rNumericArgs(2);
    1207           1 :                     if (rNumericArgs(2) > 50 || rNumericArgs(2) < 0) {
    1208           0 :                         ShowSevereError(
    1209             :                             state,
    1210           0 :                             format("{}=\"{} invalid {}=[{:.0T}].", cCurrentModuleObject, cAlphaArgs(1), cNumericFieldNames(2), rNumericArgs(2)));
    1211           0 :                         ShowContinueError(state, "..Allowable values must be between 0 C and 50 C");
    1212           0 :                         ErrorsFound = true;
    1213             :                     }
    1214             :                 }
    1215             :                 // Ensure MaxTemp >= MinTemp
    1216           1 :                 if (ComfortControlledZone(ComfortControlledZoneNum).TdbMinSetPoint > ComfortControlledZone(ComfortControlledZoneNum).TdbMaxSetPoint) {
    1217           0 :                     ShowSevereError(state, format("{}=\"{}", cCurrentModuleObject, cAlphaArgs(1)));
    1218           0 :                     ShowContinueError(state, format("..{} > {}", cNumericFieldNames(1), cNumericFieldNames(2)));
    1219           0 :                     ShowContinueError(state, format("..[{:.0T}] > [{:.0T}].", rNumericArgs(1), rNumericArgs(2)));
    1220           0 :                     ErrorsFound = true;
    1221             :                 }
    1222             :                 // If MaxTemp = MinTemp, no thermal comfort control
    1223           1 :                 if (ComfortControlledZone(ComfortControlledZoneNum).TdbMinSetPoint ==
    1224           1 :                     ComfortControlledZone(ComfortControlledZoneNum).TdbMaxSetPoint) {
    1225           0 :                     ShowSevereError(state, format("{}=\"{}", cCurrentModuleObject, cAlphaArgs(1)));
    1226           0 :                     ShowContinueError(state, format("..{} = {}", cNumericFieldNames(1), cNumericFieldNames(2)));
    1227           0 :                     ShowContinueError(state, "The zone will be controlled using this dry-bulb temperature setpoint.");
    1228             :                 }
    1229             :                 // read Thermal comfort type schedule name
    1230           1 :                 ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchedName = cAlphaArgs(5);
    1231           1 :                 ComfortControlledZone(ComfortControlledZoneNum).ComfortSchedIndex = GetScheduleIndex(state, cAlphaArgs(5));
    1232           1 :                 if (ComfortControlledZone(ComfortControlledZoneNum).ComfortSchedIndex == 0) {
    1233           0 :                     ShowSevereError(
    1234             :                         state,
    1235           0 :                         format("{}=\"{} invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5)));
    1236           0 :                     ErrorsFound = true;
    1237             :                 } else {
    1238             :                     // Check validity of control types.
    1239             :                     ValidScheduleControlType =
    1240           1 :                         CheckScheduleValueMinMax(state, ComfortControlledZone(ComfortControlledZoneNum).ComfortSchedIndex, ">=", 0.0, "<=", 4.0);
    1241           1 :                     if (!ValidScheduleControlType) {
    1242           0 :                         ShowSevereError(
    1243             :                             state,
    1244           0 :                             format("{}=\"{}\" invalid range {}=\"{}\"", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5)));
    1245           0 :                         ShowContinueError(state, "..contains values outside of range [0,4].");
    1246           0 :                         ErrorsFound = true;
    1247             :                     }
    1248             :                 }
    1249           1 :                 ComfortControlledZone(ComfortControlledZoneNum).NumControlTypes = nint((NumAlphas - 5.0) / 2.0);
    1250           1 :                 ComfortControlledZone(ComfortControlledZoneNum).ControlType.allocate(ComfortControlledZone(ComfortControlledZoneNum).NumControlTypes);
    1251           1 :                 ComfortControlledZone(ComfortControlledZoneNum)
    1252           1 :                     .ControlTypeName.allocate(ComfortControlledZone(ComfortControlledZoneNum).NumControlTypes);
    1253           1 :                 ComfortControlledZone(ComfortControlledZoneNum)
    1254           1 :                     .ControlTypeSchIndx.allocate(ComfortControlledZone(ComfortControlledZoneNum).NumControlTypes);
    1255             : 
    1256           5 :                 for (ControlTypeNum = 1; ControlTypeNum <= ComfortControlledZone(ComfortControlledZoneNum).NumControlTypes; ++ControlTypeNum) {
    1257           4 :                     ComfortControlledZone(ComfortControlledZoneNum).ControlType(ControlTypeNum) = cAlphaArgs(nint(2.0 * ControlTypeNum - 1 + 5));
    1258           4 :                     ComfortControlledZone(ComfortControlledZoneNum).ControlTypeName(ControlTypeNum) = cAlphaArgs(nint(2.0 * ControlTypeNum + 5));
    1259           4 :                     if (ComfortControlledZone(ComfortControlledZoneNum).ControlType(ControlTypeNum) != "") {
    1260           4 :                         CTIndex = getEnumValue(ValidComfortControlTypesUC,
    1261           8 :                                                Util::makeUPPER(ComfortControlledZone(ComfortControlledZoneNum).ControlType(ControlTypeNum)));
    1262           4 :                         if (CTIndex == 0) {
    1263           0 :                             ShowSevereError(state,
    1264           0 :                                             format("{}=\"{}\" invalid {}=\"{}\"",
    1265             :                                                    cCurrentModuleObject,
    1266             :                                                    cAlphaArgs(1),
    1267           0 :                                                    cAlphaFieldNames(nint(2.0 * ControlTypeNum - 1 + 5)),
    1268           0 :                                                    cAlphaArgs(nint(2.0 * ControlTypeNum - 1 + 5))));
    1269           0 :                             ErrorsFound = true;
    1270             :                         }
    1271           4 :                         if (CTIndex > 4) { // For Fanger control only for the time being
    1272           0 :                             ShowSevereError(state,
    1273           0 :                                             format("{}=\"{}\" invalid {}=\"{}\"",
    1274             :                                                    cCurrentModuleObject,
    1275             :                                                    cAlphaArgs(1),
    1276           0 :                                                    cAlphaFieldNames(nint(2.0 * ControlTypeNum - 1 + 5)),
    1277           0 :                                                    cAlphaArgs(nint(2.0 * ControlTypeNum - 1 + 5))));
    1278           0 :                             ShowContinueError(state, "..Fanger is the only valid model.");
    1279           0 :                             ErrorsFound = true;
    1280             :                         }
    1281             :                     } else {
    1282           0 :                         ShowSevereError(state,
    1283           0 :                                         format("{}=\"{}\" invalid {}=\"<blank>\"",
    1284             :                                                cCurrentModuleObject,
    1285             :                                                cAlphaArgs(1),
    1286           0 :                                                cAlphaFieldNames(nint(2.0 * ControlTypeNum - 1 + 5))));
    1287           0 :                         ErrorsFound = true;
    1288             :                     }
    1289           4 :                     ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchIndx(ControlTypeNum) = 0;
    1290             :                 }
    1291             :             }
    1292             :         } // NumComfortTStatStatements
    1293             :     }
    1294             :     // End of Thermal comfort control reading and checking
    1295             : 
    1296         796 :     cCurrentModuleObject = ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeating)];
    1297         796 :     state.dataZoneTempPredictorCorrector->NumSingleFangerHeatingControls = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1298             : 
    1299         796 :     if (state.dataZoneTempPredictorCorrector->NumSingleFangerHeatingControls > 0)
    1300           1 :         state.dataZoneTempPredictorCorrector->SetPointSingleHeatingFanger.allocate(
    1301           1 :             state.dataZoneTempPredictorCorrector->NumSingleFangerHeatingControls);
    1302             : 
    1303         797 :     for (int idx = 1; idx <= state.dataZoneTempPredictorCorrector->NumSingleFangerHeatingControls; ++idx) {
    1304           1 :         inputProcessor->getObjectItem(state,
    1305             :                                       cCurrentModuleObject,
    1306             :                                       idx,
    1307             :                                       cAlphaArgs,
    1308             :                                       NumAlphas,
    1309             :                                       rNumericArgs,
    1310             :                                       NumNums,
    1311             :                                       IOStat,
    1312             :                                       lNumericFieldBlanks,
    1313             :                                       lAlphaFieldBlanks,
    1314             :                                       cAlphaFieldNames,
    1315             :                                       cNumericFieldNames);
    1316           1 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
    1317           1 :         auto &singleSetpointHtgFanger = state.dataZoneTempPredictorCorrector->SetPointSingleHeatingFanger(idx);
    1318           1 :         singleSetpointHtgFanger.Name = cAlphaArgs(1);
    1319           1 :         singleSetpointHtgFanger.PMVSchedName = cAlphaArgs(2);
    1320           1 :         singleSetpointHtgFanger.PMVSchedIndex = GetScheduleIndex(state, cAlphaArgs(2));
    1321           1 :         if (singleSetpointHtgFanger.PMVSchedIndex == 0) {
    1322           0 :             ShowSevereError(
    1323           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1324           0 :             ErrorsFound = true;
    1325             :         } else {
    1326           1 :             ValidScheduleControlType = CheckScheduleValueMinMax(state, singleSetpointHtgFanger.PMVSchedIndex, ">=", -3.0, "<=", 3.0);
    1327           1 :             if (!ValidScheduleControlType) {
    1328           0 :                 ShowSevereError(
    1329             :                     state,
    1330           0 :                     format(
    1331             :                         "{}=\"{}\" invalid PMV values {}=\"{}\" entered.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1332           0 :                 ShowContinueError(state, "..Values outside of range [-3,+3].");
    1333           0 :                 ErrorsFound = true;
    1334             :             }
    1335             :         }
    1336             :     } // SingleFangerHeatingControlNum
    1337             : 
    1338         796 :     cCurrentModuleObject = ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleCooling)];
    1339         796 :     state.dataZoneTempPredictorCorrector->NumSingleFangerCoolingControls = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1340             : 
    1341         796 :     if (state.dataZoneTempPredictorCorrector->NumSingleFangerCoolingControls > 0) {
    1342           1 :         state.dataZoneTempPredictorCorrector->SetPointSingleCoolingFanger.allocate(
    1343           1 :             state.dataZoneTempPredictorCorrector->NumSingleFangerCoolingControls);
    1344             :     }
    1345             : 
    1346         797 :     for (int idx = 1; idx <= state.dataZoneTempPredictorCorrector->NumSingleFangerCoolingControls; ++idx) {
    1347           1 :         inputProcessor->getObjectItem(state,
    1348             :                                       cCurrentModuleObject,
    1349             :                                       idx,
    1350             :                                       cAlphaArgs,
    1351             :                                       NumAlphas,
    1352             :                                       rNumericArgs,
    1353             :                                       NumNums,
    1354             :                                       IOStat,
    1355             :                                       lNumericFieldBlanks,
    1356             :                                       lAlphaFieldBlanks,
    1357             :                                       cAlphaFieldNames,
    1358             :                                       cNumericFieldNames);
    1359           1 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
    1360           1 :         auto &singleSetpointClgFanger = state.dataZoneTempPredictorCorrector->SetPointSingleCoolingFanger(idx);
    1361           1 :         singleSetpointClgFanger.Name = cAlphaArgs(1);
    1362           1 :         singleSetpointClgFanger.PMVSchedName = cAlphaArgs(2);
    1363           1 :         singleSetpointClgFanger.PMVSchedIndex = GetScheduleIndex(state, cAlphaArgs(2));
    1364           1 :         if (singleSetpointClgFanger.PMVSchedIndex == 0) {
    1365           0 :             ShowSevereError(
    1366           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1367           0 :             ErrorsFound = true;
    1368             :         } else {
    1369           1 :             ValidScheduleControlType = CheckScheduleValueMinMax(state, singleSetpointClgFanger.PMVSchedIndex, ">=", -3.0, "<=", 3.0);
    1370           1 :             if (!ValidScheduleControlType) {
    1371           0 :                 ShowSevereError(
    1372             :                     state,
    1373           0 :                     format(
    1374             :                         "{}=\"{}\" invalid PMV values {}=\"{}\" entered.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1375           0 :                 ShowContinueError(state, "..Values outside of range [-3,+3].");
    1376           0 :                 ErrorsFound = true;
    1377             :             }
    1378             :         }
    1379             : 
    1380             :     } // SingleFangerCoolingControlNum
    1381             : 
    1382         796 :     cCurrentModuleObject = ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeatCool)];
    1383         796 :     state.dataZoneTempPredictorCorrector->NumSingleFangerHeatCoolControls = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1384             : 
    1385         796 :     if (state.dataZoneTempPredictorCorrector->NumSingleFangerHeatCoolControls > 0)
    1386           1 :         state.dataZoneTempPredictorCorrector->SetPointSingleHeatCoolFanger.allocate(
    1387           1 :             state.dataZoneTempPredictorCorrector->NumSingleFangerHeatCoolControls);
    1388             : 
    1389         797 :     for (int idx = 1; idx <= state.dataZoneTempPredictorCorrector->NumSingleFangerHeatCoolControls; ++idx) {
    1390           1 :         inputProcessor->getObjectItem(state,
    1391             :                                       cCurrentModuleObject,
    1392             :                                       idx,
    1393             :                                       cAlphaArgs,
    1394             :                                       NumAlphas,
    1395             :                                       rNumericArgs,
    1396             :                                       NumNums,
    1397             :                                       IOStat,
    1398             :                                       lNumericFieldBlanks,
    1399             :                                       lAlphaFieldBlanks,
    1400             :                                       cAlphaFieldNames,
    1401             :                                       cNumericFieldNames);
    1402           1 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
    1403           1 :         auto &singleSetpointHeatCoolFanger = state.dataZoneTempPredictorCorrector->SetPointSingleHeatCoolFanger(idx);
    1404           1 :         singleSetpointHeatCoolFanger.Name = cAlphaArgs(1);
    1405           1 :         singleSetpointHeatCoolFanger.PMVSchedName = cAlphaArgs(2);
    1406           1 :         singleSetpointHeatCoolFanger.PMVSchedIndex = GetScheduleIndex(state, cAlphaArgs(2));
    1407           1 :         if (singleSetpointHeatCoolFanger.PMVSchedIndex == 0) {
    1408           0 :             ShowSevereError(
    1409           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1410           0 :             ErrorsFound = true;
    1411             :         } else {
    1412           1 :             ValidScheduleControlType = CheckScheduleValueMinMax(state, singleSetpointHeatCoolFanger.PMVSchedIndex, ">=", -3.0, "<=", 3.0);
    1413           1 :             if (!ValidScheduleControlType) {
    1414           0 :                 ShowSevereError(
    1415             :                     state,
    1416           0 :                     format(
    1417             :                         "{}=\"{}\" invalid PMV values {}=\"{}\" entered.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1418           0 :                 ShowContinueError(state, "..Values outside of range [-3,+3].");
    1419           0 :                 ErrorsFound = true;
    1420             :             }
    1421             :         }
    1422             : 
    1423             :     } // SingleFangerHeatCoolControlNum
    1424             : 
    1425         796 :     cCurrentModuleObject = ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand)];
    1426         796 :     state.dataZoneTempPredictorCorrector->NumDualFangerHeatCoolControls = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1427             : 
    1428         796 :     if (state.dataZoneTempPredictorCorrector->NumDualFangerHeatCoolControls > 0)
    1429           1 :         state.dataZoneTempPredictorCorrector->SetPointDualHeatCoolFanger.allocate(
    1430           1 :             state.dataZoneTempPredictorCorrector->NumDualFangerHeatCoolControls);
    1431             : 
    1432         797 :     for (int idx = 1; idx <= state.dataZoneTempPredictorCorrector->NumDualFangerHeatCoolControls; ++idx) {
    1433           1 :         inputProcessor->getObjectItem(state,
    1434             :                                       cCurrentModuleObject,
    1435             :                                       idx,
    1436             :                                       cAlphaArgs,
    1437             :                                       NumAlphas,
    1438             :                                       rNumericArgs,
    1439             :                                       NumNums,
    1440             :                                       IOStat,
    1441             :                                       lNumericFieldBlanks,
    1442             :                                       lAlphaFieldBlanks,
    1443             :                                       cAlphaFieldNames,
    1444             :                                       cNumericFieldNames);
    1445           1 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
    1446           1 :         auto &dualSetpointHeatCoolFanger = state.dataZoneTempPredictorCorrector->SetPointDualHeatCoolFanger(idx);
    1447           1 :         dualSetpointHeatCoolFanger.Name = cAlphaArgs(1);
    1448           1 :         dualSetpointHeatCoolFanger.HeatPMVSetptSchedName = cAlphaArgs(2);
    1449           1 :         dualSetpointHeatCoolFanger.HeatPMVSchedIndex = GetScheduleIndex(state, cAlphaArgs(2));
    1450           1 :         if (dualSetpointHeatCoolFanger.HeatPMVSchedIndex == 0) {
    1451           0 :             ShowSevereError(
    1452           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1453           0 :             ErrorsFound = true;
    1454             :         }
    1455           1 :         dualSetpointHeatCoolFanger.CoolPMVSetptSchedName = cAlphaArgs(3);
    1456           1 :         dualSetpointHeatCoolFanger.CoolPMVSchedIndex = GetScheduleIndex(state, cAlphaArgs(3));
    1457           1 :         if (dualSetpointHeatCoolFanger.CoolPMVSchedIndex == 0) {
    1458           0 :             ShowSevereError(
    1459           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(3), cAlphaArgs(3)));
    1460           0 :             ErrorsFound = true;
    1461             :         } else {
    1462           1 :             ValidScheduleControlType = CheckScheduleValueMinMax(state, dualSetpointHeatCoolFanger.HeatPMVSchedIndex, ">=", -3.0, "<=", 3.0);
    1463           1 :             if (!ValidScheduleControlType) {
    1464           0 :                 ShowSevereError(
    1465             :                     state,
    1466           0 :                     format(
    1467             :                         "{}=\"{}\" invalid PMV values {}=\"{}\" entered.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1468           0 :                 ShowContinueError(state, "..Values outside of range [-3,+3].");
    1469           0 :                 ErrorsFound = true;
    1470             :             }
    1471           1 :             ValidScheduleControlType = CheckScheduleValueMinMax(state, dualSetpointHeatCoolFanger.CoolPMVSchedIndex, ">=", -3.0, "<=", 3.0);
    1472           1 :             if (!ValidScheduleControlType) {
    1473           0 :                 ShowSevereError(
    1474             :                     state,
    1475           0 :                     format(
    1476             :                         "{}=\"{}\" invalid PMV values {}=\"{}\" entered.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(3), cAlphaArgs(3)));
    1477           0 :                 ShowContinueError(state, "..Values outside of range [-3,+3].");
    1478           0 :                 ErrorsFound = true;
    1479             :             }
    1480             :         }
    1481             : 
    1482             :     } // DualFangerHeatCoolControlNum
    1483             : 
    1484             :     // Finish filling in Schedule pointing indexes for Thermal Comfort Control
    1485         797 :     for (ComfortControlledZoneNum = 1; ComfortControlledZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++ComfortControlledZoneNum) {
    1486             : 
    1487           1 :         int ComfortIndex = Util::FindItem(ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeating)],
    1488           1 :                                           ComfortControlledZone(ComfortControlledZoneNum).ControlType,
    1489           1 :                                           ComfortControlledZone(ComfortControlledZoneNum).NumControlTypes);
    1490           1 :         ComfortControlledZone(ComfortControlledZoneNum).SchIndx_SingleHeating = ComfortIndex;
    1491           1 :         if (ComfortIndex > 0) {
    1492           1 :             ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchIndx(ComfortIndex) =
    1493           1 :                 Util::FindItem(ComfortControlledZone(ComfortControlledZoneNum).ControlTypeName(ComfortIndex),
    1494           1 :                                state.dataZoneTempPredictorCorrector->SetPointSingleHeatingFanger);
    1495           1 :             TComfortControlTypes(ComfortControlledZoneNum).MustHave[static_cast<int>(HVAC::ThermostatType::SingleHeating)] = true;
    1496             :         }
    1497             : 
    1498           1 :         ComfortIndex = Util::FindItem(ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleCooling)],
    1499           1 :                                       ComfortControlledZone(ComfortControlledZoneNum).ControlType,
    1500           1 :                                       ComfortControlledZone(ComfortControlledZoneNum).NumControlTypes);
    1501           1 :         ComfortControlledZone(ComfortControlledZoneNum).SchIndx_SingleCooling = ComfortIndex;
    1502           1 :         if (ComfortIndex > 0) {
    1503           1 :             ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchIndx(ComfortIndex) =
    1504           1 :                 Util::FindItem(ComfortControlledZone(ComfortControlledZoneNum).ControlTypeName(ComfortIndex),
    1505           1 :                                state.dataZoneTempPredictorCorrector->SetPointSingleCoolingFanger);
    1506           1 :             TComfortControlTypes(ComfortControlledZoneNum).MustHave[static_cast<int>(HVAC::ThermostatType::SingleCooling)] = true;
    1507             :         }
    1508             : 
    1509           1 :         ComfortIndex = Util::FindItem(ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeatCool)],
    1510           1 :                                       ComfortControlledZone(ComfortControlledZoneNum).ControlType,
    1511           1 :                                       ComfortControlledZone(ComfortControlledZoneNum).NumControlTypes);
    1512           1 :         ComfortControlledZone(ComfortControlledZoneNum).SchIndx_SingleHeatCool = ComfortIndex;
    1513           1 :         if (ComfortIndex > 0) {
    1514           1 :             ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchIndx(ComfortIndex) =
    1515           1 :                 Util::FindItem(ComfortControlledZone(ComfortControlledZoneNum).ControlTypeName(ComfortIndex),
    1516           1 :                                state.dataZoneTempPredictorCorrector->SetPointSingleHeatCoolFanger);
    1517           1 :             TComfortControlTypes(ComfortControlledZoneNum).MustHave[static_cast<int>(HVAC::ThermostatType::SingleHeatCool)] = true;
    1518             :         }
    1519             : 
    1520           1 :         ComfortIndex = Util::FindItem(ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand)],
    1521           1 :                                       ComfortControlledZone(ComfortControlledZoneNum).ControlType,
    1522           1 :                                       ComfortControlledZone(ComfortControlledZoneNum).NumControlTypes);
    1523           1 :         ComfortControlledZone(ComfortControlledZoneNum).SchIndx_DualSetPointWithDeadBand = ComfortIndex;
    1524           1 :         if (ComfortIndex > 0) {
    1525           1 :             ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchIndx(ComfortIndex) =
    1526           1 :                 Util::FindItem(ComfortControlledZone(ComfortControlledZoneNum).ControlTypeName(ComfortIndex),
    1527           1 :                                state.dataZoneTempPredictorCorrector->SetPointDualHeatCoolFanger);
    1528           1 :             TComfortControlTypes(ComfortControlledZoneNum).MustHave[static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand)] = true;
    1529             :         }
    1530             :     }
    1531             : 
    1532             :     // Now, Check the schedule values/indices for validity for Thermal Comfort Control
    1533             : 
    1534         797 :     for (ComfortControlledZoneNum = 1; ComfortControlledZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++ComfortControlledZoneNum) {
    1535             : 
    1536           1 :         ActualZoneNum = ComfortControlledZone(ComfortControlledZoneNum).ActualZoneNum;
    1537           1 :         CTIndex = ComfortControlledZone(ComfortControlledZoneNum).ComfortSchedIndex;
    1538           1 :         if (CTIndex == 0) continue; // error will be caught elsewhere
    1539           1 :         SchedMin = GetScheduleMinValue(state, CTIndex);
    1540           1 :         SchedMax = GetScheduleMaxValue(state, CTIndex);
    1541             : 
    1542           1 :         if (SchedMin == 0 && SchedMax == 0) {
    1543           0 :             if (FindNumberInList(CTIndex, CCmSchedMapToControlledZone, state.dataZoneCtrls->NumComfortControlledZones) == 0) {
    1544           0 :                 ShowWarningError(state, format("Control Type Schedule={}", ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchedName));
    1545           0 :                 ShowContinueError(state, "..specifies control type 0 for all entries.");
    1546           0 :                 ShowContinueError(state, "All zones using this Control Type Schedule have no thermal comfort control.");
    1547             :             }
    1548           0 :             CCmSchedMapToControlledZone(ComfortControlledZoneNum) = CTIndex;
    1549             :         }
    1550             : 
    1551           6 :         for (ControlTypeNum = SchedMin; ControlTypeNum <= SchedMax; ++ControlTypeNum) {
    1552             : 
    1553             :             int ComfortIndex;
    1554           5 :             switch (static_cast<HVAC::ThermostatType>(ControlTypeNum)) {
    1555           1 :             case HVAC::ThermostatType::Uncontrolled:
    1556           1 :                 break;
    1557           1 :             case HVAC::ThermostatType::SingleHeating:
    1558           1 :                 ComfortIndex = ComfortControlledZone(ComfortControlledZoneNum).SchIndx_SingleHeating;
    1559           1 :                 TComfortControlTypes(ComfortControlledZoneNum).DidHave[static_cast<int>(HVAC::ThermostatType::SingleHeating)] = true;
    1560           1 :                 if (ComfortIndex != 0) {
    1561           1 :                     SchedTypeIndex = ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchIndx(ComfortIndex);
    1562           1 :                     if (SchedTypeIndex == 0) {
    1563           0 :                         ShowSevereError(state,
    1564           0 :                                         format("GetZoneAirSetpoints: Could not find {} Schedule={}",
    1565           0 :                                                ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeating)],
    1566           0 :                                                ComfortControlledZone(ComfortControlledZoneNum).ControlTypeName(ComfortIndex)));
    1567           0 :                         ErrorsFound = true;
    1568             :                     }
    1569             :                 } else { // ComfortIndex = 0
    1570           0 :                     if (CheckScheduleValue(state, CTIndex, static_cast<int>(HVAC::ThermostatType::SingleHeating))) {
    1571           0 :                         ShowSevereError(state,
    1572           0 :                                         format("Control Type Schedule={}", ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchedName));
    1573           0 :                         ShowContinueError(state,
    1574           0 :                                           format("..specifies thermal control type 1 ({}) as the control type. Not valid for this zone.",
    1575           0 :                                                  ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeating)]));
    1576           0 :                         ShowContinueError(state,
    1577           0 :                                           format("..reference {}={}",
    1578             :                                                  cZControlTypes(static_cast<int>(ZoneControlTypes::TCTStat)),
    1579           0 :                                                  ComfortControlledZone(ComfortControlledZoneNum).Name));
    1580           0 :                         ShowContinueError(state, format("..reference ZONE={}", ComfortControlledZone(ComfortControlledZoneNum).ZoneName));
    1581           0 :                         ErrorsFound = true;
    1582             :                     }
    1583             :                 }
    1584           1 :                 break;
    1585           1 :             case HVAC::ThermostatType::SingleCooling:
    1586           1 :                 ComfortIndex = ComfortControlledZone(ComfortControlledZoneNum).SchIndx_SingleCooling;
    1587           1 :                 TComfortControlTypes(ComfortControlledZoneNum).DidHave[static_cast<int>(HVAC::ThermostatType::SingleCooling)] = true;
    1588           1 :                 if (ComfortIndex != 0) {
    1589           1 :                     SchedTypeIndex = ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchIndx(ComfortIndex);
    1590           1 :                     if (SchedTypeIndex == 0) {
    1591           0 :                         ShowSevereError(state,
    1592           0 :                                         format("GetZoneAirSetpoints: Could not find {} Schedule={}",
    1593           0 :                                                ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleCooling)],
    1594           0 :                                                ComfortControlledZone(ComfortControlledZoneNum).ControlTypeName(ComfortIndex)));
    1595           0 :                         ErrorsFound = true;
    1596             :                     }
    1597             :                 } else { // ComfortIndex = 0
    1598           0 :                     if (CheckScheduleValue(state, CTIndex, static_cast<int>(HVAC::ThermostatType::SingleCooling))) {
    1599           0 :                         ShowSevereError(state,
    1600           0 :                                         format("Control Type Schedule={}", ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchedName));
    1601           0 :                         ShowContinueError(state,
    1602           0 :                                           format("..specifies thermal control type 2 ({}) as the control type. Not valid for this zone.",
    1603           0 :                                                  ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleCooling)]));
    1604           0 :                         ShowContinueError(state,
    1605           0 :                                           format("..reference {}={}",
    1606             :                                                  cZControlTypes(static_cast<int>(ZoneControlTypes::TCTStat)),
    1607           0 :                                                  ComfortControlledZone(ComfortControlledZoneNum).Name));
    1608           0 :                         ShowContinueError(state, format("..reference ZONE={}", ComfortControlledZone(ComfortControlledZoneNum).ZoneName));
    1609           0 :                         ErrorsFound = true;
    1610             :                     }
    1611             :                 }
    1612           1 :                 break;
    1613           1 :             case HVAC::ThermostatType::SingleHeatCool:
    1614           1 :                 ComfortIndex = ComfortControlledZone(ComfortControlledZoneNum).SchIndx_SingleHeatCool;
    1615           1 :                 TComfortControlTypes(ComfortControlledZoneNum).DidHave[static_cast<int>(HVAC::ThermostatType::SingleHeatCool)] = true;
    1616           1 :                 if (ComfortIndex != 0) {
    1617           1 :                     SchedTypeIndex = ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchIndx(ComfortIndex);
    1618           1 :                     if (SchedTypeIndex == 0) {
    1619           0 :                         ShowSevereError(state,
    1620           0 :                                         format("GetZoneAirSetpoints: Could not find {} Schedule={}",
    1621           0 :                                                ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeatCool)],
    1622           0 :                                                ComfortControlledZone(ComfortControlledZoneNum).ControlTypeName(ComfortIndex)));
    1623           0 :                         ErrorsFound = true;
    1624             :                     }
    1625             :                 } else { // ComfortIndex = 0
    1626           0 :                     if (CheckScheduleValue(state, CTIndex, static_cast<int>(HVAC::ThermostatType::SingleHeatCool))) {
    1627           0 :                         ShowSevereError(state, format("Schedule={}", ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchedName));
    1628           0 :                         ShowContinueError(state,
    1629           0 :                                           format("..specifies thermal control type 3 ({}) as the control type. Not valid for this zone.",
    1630           0 :                                                  ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeatCool)]));
    1631           0 :                         ShowContinueError(state,
    1632           0 :                                           format("..reference {}={}",
    1633             :                                                  cZControlTypes(static_cast<int>(ZoneControlTypes::TCTStat)),
    1634           0 :                                                  ComfortControlledZone(ComfortControlledZoneNum).Name));
    1635           0 :                         ShowContinueError(state, format("..reference ZONE={}", ComfortControlledZone(ComfortControlledZoneNum).ZoneName));
    1636           0 :                         ErrorsFound = true;
    1637             :                     }
    1638             :                 }
    1639           1 :                 break;
    1640           1 :             case HVAC::ThermostatType::DualSetPointWithDeadBand:
    1641           1 :                 ComfortIndex = ComfortControlledZone(ComfortControlledZoneNum).SchIndx_DualSetPointWithDeadBand;
    1642           1 :                 TComfortControlTypes(ComfortControlledZoneNum).DidHave[static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand)] = true;
    1643           1 :                 if (ComfortIndex != 0) {
    1644           1 :                     SchedTypeIndex = ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchIndx(ComfortIndex);
    1645           1 :                     if (SchedTypeIndex == 0) {
    1646           0 :                         ShowSevereError(state,
    1647           0 :                                         format("GetZoneAirSetpoints: Could not find {} Schedule={}",
    1648           0 :                                                ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand)],
    1649           0 :                                                ComfortControlledZone(ComfortControlledZoneNum).ControlTypeName(ComfortIndex)));
    1650           0 :                         ErrorsFound = true;
    1651             :                     }
    1652             :                 } else { // ComfortIndex = 0
    1653           0 :                     if (CheckScheduleValue(state, CTIndex, static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand))) {
    1654           0 :                         ShowSevereError(state, format("Schedule={}", ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchedName));
    1655           0 :                         ShowContinueError(state,
    1656           0 :                                           format("..specifies thermal control type 4 ({}) as the control type. Not valid for this zone.",
    1657           0 :                                                  ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand)]));
    1658           0 :                         ShowContinueError(state,
    1659           0 :                                           format("..reference {}={}",
    1660             :                                                  cZControlTypes(static_cast<int>(ZoneControlTypes::TCTStat)),
    1661           0 :                                                  ComfortControlledZone(ComfortControlledZoneNum).Name));
    1662           0 :                         ShowContinueError(state, format("..reference ZONE={}", ComfortControlledZone(ComfortControlledZoneNum).ZoneName));
    1663           0 :                         ErrorsFound = true;
    1664             :                     }
    1665             :                 }
    1666           1 :                 break;
    1667           0 :             default:
    1668           0 :                 ShowSevereError(state,
    1669           0 :                                 format("GetZoneAirSetpoints: Illegal control type for Zone={}, Found value={}, in Schedule={}",
    1670           0 :                                        Zone(ActualZoneNum).Name,
    1671             :                                        ControlTypeNum,
    1672           0 :                                        ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchedName));
    1673           0 :                 ShowContinueError(state, "..valid range values are [0,4].");
    1674           0 :                 ErrorsFound = true;
    1675           0 :                 break;
    1676             :             }
    1677             :         }
    1678             :     }
    1679             : 
    1680         797 :     for (ComfortControlledZoneNum = 1; ComfortControlledZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++ComfortControlledZoneNum) {
    1681             : 
    1682           1 :         ActualZoneNum = ComfortControlledZone(ComfortControlledZoneNum).ActualZoneNum;
    1683           1 :         CTIndex = ComfortControlledZone(ComfortControlledZoneNum).ComfortSchedIndex;
    1684           1 :         if (CTIndex == 0) continue; // error caught elsewhere -- would just be confusing here
    1685             : 
    1686           5 :         for (ControlTypeNum = 1; ControlTypeNum <= 4; ++ControlTypeNum) {
    1687           8 :             if (TComfortControlTypes(ComfortControlledZoneNum).MustHave[ControlTypeNum] &&
    1688           4 :                 TComfortControlTypes(ComfortControlledZoneNum).DidHave[ControlTypeNum])
    1689           4 :                 continue;
    1690             : 
    1691           0 :             switch (static_cast<HVAC::ThermostatType>(ControlTypeNum)) {
    1692           0 :             case HVAC::ThermostatType::SingleHeating:
    1693           0 :                 if (!TComfortControlTypes(ComfortControlledZoneNum).MustHave[ControlTypeNum]) continue;
    1694           0 :                 ShowWarningError(state, format("Schedule={}", ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchedName));
    1695           0 :                 ShowContinueError(state,
    1696           0 :                                   format("...should include control type 1 ({}) but does not.",
    1697           0 :                                          ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeating)]));
    1698           0 :                 ShowContinueError(state,
    1699           0 :                                   format("..reference {}={}",
    1700             :                                          cZControlTypes(static_cast<int>(ZoneControlTypes::TCTStat)),
    1701           0 :                                          ComfortControlledZone(ComfortControlledZoneNum).Name));
    1702           0 :                 ShowContinueError(state, format("..reference ZONE={}", ComfortControlledZone(ComfortControlledZoneNum).ZoneName));
    1703           0 :                 break;
    1704           0 :             case HVAC::ThermostatType::SingleCooling:
    1705           0 :                 if (!TComfortControlTypes(ComfortControlledZoneNum).MustHave[ControlTypeNum]) continue;
    1706           0 :                 ShowWarningError(state, format("Schedule={}", ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchedName));
    1707           0 :                 ShowContinueError(state,
    1708           0 :                                   format("...should include control type 2 ({}) but does not.",
    1709           0 :                                          ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleCooling)]));
    1710           0 :                 ShowContinueError(state,
    1711           0 :                                   format("..reference {}={}",
    1712             :                                          cZControlTypes(static_cast<int>(ZoneControlTypes::TCTStat)),
    1713           0 :                                          ComfortControlledZone(ComfortControlledZoneNum).Name));
    1714           0 :                 ShowContinueError(state, format("..reference ZONE={}", ComfortControlledZone(ComfortControlledZoneNum).ZoneName));
    1715           0 :                 break;
    1716           0 :             case HVAC::ThermostatType::SingleHeatCool:
    1717           0 :                 if (!TComfortControlTypes(ComfortControlledZoneNum).MustHave[ControlTypeNum]) continue;
    1718           0 :                 ShowWarningError(state, format("Schedule={}", ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchedName));
    1719           0 :                 ShowContinueError(state,
    1720           0 :                                   format("...should include control type 3 ({}) but does not.",
    1721           0 :                                          ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::SingleHeatCool)]));
    1722           0 :                 ShowContinueError(state,
    1723           0 :                                   format("..reference {}={}",
    1724             :                                          cZControlTypes(static_cast<int>(ZoneControlTypes::TCTStat)),
    1725           0 :                                          ComfortControlledZone(ComfortControlledZoneNum).Name));
    1726           0 :                 ShowContinueError(state, format("..reference ZONE={}", ComfortControlledZone(ComfortControlledZoneNum).ZoneName));
    1727           0 :                 break;
    1728           0 :             case HVAC::ThermostatType::DualSetPointWithDeadBand:
    1729           0 :                 if (!TComfortControlTypes(ComfortControlledZoneNum).MustHave[ControlTypeNum]) continue;
    1730           0 :                 ShowWarningError(state, format("Schedule={}", ComfortControlledZone(ComfortControlledZoneNum).ControlTypeSchedName));
    1731           0 :                 ShowContinueError(state,
    1732           0 :                                   format("...should include control type 4 ({}) but does not.",
    1733           0 :                                          ValidComfortControlTypes[static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand)]));
    1734           0 :                 ShowContinueError(state,
    1735           0 :                                   format("..reference {}={}",
    1736             :                                          cZControlTypes(static_cast<int>(ZoneControlTypes::TCTStat)),
    1737           0 :                                          ComfortControlledZone(ComfortControlledZoneNum).Name));
    1738           0 :                 ShowContinueError(state, format("..reference ZONE={}", ComfortControlledZone(ComfortControlledZoneNum).ZoneName));
    1739           0 :                 break;
    1740           0 :             default:
    1741           0 :                 break;
    1742             :             }
    1743             :         }
    1744             :     }
    1745             : 
    1746         796 :     if (allocated(TComfortControlTypes)) TComfortControlTypes.deallocate();
    1747             : 
    1748             :     // Get the Hybrid Model setting inputs
    1749         796 :     HybridModel::GetHybridModelZone(state);
    1750             : 
    1751             :     // Default multiplier values
    1752         796 :     Real64 ZoneVolCapMultpSens = 1.0;
    1753         796 :     Real64 ZoneVolCapMultpMoist = 1.0;
    1754         796 :     Real64 ZoneVolCapMultpCO2 = 1.0;
    1755         796 :     Real64 ZoneVolCapMultpGenContam = 1.0;
    1756             : 
    1757             :     // Get the Zone Air Capacitance Multiplier for use in the Predictor-Corrector Procedure
    1758         796 :     cCurrentModuleObject = "ZoneCapacitanceMultiplier:ResearchSpecial";
    1759         796 :     int NumZoneCapaMultiplier = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject); // Number of ZonesCapacityMultiplier object
    1760         796 :     if (NumZoneCapaMultiplier == 0) {
    1761             :         // Assign default multiplier values to all zones
    1762        5690 :         for (int ZoneNum = 1; ZoneNum <= NumOfZones; ZoneNum++) {
    1763        4930 :             Zone(ZoneNum).ZoneVolCapMultpSens = ZoneVolCapMultpSens;
    1764        4930 :             Zone(ZoneNum).ZoneVolCapMultpMoist = ZoneVolCapMultpMoist;
    1765        4930 :             Zone(ZoneNum).ZoneVolCapMultpCO2 = ZoneVolCapMultpCO2;
    1766        4930 :             Zone(ZoneNum).ZoneVolCapMultpGenContam = ZoneVolCapMultpGenContam;
    1767             :         }
    1768             : 
    1769             :     } else {
    1770             : 
    1771             :         // Allow user to specify ZoneCapacitanceMultiplier:ResearchSpecial at zone level
    1772             :         // Added by S. Lee and R. Zhang in Oct. 2016.
    1773             :         // Assign the user inputted multipliers to specified zones
    1774          81 :         for (int ZoneCapNum = 1; ZoneCapNum <= NumZoneCapaMultiplier; ZoneCapNum++) {
    1775          45 :             inputProcessor->getObjectItem(state,
    1776             :                                           cCurrentModuleObject,
    1777             :                                           ZoneCapNum,
    1778             :                                           cAlphaArgs,
    1779             :                                           NumAlphas,
    1780             :                                           rNumericArgs,
    1781             :                                           NumNums,
    1782             :                                           IOStat,
    1783             :                                           lNumericFieldBlanks,
    1784             :                                           lAlphaFieldBlanks,
    1785             :                                           cAlphaFieldNames,
    1786             :                                           cNumericFieldNames);
    1787             : 
    1788          45 :             if (lAlphaFieldBlanks(2)) {
    1789             :                 // default multiplier values for all the zones not specified (zone or zonelist name field is empty)
    1790          33 :                 ZoneVolCapMultpSens = rNumericArgs(1);
    1791          33 :                 ZoneVolCapMultpMoist = rNumericArgs(2);
    1792          33 :                 ZoneVolCapMultpCO2 = rNumericArgs(3);
    1793          33 :                 ZoneVolCapMultpGenContam = rNumericArgs(4);
    1794             :             } else {
    1795             :                 // multiplier values for the specified zone(s)
    1796          12 :                 int ZoneNum = 0;
    1797          12 :                 ZLItem = 0;
    1798          12 :                 Item1 = Util::FindItemInList(cAlphaArgs(2), Zone);
    1799          12 :                 if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) ZLItem = Util::FindItemInList(cAlphaArgs(2), ZoneList);
    1800          12 :                 if (Item1 > 0) {
    1801          12 :                     ZoneNum = Item1;
    1802          12 :                     Zone(ZoneNum).FlagCustomizedZoneCap = true;
    1803          12 :                     Zone(ZoneNum).ZoneVolCapMultpSens = rNumericArgs(1);
    1804          12 :                     Zone(ZoneNum).ZoneVolCapMultpMoist = rNumericArgs(2);
    1805          12 :                     Zone(ZoneNum).ZoneVolCapMultpCO2 = rNumericArgs(3);
    1806          12 :                     Zone(ZoneNum).ZoneVolCapMultpGenContam = rNumericArgs(4);
    1807           0 :                 } else if (ZLItem > 0) {
    1808           0 :                     for (int ZonePtrNum = 1; ZonePtrNum < ZoneList(ZLItem).NumOfZones; ZonePtrNum++) {
    1809           0 :                         ZoneNum = ZoneList(ZLItem).Zone(ZonePtrNum);
    1810           0 :                         Zone(ZoneNum).FlagCustomizedZoneCap = true;
    1811           0 :                         Zone(ZoneNum).ZoneVolCapMultpSens = rNumericArgs(1);
    1812           0 :                         Zone(ZoneNum).ZoneVolCapMultpMoist = rNumericArgs(2);
    1813           0 :                         Zone(ZoneNum).ZoneVolCapMultpCO2 = rNumericArgs(3);
    1814           0 :                         Zone(ZoneNum).ZoneVolCapMultpGenContam = rNumericArgs(4);
    1815             :                     }
    1816             : 
    1817             :                 } else {
    1818           0 :                     ShowSevereError(
    1819             :                         state,
    1820           0 :                         format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1821           0 :                     ErrorsFound = true;
    1822             :                 }
    1823             :             }
    1824             :         }
    1825             : 
    1826             :         // Assign default multiplier values to all the other zones
    1827         162 :         for (int ZoneNum = 1; ZoneNum <= NumOfZones; ZoneNum++) {
    1828         126 :             if (!Zone(ZoneNum).FlagCustomizedZoneCap) {
    1829         114 :                 Zone(ZoneNum).ZoneVolCapMultpSens = ZoneVolCapMultpSens;
    1830         114 :                 Zone(ZoneNum).ZoneVolCapMultpMoist = ZoneVolCapMultpMoist;
    1831         114 :                 Zone(ZoneNum).ZoneVolCapMultpCO2 = ZoneVolCapMultpCO2;
    1832         114 :                 Zone(ZoneNum).ZoneVolCapMultpGenContam = ZoneVolCapMultpGenContam;
    1833             :             }
    1834             :         }
    1835             : 
    1836             :         // Calculate the average multiplier value from all zones
    1837             :         {
    1838          36 :             Real64 ZoneVolCapMultpSens_temp = 0.0;
    1839          36 :             Real64 ZoneVolCapMultpMoist_temp = 0.0;
    1840          36 :             Real64 ZoneVolCapMultpCO2_temp = 0.0;
    1841          36 :             Real64 ZoneVolCapMultpGenContam_temp = 0.0;
    1842             : 
    1843         162 :             for (int ZoneNum = 1; ZoneNum <= NumOfZones; ZoneNum++) {
    1844         126 :                 ZoneVolCapMultpSens_temp += Zone(ZoneNum).ZoneVolCapMultpSens;
    1845         126 :                 ZoneVolCapMultpMoist_temp += Zone(ZoneNum).ZoneVolCapMultpMoist;
    1846         126 :                 ZoneVolCapMultpCO2_temp += Zone(ZoneNum).ZoneVolCapMultpCO2;
    1847         126 :                 ZoneVolCapMultpGenContam_temp += Zone(ZoneNum).ZoneVolCapMultpGenContam;
    1848             :             }
    1849             : 
    1850          36 :             if (NumOfZones > 0) {
    1851          36 :                 ZoneVolCapMultpSens = ZoneVolCapMultpSens_temp / NumOfZones;
    1852          36 :                 ZoneVolCapMultpMoist = ZoneVolCapMultpMoist_temp / NumOfZones;
    1853          36 :                 ZoneVolCapMultpCO2 = ZoneVolCapMultpCO2_temp / NumOfZones;
    1854          36 :                 ZoneVolCapMultpGenContam = ZoneVolCapMultpGenContam_temp / NumOfZones;
    1855             :             }
    1856             :         }
    1857             :     }
    1858             : 
    1859         796 :     print(state.files.eio, Header);
    1860         796 :     print(state.files.eio, Format_701, ZoneVolCapMultpSens, ZoneVolCapMultpMoist, ZoneVolCapMultpCO2, ZoneVolCapMultpGenContam);
    1861             : 
    1862         796 :     cCurrentModuleObject = cZControlTypes(static_cast<int>(ZoneControlTypes::OTTStat));
    1863         796 :     state.dataZoneCtrls->NumOpTempControlledZones = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1864             : 
    1865         796 :     if (state.dataZoneCtrls->NumOpTempControlledZones > 0) {
    1866           3 :         state.dataZoneCtrls->AnyOpTempControl = true;
    1867             : 
    1868           6 :         for (int idx = 1; idx <= state.dataZoneCtrls->NumOpTempControlledZones; ++idx) {
    1869           3 :             inputProcessor->getObjectItem(state,
    1870             :                                           cCurrentModuleObject,
    1871             :                                           idx,
    1872             :                                           cAlphaArgs,
    1873             :                                           NumAlphas,
    1874             :                                           rNumericArgs,
    1875             :                                           NumNums,
    1876             :                                           IOStat,
    1877             :                                           lNumericFieldBlanks,
    1878             :                                           lAlphaFieldBlanks,
    1879             :                                           cAlphaFieldNames,
    1880             :                                           cNumericFieldNames);
    1881             :             // find matching name of  ZONECONTROL:THERMOSTAT object
    1882           3 :             found = Util::FindItem(cAlphaArgs(1), TStatObjects);
    1883           3 :             if (found == 0) {
    1884             :                 // It might be in the TempControlledZones
    1885           1 :                 found = Util::FindItem(cAlphaArgs(1), TempControlledZone);
    1886           1 :                 if (found == 0) { // throw error
    1887           0 :                     ShowSevereError(state,
    1888           0 :                                     format("{}={} invalid {} reference not found.",
    1889             :                                            cCurrentModuleObject,
    1890             :                                            cAlphaArgs(1),
    1891             :                                            cZControlTypes(static_cast<int>(ZoneControlTypes::TStat))));
    1892           0 :                     ErrorsFound = true;
    1893             :                 } else {
    1894           1 :                     TempControlledZoneNum = found;
    1895           1 :                     TempControlledZone(TempControlledZoneNum).OperativeTempControl = true;
    1896           1 :                     if (Util::SameString(cAlphaArgs(2), "Scheduled")) {
    1897           0 :                         TempControlledZone(TempControlledZoneNum).OpTempCntrlModeScheduled = true;
    1898             :                     }
    1899           1 :                     if ((!(Util::SameString(cAlphaArgs(2), "Scheduled"))) && (!(Util::SameString(cAlphaArgs(2), "Constant")))) {
    1900           0 :                         ShowSevereError(state,
    1901           0 :                                         format("{}={} invalid {}=\"{}\".", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1902           0 :                         ErrorsFound = true;
    1903             :                     }
    1904             : 
    1905           1 :                     TempControlledZone(TempControlledZoneNum).FixedRadiativeFraction = rNumericArgs(1);
    1906           1 :                     TempControlledZone(TempControlledZoneNum).OpTempRadiativeFractionSched = GetScheduleIndex(state, cAlphaArgs(3));
    1907           2 :                     if ((TempControlledZone(TempControlledZoneNum).OpTempRadiativeFractionSched == 0) &&
    1908           1 :                         (TempControlledZone(TempControlledZoneNum).OpTempCntrlModeScheduled)) { // throw error
    1909           0 :                         ShowSevereError(
    1910             :                             state,
    1911           0 :                             format("{}={} invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(3), cAlphaArgs(3)));
    1912           0 :                         ErrorsFound = true;
    1913             :                     }
    1914             : 
    1915             :                     // check validity of fixed radiative fraction
    1916           1 :                     if ((TempControlledZone(TempControlledZoneNum).FixedRadiativeFraction < 0.0) &&
    1917           0 :                         (!(TempControlledZone(TempControlledZoneNum).OpTempCntrlModeScheduled))) {
    1918           0 :                         ShowSevereError(state,
    1919           0 :                                         format("{}={} invalid {}=[{:.2T}\" cannot be negative.",
    1920             :                                                cCurrentModuleObject,
    1921             :                                                cAlphaArgs(1),
    1922             :                                                cNumericFieldNames(1),
    1923             :                                                rNumericArgs(1)));
    1924           0 :                         ErrorsFound = true;
    1925             :                     }
    1926           1 :                     if ((TempControlledZone(TempControlledZoneNum).FixedRadiativeFraction >= 0.9) &&
    1927           0 :                         (!(TempControlledZone(TempControlledZoneNum).OpTempCntrlModeScheduled))) {
    1928           0 :                         ShowSevereError(state,
    1929           0 :                                         format("{}={} invalid {}=[{:.2T}\" cannot >= .9.",
    1930             :                                                cCurrentModuleObject,
    1931             :                                                cAlphaArgs(1),
    1932             :                                                cNumericFieldNames(1),
    1933             :                                                rNumericArgs(1)));
    1934           0 :                         ErrorsFound = true;
    1935             :                     }
    1936             : 
    1937             :                     // check schedule min max.
    1938           1 :                     if (TempControlledZone(TempControlledZoneNum).OpTempCntrlModeScheduled) {
    1939           0 :                         ValidRadFractSched = CheckScheduleValueMinMax(
    1940           0 :                             state, TempControlledZone(TempControlledZoneNum).OpTempRadiativeFractionSched, ">=", 0.0, "<", 0.9);
    1941           0 :                         if (!ValidRadFractSched) {
    1942           0 :                             ShowSevereError(
    1943             :                                 state,
    1944           0 :                                 format("{}={} invalid values {}=[{}\".", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(3), cAlphaArgs(3)));
    1945           0 :                             ShowContinueError(state, "..Values outside of range [0.0,0.9).");
    1946           0 :                             ErrorsFound = true;
    1947             :                         }
    1948             :                     }
    1949             : 
    1950             :                     // added Jan, 2017 - Xuan Luo
    1951             :                     // read adaptive comfort model and calculate adaptive thermal comfort setpoint
    1952           1 :                     if (TempControlledZone(TempControlledZoneNum).OperativeTempControl) {
    1953           1 :                         if (NumAlphas >= 4 && !lAlphaFieldBlanks(4)) {
    1954             :                             int adaptiveComfortModelTypeIndex =
    1955           0 :                                 Util::FindItem(cAlphaArgs(4), AdaptiveComfortModelTypes, AdaptiveComfortModelTypes.isize());
    1956           0 :                             if (!adaptiveComfortModelTypeIndex) {
    1957           0 :                                 ShowSevereError(state,
    1958           0 :                                                 format("{}={} invalid {}=\"{}\" not found.",
    1959             :                                                        cCurrentModuleObject,
    1960             :                                                        cAlphaArgs(1),
    1961             :                                                        cAlphaFieldNames(4),
    1962             :                                                        cAlphaArgs(4)));
    1963           0 :                                 ErrorsFound = true;
    1964           0 :                             } else if (adaptiveComfortModelTypeIndex != static_cast<int>(AdaptiveComfortModel::ADAP_NONE)) {
    1965           0 :                                 TempControlledZone(TempControlledZoneNum).AdaptiveComfortTempControl = true;
    1966           0 :                                 TempControlledZone(TempControlledZoneNum).AdaptiveComfortModelTypeIndex =
    1967           0 :                                     Util::FindItem(cAlphaArgs(4), AdaptiveComfortModelTypes, AdaptiveComfortModelTypes.isize());
    1968           0 :                                 if (!state.dataZoneTempPredictorCorrector->AdapComfortDailySetPointSchedule.initialized) {
    1969           0 :                                     Array1D<Real64> runningAverageASH(state.dataWeather->NumDaysInYear, 0.0);
    1970           0 :                                     Array1D<Real64> runningAverageCEN(state.dataWeather->NumDaysInYear, 0.0);
    1971           0 :                                     CalculateMonthlyRunningAverageDryBulb(state, runningAverageASH, runningAverageCEN);
    1972           0 :                                     CalculateAdaptiveComfortSetPointSchl(state, runningAverageASH, runningAverageCEN);
    1973           0 :                                 }
    1974             :                             }
    1975             :                         }
    1976             :                     }
    1977             : 
    1978             :                     // CurrentModuleObject='ZoneControl:Thermostat:OperativeTemperature'
    1979           2 :                     SetupOutputVariable(state,
    1980             :                                         "Zone Thermostat Operative Temperature",
    1981             :                                         Constant::Units::C,
    1982           1 :                                         state.dataHeatBal->ZnAirRpt(TempControlledZone(TempControlledZoneNum).ActualZoneNum).ThermOperativeTemp,
    1983             :                                         OutputProcessor::TimeStepType::Zone,
    1984             :                                         OutputProcessor::StoreType::Average,
    1985           1 :                                         Zone(TempControlledZone(TempControlledZoneNum).ActualZoneNum).Name);
    1986             :                 }
    1987             :             } else {
    1988           8 :                 for (Item = 1; Item <= TStatObjects(found).NumOfZones; ++Item) {
    1989           6 :                     TempControlledZoneNum = TStatObjects(found).TempControlledZoneStartPtr + Item - 1;
    1990           6 :                     if (state.dataZoneCtrls->NumTempControlledZones == 0) continue;
    1991           6 :                     TempControlledZone(TempControlledZoneNum).OperativeTempControl = true;
    1992           6 :                     if (Util::SameString(cAlphaArgs(2), "Scheduled")) {
    1993           0 :                         TempControlledZone(TempControlledZoneNum).OpTempCntrlModeScheduled = true;
    1994             :                     }
    1995           6 :                     if (Item == 1) {
    1996           2 :                         if ((!(Util::SameString(cAlphaArgs(2), "Scheduled"))) && (!(Util::SameString(cAlphaArgs(2), "Constant")))) {
    1997           0 :                             ShowSevereError(
    1998           0 :                                 state, format("{}={} invalid {}=\"{}\".", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    1999           0 :                             ErrorsFound = true;
    2000             :                         }
    2001             :                     }
    2002             : 
    2003           6 :                     TempControlledZone(TempControlledZoneNum).FixedRadiativeFraction = rNumericArgs(1);
    2004           6 :                     TempControlledZone(TempControlledZoneNum).OpTempRadiativeFractionSched = GetScheduleIndex(state, cAlphaArgs(3));
    2005           6 :                     if (Item == 1) {
    2006           4 :                         if ((TempControlledZone(TempControlledZoneNum).OpTempRadiativeFractionSched == 0) &&
    2007           2 :                             (TempControlledZone(TempControlledZoneNum).OpTempCntrlModeScheduled)) { // throw error
    2008           0 :                             ShowSevereError(
    2009             :                                 state,
    2010           0 :                                 format(
    2011             :                                     "{}={} invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(3), cAlphaArgs(3)));
    2012           0 :                             ErrorsFound = true;
    2013             :                         }
    2014             :                     }
    2015             : 
    2016             :                     // check validity of fixed radiative fraction
    2017           6 :                     if (Item == 1) {
    2018           2 :                         if ((TempControlledZone(TempControlledZoneNum).FixedRadiativeFraction < 0.0) &&
    2019           0 :                             (!(TempControlledZone(TempControlledZoneNum).OpTempCntrlModeScheduled))) {
    2020           0 :                             ShowSevereError(state,
    2021           0 :                                             format("{}={} invalid {}=[{:.2T}\" cannot be negative.",
    2022             :                                                    cCurrentModuleObject,
    2023             :                                                    cAlphaArgs(1),
    2024             :                                                    cNumericFieldNames(1),
    2025             :                                                    rNumericArgs(1)));
    2026           0 :                             ErrorsFound = true;
    2027             :                         }
    2028             :                     }
    2029           6 :                     if (Item == 1) {
    2030           2 :                         if ((TempControlledZone(TempControlledZoneNum).FixedRadiativeFraction >= 0.9) &&
    2031           0 :                             (!(TempControlledZone(TempControlledZoneNum).OpTempCntrlModeScheduled))) {
    2032           0 :                             ShowSevereError(state,
    2033           0 :                                             format("{}={} invalid {}=[{:.2T}\" cannot >= .9.",
    2034             :                                                    cCurrentModuleObject,
    2035             :                                                    cAlphaArgs(1),
    2036             :                                                    cNumericFieldNames(1),
    2037             :                                                    rNumericArgs(1)));
    2038           0 :                             ErrorsFound = true;
    2039             :                         }
    2040             :                     }
    2041             : 
    2042             :                     // check schedule min max.
    2043           6 :                     if (Item == 1) {
    2044           2 :                         if (TempControlledZone(TempControlledZoneNum).OpTempCntrlModeScheduled) {
    2045           0 :                             ValidRadFractSched = CheckScheduleValueMinMax(
    2046           0 :                                 state, TempControlledZone(TempControlledZoneNum).OpTempRadiativeFractionSched, ">=", 0.0, "<", 0.9);
    2047           0 :                             if (!ValidRadFractSched) {
    2048           0 :                                 ShowSevereError(
    2049             :                                     state,
    2050           0 :                                     format(
    2051             :                                         "{}={} invalid values {}=[{}\".", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(3), cAlphaArgs(3)));
    2052           0 :                                 ShowContinueError(state, "..Values outside of range [0.0,0.9).");
    2053           0 :                                 ErrorsFound = true;
    2054             :                             }
    2055             :                         }
    2056             :                     }
    2057             : 
    2058             :                     // added Jan, 2017 - Xuan Luo
    2059             :                     // read adaptive comfort model and calculate adaptive thermal comfort setpoint
    2060           6 :                     if (TempControlledZone(TempControlledZoneNum).OperativeTempControl) {
    2061           6 :                         if (NumAlphas >= 4 && !lAlphaFieldBlanks(4)) {
    2062             :                             int adaptiveComfortModelTypeIndex =
    2063           5 :                                 Util::FindItem(cAlphaArgs(4), AdaptiveComfortModelTypes, AdaptiveComfortModelTypes.isize());
    2064           5 :                             if (!adaptiveComfortModelTypeIndex) {
    2065           0 :                                 ShowSevereError(state,
    2066           0 :                                                 format("{}={} invalid {}=\"{}\" not found.",
    2067             :                                                        cCurrentModuleObject,
    2068             :                                                        cAlphaArgs(1),
    2069             :                                                        cAlphaFieldNames(4),
    2070             :                                                        cAlphaArgs(4)));
    2071           0 :                                 ErrorsFound = true;
    2072           5 :                             } else if (adaptiveComfortModelTypeIndex != static_cast<int>(AdaptiveComfortModel::ADAP_NONE)) {
    2073           5 :                                 TempControlledZone(TempControlledZoneNum).AdaptiveComfortTempControl = true;
    2074          10 :                                 TempControlledZone(TempControlledZoneNum).AdaptiveComfortModelTypeIndex =
    2075           5 :                                     Util::FindItem(cAlphaArgs(4), AdaptiveComfortModelTypes, AdaptiveComfortModelTypes.isize());
    2076           5 :                                 if (!state.dataZoneTempPredictorCorrector->AdapComfortDailySetPointSchedule.initialized) {
    2077           1 :                                     Array1D<Real64> runningAverageASH(state.dataWeather->NumDaysInYear, 0.0);
    2078           1 :                                     Array1D<Real64> runningAverageCEN(state.dataWeather->NumDaysInYear, 0.0);
    2079           1 :                                     CalculateMonthlyRunningAverageDryBulb(state, runningAverageASH, runningAverageCEN);
    2080           1 :                                     CalculateAdaptiveComfortSetPointSchl(state, runningAverageASH, runningAverageCEN);
    2081           1 :                                 }
    2082             :                             }
    2083             :                         }
    2084             :                     }
    2085             : 
    2086             :                     // CurrentModuleObject='ZoneControl:Thermostat:OperativeTemperature'
    2087          12 :                     SetupOutputVariable(state,
    2088             :                                         "Zone Thermostat Operative Temperature",
    2089             :                                         Constant::Units::C,
    2090           6 :                                         state.dataHeatBal->ZnAirRpt(TempControlledZone(TempControlledZoneNum).ActualZoneNum).ThermOperativeTemp,
    2091             :                                         OutputProcessor::TimeStepType::Zone,
    2092             :                                         OutputProcessor::StoreType::Average,
    2093           6 :                                         Zone(TempControlledZone(TempControlledZoneNum).ActualZoneNum).Name);
    2094             :                 } // TStat Objects Loop
    2095             :             }     // found thermostat referene
    2096             :         }         // loop over NumOpTempControlledZones
    2097             :     }             // NumOpTempControlledZones > 0
    2098             : 
    2099             :     // Overcool dehumidificaton GetInput starts here
    2100         796 :     cCurrentModuleObject = cZControlTypes(static_cast<int>(ZoneControlTypes::TandHStat));
    2101         796 :     state.dataZoneCtrls->NumTempAndHumidityControlledZones = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    2102             : 
    2103         796 :     if (state.dataZoneCtrls->NumTempAndHumidityControlledZones > 0) {
    2104           1 :         state.dataZoneCtrls->AnyZoneTempAndHumidityControl = true;
    2105             : 
    2106           2 :         for (int idx = 1; idx <= state.dataZoneCtrls->NumTempAndHumidityControlledZones; ++idx) {
    2107           1 :             inputProcessor->getObjectItem(state,
    2108             :                                           cCurrentModuleObject,
    2109             :                                           idx,
    2110             :                                           cAlphaArgs,
    2111             :                                           NumAlphas,
    2112             :                                           rNumericArgs,
    2113             :                                           NumNums,
    2114             :                                           IOStat,
    2115             :                                           lNumericFieldBlanks,
    2116             :                                           lAlphaFieldBlanks,
    2117             :                                           cAlphaFieldNames,
    2118             :                                           cNumericFieldNames);
    2119             :             // find matching name of  ZONECONTROL:THERMOSTAT object
    2120           1 :             found = Util::FindItem(cAlphaArgs(1), TStatObjects);
    2121           1 :             if (found == 0) {
    2122             :                 // It might be in the TempControlledZones
    2123           0 :                 found = Util::FindItem(cAlphaArgs(1), TempControlledZone);
    2124           0 :                 if (found == 0) { // throw error
    2125           0 :                     ShowSevereError(state,
    2126           0 :                                     format("{}={} invalid {} reference not found.",
    2127             :                                            cCurrentModuleObject,
    2128             :                                            cAlphaArgs(1),
    2129             :                                            cZControlTypes(static_cast<int>(ZoneControlTypes::TStat))));
    2130           0 :                     ErrorsFound = true;
    2131             :                 } else {
    2132           0 :                     TempControlledZoneNum = found;
    2133           0 :                     TempControlledZone(TempControlledZoneNum).DehumidifyingSched = cAlphaArgs(2);
    2134           0 :                     TempControlledZone(TempControlledZoneNum).DehumidifyingSchedIndex = GetScheduleIndex(state, cAlphaArgs(2));
    2135           0 :                     if (TempControlledZone(TempControlledZoneNum).DehumidifyingSchedIndex == 0) {
    2136           0 :                         ShowSevereError(
    2137             :                             state,
    2138           0 :                             format("{}=\"{} invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    2139           0 :                         ErrorsFound = true;
    2140             :                     }
    2141           0 :                     TempControlledZone(TempControlledZoneNum).ZoneOvercoolControl = true;
    2142           0 :                     if ((Util::SameString(cAlphaArgs(3), "None"))) {
    2143           0 :                         TempControlledZone(TempControlledZoneNum).ZoneOvercoolControl = false;
    2144             :                     }
    2145           0 :                     if (Util::SameString(cAlphaArgs(4), "Scheduled")) {
    2146           0 :                         TempControlledZone(TempControlledZoneNum).OvercoolCntrlModeScheduled = true;
    2147             :                     }
    2148           0 :                     if ((!(Util::SameString(cAlphaArgs(4), "Scheduled"))) && (!(Util::SameString(cAlphaArgs(4), "Constant")))) {
    2149           0 :                         ShowSevereError(state,
    2150           0 :                                         format("{}={} invalid {}=\"{}\".", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4)));
    2151           0 :                         ErrorsFound = true;
    2152             :                     }
    2153             : 
    2154           0 :                     TempControlledZone(TempControlledZoneNum).ZoneOvercoolConstRange = rNumericArgs(1);
    2155           0 :                     TempControlledZone(TempControlledZoneNum).ZoneOvercoolRangeSchedIndex = GetScheduleIndex(state, cAlphaArgs(4));
    2156           0 :                     if ((TempControlledZone(TempControlledZoneNum).ZoneOvercoolRangeSchedIndex == 0) &&
    2157           0 :                         (TempControlledZone(TempControlledZoneNum).OvercoolCntrlModeScheduled)) { // throw error
    2158           0 :                         ShowSevereError(
    2159             :                             state,
    2160           0 :                             format("{}={} invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5)));
    2161           0 :                         ErrorsFound = true;
    2162             :                     }
    2163             : 
    2164             :                     // check validity of zone Overcool constant range
    2165           0 :                     if ((TempControlledZone(TempControlledZoneNum).ZoneOvercoolConstRange < 0.0) &&
    2166           0 :                         (!(TempControlledZone(TempControlledZoneNum).OvercoolCntrlModeScheduled))) {
    2167           0 :                         ShowSevereError(state,
    2168           0 :                                         format("{}={} invalid {}=[{:.2T}\" cannot be negative.",
    2169             :                                                cCurrentModuleObject,
    2170             :                                                cAlphaArgs(1),
    2171             :                                                cNumericFieldNames(1),
    2172             :                                                rNumericArgs(1)));
    2173           0 :                         ErrorsFound = true;
    2174             :                     }
    2175           0 :                     if ((TempControlledZone(TempControlledZoneNum).ZoneOvercoolConstRange > 3.0) &&
    2176           0 :                         (!(TempControlledZone(TempControlledZoneNum).OvercoolCntrlModeScheduled))) {
    2177           0 :                         ShowSevereError(state,
    2178           0 :                                         format("{}={} invalid {}=[{:.2T}\" cannot be > 3.0",
    2179             :                                                cCurrentModuleObject,
    2180             :                                                cAlphaArgs(1),
    2181             :                                                cNumericFieldNames(1),
    2182             :                                                rNumericArgs(1)));
    2183           0 :                         ErrorsFound = true;
    2184             :                     }
    2185             : 
    2186             :                     // check zone Overcool range schedule min/max values.
    2187           0 :                     if (TempControlledZone(TempControlledZoneNum).OvercoolCntrlModeScheduled) {
    2188           0 :                         ValidZoneOvercoolRangeSched = CheckScheduleValueMinMax(
    2189           0 :                             state, TempControlledZone(TempControlledZoneNum).ZoneOvercoolRangeSchedIndex, ">=", 0.0, "<=", 3.0);
    2190           0 :                         if (!ValidZoneOvercoolRangeSched) {
    2191           0 :                             ShowSevereError(
    2192             :                                 state,
    2193           0 :                                 format("{}={} invalid values {}=[{}\".", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5)));
    2194           0 :                             ShowContinueError(state, "..Values outside of range [0.0,3.0].");
    2195           0 :                             ErrorsFound = true;
    2196             :                         }
    2197             :                     }
    2198             :                     // check Overcool Control Ratio limits
    2199           0 :                     TempControlledZone(TempControlledZoneNum).ZoneOvercoolControlRatio = rNumericArgs(2);
    2200           0 :                     if (TempControlledZone(TempControlledZoneNum).ZoneOvercoolControlRatio < 0.0) {
    2201           0 :                         ShowSevereError(state,
    2202           0 :                                         format("{}={} invalid {}=[{:.2T}\" cannot be negative.",
    2203             :                                                cCurrentModuleObject,
    2204             :                                                cAlphaArgs(2),
    2205             :                                                cNumericFieldNames(2),
    2206             :                                                rNumericArgs(2)));
    2207           0 :                         ErrorsFound = true;
    2208             :                     }
    2209             :                 }
    2210             :             } else {
    2211           2 :                 for (Item = 1; Item <= TStatObjects(found).NumOfZones; ++Item) {
    2212           1 :                     TempControlledZoneNum = TStatObjects(found).TempControlledZoneStartPtr + Item - 1;
    2213           1 :                     TempControlledZone(TempControlledZoneNum).DehumidifyingSched = cAlphaArgs(2);
    2214           1 :                     TempControlledZone(TempControlledZoneNum).DehumidifyingSchedIndex = GetScheduleIndex(state, cAlphaArgs(2));
    2215           1 :                     if (TempControlledZone(TempControlledZoneNum).DehumidifyingSchedIndex == 0) {
    2216           0 :                         ShowSevereError(
    2217             :                             state,
    2218           0 :                             format("{}=\"{} invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    2219           0 :                         ErrorsFound = true;
    2220             :                     }
    2221           1 :                     TempControlledZone(TempControlledZoneNum).ZoneOvercoolControl = true;
    2222           1 :                     if ((Util::SameString(cAlphaArgs(3), "None"))) {
    2223           0 :                         TempControlledZone(TempControlledZoneNum).ZoneOvercoolControl = false;
    2224             :                     }
    2225           1 :                     if (Util::SameString(cAlphaArgs(4), "Scheduled")) {
    2226           0 :                         TempControlledZone(TempControlledZoneNum).OvercoolCntrlModeScheduled = false;
    2227             :                     }
    2228           1 :                     if (Item == 1) {
    2229           1 :                         if ((!(Util::SameString(cAlphaArgs(4), "Scheduled"))) && (!(Util::SameString(cAlphaArgs(4), "Constant")))) {
    2230           0 :                             ShowSevereError(
    2231           0 :                                 state, format("{}={} invalid {}=\"{}\".", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4)));
    2232           0 :                             ErrorsFound = true;
    2233             :                         }
    2234             :                     }
    2235           1 :                     TempControlledZone(TempControlledZoneNum).ZoneOvercoolConstRange = rNumericArgs(1);
    2236           1 :                     TempControlledZone(TempControlledZoneNum).ZoneOvercoolRangeSchedIndex = GetScheduleIndex(state, cAlphaArgs(6));
    2237           1 :                     if (Item == 1) {
    2238           2 :                         if ((TempControlledZone(TempControlledZoneNum).ZoneOvercoolRangeSchedIndex == 0) &&
    2239           1 :                             (TempControlledZone(TempControlledZoneNum).OvercoolCntrlModeScheduled)) { // throw error
    2240           0 :                             ShowSevereError(
    2241             :                                 state,
    2242           0 :                                 format(
    2243             :                                     "{}={} invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5)));
    2244           0 :                             ErrorsFound = true;
    2245             :                         }
    2246             :                     }
    2247             :                     // check validity of zone Overcool constant range
    2248           1 :                     if (Item == 1) {
    2249           1 :                         if ((TempControlledZone(TempControlledZoneNum).ZoneOvercoolConstRange < 0.0) &&
    2250           0 :                             (!(TempControlledZone(TempControlledZoneNum).OvercoolCntrlModeScheduled))) {
    2251           0 :                             ShowSevereError(state,
    2252           0 :                                             format("{}={} invalid {}=[{:.2T}\" cannot be negative.",
    2253             :                                                    cCurrentModuleObject,
    2254             :                                                    cAlphaArgs(1),
    2255             :                                                    cNumericFieldNames(1),
    2256             :                                                    rNumericArgs(1)));
    2257           0 :                             ErrorsFound = true;
    2258             :                         }
    2259             :                     }
    2260           1 :                     if (Item == 1) {
    2261           1 :                         if ((TempControlledZone(TempControlledZoneNum).ZoneOvercoolConstRange > 3.0) &&
    2262           0 :                             (!(TempControlledZone(TempControlledZoneNum).OvercoolCntrlModeScheduled))) {
    2263           0 :                             ShowSevereError(state,
    2264           0 :                                             format("{}={} invalid {}=[{:.2T}\" cannot > 3.0",
    2265             :                                                    cCurrentModuleObject,
    2266             :                                                    cAlphaArgs(1),
    2267             :                                                    cNumericFieldNames(1),
    2268             :                                                    rNumericArgs(1)));
    2269           0 :                             ErrorsFound = true;
    2270             :                         }
    2271             :                     }
    2272             :                     // check zone Overcool range schedule min/max values.
    2273           1 :                     if (Item == 1) {
    2274           1 :                         if (TempControlledZone(TempControlledZoneNum).OvercoolCntrlModeScheduled) {
    2275           0 :                             ValidZoneOvercoolRangeSched = CheckScheduleValueMinMax(
    2276           0 :                                 state, TempControlledZone(TempControlledZoneNum).ZoneOvercoolRangeSchedIndex, ">=", 0.0, "<=", 3.0);
    2277           0 :                             if (!ValidZoneOvercoolRangeSched) {
    2278           0 :                                 ShowSevereError(
    2279             :                                     state,
    2280           0 :                                     format(
    2281             :                                         "{}={} invalid values {}=[{}\".", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(5), cAlphaArgs(5)));
    2282           0 :                                 ShowContinueError(state, "..Values outside of range [0.0,3.0].");
    2283           0 :                                 ErrorsFound = true;
    2284             :                             }
    2285             :                         }
    2286             :                     }
    2287           1 :                     TempControlledZone(TempControlledZoneNum).ZoneOvercoolControlRatio = rNumericArgs(2);
    2288             :                     // check Overcool Control Ratio limits
    2289           1 :                     if (Item == 1) {
    2290           1 :                         if (TempControlledZone(TempControlledZoneNum).ZoneOvercoolControlRatio < 0.0) {
    2291           0 :                             ShowSevereError(state,
    2292           0 :                                             format("{}={} invalid {}=[{:.2T}\" cannot be negative.",
    2293             :                                                    cCurrentModuleObject,
    2294             :                                                    cAlphaArgs(2),
    2295             :                                                    cNumericFieldNames(2),
    2296             :                                                    rNumericArgs(2)));
    2297           0 :                             ErrorsFound = true;
    2298             :                         }
    2299             :                     }
    2300             : 
    2301             :                 } // TStat Objects Loop
    2302             :             }     // found thermostat reference
    2303             :         }         // loop over NumTempAndHumidityControlledZones
    2304             :     }             // NumTempAndHumidityControlledZones > 0
    2305             : 
    2306             :     // Staged thermostat control inputs start
    2307         796 :     cCurrentModuleObject = cZControlTypes(static_cast<int>(ZoneControlTypes::StagedDual));
    2308         796 :     NumStageControlledZones = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    2309         796 :     if (NumStageControlledZones > 0) state.dataZoneCtrls->StagedTStatObjects.allocate(NumStageControlledZones);
    2310             : 
    2311             :     // Pre-scan for use of Zone lists in TStat statements (i.e. Global application of TStat)
    2312         796 :     state.dataZoneTempPredictorCorrector->NumStageCtrZone = 0;
    2313         801 :     for (Item = 1; Item <= NumStageControlledZones; ++Item) {
    2314           5 :         inputProcessor->getObjectItem(state,
    2315             :                                       cCurrentModuleObject,
    2316             :                                       Item,
    2317             :                                       cAlphaArgs,
    2318             :                                       NumAlphas,
    2319             :                                       rNumericArgs,
    2320             :                                       NumNums,
    2321             :                                       IOStat,
    2322             :                                       lNumericFieldBlanks,
    2323             :                                       lAlphaFieldBlanks,
    2324             :                                       cAlphaFieldNames,
    2325             :                                       cNumericFieldNames);
    2326           5 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
    2327             : 
    2328           5 :         state.dataZoneCtrls->StagedTStatObjects(Item).Name = cAlphaArgs(1);
    2329           5 :         Item1 = Util::FindItemInList(cAlphaArgs(2), Zone);
    2330           5 :         ZLItem = 0;
    2331           5 :         if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) ZLItem = Util::FindItemInList(cAlphaArgs(2), ZoneList);
    2332           5 :         if (Item1 > 0) {
    2333           4 :             state.dataZoneCtrls->StagedTStatObjects(Item).StageControlledZoneStartPtr = state.dataZoneTempPredictorCorrector->NumStageCtrZone + 1;
    2334           4 :             ++state.dataZoneTempPredictorCorrector->NumStageCtrZone;
    2335           4 :             state.dataZoneCtrls->StagedTStatObjects(Item).NumOfZones = 1;
    2336           4 :             state.dataZoneCtrls->StagedTStatObjects(Item).ZoneListActive = false;
    2337           4 :             state.dataZoneCtrls->StagedTStatObjects(Item).ZoneOrZoneListPtr = Item1;
    2338           1 :         } else if (ZLItem > 0) {
    2339           1 :             state.dataZoneCtrls->StagedTStatObjects(Item).TempControlledZoneStartPtr = state.dataZoneTempPredictorCorrector->NumStageCtrZone + 1;
    2340           1 :             state.dataZoneTempPredictorCorrector->NumStageCtrZone += ZoneList(ZLItem).NumOfZones;
    2341           1 :             state.dataZoneCtrls->StagedTStatObjects(Item).NumOfZones = ZoneList(ZLItem).NumOfZones;
    2342           1 :             state.dataZoneCtrls->StagedTStatObjects(Item).ZoneListActive = true;
    2343           1 :             state.dataZoneCtrls->StagedTStatObjects(Item).ZoneOrZoneListPtr = ZLItem;
    2344             :         } else {
    2345           0 :             ShowSevereError(
    2346           0 :                 state, format("{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    2347           0 :             ErrorsFound = true;
    2348             :         }
    2349             :     }
    2350             : 
    2351         796 :     if (ErrorsFound) {
    2352           0 :         ShowSevereError(state, format("GetStagedDualSetpoint: Errors with invalid names in {} objects.", cCurrentModuleObject));
    2353           0 :         ShowContinueError(state, "...These will not be read in.  Other errors may occur.");
    2354           0 :         state.dataZoneTempPredictorCorrector->NumStageCtrZone = 0;
    2355             :     }
    2356             : 
    2357         796 :     if (state.dataZoneTempPredictorCorrector->NumStageCtrZone > 0) {
    2358           2 :         StageControlledZone.allocate(state.dataZoneTempPredictorCorrector->NumStageCtrZone);
    2359           2 :         state.dataZoneCtrls->StageZoneLogic.dimension(NumOfZones, false);
    2360             : 
    2361           2 :         StageControlledZoneNum = 0;
    2362           7 :         for (Item = 1; Item <= NumStageControlledZones; ++Item) {
    2363           5 :             inputProcessor->getObjectItem(state,
    2364             :                                           cCurrentModuleObject,
    2365             :                                           Item,
    2366             :                                           cAlphaArgs,
    2367             :                                           NumAlphas,
    2368             :                                           rNumericArgs,
    2369             :                                           NumNums,
    2370             :                                           IOStat,
    2371             :                                           lNumericFieldBlanks,
    2372             :                                           lAlphaFieldBlanks,
    2373             :                                           cAlphaFieldNames,
    2374             :                                           cNumericFieldNames);
    2375          12 :             for (Item1 = 1; Item1 <= state.dataZoneCtrls->StagedTStatObjects(Item).NumOfZones; ++Item1) {
    2376           7 :                 ++StageControlledZoneNum;
    2377           7 :                 if (state.dataZoneCtrls->StagedTStatObjects(Item).ZoneListActive) {
    2378           6 :                     cAlphaArgs(2) =
    2379           3 :                         state.dataHeatBal->Zone(ZoneList(state.dataZoneCtrls->StagedTStatObjects(Item).ZoneOrZoneListPtr).Zone(Item1)).Name;
    2380             :                 }
    2381           7 :                 int ZoneAssigned = Util::FindItemInList(
    2382           7 :                     cAlphaArgs(2), StageControlledZone, &DataZoneControls::ZoneStagedControls::ZoneName, StageControlledZoneNum - 1);
    2383           7 :                 if (ZoneAssigned == 0) {
    2384           7 :                     StageControlledZone(StageControlledZoneNum).ZoneName = cAlphaArgs(2);
    2385           7 :                     StageControlledZone(StageControlledZoneNum).ActualZoneNum = Util::FindItemInList(cAlphaArgs(2), Zone);
    2386           7 :                     if (StageControlledZone(StageControlledZoneNum).ActualZoneNum == 0) {
    2387           0 :                         ShowSevereError(
    2388             :                             state,
    2389           0 :                             format(
    2390             :                                 "{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
    2391           0 :                         ErrorsFound = true;
    2392             :                     } else {
    2393             :                         //           Zone(StageControlledZone(StageControlledZoneNum)%ActualZoneNum)%StageControlledZoneIndex =
    2394             :                         //           StageControlledZoneNum
    2395             :                     }
    2396           7 :                     state.dataZoneCtrls->StageZoneLogic(StageControlledZone(StageControlledZoneNum).ActualZoneNum) = true;
    2397             :                 } else {
    2398           0 :                     StageControlledZone(StageControlledZoneNum).ZoneName = cAlphaArgs(2); // for continuity
    2399           0 :                     ShowSevereError(state,
    2400           0 :                                     format("{}=\"{}\" invalid {}=\"{}\" zone previously assigned.",
    2401             :                                            cCurrentModuleObject,
    2402             :                                            cAlphaArgs(1),
    2403             :                                            cAlphaFieldNames(2),
    2404             :                                            cAlphaArgs(2)));
    2405           0 :                     ShowContinueError(state, format("...Zone was previously assigned to Thermostat=\"{}\".", StageControlledZone(ZoneAssigned).Name));
    2406           0 :                     ErrorsFound = true;
    2407           0 :                     continue;
    2408             :                 }
    2409             : 
    2410           7 :                 if (!state.dataZoneCtrls->StagedTStatObjects(Item).ZoneListActive) {
    2411           4 :                     StageControlledZone(StageControlledZoneNum).Name = cAlphaArgs(1);
    2412             :                 } else {
    2413           9 :                     CheckCreatedZoneItemName(
    2414             :                         state,
    2415             :                         RoutineName,
    2416             :                         cCurrentModuleObject,
    2417           3 :                         state.dataHeatBal->Zone(ZoneList(state.dataZoneCtrls->StagedTStatObjects(Item).ZoneOrZoneListPtr).Zone(Item1)).Name,
    2418           3 :                         ZoneList(state.dataZoneCtrls->StagedTStatObjects(Item).ZoneOrZoneListPtr).MaxZoneNameLength,
    2419           3 :                         state.dataZoneCtrls->StagedTStatObjects(Item).Name,
    2420             :                         StageControlledZone,
    2421             :                         StageControlledZoneNum - 1,
    2422           3 :                         StageControlledZone(StageControlledZoneNum).Name,
    2423             :                         errFlag);
    2424           3 :                     if (errFlag) ErrorsFound = true;
    2425             :                 }
    2426             : 
    2427           7 :                 StageControlledZone(StageControlledZoneNum).NumOfHeatStages = rNumericArgs(1);
    2428           7 :                 if (rNumericArgs(1) < 1 || rNumericArgs(1) > 4) {
    2429           0 :                     ShowSevereError(
    2430             :                         state,
    2431           0 :                         format("{}=\"{}\" invalid range {}=\"{:.0R}\"", cCurrentModuleObject, cAlphaArgs(1), cNumericFieldNames(1), rNumericArgs(1)));
    2432           0 :                     ShowContinueError(state, "..contains values outside of range [1,4].");
    2433           0 :                     ErrorsFound = true;
    2434             :                 }
    2435             : 
    2436           7 :                 StageControlledZone(StageControlledZoneNum).HeatSetBaseSchedName = cAlphaArgs(3);
    2437           7 :                 StageControlledZone(StageControlledZoneNum).HSBchedIndex = GetScheduleIndex(state, cAlphaArgs(3));
    2438           7 :                 if (Item1 == 1) { // only show error on first of several if zone list
    2439           5 :                     if (StageControlledZone(StageControlledZoneNum).HSBchedIndex == 0) {
    2440           0 :                         ShowSevereError(
    2441             :                             state,
    2442           0 :                             format(
    2443             :                                 "{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(3), cAlphaArgs(3)));
    2444           0 :                         ErrorsFound = true;
    2445             :                     }
    2446             :                 }
    2447             : 
    2448           7 :                 StageControlledZone(StageControlledZoneNum).HeatThroRange = rNumericArgs(2);
    2449           7 :                 if (rNumericArgs(1) < 0.0) {
    2450           0 :                     ShowSevereError(state,
    2451           0 :                                     format("{}=\"{}\" negative value is found at {}=\"{:.1R}\"",
    2452             :                                            cAlphaArgs(1),
    2453             :                                            cCurrentModuleObject,
    2454             :                                            cNumericFieldNames(2),
    2455             :                                            rNumericArgs(2)));
    2456           0 :                     ShowContinueError(state, ".. The minimum value is 0.");
    2457           0 :                     ErrorsFound = true;
    2458             :                 }
    2459             : 
    2460           7 :                 if (StageControlledZone(StageControlledZoneNum).NumOfHeatStages > 0) {
    2461           7 :                     StageControlledZone(StageControlledZoneNum).HeatTOffset.allocate(StageControlledZone(StageControlledZoneNum).NumOfHeatStages);
    2462          18 :                     for (i = 1; i <= StageControlledZone(StageControlledZoneNum).NumOfHeatStages; ++i) {
    2463          11 :                         StageControlledZone(StageControlledZoneNum).HeatTOffset(i) = rNumericArgs(2 + i);
    2464          11 :                         if (rNumericArgs(2 + i) > 0.0) {
    2465           0 :                             ShowSevereError(state,
    2466           0 :                                             format("{}=\"{}\" positive value is found at {}",
    2467             :                                                    cCurrentModuleObject,
    2468             :                                                    cAlphaArgs(1),
    2469           0 :                                                    format("{}=\"{:.1R}\"", cNumericFieldNames(2 + i), rNumericArgs(2 + i))));
    2470           0 :                             ShowContinueError(state, ".. The maximum value is 0.");
    2471           0 :                             ErrorsFound = true;
    2472             :                         }
    2473          11 :                         if (lNumericFieldBlanks(2 + i)) {
    2474           0 :                             ShowSevereError(state,
    2475           0 :                                             format("{} object ={}. The input of {} is required, but a blank is found.",
    2476             :                                                    cCurrentModuleObject,
    2477             :                                                    cAlphaArgs(1),
    2478             :                                                    cNumericFieldNames(2 + i)));
    2479           0 :                             ErrorsFound = true;
    2480             :                         }
    2481          11 :                         if (i > 1) {
    2482           4 :                             if (rNumericArgs(2 + i) >= rNumericArgs(1 + i)) {
    2483           0 :                                 ShowSevereError(state,
    2484           0 :                                                 format(R"({}="{}" The value at {}="{:.1R}" has to be less than )",
    2485             :                                                        cCurrentModuleObject,
    2486             :                                                        cAlphaArgs(1),
    2487             :                                                        cNumericFieldNames(2 + i),
    2488             :                                                        rNumericArgs(2 + i)));
    2489           0 :                                 ShowContinueError(state, format("{}=\"{:.1R}", cNumericFieldNames(1 + i), rNumericArgs(1 + i)));
    2490           0 :                                 ErrorsFound = true;
    2491             :                             }
    2492             :                         }
    2493             :                     }
    2494             :                 }
    2495             : 
    2496           7 :                 StageControlledZone(StageControlledZoneNum).NumOfCoolStages = rNumericArgs(7);
    2497           7 :                 if (rNumericArgs(7) < 1 || rNumericArgs(7) > 4) {
    2498           0 :                     ShowSevereError(
    2499             :                         state,
    2500           0 :                         format("{}=\"{}\" invalid range {}=\"{:.0R}\"", cCurrentModuleObject, cAlphaArgs(1), cNumericFieldNames(7), rNumericArgs(7)));
    2501           0 :                     ShowContinueError(state, "..contains values outside of range [1,4].");
    2502           0 :                     ErrorsFound = true;
    2503             :                 }
    2504             : 
    2505           7 :                 StageControlledZone(StageControlledZoneNum).CoolSetBaseSchedName = cAlphaArgs(4);
    2506           7 :                 StageControlledZone(StageControlledZoneNum).CSBchedIndex = GetScheduleIndex(state, cAlphaArgs(4));
    2507           7 :                 if (Item1 == 1) { // only show error on first of several if zone list
    2508           5 :                     if (StageControlledZone(StageControlledZoneNum).CSBchedIndex == 0) {
    2509           0 :                         ShowSevereError(
    2510             :                             state,
    2511           0 :                             format(
    2512             :                                 "{}=\"{}\" invalid {}=\"{}\" not found.", cCurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(4), cAlphaArgs(4)));
    2513           0 :                         ErrorsFound = true;
    2514             :                     }
    2515             :                 }
    2516             : 
    2517           7 :                 StageControlledZone(StageControlledZoneNum).CoolThroRange = rNumericArgs(8);
    2518           7 :                 if (rNumericArgs(8) < 0.0) {
    2519           0 :                     ShowSevereError(state,
    2520           0 :                                     format("{}=\"{}\" negative value is found at {}=\"{:.1R}\"",
    2521             :                                            cCurrentModuleObject,
    2522             :                                            cAlphaArgs(1),
    2523             :                                            cNumericFieldNames(8),
    2524             :                                            rNumericArgs(8)));
    2525           0 :                     ShowContinueError(state, ".. The minumum value is 0.");
    2526           0 :                     ErrorsFound = true;
    2527             :                 }
    2528             : 
    2529           7 :                 if (StageControlledZone(StageControlledZoneNum).NumOfCoolStages > 0) {
    2530           7 :                     StageControlledZone(StageControlledZoneNum).CoolTOffset.allocate(StageControlledZone(StageControlledZoneNum).NumOfCoolStages);
    2531          26 :                     for (i = 1; i <= StageControlledZone(StageControlledZoneNum).NumOfCoolStages; ++i) {
    2532          19 :                         StageControlledZone(StageControlledZoneNum).CoolTOffset(i) = rNumericArgs(8 + i);
    2533          19 :                         if (rNumericArgs(8 + i) < 0.0) {
    2534           0 :                             ShowSevereError(state,
    2535           0 :                                             format("{}=\"{}\" negative value is found at {}=\"{:.1R}\"",
    2536             :                                                    cCurrentModuleObject,
    2537             :                                                    cAlphaArgs(1),
    2538             :                                                    cNumericFieldNames(8 + i),
    2539             :                                                    rNumericArgs(8 + i)));
    2540           0 :                             ShowContinueError(state, ".. The minimum value is 0.");
    2541           0 :                             ErrorsFound = true;
    2542             :                         }
    2543          19 :                         if (lNumericFieldBlanks(8 + i)) {
    2544           0 :                             ShowSevereError(state,
    2545           0 :                                             format("{} object ={}. The input of {} is required, but a blank is found.",
    2546             :                                                    cCurrentModuleObject,
    2547             :                                                    cAlphaArgs(1),
    2548             :                                                    cNumericFieldNames(8 + i)));
    2549           0 :                             ErrorsFound = true;
    2550             :                         }
    2551          19 :                         if (i > 1) {
    2552          12 :                             if (rNumericArgs(8 + i) <= rNumericArgs(7 + i)) {
    2553           0 :                                 ShowSevereError(state,
    2554           0 :                                                 format("{}=\"{}\" The value at {}=\"{:.1R}\" has to be greater than ",
    2555             :                                                        cCurrentModuleObject,
    2556             :                                                        cAlphaArgs(1),
    2557             :                                                        cNumericFieldNames(8 + i),
    2558             :                                                        rNumericArgs(8 + i)));
    2559           0 :                                 ShowContinueError(state, format("{}=\"{:.1R}", cNumericFieldNames(7 + i), rNumericArgs(7 + i)));
    2560           0 :                                 ErrorsFound = true;
    2561             :                             }
    2562             :                         }
    2563             :                     }
    2564             :                 }
    2565             :             }
    2566             :         } // loop over NumStageControlledZones
    2567           2 :         if ((inputProcessor->getNumObjectsFound(state, "AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed") == 0) &&
    2568           1 :             (inputProcessor->getNumObjectsFound(state, "AirLoopHVAC:UnitarySystem") == 0) &&
    2569           3 :             (inputProcessor->getNumObjectsFound(state, "SetpointManager:SingleZone:OneStageCooling") == 0) &&
    2570           2 :             (inputProcessor->getNumObjectsFound(state, "SetpointManager:SingleZone:OneStageHeating") == 0)) {
    2571           0 :             ShowWarningError(state, format("{} is applicable to only selected HVAC objects which are missing from input.", cCurrentModuleObject));
    2572           0 :             ShowContinueError(state, "Model should include one or more of the following objects:  ");
    2573           0 :             ShowContinueError(state, "AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed, AirLoopHVAC:UnitarySystem, ");
    2574           0 :             ShowContinueError(
    2575             :                 state, "SetpointManager:SingleZone:OneStageCooling, and/or SetpointManager:SingleZone:OneStageHeating. The simulation continues...");
    2576             :         }
    2577             :     } // NumStageControlledZones > 0
    2578             : 
    2579         796 :     if (ErrorsFound) {
    2580           0 :         ShowFatalError(state, "Errors getting Zone Control input data.  Preceding condition(s) cause termination.");
    2581             :     }
    2582         796 : }
    2583             : 
    2584           1 : void CalculateMonthlyRunningAverageDryBulb(EnergyPlusData &state, Array1D<Real64> &runningAverageASH, Array1D<Real64> &runningAverageCEN)
    2585             : {
    2586             :     // SUBROUTINE INFORMATION:
    2587             :     //       AUTHOR         Xuan Luo
    2588             :     //       DATE WRITTEN   January 2017
    2589             :     //       RE-ENGINEERED  na
    2590             : 
    2591             :     // PURPOSE OF THIS SUBROUTINE:
    2592             :     // This subroutine calculate the monthly running average dry bulb temperature;
    2593             : 
    2594             :     // Using/Aliasing
    2595             : 
    2596             :     using OutputReportTabular::GetColumnUsingTabs;
    2597             :     using OutputReportTabular::StrToReal;
    2598             : 
    2599             :     // SUBROUTINE PARAMETER DEFINITIONS:
    2600             : 
    2601             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2602             : 
    2603           1 :     std::string lineIn;
    2604           1 :     std::string lineAvg;
    2605           1 :     std::string epwLine;
    2606             : 
    2607             :     Real64 dryBulb;
    2608             :     Real64 avgDryBulb;
    2609             : 
    2610             :     int readStat;
    2611             :     int calcEndDay;
    2612             :     int calcStartDayASH;
    2613             :     int calcStartDayCEN;
    2614             : 
    2615             :     std::string::size_type pos;
    2616             :     int ind, i, j;
    2617             : 
    2618           1 :     Array1D<Real64> adaptiveTemp(state.dataWeather->NumDaysInYear, 0.0);
    2619           1 :     Array1D<Real64> dailyDryTemp(state.dataWeather->NumDaysInYear, 0.0);
    2620             : 
    2621           1 :     readStat = 0;
    2622           1 :     if (FileSystem::fileExists(state.files.inputWeatherFilePath.filePath)) {
    2623             :         // Read hourly dry bulb temperature first
    2624           2 :         auto epwFile = state.files.inputWeatherFilePath.open(state, "CalcThermalComfortAdaptive");
    2625          10 :         for (i = 1; i <= 9; ++i) { // Headers
    2626           9 :             epwFile.readLine();
    2627             :         }
    2628         366 :         for (i = 1; i <= state.dataWeather->NumDaysInYear; ++i) {
    2629         365 :             avgDryBulb = 0.0;
    2630        9125 :             for (j = 1; j <= 24; ++j) {
    2631        8760 :                 epwLine = epwFile.readLine().data;
    2632       61320 :                 for (ind = 1; ind <= 6; ++ind) {
    2633       52560 :                     pos = index(epwLine, ',');
    2634       52560 :                     epwLine.erase(0, pos + 1);
    2635             :                 }
    2636        8760 :                 pos = index(epwLine, ',');
    2637        8760 :                 dryBulb = StrToReal(epwLine.substr(0, pos));
    2638        8760 :                 avgDryBulb += (dryBulb / 24.0);
    2639             :             }
    2640         365 :             dailyDryTemp(i) = avgDryBulb;
    2641             :         }
    2642           1 :         epwFile.close();
    2643             : 
    2644             :         // Calculate monthly running average dry bulb temperature.
    2645           1 :         int dayOfYear = 0;
    2646         366 :         while (dayOfYear < state.dataWeather->NumDaysInYear) {
    2647         365 :             dayOfYear++;
    2648         365 :             calcEndDay = dayOfYear - 1;
    2649         365 :             calcStartDayASH = calcEndDay - 30;
    2650         365 :             calcStartDayCEN = calcEndDay - 7;
    2651             : 
    2652         365 :             if (calcStartDayASH > 0) {
    2653       10688 :                 for (i = calcStartDayASH; i <= calcStartDayASH + 30; i++) {
    2654       10354 :                     avgDryBulb = dailyDryTemp(i);
    2655       10354 :                     runningAverageASH(dayOfYear) = runningAverageASH(dayOfYear) + avgDryBulb;
    2656             :                 }
    2657         334 :                 runningAverageASH(dayOfYear) /= 30;
    2658             :             } else { // Do special things for wrapping the epw
    2659          31 :                 calcStartDayASH += state.dataWeather->NumDaysInYear;
    2660         496 :                 for (i = 1; i <= calcEndDay; i++) {
    2661         465 :                     avgDryBulb = dailyDryTemp(i);
    2662         465 :                     runningAverageASH(dayOfYear) = runningAverageASH(dayOfYear) + avgDryBulb;
    2663             :                 }
    2664         496 :                 for (i = calcStartDayASH; i < state.dataWeather->NumDaysInYear; i++) {
    2665         465 :                     avgDryBulb = dailyDryTemp(i);
    2666         465 :                     runningAverageASH(dayOfYear) = runningAverageASH(dayOfYear) + avgDryBulb;
    2667             :                 }
    2668          31 :                 runningAverageASH(dayOfYear) /= 30;
    2669             :             }
    2670             : 
    2671         365 :             if (calcStartDayCEN > 0) {
    2672        3213 :                 for (i = calcStartDayCEN; i <= calcStartDayCEN + 7; i++) {
    2673        2856 :                     avgDryBulb = dailyDryTemp(i);
    2674        2856 :                     runningAverageCEN(dayOfYear) = runningAverageCEN(dayOfYear) + avgDryBulb;
    2675             :                 }
    2676         357 :                 runningAverageCEN(dayOfYear) /= 7;
    2677             :             } else { // Do special things for wrapping the epw
    2678           8 :                 calcStartDayCEN += state.dataWeather->NumDaysInYear;
    2679          36 :                 for (i = 1; i <= calcEndDay; i++) {
    2680          28 :                     avgDryBulb = dailyDryTemp(i);
    2681          28 :                     runningAverageCEN(dayOfYear) = runningAverageCEN(dayOfYear) + avgDryBulb;
    2682             :                 }
    2683          36 :                 for (i = calcStartDayCEN; i < state.dataWeather->NumDaysInYear; i++) {
    2684          28 :                     avgDryBulb = dailyDryTemp(i);
    2685          28 :                     runningAverageCEN(dayOfYear) = runningAverageCEN(dayOfYear) + avgDryBulb;
    2686             :                 }
    2687           8 :                 runningAverageCEN(dayOfYear) /= 7;
    2688             :             }
    2689             :         }
    2690           1 :     } else {
    2691           0 :         ShowFatalError(state,
    2692           0 :                        format("CalcThermalComfortAdaptive: Could not open file {} for input (read). (File does not exist)",
    2693           0 :                               state.files.inputWeatherFilePath.filePath));
    2694             :     }
    2695           1 : }
    2696             : 
    2697           1 : void CalculateAdaptiveComfortSetPointSchl(EnergyPlusData &state, Array1D<Real64> const &runningAverageASH, Array1D<Real64> const &runningAverageCEN)
    2698             : {
    2699             :     // SUBROUTINE INFORMATION:
    2700             :     //       AUTHOR         Xuan Luo
    2701             :     //       DATE WRITTEN   January 2017
    2702             :     //       RE-ENGINEERED  na
    2703             : 
    2704             :     // PURPOSE OF THIS SUBROUTINE:
    2705             :     // This subroutine calculates the zone operative temperature setpoint using adaptive comfort model.
    2706             : 
    2707             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2708           1 :     int constexpr summerDesignDayTypeIndex(9);
    2709           1 :     Real64 GrossApproxAvgDryBulbDesignDay(0.0);
    2710             : 
    2711           1 :     auto &AdapComfortDailySetPointSchedule = state.dataZoneTempPredictorCorrector->AdapComfortDailySetPointSchedule;
    2712           1 :     auto &AdapComfortSetPointSummerDesDay = state.dataZoneTempPredictorCorrector->AdapComfortSetPointSummerDesDay;
    2713             : 
    2714           3 :     for (size_t i = 1; i <= state.dataWeather->DesDayInput.size(); i++) {
    2715             :         // Summer design day
    2716           2 :         if (state.dataWeather->DesDayInput(i).DayType == summerDesignDayTypeIndex) {
    2717           1 :             GrossApproxAvgDryBulbDesignDay = (state.dataWeather->DesDayInput(i).MaxDryBulb +
    2718           1 :                                               (state.dataWeather->DesDayInput(i).MaxDryBulb - state.dataWeather->DesDayInput(i).DailyDBRange)) /
    2719             :                                              2.0;
    2720           1 :             if (GrossApproxAvgDryBulbDesignDay > 10 && GrossApproxAvgDryBulbDesignDay < 33.5) {
    2721           1 :                 AdapComfortSetPointSummerDesDay[0] = 0.31 * GrossApproxAvgDryBulbDesignDay + 17.8;
    2722           1 :                 AdapComfortSetPointSummerDesDay[1] = 0.31 * GrossApproxAvgDryBulbDesignDay + 20.3;
    2723           1 :                 AdapComfortSetPointSummerDesDay[2] = 0.31 * GrossApproxAvgDryBulbDesignDay + 21.3;
    2724             :             }
    2725           1 :             if (GrossApproxAvgDryBulbDesignDay > 10 && GrossApproxAvgDryBulbDesignDay < 30) {
    2726           1 :                 AdapComfortSetPointSummerDesDay[3] = 0.33 * GrossApproxAvgDryBulbDesignDay + 18.8;
    2727           1 :                 AdapComfortSetPointSummerDesDay[4] = 0.33 * GrossApproxAvgDryBulbDesignDay + 20.8;
    2728             :                 ;
    2729           1 :                 AdapComfortSetPointSummerDesDay[5] = 0.33 * GrossApproxAvgDryBulbDesignDay + 21.8;
    2730             :                 ;
    2731           1 :                 AdapComfortSetPointSummerDesDay[6] = 0.33 * GrossApproxAvgDryBulbDesignDay + 22.8;
    2732             :                 ;
    2733             :             }
    2734             :         }
    2735             :     }
    2736             : 
    2737           1 :     AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Central.allocate(state.dataWeather->NumDaysInYear);
    2738           1 :     AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_90.allocate(state.dataWeather->NumDaysInYear);
    2739           1 :     AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_80.allocate(state.dataWeather->NumDaysInYear);
    2740           1 :     AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Central.allocate(state.dataWeather->NumDaysInYear);
    2741           1 :     AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_I.allocate(state.dataWeather->NumDaysInYear);
    2742           1 :     AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_II.allocate(state.dataWeather->NumDaysInYear);
    2743           1 :     AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_III.allocate(state.dataWeather->NumDaysInYear);
    2744             : 
    2745             :     // Calculate the set points based on different models, set flag as -1 when running average temperature is not in the range.
    2746         366 :     for (int day = 1; day <= state.dataWeather->NumDaysInYear; day++) {
    2747         365 :         if (runningAverageASH(day) > 10 && runningAverageASH(day) < 33.5) {
    2748         365 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Central(day) = 0.31 * runningAverageASH(day) + 17.8;
    2749         365 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_90(day) = 0.31 * runningAverageASH(day) + 20.3;
    2750         365 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_80(day) = 0.31 * runningAverageASH(day) + 21.3;
    2751             :         } else {
    2752           0 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Central(day) = -1;
    2753           0 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_90(day) = -1;
    2754           0 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_80(day) = -1;
    2755             :         }
    2756         365 :         if (runningAverageCEN(day) > 10 && runningAverageCEN(day) < 30) {
    2757         216 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Central(day) = 0.33 * runningAverageCEN(day) + 18.8;
    2758         216 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_I(day) = 0.33 * runningAverageCEN(day) + 20.8;
    2759         216 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_II(day) = 0.33 * runningAverageCEN(day) + 21.8;
    2760         216 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_III(day) = 0.33 * runningAverageCEN(day) + 22.8;
    2761             :         } else {
    2762         149 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Central(day) = -1;
    2763         149 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_I(day) = -1;
    2764         149 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_II(day) = -1;
    2765         149 :             AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_III(day) = -1;
    2766             :         }
    2767             :     }
    2768           1 :     AdapComfortDailySetPointSchedule.initialized = true;
    2769           1 : }
    2770             : 
    2771    14404425 : void InitZoneAirSetPoints(EnergyPlusData &state)
    2772             : {
    2773             : 
    2774             :     // SUBROUTINE INFORMATION:
    2775             :     //       AUTHOR         Russell Taylor
    2776             :     //       DATE WRITTEN   September 1998
    2777             :     //       MODIFIED       November 2004, M. J. Witte additional report variables
    2778             :     //       MODIFIED       L.Gu, May 2006
    2779             :     //       RE-ENGINEERED  na
    2780             : 
    2781             :     // PURPOSE OF THIS SUBROUTINE:
    2782             :     // This subroutine initializes the data for the zone air setpoints.
    2783             : 
    2784             :     // METHODOLOGY EMPLOYED:
    2785             :     // Uses the status flags to trigger events.
    2786             : 
    2787             :     // SUBROUTINE PARAMETER DEFINITIONS:
    2788             :     static constexpr std::string_view RoutineName("InitZoneAirSetpoints: ");
    2789             : 
    2790             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2791             :     bool FirstSurfFlag;
    2792             :     int TRefFlag; // Flag for Reference Temperature process in Zones
    2793             : 
    2794    14404425 :     auto &ZoneList = state.dataHeatBal->ZoneList;
    2795    14404425 :     auto &TempControlledZone = state.dataZoneCtrls->TempControlledZone;
    2796    14404425 :     auto &TempZoneThermostatSetPoint = state.dataHeatBalFanSys->TempZoneThermostatSetPoint;
    2797    14404425 :     auto &TempControlType = state.dataHeatBalFanSys->TempControlType;
    2798    14404425 :     auto &TempControlTypeRpt = state.dataHeatBalFanSys->TempControlTypeRpt;
    2799    14404425 :     auto &ComfortControlledZone = state.dataZoneCtrls->ComfortControlledZone;
    2800    14404425 :     auto &ZoneThermostatSetPointLo = state.dataHeatBalFanSys->ZoneThermostatSetPointLo;
    2801    14404425 :     auto &ZoneThermostatSetPointHi = state.dataHeatBalFanSys->ZoneThermostatSetPointHi;
    2802    14404425 :     int NumOfZones = state.dataGlobal->NumOfZones;
    2803             : 
    2804    14404425 :     if (state.dataZoneTempPredictorCorrector->InitZoneAirSetPointsOneTimeFlag) {
    2805         796 :         TempZoneThermostatSetPoint.dimension(NumOfZones, 0.0);
    2806         796 :         state.dataHeatBalFanSys->AdapComfortCoolingSetPoint.dimension(NumOfZones, 0.0);
    2807         796 :         ZoneThermostatSetPointHi.dimension(NumOfZones, 0.0);
    2808         796 :         ZoneThermostatSetPointLo.dimension(NumOfZones, 0.0);
    2809         796 :         state.dataHeatBalFanSys->ZoneThermostatSetPointHiAver.dimension(NumOfZones, 0.0);
    2810         796 :         state.dataHeatBalFanSys->ZoneThermostatSetPointLoAver.dimension(NumOfZones, 0.0);
    2811             : 
    2812         796 :         state.dataHeatBalFanSys->LoadCorrectionFactor.dimension(NumOfZones, 0.0);
    2813         796 :         TempControlType.dimension(NumOfZones, HVAC::ThermostatType::Uncontrolled);
    2814         796 :         TempControlTypeRpt.dimension(NumOfZones, 0);
    2815         796 :         if (state.dataZoneCtrls->NumComfortControlledZones > 0) {
    2816           1 :             state.dataHeatBalFanSys->ComfortControlType.dimension(NumOfZones, HVAC::ThermostatType::Uncontrolled);
    2817           1 :             state.dataHeatBalFanSys->ComfortControlTypeRpt.dimension(NumOfZones, 0);
    2818           1 :             state.dataHeatBalFanSys->ZoneComfortControlsFanger.allocate(NumOfZones);
    2819             :         }
    2820         796 :         state.dataZoneEnergyDemand->Setback.dimension(NumOfZones, false);
    2821         796 :         state.dataZoneEnergyDemand->DeadBandOrSetback.dimension(NumOfZones, false);
    2822         796 :         state.dataZoneEnergyDemand->CurDeadBandOrSetback.dimension(NumOfZones, false);
    2823             : 
    2824         796 :         state.dataHeatBal->ZoneListSNLoadHeatEnergy.dimension(state.dataHeatBal->NumOfZoneLists, 0.0);
    2825         796 :         state.dataHeatBal->ZoneListSNLoadCoolEnergy.dimension(state.dataHeatBal->NumOfZoneLists, 0.0);
    2826         796 :         state.dataHeatBal->ZoneListSNLoadHeatRate.dimension(state.dataHeatBal->NumOfZoneLists, 0.0);
    2827         796 :         state.dataHeatBal->ZoneListSNLoadCoolRate.dimension(state.dataHeatBal->NumOfZoneLists, 0.0);
    2828             : 
    2829         796 :         state.dataHeatBal->ZoneGroupSNLoadHeatEnergy.dimension(state.dataHeatBal->NumOfZoneGroups, 0.0);
    2830         796 :         state.dataHeatBal->ZoneGroupSNLoadCoolEnergy.dimension(state.dataHeatBal->NumOfZoneGroups, 0.0);
    2831         796 :         state.dataHeatBal->ZoneGroupSNLoadHeatRate.dimension(state.dataHeatBal->NumOfZoneGroups, 0.0);
    2832         796 :         state.dataHeatBal->ZoneGroupSNLoadCoolRate.dimension(state.dataHeatBal->NumOfZoneGroups, 0.0);
    2833             : 
    2834             :         // Hybrid modeling
    2835         796 :         state.dataHeatBalFanSys->PreviousMeasuredZT1.dimension(NumOfZones, 0.0);
    2836         796 :         state.dataHeatBalFanSys->PreviousMeasuredZT2.dimension(NumOfZones, 0.0);
    2837         796 :         state.dataHeatBalFanSys->PreviousMeasuredZT3.dimension(NumOfZones, 0.0);
    2838         796 :         state.dataHeatBalFanSys->PreviousMeasuredHumRat1.dimension(NumOfZones, 0.0);
    2839         796 :         state.dataHeatBalFanSys->PreviousMeasuredHumRat2.dimension(NumOfZones, 0.0);
    2840         796 :         state.dataHeatBalFanSys->PreviousMeasuredHumRat3.dimension(NumOfZones, 0.0);
    2841             : 
    2842             :         // Allocate Derived Types
    2843         796 :         state.dataZoneEnergyDemand->ZoneSysEnergyDemand.allocate(NumOfZones);
    2844         796 :         state.dataZoneEnergyDemand->ZoneSysMoistureDemand.allocate(NumOfZones);
    2845         796 :         if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
    2846           2 :             state.dataZoneEnergyDemand->spaceSysEnergyDemand.allocate(state.dataGlobal->numSpaces);
    2847           2 :             state.dataZoneEnergyDemand->spaceSysMoistureDemand.allocate(state.dataGlobal->numSpaces);
    2848             :         }
    2849             : 
    2850        5852 :         for (int zoneNum = 1; zoneNum <= NumOfZones; ++zoneNum) {
    2851        5056 :             FirstSurfFlag = true;
    2852       10124 :             for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    2853        5068 :                 auto &thisSpace = state.dataHeatBal->space(spaceNum);
    2854       49458 :                 for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
    2855       44390 :                     if (FirstSurfFlag) {
    2856        5056 :                         TRefFlag = state.dataSurface->SurfTAirRef(SurfNum);
    2857        5056 :                         FirstSurfFlag = false;
    2858             :                     }
    2859             :                     // for each particular zone, the reference air temperature(s) should be the same
    2860             :                     // (either mean air, bulk air, or supply air temp).
    2861       44390 :                     if (state.dataSurface->SurfTAirRef(SurfNum) != TRefFlag) {
    2862           0 :                         ShowWarningError(state,
    2863           0 :                                          format("Different reference air temperatures for difference surfaces encountered in zone {}",
    2864           0 :                                                 state.dataHeatBal->Zone(zoneNum).Name));
    2865             :                     }
    2866             :                 }
    2867        5056 :             }
    2868             :         }
    2869             : 
    2870             :         // CurrentModuleObject='Zone'
    2871        5852 :         for (int zoneNum = 1; zoneNum <= NumOfZones; ++zoneNum) {
    2872        5056 :             auto &thisZone = state.dataHeatBal->Zone(zoneNum);
    2873        5056 :             state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum).setUpOutputVars(state, DataStringGlobals::zonePrefix, thisZone.Name);
    2874        5056 :             if (state.dataHeatBal->doSpaceHeatBalanceSimulation) {
    2875          28 :                 for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    2876          16 :                     state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).setUpOutputVars(
    2877          16 :                         state, DataStringGlobals::spacePrefix, state.dataHeatBal->space(spaceNum).Name);
    2878          12 :                 }
    2879             :             }
    2880        5056 :             bool staged = false;
    2881        5056 :             if (allocated(state.dataZoneCtrls->StageZoneLogic)) {
    2882           8 :                 staged = state.dataZoneCtrls->StageZoneLogic(zoneNum);
    2883             :             }
    2884             :             // If not doSpaceHeatBalanceSimulation then meter zones, not spaces
    2885        5056 :             bool attachMeters = !state.dataHeatBal->doSpaceHeatBalanceSimulation;
    2886        5056 :             state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).setUpOutputVars(
    2887        5056 :                 state, DataStringGlobals::zonePrefix, thisZone.Name, staged, attachMeters, thisZone.Multiplier, thisZone.ListMultiplier);
    2888        5056 :             if (state.dataHeatBal->doSpaceHeatBalanceSimulation) {
    2889             :                 // If doSpaceHeatBalanceSimulation then meter spaces, not zones
    2890          12 :                 attachMeters = state.dataHeatBal->doSpaceHeatBalanceSimulation;
    2891          28 :                 for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    2892          16 :                     state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).setUpOutputVars(state,
    2893             :                                                                                                DataStringGlobals::spacePrefix,
    2894          16 :                                                                                                state.dataHeatBal->space(spaceNum).Name,
    2895             :                                                                                                staged,
    2896             :                                                                                                attachMeters,
    2897             :                                                                                                thisZone.Multiplier,
    2898             :                                                                                                thisZone.ListMultiplier);
    2899          12 :                 }
    2900             :             }
    2901        5056 :             state.dataZoneEnergyDemand->ZoneSysMoistureDemand(zoneNum).setUpOutputVars(state, DataStringGlobals::zonePrefix, thisZone.Name);
    2902        5056 :             if (state.dataHeatBal->doSpaceHeatBalanceSimulation) {
    2903          28 :                 for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    2904          16 :                     state.dataZoneEnergyDemand->spaceSysMoistureDemand(spaceNum).setUpOutputVars(
    2905          16 :                         state, DataStringGlobals::spacePrefix, state.dataHeatBal->space(spaceNum).Name);
    2906          12 :                 }
    2907             :             }
    2908       10112 :             SetupOutputVariable(state,
    2909             :                                 "Zone Thermostat Air Temperature",
    2910             :                                 Constant::Units::C,
    2911        5056 :                                 state.dataHeatBalFanSys->TempTstatAir(zoneNum),
    2912             :                                 OutputProcessor::TimeStepType::System,
    2913             :                                 OutputProcessor::StoreType::Average,
    2914        5056 :                                 thisZone.Name);
    2915        5056 :             SetupOutputVariable(state,
    2916             :                                 "Zone Thermostat Control Type",
    2917             :                                 Constant::Units::None,
    2918             :                                 TempControlTypeRpt(zoneNum),
    2919             :                                 OutputProcessor::TimeStepType::Zone,
    2920             :                                 OutputProcessor::StoreType::Average,
    2921        5056 :                                 thisZone.Name);
    2922       10112 :             SetupOutputVariable(state,
    2923             :                                 "Zone Thermostat Heating Setpoint Temperature",
    2924             :                                 Constant::Units::C,
    2925        5056 :                                 ZoneThermostatSetPointLo(zoneNum),
    2926             :                                 OutputProcessor::TimeStepType::System,
    2927             :                                 OutputProcessor::StoreType::Average,
    2928        5056 :                                 thisZone.Name);
    2929       10112 :             SetupOutputVariable(state,
    2930             :                                 "Zone Thermostat Cooling Setpoint Temperature",
    2931             :                                 Constant::Units::C,
    2932        5056 :                                 ZoneThermostatSetPointHi(zoneNum),
    2933             :                                 OutputProcessor::TimeStepType::System,
    2934             :                                 OutputProcessor::StoreType::Average,
    2935        5056 :                                 thisZone.Name);
    2936       10112 :             SetupOutputVariable(state,
    2937             :                                 "Zone Adaptive Comfort Operative Temperature Set Point",
    2938             :                                 Constant::Units::C,
    2939        5056 :                                 state.dataHeatBalFanSys->AdapComfortCoolingSetPoint(zoneNum),
    2940             :                                 OutputProcessor::TimeStepType::Zone,
    2941             :                                 OutputProcessor::StoreType::Average,
    2942        5056 :                                 thisZone.Name);
    2943       10112 :             SetupOutputVariable(state,
    2944             :                                 "Zone Predicted Sensible Load Room Air Correction Factor",
    2945             :                                 Constant::Units::None,
    2946        5056 :                                 state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum),
    2947             :                                 OutputProcessor::TimeStepType::System,
    2948             :                                 OutputProcessor::StoreType::Average,
    2949        5056 :                                 thisZone.Name);
    2950             :         } // zoneNum
    2951             : 
    2952             :         // Thermal comfort control output
    2953         796 :         if (state.dataZoneCtrls->NumComfortControlledZones > 0) {
    2954             :             // CurrentModuleObject='ZoneControl:Thermostat:ThermalComfort'
    2955           2 :             for (int Loop = 1; Loop <= state.dataZoneCtrls->NumComfortControlledZones; ++Loop) {
    2956           1 :                 int zoneNum = ComfortControlledZone(Loop).ActualZoneNum;
    2957           1 :                 auto &thisZone = state.dataHeatBal->Zone(zoneNum);
    2958           1 :                 SetupOutputVariable(state,
    2959             :                                     "Zone Thermal Comfort Control Type",
    2960             :                                     Constant::Units::None,
    2961           1 :                                     state.dataHeatBalFanSys->ComfortControlTypeRpt(zoneNum),
    2962             :                                     OutputProcessor::TimeStepType::Zone,
    2963             :                                     OutputProcessor::StoreType::Average,
    2964           1 :                                     thisZone.Name);
    2965           2 :                 SetupOutputVariable(state,
    2966             :                                     "Zone Thermal Comfort Control Fanger Low Setpoint PMV",
    2967             :                                     Constant::Units::None,
    2968           1 :                                     state.dataHeatBalFanSys->ZoneComfortControlsFanger(zoneNum).LowPMV,
    2969             :                                     OutputProcessor::TimeStepType::Zone,
    2970             :                                     OutputProcessor::StoreType::Average,
    2971           1 :                                     thisZone.Name);
    2972           2 :                 SetupOutputVariable(state,
    2973             :                                     "Zone Thermal Comfort Control Fanger High Setpoint PMV",
    2974             :                                     Constant::Units::None,
    2975           1 :                                     state.dataHeatBalFanSys->ZoneComfortControlsFanger(zoneNum).HighPMV,
    2976             :                                     OutputProcessor::TimeStepType::Zone,
    2977             :                                     OutputProcessor::StoreType::Average,
    2978           1 :                                     thisZone.Name);
    2979             :             }
    2980             :         }
    2981             : 
    2982             :         // CurrentModuleObject='ZoneList'
    2983         844 :         for (int Loop = 1; Loop <= state.dataHeatBal->NumOfZoneLists; ++Loop) {
    2984          96 :             SetupOutputVariable(state,
    2985             :                                 "Zone List Sensible Heating Energy",
    2986             :                                 Constant::Units::J,
    2987          48 :                                 state.dataHeatBal->ZoneListSNLoadHeatEnergy(Loop),
    2988             :                                 OutputProcessor::TimeStepType::System,
    2989             :                                 OutputProcessor::StoreType::Sum,
    2990          48 :                                 ZoneList(Loop).Name);
    2991          96 :             SetupOutputVariable(state,
    2992             :                                 "Zone List Sensible Cooling Energy",
    2993             :                                 Constant::Units::J,
    2994          48 :                                 state.dataHeatBal->ZoneListSNLoadCoolEnergy(Loop),
    2995             :                                 OutputProcessor::TimeStepType::System,
    2996             :                                 OutputProcessor::StoreType::Sum,
    2997          48 :                                 ZoneList(Loop).Name);
    2998          96 :             SetupOutputVariable(state,
    2999             :                                 "Zone List Sensible Heating Rate",
    3000             :                                 Constant::Units::W,
    3001          48 :                                 state.dataHeatBal->ZoneListSNLoadHeatRate(Loop),
    3002             :                                 OutputProcessor::TimeStepType::System,
    3003             :                                 OutputProcessor::StoreType::Average,
    3004          48 :                                 ZoneList(Loop).Name);
    3005          96 :             SetupOutputVariable(state,
    3006             :                                 "Zone List Sensible Cooling Rate",
    3007             :                                 Constant::Units::W,
    3008          48 :                                 state.dataHeatBal->ZoneListSNLoadCoolRate(Loop),
    3009             :                                 OutputProcessor::TimeStepType::System,
    3010             :                                 OutputProcessor::StoreType::Average,
    3011          48 :                                 ZoneList(Loop).Name);
    3012             :         } // Loop
    3013             : 
    3014             :         // CurrentModuleObject='ZoneGroup'
    3015         800 :         for (int Loop = 1; Loop <= state.dataHeatBal->NumOfZoneGroups; ++Loop) {
    3016           8 :             SetupOutputVariable(state,
    3017             :                                 "Zone Group Sensible Heating Energy",
    3018             :                                 Constant::Units::J,
    3019           4 :                                 state.dataHeatBal->ZoneGroupSNLoadHeatEnergy(Loop),
    3020             :                                 OutputProcessor::TimeStepType::System,
    3021             :                                 OutputProcessor::StoreType::Sum,
    3022           4 :                                 state.dataHeatBal->ZoneGroup(Loop).Name);
    3023           8 :             SetupOutputVariable(state,
    3024             :                                 "Zone Group Sensible Cooling Energy",
    3025             :                                 Constant::Units::J,
    3026           4 :                                 state.dataHeatBal->ZoneGroupSNLoadCoolEnergy(Loop),
    3027             :                                 OutputProcessor::TimeStepType::System,
    3028             :                                 OutputProcessor::StoreType::Sum,
    3029           4 :                                 state.dataHeatBal->ZoneGroup(Loop).Name);
    3030           8 :             SetupOutputVariable(state,
    3031             :                                 "Zone Group Sensible Heating Rate",
    3032             :                                 Constant::Units::W,
    3033           4 :                                 state.dataHeatBal->ZoneGroupSNLoadHeatRate(Loop),
    3034             :                                 OutputProcessor::TimeStepType::System,
    3035             :                                 OutputProcessor::StoreType::Average,
    3036           4 :                                 state.dataHeatBal->ZoneGroup(Loop).Name);
    3037           8 :             SetupOutputVariable(state,
    3038             :                                 "Zone Group Sensible Cooling Rate",
    3039             :                                 Constant::Units::W,
    3040           4 :                                 state.dataHeatBal->ZoneGroupSNLoadCoolRate(Loop),
    3041             :                                 OutputProcessor::TimeStepType::System,
    3042             :                                 OutputProcessor::StoreType::Average,
    3043           4 :                                 state.dataHeatBal->ZoneGroup(Loop).Name);
    3044             :         } // Loop
    3045             : 
    3046         796 :         state.dataZoneTempPredictorCorrector->InitZoneAirSetPointsOneTimeFlag = false;
    3047             :     }
    3048             : 
    3049             :     // Do the Begin Environment initializations
    3050    14404425 :     if (state.dataZoneTempPredictorCorrector->MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
    3051       55104 :         for (auto &thisZoneHB : state.dataZoneTempPredictorCorrector->zoneHeatBalance) {
    3052       48661 :             thisZoneHB.beginEnvironmentInit(state);
    3053        6443 :         }
    3054        6443 :         if (state.dataHeatBal->doSpaceHeatBalance) {
    3055         209 :             for (auto &thisSpaceHB : state.dataZoneTempPredictorCorrector->spaceHeatBalance) {
    3056         186 :                 thisSpaceHB.beginEnvironmentInit(state);
    3057          23 :             }
    3058             :         }
    3059        6443 :         TempZoneThermostatSetPoint = 0.0;
    3060        6443 :         state.dataHeatBalFanSys->AdapComfortCoolingSetPoint = 0.0;
    3061        6443 :         ZoneThermostatSetPointHi = 0.0;
    3062        6443 :         ZoneThermostatSetPointLo = 0.0;
    3063             : 
    3064        6443 :         state.dataHeatBalFanSys->LoadCorrectionFactor = 1.0;
    3065        6443 :         TempControlType = HVAC::ThermostatType::Uncontrolled;
    3066       55104 :         for (auto &e : state.dataZoneEnergyDemand->ZoneSysEnergyDemand) {
    3067       48661 :             e.beginEnvironmentInit();
    3068        6443 :         }
    3069       55104 :         for (auto &e : state.dataZoneEnergyDemand->ZoneSysMoistureDemand) {
    3070       48661 :             e.beginEnvironmentInit();
    3071        6443 :         }
    3072        6443 :         if (state.dataHeatBal->doSpaceHeatBalance) {
    3073         209 :             for (auto &e : state.dataZoneEnergyDemand->spaceSysEnergyDemand) {
    3074         186 :                 e.beginEnvironmentInit();
    3075          23 :             }
    3076         209 :             for (auto &e : state.dataZoneEnergyDemand->spaceSysMoistureDemand) {
    3077         186 :                 e.beginEnvironmentInit();
    3078          23 :             }
    3079             :         }
    3080             : 
    3081        6443 :         state.dataZoneEnergyDemand->DeadBandOrSetback = false;
    3082             : 
    3083       55104 :         for (auto &e : state.dataHeatBal->Zone)
    3084       55104 :             e.NoHeatToReturnAir = false;
    3085        6443 :         state.dataHeatBalFanSys->PreviousMeasuredZT1 = 0.0;     // Hybrid modeling
    3086        6443 :         state.dataHeatBalFanSys->PreviousMeasuredZT2 = 0.0;     // Hybrid modeling
    3087        6443 :         state.dataHeatBalFanSys->PreviousMeasuredZT3 = 0.0;     // Hybrid modeling
    3088        6443 :         state.dataHeatBalFanSys->PreviousMeasuredHumRat1 = 0.0; // Hybrid modeling
    3089        6443 :         state.dataHeatBalFanSys->PreviousMeasuredHumRat2 = 0.0; // Hybrid modeling
    3090        6443 :         state.dataHeatBalFanSys->PreviousMeasuredHumRat3 = 0.0; // Hybrid modeling
    3091             : 
    3092        6443 :         state.dataZoneTempPredictorCorrector->MyEnvrnFlag = false;
    3093             :     }
    3094             : 
    3095    14404425 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    3096    14346565 :         state.dataZoneTempPredictorCorrector->MyEnvrnFlag = true;
    3097             :     }
    3098             : 
    3099             :     // Do the Begin Day initializations
    3100    14404425 :     if (state.dataZoneTempPredictorCorrector->MyDayFlag && state.dataGlobal->BeginDayFlag) {
    3101       25411 :         state.dataZoneTempPredictorCorrector->MyDayFlag = false;
    3102             :     }
    3103             : 
    3104    14404425 :     if (!state.dataGlobal->BeginDayFlag) {
    3105    14251049 :         state.dataZoneTempPredictorCorrector->MyDayFlag = true;
    3106             :     }
    3107             : 
    3108   106977414 :     for (int Loop = 1; Loop <= state.dataZoneCtrls->NumTempControlledZones; ++Loop) {
    3109    92572989 :         if (state.dataZoneEquip->ZoneEquipInputsFilled && !state.dataZoneTempPredictorCorrector->ControlledZonesChecked) {
    3110        4191 :             if (!VerifyControlledZoneForThermostat(state, TempControlledZone(Loop).ZoneName)) {
    3111           0 :                 ShowSevereError(state,
    3112           0 :                                 format("{}Zone=\"{}\" has specified a Thermostatic control but is not a controlled zone.",
    3113             :                                        RoutineName,
    3114           0 :                                        TempControlledZone(Loop).ZoneName));
    3115           0 :                 ShowContinueError(state, "...must have a ZoneHVAC:EquipmentConnections specification for this zone.");
    3116           0 :                 state.dataZoneTempPredictorCorrector->ErrorsFound = true;
    3117             :             }
    3118             :         }
    3119             : 
    3120    92572989 :         if (TempControlledZone(Loop).ManageDemand) {
    3121           0 :             int ZoneNum = TempControlledZone(Loop).ActualZoneNum;
    3122             : 
    3123           0 :             switch (TempControlType(ZoneNum)) {
    3124           0 :             case HVAC::ThermostatType::SingleHeating:
    3125           0 :                 if (TempZoneThermostatSetPoint(ZoneNum) > TempControlledZone(Loop).HeatingResetLimit) {
    3126           0 :                     TempZoneThermostatSetPoint(ZoneNum) = TempControlledZone(Loop).HeatingResetLimit;
    3127           0 :                     ZoneThermostatSetPointLo(ZoneNum) = TempZoneThermostatSetPoint(ZoneNum);
    3128             :                 }
    3129           0 :                 break;
    3130           0 :             case HVAC::ThermostatType::SingleCooling:
    3131           0 :                 if (TempZoneThermostatSetPoint(ZoneNum) < TempControlledZone(Loop).CoolingResetLimit) {
    3132           0 :                     TempZoneThermostatSetPoint(ZoneNum) = TempControlledZone(Loop).CoolingResetLimit;
    3133           0 :                     ZoneThermostatSetPointHi(ZoneNum) = TempZoneThermostatSetPoint(ZoneNum);
    3134             :                 }
    3135           0 :                 break;
    3136           0 :             case HVAC::ThermostatType::SingleHeatCool:
    3137           0 :                 if ((TempZoneThermostatSetPoint(ZoneNum) > TempControlledZone(Loop).HeatingResetLimit) ||
    3138           0 :                     (TempZoneThermostatSetPoint(ZoneNum) < TempControlledZone(Loop).CoolingResetLimit)) {
    3139             : 
    3140           0 :                     TempControlType(ZoneNum) = HVAC::ThermostatType::DualSetPointWithDeadBand;
    3141           0 :                     TempControlTypeRpt(ZoneNum) = static_cast<int>(TempControlType(ZoneNum));
    3142           0 :                     ZoneThermostatSetPointLo(ZoneNum) = TempZoneThermostatSetPoint(ZoneNum);
    3143           0 :                     ZoneThermostatSetPointHi(ZoneNum) = TempZoneThermostatSetPoint(ZoneNum);
    3144             : 
    3145           0 :                     if (ZoneThermostatSetPointLo(ZoneNum) > TempControlledZone(Loop).HeatingResetLimit)
    3146           0 :                         ZoneThermostatSetPointLo(ZoneNum) = TempControlledZone(Loop).HeatingResetLimit;
    3147           0 :                     if (ZoneThermostatSetPointHi(ZoneNum) < TempControlledZone(Loop).CoolingResetLimit)
    3148           0 :                         ZoneThermostatSetPointHi(ZoneNum) = TempControlledZone(Loop).CoolingResetLimit;
    3149             :                 }
    3150           0 :                 break;
    3151           0 :             case HVAC::ThermostatType::DualSetPointWithDeadBand:
    3152           0 :                 if (ZoneThermostatSetPointLo(ZoneNum) > TempControlledZone(Loop).HeatingResetLimit)
    3153           0 :                     ZoneThermostatSetPointLo(ZoneNum) = TempControlledZone(Loop).HeatingResetLimit;
    3154           0 :                 if (ZoneThermostatSetPointHi(ZoneNum) < TempControlledZone(Loop).CoolingResetLimit)
    3155           0 :                     ZoneThermostatSetPointHi(ZoneNum) = TempControlledZone(Loop).CoolingResetLimit;
    3156           0 :                 break;
    3157           0 :             default:
    3158           0 :                 break;
    3159             :             }
    3160             :         }
    3161             :     }
    3162             : 
    3163    14414697 :     for (int Loop = 1; Loop <= state.dataZoneCtrls->NumComfortControlledZones; ++Loop) {
    3164       10272 :         if (state.dataZoneEquip->ZoneEquipInputsFilled && !state.dataZoneTempPredictorCorrector->ControlledZonesChecked) {
    3165           1 :             if (!VerifyControlledZoneForThermostat(state, ComfortControlledZone(Loop).ZoneName)) {
    3166           0 :                 ShowSevereError(state,
    3167           0 :                                 format("{}Zone=\"{}\" has specified a Comfort control but is not a controlled zone.",
    3168             :                                        RoutineName,
    3169           0 :                                        ComfortControlledZone(Loop).ZoneName));
    3170           0 :                 ShowContinueError(state, "...must have a ZoneHVAC:EquipmentConnections specification for this zone.");
    3171           0 :                 state.dataZoneTempPredictorCorrector->ErrorsFound = true;
    3172             :             }
    3173             :         }
    3174       10272 :         if (ComfortControlledZone(Loop).ManageDemand) {
    3175           0 :             int ZoneNum = ComfortControlledZone(Loop).ActualZoneNum;
    3176             : 
    3177           0 :             switch (state.dataHeatBalFanSys->ComfortControlType(ZoneNum)) {
    3178           0 :             case HVAC::ThermostatType::SingleHeating:
    3179           0 :                 if (TempZoneThermostatSetPoint(ZoneNum) >= ComfortControlledZone(Loop).HeatingResetLimit) {
    3180           0 :                     TempZoneThermostatSetPoint(ZoneNum) = ComfortControlledZone(Loop).HeatingResetLimit;
    3181           0 :                     ZoneThermostatSetPointLo(ZoneNum) = TempZoneThermostatSetPoint(ZoneNum);
    3182           0 :                     TempControlType(ZoneNum) = HVAC::ThermostatType::SingleHeating;
    3183           0 :                     TempControlTypeRpt(ZoneNum) = static_cast<int>(TempControlType(ZoneNum));
    3184             :                 }
    3185           0 :                 break;
    3186           0 :             case HVAC::ThermostatType::SingleCooling:
    3187           0 :                 if (TempZoneThermostatSetPoint(ZoneNum) <= ComfortControlledZone(Loop).CoolingResetLimit) {
    3188           0 :                     TempZoneThermostatSetPoint(ZoneNum) = ComfortControlledZone(Loop).CoolingResetLimit;
    3189           0 :                     ZoneThermostatSetPointHi(ZoneNum) = TempZoneThermostatSetPoint(ZoneNum);
    3190           0 :                     TempControlType(ZoneNum) = HVAC::ThermostatType::SingleCooling;
    3191           0 :                     TempControlTypeRpt(ZoneNum) = static_cast<int>(TempControlType(ZoneNum));
    3192             :                 }
    3193           0 :                 break;
    3194           0 :             case HVAC::ThermostatType::SingleHeatCool:
    3195           0 :                 if ((TempZoneThermostatSetPoint(ZoneNum) >= ComfortControlledZone(Loop).HeatingResetLimit) ||
    3196           0 :                     (TempZoneThermostatSetPoint(ZoneNum) <= ComfortControlledZone(Loop).CoolingResetLimit)) {
    3197             : 
    3198           0 :                     TempControlType(ZoneNum) = HVAC::ThermostatType::DualSetPointWithDeadBand;
    3199           0 :                     TempControlTypeRpt(ZoneNum) = static_cast<int>(TempControlType(ZoneNum));
    3200           0 :                     ZoneThermostatSetPointLo(ZoneNum) = TempZoneThermostatSetPoint(ZoneNum);
    3201           0 :                     ZoneThermostatSetPointHi(ZoneNum) = TempZoneThermostatSetPoint(ZoneNum);
    3202             : 
    3203           0 :                     if (ZoneThermostatSetPointLo(ZoneNum) >= ComfortControlledZone(Loop).HeatingResetLimit)
    3204           0 :                         ZoneThermostatSetPointLo(ZoneNum) = ComfortControlledZone(Loop).HeatingResetLimit;
    3205           0 :                     if (ZoneThermostatSetPointHi(ZoneNum) <= ComfortControlledZone(Loop).CoolingResetLimit)
    3206           0 :                         ZoneThermostatSetPointHi(ZoneNum) = ComfortControlledZone(Loop).CoolingResetLimit;
    3207             :                 }
    3208           0 :                 break;
    3209           0 :             case HVAC::ThermostatType::DualSetPointWithDeadBand:
    3210           0 :                 TempControlType(ZoneNum) = HVAC::ThermostatType::DualSetPointWithDeadBand;
    3211           0 :                 TempControlTypeRpt(ZoneNum) = static_cast<int>(TempControlType(ZoneNum));
    3212           0 :                 if (ZoneThermostatSetPointLo(ZoneNum) >= ComfortControlledZone(Loop).HeatingResetLimit)
    3213           0 :                     ZoneThermostatSetPointLo(ZoneNum) = ComfortControlledZone(Loop).HeatingResetLimit;
    3214           0 :                 if (ZoneThermostatSetPointHi(ZoneNum) <= ComfortControlledZone(Loop).CoolingResetLimit)
    3215           0 :                     ZoneThermostatSetPointHi(ZoneNum) = ComfortControlledZone(Loop).CoolingResetLimit;
    3216           0 :                 break;
    3217           0 :             default:
    3218           0 :                 break;
    3219             :             }
    3220             :         } // Demand manager
    3221             :     }
    3222             : 
    3223    14404425 :     if (state.dataZoneTempPredictorCorrector->ErrorsFound) {
    3224           0 :         ShowFatalError(state, "InitZoneAirSetpoints - program terminates due to previous condition.");
    3225             :     }
    3226             : 
    3227    14404425 :     if (state.dataZoneEquip->ZoneEquipInputsFilled) {
    3228    14404425 :         state.dataZoneTempPredictorCorrector->ControlledZonesChecked = true;
    3229             :     }
    3230    14404425 : }
    3231             : 
    3232       48847 : void ZoneSpaceHeatBalanceData::beginEnvironmentInit(EnergyPlusData &state)
    3233             : {
    3234      244235 :     for (int i = 0; i <= 3; ++i) {
    3235      195388 :         this->ZTM[i] = 0.0;
    3236      195388 :         this->WPrevZoneTS[i] = state.dataEnvrn->OutHumRat;
    3237      195388 :         this->DSWPrevZoneTS[i] = state.dataEnvrn->OutHumRat;
    3238      195388 :         this->WPrevZoneTSTemp[i] = 0.0;
    3239             :     }
    3240       48847 :     this->WTimeMinusP = state.dataEnvrn->OutHumRat;
    3241       48847 :     this->W1 = state.dataEnvrn->OutHumRat;
    3242       48847 :     this->WMX = state.dataEnvrn->OutHumRat;
    3243       48847 :     this->WM2 = state.dataEnvrn->OutHumRat;
    3244       48847 :     this->airHumRatTemp = 0.0;
    3245       48847 :     this->tempIndLoad = 0.0;
    3246       48847 :     this->tempDepLoad = 0.0;
    3247       48847 :     this->airRelHum = 0.0;
    3248       48847 :     this->AirPowerCap = 0.0;
    3249       48847 :     this->T1 = 0.0;
    3250       48847 : }
    3251             : 
    3252        5072 : void ZoneSpaceHeatBalanceData::setUpOutputVars(EnergyPlusData &state, std::string_view prefix, std::string const &name)
    3253             : {
    3254       15216 :     SetupOutputVariable(state,
    3255       10144 :                         format("{} Air Temperature", prefix),
    3256             :                         Constant::Units::C,
    3257        5072 :                         this->ZT,
    3258             :                         OutputProcessor::TimeStepType::System,
    3259             :                         OutputProcessor::StoreType::Average,
    3260             :                         name);
    3261       15216 :     SetupOutputVariable(state,
    3262       10144 :                         format("{} Air Humidity Ratio", prefix),
    3263             :                         Constant::Units::None,
    3264        5072 :                         this->airHumRat,
    3265             :                         OutputProcessor::TimeStepType::System,
    3266             :                         OutputProcessor::StoreType::Average,
    3267             :                         name);
    3268       15216 :     SetupOutputVariable(state,
    3269       10144 :                         format("{} Air Relative Humidity", prefix),
    3270             :                         Constant::Units::Perc,
    3271        5072 :                         this->airRelHum,
    3272             :                         OutputProcessor::TimeStepType::System,
    3273             :                         OutputProcessor::StoreType::Average,
    3274             :                         name);
    3275       15216 :     SetupOutputVariable(state,
    3276       10144 :                         format("{} Mean Radiant Temperature", prefix),
    3277             :                         Constant::Units::C,
    3278        5072 :                         this->MRT,
    3279             :                         OutputProcessor::TimeStepType::Zone,
    3280             :                         OutputProcessor::StoreType::Average,
    3281             :                         name);
    3282        5072 : }
    3283             : 
    3284     3866727 : void PredictSystemLoads(EnergyPlusData &state,
    3285             :                         bool const ShortenTimeStepSys,
    3286             :                         bool const UseZoneTimeStepHistory, // if true then use zone timestep history, if false use system time step
    3287             :                         Real64 const PriorTimeStep         // the old value for timestep length is passed for possible use in interpolating
    3288             : )
    3289             : {
    3290             : 
    3291             :     // SUBROUTINE INFORMATION:
    3292             :     //       AUTHOR         Russ Taylor
    3293             :     //       DATE WRITTEN   May 1997
    3294             :     //       MODIFIED       na
    3295             :     //       RE-ENGINEERED  July 2003 (Peter Graham Ellis)
    3296             : 
    3297             :     // PURPOSE OF THIS SUBROUTINE:
    3298             :     // This subroutine is responsible for determining
    3299             :     // how much of each type of energy every zone requires.
    3300             :     // In effect, this subroutine defines and simulates all
    3301             :     // the system types and in the case of hybrid systems
    3302             :     // which use more than one type of energy must determine
    3303             :     // how to apportion the load. An example of a hybrid system
    3304             :     // is a water loop heat pump with supplemental air.  In
    3305             :     // this case, a zone will require water from the loop and
    3306             :     // cooled or heated air from the air system. A simpler
    3307             :     // example would be a VAV system with baseboard heaters.
    3308             : 
    3309             :     //  Basic Air System Types
    3310             :     //  1) Constant Volume Single Duct
    3311             :     //  2) Variable Volume Single Duct
    3312             :     //  3) Constant Volume Dual Duct
    3313             :     //  4) Variable Volume Dual Duct
    3314             : 
    3315             :     // METHODOLOGY EMPLOYED:
    3316             :     // 0.  Determine if simulation has downstepped and readjust history and revert node results
    3317             :     // 1.  Determine zone load - this is zone temperature dependent
    3318             :     // 2.  Determine balance point - the temperature at which the
    3319             :     //     zone load is balanced by the system output. The way the
    3320             :     //     balance point is determined will be different depending on
    3321             :     //     the type of system being simulated.
    3322             :     // 3.  Calculate zone energy requirements
    3323             : 
    3324             :     // Staged thermostat setpoint
    3325     3866727 :     if (state.dataZoneTempPredictorCorrector->NumStageCtrZone > 0) {
    3326      127321 :         for (int RelativeZoneNum = 1; RelativeZoneNum <= state.dataZoneTempPredictorCorrector->NumStageCtrZone; ++RelativeZoneNum) {
    3327      100893 :             auto &thisStageControlZone = state.dataZoneCtrls->StageControlledZone(RelativeZoneNum);
    3328      100893 :             int ActualZoneNum = thisStageControlZone.ActualZoneNum;
    3329      100893 :             auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ActualZoneNum);
    3330      100893 :             auto &thisZoneThermostatSetPointLo = state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ActualZoneNum);
    3331      100893 :             auto &thisZoneThermostatSetPointHi = state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ActualZoneNum);
    3332      100893 :             Real64 ZoneT = thisZoneHB.MAT; // Zone temperature at previous time step
    3333      100893 :             if (ShortenTimeStepSys) ZoneT = thisZoneHB.XMPT;
    3334      100893 :             thisStageControlZone.HeatSetPoint = ScheduleManager::GetCurrentScheduleValue(state, thisStageControlZone.HSBchedIndex);
    3335      100893 :             thisStageControlZone.CoolSetPoint = ScheduleManager::GetCurrentScheduleValue(state, thisStageControlZone.CSBchedIndex);
    3336      100893 :             if (thisStageControlZone.HeatSetPoint >= thisStageControlZone.CoolSetPoint) {
    3337           0 :                 ++thisStageControlZone.StageErrCount;
    3338           0 :                 if (thisStageControlZone.StageErrCount < 2) {
    3339           0 :                     ShowWarningError(
    3340             :                         state,
    3341           0 :                         format("ZoneControl:Thermostat:StagedDualSetpoint: The heating setpoint is equal to or above the cooling setpoint in {}",
    3342           0 :                                thisStageControlZone.Name));
    3343           0 :                     ShowContinueError(state, "The zone heating setpoint is set to the cooling setpoint - 0.1C.");
    3344           0 :                     ShowContinueErrorTimeStamp(state, "Occurrence info:");
    3345             :                 } else {
    3346           0 :                     ShowRecurringWarningErrorAtEnd(state,
    3347             :                                                    "The heating setpoint is still above the cooling setpoint",
    3348           0 :                                                    thisStageControlZone.StageErrIndex,
    3349           0 :                                                    thisStageControlZone.HeatSetPoint,
    3350           0 :                                                    thisStageControlZone.HeatSetPoint);
    3351             :                 }
    3352           0 :                 thisStageControlZone.HeatSetPoint = thisStageControlZone.CoolSetPoint - 0.1; //???????????
    3353             :             }
    3354             :             // Determine either cooling or heating
    3355      100893 :             if (thisStageControlZone.CoolSetPoint < ZoneT) { // Cooling
    3356       19407 :                 Real64 SetpointOffset = ZoneT - thisStageControlZone.CoolSetPoint;
    3357       19407 :                 int Itemp = 0;
    3358       69285 :                 for (int I = 1; I <= thisStageControlZone.NumOfCoolStages; ++I) {
    3359       49878 :                     if (SetpointOffset >= thisStageControlZone.CoolTOffset(I)) {
    3360       30440 :                         Itemp = -I;
    3361             :                     }
    3362             :                 }
    3363       19407 :                 state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ActualZoneNum).StageNum = Itemp;
    3364       19407 :                 if (SetpointOffset >= 0.5 * thisStageControlZone.CoolThroRange) {
    3365        7226 :                     thisZoneThermostatSetPointHi = thisStageControlZone.CoolSetPoint - 0.5 * thisStageControlZone.CoolThroRange;
    3366             :                 } else {
    3367       12181 :                     thisZoneThermostatSetPointHi = thisStageControlZone.CoolSetPoint + 0.5 * thisStageControlZone.CoolThroRange;
    3368             :                 }
    3369       19407 :                 thisZoneThermostatSetPointLo = thisZoneThermostatSetPointHi;
    3370       81486 :             } else if (thisStageControlZone.HeatSetPoint > ZoneT) { // heating
    3371       37113 :                 Real64 SetpointOffset = ZoneT - thisStageControlZone.HeatSetPoint;
    3372       37113 :                 int Itemp = 0;
    3373       86506 :                 for (int I = 1; I <= thisStageControlZone.NumOfHeatStages; ++I) {
    3374       49393 :                     if (std::abs(SetpointOffset) >= std::abs(thisStageControlZone.HeatTOffset(I))) {
    3375       46615 :                         Itemp = I;
    3376             :                     }
    3377             :                 }
    3378       37113 :                 state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ActualZoneNum).StageNum = Itemp;
    3379       37113 :                 if (std::abs(SetpointOffset) >= 0.5 * thisStageControlZone.CoolThroRange) {
    3380       25332 :                     thisZoneThermostatSetPointLo = thisStageControlZone.HeatSetPoint + 0.5 * thisStageControlZone.HeatThroRange;
    3381             :                 } else {
    3382       11781 :                     thisZoneThermostatSetPointLo = thisStageControlZone.HeatSetPoint - 0.5 * thisStageControlZone.HeatThroRange;
    3383             :                 }
    3384       37113 :                 thisZoneThermostatSetPointHi = thisZoneThermostatSetPointLo;
    3385             :             } else {
    3386       44373 :                 thisZoneThermostatSetPointHi = thisStageControlZone.CoolSetPoint + 0.5 * thisStageControlZone.CoolThroRange;
    3387       44373 :                 thisZoneThermostatSetPointLo = thisStageControlZone.HeatSetPoint - 0.5 * thisStageControlZone.HeatThroRange;
    3388       44373 :                 state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ActualZoneNum).StageNum = 0;
    3389             :             }
    3390             :             // SpaceHB TODO: For now, set space stagenum to zone stagenum - later need to see what space the thermostat is in
    3391      100893 :             if (state.dataHeatBal->doSpaceHeatBalance) {
    3392           0 :                 for (int spaceNum : state.dataHeatBal->Zone(ActualZoneNum).spaceIndexes) {
    3393           0 :                     state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).StageNum =
    3394           0 :                         state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ActualZoneNum).StageNum;
    3395           0 :                 }
    3396             :             }
    3397             :         }
    3398             :     }
    3399             : 
    3400             :     // Setpoint revision for onoff thermostat
    3401     3866727 :     if (state.dataZoneTempPredictorCorrector->NumOnOffCtrZone > 0) {
    3402       93112 :         Real64 TempTole = 0.02;
    3403             :         Real64 Tprev;
    3404      186224 :         for (int RelativeZoneNum = 1; RelativeZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++RelativeZoneNum) {
    3405       93112 :             auto &thisTempControlledZone = state.dataZoneCtrls->TempControlledZone(RelativeZoneNum);
    3406       93112 :             if (thisTempControlledZone.DeltaTCutSet > 0.0) {
    3407       93112 :                 if (ShortenTimeStepSys) {
    3408       16254 :                     thisTempControlledZone.HeatModeLast = thisTempControlledZone.HeatModeLastSave;
    3409       16254 :                     thisTempControlledZone.CoolModeLast = thisTempControlledZone.CoolModeLastSave;
    3410             :                 } else {
    3411       76858 :                     thisTempControlledZone.HeatModeLastSave = thisTempControlledZone.HeatModeLast;
    3412       76858 :                     thisTempControlledZone.CoolModeLastSave = thisTempControlledZone.CoolModeLast;
    3413             :                 }
    3414       93112 :                 auto &thisTempZoneThermostatSetPoint = state.dataHeatBalFanSys->TempZoneThermostatSetPoint(thisTempControlledZone.ActualZoneNum);
    3415       93112 :                 auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(thisTempControlledZone.ActualZoneNum);
    3416       93112 :                 auto &thisZoneThermostatSetPointLo = state.dataHeatBalFanSys->ZoneThermostatSetPointLo(thisTempControlledZone.ActualZoneNum);
    3417       93112 :                 auto &thisZoneThermostatSetPointHi = state.dataHeatBalFanSys->ZoneThermostatSetPointHi(thisTempControlledZone.ActualZoneNum);
    3418             : 
    3419       93112 :                 thisTempControlledZone.CoolOffFlag = false;
    3420       93112 :                 thisTempControlledZone.HeatOffFlag = false;
    3421       93112 :                 if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::ThirdOrder) {
    3422       93112 :                     Tprev = thisZoneHB.MAT;
    3423       93112 :                     if (ShortenTimeStepSys) Tprev = thisZoneHB.XMPT;
    3424             :                 } else {
    3425           0 :                     Tprev = thisZoneHB.T1;
    3426             :                 }
    3427             : 
    3428       93112 :                 switch (state.dataHeatBalFanSys->TempControlType(thisTempControlledZone.ActualZoneNum)) {
    3429           0 :                 case HVAC::ThermostatType::SingleHeating:
    3430           0 :                     thisTempZoneThermostatSetPoint = thisTempControlledZone.ZoneThermostatSetPointLo;
    3431           0 :                     thisZoneThermostatSetPointLo = thisTempControlledZone.ZoneThermostatSetPointLo;
    3432           0 :                     if (Tprev < thisTempControlledZone.ZoneThermostatSetPointLo + TempTole) {
    3433           0 :                         thisTempZoneThermostatSetPoint = thisTempControlledZone.ZoneThermostatSetPointLo + thisTempControlledZone.DeltaTCutSet;
    3434           0 :                         thisZoneThermostatSetPointLo = thisTempZoneThermostatSetPoint;
    3435           0 :                     } else if (Tprev > thisTempControlledZone.ZoneThermostatSetPointLo &&
    3436           0 :                                (Tprev < thisTempControlledZone.ZoneThermostatSetPointLo + thisTempControlledZone.DeltaTCutSet - TempTole)) {
    3437           0 :                         thisTempZoneThermostatSetPoint = thisTempControlledZone.ZoneThermostatSetPointLo + thisTempControlledZone.DeltaTCutSet;
    3438           0 :                         thisZoneThermostatSetPointLo = thisTempZoneThermostatSetPoint;
    3439             :                     } else {
    3440           0 :                         thisTempControlledZone.HeatOffFlag = true;
    3441             :                     }
    3442           0 :                     if (thisTempControlledZone.HeatModeLast && Tprev > thisTempControlledZone.ZoneThermostatSetPointLo) {
    3443           0 :                         thisTempZoneThermostatSetPoint = thisTempControlledZone.ZoneThermostatSetPointLo;
    3444           0 :                         thisZoneThermostatSetPointLo = thisTempControlledZone.ZoneThermostatSetPointLo;
    3445           0 :                         thisTempControlledZone.HeatOffFlag = true;
    3446             :                     }
    3447           0 :                     break;
    3448           0 :                 case HVAC::ThermostatType::SingleCooling:
    3449           0 :                     thisTempZoneThermostatSetPoint = thisTempControlledZone.ZoneThermostatSetPointHi;
    3450           0 :                     thisZoneThermostatSetPointHi = thisTempControlledZone.ZoneThermostatSetPointHi;
    3451           0 :                     if (Tprev > thisTempControlledZone.ZoneThermostatSetPointHi - TempTole) {
    3452           0 :                         thisTempZoneThermostatSetPoint = thisTempControlledZone.ZoneThermostatSetPointHi - thisTempControlledZone.DeltaTCutSet;
    3453           0 :                         thisZoneThermostatSetPointHi = thisTempZoneThermostatSetPoint;
    3454           0 :                     } else if (Tprev < thisTempControlledZone.ZoneThermostatSetPointHi &&
    3455           0 :                                Tprev > thisTempControlledZone.ZoneThermostatSetPointHi - thisTempControlledZone.DeltaTCutSet + TempTole) {
    3456           0 :                         thisTempZoneThermostatSetPoint = thisTempControlledZone.ZoneThermostatSetPointHi - thisTempControlledZone.DeltaTCutSet;
    3457           0 :                         thisZoneThermostatSetPointHi = thisTempZoneThermostatSetPoint;
    3458             :                     } else {
    3459           0 :                         thisTempControlledZone.CoolOffFlag = true;
    3460             :                     }
    3461           0 :                     if (thisTempControlledZone.CoolModeLast && Tprev < thisTempControlledZone.ZoneThermostatSetPointHi) {
    3462           0 :                         thisTempZoneThermostatSetPoint = thisTempControlledZone.ZoneThermostatSetPointHi;
    3463           0 :                         thisZoneThermostatSetPointHi = thisTempControlledZone.ZoneThermostatSetPointHi;
    3464           0 :                         thisTempControlledZone.CoolOffFlag = true;
    3465             :                     }
    3466           0 :                     break;
    3467       93112 :                 case HVAC::ThermostatType::DualSetPointWithDeadBand:
    3468       93112 :                     thisZoneThermostatSetPointHi = thisTempControlledZone.ZoneThermostatSetPointHi;
    3469       93112 :                     thisZoneThermostatSetPointLo = thisTempControlledZone.ZoneThermostatSetPointLo;
    3470       93112 :                     if (Tprev > thisTempControlledZone.ZoneThermostatSetPointHi - TempTole) {
    3471        6917 :                         thisZoneThermostatSetPointHi = thisTempControlledZone.ZoneThermostatSetPointHi - thisTempControlledZone.DeltaTCutSet;
    3472       86195 :                     } else if (Tprev < thisTempControlledZone.ZoneThermostatSetPointHi &&
    3473       86195 :                                Tprev > thisTempControlledZone.ZoneThermostatSetPointHi - thisTempControlledZone.DeltaTCutSet + TempTole) {
    3474       31484 :                         thisZoneThermostatSetPointHi = thisTempControlledZone.ZoneThermostatSetPointHi - thisTempControlledZone.DeltaTCutSet;
    3475             :                     } else {
    3476       54711 :                         thisTempControlledZone.CoolOffFlag = true;
    3477             :                     }
    3478       93112 :                     if (thisTempControlledZone.CoolModeLast && Tprev < thisTempControlledZone.ZoneThermostatSetPointHi) {
    3479       66971 :                         thisZoneThermostatSetPointHi = thisTempControlledZone.ZoneThermostatSetPointHi;
    3480       66971 :                         thisTempControlledZone.CoolOffFlag = true;
    3481             :                     }
    3482             : 
    3483       93112 :                     if (Tprev < thisTempControlledZone.ZoneThermostatSetPointLo + TempTole) {
    3484       14898 :                         thisZoneThermostatSetPointLo = thisTempControlledZone.ZoneThermostatSetPointLo + thisTempControlledZone.DeltaTCutSet;
    3485       78214 :                     } else if (Tprev > thisTempControlledZone.ZoneThermostatSetPointLo &&
    3486       78214 :                                (Tprev < thisTempControlledZone.ZoneThermostatSetPointLo + thisTempControlledZone.DeltaTCutSet - TempTole)) {
    3487       23406 :                         thisZoneThermostatSetPointLo = thisTempControlledZone.ZoneThermostatSetPointLo + thisTempControlledZone.DeltaTCutSet;
    3488             :                     } else {
    3489       54808 :                         thisTempControlledZone.HeatOffFlag = true;
    3490             :                     }
    3491       93112 :                     if (thisTempControlledZone.HeatModeLast && Tprev > thisTempControlledZone.ZoneThermostatSetPointLo) {
    3492       46868 :                         thisZoneThermostatSetPointLo = thisTempControlledZone.ZoneThermostatSetPointLo;
    3493       46868 :                         thisTempControlledZone.HeatOffFlag = true;
    3494             :                     }
    3495             :                     // check setpoint for both and provde an error message
    3496       93112 :                     if (thisZoneThermostatSetPointLo >= thisZoneThermostatSetPointHi) {
    3497           0 :                         ShowSevereError(state,
    3498             :                                         "DualSetPointWithDeadBand: When Temperature Difference Between Cutout And Setpoint is applied, the heating "
    3499             :                                         "setpoint is greater than the cooling setpoint. ");
    3500           0 :                         ShowContinueErrorTimeStamp(state,
    3501           0 :                                                    format("occurs in Zone={}", state.dataHeatBal->Zone(thisTempControlledZone.ActualZoneNum).Name));
    3502           0 :                         ShowContinueError(state, format("Zone Heating ThermostatSetPoint={:.2R}", thisZoneThermostatSetPointLo));
    3503           0 :                         ShowContinueError(state, format("Zone Cooling ThermostatSetPoint={:.2R}", thisZoneThermostatSetPointHi));
    3504           0 :                         ShowFatalError(state, "Program terminates due to above conditions.");
    3505             :                     }
    3506       93112 :                     break;
    3507           0 :                 default:
    3508           0 :                     break;
    3509             :                 }
    3510             :             }
    3511             :         }
    3512             :     }
    3513             : 
    3514    33784504 :     for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    3515    29917777 :         auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum);
    3516    29917777 :         thisZoneHB.predictSystemLoad(state, ShortenTimeStepSys, UseZoneTimeStepHistory, PriorTimeStep, zoneNum);
    3517    59899418 :         for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    3518    29981641 :             if (state.dataHeatBal->doSpaceHeatBalance) {
    3519       86394 :                 state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).predictSystemLoad(
    3520             :                     state, ShortenTimeStepSys, UseZoneTimeStepHistory, PriorTimeStep, zoneNum, spaceNum);
    3521    29895247 :             } else if (ShortenTimeStepSys) {
    3522     2872174 :                 state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).MAT = thisZoneHB.MAT;
    3523     2872174 :                 state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).airHumRat = thisZoneHB.airHumRat;
    3524             :             }
    3525    29917777 :         }
    3526             :     }
    3527     3866727 :     if (state.dataZoneTempPredictorCorrector->NumOnOffCtrZone > 0) {
    3528      186224 :         for (int RelativeZoneNum = 1; RelativeZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++RelativeZoneNum) {
    3529       93112 :             auto &thisTempControlledZone = state.dataZoneCtrls->TempControlledZone(RelativeZoneNum);
    3530       93112 :             if (thisTempControlledZone.DeltaTCutSet > 0.0) {
    3531       93112 :                 int ZoneNum = thisTempControlledZone.ActualZoneNum;
    3532       93112 :                 if (thisTempControlledZone.CoolOffFlag && state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).TotalOutputRequired >= 0.0) {
    3533       66033 :                     thisTempControlledZone.CoolModeLast = true;
    3534             :                 } else {
    3535       27079 :                     thisTempControlledZone.CoolModeLast = false;
    3536             :                 }
    3537       93112 :                 if (thisTempControlledZone.HeatOffFlag && state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).TotalOutputRequired <= 0.0) {
    3538       46851 :                     thisTempControlledZone.HeatModeLast = true;
    3539             :                 } else {
    3540       46261 :                     thisTempControlledZone.HeatModeLast = false;
    3541             :                 }
    3542             :             }
    3543             :         }
    3544             :     }
    3545     3866727 : }
    3546    30004171 : void ZoneSpaceHeatBalanceData::predictSystemLoad(
    3547             :     EnergyPlusData &state,
    3548             :     bool const shortenTimeStepSys,
    3549             :     bool const useZoneTimeStepHistory, // if true then use zone timestep history, if false use system time step
    3550             :     Real64 const priorTimeStep,        // the old value for timestep length is passed for possible use in interpolating
    3551             :     int zoneNum,
    3552             :     int spaceNum)
    3553             : {
    3554    30004171 :     assert(zoneNum > 0);
    3555    30004171 :     this->updateTemperatures(state, shortenTimeStepSys, useZoneTimeStepHistory, priorTimeStep, zoneNum, spaceNum);
    3556             : 
    3557    30004171 :     Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    3558    30004171 :     Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    3559             : 
    3560    30004171 :     Real64 volume = 0.0;
    3561    30004171 :     if (spaceNum > 0) {
    3562       86394 :         volume = state.dataHeatBal->space(spaceNum).Volume;
    3563             :     } else {
    3564    29917777 :         volume = state.dataHeatBal->Zone(zoneNum).Volume;
    3565             :     }
    3566             : 
    3567    30004171 :     this->AirPowerCap = volume * state.dataHeatBal->Zone(zoneNum).ZoneVolCapMultpSens *
    3568    30004171 :                         Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->MAT, this->airHumRat) *
    3569    30004171 :                         Psychrometrics::PsyCpAirFnW(this->airHumRat) / TimeStepSysSec;
    3570    30004171 :     Real64 RAFNFrac = 0.0;
    3571             : 
    3572             :     // Calculate the various heat balance sums
    3573             : 
    3574             :     // NOTE: SumSysMCp and SumSysMCpT are not used in the predict step
    3575    30004171 :     this->calcZoneOrSpaceSums(state, false, zoneNum, spaceNum);
    3576             : 
    3577             :     // Sum all convective internal gains except for people: SumIntGainExceptPeople
    3578    30004171 :     if (spaceNum == 0 && state.dataHybridModel->FlagHybridModel_PC) {
    3579        8212 :         this->SumIntGainExceptPeople = 0.0;
    3580        8212 :         this->SumIntGainExceptPeople = InternalHeatGains::SumAllInternalConvectionGainsExceptPeople(state, zoneNum);
    3581             :     }
    3582             : 
    3583    30004171 :     this->TempDepCoef = this->SumHA + this->SumMCp;
    3584    30004171 :     this->TempIndCoef = this->SumIntGain + this->SumHATsurf - this->SumHATref + this->SumMCpT + this->SysDepZoneLoadsLagged;
    3585    30004171 :     this->TempHistoryTerm = this->AirPowerCap * (3.0 * this->ZTM[0] - (3.0 / 2.0) * this->ZTM[1] + (1.0 / 3.0) * this->ZTM[2]);
    3586    30004171 :     this->tempDepLoad = (11.0 / 6.0) * this->AirPowerCap + this->TempDepCoef;
    3587    30004171 :     this->tempIndLoad = this->TempHistoryTerm + this->TempIndCoef;
    3588    30004171 :     if (state.dataRoomAir->anyNonMixingRoomAirModel) {
    3589      160042 :         if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    3590             :             // RoomAirflowNetworkModel - make dynamic term independent of TimeStepSys
    3591        7413 :             auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
    3592        7413 :             if (afnZoneInfo.IsUsed) {
    3593        7413 :                 int RoomAirNode = afnZoneInfo.ControlAirNodeID;
    3594        7413 :                 RoomAir::LoadPredictionRoomAirModelAFN(state, zoneNum, RoomAirNode);
    3595        7413 :                 this->TempDepCoef = afnZoneInfo.Node(RoomAirNode).SumHA + afnZoneInfo.Node(RoomAirNode).SumLinkMCp;
    3596        7413 :                 this->TempIndCoef = afnZoneInfo.Node(RoomAirNode).SumIntSensibleGain + afnZoneInfo.Node(RoomAirNode).SumHATsurf -
    3597        7413 :                                     afnZoneInfo.Node(RoomAirNode).SumHATref + afnZoneInfo.Node(RoomAirNode).SumLinkMCpT +
    3598        7413 :                                     afnZoneInfo.Node(RoomAirNode).SysDepZoneLoadsLagged;
    3599        7413 :                 this->AirPowerCap = afnZoneInfo.Node(RoomAirNode).AirVolume * state.dataHeatBal->Zone(zoneNum).ZoneVolCapMultpSens *
    3600        7413 :                                     afnZoneInfo.Node(RoomAirNode).RhoAir * afnZoneInfo.Node(RoomAirNode).CpAir / TimeStepSysSec;
    3601        7413 :                 this->TempHistoryTerm = this->AirPowerCap * (3.0 * this->ZTM[0] - (3.0 / 2.0) * this->ZTM[1] + (1.0 / 3.0) * this->ZTM[2]);
    3602        7413 :                 this->tempDepLoad = (11.0 / 6.0) * this->AirPowerCap + this->TempDepCoef;
    3603        7413 :                 this->tempIndLoad = this->TempHistoryTerm + this->TempIndCoef;
    3604        7413 :                 if (afnZoneInfo.Node(RoomAirNode).HasHVACAssigned) RAFNFrac = afnZoneInfo.Node(RoomAirNode).HVAC(1).SupplyFraction;
    3605             :             }
    3606             :         }
    3607             :     }
    3608             : 
    3609             :     // Exact solution or Euler method
    3610    30004171 :     state.dataHVACGlobal->ShortenTimeStepSysRoomAir = false;
    3611    30004171 :     if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
    3612    13027363 :         if (shortenTimeStepSys && TimeStepSys < state.dataGlobal->TimeStepZone) {
    3613     1580879 :             if (state.dataHVACGlobal->PreviousTimeStep < state.dataGlobal->TimeStepZone) {
    3614     1280336 :                 this->T1 = this->TM2;
    3615     1280336 :                 this->W1 = this->WM2;
    3616     1280336 :                 if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    3617           0 :                     auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
    3618           0 :                     for (auto &afnNode : afnZoneInfo.Node) {
    3619           0 :                         afnNode.AirTempT1 = afnNode.AirTempT2;
    3620           0 :                         afnNode.HumRatT1 = afnNode.HumRatT2;
    3621             :                     }
    3622             :                 }
    3623             :             } else {
    3624      300543 :                 this->T1 = this->TMX;
    3625      300543 :                 this->W1 = this->WMX;
    3626      300543 :                 if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    3627           0 :                     auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
    3628           0 :                     for (auto &afnNode : afnZoneInfo.Node) {
    3629           0 :                         afnNode.AirTempT1 = afnNode.AirTempTX;
    3630           0 :                         afnNode.HumRatT1 = afnNode.HumRatTX;
    3631             :                     }
    3632             :                 }
    3633             :             }
    3634     1580879 :             state.dataHVACGlobal->ShortenTimeStepSysRoomAir = true;
    3635             :         } else {
    3636    11446484 :             this->T1 = this->ZT;
    3637    11446484 :             this->W1 = this->airHumRat;
    3638    11446484 :             if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    3639           0 :                 auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
    3640           0 :                 for (auto &afnNode : afnZoneInfo.Node) {
    3641           0 :                     afnNode.AirTempT1 = afnNode.AirTemp;
    3642           0 :                     afnNode.HumRatT1 = afnNode.HumRat;
    3643             :                 }
    3644             :             }
    3645             :         }
    3646    13027363 :         this->tempDepLoad = this->TempDepCoef;
    3647    13027363 :         this->tempIndLoad = this->TempIndCoef;
    3648             :     }
    3649             : 
    3650             :     // Calculate the predicted zone load to be provided by the system with the given desired zone air temperature
    3651    30004171 :     this->calcPredictedSystemLoad(state, RAFNFrac, zoneNum, spaceNum);
    3652             : 
    3653             :     // Calculate the predicted zone load to be provided by the system with the given desired humidity ratio
    3654    30004171 :     this->calcPredictedHumidityRatio(state, RAFNFrac, zoneNum, spaceNum);
    3655    30004171 : }
    3656             : 
    3657     2804720 : void CalcZoneAirTempSetPoints(EnergyPlusData &state)
    3658             : {
    3659             : 
    3660             :     // SUBROUTINE INFORMATION:
    3661             :     //       AUTHOR         Russ Taylor
    3662             :     //       DATE WRITTEN   Nov 1997
    3663             :     //       MODIFIED       Aug 2013, Xiufeng Pang (XP) - Added code for updating set points during
    3664             :     //                      optimum start period
    3665             :     //       RE-ENGINEERED  na
    3666             : 
    3667             :     // PURPOSE OF THIS SUBROUTINE:
    3668             :     // This routine sets what the setpoints for each controlled zone should be based on schedules.
    3669             :     // This is called each time step.
    3670             : 
    3671             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3672             :     int RelativeZoneNum;
    3673             :     int ActualZoneNum;
    3674             :     int TempControlSchedIndex;
    3675             :     int SetPointTempSchedIndexHot;
    3676             :     int SetPointTempSchedIndexCold;
    3677             :     int SchedNameIndex;
    3678     2804720 :     Array2D<Real64> DaySPValues; // Day room temp setpoint values - for optimum start
    3679             :     int OccStartTime;            // Occupancy start time - for optimum start
    3680             :     Real64 DeltaT;               // Temperature difference between cutout and setpoint
    3681             : 
    3682     2804720 :     auto &Zone = state.dataHeatBal->Zone;
    3683     2804720 :     auto &TempControlledZone = state.dataZoneCtrls->TempControlledZone;
    3684     2804720 :     auto &TempZoneThermostatSetPoint = state.dataHeatBalFanSys->TempZoneThermostatSetPoint;
    3685     2804720 :     auto &TempControlType = state.dataHeatBalFanSys->TempControlType;
    3686     2804720 :     auto &TempControlTypeRpt = state.dataHeatBalFanSys->TempControlTypeRpt;
    3687     2804720 :     auto &ZoneThermostatSetPointLo = state.dataHeatBalFanSys->ZoneThermostatSetPointLo;
    3688     2804720 :     auto &ZoneThermostatSetPointHi = state.dataHeatBalFanSys->ZoneThermostatSetPointHi;
    3689     2804720 :     int NumOfZones = state.dataGlobal->NumOfZones;
    3690             : 
    3691     2804720 :     TempControlType = HVAC::ThermostatType::Uncontrolled; // Default
    3692             : 
    3693             :     // Place holder for occupied heating and cooling set points - for optimum start
    3694     2804720 :     if (!allocated(state.dataZoneCtrls->OccRoomTSetPointHeat)) {
    3695         796 :         state.dataZoneCtrls->OccRoomTSetPointHeat.allocate(NumOfZones);
    3696             :     }
    3697     2804720 :     if (!allocated(state.dataZoneCtrls->OccRoomTSetPointCool)) {
    3698         796 :         state.dataZoneCtrls->OccRoomTSetPointCool.allocate(NumOfZones);
    3699             :     }
    3700     2804720 :     state.dataZoneCtrls->OccRoomTSetPointHeat = 0.0;
    3701     2804720 :     state.dataZoneCtrls->OccRoomTSetPointCool = 100.0;
    3702     2804720 :     DeltaT = 0.0;
    3703             : 
    3704    19716837 :     for (RelativeZoneNum = 1; RelativeZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++RelativeZoneNum) {
    3705             : 
    3706             :         // What if this zone not controlled???
    3707    16912117 :         ActualZoneNum = TempControlledZone(RelativeZoneNum).ActualZoneNum;
    3708    16912117 :         TempControlSchedIndex = TempControlledZone(RelativeZoneNum).CTSchedIndex;
    3709    16912117 :         TempControlType(ActualZoneNum) = static_cast<HVAC::ThermostatType>(ScheduleManager::GetCurrentScheduleValue(state, TempControlSchedIndex));
    3710    16912117 :         TempControlTypeRpt(ActualZoneNum) = static_cast<int>(TempControlType(ActualZoneNum));
    3711             :         // Error detection for these values is done in the Get routine
    3712             : 
    3713    16912117 :         switch (TempControlType(ActualZoneNum)) {
    3714        2034 :         case HVAC::ThermostatType::Uncontrolled:
    3715        2034 :             break;
    3716     1908900 :         case HVAC::ThermostatType::SingleHeating:
    3717     1908900 :             SchedNameIndex = TempControlledZone(RelativeZoneNum).SchIndx_SingleHeatSetPoint;
    3718     1908900 :             TempZoneThermostatSetPoint(ActualZoneNum) = ScheduleManager::GetCurrentScheduleValue(state, SchedNameIndex);
    3719     1908900 :             TempControlledZone(RelativeZoneNum).ZoneThermostatSetPointLo = TempZoneThermostatSetPoint(ActualZoneNum);
    3720             : 
    3721     1908900 :             AdjustAirSetPointsforOpTempCntrl(state, RelativeZoneNum, ActualZoneNum, TempZoneThermostatSetPoint(ActualZoneNum));
    3722     1908900 :             ZoneThermostatSetPointLo(ActualZoneNum) = TempZoneThermostatSetPoint(ActualZoneNum);
    3723     1908900 :             break;
    3724     1923200 :         case HVAC::ThermostatType::SingleCooling:
    3725     1923200 :             SchedNameIndex = TempControlledZone(RelativeZoneNum).SchIndx_SingleCoolSetPoint;
    3726     1923200 :             TempZoneThermostatSetPoint(ActualZoneNum) = ScheduleManager::GetCurrentScheduleValue(state, SchedNameIndex);
    3727     1923200 :             TempControlledZone(RelativeZoneNum).ZoneThermostatSetPointHi = TempZoneThermostatSetPoint(ActualZoneNum);
    3728             : 
    3729             :             // Added Jan 17 (X. Luo)
    3730             :             // Adjust operative temperature based on adaptive comfort model
    3731     1923200 :             if ((TempControlledZone(RelativeZoneNum).AdaptiveComfortTempControl)) {
    3732        6750 :                 AdjustOperativeSetPointsforAdapComfort(state, RelativeZoneNum, TempZoneThermostatSetPoint(ActualZoneNum));
    3733        6750 :                 state.dataHeatBalFanSys->AdapComfortCoolingSetPoint(ActualZoneNum) = TempZoneThermostatSetPoint(ActualZoneNum);
    3734             :             }
    3735             : 
    3736     1923200 :             AdjustAirSetPointsforOpTempCntrl(state, RelativeZoneNum, ActualZoneNum, TempZoneThermostatSetPoint(ActualZoneNum));
    3737     1923200 :             ZoneThermostatSetPointHi(ActualZoneNum) = TempZoneThermostatSetPoint(ActualZoneNum);
    3738             : 
    3739     1923200 :             AdjustCoolingSetPointforTempAndHumidityControl(state, RelativeZoneNum, ActualZoneNum);
    3740     1923200 :             break;
    3741       79254 :         case HVAC::ThermostatType::SingleHeatCool:
    3742             : 
    3743       79254 :             SchedNameIndex = TempControlledZone(RelativeZoneNum).SchIndx_SingleHeatCoolSetPoint;
    3744             : 
    3745       79254 :             TempZoneThermostatSetPoint(ActualZoneNum) = ScheduleManager::GetCurrentScheduleValue(state, SchedNameIndex);
    3746             : 
    3747             :             // Added Jan 17 (X. Luo)
    3748             :             // Adjust operative temperature based on adaptive comfort model
    3749       79254 :             if ((TempControlledZone(RelativeZoneNum).AdaptiveComfortTempControl)) {
    3750           0 :                 AdjustOperativeSetPointsforAdapComfort(state, RelativeZoneNum, TempZoneThermostatSetPoint(ActualZoneNum));
    3751           0 :                 state.dataHeatBalFanSys->AdapComfortCoolingSetPoint(ActualZoneNum) = TempZoneThermostatSetPoint(ActualZoneNum);
    3752             :             }
    3753             : 
    3754       79254 :             AdjustAirSetPointsforOpTempCntrl(state, RelativeZoneNum, ActualZoneNum, TempZoneThermostatSetPoint(ActualZoneNum));
    3755             : 
    3756       79254 :             ZoneThermostatSetPointHi(ActualZoneNum) = TempZoneThermostatSetPoint(ActualZoneNum);
    3757       79254 :             ZoneThermostatSetPointLo(ActualZoneNum) = TempZoneThermostatSetPoint(ActualZoneNum);
    3758             : 
    3759             :             // Change the room set point to occupied set point during optimum start period--------------
    3760             : 
    3761       79254 :             if (allocated(state.dataAvail->OptStart)) {
    3762           0 :                 if (!allocated(DaySPValues)) {
    3763           0 :                     DaySPValues.allocate(state.dataGlobal->NumOfTimeStepInHour, 24);
    3764             :                 }
    3765           0 :                 if (state.dataAvail->OptStart(ActualZoneNum).ActualZoneNum == ActualZoneNum) {
    3766           0 :                     ScheduleManager::GetScheduleValuesForDay(state, SetPointTempSchedIndexCold, DaySPValues);
    3767           0 :                     OccStartTime = CEILING(state.dataAvail->OptStart(ActualZoneNum).OccStartTime) + 1;
    3768           0 :                     TempZoneThermostatSetPoint(ActualZoneNum) = DaySPValues(1, OccStartTime);
    3769             :                 }
    3770             : 
    3771           0 :                 if (state.dataAvail->OptStart(ActualZoneNum).OptStartFlag) {
    3772           0 :                     ZoneThermostatSetPointHi(ActualZoneNum) = TempZoneThermostatSetPoint(ActualZoneNum);
    3773           0 :                     ZoneThermostatSetPointLo(ActualZoneNum) = TempZoneThermostatSetPoint(ActualZoneNum);
    3774             :                 }
    3775             :             }
    3776             :             //--------------------------------------------------------------------------------------------
    3777       79254 :             break;
    3778    12998729 :         case HVAC::ThermostatType::DualSetPointWithDeadBand:
    3779    12998729 :             SetPointTempSchedIndexHot = TempControlledZone(RelativeZoneNum).SchIndx_DualSetPointWDeadBandHeat;
    3780    12998729 :             SetPointTempSchedIndexCold = TempControlledZone(RelativeZoneNum).SchIndx_DualSetPointWDeadBandCool;
    3781             : 
    3782    12998729 :             ZoneThermostatSetPointHi(ActualZoneNum) = ScheduleManager::GetCurrentScheduleValue(state, SetPointTempSchedIndexCold);
    3783    12998729 :             TempControlledZone(RelativeZoneNum).ZoneThermostatSetPointHi = ZoneThermostatSetPointHi(ActualZoneNum);
    3784             : 
    3785             :             // Added Jan 17 (X. Luo)
    3786             :             // Adjust operative temperature based on adaptive comfort model
    3787    12998729 :             if ((TempControlledZone(RelativeZoneNum).AdaptiveComfortTempControl)) {
    3788          15 :                 AdjustOperativeSetPointsforAdapComfort(state, RelativeZoneNum, ZoneThermostatSetPointHi(ActualZoneNum));
    3789          15 :                 state.dataHeatBalFanSys->AdapComfortCoolingSetPoint(ActualZoneNum) = ZoneThermostatSetPointHi(ActualZoneNum);
    3790             :             }
    3791             : 
    3792    12998729 :             AdjustAirSetPointsforOpTempCntrl(state, RelativeZoneNum, ActualZoneNum, ZoneThermostatSetPointHi(ActualZoneNum));
    3793             : 
    3794    12998729 :             ZoneThermostatSetPointLo(ActualZoneNum) = ScheduleManager::GetCurrentScheduleValue(state, SetPointTempSchedIndexHot);
    3795    12998729 :             TempControlledZone(RelativeZoneNum).ZoneThermostatSetPointLo = ZoneThermostatSetPointLo(ActualZoneNum);
    3796    12998729 :             AdjustAirSetPointsforOpTempCntrl(state, RelativeZoneNum, ActualZoneNum, ZoneThermostatSetPointLo(ActualZoneNum));
    3797             : 
    3798             :             // Change the room set point to occupied set point during optimum start period--------------
    3799             : 
    3800    12998729 :             if (allocated(state.dataAvail->OptStart)) {
    3801       36848 :                 if (!allocated(DaySPValues)) {
    3802        2303 :                     DaySPValues.allocate(state.dataGlobal->NumOfTimeStepInHour, 24);
    3803             :                 }
    3804       36848 :                 if (state.dataAvail->OptStart(ActualZoneNum).ActualZoneNum == ActualZoneNum) {
    3805       11515 :                     ScheduleManager::GetScheduleValuesForDay(state, SetPointTempSchedIndexCold, DaySPValues);
    3806       11515 :                     OccStartTime = CEILING(state.dataAvail->OptStart(ActualZoneNum).OccStartTime) + 1;
    3807       11515 :                     state.dataZoneCtrls->OccRoomTSetPointCool(ActualZoneNum) = DaySPValues(1, OccStartTime);
    3808       11515 :                     ScheduleManager::GetScheduleValuesForDay(state, SetPointTempSchedIndexHot, DaySPValues);
    3809       11515 :                     state.dataZoneCtrls->OccRoomTSetPointHeat(ActualZoneNum) = DaySPValues(1, OccStartTime);
    3810             :                 }
    3811             : 
    3812       36848 :                 if (state.dataAvail->OptStart(ActualZoneNum).OptStartFlag) {
    3813        1740 :                     ZoneThermostatSetPointHi(ActualZoneNum) = state.dataZoneCtrls->OccRoomTSetPointCool(ActualZoneNum);
    3814        1740 :                     ZoneThermostatSetPointLo(ActualZoneNum) = state.dataZoneCtrls->OccRoomTSetPointHeat(ActualZoneNum);
    3815             :                 }
    3816             :             }
    3817             :             //--------------------------------------------------------------------------------------------
    3818             : 
    3819    12998729 :             AdjustCoolingSetPointforTempAndHumidityControl(state, RelativeZoneNum, ActualZoneNum);
    3820    12998729 :             break;
    3821           0 :         default:
    3822           0 :             ShowSevereError(state,
    3823           0 :                             format("CalcZoneAirTempSetpoints: Illegal control type for Zone={}, Found value={}, in Schedule={}",
    3824           0 :                                    Zone(ActualZoneNum).Name,
    3825             :                                    TempControlType(ActualZoneNum),
    3826           0 :                                    TempControlledZone(RelativeZoneNum).ControlTypeSchedName));
    3827             : 
    3828           0 :             break;
    3829             :         }
    3830             : 
    3831             :         // Apply offset for faulty therostats
    3832    16916725 :         if ((state.dataFaultsMgr->NumFaultyThermostat > 0) && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
    3833        4608 :             (!state.dataGlobal->KickOffSimulation)) {
    3834             :             //  loop through the FaultsThermostatOffset objects to find the one for the zone
    3835       34848 :             for (int iFault = 1; iFault <= state.dataFaultsMgr->NumFaultyThermostat; ++iFault) {
    3836             : 
    3837       34848 :                 if (Util::SameString(TempControlledZone(RelativeZoneNum).Name,
    3838       34848 :                                      state.dataFaultsMgr->FaultsThermostatOffset(iFault).FaultyThermostatName)) {
    3839             : 
    3840             :                     // Check fault availability schedules
    3841        4608 :                     if (ScheduleManager::GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsThermostatOffset(iFault).availSchedNum) > 0.0) {
    3842             : 
    3843             :                         // Check fault severity schedules to update the reference thermostat offset
    3844        4608 :                         double rSchVal = 1.0;
    3845             :                         double offsetUpdated;
    3846        4608 :                         if (state.dataFaultsMgr->FaultsThermostatOffset(iFault).severitySchedNum >= 0) {
    3847             :                             rSchVal =
    3848           0 :                                 ScheduleManager::GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsThermostatOffset(iFault).severitySchedNum);
    3849             :                         }
    3850        4608 :                         offsetUpdated = rSchVal * state.dataFaultsMgr->FaultsThermostatOffset(iFault).Offset;
    3851             : 
    3852             :                         // Positive offset means the sensor reading is higher than the actual value
    3853        4608 :                         TempZoneThermostatSetPoint(ActualZoneNum) -= offsetUpdated;
    3854        4608 :                         ZoneThermostatSetPointLo(ActualZoneNum) -= offsetUpdated;
    3855        4608 :                         ZoneThermostatSetPointHi(ActualZoneNum) -= offsetUpdated;
    3856             :                     }
    3857             : 
    3858             :                     // Stop searching the FaultsThermostatOffset object for the zone
    3859        4608 :                     break;
    3860             :                 }
    3861             :             }
    3862             :         }
    3863             :     }
    3864             : 
    3865     2804720 :     if (state.dataZoneCtrls->NumComfortControlledZones > 0) CalcZoneAirComfortSetPoints(state);
    3866     2804720 :     OverrideAirSetPointsforEMSCntrl(state);
    3867     2804720 : }
    3868             : 
    3869    30004171 : void ZoneSpaceHeatBalanceData::calcPredictedHumidityRatio(EnergyPlusData &state, Real64 const RAFNFrac, int const zoneNum, int const spaceNum)
    3870             : {
    3871             : 
    3872             :     // SUBROUTINE INFORMATION:
    3873             :     //       AUTHOR         Richard J. Liesen
    3874             :     //       DATE WRITTEN   May 2001
    3875             : 
    3876             :     // PURPOSE OF THIS SUBROUTINE:
    3877             :     // This subroutine does the prediction step for humidity control
    3878             : 
    3879             :     // METHODOLOGY EMPLOYED:
    3880             :     // This solves for the required system moisture required to try and achieve the desired
    3881             :     // Humidity Ratio in the Zone
    3882             : 
    3883             :     // REFERENCES:
    3884             :     // Routine FinalZnCalcs - FINAL ZONE CALCULATIONS, authored by Dale Herron
    3885             :     // for BLAST.
    3886             : 
    3887             :     static constexpr std::string_view RoutineName("calcPredictedHumidityRatio");
    3888             : 
    3889    30004171 :     Real64 ZoneRHHumidifyingSetPoint = 0.0;   // Zone humidifying set point (%)
    3890    30004171 :     Real64 ZoneRHDehumidifyingSetPoint = 0.0; // Zone dehumidifying set point (%)
    3891             : 
    3892    30004171 :     auto &thisZone = state.dataHeatBal->Zone(zoneNum);
    3893    30004171 :     bool SingleSetPoint = false; // This determines whether both setpoint are equal or not
    3894             : 
    3895             :     // Check to see if this is a "humidity controlled zone"
    3896    30004171 :     bool ControlledHumidZoneFlag = false;
    3897             :     // Check all the controlled zones to see if it matches the zone simulated
    3898    30004171 :     if (thisZone.humidityControlZoneIndex > 0) {
    3899     1126045 :         auto &humidityControlZone = state.dataZoneCtrls->HumidityControlZone(thisZone.humidityControlZoneIndex);
    3900     1126045 :         assert(humidityControlZone.ActualZoneNum == zoneNum);
    3901     1126045 :         ZoneRHHumidifyingSetPoint = ScheduleManager::GetCurrentScheduleValue(state, humidityControlZone.HumidifyingSchedIndex);
    3902     1126045 :         ZoneRHDehumidifyingSetPoint = ScheduleManager::GetCurrentScheduleValue(state, humidityControlZone.DehumidifyingSchedIndex);
    3903             : 
    3904             :         // Apply EMS values to overwrite the humidistat values
    3905     1126045 :         if (humidityControlZone.EMSOverrideHumidifySetPointOn) {
    3906           0 :             ZoneRHHumidifyingSetPoint = humidityControlZone.EMSOverrideHumidifySetPointValue;
    3907             :         }
    3908     1126045 :         if (humidityControlZone.EMSOverrideDehumidifySetPointOn) {
    3909           0 :             ZoneRHDehumidifyingSetPoint = humidityControlZone.EMSOverrideDehumidifySetPointValue;
    3910             :         }
    3911             : 
    3912             :         // Apply offsets for faulty humidistats
    3913     1126667 :         if ((state.dataFaultsMgr->NumFaultyHumidistat > 0) && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
    3914         622 :             (!state.dataGlobal->KickOffSimulation)) {
    3915             : 
    3916             :             //  loop through the FaultsHumidistatOffset objects to find the one for the zone
    3917         622 :             for (int iFault = 1; iFault <= state.dataFaultsMgr->NumFaultyHumidistat; ++iFault) {
    3918             : 
    3919         622 :                 if (Util::SameString(humidityControlZone.ControlName, state.dataFaultsMgr->FaultsHumidistatOffset(iFault).FaultyHumidistatName)) {
    3920             : 
    3921         622 :                     if (Util::SameString(state.dataFaultsMgr->FaultsHumidistatOffset(iFault).FaultyHumidistatType, "ThermostatOffsetDependent")) {
    3922             :                         // For Humidistat Offset Type I: ThermostatOffsetDependent
    3923             : 
    3924         304 :                         bool IsThermostatFound = false;
    3925         304 :                         double offsetThermostat = 0.0;
    3926         304 :                         double offsetZoneRHHumidifyingSetPoint = 0.0;
    3927         304 :                         double offsetZoneRHDehumidifyingSetPoint = 0.0;
    3928             :                         double faultZoneWHumidifyingSetPoint;
    3929             :                         double faultZoneWDehumidifyingSetPoint;
    3930             : 
    3931             :                         // Get the offset value of the corresponding thermostat fault object
    3932         304 :                         if (state.dataFaultsMgr->NumFaultyThermostat > 0) {
    3933             : 
    3934             :                             //  loop through the FaultsThermostatOffset objects to find the one causes the Humidistat Offset
    3935         304 :                             for (int iFaultThermo = 1; iFaultThermo <= state.dataFaultsMgr->NumFaultyThermostat; ++iFaultThermo) {
    3936             : 
    3937         304 :                                 if (Util::SameString(state.dataFaultsMgr->FaultsHumidistatOffset(iFault).FaultyThermostatName,
    3938         304 :                                                      state.dataFaultsMgr->FaultsThermostatOffset(iFaultThermo).Name)) {
    3939         304 :                                     IsThermostatFound = true;
    3940             : 
    3941             :                                     // Check fault availability schedules
    3942         608 :                                     if (ScheduleManager::GetCurrentScheduleValue(
    3943         304 :                                             state, state.dataFaultsMgr->FaultsThermostatOffset(iFaultThermo).availSchedNum) > 0.0) {
    3944             : 
    3945             :                                         // Check fault severity schedules to update the reference thermostat offset
    3946         304 :                                         double rSchVal = 1.0;
    3947         304 :                                         if (state.dataFaultsMgr->FaultsThermostatOffset(iFaultThermo).severitySchedNum >= 0) {
    3948           0 :                                             rSchVal = ScheduleManager::GetCurrentScheduleValue(
    3949           0 :                                                 state, state.dataFaultsMgr->FaultsThermostatOffset(iFaultThermo).severitySchedNum);
    3950             :                                         }
    3951         304 :                                         offsetThermostat = rSchVal * state.dataFaultsMgr->FaultsThermostatOffset(iFaultThermo).Offset;
    3952             :                                     }
    3953             : 
    3954             :                                     // Stop searching the FaultsThermostatOffset object for the Humidistat Offset
    3955         304 :                                     break;
    3956             :                                 }
    3957             :                             }
    3958             :                         }
    3959             : 
    3960             :                         // The FaultsThermostatOffset specified in the FaultHumidistatOffset is not found
    3961         304 :                         if (!IsThermostatFound) {
    3962           0 :                             ShowSevereError(
    3963             :                                 state,
    3964           0 :                                 format("FaultModel:HumidistatOffset = \"{}\" invalid Reference Humidistat Offset Name = \"{}\" not found.",
    3965           0 :                                        state.dataFaultsMgr->FaultsHumidistatOffset(iFault).Name,
    3966           0 :                                        state.dataFaultsMgr->FaultsHumidistatOffset(iFault).FaultyThermostatName));
    3967           0 :                             ShowFatalError(state, "Errors getting FaultModel input data.  Preceding condition(s) cause termination.");
    3968             :                         }
    3969             : 
    3970         304 :                         if (offsetThermostat != 0.0) {
    3971             :                             // Calculate the humidistat offset value from the thermostat offset value
    3972         304 :                             faultZoneWHumidifyingSetPoint = Psychrometrics::PsyWFnTdbRhPb(
    3973         304 :                                 state, (this->MAT + offsetThermostat), (ZoneRHHumidifyingSetPoint / 100.0), state.dataEnvrn->OutBaroPress);
    3974         304 :                             faultZoneWDehumidifyingSetPoint = Psychrometrics::PsyWFnTdbRhPb(
    3975         304 :                                 state, (this->MAT + offsetThermostat), (ZoneRHDehumidifyingSetPoint / 100.0), state.dataEnvrn->OutBaroPress);
    3976         304 :                             offsetZoneRHHumidifyingSetPoint =
    3977         304 :                                 ZoneRHHumidifyingSetPoint -
    3978         304 :                                 Psychrometrics::PsyRhFnTdbWPb(state, this->MAT, faultZoneWHumidifyingSetPoint, state.dataEnvrn->OutBaroPress) * 100.0;
    3979         304 :                             offsetZoneRHDehumidifyingSetPoint =
    3980         304 :                                 ZoneRHDehumidifyingSetPoint -
    3981         304 :                                 Psychrometrics::PsyRhFnTdbWPb(state, this->MAT, faultZoneWDehumidifyingSetPoint, state.dataEnvrn->OutBaroPress) *
    3982             :                                     100.0;
    3983             : 
    3984             :                             // Apply the calculated humidistat offset value
    3985             :                             // Positive offset means the sensor reading is higher than the actual value
    3986         304 :                             ZoneRHHumidifyingSetPoint -= offsetZoneRHHumidifyingSetPoint;
    3987         304 :                             ZoneRHDehumidifyingSetPoint -= offsetZoneRHDehumidifyingSetPoint;
    3988             : 
    3989             :                             // constrain value to something reasonable
    3990         304 :                             ZoneRHHumidifyingSetPoint = min(100.0, max(0.0, ZoneRHHumidifyingSetPoint));
    3991         304 :                             ZoneRHDehumidifyingSetPoint = min(100.0, max(0.0, ZoneRHDehumidifyingSetPoint));
    3992             :                         }
    3993             : 
    3994             :                     } else {
    3995             :                         // For Humidistat Offset Type II: ThermostatOffsetIndependent
    3996             : 
    3997             :                         // Check fault availability schedules
    3998         318 :                         if (ScheduleManager::GetCurrentScheduleValue(state, state.dataFaultsMgr->FaultsHumidistatOffset(iFault).availSchedNum) >
    3999             :                             0.0) {
    4000             : 
    4001             :                             // Check fault severity schedules to update the reference humidistat offset
    4002         318 :                             double rSchVal = 1.0;
    4003             :                             double offsetUpdated;
    4004         318 :                             if (state.dataFaultsMgr->FaultsHumidistatOffset(iFault).severitySchedNum >= 0) {
    4005           0 :                                 rSchVal = ScheduleManager::GetCurrentScheduleValue(
    4006           0 :                                     state, state.dataFaultsMgr->FaultsHumidistatOffset(iFault).severitySchedNum);
    4007             :                             }
    4008         318 :                             offsetUpdated = rSchVal * state.dataFaultsMgr->FaultsHumidistatOffset(iFault).Offset;
    4009             : 
    4010             :                             // Positive offset means the sensor reading is higher than the actual value
    4011         318 :                             ZoneRHHumidifyingSetPoint -= offsetUpdated;
    4012         318 :                             ZoneRHDehumidifyingSetPoint -= offsetUpdated;
    4013             : 
    4014             :                             // constrain value to something reasonable
    4015         318 :                             ZoneRHHumidifyingSetPoint = min(100.0, max(0.0, ZoneRHHumidifyingSetPoint));
    4016         318 :                             ZoneRHDehumidifyingSetPoint = min(100.0, max(0.0, ZoneRHDehumidifyingSetPoint));
    4017             :                         }
    4018             :                     }
    4019         622 :                     break;
    4020             :                 }
    4021             :             }
    4022             :         }
    4023             : 
    4024             :         // Run-time error check
    4025     1126045 :         if (ZoneRHHumidifyingSetPoint > ZoneRHDehumidifyingSetPoint) {
    4026           0 :             if (humidityControlZone.ErrorIndex == 0) {
    4027           0 :                 ShowWarningMessage(
    4028           0 :                     state, format("HUMIDISTAT: The humidifying setpoint is above the dehumidifying setpoint in {}", humidityControlZone.ControlName));
    4029           0 :                 ShowContinueError(state, "The zone humidifying setpoint is set to the dehumidifying setpoint.");
    4030           0 :                 ShowContinueErrorTimeStamp(state, "Occurrence info:");
    4031             :             }
    4032           0 :             ShowRecurringWarningErrorAtEnd(state,
    4033             :                                            "The humidifying setpoint is still above the dehumidifying setpoint",
    4034           0 :                                            humidityControlZone.ErrorIndex,
    4035             :                                            ZoneRHHumidifyingSetPoint,
    4036             :                                            ZoneRHHumidifyingSetPoint);
    4037           0 :             ZoneRHHumidifyingSetPoint = ZoneRHDehumidifyingSetPoint;
    4038             :         }
    4039     1126045 :         if (ZoneRHHumidifyingSetPoint == ZoneRHDehumidifyingSetPoint) SingleSetPoint = true;
    4040     1126045 :         ControlledHumidZoneFlag = true;
    4041             : 
    4042             :     } // HumidControlledZoneNum
    4043             : 
    4044             :     // if zone latent sizing is requested but no humidistat exists
    4045    30004171 :     if (state.dataGlobal->DoingSizing && !ControlledHumidZoneFlag && state.dataHeatBal->DoLatentSizing) {
    4046       43500 :         for (size_t zoneEqConfigNum = 1; zoneEqConfigNum <= state.dataZoneEquip->ZoneEquipConfig.size(); ++zoneEqConfigNum) {
    4047       43500 :             auto &zoneEqConfig = state.dataZoneEquip->ZoneEquipConfig(zoneEqConfigNum);
    4048       43500 :             if (!zoneEqConfig.IsControlled) continue;
    4049       23814 :             int ZoneSizNum = Util::FindItemInList(zoneEqConfig.ZoneName, state.dataSize->ZoneSizingInput, &DataSizing::ZoneSizingInputData::ZoneName);
    4050             :             // should use the first Sizing:Zone object if not found
    4051       23814 :             if (ZoneSizNum == 0 && !state.dataSize->ZoneSizingInput.empty()) ZoneSizNum = 1;
    4052       23814 :             if (ZoneSizNum > 0) {
    4053       23814 :                 auto &zoneSizingInput = state.dataSize->ZoneSizingInput(ZoneSizNum);
    4054       23814 :                 if (zoneSizingInput.zoneLatentSizing) {
    4055       47628 :                     ZoneRHDehumidifyingSetPoint = (zoneSizingInput.zoneRHDehumidifySchIndex)
    4056       23814 :                                                       ? ScheduleManager::GetCurrentScheduleValue(state, zoneSizingInput.zoneRHDehumidifySchIndex)
    4057             :                                                       : zoneSizingInput.zoneRHDehumidifySetPoint;
    4058       47628 :                     ZoneRHHumidifyingSetPoint = (zoneSizingInput.zoneRHHumidifySchIndex)
    4059       23814 :                                                     ? ScheduleManager::GetCurrentScheduleValue(state, zoneSizingInput.zoneRHHumidifySchIndex)
    4060             :                                                     : zoneSizingInput.zoneRHHumidifySetPoint;
    4061       23814 :                     if (ZoneRHHumidifyingSetPoint > ZoneRHDehumidifyingSetPoint) ZoneRHHumidifyingSetPoint = ZoneRHDehumidifyingSetPoint;
    4062       23814 :                     if (ZoneRHHumidifyingSetPoint == ZoneRHDehumidifyingSetPoint) SingleSetPoint = true;
    4063       23814 :                     ControlledHumidZoneFlag = true;
    4064             :                 }
    4065             :             }
    4066       23814 :             break;
    4067             :         }
    4068             :     }
    4069             : 
    4070    30004171 :     Real64 LoadToHumidifySetPoint = 0.0;   // Moisture load at humidifying set point
    4071    30004171 :     Real64 LoadToDehumidifySetPoint = 0.0; // Moisture load at dehumidifying set point
    4072    30004171 :     Real64 totalOutputRequired = 0.0;
    4073    30004171 :     if (ControlledHumidZoneFlag) {
    4074             : 
    4075             :         // Calculate hourly humidity ratio from infiltration + humidity added from latent load
    4076             :         // to determine system added/subtracted moisture.
    4077     1149859 :         Real64 LatentGain = this->latentGain + state.dataHeatBalFanSys->SumLatentHTRadSys(zoneNum) + state.dataHeatBalFanSys->SumLatentPool(zoneNum);
    4078             : 
    4079     1149859 :         Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    4080             : 
    4081             :         // Calculate the coefficients for the 3rd Order derivative for final
    4082             :         // zone humidity ratio.  The A, B, C coefficients are analogous to the heat balance.
    4083             :         // SumHmARaW and SumHmARa will be used with the Moisture Balance on the building elements and
    4084             :         // are currently set to zero when the CTF only version is used.
    4085             : 
    4086             :         // The density of air and latent heat of vaporization are calculated as functions.
    4087     1149859 :         Real64 RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->ZT, this->airHumRat, RoutineName);
    4088     1149859 :         Real64 H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(this->airHumRat, this->ZT);
    4089             : 
    4090             :         // Assume that the system will have flow
    4091     1149859 :         Real64 A = 0.0;
    4092     1149859 :         Real64 B = 0.0;
    4093     1149859 :         Real64 C = 0.0;
    4094     2258641 :         if (state.afn->multizone_always_simulated ||
    4095     1108782 :             (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
    4096           0 :              state.afn->AirflowNetworkFanActivated)) {
    4097             :             // Multizone airflow calculated in AirflowNetwork
    4098       41077 :             B = (LatentGain / H2OHtOfVap) + state.afn->exchangeData(zoneNum).SumMHrW + state.afn->exchangeData(zoneNum).SumMMHrW + this->SumHmARaW;
    4099       41077 :             A = state.afn->exchangeData(zoneNum).SumMHr + state.afn->exchangeData(zoneNum).SumMMHr + this->SumHmARa;
    4100             :         } else {
    4101     1108782 :             B = (LatentGain / H2OHtOfVap) + ((this->OAMFL + this->VAMFL + this->CTMFL) * state.dataEnvrn->OutHumRat) + this->EAMFLxHumRat +
    4102     1108782 :                 this->SumHmARaW + this->MixingMassFlowXHumRat + this->MDotOA * state.dataEnvrn->OutHumRat;
    4103     1108782 :             A = this->OAMFL + this->VAMFL + this->EAMFL + this->CTMFL + this->SumHmARa + this->MixingMassFlowZone + this->MDotOA;
    4104             :         }
    4105     1149859 :         Real64 volume = 0.0;
    4106     1149859 :         if (spaceNum > 0) {
    4107           0 :             volume = state.dataHeatBal->space(spaceNum).Volume;
    4108             :         } else {
    4109     1149859 :             volume = thisZone.Volume;
    4110             :         }
    4111     1149859 :         C = RhoAir * volume * thisZone.ZoneVolCapMultpMoist / TimeStepSysSec;
    4112             : 
    4113     1149859 :         if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    4114           0 :             auto &roomAFNInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
    4115           0 :             int RoomAirNode = roomAFNInfo.ControlAirNodeID;
    4116           0 :             H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(roomAFNInfo.Node(RoomAirNode).HumRat, roomAFNInfo.Node(RoomAirNode).AirTemp);
    4117           0 :             A = roomAFNInfo.Node(RoomAirNode).SumLinkM + roomAFNInfo.Node(RoomAirNode).SumHmARa;
    4118           0 :             B = (roomAFNInfo.Node(RoomAirNode).SumIntLatentGain / H2OHtOfVap) + roomAFNInfo.Node(RoomAirNode).SumLinkMW +
    4119           0 :                 roomAFNInfo.Node(RoomAirNode).SumHmARaW;
    4120           0 :             C = roomAFNInfo.Node(RoomAirNode).RhoAir * roomAFNInfo.Node(RoomAirNode).AirVolume * thisZone.ZoneVolCapMultpMoist / TimeStepSysSec;
    4121             :         }
    4122             : 
    4123             :         // Use a 3rd Order derivative to predict zone moisture addition or removal and
    4124             :         // smooth the changes using the zone air capacitance.  Positive values of Moist Load means that
    4125             :         // this amount of moisture must be added to the zone to reach the setpoint.  Negative values represent
    4126             :         // the amount of moisture that must be removed by the system.
    4127             :         // MoistLoadHumidSetPoint = massflow * HumRat = kgDryAir/s * kgWater/kgDryAir = kgWater/s
    4128             :         Real64 WZoneSetPoint =
    4129     1149859 :             Psychrometrics::PsyWFnTdbRhPb(state, this->ZT, (ZoneRHHumidifyingSetPoint / 100.0), state.dataEnvrn->OutBaroPress, RoutineName);
    4130     1149859 :         Real64 exp_700_A_C(0.0);
    4131     1149859 :         if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::ThirdOrder) {
    4132      894617 :             LoadToHumidifySetPoint =
    4133     1789234 :                 ((11.0 / 6.0) * C + A) * WZoneSetPoint -
    4134      894617 :                 (B + C * (3.0 * this->WPrevZoneTSTemp[0] - (3.0 / 2.0) * this->WPrevZoneTSTemp[1] + (1.0 / 3.0) * this->WPrevZoneTSTemp[2]));
    4135             :             // Exact solution
    4136      255242 :         } else if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::AnalyticalSolution) {
    4137      255242 :             if (A == 0.0) { // B=0
    4138       39590 :                 LoadToHumidifySetPoint = C * (WZoneSetPoint - this->W1) - B;
    4139             :             } else {
    4140      215652 :                 exp_700_A_C = std::exp(min(700.0, -A / C)); // Tuned Save expensive value
    4141      215652 :                 LoadToHumidifySetPoint = A * (WZoneSetPoint - this->W1 * exp_700_A_C) / (1.0 - exp_700_A_C) - B;
    4142             :             }
    4143           0 :         } else if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::EulerMethod) {
    4144           0 :             LoadToHumidifySetPoint = C * (WZoneSetPoint - this->W1) + A * WZoneSetPoint - B;
    4145             :         }
    4146     1149859 :         if (RAFNFrac > 0.0) LoadToHumidifySetPoint = LoadToHumidifySetPoint / RAFNFrac;
    4147             :         WZoneSetPoint =
    4148     1149859 :             Psychrometrics::PsyWFnTdbRhPb(state, this->ZT, (ZoneRHDehumidifyingSetPoint / 100.0), state.dataEnvrn->OutBaroPress, RoutineName);
    4149     1149859 :         if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::ThirdOrder) {
    4150      894617 :             LoadToDehumidifySetPoint =
    4151     1789234 :                 ((11.0 / 6.0) * C + A) * WZoneSetPoint -
    4152      894617 :                 (B + C * (3.0 * this->WPrevZoneTSTemp[0] - (3.0 / 2.0) * this->WPrevZoneTSTemp[1] + (1.0 / 3.0) * this->WPrevZoneTSTemp[2]));
    4153             :             // Exact solution
    4154      255242 :         } else if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::AnalyticalSolution) {
    4155      255242 :             if (A == 0.0) { // B=0
    4156       39590 :                 LoadToDehumidifySetPoint = C * (WZoneSetPoint - this->W1) - B;
    4157             :             } else {
    4158      215652 :                 LoadToDehumidifySetPoint = A * (WZoneSetPoint - this->W1 * exp_700_A_C) / (1.0 - exp_700_A_C) - B; // exp_700_A_C set above
    4159             :             }
    4160           0 :         } else if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::EulerMethod) {
    4161           0 :             LoadToDehumidifySetPoint = C * (WZoneSetPoint - this->W1) + A * WZoneSetPoint - B;
    4162             :         }
    4163     1149859 :         if (RAFNFrac > 0.0) LoadToDehumidifySetPoint = LoadToDehumidifySetPoint / RAFNFrac;
    4164             : 
    4165             :         // The load is added to the TotalOutputRequired as in the Temperature Predictor.  There is also the remaining
    4166             :         // output variable for those who will use this for humidity control and stored in DataZoneEnergyDemands with the
    4167             :         // analogous temperature terms.
    4168             : 
    4169     1149859 :         if (SingleSetPoint) {
    4170      617690 :             totalOutputRequired = LoadToHumidifySetPoint;
    4171             :         } else {
    4172      532169 :             if (LoadToHumidifySetPoint > 0.0 && LoadToDehumidifySetPoint > 0.0) {
    4173      127963 :                 totalOutputRequired = LoadToHumidifySetPoint;
    4174      404206 :             } else if (LoadToHumidifySetPoint < 0.0 && LoadToDehumidifySetPoint < 0.0) {
    4175      128330 :                 totalOutputRequired = LoadToDehumidifySetPoint;
    4176      275876 :             } else if (LoadToHumidifySetPoint <= 0.0 && LoadToDehumidifySetPoint >= 0.0) { // deadband includes zero loads
    4177      275876 :                 totalOutputRequired = 0.0;
    4178             :             } else { // this should never occur!
    4179           0 :                 ShowSevereError(
    4180             :                     state, "Humidistat: Unanticipated combination of humidifying and dehumidifying loads - report to EnergyPlus Development Team");
    4181           0 :                 ShowContinueErrorTimeStamp(state, format("occurs in Zone = {}", thisZone.Name));
    4182           0 :                 ShowContinueError(
    4183             :                     state,
    4184           0 :                     format("LoadToHumidifySetPoint={:.5R}, LoadToDehumidifySetPoint={:.5R}", LoadToHumidifySetPoint, LoadToDehumidifySetPoint));
    4185           0 :                 ShowContinueError(state, format("Zone RH Humidifying Set-point={:.1R}", ZoneRHHumidifyingSetPoint));
    4186           0 :                 ShowContinueError(state, format("Zone RH Dehumidifying Set-point={:.2R}", ZoneRHDehumidifyingSetPoint));
    4187           0 :                 ShowFatalError(state, "Program terminates due to above conditions.");
    4188             :             }
    4189             :         }
    4190             :     }
    4191             : 
    4192             :     // Apply zone multipliers as needed or set to zero
    4193    30004171 :     if (spaceNum > 0) {
    4194       86394 :         auto &thisspaceSysMoistureDemand = state.dataZoneEnergyDemand->spaceSysMoistureDemand(spaceNum);
    4195       86394 :         if (ControlledHumidZoneFlag) {
    4196           0 :             thisspaceSysMoistureDemand.reportMoistLoadsZoneMultiplier(
    4197             :                 state, zoneNum, totalOutputRequired, LoadToHumidifySetPoint, LoadToDehumidifySetPoint);
    4198             :         } else {
    4199       86394 :             thisspaceSysMoistureDemand.TotalOutputRequired = 0.0;
    4200       86394 :             thisspaceSysMoistureDemand.OutputRequiredToDehumidifyingSP = 0.0;
    4201       86394 :             thisspaceSysMoistureDemand.OutputRequiredToHumidifyingSP = 0.0;
    4202             :         }
    4203             :     } else {
    4204    29917777 :         auto &thisZoneSysMoistureDemand = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(zoneNum);
    4205    29917777 :         if (ControlledHumidZoneFlag) {
    4206     1149859 :             thisZoneSysMoistureDemand.reportMoistLoadsZoneMultiplier(
    4207             :                 state, zoneNum, totalOutputRequired, LoadToHumidifySetPoint, LoadToDehumidifySetPoint);
    4208             :         } else {
    4209    28767918 :             thisZoneSysMoistureDemand.TotalOutputRequired = 0.0;
    4210    28767918 :             thisZoneSysMoistureDemand.OutputRequiredToDehumidifyingSP = 0.0;
    4211    28767918 :             thisZoneSysMoistureDemand.OutputRequiredToHumidifyingSP = 0.0;
    4212             :         }
    4213             :     }
    4214    30004171 : }
    4215             : 
    4216     3866489 : Real64 correctZoneAirTemps(EnergyPlusData &state,
    4217             :                            bool useZoneTimeStepHistory // if true then use zone timestep history, if false use system time step history
    4218             : )
    4219             : {
    4220     3866489 :     Real64 maxTempChange = DataPrecisionGlobals::constant_zero; // Max absolute air temperature change between previous and current timestep
    4221    33782838 :     for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    4222    29916349 :         auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum);
    4223    29916349 :         Real64 zoneTempChange = thisZoneHB.correctAirTemp(state, useZoneTimeStepHistory, zoneNum);
    4224    29916349 :         auto &thisZone = state.dataHeatBal->Zone(zoneNum);
    4225    59896562 :         for (int spaceNum : thisZone.spaceIndexes) {
    4226    29980213 :             auto &thisSpaceHB = state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum);
    4227    30066607 :             if (state.dataHeatBal->doSpaceHeatBalanceSimulation &&
    4228       86394 :                 !state.dataGlobal->DoingSizing) { // Need space air temps to match zone temps for sizing
    4229       29170 :                 Real64 spaceTempChange = thisSpaceHB.correctAirTemp(state, useZoneTimeStepHistory, zoneNum, spaceNum);
    4230       29170 :                 maxTempChange = max(maxTempChange, spaceTempChange);
    4231             :             } else {
    4232             :                 // If no SpaceHB, then set space temps to match zone temps
    4233    29951043 :                 if (state.dataHeatBal->space(spaceNum).IsControlled) {
    4234       11364 :                     auto &thisZoneNode = state.dataLoopNodes->Node(thisZone.SystemZoneNodeNumber);
    4235       11364 :                     auto &thisSpaceNode = state.dataLoopNodes->Node(state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber);
    4236       11364 :                     thisSpaceNode.Temp = thisZoneNode.Temp;
    4237       11364 :                     thisSpaceNode.HumRat = thisZoneNode.HumRat;
    4238       11364 :                     thisSpaceNode.Enthalpy = thisZoneNode.Enthalpy;
    4239             :                 }
    4240    29951043 :                 thisSpaceHB.ZT = thisZoneHB.ZT;
    4241    29951043 :                 thisSpaceHB.ZTM = thisZoneHB.ZTM;
    4242    29951043 :                 thisSpaceHB.MAT = thisZoneHB.MAT;
    4243    29951043 :                 thisSpaceHB.airHumRat = thisZoneHB.airHumRat;
    4244    29951043 :                 thisSpaceHB.airRelHum = thisZoneHB.airRelHum;
    4245             :                 // thisSpaceHB.ZTAVComf = thisZoneHB.ZTAVComf;
    4246             :             }
    4247    29916349 :         }
    4248    29916349 :         maxTempChange = max(maxTempChange, zoneTempChange);
    4249             : 
    4250    29916349 :         CalcZoneComponentLoadSums(
    4251    59832698 :             state, zoneNum, &state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum), state.dataHeatBal->ZnAirRpt(zoneNum));
    4252    29916349 :         if (state.dataHeatBal->doSpaceHeatBalanceSimulation) {
    4253      150192 :             for (int spaceNum : thisZone.spaceIndexes) {
    4254       86394 :                 CalcZoneComponentLoadSums(
    4255      172788 :                     state, zoneNum, &state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum), state.dataHeatBal->spaceAirRpt(spaceNum));
    4256       63798 :             }
    4257             :         }
    4258             :     }
    4259     3866489 :     return maxTempChange;
    4260             : }
    4261             : 
    4262    29945519 : Real64 ZoneSpaceHeatBalanceData::correctAirTemp(
    4263             :     EnergyPlusData &state,
    4264             :     bool const useZoneTimeStepHistory, // if true then use zone timestep history, if false use system time step history
    4265             :     int const zoneNum,
    4266             :     int const spaceNum)
    4267             : {
    4268             : 
    4269             :     // SUBROUTINE INFORMATION:
    4270             :     //       AUTHOR         Russell Taylor
    4271             :     //       MODIFIED       November 1999, LKL; November 2016 Sang Hoon Lee, Tianzhen Hong, Rongpeng Zhang;
    4272             :     //       RE-ENGINEERED  July 2003 (Peter Graham Ellis)
    4273             :     //                      February 2008 (Brent Griffith reworked history )
    4274             : 
    4275             :     // PURPOSE OF THIS SUBROUTINE:
    4276             :     // This subroutine updates the zone air temperature and modifies the system
    4277             :     // time step.
    4278             : 
    4279             :     static constexpr std::string_view RoutineName("correctAirTemp");
    4280             : 
    4281    29945519 :     Real64 tempChange = DataPrecisionGlobals::constant_zero; // Zone or space air temperature change between previous and current timestep
    4282             : 
    4283    29945519 :     assert(zoneNum > 0);
    4284    29945519 :     auto &thisZone = state.dataHeatBal->Zone(zoneNum);
    4285             : 
    4286             :     // Update zone temperatures
    4287             : 
    4288    29945519 :     Real64 ZoneMult = thisZone.Multiplier * thisZone.ListMultiplier;
    4289             : 
    4290    29945519 :     Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    4291             : 
    4292             :     // update the variables actually used in the balance equations.
    4293    29945519 :     if (!useZoneTimeStepHistory) {
    4294    10057673 :         this->ZTM = this->DSXMAT;
    4295    10057673 :         this->WPrevZoneTSTemp = this->DSWPrevZoneTS;
    4296             :     } else {
    4297    19887846 :         this->ZTM = this->XMAT;
    4298    19887846 :         this->WPrevZoneTSTemp = this->WPrevZoneTS;
    4299             :     }
    4300             : 
    4301    29945519 :     Real64 volume = 0.0;
    4302    29945519 :     if (spaceNum > 0) {
    4303       29170 :         volume = state.dataHeatBal->space(spaceNum).Volume;
    4304             :     } else {
    4305    29916349 :         volume = thisZone.Volume;
    4306             :     }
    4307    89836557 :     this->AirPowerCap = volume * thisZone.ZoneVolCapMultpSens *
    4308    29945519 :                         Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->MAT, this->airHumRat, RoutineName) *
    4309    29945519 :                         Psychrometrics::PsyCpAirFnW(this->airHumRat) / TimeStepSysSec;
    4310             : 
    4311             :     // SpaceHB TODO: For now, room air model is only for zones
    4312    29945519 :     if (spaceNum == 0) {
    4313    29916349 :         RoomAir::ManageAirModel(state, zoneNum);
    4314             :     }
    4315             : 
    4316             :     // Calculate the various heat balance sums
    4317    29945519 :     this->calcZoneOrSpaceSums(state, true, zoneNum, spaceNum);
    4318             : 
    4319             :     // Sum all convective internal gains except for people: SumIntGainExceptPeople
    4320    29945519 :     if (state.dataHybridModel->FlagHybridModel_PC) {
    4321             :         // TODO: For now, don't do space heat balance with hybrid model
    4322        8212 :         this->SumIntGainExceptPeople = InternalHeatGains::SumAllInternalConvectionGainsExceptPeople(state, zoneNum);
    4323             :     }
    4324             : 
    4325             :     //    ZoneTempHistoryTerm = (3.0D0 * ZTM1(zoneNum) - (3.0D0/2.0D0) * ZTM2(zoneNum) + (1.0D0/3.0D0) * ZTM3(zoneNum))
    4326    29945519 :     int ZoneNodeNum = thisZone.SystemZoneNodeNumber;
    4327    29945519 :     if (spaceNum > 0) {
    4328       29170 :         ZoneNodeNum = state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber;
    4329             :     }
    4330             : 
    4331    29945519 :     Real64 SNLoad = 0.0;
    4332             : 
    4333    29945519 :     if (ZoneNodeNum > 0) { // This zone is controlled by a zone equipment configuration or zone plenum
    4334    26816642 :         auto &thisSystemNode = state.dataLoopNodes->Node(ZoneNodeNum);
    4335             : 
    4336             :         // Heat balance coefficients for controlled zone, i.e. with system air flow
    4337    26816642 :         this->TempDepCoef = this->SumHA + this->SumMCp + this->SumSysMCp;
    4338    26816642 :         this->TempIndCoef = this->SumIntGain + this->SumHATsurf - this->SumHATref + this->SumMCpT + this->SumSysMCpT +
    4339    26816642 :                             (this->NonAirSystemResponse / ZoneMult + this->SysDepZoneLoadsLagged);
    4340             : 
    4341    26816642 :         if (state.afn->distribution_simulated) {
    4342      232029 :             this->TempIndCoef += state.afn->exchangeData(zoneNum).TotalSen;
    4343             :         }
    4344             : 
    4345             :         // Solve for zone air temperature
    4346    26816642 :         switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    4347    14723288 :         case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    4348    14723288 :             this->ZT = (this->TempIndCoef + this->AirPowerCap * (3.0 * this->ZTM[0] - (3.0 / 2.0) * this->ZTM[1] + (1.0 / 3.0) * this->ZTM[2])) /
    4349    14723288 :                        ((11.0 / 6.0) * this->AirPowerCap + this->TempDepCoef);
    4350    14723288 :         } break;
    4351    12061752 :         case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    4352    12061752 :             if (this->TempDepCoef == 0.0) { // B=0
    4353           0 :                 this->ZT = this->T1 + this->TempIndCoef / this->AirPowerCap;
    4354             :             } else {
    4355    12061752 :                 this->ZT = (this->T1 - this->TempIndCoef / this->TempDepCoef) * std::exp(min(700.0, -this->TempDepCoef / this->AirPowerCap)) +
    4356    12061752 :                            this->TempIndCoef / this->TempDepCoef;
    4357             :             }
    4358    12061752 :         } break;
    4359       31602 :         case DataHeatBalance::SolutionAlgo::EulerMethod: {
    4360       31602 :             this->ZT = (this->AirPowerCap * this->T1 + this->TempIndCoef) / (this->AirPowerCap + this->TempDepCoef);
    4361       31602 :         } break;
    4362           0 :         default:
    4363           0 :             break;
    4364             :         }
    4365             :         // Update zone node temperature and thermostat temperature unless already updated in Room Air Model,
    4366             :         // calculate load correction factor
    4367    26816642 :         if (!state.dataRoomAir->anyNonMixingRoomAirModel) {
    4368             :             // Fully mixed
    4369    26708422 :             thisSystemNode.Temp = this->ZT;
    4370             :             // SpaceHB TODO: What to do here if this is for space
    4371    26708422 :             if (spaceNum == 0) {
    4372    26679252 :                 state.dataHeatBalFanSys->TempTstatAir(zoneNum) = this->ZT;
    4373             :             }
    4374    26708422 :             state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0;
    4375             :         } else {
    4376      108220 :             auto &thisAirModel = state.dataRoomAir->AirModel(zoneNum);
    4377      108220 :             if ((thisAirModel.AirModel == RoomAir::RoomAirModel::Mixing) || (!thisAirModel.SimAirModel)) {
    4378             :                 // Fully mixed
    4379       41760 :                 thisSystemNode.Temp = this->ZT;
    4380             :                 // SpaceHB TODO: What to do here if this is for space
    4381       41760 :                 if (spaceNum == 0) {
    4382       41760 :                     state.dataHeatBalFanSys->TempTstatAir(zoneNum) = this->ZT;
    4383             :                 }
    4384       41760 :                 state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0;
    4385       66460 :             } else if (state.dataRoomAir->IsZoneDispVent3Node(zoneNum) || state.dataRoomAir->IsZoneUFAD(zoneNum)) {
    4386             :                 // UCSDDV: Not fully mixed - calculate factor to correct load for fully mixed assumption
    4387             :                 // Space HB TODO: Space HB doesn't mix with DV etc.
    4388       13152 :                 if (this->SumSysMCp > HVAC::SmallMassFlow) {
    4389       12303 :                     Real64 TempSupplyAir = this->SumSysMCpT / this->SumSysMCp; // Non-negligible flow, calculate supply air temperature
    4390       12303 :                     if (std::abs(TempSupplyAir - this->ZT) > state.dataHeatBal->TempConvergTol) {
    4391       12035 :                         state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = (TempSupplyAir - thisSystemNode.Temp) / (TempSupplyAir - this->ZT);
    4392             :                         // constrain value to something reasonable
    4393       12035 :                         state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = max(-3.0, state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum));
    4394       12035 :                         state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = min(3.0, state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum));
    4395             : 
    4396             :                     } else {
    4397         268 :                         state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0; // Indeterminate
    4398             :                     }
    4399             :                 } else {
    4400             :                     // Negligible flow, assume mixed - reasonable lagged starting value for first step time with significant flow
    4401         849 :                     state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0;
    4402             :                 }
    4403       53308 :             } else if (thisAirModel.SimAirModel && ((thisAirModel.AirModel == RoomAir::RoomAirModel::UserDefined) ||
    4404       16039 :                                                     (thisAirModel.AirModel == RoomAir::RoomAirModel::DispVent1Node))) {
    4405       45895 :                 if (this->SumSysMCp > HVAC::SmallMassFlow) {
    4406       45535 :                     Real64 TempSupplyAir = this->SumSysMCpT / this->SumSysMCp; // Non-negligible flow, calculate supply air temperature
    4407       45535 :                     if (std::abs(TempSupplyAir - this->ZT) > state.dataHeatBal->TempConvergTol) {
    4408       45531 :                         state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = (TempSupplyAir - thisSystemNode.Temp) / (TempSupplyAir - this->ZT);
    4409             :                         // constrain value
    4410       45531 :                         state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = max(-3.0, state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum));
    4411       45531 :                         state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = min(3.0, state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum));
    4412             : 
    4413             :                     } else {
    4414           4 :                         state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0; // Indeterminate
    4415             :                     }
    4416             :                 } else {
    4417             :                     // Negligible flow, assume mixed - reasonable lagged starting value for first step time with significant flow
    4418         360 :                     state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0;
    4419             :                 }
    4420       53308 :             } else if (thisAirModel.AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    4421             :                 // Zone node used in the RoomAirflowNetwork model
    4422        7413 :                 this->ZT = state.dataRoomAir->AFNZoneInfo(zoneNum).Node(state.dataRoomAir->AFNZoneInfo(zoneNum).ControlAirNodeID).AirTemp;
    4423        7413 :                 thisSystemNode.Temp = this->ZT;
    4424             :                 // SpaceHB TODO: What to do here if this is for space
    4425        7413 :                 if (spaceNum == 0) {
    4426        7413 :                     state.dataHeatBalFanSys->TempTstatAir(zoneNum) = this->ZT;
    4427             :                 }
    4428        7413 :                 state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0;
    4429             :             } else {
    4430           0 :                 thisSystemNode.Temp = this->ZT;
    4431             :                 // SpaceHB TODO: What to do here if this is for space
    4432           0 :                 if (spaceNum == 0) {
    4433           0 :                     state.dataHeatBalFanSys->TempTstatAir(zoneNum) = this->ZT;
    4434             :                 }
    4435           0 :                 state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0;
    4436             :             }
    4437             :         }
    4438             : 
    4439             :         // Sensible load is the enthalpy into the zone minus the enthalpy that leaves the zone.
    4440    26816642 :         Real64 CpAir = Psychrometrics::PsyCpAirFnW(this->airHumRat);
    4441    26816642 :         Real64 ZoneEnthalpyIn = this->SumSysMCpT;
    4442             : 
    4443             :         // SNLOAD is the single zone load, without Zone Multiplier or Zone List Multiplier
    4444    26816642 :         SNLoad = ZoneEnthalpyIn - (thisSystemNode.MassFlowRate / ZoneMult) * CpAir * thisSystemNode.Temp + this->NonAirSystemResponse / ZoneMult +
    4445    26816642 :                  this->SysDepZoneLoadsLagged;
    4446             : 
    4447             :     } else {
    4448             : 
    4449             :         // Heat balance coefficients for uncontrolled zone, i.e. without system air flow
    4450     3128877 :         this->TempDepCoef = this->SumHA + this->SumMCp;
    4451     3128877 :         this->TempIndCoef = this->SumIntGain + this->SumHATsurf - this->SumHATref + this->SumMCpT;
    4452             : 
    4453     3128877 :         if (state.afn->distribution_simulated) {
    4454      146507 :             this->TempIndCoef += state.afn->exchangeData(zoneNum).TotalSen;
    4455             :         }
    4456             : 
    4457             :         // Solve for zone air temperature
    4458     3128877 :         switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    4459     2194868 :         case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    4460     2194868 :             this->ZT = (this->TempIndCoef + this->AirPowerCap * (3.0 * this->ZTM[0] - (3.0 / 2.0) * this->ZTM[1] + (1.0 / 3.0) * this->ZTM[2])) /
    4461     2194868 :                        ((11.0 / 6.0) * this->AirPowerCap + this->TempDepCoef);
    4462             :             // Exact solution
    4463     2194868 :         } break;
    4464      927401 :         case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    4465      927401 :             if (this->TempDepCoef == 0.0) { // B=0
    4466           0 :                 this->ZT = this->T1 + this->TempIndCoef / this->AirPowerCap;
    4467             :             } else {
    4468      927401 :                 this->ZT = (this->T1 - this->TempIndCoef / this->TempDepCoef) * std::exp(min(700.0, -this->TempDepCoef / this->AirPowerCap)) +
    4469      927401 :                            this->TempIndCoef / this->TempDepCoef;
    4470             :             }
    4471      927401 :         } break;
    4472        6608 :         case DataHeatBalance::SolutionAlgo::EulerMethod: {
    4473        6608 :             this->ZT = (this->AirPowerCap * this->T1 + this->TempIndCoef) / (this->AirPowerCap + this->TempDepCoef);
    4474        6608 :         } break;
    4475           0 :         default:
    4476           0 :             break;
    4477             :         }
    4478             : 
    4479             :         // SpaceHB TODO: For now, room air model is only for zones
    4480     3128877 :         if (spaceNum == 0 && state.dataRoomAir->anyNonMixingRoomAirModel) {
    4481       51822 :             if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    4482           0 :                 this->ZT = state.dataRoomAir->AFNZoneInfo(zoneNum).Node(state.dataRoomAir->AFNZoneInfo(zoneNum).ControlAirNodeID).AirTemp;
    4483             :             }
    4484             :         }
    4485             : 
    4486             :         // No sensible load
    4487     3128877 :         SNLoad = 0.0;
    4488             :     }
    4489             : 
    4490             :     // Hybrid modeling start
    4491             :     // SpaceHB TODO: For now, hybrid model is only for zones
    4492    29945519 :     if (spaceNum == 0 && state.dataHybridModel->FlagHybridModel) {
    4493       30204 :         if ((state.dataHybridModel->HybridModelZone(zoneNum).InfiltrationCalc_T ||
    4494       24706 :              state.dataHybridModel->HybridModelZone(zoneNum).InternalThermalMassCalc_T ||
    4495       16462 :              state.dataHybridModel->HybridModelZone(zoneNum).PeopleCountCalc_T) &&
    4496       54910 :             (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing)) {
    4497        1800 :             InverseModelTemperature(state,
    4498             :                                     zoneNum,
    4499             :                                     this->SumIntGain,
    4500             :                                     this->SumIntGainExceptPeople,
    4501             :                                     this->SumHA,
    4502             :                                     this->SumHATsurf,
    4503             :                                     this->SumHATref,
    4504             :                                     this->SumMCp,
    4505             :                                     this->SumMCpT,
    4506             :                                     this->SumSysMCp,
    4507             :                                     this->SumSysMCpT,
    4508             :                                     this->AirPowerCap);
    4509             :         }
    4510             :     }
    4511             : 
    4512    29945519 :     this->MAT = this->ZT;
    4513             : 
    4514             :     // Determine sensible load heating/cooling rate and energy
    4515    29945519 :     if (spaceNum > 0) {
    4516       29170 :         state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).reportZoneAirSystemSensibleLoads(state, SNLoad);
    4517             :     } else {
    4518    29916349 :         state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).reportZoneAirSystemSensibleLoads(state, SNLoad);
    4519             :     }
    4520             : 
    4521             :     // Final humidity calcs
    4522    29945519 :     this->correctHumRat(state, zoneNum, spaceNum);
    4523             : 
    4524    29945519 :     this->airHumRat = this->airHumRatTemp;
    4525    29945519 :     this->airRelHum = 100.0 * Psychrometrics::PsyRhFnTdbWPb(state, this->ZT, this->airHumRat, state.dataEnvrn->OutBaroPress, RoutineName);
    4526             : 
    4527             :     // tempChange is used by HVACManager to determine if the timestep needs to be shortened.
    4528    29945519 :     bool isMixed = true;
    4529             :     // SpaceHB TODO: For now, room air model is only for zones
    4530    29945519 :     if (spaceNum == 0 && state.dataRoomAir->anyNonMixingRoomAirModel) {
    4531      313764 :         isMixed = !((state.dataRoomAir->IsZoneDispVent3Node(zoneNum) && !state.dataRoomAir->ZoneDispVent3NodeMixedFlag(zoneNum)) ||
    4532      153722 :                     (state.dataRoomAir->IsZoneUFAD(zoneNum) && !state.dataRoomAir->ZoneUFADMixedFlag(zoneNum)));
    4533             :     }
    4534    29945519 :     switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    4535    16918156 :     case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    4536    16918156 :         if (isMixed) {
    4537    16905004 :             tempChange = max(tempChange, std::abs(this->ZT - this->ZTM[0]));
    4538             :         } else {
    4539       26304 :             tempChange = max(tempChange,
    4540       13152 :                              max(std::abs(state.dataRoomAir->ZTOC(zoneNum) - state.dataRoomAir->ZTMOC(zoneNum)[0]),
    4541       13152 :                                  std::abs(state.dataRoomAir->ZTMX(zoneNum) - state.dataRoomAir->ZTMMX(zoneNum)[0])));
    4542             :         }
    4543    16918156 :     } break;
    4544    13027363 :     case DataHeatBalance::SolutionAlgo::AnalyticalSolution:
    4545             :     case DataHeatBalance::SolutionAlgo::EulerMethod: {
    4546    13027363 :         if (isMixed) {
    4547    13025934 :             tempChange = max(tempChange, std::abs(this->ZT - this->T1));
    4548             :         } else {
    4549        1429 :             tempChange = max(tempChange,
    4550        1429 :                              max(std::abs(state.dataRoomAir->ZTOC(zoneNum) - state.dataRoomAir->Zone1OC(zoneNum)),
    4551        1429 :                                  std::abs(state.dataRoomAir->ZTMX(zoneNum) - state.dataRoomAir->Zone1MX(zoneNum))));
    4552             :         }
    4553    13027363 :     } break;
    4554           0 :     default:
    4555           0 :         break;
    4556             :     }
    4557             : 
    4558    29945519 :     return tempChange;
    4559             : }
    4560             : 
    4561     2804482 : void PushZoneTimestepHistories(EnergyPlusData &state)
    4562             : {
    4563             : 
    4564             :     // SUBROUTINE INFORMATION:
    4565             :     //       AUTHOR         Brent Griffith
    4566             :     //       DATE WRITTEN   February 2008
    4567             : 
    4568             :     // PURPOSE OF THIS SUBROUTINE:
    4569             :     // push histories for timestep advancing
    4570             : 
    4571    22670650 :     for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    4572    19866168 :         state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum).pushZoneTimestepHistory(state, zoneNum);
    4573    19866168 :         if (state.dataHeatBal->doSpaceHeatBalance) {
    4574      113364 :             for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    4575       64782 :                 state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).pushZoneTimestepHistory(state, zoneNum, spaceNum);
    4576       48582 :             }
    4577             :         }
    4578             :     }
    4579     2804482 : }
    4580             : 
    4581    19930950 : void ZoneSpaceHeatBalanceData::pushZoneTimestepHistory(EnergyPlusData &state, int const zoneNum, int const spaceNum)
    4582             : {
    4583             : 
    4584    19930950 :     constexpr std::string_view routineName("pushTimestepHistories");
    4585    19930950 :     assert(zoneNum > 0);
    4586             : 
    4587    19930950 :     auto &thisAirModel = state.dataRoomAir->AirModel(zoneNum);
    4588             : 
    4589             :     // Push the temperature and humidity ratio histories
    4590             : 
    4591    79723800 :     for (int iHistory = 3; iHistory >= 1; --iHistory) {
    4592    59792850 :         this->XMAT[iHistory] = this->XMAT[iHistory - 1];
    4593    59792850 :         this->WPrevZoneTS[iHistory] = this->WPrevZoneTS[iHistory - 1];
    4594             :     }
    4595    19930950 :     this->XMAT[0] = this->ZTAV; // using average for whole zone time step.
    4596    19930950 :     this->XMPT = this->ZT;
    4597    19930950 :     this->WPrevZoneTS[0] = this->airHumRatAvg; // using average for whole zone time step.
    4598    19930950 :     this->airHumRat = this->airHumRatTemp;
    4599    19930950 :     this->WTimeMinusP = this->airHumRatTemp;
    4600    19930950 :     this->airRelHum = 100.0 * Psychrometrics::PsyRhFnTdbWPb(state, this->ZT, this->airHumRat, state.dataEnvrn->OutBaroPress, routineName);
    4601             : 
    4602             :     // SpaceHB TODO: For now, room air model is only for zones
    4603    19930950 :     if (spaceNum == 0) {
    4604    19866168 :         if (thisAirModel.AirModel == RoomAir::RoomAirModel::DispVent3Node || thisAirModel.AirModel == RoomAir::RoomAirModel::UFADInt ||
    4605    19850550 :             thisAirModel.AirModel == RoomAir::RoomAirModel::UFADExt) {
    4606       26442 :             state.dataRoomAir->XMATFloor(zoneNum)[3] = state.dataRoomAir->XMATFloor(zoneNum)[2];
    4607       26442 :             state.dataRoomAir->XMATFloor(zoneNum)[2] = state.dataRoomAir->XMATFloor(zoneNum)[1];
    4608       26442 :             state.dataRoomAir->XMATFloor(zoneNum)[1] = state.dataRoomAir->XMATFloor(zoneNum)[0];
    4609       26442 :             state.dataRoomAir->XMATFloor(zoneNum)[0] = state.dataRoomAir->ZTFloor(zoneNum);
    4610       26442 :             state.dataRoomAir->MATFloor(zoneNum) = state.dataRoomAir->ZTFloor(zoneNum);
    4611             : 
    4612       26442 :             state.dataRoomAir->XMATOC(zoneNum)[3] = state.dataRoomAir->XMATOC(zoneNum)[2];
    4613       26442 :             state.dataRoomAir->XMATOC(zoneNum)[2] = state.dataRoomAir->XMATOC(zoneNum)[1];
    4614       26442 :             state.dataRoomAir->XMATOC(zoneNum)[1] = state.dataRoomAir->XMATOC(zoneNum)[0];
    4615       26442 :             state.dataRoomAir->XMATOC(zoneNum)[0] = state.dataRoomAir->ZTOC(zoneNum);
    4616       26442 :             state.dataRoomAir->MATOC(zoneNum) = state.dataRoomAir->ZTOC(zoneNum);
    4617             : 
    4618       26442 :             state.dataRoomAir->XMATMX(zoneNum)[3] = state.dataRoomAir->XMATMX(zoneNum)[2];
    4619       26442 :             state.dataRoomAir->XMATMX(zoneNum)[2] = state.dataRoomAir->XMATMX(zoneNum)[1];
    4620       26442 :             state.dataRoomAir->XMATMX(zoneNum)[1] = state.dataRoomAir->XMATMX(zoneNum)[0];
    4621       26442 :             state.dataRoomAir->XMATMX(zoneNum)[0] = state.dataRoomAir->ZTMX(zoneNum);
    4622       26442 :             state.dataRoomAir->MATMX(zoneNum) = state.dataRoomAir->ZTMX(zoneNum);
    4623             :         }
    4624             : 
    4625             :         // for RoomAirflowNetwork model
    4626    19866168 :         if (thisAirModel.AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    4627       40425 :             for (auto &afnNode : state.dataRoomAir->AFNZoneInfo(zoneNum).Node) {
    4628       34650 :                 afnNode.AirTempX[3] = afnNode.AirTempX[2];
    4629       34650 :                 afnNode.AirTempX[2] = afnNode.AirTempX[1];
    4630       34650 :                 afnNode.AirTempX[1] = afnNode.AirTempX[0];
    4631       34650 :                 afnNode.AirTempX[0] = afnNode.AirTemp;
    4632             : 
    4633       34650 :                 afnNode.HumRatX[3] = afnNode.HumRatX[2];
    4634       34650 :                 afnNode.HumRatX[2] = afnNode.HumRatX[1];
    4635       34650 :                 afnNode.HumRatX[1] = afnNode.HumRatX[0];
    4636       34650 :                 afnNode.HumRatX[0] = afnNode.HumRat;
    4637             :             }
    4638             :         }
    4639             :     }
    4640             : 
    4641    19930950 :     if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
    4642     7222767 :         this->TM2 = this->TMX;
    4643     7222767 :         this->TMX = this->ZTAV; // using average for whole zone time step.
    4644     7222767 :         this->WM2 = this->WMX;
    4645     7222767 :         this->WMX = this->airHumRatAvg; // using average for whole zone time step.
    4646             :         // SpaceHB TODO: For now, room air model is only for zones
    4647     7222767 :         if (spaceNum == 0) {
    4648     7222767 :             if (thisAirModel.AirModel == RoomAir::RoomAirModel::DispVent3Node || thisAirModel.AirModel == RoomAir::RoomAirModel::UFADInt ||
    4649     7216989 :                 thisAirModel.AirModel == RoomAir::RoomAirModel::UFADExt) {
    4650        5778 :                 state.dataRoomAir->ZoneM2Floor(zoneNum) = state.dataRoomAir->ZoneMXFloor(zoneNum);
    4651        5778 :                 state.dataRoomAir->ZoneMXFloor(zoneNum) = state.dataRoomAir->ZTFloor(zoneNum); // using average for whole zone time step.
    4652        5778 :                 state.dataRoomAir->ZoneM2OC(zoneNum) = state.dataRoomAir->ZoneMXOC(zoneNum);
    4653        5778 :                 state.dataRoomAir->ZoneMXOC(zoneNum) = state.dataRoomAir->ZTOC(zoneNum); // using average for whole zone time step.
    4654        5778 :                 state.dataRoomAir->ZoneM2MX(zoneNum) = state.dataRoomAir->ZoneMXMX(zoneNum);
    4655        5778 :                 state.dataRoomAir->ZoneMXMX(zoneNum) = state.dataRoomAir->ZTMX(zoneNum); // using average for whole zone time step.
    4656             :             }
    4657             : 
    4658     7222767 :             if (thisAirModel.AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    4659           0 :                 for (auto &afnNode : state.dataRoomAir->AFNZoneInfo(zoneNum).Node) {
    4660           0 :                     afnNode.AirTempT2 = afnNode.AirTempTX;
    4661           0 :                     afnNode.AirTempTX = afnNode.AirTemp;
    4662             : 
    4663           0 :                     afnNode.HumRatT2 = afnNode.HumRatTX;
    4664           0 :                     afnNode.HumRatTX = afnNode.HumRat;
    4665             :                 }
    4666             :             }
    4667             :         }
    4668             :     }
    4669    19930950 : }
    4670             : 
    4671     1062007 : void PushSystemTimestepHistories(EnergyPlusData &state)
    4672             : {
    4673             : 
    4674             :     // SUBROUTINE INFORMATION:
    4675             :     //       AUTHOR         Brent Griffith
    4676             :     //       DATE WRITTEN   April 2008
    4677             : 
    4678             :     // PURPOSE OF THIS SUBROUTINE:
    4679             :     // Push the temperature and humidity ratio histories back in time
    4680             : 
    4681    11112188 :     for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    4682    10050181 :         state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum).pushSystemTimestepHistory(state, zoneNum);
    4683    10050181 :         if (state.dataHeatBal->doSpaceHeatBalance) {
    4684       36828 :             for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    4685       21612 :                 state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).pushSystemTimestepHistory(state, zoneNum, spaceNum);
    4686       15216 :             }
    4687             :         }
    4688             :     }
    4689     1062007 : }
    4690             : 
    4691    10071793 : void ZoneSpaceHeatBalanceData::pushSystemTimestepHistory(EnergyPlusData &state, int const zoneNum, int const spaceNum)
    4692             : {
    4693    10071793 :     assert(zoneNum > 0);
    4694    40287172 :     for (int iHistory = 3; iHistory >= 1; --iHistory) {
    4695    30215379 :         this->DSXMAT[iHistory] = this->DSXMAT[iHistory - 1];
    4696    30215379 :         this->DSWPrevZoneTS[iHistory] = this->DSWPrevZoneTS[iHistory - 1];
    4697             :     }
    4698    10071793 :     this->DSXMAT[0] = this->MAT;
    4699    10071793 :     this->DSWPrevZoneTS[0] = this->airHumRat;
    4700             : 
    4701             :     // SpaceHB TODO: For now, room air model is only for zones
    4702    10071793 :     if (spaceNum == 0 && state.dataRoomAir->anyNonMixingRoomAirModel) {
    4703       33820 :         if (state.dataRoomAir->IsZoneDispVent3Node(zoneNum) || state.dataRoomAir->IsZoneUFAD(zoneNum)) {
    4704        5868 :             state.dataRoomAir->DSXMATFloor(zoneNum)[3] = state.dataRoomAir->DSXMATFloor(zoneNum)[2];
    4705        5868 :             state.dataRoomAir->DSXMATFloor(zoneNum)[2] = state.dataRoomAir->DSXMATFloor(zoneNum)[1];
    4706        5868 :             state.dataRoomAir->DSXMATFloor(zoneNum)[1] = state.dataRoomAir->DSXMATFloor(zoneNum)[0];
    4707        5868 :             state.dataRoomAir->DSXMATFloor(zoneNum)[0] = state.dataRoomAir->MATFloor(zoneNum);
    4708             : 
    4709        5868 :             state.dataRoomAir->DSXMATOC(zoneNum)[3] = state.dataRoomAir->DSXMATOC(zoneNum)[2];
    4710        5868 :             state.dataRoomAir->DSXMATOC(zoneNum)[2] = state.dataRoomAir->DSXMATOC(zoneNum)[1];
    4711        5868 :             state.dataRoomAir->DSXMATOC(zoneNum)[1] = state.dataRoomAir->DSXMATOC(zoneNum)[0];
    4712        5868 :             state.dataRoomAir->DSXMATOC(zoneNum)[0] = state.dataRoomAir->MATOC(zoneNum);
    4713             : 
    4714        5868 :             state.dataRoomAir->DSXMATMX(zoneNum)[3] = state.dataRoomAir->DSXMATMX(zoneNum)[2];
    4715        5868 :             state.dataRoomAir->DSXMATMX(zoneNum)[2] = state.dataRoomAir->DSXMATMX(zoneNum)[1];
    4716        5868 :             state.dataRoomAir->DSXMATMX(zoneNum)[1] = state.dataRoomAir->DSXMATMX(zoneNum)[0];
    4717        5868 :             state.dataRoomAir->DSXMATMX(zoneNum)[0] = state.dataRoomAir->MATMX(zoneNum);
    4718             :         }
    4719       33820 :         if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    4720       11466 :             for (auto &afnNode : state.dataRoomAir->AFNZoneInfo(zoneNum).Node) {
    4721        9828 :                 afnNode.AirTempDSX[3] = afnNode.AirTempDSX[2];
    4722        9828 :                 afnNode.AirTempDSX[2] = afnNode.AirTempDSX[1];
    4723        9828 :                 afnNode.AirTempDSX[1] = afnNode.AirTempDSX[0];
    4724        9828 :                 afnNode.AirTempDSX[0] = afnNode.AirTemp;
    4725             : 
    4726        9828 :                 afnNode.HumRatDSX[3] = afnNode.HumRatDSX[2];
    4727        9828 :                 afnNode.HumRatDSX[2] = afnNode.HumRatDSX[1];
    4728        9828 :                 afnNode.HumRatDSX[1] = afnNode.HumRatDSX[0];
    4729        9828 :                 afnNode.HumRatDSX[0] = afnNode.HumRat;
    4730             :             }
    4731             :         }
    4732             :     }
    4733             : 
    4734    10071793 :     if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
    4735     5804596 :         this->TM2 = this->TMX;
    4736     5804596 :         this->TMX = this->MAT; // using average for whole zone time step.
    4737     5804596 :         this->WM2 = this->WMX;
    4738     5804596 :         this->WMX = this->airHumRatTemp; // using average for whole zone time step.
    4739             : 
    4740             :         // SpaceHB TODO: For now, room air model is only for zones
    4741     5804596 :         if (spaceNum == 0) {
    4742     5804596 :             if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::DispVent3Node ||
    4743    11608362 :                 state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::UFADInt ||
    4744     5803766 :                 state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::UFADExt) {
    4745         830 :                 state.dataRoomAir->ZoneM2Floor(zoneNum) = state.dataRoomAir->ZoneMXFloor(zoneNum);
    4746         830 :                 state.dataRoomAir->ZoneMXFloor(zoneNum) = state.dataRoomAir->ZTFloor(zoneNum); // using average for whole zone time step.
    4747         830 :                 state.dataRoomAir->ZoneM2OC(zoneNum) = state.dataRoomAir->ZoneMXOC(zoneNum);
    4748         830 :                 state.dataRoomAir->ZoneMXOC(zoneNum) = state.dataRoomAir->ZTOC(zoneNum); // using average for whole zone time step.
    4749         830 :                 state.dataRoomAir->ZoneM2MX(zoneNum) = state.dataRoomAir->ZoneMXMX(zoneNum);
    4750         830 :                 state.dataRoomAir->ZoneMXMX(zoneNum) = state.dataRoomAir->ZTMX(zoneNum); // using average for whole zone time step.
    4751             :             }
    4752     5804596 :             if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    4753           0 :                 for (int LoopNode = 1; LoopNode <= state.dataRoomAir->AFNZoneInfo(zoneNum).NumOfAirNodes; ++LoopNode) {
    4754           0 :                     auto &afnNode = state.dataRoomAir->AFNZoneInfo(zoneNum).Node(LoopNode);
    4755           0 :                     afnNode.AirTempT2 = afnNode.AirTempTX;
    4756           0 :                     afnNode.AirTempTX = afnNode.AirTemp;
    4757             : 
    4758           0 :                     afnNode.HumRatT2 = afnNode.HumRatTX;
    4759           0 :                     afnNode.HumRatTX = afnNode.HumRat;
    4760             :                 }
    4761             :             }
    4762             :         }
    4763             :     }
    4764    10071793 : }
    4765             : 
    4766           0 : void RevertZoneTimestepHistories(EnergyPlusData &state)
    4767             : {
    4768             :     // SUBROUTINE INFORMATION:
    4769             :     //       AUTHOR         Brent Griffith
    4770             :     //       DATE WRITTEN   February 2008
    4771             : 
    4772             :     // PURPOSE OF THIS SUBROUTINE:
    4773             :     // Revert the temperature and humidity ratio histories
    4774             : 
    4775           0 :     for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
    4776           0 :         state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum).revertZoneTimestepHistory(state, zoneNum);
    4777           0 :         if (state.dataHeatBal->doSpaceHeatBalance) {
    4778           0 :             for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    4779           0 :                 state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).revertZoneTimestepHistory(state, zoneNum, spaceNum);
    4780           0 :             }
    4781             :         }
    4782             :     }
    4783           0 : }
    4784             : 
    4785           0 : void ZoneSpaceHeatBalanceData::revertZoneTimestepHistory(EnergyPlusData &state, int const zoneNum, int const spaceNum)
    4786             : {
    4787           0 :     assert(zoneNum > 0);
    4788             : 
    4789           0 :     for (int iHistory = 0; iHistory <= 2; ++iHistory) {
    4790           0 :         this->XMAT[iHistory] = this->XMAT[iHistory + 1];
    4791           0 :         this->WPrevZoneTS[iHistory] = this->WPrevZoneTS[iHistory + 1];
    4792             :     }
    4793             : 
    4794             :     // SpaceHB TODO: For now, room air model is only for zones
    4795           0 :     if (spaceNum == 0) {
    4796           0 :         if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::DispVent3Node ||
    4797           0 :             state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::UFADInt ||
    4798           0 :             state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::UFADExt) {
    4799             : 
    4800           0 :             state.dataRoomAir->XMATFloor(zoneNum)[0] = state.dataRoomAir->XMATFloor(zoneNum)[1];
    4801           0 :             state.dataRoomAir->XMATFloor(zoneNum)[1] = state.dataRoomAir->XMATFloor(zoneNum)[2];
    4802           0 :             state.dataRoomAir->XMATFloor(zoneNum)[2] = state.dataRoomAir->XMATFloor(zoneNum)[3];
    4803             : 
    4804           0 :             state.dataRoomAir->XMATOC(zoneNum)[0] = state.dataRoomAir->XMATOC(zoneNum)[1];
    4805           0 :             state.dataRoomAir->XMATOC(zoneNum)[1] = state.dataRoomAir->XMATOC(zoneNum)[2];
    4806           0 :             state.dataRoomAir->XMATOC(zoneNum)[2] = state.dataRoomAir->XMATOC(zoneNum)[3];
    4807             : 
    4808           0 :             state.dataRoomAir->XMATMX(zoneNum)[0] = state.dataRoomAir->XMATMX(zoneNum)[1];
    4809           0 :             state.dataRoomAir->XMATMX(zoneNum)[1] = state.dataRoomAir->XMATMX(zoneNum)[2];
    4810           0 :             state.dataRoomAir->XMATMX(zoneNum)[3] = state.dataRoomAir->XMATMX(zoneNum)[3];
    4811             :         }
    4812             : 
    4813           0 :         if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    4814           0 :             for (auto &afnNode : state.dataRoomAir->AFNZoneInfo(zoneNum).Node) {
    4815           0 :                 afnNode.AirTempX[0] = afnNode.AirTempX[1];
    4816           0 :                 afnNode.AirTempX[1] = afnNode.AirTempX[2];
    4817           0 :                 afnNode.AirTempX[2] = afnNode.AirTempX[3];
    4818             : 
    4819           0 :                 afnNode.HumRatX[0] = afnNode.HumRatX[1];
    4820           0 :                 afnNode.HumRatX[1] = afnNode.HumRatX[2];
    4821           0 :                 afnNode.HumRatX[2] = afnNode.HumRatX[3];
    4822             :             }
    4823             :         }
    4824             :     }
    4825           0 : }
    4826             : 
    4827    29945519 : void ZoneSpaceHeatBalanceData::correctHumRat(EnergyPlusData &state, int const zoneNum, int const spaceNum)
    4828             : {
    4829             : 
    4830             :     // SUBROUTINE INFORMATION:
    4831             :     //       AUTHOR         Richard Liesen
    4832             :     //       DATE WRITTEN   2000
    4833             :     // REFERENCES: Routine FinalZnCalcs - FINAL ZONE CALCULATIONS, authored by Dale Herron for BLAST.
    4834             : 
    4835    29945519 :     assert(zoneNum > 0);
    4836             :     static constexpr std::string_view RoutineName("correctHumRat");
    4837             : 
    4838    29945519 :     Real64 MoistureMassFlowRate = 0.0;
    4839    29945519 :     Real64 ZoneMassFlowRate = 0.0;
    4840    29945519 :     auto &zone = state.dataHeatBal->Zone(zoneNum);
    4841    29945519 :     int ZoneMult = zone.Multiplier * zone.ListMultiplier;
    4842    29945519 :     bool ControlledZoneAirFlag = zone.IsControlled;
    4843    29945519 :     bool ZoneRetPlenumAirFlag = zone.IsReturnPlenum;
    4844    29945519 :     bool ZoneSupPlenumAirFlag = zone.IsSupplyPlenum;
    4845             : 
    4846    29945519 :     if (ControlledZoneAirFlag) { // If there is system flow then calculate the flow rates
    4847    25713232 :         auto &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(zoneNum);
    4848             :         // Calculate moisture flow rate into each zone
    4849    51867797 :         for (int NodeNum = 1; NodeNum <= zoneEquipConfig.NumInletNodes; ++NodeNum) {
    4850    26154565 :             auto &inletNode = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(NodeNum));
    4851    26154565 :             MoistureMassFlowRate += (inletNode.MassFlowRate * inletNode.HumRat) / ZoneMult;
    4852    26154565 :             ZoneMassFlowRate += inletNode.MassFlowRate / ZoneMult;
    4853             :         }
    4854             : 
    4855             :         // Do the calculations for the plenum zone
    4856     4232287 :     } else if (ZoneRetPlenumAirFlag) {
    4857     1083884 :         int ZoneRetPlenumNum = zone.PlenumCondNum;
    4858     1083884 :         auto &zoneRetPlenCond = state.dataZonePlenum->ZoneRetPlenCond(ZoneRetPlenumNum);
    4859     6284133 :         for (int NodeNum = 1; NodeNum <= zoneRetPlenCond.NumInletNodes; ++NodeNum) {
    4860     5200249 :             auto &inletNode = state.dataLoopNodes->Node(zoneRetPlenCond.InletNode(NodeNum));
    4861     5200249 :             MoistureMassFlowRate += (inletNode.MassFlowRate * inletNode.HumRat) / ZoneMult;
    4862     5200249 :             ZoneMassFlowRate += inletNode.MassFlowRate / ZoneMult;
    4863             :         }
    4864             :         // add in the leak flow
    4865     6302773 :         for (int ADUListIndex = 1; ADUListIndex <= zoneRetPlenCond.NumADUs; ++ADUListIndex) {
    4866     5218889 :             int ADUNum = zoneRetPlenCond.ADUIndex(ADUListIndex);
    4867     5218889 :             auto &airDistUnit = state.dataDefineEquipment->AirDistUnit(ADUNum);
    4868     5218889 :             if (airDistUnit.UpStreamLeak) {
    4869      106595 :                 int ADUInNode = airDistUnit.InletNodeNum;
    4870      106595 :                 MoistureMassFlowRate += (airDistUnit.MassFlowRateUpStrLk * state.dataLoopNodes->Node(ADUInNode).HumRat) / ZoneMult;
    4871      106595 :                 ZoneMassFlowRate += airDistUnit.MassFlowRateUpStrLk / ZoneMult;
    4872             :             }
    4873     5218889 :             if (airDistUnit.DownStreamLeak) {
    4874      106595 :                 int ADUOutNode = airDistUnit.OutletNodeNum;
    4875      106595 :                 MoistureMassFlowRate += (airDistUnit.MassFlowRateDnStrLk * state.dataLoopNodes->Node(ADUOutNode).HumRat) / ZoneMult;
    4876      106595 :                 ZoneMassFlowRate += airDistUnit.MassFlowRateDnStrLk / ZoneMult;
    4877             :             }
    4878             :         }
    4879             : 
    4880     3148403 :     } else if (ZoneSupPlenumAirFlag) {
    4881       19526 :         int ZoneSupPlenumNum = zone.PlenumCondNum;
    4882       19526 :         auto &inletNode = state.dataLoopNodes->Node(state.dataZonePlenum->ZoneSupPlenCond(ZoneSupPlenumNum).InletNode);
    4883       19526 :         MoistureMassFlowRate += (inletNode.MassFlowRate * inletNode.HumRat) / ZoneMult;
    4884       19526 :         ZoneMassFlowRate += inletNode.MassFlowRate / ZoneMult;
    4885             :     }
    4886             : 
    4887             :     // Calculate hourly humidity ratio from infiltration + humidity added from latent load + system added moisture
    4888    29945519 :     Real64 LatentGain = this->latentGain + state.dataHeatBalFanSys->SumLatentHTRadSys(zoneNum) + state.dataHeatBalFanSys->SumLatentPool(zoneNum);
    4889             : 
    4890    29945519 :     Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    4891             : 
    4892             :     // Calculate the coefficients for the 3rd order derivative for final
    4893             :     // zone humidity ratio.  The A, B, C coefficients are analogous to the
    4894             :     // heat balance.  There are 2 cases that should be considered, system
    4895             :     // operating and system shutdown.
    4896             : 
    4897    29945519 :     Real64 const RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->ZT, this->airHumRat, RoutineName);
    4898    29945519 :     Real64 const H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(this->airHumRat, this->ZT);
    4899             : 
    4900    29945519 :     Real64 B = (LatentGain / H2OHtOfVap) + ((this->OAMFL + this->VAMFL + this->CTMFL) * state.dataEnvrn->OutHumRat) + this->EAMFLxHumRat +
    4901    29945519 :                (MoistureMassFlowRate) + this->SumHmARaW + this->MixingMassFlowXHumRat + this->MDotOA * state.dataEnvrn->OutHumRat;
    4902    29945519 :     Real64 A = ZoneMassFlowRate + this->OAMFL + this->VAMFL + this->EAMFL + this->CTMFL + this->SumHmARa + this->MixingMassFlowZone + this->MDotOA;
    4903             : 
    4904    59399375 :     if (state.afn->multizone_always_simulated ||
    4905    29453856 :         (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
    4906       23258 :          state.afn->AirflowNetworkFanActivated)) {
    4907      509897 :         auto &exchangeData = state.afn->exchangeData(zoneNum);
    4908             :         // Multizone airflow calculated in AirflowNetwork
    4909      509897 :         B = (LatentGain / H2OHtOfVap) + (exchangeData.SumMHrW + exchangeData.SumMMHrW) + (MoistureMassFlowRate) + this->SumHmARaW;
    4910      509897 :         A = ZoneMassFlowRate + exchangeData.SumMHr + exchangeData.SumMMHr + this->SumHmARa;
    4911             :     }
    4912    29945519 :     Real64 C = RhoAir * zone.Volume * zone.ZoneVolCapMultpMoist / TimeStepSysSec;
    4913             : 
    4914    29945519 :     if (state.afn->distribution_simulated) {
    4915      378536 :         B += state.afn->exchangeData(zoneNum).TotalLat;
    4916             :     }
    4917             : 
    4918             :     // Use a 3rd order derivative to predict final zone humidity ratio and
    4919             :     // smooth the changes using the zone air capacitance.
    4920             :     // auto &zoneAirHumRatTemp = this->ZoneAirHumRatTemp;
    4921             :     // auto &zoneW1 = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).ZoneW1;
    4922    29945519 :     switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    4923    16918156 :     case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    4924    16918156 :         this->airHumRatTemp =
    4925    16918156 :             (B + C * (3.0 * this->WPrevZoneTSTemp[0] - (3.0 / 2.0) * this->WPrevZoneTSTemp[1] + (1.0 / 3.0) * this->WPrevZoneTSTemp[2])) /
    4926    16918156 :             ((11.0 / 6.0) * C + A);
    4927             :         // Exact solution
    4928    16918156 :     } break;
    4929    12989153 :     case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    4930    12989153 :         if (A == 0.0) { // B=0
    4931      521496 :             this->airHumRatTemp = this->W1 + B / C;
    4932             :         } else {
    4933    12467657 :             this->airHumRatTemp = (this->W1 - B / A) * std::exp(min(700.0, -A / C)) + B / A;
    4934             :         }
    4935    12989153 :     } break;
    4936       38210 :     case DataHeatBalance::SolutionAlgo::EulerMethod: {
    4937       38210 :         this->airHumRatTemp = (C * this->W1 + B) / (C + A);
    4938       38210 :     } break;
    4939           0 :     default:
    4940           0 :         break;
    4941             :     }
    4942             : 
    4943             :     // Set the humidity ratio to zero if the zone has been dried out
    4944    29945519 :     if (this->airHumRatTemp < 0.0) this->airHumRatTemp = 0.0;
    4945             : 
    4946             :     // Check to make sure that is saturated there is condensation in the zone
    4947             :     // by resetting to saturation conditions.
    4948    29945519 :     Real64 const WZSat = Psychrometrics::PsyWFnTdbRhPb(state, this->ZT, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
    4949             : 
    4950    29945519 :     if (this->airHumRatTemp > WZSat) this->airHumRatTemp = WZSat;
    4951             : 
    4952    29945519 :     if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    4953        7413 :         this->airHumRatTemp = state.dataRoomAir->AFNZoneInfo(zoneNum).Node(state.dataRoomAir->AFNZoneInfo(zoneNum).ControlAirNodeID).HumRat;
    4954             :     }
    4955             : 
    4956             :     // HybridModel with measured humidity ratio begins
    4957             :     // SpaceHB TODO: For now, hybrid model is only for zones
    4958    29945519 :     if (spaceNum == 0 && state.dataHybridModel->FlagHybridModel) {
    4959       30204 :         if ((state.dataHybridModel->HybridModelZone(zoneNum).InfiltrationCalc_H ||
    4960       27454 :              state.dataHybridModel->HybridModelZone(zoneNum).PeopleCountCalc_H) &&
    4961       57658 :             (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing)) {
    4962         600 :             Real64 LatentGainExceptPeople = 0.0;
    4963         600 :             if (state.dataHybridModel->HybridModelZone(zoneNum).PeopleCountCalc_H) {
    4964         298 :                 LatentGainExceptPeople = this->latentGainExceptPeople + state.dataHeatBalFanSys->SumLatentHTRadSys(zoneNum) +
    4965         298 :                                          state.dataHeatBalFanSys->SumLatentPool(zoneNum);
    4966             :             }
    4967             : 
    4968         600 :             InverseModelHumidity(state, zoneNum, LatentGain, LatentGainExceptPeople, ZoneMassFlowRate, MoistureMassFlowRate, H2OHtOfVap, RhoAir);
    4969             :         }
    4970             :     }
    4971             : 
    4972             :     // Now put the calculated info into the actual zone nodes; ONLY if there is zone air flow, i.e. controlled zone or plenum zone
    4973    29945519 :     int ZoneNodeNum = zone.SystemZoneNodeNumber;
    4974    29945519 :     if (spaceNum > 0) {
    4975       29170 :         ZoneNodeNum = state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber;
    4976             :     }
    4977    29945519 :     if (ZoneNodeNum > 0) {
    4978    26816642 :         state.dataLoopNodes->Node(ZoneNodeNum).HumRat = this->airHumRatTemp;
    4979    26816642 :         state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy = Psychrometrics::PsyHFnTdbW(this->ZT, this->airHumRatTemp);
    4980             :     }
    4981    29945519 :     if (state.dataHeatBal->DoLatentSizing) {
    4982       38334 :         Real64 sensibleLoad = 0.0;
    4983       38334 :         Real64 pSat = Psychrometrics::PsyPsatFnTemp(state, this->ZT, RoutineName);
    4984       38334 :         Real64 Tdp = Psychrometrics::PsyTdpFnWPb(state, this->airHumRatTemp, state.dataEnvrn->StdBaroPress);
    4985       38334 :         Real64 vaporPressureDiff = pSat - Psychrometrics::PsyPsatFnTemp(state, Tdp, RoutineName);
    4986       38334 :         if (spaceNum > 0) {
    4987           0 :             sensibleLoad = state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).airSysHeatRate +
    4988           0 :                            state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).airSysCoolRate;
    4989           0 :             state.dataZoneEnergyDemand->spaceSysMoistureDemand(spaceNum).reportZoneAirSystemMoistureLoads(
    4990             :                 state, LatentGain, sensibleLoad, vaporPressureDiff);
    4991             :         } else {
    4992       38334 :             sensibleLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).airSysHeatRate +
    4993       38334 :                            state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).airSysCoolRate;
    4994       38334 :             state.dataZoneEnergyDemand->ZoneSysMoistureDemand(zoneNum).reportZoneAirSystemMoistureLoads(
    4995             :                 state, LatentGain, sensibleLoad, vaporPressureDiff);
    4996             :         }
    4997             :     }
    4998    29945519 : }
    4999             : 
    5000       60400 : void DownInterpolate4HistoryValues(Real64 const OldTimeStep,
    5001             :                                    Real64 const NewTimeStep,
    5002             :                                    Real64 const oldVal0,
    5003             :                                    Real64 const oldVal1,
    5004             :                                    Real64 const oldVal2,
    5005             :                                    Real64 &newVal0,
    5006             :                                    Real64 &newVal1,
    5007             :                                    Real64 &newVal2,
    5008             :                                    Real64 &newVal3,
    5009             :                                    Real64 &newVal4)
    5010             : {
    5011             :     // SUBROUTINE INFORMATION:
    5012             :     //       AUTHOR         Brent Griffith
    5013             :     //       DATE WRITTEN   Feb 2008
    5014             : 
    5015             :     // PURPOSE OF THIS SUBROUTINE:
    5016             :     // provide a reusable routine for the various places that need to
    5017             :     // interpolate a new set of history values on a different time scale
    5018             :     // Once the systemtimestep has shortened, the new history terms need to be interpolated
    5019             : 
    5020             :     // METHODOLOGY EMPLOYED:
    5021             :     // This routine assumes that the direction is to a shorter timestep.
    5022             :     // The down step ratio, DSRatio = OldTimeStep/ NewTimeStep
    5023             :     //  is expected to be roughly integer-valued and near 2.0 or 3.0 or 4.0 or more.
    5024             : 
    5025             :     // old math variables
    5026             :     // Real64 const oldTime0 = 0.0;
    5027             :     // Real64 const oldTime1 = oldTime0 - OldTimeStep;
    5028             :     // Real64 const newTime0 = 0.0;
    5029             :     // Real64 const newTime1 = newTime0 - NewTimeStep;
    5030             :     // Real64 const newTime2 = newTime1 - NewTimeStep;
    5031             :     // Real64 const newTime3 = newTime2 - NewTimeStep;
    5032             :     // Real64 const newTime4 = newTime3 - NewTimeStep;
    5033             : 
    5034       60400 :     Real64 constexpr realTWO = 2.0;
    5035       60400 :     Real64 constexpr realTHREE = 3.0;
    5036             :     // first determine the ratio of system time step to zone time step
    5037       60400 :     Real64 const DSRatio = OldTimeStep / NewTimeStep; // should pretty much be an integer value 2, 3, 4, etc.
    5038             : 
    5039       60400 :     newVal0 = oldVal0;
    5040             : 
    5041       60400 :     if (std::abs(DSRatio - realTWO) < 0.01) { // DSRatio = 2
    5042             :         // when DSRatio = 2 the 1st point lies exactly between old points, and 2nd point is old 1st point
    5043             :         // first two points lie between oldVal0 and oldVal1
    5044             :         // old math example
    5045             :         // newVal1 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime1) / (OldTimeStep));
    5046             :         // newVal2 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime2) / (OldTimeStep));
    5047       11800 :         newVal1 = (oldVal0 + oldVal1) / realTWO;
    5048       11800 :         newVal2 = oldVal1;
    5049             :         // when DSRatio = 2 the 3rd point lies exactly between old points, and 4th point is old 2nd point
    5050             :         // last two points lie between oldVal1 and oldVal2
    5051             :         // newVal3 = oldVal1 + (oldVal2 - oldVal1) * ((oldTime1 - newTime3) / (OldTimeStep));
    5052             :         // newVal4 = oldVal1 + (oldVal2 - oldVal1) * ((oldTime1 - newTime4) / (OldTimeStep));
    5053       11800 :         newVal3 = (oldVal1 + oldVal2) / realTWO;
    5054       11800 :         newVal4 = oldVal2;
    5055       48600 :     } else if (std::abs(DSRatio - realTHREE) < 0.01) { // DSRatio = 3
    5056             :         // when DSRatio = 3 the 1st point lies 1/3 way between old points, and 2nd and 3rd points are 2/3 and 3/3 the way
    5057             :         // first three points lie between oldVal0 and oldVal1
    5058             :         // newVal1 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime1) / (OldTimeStep));
    5059             :         // newVal2 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime2) / (OldTimeStep));
    5060             :         // newVal3 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime3) / (OldTimeStep));
    5061        7751 :         Real64 delta10 = (oldVal1 - oldVal0) / realTHREE;
    5062        7751 :         newVal1 = oldVal0 + delta10;
    5063        7751 :         newVal2 = newVal1 + delta10;
    5064        7751 :         newVal3 = oldVal1;
    5065             :         // last point lies 1/3 way between oldVal1 and oldVal2
    5066             :         // newVal4 = oldVal1 + (oldVal2 - oldVal1) * ((oldTime1 - newTime4) / (OldTimeStep));
    5067        7751 :         newVal4 = oldVal1 + (oldVal2 - oldVal1) / realTHREE;
    5068             : 
    5069             :     } else { // DSRatio = 4 or more
    5070             :         // all new points lie between oldVal0 and oldVal1 (if DSRatio = 4, newVal4 = oldVal1)
    5071             :         // newVal1 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime1) / (OldTimeStep));
    5072             :         // newVal2 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime2) / (OldTimeStep));
    5073             :         // newVal3 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime3) / (OldTimeStep));
    5074             :         // newVal4 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime4) / (OldTimeStep));
    5075       40849 :         Real64 delta10 = (oldVal1 - oldVal0) / DSRatio;
    5076       40849 :         newVal1 = oldVal0 + delta10;
    5077       40849 :         newVal2 = newVal1 + delta10;
    5078       40849 :         newVal3 = newVal2 + delta10;
    5079       40849 :         newVal4 = newVal3 + delta10;
    5080             :     }
    5081       60400 : }
    5082             : 
    5083     2838346 : Real64 DownInterpolate4HistoryValues(Real64 OldTimeStep, Real64 NewTimeStep, std::array<Real64, 4> const &oldVals, std::array<Real64, 4> &newVals)
    5084             : {
    5085     2838346 :     Real64 constexpr realTWO = 2.0;
    5086     2838346 :     Real64 constexpr realTHREE = 3.0;
    5087             :     // first determine the ratio of system time step to zone time step
    5088     2838346 :     Real64 const DSRatio = OldTimeStep / NewTimeStep; // should pretty much be an integer value 2, 3, 4, etc.
    5089             : 
    5090     2838346 :     newVals[0] = oldVals[0];
    5091             : 
    5092     2838346 :     if (std::abs(DSRatio - realTWO) < 0.01) { // DSRatio = 2
    5093             :         // first point lies exactly between (oldVals[0] and oldVals[1])
    5094      948548 :         newVals[1] = (oldVals[0] + oldVals[1]) / realTWO;
    5095             :         // 2nd point is oldVal[1] and last point lies exactly between (oldVals[1] and oldVals[2])
    5096      948548 :         newVals[2] = oldVals[1];
    5097      948548 :         newVals[3] = (oldVals[1] + oldVals[2]) / realTWO;
    5098             : 
    5099     1889798 :     } else if (std::abs(DSRatio - realTHREE) < 0.01) { // DSRatio = 3
    5100             :         // first two points lie between (oldVals[0] and oldVals[1])
    5101      460241 :         Real64 delta10 = (oldVals[1] - oldVals[0]) / realTHREE;
    5102      460241 :         newVals[1] = oldVals[0] + delta10;
    5103      460241 :         newVals[2] = newVals[1] + delta10;
    5104             :         // last point is oldVals[1]
    5105      460241 :         newVals[3] = oldVals[1];
    5106             : 
    5107             :     } else { // DSRatio = 4 or more
    5108             :         // all new points lie between (oldVals[0] and oldVals[1])
    5109     1429557 :         Real64 delta10 = (oldVals[1] - oldVals[0]) / DSRatio;
    5110     1429557 :         newVals[1] = oldVals[0] + delta10;
    5111     1429557 :         newVals[2] = newVals[1] + delta10;
    5112     1429557 :         newVals[3] = newVals[2] + delta10;
    5113             :     }
    5114     2838346 :     return oldVals[0];
    5115             : }
    5116        1800 : void InverseModelTemperature(EnergyPlusData &state,
    5117             :                              int const ZoneNum,                   // Zone number
    5118             :                              Real64 const SumIntGain,             // Zone sum of convective internal gains
    5119             :                              Real64 const SumIntGainExceptPeople, // Zone sum of convective internal gains except for people
    5120             :                              Real64 const SumHA,                  // Zone sum of Hc*Area
    5121             :                              Real64 const SumHATsurf,             // Zone sum of Hc*Area*Tsurf
    5122             :                              Real64 const SumHATref,              // Zone sum of Hc*Area*Tref, for ceiling diffuser convection correlation
    5123             :                              Real64 const SumMCp,                 // Zone sum of MassFlowRate*Cp
    5124             :                              Real64 const SumMCpT,                // Zone sum of MassFlowRate*Cp*T
    5125             :                              Real64 const SumSysMCp,              // Zone sum of air system MassFlowRate*Cp
    5126             :                              Real64 const SumSysMCpT,             // Zone sum of air system MassFlowRate*Cp*T
    5127             :                              Real64 const AirCap                  // Formerly CoefAirrat, coef in zone temp eqn with dim of "air power capacity"rd
    5128             : )
    5129             : {
    5130             :     // SUBROUTINE INFORMATION:
    5131             :     //       AUTHOR         Han Li
    5132             :     //       DATE WRITTEN   February 2019
    5133             : 
    5134             :     // PURPOSE OF THIS SUBROUTINE:
    5135             :     // This subroutine inversely solve infiltration airflow rate or people count with zone air temperatures measurements.
    5136             : 
    5137             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5138        1800 :     Real64 AirCapHM(0.0); // Air power capacity for hybrid modeling
    5139        1800 :     Real64 AA(0.0);
    5140        1800 :     Real64 BB(0.0);
    5141        1800 :     Real64 FractionConvection(0.0); // Default convection portion of the sensible heat from people
    5142             : 
    5143        1800 :     auto &zone = state.dataHeatBal->Zone(ZoneNum);
    5144        1800 :     auto &hybridModelZone = state.dataHybridModel->HybridModelZone(ZoneNum);
    5145        1800 :     auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
    5146             : 
    5147        1800 :     int ZoneMult = zone.Multiplier * zone.ListMultiplier;
    5148        1800 :     zone.ZoneMeasuredTemperature = ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneMeasuredTemperatureSchedulePtr);
    5149        1800 :     zone.ZoneVolCapMultpSensHM = 1.0; // Initialize to 1.0 in case hybrid not active
    5150             : 
    5151             :     // HM calculation only HM calculation period start
    5152        1800 :     if (state.dataEnvrn->DayOfYear >= hybridModelZone.HybridStartDayOfYear && state.dataEnvrn->DayOfYear <= hybridModelZone.HybridEndDayOfYear) {
    5153        1800 :         Real64 MultpHM(1.0);
    5154             : 
    5155        1800 :         thisZoneHB.ZT = zone.ZoneMeasuredTemperature; // Array1D<Real64> ZT -- Zone
    5156             :                                                       // Air Temperature Averaged over
    5157             :                                                       // the System Time Increment
    5158        1800 :         if (hybridModelZone.InfiltrationCalc_T && state.dataHVACGlobal->UseZoneTimeStepHistory) {
    5159             :             static constexpr std::string_view RoutineNameInfiltration("CalcAirFlowSimple:Infiltration");
    5160             : 
    5161         576 :             if (hybridModelZone.IncludeSystemSupplyParameters) {
    5162           0 :                 zone.ZoneMeasuredSupplyAirTemperature =
    5163           0 :                     ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneSupplyAirTemperatureSchedulePtr);
    5164           0 :                 zone.ZoneMeasuredSupplyAirFlowRate =
    5165           0 :                     ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneSupplyAirMassFlowRateSchedulePtr);
    5166           0 :                 zone.ZoneMeasuredSupplyAirHumidityRatio =
    5167           0 :                     ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneSupplyAirHumidityRatioSchedulePtr);
    5168             :                 // Calculate the air humidity ratio at supply air inlet.
    5169           0 :                 Real64 CpAirInlet(0.0);
    5170           0 :                 CpAirInlet = Psychrometrics::PsyCpAirFnW(zone.ZoneMeasuredSupplyAirHumidityRatio);
    5171             : 
    5172           0 :                 Real64 SumSysMCp_HM = zone.ZoneMeasuredSupplyAirFlowRate * CpAirInlet;
    5173           0 :                 Real64 SumSysMCpT_HM = zone.ZoneMeasuredSupplyAirFlowRate * CpAirInlet * zone.ZoneMeasuredSupplyAirTemperature;
    5174             : 
    5175           0 :                 AA = SumSysMCp_HM + SumHA + thisZoneHB.MCPV + thisZoneHB.MCPM + thisZoneHB.MCPE + thisZoneHB.MCPC + thisZoneHB.MDotCPOA;
    5176           0 :                 BB = SumSysMCpT_HM + SumIntGain + SumHATsurf - SumHATref + thisZoneHB.MCPTV + thisZoneHB.MCPTM + thisZoneHB.MCPTE + thisZoneHB.MCPTC +
    5177           0 :                      thisZoneHB.MDotCPOA * zone.OutDryBulbTemp + (thisZoneHB.NonAirSystemResponse / ZoneMult + thisZoneHB.SysDepZoneLoadsLagged);
    5178             :             } else {
    5179         576 :                 AA = SumHA + thisZoneHB.MCPV + thisZoneHB.MCPM + thisZoneHB.MCPE + thisZoneHB.MCPC + thisZoneHB.MDotCPOA;
    5180         576 :                 BB = SumIntGain + SumHATsurf - SumHATref + thisZoneHB.MCPTV + thisZoneHB.MCPTM + thisZoneHB.MCPTE + thisZoneHB.MCPTC +
    5181         576 :                      thisZoneHB.MDotCPOA * zone.OutDryBulbTemp;
    5182             :             }
    5183         576 :             Real64 CC = AirCap;
    5184             :             Real64 DD =
    5185         576 :                 (3.0 * state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum) - (3.0 / 2.0) * state.dataHeatBalFanSys->PreviousMeasuredZT2(ZoneNum) +
    5186         576 :                  (1.0 / 3.0) * state.dataHeatBalFanSys->PreviousMeasuredZT3(ZoneNum));
    5187             : 
    5188         576 :             Real64 delta_T = (zone.ZoneMeasuredTemperature - zone.OutDryBulbTemp);
    5189         576 :             Real64 CpAir = Psychrometrics::PsyCpAirFnW(state.dataEnvrn->OutHumRat);
    5190         576 :             Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(
    5191         576 :                 state, state.dataEnvrn->OutBaroPress, zone.OutDryBulbTemp, state.dataEnvrn->OutHumRat, RoutineNameInfiltration);
    5192         576 :             zone.delta_T = delta_T;
    5193             : 
    5194             :             // s4 - Set ACH to 0 when delta_T <= 0.5, add max and min limits to ach
    5195         576 :             Real64 M_inf = 0.0;
    5196         576 :             if (std::abs(delta_T) > 0.5) {
    5197         558 :                 M_inf = (BB + CC * DD - ((11.0 / 6.0) * CC + AA) * zone.ZoneMeasuredTemperature) / (CpAir * delta_T);
    5198             :             }
    5199         576 :             Real64 ACH_inf = max(0.0, min(10.0, (M_inf / AirDensity) / zone.Volume * Constant::SecInHour));
    5200         576 :             M_inf = (ACH_inf / Constant::SecInHour) * zone.Volume * AirDensity;
    5201             : 
    5202             :             // Overwrite variable with inverse solution
    5203         576 :             zone.MCPIHM = M_inf;
    5204         576 :             zone.InfilOAAirChangeRateHM = ACH_inf;
    5205             : 
    5206             :         } // Hybrid model infiltration calculation end
    5207             : 
    5208             :         // Hybrid modeling internal thermal mass calculation start
    5209        2664 :         if (hybridModelZone.InternalThermalMassCalc_T && SumSysMCpT == 0 && thisZoneHB.ZT != state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum) &&
    5210         864 :             state.dataHVACGlobal->UseZoneTimeStepHistory) { // HM calculation only when SumSysMCpT =0,
    5211             :                                                             // TimeStepZone (not @ TimeStepSys)
    5212         864 :             Real64 TempDepCoef = SumHA + SumMCp + SumSysMCp;
    5213         864 :             Real64 TempIndCoef = SumIntGain + SumHATsurf - SumHATref + SumMCpT + SumSysMCpT +
    5214         864 :                                  (thisZoneHB.NonAirSystemResponse / ZoneMult + thisZoneHB.SysDepZoneLoadsLagged);
    5215             :             //    TempHistoryTerm = AirCap * (3.0 * ZTM1(ZoneNum) - (3.0/2.0) * ZTM2(ZoneNum) + (1.0/3.0) * ZTM3(ZoneNum)) !debug only
    5216             : 
    5217         864 :             if (state.afn->distribution_simulated) {
    5218           0 :                 TempIndCoef += state.afn->exchangeData(ZoneNum).TotalSen;
    5219             :             }
    5220             :             // Calculate air capacity using DataHeatBalance::SolutionAlgo::AnalyticalSolution
    5221         864 :             if (TempDepCoef == 0.0) {
    5222             :                 // Is this correct? Shouldn't we use log?? What if thisZT ==
    5223             :                 // PreviousMeasuredZT1(ZoneNum)??
    5224           0 :                 AirCapHM = TempIndCoef / (thisZoneHB.ZT - state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum)); // Inverse equation
    5225             :             } else {
    5226         864 :                 Real64 AirCapHM_temp = 0.0;
    5227         864 :                 if (TempIndCoef == TempDepCoef * thisZoneHB.ZT) {
    5228           0 :                     AirCapHM_temp = 0.0; //  This is the denominator.
    5229             :                 } else {
    5230         864 :                     AirCapHM_temp = (TempIndCoef - TempDepCoef * state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum)) /
    5231         864 :                                     (TempIndCoef - TempDepCoef * thisZoneHB.ZT);
    5232             :                 }
    5233             : 
    5234         864 :                 if ((AirCapHM_temp > 0) && (AirCapHM_temp != 1)) {    // Avoide IND
    5235         857 :                     AirCapHM = TempDepCoef / std::log(AirCapHM_temp); // Inverse equation
    5236             :                 } else {
    5237           7 :                     AirCapHM = TempIndCoef / (thisZoneHB.ZT - state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum));
    5238             :                 }
    5239             :             }
    5240             : 
    5241             :             // Calculate multiplier
    5242         864 :             if (std::abs(thisZoneHB.ZT - state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum)) > 0.05) { // Filter
    5243         288 :                 MultpHM = AirCapHM /
    5244         288 :                           (zone.Volume *
    5245         288 :                            Psychrometrics::PsyRhoAirFnPbTdbW(state,
    5246         144 :                                                              state.dataEnvrn->OutBaroPress,
    5247             :                                                              thisZoneHB.ZT,
    5248         144 :                                                              thisZoneHB.airHumRat) *
    5249         144 :                            Psychrometrics::PsyCpAirFnW(thisZoneHB.airHumRat)) *
    5250         144 :                           (state.dataGlobal->TimeStepZone * Constant::SecInHour); // Inverse equation
    5251             :             } else {
    5252         720 :                 MultpHM = 1.0; // Default value 1.0
    5253             :             }
    5254             : 
    5255         864 :             processInverseModelMultpHM(
    5256         864 :                 state, MultpHM, zone.ZoneVolCapMultpSensHMSum, zone.ZoneVolCapMultpSensHMCountSum, zone.ZoneVolCapMultpSensHMAverage, ZoneNum);
    5257         864 :             zone.ZoneVolCapMultpSensHM = MultpHM;
    5258             : 
    5259             :         } // Hybrid model internal thermal mass calcualtion end
    5260             : 
    5261             :         // Hybrid model people count calculation
    5262        1800 :         if (hybridModelZone.PeopleCountCalc_T && state.dataHVACGlobal->UseZoneTimeStepHistory) {
    5263         288 :             zone.ZoneMeasuredTemperature = ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneMeasuredTemperatureSchedulePtr);
    5264         288 :             zone.ZonePeopleActivityLevel = ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZonePeopleActivityLevelSchedulePtr);
    5265         288 :             zone.ZonePeopleSensibleHeatFraction =
    5266         288 :                 ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZonePeopleSensibleFractionSchedulePtr);
    5267         288 :             zone.ZonePeopleRadiantHeatFraction =
    5268         288 :                 ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZonePeopleRadiationFractionSchedulePtr);
    5269             : 
    5270         288 :             Real64 FractionSensible = zone.ZonePeopleSensibleHeatFraction;
    5271         288 :             Real64 FractionRadiation = zone.ZonePeopleRadiantHeatFraction;
    5272         288 :             Real64 ActivityLevel = ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZonePeopleActivityLevelSchedulePtr);
    5273             : 
    5274         288 :             if (FractionSensible <= 0.0) {
    5275           0 :                 FractionSensible = 0.6;
    5276             :             }
    5277             : 
    5278         288 :             if (FractionRadiation <= 0.0) {
    5279           0 :                 FractionConvection = 0.7;
    5280             :             } else {
    5281         288 :                 FractionConvection = 1.0 - FractionRadiation;
    5282             :             }
    5283             : 
    5284         288 :             if (ActivityLevel <= 0.0) {
    5285           0 :                 ActivityLevel = 130.0;
    5286             :             }
    5287             : 
    5288         288 :             if (hybridModelZone.IncludeSystemSupplyParameters) {
    5289           0 :                 zone.ZoneMeasuredSupplyAirTemperature =
    5290           0 :                     ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneSupplyAirTemperatureSchedulePtr);
    5291           0 :                 zone.ZoneMeasuredSupplyAirFlowRate =
    5292           0 :                     ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneSupplyAirMassFlowRateSchedulePtr);
    5293           0 :                 zone.ZoneMeasuredSupplyAirHumidityRatio =
    5294           0 :                     ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneSupplyAirHumidityRatioSchedulePtr);
    5295             : 
    5296             :                 // Calculate the air humidity ratio at supply air inlet.
    5297           0 :                 Real64 CpAirInlet = Psychrometrics::PsyCpAirFnW(zone.ZoneMeasuredSupplyAirHumidityRatio);
    5298             : 
    5299           0 :                 Real64 SumSysMCp_HM = zone.ZoneMeasuredSupplyAirFlowRate * CpAirInlet;
    5300           0 :                 Real64 SumSysMCpT_HM = zone.ZoneMeasuredSupplyAirFlowRate * CpAirInlet * zone.ZoneMeasuredSupplyAirTemperature;
    5301             : 
    5302           0 :                 AA = SumSysMCp_HM + SumHA + SumMCp;
    5303           0 :                 BB = SumSysMCpT_HM + SumIntGainExceptPeople + SumHATsurf - SumHATref + SumMCpT +
    5304           0 :                      (thisZoneHB.NonAirSystemResponse / ZoneMult + thisZoneHB.SysDepZoneLoadsLagged);
    5305             :             } else {
    5306         288 :                 AA = SumHA + SumMCp;
    5307         288 :                 BB = SumIntGainExceptPeople + SumHATsurf - SumHATref + SumMCpT;
    5308             :             }
    5309             : 
    5310         288 :             Real64 CC = AirCap;
    5311             :             Real64 DD =
    5312         288 :                 (3.0 * state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum) - (3.0 / 2.0) * state.dataHeatBalFanSys->PreviousMeasuredZT2(ZoneNum) +
    5313         288 :                  (1.0 / 3.0) * state.dataHeatBalFanSys->PreviousMeasuredZT3(ZoneNum));
    5314             : 
    5315         288 :             Real64 SumIntGainPeople = ((11.0 / 6.0) * CC + AA) * zone.ZoneMeasuredTemperature - BB - CC * DD;
    5316         288 :             Real64 UpperBound = max(0.0, SumIntGain / (ActivityLevel * FractionSensible * FractionConvection));
    5317         288 :             Real64 NumPeople = min(UpperBound, max(0.0, SumIntGainPeople / (ActivityLevel * FractionSensible * FractionConvection)));
    5318             : 
    5319         288 :             if (NumPeople < 0.05) {
    5320         286 :                 NumPeople = 0;
    5321             :             }
    5322         288 :             zone.NumOccHM = NumPeople;
    5323             :         }
    5324             :     }
    5325             : 
    5326             :     // Update zone temperatures in the previous steps
    5327        1800 :     state.dataHeatBalFanSys->PreviousMeasuredZT3(ZoneNum) = state.dataHeatBalFanSys->PreviousMeasuredZT2(ZoneNum);
    5328        1800 :     state.dataHeatBalFanSys->PreviousMeasuredZT2(ZoneNum) = state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum);
    5329        1800 :     state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum) = thisZoneHB.ZT;
    5330        1800 : }
    5331             : 
    5332         864 : void processInverseModelMultpHM(EnergyPlusData &state,
    5333             :                                 Real64 &multiplierHM, // Hybrid model thermal mass multiplier
    5334             :                                 Real64 &multSumHM,    // Sum of Hybrid model thermal mass multipliers
    5335             :                                 Real64 &countSumHM,   // Count of number of points in sum
    5336             :                                 Real64 &multAvgHM,    // Average of hybrid model mass multipier
    5337             :                                 int zoneNum           // Zone number for the hybrid model
    5338             : )
    5339             : {
    5340         864 :     Real64 constexpr minHMMultValue = 1.0;
    5341         864 :     Real64 constexpr maxHMMultValue = 30.0;
    5342             : 
    5343         864 :     auto &zone = state.dataHeatBal->Zone(zoneNum);
    5344         864 :     auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum);
    5345             : 
    5346             :     // Apply limits and generate warnings as needed
    5347         864 :     if (multiplierHM < minHMMultValue) { // don't allow this to be less than minimum (potential for instability)
    5348          70 :         multiplierHM = minHMMultValue;
    5349         794 :     } else if (multiplierHM > maxHMMultValue) { // as per suggestions in Defect #10508, only warn if greater than the max
    5350           4 :         if (thisZoneHB.hmThermalMassMultErrIndex == 0) {
    5351           2 :             ShowWarningMessage(state, format("Hybrid model thermal mass multiplier higher than the limit for {}", zone.Name));
    5352           2 :             ShowContinueError(state, "This means that the ratio of the zone air heat capacity for the current time step to the");
    5353           2 :             ShowContinueError(state, format("zone air heat storage is higher than the maximum limit of {:.1R}.", maxHMMultValue));
    5354             :         }
    5355          12 :         ShowRecurringWarningErrorAtEnd(
    5356           8 :             state, "Hybrid model thermal mass multiplier limit exceeded in zone " + zone.Name, thisZoneHB.hmThermalMassMultErrIndex);
    5357             :     }
    5358             : 
    5359             :     // Update running totals (but only when there is a valid multiplier, i.e. multiplier is greater than min but not higher than the max)
    5360         864 :     if (multiplierHM > minHMMultValue) {
    5361          74 :         multSumHM += multiplierHM;
    5362          74 :         countSumHM++;
    5363             :     }
    5364             : 
    5365             :     // Calculate average (always so that it does get calculated)
    5366         864 :     if (countSumHM >= 1) multAvgHM = multSumHM / countSumHM;
    5367         864 : }
    5368             : 
    5369         600 : void InverseModelHumidity(EnergyPlusData &state,
    5370             :                           int const ZoneNum,                   // Zone number
    5371             :                           Real64 const LatentGain,             // Zone sum of latent gain
    5372             :                           Real64 const LatentGainExceptPeople, // Zone sum of latent gain except for people
    5373             :                           Real64 const ZoneMassFlowRate,       // Zone air mass flow rate
    5374             :                           Real64 const MoistureMassFlowRate,   // Zone moisture mass flow rate
    5375             :                           Real64 const H2OHtOfVap,             // Heat of vaporization of air
    5376             :                           Real64 const RhoAir                  // Air density
    5377             : )
    5378             : {
    5379             :     // SUBROUTINE INFORMATION:
    5380             :     //       AUTHOR         Han Li
    5381             :     //       DATE WRITTEN   February 2019
    5382             : 
    5383             :     // PURPOSE OF THIS SUBROUTINE:
    5384             :     // This subroutine inversely solve infiltration airflow rate or people count with zone air humidity measurements.
    5385             : 
    5386             :     // SUBROUTINE PARAMETER DEFINITIONS:
    5387             :     static constexpr std::string_view RoutineName("InverseModelHumidity");
    5388             : 
    5389             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5390         600 :     Real64 AA(0.0);
    5391         600 :     Real64 BB(0.0);
    5392         600 :     Real64 ActivityLevel(0.0);
    5393         600 :     Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    5394             : 
    5395         600 :     auto &zone = state.dataHeatBal->Zone(ZoneNum);
    5396         600 :     auto &hybridModelZone = state.dataHybridModel->HybridModelZone(ZoneNum);
    5397         600 :     auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
    5398             : 
    5399             :     // Get measured zone humidity ratio
    5400         600 :     zone.ZoneMeasuredHumidityRatio = ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneMeasuredHumidityRatioSchedulePtr);
    5401             : 
    5402         600 :     if (state.dataEnvrn->DayOfYear >= hybridModelZone.HybridStartDayOfYear && state.dataEnvrn->DayOfYear <= hybridModelZone.HybridEndDayOfYear) {
    5403         600 :         thisZoneHB.airHumRat = zone.ZoneMeasuredHumidityRatio;
    5404             : 
    5405             :         // Hybrid Model calculate air infiltration rate
    5406         600 :         if (hybridModelZone.InfiltrationCalc_H && state.dataHVACGlobal->UseZoneTimeStepHistory) {
    5407             :             // Conditionally calculate the time dependent and time independent terms
    5408         288 :             if (hybridModelZone.IncludeSystemSupplyParameters) {
    5409           0 :                 zone.ZoneMeasuredSupplyAirFlowRate =
    5410           0 :                     ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneSupplyAirMassFlowRateSchedulePtr);
    5411           0 :                 zone.ZoneMeasuredSupplyAirHumidityRatio =
    5412           0 :                     ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneSupplyAirHumidityRatioSchedulePtr);
    5413             : 
    5414           0 :                 Real64 SumSysM_HM = zone.ZoneMeasuredSupplyAirFlowRate;
    5415           0 :                 Real64 SumSysMHumRat_HM = zone.ZoneMeasuredSupplyAirFlowRate * zone.ZoneMeasuredSupplyAirHumidityRatio;
    5416             : 
    5417           0 :                 AA = SumSysM_HM + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.SumHmARa + thisZoneHB.MixingMassFlowZone +
    5418           0 :                      thisZoneHB.MDotOA;
    5419           0 :                 BB = SumSysMHumRat_HM + (LatentGain / H2OHtOfVap) + ((thisZoneHB.VAMFL + thisZoneHB.CTMFL) * state.dataEnvrn->OutHumRat) +
    5420           0 :                      thisZoneHB.EAMFLxHumRat + thisZoneHB.SumHmARaW + thisZoneHB.MixingMassFlowXHumRat +
    5421           0 :                      thisZoneHB.MDotOA * state.dataEnvrn->OutHumRat;
    5422             :             } else {
    5423         288 :                 AA = thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.SumHmARa + thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
    5424         288 :                 BB = (LatentGain / H2OHtOfVap) + ((thisZoneHB.VAMFL + thisZoneHB.CTMFL) * state.dataEnvrn->OutHumRat) + thisZoneHB.EAMFLxHumRat +
    5425         288 :                      thisZoneHB.SumHmARaW + thisZoneHB.MixingMassFlowXHumRat + thisZoneHB.MDotOA * state.dataEnvrn->OutHumRat;
    5426             :             }
    5427             : 
    5428         288 :             Real64 CC = RhoAir * zone.Volume * zone.ZoneVolCapMultpMoist / TimeStepSysSec;
    5429         288 :             Real64 DD = (3.0 * state.dataHeatBalFanSys->PreviousMeasuredHumRat1(ZoneNum) -
    5430         288 :                          (3.0 / 2.0) * state.dataHeatBalFanSys->PreviousMeasuredHumRat2(ZoneNum) +
    5431         288 :                          (1.0 / 3.0) * state.dataHeatBalFanSys->PreviousMeasuredHumRat3(ZoneNum));
    5432             : 
    5433         288 :             Real64 delta_HR = (zone.ZoneMeasuredHumidityRatio - state.dataEnvrn->OutHumRat);
    5434             : 
    5435             :             Real64 AirDensity =
    5436         288 :                 Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, zone.OutDryBulbTemp, state.dataEnvrn->OutHumRat, RoutineName);
    5437             : 
    5438         288 :             Real64 M_inf = 0.0;
    5439         288 :             if (std::abs(zone.ZoneMeasuredHumidityRatio - state.dataEnvrn->OutHumRat) > 0.0000001) {
    5440         288 :                 M_inf = (CC * DD + BB - ((11.0 / 6.0) * CC + AA) * zone.ZoneMeasuredHumidityRatio) / delta_HR;
    5441             :             }
    5442             : 
    5443             :             // Add threshold for air change rate
    5444         288 :             Real64 ACH_inf = max(0.0, min(10.0, (M_inf / AirDensity) / zone.Volume * Constant::SecInHour));
    5445         288 :             M_inf = (ACH_inf / Constant::SecInHour) * zone.Volume * AirDensity;
    5446         288 :             zone.MCPIHM = M_inf;
    5447         288 :             zone.InfilOAAirChangeRateHM = ACH_inf;
    5448             :         }
    5449             : 
    5450             :         // Hybrid Model calculate people count
    5451         600 :         if (hybridModelZone.PeopleCountCalc_H && state.dataHVACGlobal->UseZoneTimeStepHistory) {
    5452         288 :             zone.ZonePeopleActivityLevel = ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZonePeopleActivityLevelSchedulePtr);
    5453         288 :             zone.ZonePeopleSensibleHeatFraction =
    5454         288 :                 ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZonePeopleSensibleFractionSchedulePtr);
    5455         288 :             zone.ZonePeopleRadiantHeatFraction =
    5456         288 :                 ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZonePeopleRadiationFractionSchedulePtr);
    5457             : 
    5458         288 :             Real64 FractionSensible = zone.ZonePeopleSensibleHeatFraction;
    5459             : 
    5460         288 :             if (FractionSensible <= 0.0) {
    5461           0 :                 FractionSensible = 0.6;
    5462             :             }
    5463             : 
    5464         288 :             if (ActivityLevel <= 0.0) {
    5465         288 :                 ActivityLevel = 130.0;
    5466             :             }
    5467             : 
    5468             :             // Conditionally calculate the humidity-dependent and humidity-independent
    5469             :             // terms.
    5470         288 :             if (hybridModelZone.IncludeSystemSupplyParameters) {
    5471         288 :                 zone.ZoneMeasuredSupplyAirFlowRate =
    5472         288 :                     ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneSupplyAirMassFlowRateSchedulePtr);
    5473         288 :                 zone.ZoneMeasuredSupplyAirHumidityRatio =
    5474         288 :                     ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneSupplyAirHumidityRatioSchedulePtr);
    5475             : 
    5476         288 :                 Real64 SumSysM_HM = zone.ZoneMeasuredSupplyAirFlowRate;
    5477         288 :                 Real64 SumSysMHumRat_HM = zone.ZoneMeasuredSupplyAirFlowRate * zone.ZoneMeasuredSupplyAirHumidityRatio;
    5478             : 
    5479         288 :                 AA = SumSysM_HM + thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.SumHmARa +
    5480         288 :                      thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
    5481         864 :                 BB = SumSysMHumRat_HM + (LatentGainExceptPeople / H2OHtOfVap) +
    5482         288 :                      ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.CTMFL) * state.dataEnvrn->OutHumRat) + thisZoneHB.EAMFLxHumRat +
    5483         288 :                      thisZoneHB.SumHmARaW + thisZoneHB.MixingMassFlowXHumRat + thisZoneHB.MDotOA * state.dataEnvrn->OutHumRat;
    5484             :             } else {
    5485           0 :                 AA = ZoneMassFlowRate + thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.SumHmARa +
    5486           0 :                      thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
    5487           0 :                 BB = (LatentGainExceptPeople / H2OHtOfVap) + ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.CTMFL) * state.dataEnvrn->OutHumRat) +
    5488           0 :                      thisZoneHB.EAMFLxHumRat + (MoistureMassFlowRate) + thisZoneHB.SumHmARaW + thisZoneHB.MixingMassFlowXHumRat +
    5489           0 :                      thisZoneHB.MDotOA * state.dataEnvrn->OutHumRat;
    5490             :             }
    5491             : 
    5492         288 :             Real64 CC = RhoAir * zone.Volume * zone.ZoneVolCapMultpMoist / TimeStepSysSec;
    5493         288 :             Real64 DD = (3.0 * state.dataHeatBalFanSys->PreviousMeasuredHumRat1(ZoneNum) -
    5494         288 :                          (3.0 / 2.0) * state.dataHeatBalFanSys->PreviousMeasuredHumRat2(ZoneNum) +
    5495         288 :                          (1.0 / 3.0) * state.dataHeatBalFanSys->PreviousMeasuredHumRat3(ZoneNum));
    5496             : 
    5497         288 :             Real64 LatentGainPeople = (((11.0 / 6.0) * CC + AA) * zone.ZoneMeasuredHumidityRatio - BB - CC * DD) * H2OHtOfVap;
    5498         288 :             Real64 UpperBound = max(0.0, LatentGain / (ActivityLevel * (1.0 - FractionSensible)));
    5499         288 :             Real64 NumPeople = min(UpperBound, max(0.0, LatentGainPeople / (ActivityLevel * (1.0 - FractionSensible))));
    5500         288 :             NumPeople = floor(NumPeople * 100.00 + 0.5) / 100.00;
    5501         288 :             if (NumPeople < 0.05) {
    5502         235 :                 NumPeople = 0;
    5503             :             }
    5504         288 :             zone.NumOccHM = NumPeople;
    5505             :         }
    5506             :     }
    5507             : 
    5508             :     // Update zone humidity ratio in the previous steps
    5509         600 :     state.dataHeatBalFanSys->PreviousMeasuredHumRat3(ZoneNum) = state.dataHeatBalFanSys->PreviousMeasuredHumRat2(ZoneNum);
    5510         600 :     state.dataHeatBalFanSys->PreviousMeasuredHumRat2(ZoneNum) = state.dataHeatBalFanSys->PreviousMeasuredHumRat1(ZoneNum);
    5511         600 :     state.dataHeatBalFanSys->PreviousMeasuredHumRat1(ZoneNum) = zone.ZoneMeasuredHumidityRatio;
    5512         600 : }
    5513             : 
    5514    59949690 : void ZoneSpaceHeatBalanceData::calcZoneOrSpaceSums(EnergyPlusData &state,
    5515             :                                                    bool const CorrectorFlag, // Corrector call flag
    5516             :                                                    int const zoneNum,
    5517             :                                                    int const spaceNum)
    5518             : {
    5519             : 
    5520             :     // SUBROUTINE INFORMATION:
    5521             :     //       AUTHOR         Peter Graham Ellis
    5522             :     //       DATE WRITTEN   July 2003
    5523             :     //       MODIFIED       Aug 2003, FCW: add this->SumHA contributions from window frame and divider
    5524             :     //                      Aug 2003, CC: change how the reference temperatures are used
    5525             : 
    5526             :     // PURPOSE OF THIS SUBROUTINE:
    5527             :     // This subroutine calculates the various sums that go into the zone heat balance
    5528             :     // equation.  This replaces the SUMC, SumHA, and SumHAT calculations that were
    5529             :     // previously done in various places throughout the program.
    5530             :     // The SumHAT portion of the code is reproduced in RadiantSystemHighTemp and
    5531             :     // RadiantSystemLowTemp and should be updated accordingly.
    5532             :     // A reference temperature (Tref) is specified for use with the ceiling diffuser
    5533             :     // convection correlation.  A bogus value of Tref = -999.9 defaults to using
    5534             :     // the zone air (i.e. outlet) temperature for the reference temperature.
    5535             :     // If Tref is applied to all surfaces, SumHA = 0, and SumHATref /= 0.
    5536             :     // If Tref is not used at all, SumHATref = 0, and SumHA /= 0.
    5537             :     // For future implementations, Tref can be easily converted into an array to
    5538             :     // allow a different reference temperature to be specified for each surface.
    5539    59949690 :     assert(zoneNum > 0);
    5540             : 
    5541    59949690 :     this->SumHA = 0.0;
    5542    59949690 :     this->SumHATsurf = 0.0;
    5543    59949690 :     this->SumHATref = 0.0;
    5544    59949690 :     this->SumSysMCp = 0.0;
    5545    59949690 :     this->SumSysMCpT = 0.0;
    5546             :     // Sum all convective internal gains: this->SumIntGain
    5547    59949690 :     if (spaceNum == 0) {
    5548    59834126 :         this->SumIntGain = InternalHeatGains::zoneSumAllInternalConvectionGains(state, zoneNum);
    5549             :     } else {
    5550      115564 :         this->SumIntGain = InternalHeatGains::spaceSumAllInternalConvectionGains(state, spaceNum);
    5551             :     }
    5552    59949690 :     this->SumIntGain += state.dataHeatBalFanSys->SumConvHTRadSys(zoneNum) + state.dataHeatBalFanSys->SumConvPool(zoneNum);
    5553             : 
    5554             :     // Add heat to return air if zonal system (no return air) or cycling system (return air frequently very low or zero)
    5555    59949690 :     assert(zoneNum > 0);
    5556    59949690 :     auto &thisZone = state.dataHeatBal->Zone(zoneNum);
    5557    59949690 :     if (thisZone.NoHeatToReturnAir) {
    5558     7205080 :         if (spaceNum == 0) {
    5559     7205080 :             this->SumIntGain += InternalHeatGains::zoneSumAllReturnAirConvectionGains(state, zoneNum, 0);
    5560             :         } else {
    5561           0 :             this->SumIntGain += InternalHeatGains::spaceSumAllReturnAirConvectionGains(state, spaceNum, 0);
    5562             :         }
    5563             :     }
    5564             : 
    5565             :     // Sum all non-system air flow, i.e. infiltration, simple ventilation, mixing, earth tube: this->SumMCp, this->SumMCpT
    5566    59949690 :     this->SumMCp = this->MCPI + this->MCPV + this->MCPM + this->MCPE + this->MCPC + this->MDotCPOA;
    5567    59949690 :     this->SumMCpT = this->MCPTI + this->MCPTV + this->MCPTM + this->MCPTE + this->MCPTC + this->MDotCPOA * thisZone.OutDryBulbTemp;
    5568             : 
    5569             :     // Sum all multizone air flow calculated from AirflowNetwork by assuming no simple air infiltration model
    5570   118916054 :     if (state.afn->multizone_always_simulated ||
    5571    58966364 :         (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
    5572       46516 :          state.afn->AirflowNetworkFanActivated)) {
    5573     1019781 :         auto &exchangeData = state.afn->exchangeData(zoneNum);
    5574     1019781 :         this->SumMCp = exchangeData.SumMCp + exchangeData.SumMVCp + exchangeData.SumMMCp;
    5575     1019781 :         this->SumMCpT = exchangeData.SumMCpT + exchangeData.SumMVCpT + exchangeData.SumMMCpT;
    5576             :     }
    5577             : 
    5578             :     // Sum all system air flow: this->SumSysMCp, this->SumSysMCpT and check to see if this is a controlled zone
    5579             :     // If the space is controlled, use space supply nodes, otherwise use zone supply nodes and allocate later
    5580    59949690 :     bool isSpaceControlled = (spaceNum > 0 && state.dataZoneEquip->spaceEquipConfig(spaceNum).IsControlled);
    5581    59949690 :     if (CorrectorFlag) {
    5582             :         // Plenum and controlled zones have a different set of inlet nodes which must be calculated.
    5583    29945519 :         if (thisZone.IsControlled) {
    5584    25713232 :             auto const &zsec = (isSpaceControlled ? state.dataZoneEquip->spaceEquipConfig(spaceNum) : state.dataZoneEquip->ZoneEquipConfig(zoneNum));
    5585    51867797 :             for (int NodeNum = 1, NodeNum_end = zsec.NumInletNodes; NodeNum <= NodeNum_end; ++NodeNum) {
    5586             :                 // Get node conditions, this next block is of interest to irratic system loads... maybe nodes are not accurate at time of call?
    5587             :                 //  how can we tell?  predict step must be lagged ?  correct step, systems have run.
    5588    26154565 :                 auto const &node(state.dataLoopNodes->Node(zsec.InletNode(NodeNum)));
    5589    26154565 :                 Real64 CpAir = Psychrometrics::PsyCpAirFnW(this->airHumRat);
    5590    26154565 :                 Real64 const MassFlowRate_CpAir(node.MassFlowRate * CpAir);
    5591    26154565 :                 this->SumSysMCp += MassFlowRate_CpAir;
    5592    26154565 :                 this->SumSysMCpT += MassFlowRate_CpAir * node.Temp;
    5593             :             }
    5594             : 
    5595     4232287 :         } else if (thisZone.IsReturnPlenum) {
    5596     1083884 :             auto const &zrpc(state.dataZonePlenum->ZoneRetPlenCond(thisZone.PlenumCondNum));
    5597     1083884 :             Real64 const air_hum_rat(this->airHumRat);
    5598     6284133 :             for (int NodeNum = 1, NodeNum_end = zrpc.NumInletNodes; NodeNum <= NodeNum_end; ++NodeNum) {
    5599     5200249 :                 auto const &node(state.dataLoopNodes->Node(zrpc.InletNode(NodeNum)));
    5600     5200249 :                 Real64 const MassFlowRate_CpAir(node.MassFlowRate * Psychrometrics::PsyCpAirFnW(air_hum_rat));
    5601     5200249 :                 this->SumSysMCp += MassFlowRate_CpAir;
    5602     5200249 :                 this->SumSysMCpT += MassFlowRate_CpAir * node.Temp;
    5603             :             }
    5604             :             // add in the leaks
    5605     6302773 :             for (int ADUListIndex = 1, ADUListIndex_end = zrpc.NumADUs; ADUListIndex <= ADUListIndex_end; ++ADUListIndex) {
    5606     5218889 :                 auto &airDistUnit = state.dataDefineEquipment->AirDistUnit(zrpc.ADUIndex(ADUListIndex));
    5607     5218889 :                 if (airDistUnit.UpStreamLeak) {
    5608      106595 :                     Real64 const MassFlowRate_CpAir(airDistUnit.MassFlowRateUpStrLk * Psychrometrics::PsyCpAirFnW(air_hum_rat));
    5609      106595 :                     this->SumSysMCp += MassFlowRate_CpAir;
    5610      106595 :                     this->SumSysMCpT += MassFlowRate_CpAir * state.dataLoopNodes->Node(airDistUnit.InletNodeNum).Temp;
    5611             :                 }
    5612     5218889 :                 if (airDistUnit.DownStreamLeak) {
    5613      106595 :                     Real64 const MassFlowRate_CpAir(airDistUnit.MassFlowRateDnStrLk * Psychrometrics::PsyCpAirFnW(air_hum_rat));
    5614      106595 :                     this->SumSysMCp += MassFlowRate_CpAir;
    5615      106595 :                     this->SumSysMCpT += MassFlowRate_CpAir * state.dataLoopNodes->Node(airDistUnit.OutletNodeNum).Temp;
    5616             :                 }
    5617             :             }
    5618             : 
    5619     3148403 :         } else if (thisZone.IsSupplyPlenum) {
    5620       19526 :             Real64 MassFlowRate = state.dataLoopNodes->Node(state.dataZonePlenum->ZoneSupPlenCond(thisZone.PlenumCondNum).InletNode).MassFlowRate;
    5621       19526 :             Real64 CpAir = Psychrometrics::PsyCpAirFnW(this->airHumRat);
    5622       19526 :             this->SumSysMCp += MassFlowRate * CpAir;
    5623       19526 :             this->SumSysMCpT +=
    5624       19526 :                 MassFlowRate * CpAir * state.dataLoopNodes->Node(state.dataZonePlenum->ZoneSupPlenCond(thisZone.PlenumCondNum).InletNode).Temp;
    5625             :         }
    5626             : 
    5627    29945519 :         int ZoneMult = thisZone.Multiplier * thisZone.ListMultiplier;
    5628             : 
    5629    29945519 :         this->SumSysMCp /= ZoneMult;
    5630    29945519 :         this->SumSysMCpT /= ZoneMult;
    5631             :     }
    5632             : 
    5633    59949690 :     if (spaceNum > 0 && !isSpaceControlled) {
    5634             :         // If space is not controlled, allocate zone-level airflow by volume
    5635       93034 :         Real64 spaceFrac = state.dataHeatBal->space(spaceNum).fracZoneVolume;
    5636       93034 :         this->SumSysMCp *= spaceFrac;
    5637       93034 :         this->SumSysMCpT *= spaceFrac;
    5638             :     }
    5639             : 
    5640             :     // Sum all surface convection: this->SumHA, this->SumHATsurf, this->SumHATref (and additional contributions to this->SumIntGain)
    5641    59949690 :     SumHATOutput sumHATResults; // space or zone return values
    5642    59949690 :     sumHATResults = this->calcSumHAT(state, zoneNum, spaceNum);
    5643    59949690 :     this->SumIntGain += sumHATResults.sumIntGain;
    5644    59949690 :     this->SumHA = sumHATResults.sumHA;
    5645    59949690 :     this->SumHATsurf = sumHATResults.sumHATsurf;
    5646    59949690 :     this->SumHATref = sumHATResults.sumHATref;
    5647    59949690 : }
    5648             : 
    5649    59834126 : SumHATOutput ZoneHeatBalanceData::calcSumHAT(EnergyPlusData &state, int const zoneNum, [[maybe_unused]] int const spaceNum)
    5650             : {
    5651    59834126 :     assert(zoneNum > 0);
    5652    59834126 :     assert(spaceNum == 0);
    5653    59834126 :     SumHATOutput zoneResults; // zone-level return values
    5654   119795980 :     for (int zoneSpaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
    5655    59961854 :         SumHATOutput spaceResults; // temporary return value from space-level calcSumHAT
    5656    59961854 :         spaceResults = state.dataZoneTempPredictorCorrector->spaceHeatBalance(zoneSpaceNum).calcSumHAT(state, zoneNum, zoneSpaceNum);
    5657    59961854 :         zoneResults.sumIntGain += spaceResults.sumIntGain;
    5658    59961854 :         zoneResults.sumHA += spaceResults.sumHA;
    5659    59961854 :         zoneResults.sumHATsurf += spaceResults.sumHATsurf;
    5660    59961854 :         zoneResults.sumHATref += spaceResults.sumHATref;
    5661    59834126 :     }
    5662    59834126 :     return zoneResults;
    5663             : }
    5664             : 
    5665    60077418 : SumHATOutput SpaceHeatBalanceData::calcSumHAT(EnergyPlusData &state, int const zoneNum, int const spaceNum)
    5666             : {
    5667    60077418 :     assert(zoneNum > 0);
    5668    60077418 :     assert(spaceNum > 0);
    5669    60077418 :     auto &thisZone = state.dataHeatBal->Zone(zoneNum);
    5670    60077418 :     auto &thisSpace = state.dataHeatBal->space(spaceNum);
    5671    60077418 :     SumHATOutput results; // space-level return values
    5672             : 
    5673   582931758 :     for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
    5674   522854340 :         Real64 HA = 0.0;
    5675   522854340 :         Real64 Area = state.dataSurface->Surface(SurfNum).Area; // For windows, this is the glazing area
    5676             : 
    5677   522854340 :         if (state.dataSurface->Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window) {
    5678    72079374 :             DataSurfaces::WinShadingType const shading_flag = state.dataSurface->SurfWinShadingFlag(SurfNum);
    5679             : 
    5680             :             // Add to the convective internal gains
    5681    72079374 :             if (ANY_INTERIOR_SHADE_BLIND(shading_flag)) {
    5682             :                 // The shade area covers the area of the glazing plus the area of the dividers.
    5683      555262 :                 Area += state.dataSurface->SurfWinDividerArea(SurfNum);
    5684             :                 // If interior shade or blind is present it is assumed that both the convective and IR radiative gain
    5685             :                 // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative
    5686             :                 // interaction between divider and shade or blind is ignored due to the difficulty of calculating this interaction
    5687             :                 // at the same time that the interaction between glass and shade is calculated.
    5688      555262 :                 results.sumIntGain += state.dataSurface->SurfWinDividerHeatGain(SurfNum);
    5689             :             }
    5690             : 
    5691             :             // Other convection term is applicable to equivalent layer window (ASHWAT) model
    5692    72079374 :             if (state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).WindowTypeEQL)
    5693       16326 :                 results.sumIntGain += state.dataSurface->SurfWinOtherConvHeatGain(SurfNum);
    5694             : 
    5695             :             // Convective heat gain from natural convection in gap between glass and interior shade or blind
    5696    72079374 :             if (ANY_INTERIOR_SHADE_BLIND(shading_flag)) results.sumIntGain += state.dataSurface->SurfWinConvHeatFlowNatural(SurfNum);
    5697             : 
    5698             :             // Convective heat gain from airflow window
    5699    72079374 :             if (state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
    5700       40144 :                 results.sumIntGain += state.dataSurface->SurfWinConvHeatGainToZoneAir(SurfNum);
    5701       40144 :                 if (thisZone.NoHeatToReturnAir) {
    5702       40048 :                     results.sumIntGain += state.dataSurface->SurfWinRetHeatGainToZoneAir(SurfNum);
    5703       40048 :                     state.dataSurface->SurfWinHeatGain(SurfNum) += state.dataSurface->SurfWinRetHeatGainToZoneAir(SurfNum);
    5704       40048 :                     if (state.dataSurface->SurfWinHeatGain(SurfNum) >= 0.0) {
    5705       11000 :                         state.dataSurface->SurfWinHeatGainRep(SurfNum) = state.dataSurface->SurfWinHeatGain(SurfNum);
    5706       11000 :                         state.dataSurface->SurfWinHeatGainRepEnergy(SurfNum) =
    5707       11000 :                             state.dataSurface->SurfWinHeatGainRep(SurfNum) * state.dataGlobal->TimeStepZoneSec;
    5708             :                     } else {
    5709       29048 :                         state.dataSurface->SurfWinHeatLossRep(SurfNum) = -state.dataSurface->SurfWinHeatGain(SurfNum);
    5710       29048 :                         state.dataSurface->SurfWinHeatLossRepEnergy(SurfNum) =
    5711       29048 :                             state.dataSurface->SurfWinHeatLossRep(SurfNum) * state.dataGlobal->TimeStepZoneSec;
    5712             :                     }
    5713       40048 :                     state.dataSurface->SurfWinHeatTransferRepEnergy(SurfNum) =
    5714       40048 :                         state.dataSurface->SurfWinHeatGain(SurfNum) * state.dataGlobal->TimeStepZoneSec;
    5715             :                 }
    5716             :             }
    5717             : 
    5718             :             // Add to the surface convection sums
    5719    72079374 :             if (state.dataSurface->SurfWinFrameArea(SurfNum) > 0.0) {
    5720             :                 // Window frame contribution
    5721     2878140 :                 Real64 const HA_surf(state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataSurface->SurfWinFrameArea(SurfNum) *
    5722     2878140 :                                      (1.0 + state.dataSurface->SurfWinProjCorrFrIn(SurfNum)));
    5723     2878140 :                 results.sumHATsurf += HA_surf * state.dataSurface->SurfWinFrameTempIn(SurfNum);
    5724     2878140 :                 HA += HA_surf;
    5725             :             }
    5726             : 
    5727    72079374 :             if (state.dataSurface->SurfWinDividerArea(SurfNum) > 0.0 && !ANY_INTERIOR_SHADE_BLIND(shading_flag)) {
    5728             :                 // Window divider contribution (only from shade or blind for window with divider and interior shade or blind)
    5729      996450 :                 Real64 const HA_surf(state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataSurface->SurfWinDividerArea(SurfNum) *
    5730      996450 :                                      (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum)));
    5731      996450 :                 results.sumHATsurf += HA_surf * state.dataSurface->SurfWinDividerTempIn(SurfNum);
    5732      996450 :                 HA += HA_surf;
    5733             :             }
    5734             : 
    5735             :         } // End of check if window
    5736             : 
    5737   522854340 :         HA += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * Area;
    5738   522854340 :         results.sumHATsurf += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * Area * state.dataHeatBalSurf->SurfTempInTmp(SurfNum);
    5739             : 
    5740             :         // determine reference air temperature for this surface
    5741   522854340 :         switch (state.dataSurface->SurfTAirRef(SurfNum)) {
    5742     3134082 :         case DataSurfaces::RefAirTemp::ZoneMeanAirTemp:
    5743             :             // The zone air is the reference temperature (which is to be solved for in CorrectZoneAirTemp).
    5744     3134082 :             results.sumHA += HA;
    5745     3134082 :             break;
    5746     4434627 :         case DataSurfaces::RefAirTemp::AdjacentAirTemp:
    5747     4434627 :             results.sumHATref += HA * state.dataHeatBal->SurfTempEffBulkAir(SurfNum);
    5748     4434627 :             break;
    5749           0 :         case DataSurfaces::RefAirTemp::ZoneSupplyAirTemp:
    5750             :             // check whether this zone is a controlled zone or not
    5751           0 :             if (!thisZone.IsControlled) {
    5752           0 :                 ShowFatalError(state,
    5753           0 :                                format("Zones must be controlled for Ceiling-Diffuser Convection model. No system serves zone {}", thisZone.Name));
    5754           0 :                 return results;
    5755             :             }
    5756             :             // determine supply air temperature as a weighted average of the inlet temperatures.
    5757             :             // TODO: For now, use zone-level values for system flow
    5758           0 :             if (state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum).SumSysMCp > 0.0) {
    5759           0 :                 results.sumHATref += HA * state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum).SumSysMCpT /
    5760           0 :                                      state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum).SumSysMCp;
    5761             :             } else {
    5762             :                 // no system flow (yet) so just use zone air temperature #5906
    5763           0 :                 results.sumHA += HA;
    5764             :             }
    5765           0 :             break;
    5766   515285631 :         default:
    5767             :             // currently set to mean air temp but should add error warning here
    5768   515285631 :             results.sumHA += HA;
    5769   515285631 :             break;
    5770             :         }
    5771             : 
    5772             :     } // SurfNum
    5773    60077418 :     return results;
    5774             : }
    5775    30002743 : void CalcZoneComponentLoadSums(EnergyPlusData &state,
    5776             :                                int ZoneNum, // Zone number
    5777             :                                ZoneTempPredictorCorrector::ZoneSpaceHeatBalanceData *thisHB,
    5778             :                                DataHeatBalance::AirReportVars &thisAirRpt)
    5779             : {
    5780             : 
    5781             :     // SUBROUTINE INFORMATION:
    5782             :     //       AUTHOR         Brent Griffith
    5783             :     //       DATE WRITTEN   Feb 2008
    5784             : 
    5785             :     // PURPOSE OF THIS SUBROUTINE:
    5786             :     // This subroutine calculates the various sums that go into the zone heat balance
    5787             :     // equation for reporting (and diagnostic) purposes only.
    5788             :     // It was derived from CalcZonethisAirRpt.Sums but differs in that that routine
    5789             :     // breaks up the component's dependence on zone air temp in order to *solve* for zone air temp,
    5790             :     // but here we *use* the result for zone air temp and calculate the terms of the heat balance
    5791             :     // Go back and calculate each of the 6 terms in Equation 5 and fill report variables.
    5792             :     // notes on these raw terms for zone air heat balance model :
    5793             :     //  these are state variables at the end of the last system timestep.
    5794             :     //  they are not necessarily proper averages for what happened over entire zone time step
    5795             :     //  these are not multiplied by zone multipliers.
    5796             :     //  The values are all Watts.
    5797             : 
    5798             :     // REFERENCES:
    5799             :     // Equation 5 in Engineering Reference.
    5800             : 
    5801    30002743 :     thisAirRpt.SumIntGains = 0.0;    // Zone sum of convective internal gains
    5802    30002743 :     thisAirRpt.SumHADTsurfs = 0.0;   // Zone sum of Hc*Area*(Tsurf - Tz)
    5803    30002743 :     thisAirRpt.SumMCpDTzones = 0.0;  // zone sum of MassFlowRate*cp*(TremotZone - Tz) transfer air from other zone, Mixing
    5804    30002743 :     thisAirRpt.SumMCpDtInfil = 0.0;  // Zone sum of MassFlowRate*Cp*(Tout - Tz)
    5805    30002743 :     thisAirRpt.SumMCpDTsystem = 0.0; // Zone sum of air system MassFlowRate*Cp*(Tsup - Tz)
    5806    30002743 :     thisAirRpt.SumNonAirSystem = 0.0;
    5807    30002743 :     thisAirRpt.CzdTdt = 0.0;
    5808    30002743 :     thisAirRpt.imBalance = 0.0;
    5809    30002743 :     thisAirRpt.SumEnthalpyM = 0.0;
    5810    30002743 :     thisAirRpt.SumEnthalpyH = 0.0;
    5811             : 
    5812    30002743 :     auto &thisZone = state.dataHeatBal->Zone(ZoneNum);
    5813             : 
    5814    30002743 :     Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    5815             : 
    5816             :     // Sum all convective internal gains: SumIntGain
    5817    30002743 :     thisAirRpt.SumIntGains = InternalHeatGains::zoneSumAllInternalConvectionGains(state, ZoneNum);
    5818             : 
    5819             :     // Add heat to return air if zonal system (no return air) or cycling system (return air frequently very
    5820             :     // low or zero)
    5821    30002743 :     if (thisZone.NoHeatToReturnAir) {
    5822     3602540 :         thisAirRpt.SumIntGains += InternalHeatGains::zoneSumAllReturnAirConvectionGains(state, ZoneNum, 0);
    5823             :     }
    5824             : 
    5825             :     // sum non-system air flow transfers between zones
    5826    30002743 :     thisAirRpt.SumMCpDTzones = thisHB->MCPTM - thisHB->MCPM * thisHB->MAT; // but maybe it should be ZTAV(ZoneNum)
    5827             : 
    5828             :     // Sum non-system air flow, i.e. infiltration, simple ventilation, earth tube
    5829             :     //  reuse SumMCp, SumMCpT from CalcZoneSum but use MAT (or maybe ZTAV?) to complete
    5830    30002743 :     thisAirRpt.SumMCpDtInfil = (thisHB->MCPTI - thisHB->MCPI * thisHB->MAT) + (thisHB->MCPTV - thisHB->MCPV * thisHB->MAT) +
    5831    30002743 :                                (thisHB->MCPTE - thisHB->MCPE * thisHB->MAT) + (thisHB->MCPTC - thisHB->MCPC * thisHB->MAT) +
    5832    30002743 :                                (thisHB->MDotCPOA * thisZone.OutDryBulbTemp -
    5833    30002743 :                                 thisHB->MDotCPOA * thisHB->MAT); // infiltration | Ventilation (simple) | Earth tube. | Cooltower | combined OA flow
    5834             : 
    5835             :     // Sum all multizone air flow calculated from AirflowNetwork by assuming no simple air infiltration model (if used)
    5836    59513823 :     if (state.afn->multizone_always_simulated ||
    5837    29511080 :         (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
    5838       23258 :          state.afn->AirflowNetworkFanActivated)) {
    5839             :         // Multizone airflow calculated in AirflowNetwork
    5840      509897 :         thisAirRpt.SumMCpDtInfil = state.afn->exchangeData(ZoneNum).SumMCpT + state.afn->exchangeData(ZoneNum).SumMVCpT -
    5841      509897 :                                    (state.afn->exchangeData(ZoneNum).SumMCp + state.afn->exchangeData(ZoneNum).SumMVCp) * thisHB->MAT;
    5842      509897 :         thisAirRpt.SumMCpDTzones = state.afn->exchangeData(ZoneNum).SumMMCpT - state.afn->exchangeData(ZoneNum).SumMMCp * thisHB->MAT;
    5843             :     }
    5844             : 
    5845             :     // Sum all system air flow: reusing how SumSysMCp, SumSysMCpT are calculated in CalcZoneSums
    5846             :     // Plenum and controlled zones have a different set of inlet nodes which must be calculated.
    5847    30002743 :     Real64 QSensRate = 0.0;
    5848    30002743 :     if (thisZone.IsControlled) {
    5849    25763444 :         auto &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(ZoneNum);
    5850    51968221 :         for (int NodeNum = 1; NodeNum <= zoneEquipConfig.NumInletNodes; ++NodeNum) {
    5851             :             // Get node conditions
    5852    26204777 :             Real64 const NodeTemp = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(NodeNum)).Temp;
    5853    26204777 :             Real64 const MassFlowRate = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(NodeNum)).MassFlowRate;
    5854    26204777 :             QSensRate = calcZoneSensibleOutput(MassFlowRate, NodeTemp, thisHB->MAT, thisHB->airHumRat);
    5855    26204777 :             thisAirRpt.SumMCpDTsystem += QSensRate;
    5856             : 
    5857    26204777 :             if (zoneEquipConfig.InletNodeADUNum(NodeNum) > 0) {
    5858    13820498 :                 auto &airDistUnit = state.dataDefineEquipment->AirDistUnit(zoneEquipConfig.InletNodeADUNum(NodeNum));
    5859    13820498 :                 Real64 ADUHeatAddRate = calcZoneSensibleOutput(state.dataLoopNodes->Node(airDistUnit.OutletNodeNum).MassFlowRate,
    5860    13820498 :                                                                state.dataLoopNodes->Node(airDistUnit.OutletNodeNum).Temp,
    5861             :                                                                thisHB->MAT,
    5862             :                                                                thisHB->airHumRat);
    5863    13820498 :                 airDistUnit.HeatRate = max(0.0, ADUHeatAddRate);
    5864    13820498 :                 airDistUnit.CoolRate = std::abs(min(0.0, ADUHeatAddRate));
    5865    13820498 :                 airDistUnit.HeatGain = airDistUnit.HeatRate * TimeStepSysSec;
    5866    13820498 :                 airDistUnit.CoolGain = airDistUnit.CoolRate * TimeStepSysSec;
    5867             :             }
    5868             :         }
    5869             : 
    5870     4239299 :     } else if (thisZone.IsReturnPlenum) {
    5871     1083884 :         auto &zoneRetPlenCond = state.dataZonePlenum->ZoneRetPlenCond(thisZone.PlenumCondNum);
    5872     6284133 :         for (int NodeNum = 1; NodeNum <= zoneRetPlenCond.NumInletNodes; ++NodeNum) {
    5873     5200249 :             QSensRate = calcZoneSensibleOutput(state.dataLoopNodes->Node(zoneRetPlenCond.InletNode(NodeNum)).MassFlowRate,
    5874     5200249 :                                                state.dataLoopNodes->Node(zoneRetPlenCond.InletNode(NodeNum)).Temp,
    5875             :                                                thisHB->MAT,
    5876             :                                                thisHB->airHumRat);
    5877     5200249 :             thisAirRpt.SumMCpDTsystem += QSensRate;
    5878             :         }
    5879             :         // add in the leaks
    5880     6302773 :         for (int ADUListIndex = 1; ADUListIndex <= zoneRetPlenCond.NumADUs; ++ADUListIndex) {
    5881     5218889 :             auto &airDistUnit = state.dataDefineEquipment->AirDistUnit(zoneRetPlenCond.ADUIndex(ADUListIndex));
    5882     5218889 :             if (airDistUnit.UpStreamLeak) {
    5883      319785 :                 QSensRate = calcZoneSensibleOutput(
    5884      106595 :                     airDistUnit.MassFlowRateUpStrLk, state.dataLoopNodes->Node(airDistUnit.InletNodeNum).Temp, thisHB->MAT, thisHB->airHumRat);
    5885      106595 :                 thisAirRpt.SumMCpDTsystem += QSensRate;
    5886             :             }
    5887     5218889 :             if (airDistUnit.DownStreamLeak) {
    5888      319785 :                 QSensRate = calcZoneSensibleOutput(
    5889      106595 :                     airDistUnit.MassFlowRateDnStrLk, state.dataLoopNodes->Node(airDistUnit.OutletNodeNum).Temp, thisHB->MAT, thisHB->airHumRat);
    5890      106595 :                 thisAirRpt.SumMCpDTsystem += QSensRate;
    5891             :             }
    5892             :         }
    5893             : 
    5894     3155415 :     } else if (thisZone.IsSupplyPlenum) {
    5895       19526 :         auto &zoneSupPlenCond = state.dataZonePlenum->ZoneSupPlenCond(thisZone.PlenumCondNum);
    5896       19526 :         QSensRate = calcZoneSensibleOutput(state.dataLoopNodes->Node(zoneSupPlenCond.InletNode).MassFlowRate,
    5897       19526 :                                            state.dataLoopNodes->Node(zoneSupPlenCond.InletNode).Temp,
    5898             :                                            thisHB->MAT,
    5899             :                                            thisHB->airHumRat);
    5900       19526 :         thisAirRpt.SumMCpDTsystem += QSensRate;
    5901             :     }
    5902             : 
    5903             :     // non air system response.
    5904    30002743 :     thisAirRpt.SumNonAirSystem =
    5905    30002743 :         thisHB->NonAirSystemResponse + state.dataHeatBalFanSys->SumConvHTRadSys(ZoneNum) + state.dataHeatBalFanSys->SumConvPool(ZoneNum);
    5906             : 
    5907             :     // Sum all surface convection: SumHA, SumHATsurf, SumHATref (and additional contributions to SumIntGain)
    5908    60137138 :     for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
    5909    30134395 :         auto &thisSpace = state.dataHeatBal->space(spaceNum);
    5910   292024439 :         for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
    5911             : 
    5912   261890044 :             Real64 Area = state.dataSurface->Surface(SurfNum).Area; // For windows, this is the glazing area
    5913   261890044 :             Real64 RefAirTemp = state.dataSurface->Surface(SurfNum).getInsideAirTemperature(state, SurfNum);
    5914             : 
    5915   261890044 :             if (state.dataSurface->Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window) {
    5916             : 
    5917             :                 // Add to the convective internal gains
    5918    36082605 :                 if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
    5919             :                     // The shade area covers the area of the glazing plus the area of the dividers.
    5920      277631 :                     Area += state.dataSurface->SurfWinDividerArea(SurfNum);
    5921             :                     // If interior shade or blind is present it is assumed that both the convective and IR radiative gain
    5922             :                     // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative
    5923             :                     // interaction between divider and shade or blind is ignored due to the difficulty of calculating this interaction
    5924             :                     // at the same time that the interaction between glass and shade is calculated.
    5925      277631 :                     thisAirRpt.SumIntGains += state.dataSurface->SurfWinDividerHeatGain(SurfNum);
    5926             :                 }
    5927             : 
    5928             :                 // Other convection term is applicable to equivalent layer window (ASHWAT) model
    5929    36082605 :                 if (state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).WindowTypeEQL)
    5930        8163 :                     thisAirRpt.SumIntGains += state.dataSurface->SurfWinOtherConvHeatGain(SurfNum);
    5931             : 
    5932             :                 // Convective heat gain from natural convection in gap between glass and interior shade or blind
    5933    36082605 :                 if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum)))
    5934      277631 :                     thisAirRpt.SumIntGains += state.dataSurface->SurfWinConvHeatFlowNatural(SurfNum);
    5935             : 
    5936             :                 // Convective heat gain from airflow window
    5937    36082605 :                 if (state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
    5938       20072 :                     thisAirRpt.SumIntGains += state.dataSurface->SurfWinConvHeatGainToZoneAir(SurfNum);
    5939       20072 :                     if (thisZone.NoHeatToReturnAir) {
    5940       20024 :                         thisAirRpt.SumIntGains += state.dataSurface->SurfWinRetHeatGainToZoneAir(SurfNum);
    5941             :                     }
    5942             :                 }
    5943             : 
    5944             :                 // Add to the surface convection sums
    5945    36082605 :                 if (state.dataSurface->SurfWinFrameArea(SurfNum) > 0.0) {
    5946             :                     // Window frame contribution
    5947     1439070 :                     thisAirRpt.SumHADTsurfs += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataSurface->SurfWinFrameArea(SurfNum) *
    5948     1439070 :                                                (1.0 + state.dataSurface->SurfWinProjCorrFrIn(SurfNum)) *
    5949     1439070 :                                                (state.dataSurface->SurfWinFrameTempIn(SurfNum) - RefAirTemp);
    5950             :                 }
    5951             : 
    5952    36583819 :                 if (state.dataSurface->SurfWinDividerArea(SurfNum) > 0.0 &&
    5953      501214 :                     !ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
    5954             :                     // Window divider contribution (only from shade or blind for window with divider and interior shade or blind)
    5955      498225 :                     thisAirRpt.SumHADTsurfs += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataSurface->SurfWinDividerArea(SurfNum) *
    5956      498225 :                                                (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum)) *
    5957      498225 :                                                (state.dataSurface->SurfWinDividerTempIn(SurfNum) - RefAirTemp);
    5958             :                 }
    5959             : 
    5960             :             } // End of check if window
    5961             : 
    5962   261890044 :             thisAirRpt.SumHADTsurfs +=
    5963   261890044 :                 state.dataHeatBalSurf->SurfHConvInt(SurfNum) * Area * (state.dataHeatBalSurf->SurfTempInTmp(SurfNum) - RefAirTemp);
    5964             : 
    5965             :             // Accumulate Zone Phase Change Material Melting/Freezing Enthalpy output variables
    5966   261890044 :             if (state.dataSurface->Surface(SurfNum).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CondFD) {
    5967     1710066 :                 thisAirRpt.SumEnthalpyM += state.dataHeatBalFiniteDiffMgr->SurfaceFD(SurfNum).EnthalpyM;
    5968     1710066 :                 thisAirRpt.SumEnthalpyH += state.dataHeatBalFiniteDiffMgr->SurfaceFD(SurfNum).EnthalpyF;
    5969             :             }
    5970             :         }
    5971    30002743 :     }
    5972             :     // now calculate air energy storage source term.
    5973             :     // capacitance is volume * density * heat capacity
    5974    30002743 :     Real64 CpAir = Psychrometrics::PsyCpAirFnW(thisHB->airHumRat);
    5975    30002743 :     Real64 RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisHB->MAT, thisHB->airHumRat);
    5976             : 
    5977    30002743 :     switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    5978    16975380 :     case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    5979    16975380 :         thisAirRpt.CzdTdt = RhoAir * CpAir * thisZone.Volume * thisZone.ZoneVolCapMultpSens * (thisHB->MAT - thisHB->ZTM[0]) / TimeStepSysSec;
    5980             :         // Exact solution
    5981    16975380 :     } break;
    5982    12989153 :     case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    5983    12989153 :         thisAirRpt.CzdTdt = thisHB->TempIndCoef - thisHB->TempDepCoef * thisHB->MAT;
    5984    12989153 :     } break;
    5985       38210 :     case DataHeatBalance::SolutionAlgo::EulerMethod: {
    5986       38210 :         thisAirRpt.CzdTdt = thisHB->AirPowerCap * (thisHB->MAT - thisHB->T1);
    5987       38210 :     } break;
    5988           0 :     default:
    5989           0 :         break;
    5990             :     }
    5991             : 
    5992    30002743 :     if (state.dataGlobal->DisplayZoneAirHeatBalanceOffBalance) {
    5993      263377 :         thisAirRpt.imBalance = thisAirRpt.SumIntGains + thisAirRpt.SumHADTsurfs + thisAirRpt.SumMCpDTzones + thisAirRpt.SumMCpDtInfil +
    5994      263377 :                                thisAirRpt.SumMCpDTsystem + thisAirRpt.SumNonAirSystem - thisAirRpt.CzdTdt;
    5995             : 
    5996             :         // throw warning if seriously out of balance (this may need to be removed if too noisy... )
    5997             :         // formulate dynamic threshold value based on 20% of quadrature sum of components
    5998      263377 :         Real64 Threshold = 0.2 * std::sqrt(pow_2(thisAirRpt.SumIntGains) + pow_2(thisAirRpt.SumHADTsurfs) + pow_2(thisAirRpt.SumMCpDTzones) +
    5999      263377 :                                            pow_2(thisAirRpt.SumMCpDtInfil) + pow_2(thisAirRpt.SumMCpDTsystem) + pow_2(thisAirRpt.SumNonAirSystem) +
    6000      263377 :                                            pow_2(thisAirRpt.CzdTdt));
    6001      264173 :         if ((std::abs(thisAirRpt.imBalance) > Threshold) && (!state.dataGlobal->WarmupFlag) &&
    6002         796 :             (!state.dataGlobal->DoingSizing)) { // air balance is out by more than threshold
    6003         796 :             if (thisZone.AirHBimBalanceErrIndex == 0) {
    6004          14 :                 ShowWarningMessage(state, format("Zone Air Heat Balance is out of balance for zone named {}", thisZone.Name));
    6005          14 :                 ShowContinueError(state, format("Zone Air Heat Balance Deviation Rate is more than {:.1R} {{W}}", Threshold));
    6006          14 :                 if (state.dataHVACGlobal->TurnFansOn) {
    6007           0 :                     ShowContinueError(state, "Night cycle fan operation may be causing above error");
    6008             :                 }
    6009             : 
    6010          14 :                 ShowContinueErrorTimeStamp(state, " Occurrence info:");
    6011             :             }
    6012        2388 :             ShowRecurringWarningErrorAtEnd(state,
    6013        1592 :                                            format("Zone Air Heat Balance is out of balance ... zone named {}", thisZone.Name),
    6014         796 :                                            thisZone.AirHBimBalanceErrIndex,
    6015        1592 :                                            std::abs(thisAirRpt.imBalance) - Threshold,
    6016        1592 :                                            std::abs(thisAirRpt.imBalance) - Threshold,
    6017             :                                            _,
    6018             :                                            "{W}",
    6019             :                                            "{W}");
    6020             :         }
    6021             :     }
    6022    30002743 : }
    6023             : 
    6024        3493 : bool VerifyThermostatInZone(EnergyPlusData &state, std::string const &ZoneName) // Zone to verify
    6025             : {
    6026             : 
    6027             :     // FUNCTION INFORMATION:
    6028             :     //       AUTHOR         Linda Lawrie
    6029             :     //       DATE WRITTEN   Feb 2005
    6030             : 
    6031             :     // PURPOSE OF THIS FUNCTION:
    6032             :     // This function verifies that a zone (by name) has a Zone Control:Thermostatic object entered.
    6033             : 
    6034        3493 :     if (state.dataZoneCtrls->GetZoneAirStatsInputFlag) {
    6035           0 :         GetZoneAirSetPoints(state);
    6036           0 :         state.dataZoneCtrls->GetZoneAirStatsInputFlag = false;
    6037             :     }
    6038        3493 :     if (state.dataZoneCtrls->NumTempControlledZones > 0) {
    6039        3490 :         if (Util::FindItemInList(ZoneName, state.dataZoneCtrls->TempControlledZone, &DataZoneControls::ZoneTempControls::ZoneName) > 0) {
    6040        3489 :             return true;
    6041             :         } else {
    6042           1 :             return false;
    6043             :         }
    6044             :     }
    6045           3 :     return false;
    6046             : }
    6047             : 
    6048        4192 : bool VerifyControlledZoneForThermostat(EnergyPlusData &state, std::string const &ZoneName) // Zone to verify
    6049             : {
    6050             : 
    6051             :     // FUNCTION INFORMATION:
    6052             :     //       AUTHOR         Linda Lawrie
    6053             :     //       DATE WRITTEN   Mar 2007
    6054             : 
    6055             :     // PURPOSE OF THIS FUNCTION:
    6056             :     // This function verifies that a zone (by name) has a ZoneHVAC:EquipmentConnections object entered.
    6057             : 
    6058        4192 :     return (Util::FindItemInList(ZoneName, state.dataZoneEquip->ZoneEquipConfig, &DataZoneEquipment::EquipConfiguration::ZoneName) > 0);
    6059             : }
    6060             : 
    6061     3561101 : void DetectOscillatingZoneTemp(EnergyPlusData &state)
    6062             : {
    6063             :     // SUBROUTINE INFORMATION:
    6064             :     //       AUTHOR         Jason Glazer
    6065             :     //       DATE WRITTEN   August 2005
    6066             : 
    6067             :     // PURPOSE OF THIS SUBROUTINE:
    6068             :     // Oscillating temperatures between HVAC timesteps indicate that the
    6069             :     // simulation may be poor. Code is trying to be fast since the purpose
    6070             :     // is to see the impact on oscillating by trying longer time steps in
    6071             :     // an attempt to speed up the simulation.
    6072             :     // Note that the OscillateMagnitude threshold must be less than
    6073             :     // MaxZoneTempDiff since ManageHVAC keeps shortening the timestep
    6074             :     // until that is reached unless it goes to less than the
    6075             :     // MinTimeStepSys.
    6076             : 
    6077             :     // first time run allocate arrays and setup output variable
    6078     3561101 :     if (state.dataZoneTempPredictorCorrector->SetupOscillationOutputFlag) {
    6079         796 :         state.dataZoneTempPredictorCorrector->ZoneTempHist.allocate(4, state.dataGlobal->NumOfZones);
    6080         796 :         state.dataZoneTempPredictorCorrector->ZoneTempHist = 0.0;
    6081         796 :         state.dataZoneTempPredictorCorrector->ZoneTempOscillate.dimension(state.dataGlobal->NumOfZones, 0.0);
    6082         796 :         state.dataZoneTempPredictorCorrector->ZoneTempOscillateDuringOccupancy.dimension(state.dataGlobal->NumOfZones, 0.0);
    6083         796 :         state.dataZoneTempPredictorCorrector->ZoneTempOscillateInDeadband.dimension(state.dataGlobal->NumOfZones, 0.0);
    6084             :         // set up zone by zone variables, CurrentModuleObject='Zone'
    6085        5852 :         for (int iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    6086        5056 :             auto &zone = state.dataHeatBal->Zone(iZone);
    6087       10112 :             SetupOutputVariable(state,
    6088             :                                 "Zone Oscillating Temperatures Time",
    6089             :                                 Constant::Units::hr,
    6090        5056 :                                 state.dataZoneTempPredictorCorrector->ZoneTempOscillate(iZone),
    6091             :                                 OutputProcessor::TimeStepType::System,
    6092             :                                 OutputProcessor::StoreType::Sum,
    6093        5056 :                                 zone.Name);
    6094       10112 :             SetupOutputVariable(state,
    6095             :                                 "Zone Oscillating Temperatures During Occupancy Time",
    6096             :                                 Constant::Units::hr,
    6097        5056 :                                 state.dataZoneTempPredictorCorrector->ZoneTempOscillateDuringOccupancy(iZone),
    6098             :                                 OutputProcessor::TimeStepType::System,
    6099             :                                 OutputProcessor::StoreType::Sum,
    6100        5056 :                                 zone.Name);
    6101       10112 :             SetupOutputVariable(state,
    6102             :                                 "Zone Oscillating Temperatures in Deadband Time",
    6103             :                                 Constant::Units::hr,
    6104        5056 :                                 state.dataZoneTempPredictorCorrector->ZoneTempOscillateInDeadband(iZone),
    6105             :                                 OutputProcessor::TimeStepType::System,
    6106             :                                 OutputProcessor::StoreType::Sum,
    6107        5056 :                                 zone.Name);
    6108             :         }
    6109             :         // set up a variable covering all zones
    6110        1592 :         SetupOutputVariable(state,
    6111             :                             "Facility Any Zone Oscillating Temperatures Time",
    6112             :                             Constant::Units::hr,
    6113         796 :                             state.dataZoneTempPredictorCorrector->AnyZoneTempOscillate,
    6114             :                             OutputProcessor::TimeStepType::System,
    6115             :                             OutputProcessor::StoreType::Sum,
    6116             :                             "Facility");
    6117        1592 :         SetupOutputVariable(state,
    6118             :                             "Facility Any Zone Oscillating Temperatures During Occupancy Time",
    6119             :                             Constant::Units::hr,
    6120         796 :                             state.dataZoneTempPredictorCorrector->AnyZoneTempOscillateDuringOccupancy,
    6121             :                             OutputProcessor::TimeStepType::System,
    6122             :                             OutputProcessor::StoreType::Sum,
    6123             :                             "Facility");
    6124        1592 :         SetupOutputVariable(state,
    6125             :                             "Facility Any Zone Oscillating Temperatures in Deadband Time",
    6126             :                             Constant::Units::hr,
    6127         796 :                             state.dataZoneTempPredictorCorrector->AnyZoneTempOscillateInDeadband,
    6128             :                             OutputProcessor::TimeStepType::System,
    6129             :                             OutputProcessor::StoreType::Sum,
    6130             :                             "Facility");
    6131             :         // test if the oscillation variables are even used
    6132        1592 :         if (ReportingThisVariable(state, "Zone Oscillating Temperatures Time") ||
    6133        1592 :             ReportingThisVariable(state, "Zone Oscillating Temperatures During Occupancy Time") ||
    6134        1592 :             ReportingThisVariable(state, "Zone Oscillating Temperatures in Deadband Time") ||
    6135        1592 :             ReportingThisVariable(state, "Facility Any Zone Oscillating Temperatures Time") ||
    6136        3980 :             ReportingThisVariable(state, "Facility Any Zone Oscillating Temperatures During Occupancy Time") ||
    6137        1592 :             ReportingThisVariable(state, "Facility Any Zone Oscillating Temperatures in Deadband Time")) {
    6138           0 :             state.dataZoneTempPredictorCorrector->OscillationVariablesNeeded = true;
    6139             :         }
    6140         796 :         state.dataZoneTempPredictorCorrector->SetupOscillationOutputFlag = false;
    6141             :     }
    6142             : 
    6143     3561101 :     Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    6144     3561101 :     if (state.dataZoneTempPredictorCorrector->OscillationVariablesNeeded) {
    6145             :         // precalc the negative value for performance
    6146       18342 :         Real64 NegOscillateMagnitude = -HVAC::OscillateMagnitude;
    6147             :         // assume no zone is oscillating
    6148       18342 :         bool isAnyZoneOscillating = false;
    6149       18342 :         bool isAnyZoneOscillatingDuringOccupancy = false;
    6150       18342 :         bool isAnyZoneOscillatingInDeadband = false;
    6151             : 
    6152      342829 :         for (int iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    6153      324487 :             bool isOscillate = false;
    6154      324487 :             state.dataZoneTempPredictorCorrector->ZoneTempHist(4, iZone) = state.dataZoneTempPredictorCorrector->ZoneTempHist(3, iZone);
    6155      324487 :             state.dataZoneTempPredictorCorrector->ZoneTempHist(3, iZone) = state.dataZoneTempPredictorCorrector->ZoneTempHist(2, iZone);
    6156      324487 :             state.dataZoneTempPredictorCorrector->ZoneTempHist(2, iZone) = state.dataZoneTempPredictorCorrector->ZoneTempHist(1, iZone);
    6157      324487 :             state.dataZoneTempPredictorCorrector->ZoneTempHist(1, iZone) = state.dataZoneTempPredictorCorrector->zoneHeatBalance(iZone).ZT;
    6158             :             Real64 Diff34 =
    6159      324487 :                 state.dataZoneTempPredictorCorrector->ZoneTempHist(3, iZone) - state.dataZoneTempPredictorCorrector->ZoneTempHist(4, iZone);
    6160             :             Real64 Diff23 =
    6161      324487 :                 state.dataZoneTempPredictorCorrector->ZoneTempHist(2, iZone) - state.dataZoneTempPredictorCorrector->ZoneTempHist(3, iZone);
    6162             :             Real64 Diff12 =
    6163      324487 :                 state.dataZoneTempPredictorCorrector->ZoneTempHist(1, iZone) - state.dataZoneTempPredictorCorrector->ZoneTempHist(2, iZone);
    6164             :             // roll out the conditionals for increased performance
    6165      324487 :             if (Diff12 > HVAC::OscillateMagnitude) {
    6166       58059 :                 if (Diff23 < NegOscillateMagnitude) {
    6167       10840 :                     if (Diff34 > HVAC::OscillateMagnitude) {
    6168        2734 :                         isOscillate = true;
    6169             :                     }
    6170             :                 }
    6171             :             }
    6172             :             // now try the opposite sequence of swings
    6173      324487 :             if (Diff12 < NegOscillateMagnitude) {
    6174       52758 :                 if (Diff23 > HVAC::OscillateMagnitude) {
    6175        7372 :                     if (Diff34 < NegOscillateMagnitude) {
    6176        2378 :                         isOscillate = true;
    6177             :                     }
    6178             :                 }
    6179             :             }
    6180      324487 :             state.dataZoneTempPredictorCorrector->ZoneTempOscillateDuringOccupancy(iZone) = 0.0;
    6181      324487 :             state.dataZoneTempPredictorCorrector->ZoneTempOscillateInDeadband(iZone) = 0.0;
    6182      324487 :             if (isOscillate) {
    6183        5112 :                 state.dataZoneTempPredictorCorrector->ZoneTempOscillate(iZone) = TimeStepSys;
    6184        5112 :                 isAnyZoneOscillating = true;
    6185        5112 :                 if (allocated(state.dataThermalComforts->ThermalComfortInASH55)) {
    6186        5112 :                     if (state.dataThermalComforts->ThermalComfortInASH55(iZone).ZoneIsOccupied) {
    6187         372 :                         state.dataZoneTempPredictorCorrector->ZoneTempOscillateDuringOccupancy(iZone) = TimeStepSys;
    6188         372 :                         isAnyZoneOscillatingDuringOccupancy = true;
    6189             :                     }
    6190             :                 }
    6191        5112 :                 if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(iZone)) {
    6192         882 :                     state.dataZoneTempPredictorCorrector->ZoneTempOscillateInDeadband(iZone) = TimeStepSys;
    6193         882 :                     isAnyZoneOscillatingInDeadband = true;
    6194             :                 }
    6195             :             } else {
    6196      319375 :                 state.dataZoneTempPredictorCorrector->ZoneTempOscillate(iZone) = 0.0;
    6197             :             }
    6198             :         }
    6199             :         // any zone variable
    6200       18342 :         state.dataZoneTempPredictorCorrector->AnyZoneTempOscillate = (isAnyZoneOscillating) ? TimeStepSys : 0.0;
    6201       18342 :         state.dataZoneTempPredictorCorrector->AnyZoneTempOscillateDuringOccupancy = (isAnyZoneOscillatingDuringOccupancy) ? TimeStepSys : 0.0;
    6202       18342 :         state.dataZoneTempPredictorCorrector->AnyZoneTempOscillateInDeadband = (isAnyZoneOscillatingInDeadband) ? TimeStepSys : 0.0;
    6203             : 
    6204             :         // annual/runperiod sum for _perflog.csv file
    6205       18342 :         state.dataZoneTempPredictorCorrector->AnnualAnyZoneTempOscillate += state.dataZoneTempPredictorCorrector->AnyZoneTempOscillate;
    6206       36684 :         state.dataZoneTempPredictorCorrector->AnnualAnyZoneTempOscillateDuringOccupancy +=
    6207       18342 :             state.dataZoneTempPredictorCorrector->AnyZoneTempOscillateDuringOccupancy;
    6208       18342 :         state.dataZoneTempPredictorCorrector->AnnualAnyZoneTempOscillateInDeadband +=
    6209       18342 :             state.dataZoneTempPredictorCorrector->AnyZoneTempOscillateInDeadband;
    6210             :     }
    6211     3561101 : }
    6212             : 
    6213    29908812 : void AdjustAirSetPointsforOpTempCntrl(EnergyPlusData &state, int const TempControlledZoneID, int const ActualZoneNum, Real64 &ZoneAirSetPoint)
    6214             : {
    6215             : 
    6216             :     // SUBROUTINE INFORMATION:
    6217             :     //       AUTHOR         B. Griffith
    6218             :     //       DATE WRITTEN   June 2006
    6219             : 
    6220             :     // PURPOSE OF THIS SUBROUTINE:
    6221             :     // This subroutine modifies the air temperature setpoint to effect operative temperature control
    6222             : 
    6223             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6224             :     Real64 thisMRTFraction; // local variable for fraction that MRT is in Op Temp definition
    6225             : 
    6226    29908812 :     if (!(state.dataZoneCtrls->AnyOpTempControl)) return; // do nothing to setpoint
    6227             : 
    6228       33144 :     auto &tempControlledZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneID);
    6229       33144 :     if (!(tempControlledZone.OperativeTempControl)) return; // do nothing to setpoint
    6230             : 
    6231             :     // is operative temp radiative fraction scheduled or fixed?
    6232       36528 :     thisMRTFraction = (tempControlledZone.OpTempCntrlModeScheduled)
    6233       18264 :                           ? ScheduleManager::GetCurrentScheduleValue(state, tempControlledZone.OpTempRadiativeFractionSched)
    6234             :                           : tempControlledZone.FixedRadiativeFraction;
    6235             : 
    6236             :     // get mean radiant temperature for zone
    6237       18264 :     Real64 thisMRT = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ActualZoneNum).MRT;
    6238             : 
    6239             :     // modify setpoint for operative temperature control
    6240             :     //  trapping for MRT fractions between 0.0 and 0.9 during get input, so shouldn't be able to divide by zero here.
    6241       18264 :     ZoneAirSetPoint = (ZoneAirSetPoint - thisMRTFraction * thisMRT) / (1.0 - thisMRTFraction);
    6242             : }
    6243             : 
    6244        6765 : void AdjustOperativeSetPointsforAdapComfort(EnergyPlusData &state, int const TempControlledZoneID, Real64 &ZoneAirSetPoint)
    6245             : {
    6246             :     // SUBROUTINE INFORMATION:
    6247             :     //       AUTHOR         Xuan Luo
    6248             :     //       DATE WRITTEN   Jan 2017
    6249             : 
    6250             :     // PURPOSE OF THIS SUBROUTINE:
    6251             :     // This routine adjust the operative setpoints for each controlled adaptive thermal comfort models.
    6252             : 
    6253        6765 :     auto &tempControlledZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneID);
    6254        6765 :     auto &AdapComfortDailySetPointSchedule = state.dataZoneTempPredictorCorrector->AdapComfortDailySetPointSchedule;
    6255             : 
    6256             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6257        6765 :     int originZoneAirSetPoint = ZoneAirSetPoint;
    6258        6765 :     int AdaptiveComfortModelTypeIndex = tempControlledZone.AdaptiveComfortModelTypeIndex;
    6259             : 
    6260             :     // adjust zone operative setpoint
    6261        6765 :     if (!(tempControlledZone.AdaptiveComfortTempControl)) return; // do nothing to setpoint
    6262        6780 :     if ((state.dataWeather->Environment(state.dataWeather->Envrn).KindOfEnvrn != Constant::KindOfSim::DesignDay) &&
    6263          15 :         (state.dataWeather->Environment(state.dataWeather->Envrn).KindOfEnvrn != Constant::KindOfSim::HVACSizeDesignDay)) {
    6264             :         // Adjust run period cooling set point
    6265          15 :         switch (AdaptiveComfortModelTypeIndex) {
    6266          15 :         case static_cast<int>(AdaptiveComfortModel::ASH55_CENTRAL):
    6267          15 :             ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Central(state.dataEnvrn->DayOfYear);
    6268          15 :             break;
    6269           0 :         case static_cast<int>(AdaptiveComfortModel::ASH55_UPPER_90):
    6270           0 :             ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_90(state.dataEnvrn->DayOfYear);
    6271           0 :             break;
    6272           0 :         case static_cast<int>(AdaptiveComfortModel::ASH55_UPPER_80):
    6273           0 :             ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_80(state.dataEnvrn->DayOfYear);
    6274           0 :             break;
    6275           0 :         case static_cast<int>(AdaptiveComfortModel::CEN15251_CENTRAL):
    6276           0 :             ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Central(state.dataEnvrn->DayOfYear);
    6277           0 :             break;
    6278           0 :         case static_cast<int>(AdaptiveComfortModel::CEN15251_UPPER_I):
    6279           0 :             ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_I(state.dataEnvrn->DayOfYear);
    6280           0 :             break;
    6281           0 :         case static_cast<int>(AdaptiveComfortModel::CEN15251_UPPER_II):
    6282           0 :             ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_II(state.dataEnvrn->DayOfYear);
    6283           0 :             break;
    6284           0 :         case static_cast<int>(AdaptiveComfortModel::CEN15251_UPPER_III):
    6285           0 :             ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_III(state.dataEnvrn->DayOfYear);
    6286           0 :             break;
    6287           0 :         default:
    6288           0 :             break;
    6289             :         }
    6290             :     } else {
    6291        6750 :         int const envrnDayNum(state.dataWeather->Environment(state.dataWeather->Envrn).DesignDayNum);
    6292        6750 :         int constexpr summerDesignDayTypeIndex(9);
    6293             :         // Adjust summer design day set point
    6294        6750 :         if (state.dataWeather->DesDayInput(envrnDayNum).DayType == summerDesignDayTypeIndex) {
    6295        6750 :             ZoneAirSetPoint = state.dataZoneTempPredictorCorrector->AdapComfortSetPointSummerDesDay[AdaptiveComfortModelTypeIndex - 2];
    6296             :         }
    6297             :     }
    6298             :     // If adaptive operative temperature not applicable, set back
    6299        6765 :     if (ZoneAirSetPoint < originZoneAirSetPoint) {
    6300          15 :         ZoneAirSetPoint = originZoneAirSetPoint;
    6301             :     }
    6302             :     // If meet fault flag, set back
    6303        6765 :     if (ZoneAirSetPoint == -1) {
    6304           0 :         ZoneAirSetPoint = originZoneAirSetPoint;
    6305             :     }
    6306             : }
    6307             : 
    6308        2025 : void CalcZoneAirComfortSetPoints(EnergyPlusData &state)
    6309             : {
    6310             : 
    6311             :     // SUBROUTINE INFORMATION:
    6312             :     //       AUTHOR         Lixing Gu
    6313             :     //       DATE WRITTEN   May 2006
    6314             : 
    6315             :     // PURPOSE OF THIS SUBROUTINE:
    6316             :     // This routine sets the thermal comfort setpoints for each controlled zone based on air tempeature obtained from thermal comfort models.
    6317             : 
    6318             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6319        2025 :     Real64 SetPointLo = 0.0;
    6320        2025 :     Real64 SetPointHi = 0.0;
    6321        2025 :     Real64 Tset = 0.0;
    6322        2025 :     int PeopleNum = 0;
    6323        2025 :     int ObjectCount = 0;
    6324        2025 :     Real64 PeopleCount = 0.0;
    6325        2025 :     int SetPointComfortSchedIndex = 0;
    6326        2025 :     int SchedTypeIndex = 0;
    6327             : 
    6328             :     // Call thermal comfort module to read zone control comfort object
    6329        2025 :     if (state.dataZoneTempPredictorCorrector->CalcZoneAirComfortSetPointsFirstTimeFlag) {
    6330           1 :         ThermalComfort::ManageThermalComfort(state, true);
    6331           1 :         state.dataZoneTempPredictorCorrector->CalcZoneAirComfortSetPointsFirstTimeFlag = false;
    6332             :     }
    6333             : 
    6334        2025 :     state.dataHeatBalFanSys->ComfortControlType = HVAC::ThermostatType::Uncontrolled; // Default
    6335             : 
    6336        4050 :     for (int RelativeZoneNum = 1; RelativeZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++RelativeZoneNum) {
    6337             : 
    6338        2025 :         auto &comfortControlledZone = state.dataZoneCtrls->ComfortControlledZone(RelativeZoneNum);
    6339        2025 :         int ActualZoneNum = comfortControlledZone.ActualZoneNum;
    6340        2025 :         auto &zone = state.dataHeatBal->Zone(ActualZoneNum);
    6341        2025 :         auto &comfortControlType = state.dataHeatBalFanSys->ComfortControlType(ActualZoneNum);
    6342        2025 :         auto &comfortControlTypeRpt = state.dataHeatBalFanSys->ComfortControlTypeRpt(ActualZoneNum);
    6343        2025 :         auto &tempZoneThermostatSetPoint = state.dataHeatBalFanSys->TempZoneThermostatSetPoint(ActualZoneNum);
    6344        2025 :         auto &zoneComfortControlsFanger = state.dataHeatBalFanSys->ZoneComfortControlsFanger(ActualZoneNum);
    6345        2025 :         comfortControlType =
    6346        2025 :             static_cast<HVAC::ThermostatType>(ScheduleManager::GetCurrentScheduleValue(state, comfortControlledZone.ComfortSchedIndex));
    6347        2025 :         comfortControlTypeRpt = static_cast<int>(comfortControlType);
    6348             : 
    6349             :         // Get PMV values
    6350        2025 :         switch (comfortControlType) {
    6351        1185 :         case HVAC::ThermostatType::Uncontrolled:
    6352        1185 :             zoneComfortControlsFanger.LowPMV = -999.0;
    6353        1185 :             zoneComfortControlsFanger.HighPMV = -999.0;
    6354        1185 :             break;
    6355         210 :         case HVAC::ThermostatType::SingleHeating:
    6356         210 :             zoneComfortControlsFanger.FangerType = static_cast<int>(HVAC::ThermostatType::SingleHeating);
    6357         420 :             zoneComfortControlsFanger.LowPMV = ScheduleManager::GetCurrentScheduleValue(
    6358             :                 state,
    6359             :                 state.dataZoneTempPredictorCorrector
    6360         210 :                     ->SetPointSingleHeatingFanger(comfortControlledZone.ControlTypeSchIndx(comfortControlledZone.SchIndx_SingleHeating))
    6361             :                     .PMVSchedIndex);
    6362         210 :             zoneComfortControlsFanger.HighPMV = -999.0;
    6363         210 :             break;
    6364         210 :         case HVAC::ThermostatType::SingleCooling:
    6365         210 :             zoneComfortControlsFanger.FangerType = static_cast<int>(HVAC::ThermostatType::SingleCooling);
    6366         210 :             zoneComfortControlsFanger.LowPMV = -999.0;
    6367         420 :             zoneComfortControlsFanger.HighPMV = ScheduleManager::GetCurrentScheduleValue(
    6368             :                 state,
    6369             :                 state.dataZoneTempPredictorCorrector
    6370         210 :                     ->SetPointSingleCoolingFanger(comfortControlledZone.ControlTypeSchIndx(comfortControlledZone.SchIndx_SingleCooling))
    6371             :                     .PMVSchedIndex);
    6372         210 :             break;
    6373         210 :         case HVAC::ThermostatType::SingleHeatCool:
    6374         210 :             SetPointComfortSchedIndex =
    6375             :                 state.dataZoneTempPredictorCorrector
    6376         210 :                     ->SetPointSingleHeatCoolFanger(comfortControlledZone.ControlTypeSchIndx(comfortControlledZone.SchIndx_SingleHeatCool))
    6377             :                     .PMVSchedIndex;
    6378         210 :             zoneComfortControlsFanger.FangerType = static_cast<int>(HVAC::ThermostatType::SingleHeatCool);
    6379         210 :             zoneComfortControlsFanger.LowPMV = ScheduleManager::GetCurrentScheduleValue(state, SetPointComfortSchedIndex);
    6380         210 :             zoneComfortControlsFanger.HighPMV = ScheduleManager::GetCurrentScheduleValue(state, SetPointComfortSchedIndex);
    6381         210 :             break;
    6382         210 :         case HVAC::ThermostatType::DualSetPointWithDeadBand:
    6383         210 :             SchedTypeIndex = comfortControlledZone.ControlTypeSchIndx(comfortControlledZone.SchIndx_DualSetPointWithDeadBand);
    6384         210 :             zoneComfortControlsFanger.FangerType = static_cast<int>(HVAC::ThermostatType::DualSetPointWithDeadBand);
    6385         420 :             zoneComfortControlsFanger.LowPMV = ScheduleManager::GetCurrentScheduleValue(
    6386         210 :                 state, state.dataZoneTempPredictorCorrector->SetPointDualHeatCoolFanger(SchedTypeIndex).HeatPMVSchedIndex);
    6387         420 :             zoneComfortControlsFanger.HighPMV = ScheduleManager::GetCurrentScheduleValue(
    6388         210 :                 state, state.dataZoneTempPredictorCorrector->SetPointDualHeatCoolFanger(SchedTypeIndex).CoolPMVSchedIndex);
    6389         210 :             if (zoneComfortControlsFanger.LowPMV > zoneComfortControlsFanger.HighPMV) {
    6390           0 :                 ++zoneComfortControlsFanger.DualPMVErrCount;
    6391           0 :                 if (zoneComfortControlsFanger.DualPMVErrCount < 2) {
    6392           0 :                     ShowWarningError(state,
    6393           0 :                                      format("ThermostatSetpoint:ThermalComfort:Fanger:DualSetpoint: The heating PMV setpoint is above the "
    6394             :                                             "cooling PMV setpoint in {}",
    6395           0 :                                             state.dataZoneTempPredictorCorrector->SetPointDualHeatCoolFanger(SchedTypeIndex).Name));
    6396           0 :                     ShowContinueError(state, "The zone dual heating PMV setpoint is set to the dual cooling PMV setpoint.");
    6397           0 :                     ShowContinueErrorTimeStamp(state, "Occurrence info:");
    6398             :                 } else {
    6399           0 :                     ShowRecurringWarningErrorAtEnd(state,
    6400             :                                                    "The heating PMV setpoint is still above the cooling PMV setpoint",
    6401           0 :                                                    zoneComfortControlsFanger.DualPMVErrIndex,
    6402           0 :                                                    zoneComfortControlsFanger.LowPMV,
    6403           0 :                                                    zoneComfortControlsFanger.LowPMV);
    6404             :                 }
    6405           0 :                 zoneComfortControlsFanger.LowPMV = zoneComfortControlsFanger.HighPMV;
    6406             :             }
    6407         210 :             break;
    6408           0 :         default:
    6409           0 :             ShowSevereError(state,
    6410           0 :                             format("CalcZoneAirTempSetpoints: Illegal thermal control control type for Zone={}, Found value={}, in Schedule={}",
    6411           0 :                                    zone.Name,
    6412             :                                    comfortControlTypeRpt,
    6413           0 :                                    comfortControlledZone.ControlTypeSchedName));
    6414           0 :             break;
    6415             :         }
    6416             : 
    6417             :         // Check Average method
    6418        2025 :         switch (comfortControlledZone.AverageMethod) {
    6419        2025 :         case DataZoneControls::AverageMethod::NO:
    6420        2025 :             PeopleNum = comfortControlledZone.SpecificObjectNum;
    6421        2025 :             if (comfortControlType == HVAC::ThermostatType::SingleCooling) {
    6422         210 :                 GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, SetPointLo);
    6423             :             } else {
    6424        1815 :                 GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.LowPMV, SetPointLo);
    6425             :             }
    6426        2025 :             if (comfortControlType == HVAC::ThermostatType::DualSetPointWithDeadBand)
    6427         210 :                 GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, SetPointHi);
    6428        2025 :             break;
    6429           0 :         case DataZoneControls::AverageMethod::SPE:
    6430           0 :             PeopleNum = comfortControlledZone.SpecificObjectNum;
    6431           0 :             if (comfortControlType == HVAC::ThermostatType::SingleCooling) {
    6432           0 :                 GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, SetPointLo);
    6433             :             } else {
    6434           0 :                 GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.LowPMV, SetPointLo);
    6435             :             }
    6436           0 :             if (comfortControlType == HVAC::ThermostatType::DualSetPointWithDeadBand)
    6437           0 :                 GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, SetPointHi);
    6438           0 :             break;
    6439           0 :         case DataZoneControls::AverageMethod::OBJ:
    6440           0 :             SetPointLo = 0.0;
    6441           0 :             SetPointHi = 0.0;
    6442           0 :             for (int PeopleNum = 1; PeopleNum <= state.dataHeatBal->TotPeople; ++PeopleNum) {
    6443           0 :                 if (ActualZoneNum == state.dataHeatBal->People(PeopleNum).ZonePtr) {
    6444           0 :                     ++ObjectCount;
    6445           0 :                     GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.LowPMV, Tset);
    6446           0 :                     SetPointLo += Tset;
    6447           0 :                     if (comfortControlType == HVAC::ThermostatType::DualSetPointWithDeadBand) {
    6448           0 :                         GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, Tset);
    6449           0 :                         SetPointHi += Tset;
    6450             :                     }
    6451             :                 }
    6452             :             }
    6453           0 :             SetPointLo /= ObjectCount;
    6454           0 :             if (comfortControlType == HVAC::ThermostatType::DualSetPointWithDeadBand) SetPointHi /= ObjectCount;
    6455           0 :             break;
    6456           0 :         case DataZoneControls::AverageMethod::PEO:
    6457           0 :             SetPointLo = 0.0;
    6458           0 :             SetPointHi = 0.0;
    6459           0 :             for (int PeopleNum = 1; PeopleNum <= state.dataHeatBal->TotPeople; ++PeopleNum) {
    6460           0 :                 if (ActualZoneNum == state.dataHeatBal->People(PeopleNum).ZonePtr) {
    6461           0 :                     int NumberOccupants = state.dataHeatBal->People(PeopleNum).NumberOfPeople *
    6462           0 :                                           ScheduleManager::GetCurrentScheduleValue(state, state.dataHeatBal->People(PeopleNum).NumberOfPeoplePtr);
    6463           0 :                     PeopleCount += NumberOccupants;
    6464           0 :                     GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.LowPMV, Tset);
    6465           0 :                     SetPointLo += Tset * NumberOccupants;
    6466           0 :                     if (comfortControlType == HVAC::ThermostatType::DualSetPointWithDeadBand) {
    6467           0 :                         GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, Tset);
    6468           0 :                         SetPointHi += Tset * NumberOccupants;
    6469             :                     }
    6470             :                 }
    6471             :             }
    6472           0 :             if (PeopleCount > 0) {
    6473           0 :                 SetPointLo /= PeopleCount;
    6474           0 :                 if (comfortControlType == HVAC::ThermostatType::DualSetPointWithDeadBand) SetPointHi /= PeopleCount;
    6475             :             } else {
    6476           0 :                 if (comfortControlledZone.PeopleAverageErrIndex == 0) {
    6477           0 :                     ShowWarningMessage(state,
    6478           0 :                                        format("ZoneControl:Thermostat:ThermalComfort: The total number of people in Zone = {} is zero. The People "
    6479             :                                               "Average option is not used.",
    6480           0 :                                               zone.Name));
    6481           0 :                     ShowContinueError(state, "The Object Average option is used instead. Simulation continues .....");
    6482           0 :                     ShowContinueErrorTimeStamp(state, "Occurrence info:");
    6483             :                 }
    6484           0 :                 ShowRecurringWarningErrorAtEnd(state,
    6485           0 :                                                "ZoneControl:Thermostat:ThermalComfort: The total number of people in Zone = " + zone.Name +
    6486             :                                                    " is still zero. The People Average option is not used",
    6487           0 :                                                comfortControlledZone.PeopleAverageErrIndex,
    6488             :                                                PeopleCount,
    6489             :                                                PeopleCount);
    6490           0 :                 SetPointLo = 0.0;
    6491           0 :                 SetPointHi = 0.0;
    6492           0 :                 for (int PeopleNum = 1; PeopleNum <= state.dataHeatBal->TotPeople; ++PeopleNum) {
    6493           0 :                     if (ActualZoneNum == state.dataHeatBal->People(PeopleNum).ZonePtr) {
    6494           0 :                         ++ObjectCount;
    6495           0 :                         GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.LowPMV, Tset);
    6496           0 :                         SetPointLo += Tset;
    6497           0 :                         if (comfortControlType == HVAC::ThermostatType::DualSetPointWithDeadBand) {
    6498           0 :                             GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, Tset);
    6499           0 :                             SetPointHi += Tset;
    6500             :                         }
    6501             :                     }
    6502             :                 }
    6503           0 :                 SetPointLo /= ObjectCount;
    6504           0 :                 if (comfortControlType == HVAC::ThermostatType::DualSetPointWithDeadBand) SetPointHi /= ObjectCount;
    6505             :             }
    6506           0 :             break;
    6507           0 :         default:
    6508           0 :             break;
    6509             :         }
    6510             : 
    6511             :         // Assign setpoint
    6512        2025 :         switch (comfortControlType) {
    6513        1185 :         case HVAC::ThermostatType::Uncontrolled:
    6514        1185 :             switch (state.dataHeatBalFanSys->TempControlType(ActualZoneNum)) {
    6515         594 :             case HVAC::ThermostatType::SingleHeating:
    6516         594 :                 state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ActualZoneNum) = 0.0;
    6517         594 :                 break;
    6518         591 :             case HVAC::ThermostatType::SingleCooling:
    6519         591 :                 state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ActualZoneNum) = 0.0;
    6520         591 :                 break;
    6521           0 :             default:
    6522           0 :                 break;
    6523             :             }
    6524        1185 :             break;
    6525         210 :         case HVAC::ThermostatType::SingleHeating:
    6526         210 :             if (SetPointLo < comfortControlledZone.TdbMinSetPoint) {
    6527           0 :                 SetPointLo = comfortControlledZone.TdbMinSetPoint;
    6528           0 :                 if (comfortControlledZone.TdbMinErrIndex < 2) {
    6529           0 :                     ShowWarningMessage(state,
    6530           0 :                                        format("ThermostatSetpoint:ThermalComfort:Fanger:SingleHeating temperature is below the Minimum dry-bulb "
    6531             :                                               "temperature setpoint {}",
    6532           0 :                                               comfortControlledZone.Name));
    6533           0 :                     ShowContinueError(state, "The zone heating setpoint is set to the Minimum dry-bulb temperature setpoint");
    6534           0 :                     ShowContinueErrorTimeStamp(state, "Occurrence info:");
    6535             :                 }
    6536           0 :                 ShowRecurringWarningErrorAtEnd(state,
    6537             :                                                "ThermostatSetpoint:ThermalComfort:Fanger:SingleHeating temperature is still below the "
    6538             :                                                "Minimum dry-bulb temperature setpoint ...",
    6539           0 :                                                comfortControlledZone.TdbMinErrIndex,
    6540             :                                                SetPointLo,
    6541             :                                                SetPointLo);
    6542             :             }
    6543         210 :             tempZoneThermostatSetPoint = SetPointLo;
    6544         210 :             state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ActualZoneNum) = tempZoneThermostatSetPoint;
    6545         210 :             state.dataHeatBalFanSys->TempControlType(ActualZoneNum) = HVAC::ThermostatType::SingleHeating;
    6546         210 :             state.dataHeatBalFanSys->TempControlTypeRpt(ActualZoneNum) = static_cast<int>(state.dataHeatBalFanSys->TempControlType(ActualZoneNum));
    6547         210 :             break;
    6548         210 :         case HVAC::ThermostatType::SingleCooling:
    6549         210 :             if (SetPointLo > comfortControlledZone.TdbMaxSetPoint) {
    6550           0 :                 SetPointLo = comfortControlledZone.TdbMaxSetPoint;
    6551           0 :                 if (comfortControlledZone.TdbMaxErrIndex == 0) {
    6552           0 :                     ShowWarningMessage(state,
    6553           0 :                                        format("ThermostatSetpoint:ThermalComfort:Fanger:SingleCooling temperature is above the Maximum dry-bulb "
    6554             :                                               "temperature setpoint {}",
    6555           0 :                                               comfortControlledZone.Name));
    6556           0 :                     ShowContinueError(state, "The zone cooling setpoint is set to the Maximum dry-bulb temperature setpoint");
    6557           0 :                     ShowContinueErrorTimeStamp(state, "Occurrence info:");
    6558             :                 }
    6559           0 :                 ShowRecurringWarningErrorAtEnd(state,
    6560             :                                                "ThermostatSetpoint:ThermalComfort:Fanger:SingleCooling temperature is still above the "
    6561             :                                                "Maximum dry-bulb temperature setpoint ...",
    6562           0 :                                                comfortControlledZone.TdbMaxErrIndex,
    6563             :                                                SetPointLo,
    6564             :                                                SetPointLo);
    6565             :             }
    6566         210 :             tempZoneThermostatSetPoint = SetPointLo;
    6567         210 :             state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ActualZoneNum) = tempZoneThermostatSetPoint;
    6568         210 :             state.dataHeatBalFanSys->TempControlType(ActualZoneNum) = HVAC::ThermostatType::SingleCooling;
    6569         210 :             state.dataHeatBalFanSys->TempControlTypeRpt(ActualZoneNum) = static_cast<int>(state.dataHeatBalFanSys->TempControlType(ActualZoneNum));
    6570         210 :             break;
    6571         210 :         case HVAC::ThermostatType::SingleHeatCool:
    6572         210 :             if (comfortControlledZone.TdbMaxSetPoint == comfortControlledZone.TdbMinSetPoint) {
    6573           0 :                 SetPointLo = comfortControlledZone.TdbMaxSetPoint;
    6574             :             }
    6575         210 :             if (SetPointLo > comfortControlledZone.TdbMaxSetPoint) SetPointLo = comfortControlledZone.TdbMaxSetPoint;
    6576         210 :             if (SetPointLo < comfortControlledZone.TdbMinSetPoint) SetPointLo = comfortControlledZone.TdbMinSetPoint;
    6577         210 :             if (SetPointLo < comfortControlledZone.TdbMinSetPoint || SetPointLo > comfortControlledZone.TdbMaxSetPoint) {
    6578           0 :                 if (comfortControlledZone.TdbHCErrIndex == 0) {
    6579           0 :                     ShowWarningMessage(state,
    6580           0 :                                        format("ThermostatSetpoint:ThermalComfort:Fanger:SingleHeatingOrCooling temperature is above the Maximum or "
    6581             :                                               "below the Minimum dry-bulb temperature setpoint {}",
    6582           0 :                                               comfortControlledZone.Name));
    6583           0 :                     ShowContinueError(state,
    6584             :                                       "The zone setpoint is set to the Maximum dry-bulb temperature setpoint if above or the Minimum "
    6585             :                                       "dry-bulb temperature setpoint if below");
    6586           0 :                     ShowContinueErrorTimeStamp(state, "Occurrence info:");
    6587             :                 }
    6588           0 :                 ShowRecurringWarningErrorAtEnd(state,
    6589             :                                                "ThermostatSetpoint:ThermalComfort:Fanger:SingleHeatingOrCooling temperature is still beyond "
    6590             :                                                "the range between Maximum and Minimum dry-bulb temperature setpoint ...",
    6591           0 :                                                comfortControlledZone.TdbHCErrIndex,
    6592             :                                                SetPointLo,
    6593             :                                                SetPointLo);
    6594             :             }
    6595         210 :             tempZoneThermostatSetPoint = SetPointLo;
    6596         210 :             state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ActualZoneNum) = tempZoneThermostatSetPoint;
    6597         210 :             state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ActualZoneNum) = tempZoneThermostatSetPoint;
    6598         210 :             state.dataHeatBalFanSys->TempControlType(ActualZoneNum) = HVAC::ThermostatType::SingleHeatCool;
    6599         210 :             state.dataHeatBalFanSys->TempControlTypeRpt(ActualZoneNum) = static_cast<int>(state.dataHeatBalFanSys->TempControlType(ActualZoneNum));
    6600         210 :             break;
    6601         210 :         case HVAC::ThermostatType::DualSetPointWithDeadBand:
    6602         210 :             if (SetPointLo < comfortControlledZone.TdbMinSetPoint) {
    6603           0 :                 SetPointLo = comfortControlledZone.TdbMinSetPoint;
    6604             : 
    6605           0 :                 if (comfortControlledZone.TdbDualMinErrIndex == 0) {
    6606           0 :                     ShowWarningMessage(state,
    6607           0 :                                        format("ThermostatSetpoint:ThermalComfort:Fanger:DualSetpoint temperature is below the Minimum dry-bulb "
    6608             :                                               "temperature setpoint {}",
    6609           0 :                                               comfortControlledZone.Name));
    6610           0 :                     ShowContinueError(state, "The zone dual heating setpoint is set to the Minimum dry-bulb temperature setpoint");
    6611           0 :                     ShowContinueErrorTimeStamp(state, "Occurrence info:");
    6612             :                 }
    6613           0 :                 ShowRecurringWarningErrorAtEnd(state,
    6614             :                                                "ThermostatSetpoint:ThermalComfort:Fanger:DualSetpoint temperature is still below the Minimum "
    6615             :                                                "dry-bulb temperature setpoint ...",
    6616           0 :                                                comfortControlledZone.TdbDualMinErrIndex,
    6617             :                                                SetPointLo,
    6618             :                                                SetPointLo);
    6619             :             }
    6620         210 :             if (SetPointHi > comfortControlledZone.TdbMaxSetPoint) {
    6621           0 :                 SetPointHi = comfortControlledZone.TdbMaxSetPoint;
    6622           0 :                 if (comfortControlledZone.TdbDualMaxErrIndex == 0) {
    6623           0 :                     ShowWarningMessage(state,
    6624           0 :                                        format("ThermostatSetpoint:ThermalComfort:Fanger:DualSetpoint temperature is above the Maximum dry-bulb "
    6625             :                                               "temperature setpoint in zone = {}",
    6626           0 :                                               comfortControlledZone.Name));
    6627           0 :                     ShowContinueError(state, "The zone dual cooling setpoint is set to the Maximum dry-bulb temperature setpoint");
    6628           0 :                     ShowContinueErrorTimeStamp(state, "Occurrence info:");
    6629             :                 }
    6630           0 :                 ShowRecurringWarningErrorAtEnd(state,
    6631             :                                                "ThermostatSetpoint:ThermalComfort:Fanger:DualSetpoint temperature is still above the Maximum "
    6632             :                                                "dry-bulb temperature setpoint ...",
    6633           0 :                                                comfortControlledZone.TdbDualMaxErrIndex,
    6634             :                                                SetPointLo,
    6635             :                                                SetPointLo);
    6636             :             }
    6637             : 
    6638         210 :             state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ActualZoneNum) = SetPointLo;
    6639         210 :             state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ActualZoneNum) = SetPointHi;
    6640         210 :             state.dataHeatBalFanSys->TempControlType(ActualZoneNum) = HVAC::ThermostatType::DualSetPointWithDeadBand;
    6641         210 :             state.dataHeatBalFanSys->TempControlTypeRpt(ActualZoneNum) = static_cast<int>(state.dataHeatBalFanSys->TempControlType(ActualZoneNum));
    6642         210 :             break;
    6643           0 :         default:
    6644           0 :             ShowSevereError(state,
    6645           0 :                             format("CalcZoneAirComfortSetpoints: Illegal thermal control control type for Zone={}, Found value={}, in Schedule={}",
    6646           0 :                                    zone.Name,
    6647             :                                    comfortControlTypeRpt,
    6648           0 :                                    comfortControlledZone.ControlTypeSchedName));
    6649             :         }
    6650             :     }
    6651        2025 : }
    6652             : 
    6653        2235 : void GetComfortSetPoints(EnergyPlusData &state,
    6654             :                          int const PeopleNum,
    6655             :                          int const ComfortControlNum,
    6656             :                          Real64 const PMVSet,
    6657             :                          Real64 &Tset // drybulb setpoint temperature for a given PMV value
    6658             : )
    6659             : {
    6660             : 
    6661             :     // SUBROUTINE INFORMATION:
    6662             :     //       AUTHOR         Lixing Gu
    6663             :     //       DATE WRITTEN   May, 2006
    6664             :     // PURPOSE OF THIS SUBROUTINE:
    6665             :     // This routine sets what the thermal comfort setpoints for each controlled zone should be based on air temperature
    6666             :     // obtained from thermal comfort models. This is called each time step.
    6667             : 
    6668             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    6669             :     // 0 = Solution; 1 = Set to Min; 2 Set to Max
    6670             : 
    6671             :     // SUBROUTINE PARAMETER DEFINITIONS:
    6672        2235 :     Real64 constexpr Acc(0.001); // accuracy control for SolveRoot
    6673        2235 :     int constexpr MaxIter(500);  // iteration control for SolveRoot
    6674             : 
    6675             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    6676        2235 :     Real64 PMVResult = 0.0; // Calculated PMV value
    6677        2235 :     int SolFla = 0;         // feed back flag from SolveRoot
    6678             : 
    6679        2235 :     auto &comfortControlledZone = state.dataZoneCtrls->ComfortControlledZone(ComfortControlNum);
    6680        2235 :     Real64 Tmin = comfortControlledZone.TdbMinSetPoint;
    6681        2235 :     Real64 Tmax = comfortControlledZone.TdbMaxSetPoint;
    6682             : 
    6683        2235 :     ThermalComfort::CalcThermalComfortFanger(state, PeopleNum, Tmin, PMVResult);
    6684        2235 :     Real64 PMVMin = PMVResult;
    6685        2235 :     ThermalComfort::CalcThermalComfortFanger(state, PeopleNum, Tmax, PMVResult);
    6686        2235 :     Real64 PMVMax = PMVResult;
    6687        2235 :     if (PMVSet > PMVMin && PMVSet < PMVMax) {
    6688             : 
    6689       15843 :         auto f = [&state, PMVSet, PeopleNum](Real64 Tset) {
    6690        5281 :             Real64 PMVresult = 0.0; // resulting PMV values
    6691        5281 :             ThermalComfort::CalcThermalComfortFanger(state, PeopleNum, Tset, PMVresult);
    6692        5281 :             return (PMVSet - PMVresult);
    6693        1050 :         };
    6694             : 
    6695        1050 :         General::SolveRoot(state, Acc, MaxIter, SolFla, Tset, f, Tmin, Tmax);
    6696        1050 :         if (SolFla == -1) {
    6697           0 :             if (!state.dataGlobal->WarmupFlag) {
    6698           0 :                 ++state.dataZoneTempPredictorCorrector->IterLimitExceededNum1;
    6699           0 :                 if (state.dataZoneTempPredictorCorrector->IterLimitExceededNum1 == 1) {
    6700           0 :                     ShowWarningError(
    6701             :                         state,
    6702           0 :                         format("{}: Iteration limit exceeded calculating thermal comfort Fanger setpoint and non-converged setpoint is used",
    6703           0 :                                comfortControlledZone.Name));
    6704             :                 } else {
    6705           0 :                     ShowRecurringWarningErrorAtEnd(state,
    6706           0 :                                                    comfortControlledZone.Name + ":  Iteration limit exceeded calculating thermal comfort setpoint.",
    6707           0 :                                                    state.dataZoneTempPredictorCorrector->IterLimitErrIndex1,
    6708             :                                                    Tset,
    6709             :                                                    Tset);
    6710             :                 }
    6711             :             }
    6712        1050 :         } else if (SolFla == -2) {
    6713           0 :             if (!state.dataGlobal->WarmupFlag) {
    6714           0 :                 ++state.dataZoneTempPredictorCorrector->IterLimitExceededNum2;
    6715           0 :                 if (state.dataZoneTempPredictorCorrector->IterLimitExceededNum2 == 1) {
    6716           0 :                     ShowWarningError(
    6717             :                         state,
    6718           0 :                         format("{}: Solution is not found in calculating thermal comfort Fanger setpoint and the minimum setpoint is used",
    6719           0 :                                comfortControlledZone.Name));
    6720             :                 } else {
    6721           0 :                     ShowRecurringWarningErrorAtEnd(
    6722             :                         state,
    6723           0 :                         format("{}:  Solution is not found in  calculating thermal comfort Fanger setpoint.", comfortControlledZone.Name),
    6724           0 :                         state.dataZoneTempPredictorCorrector->IterLimitErrIndex2,
    6725             :                         Tset,
    6726             :                         Tset);
    6727             :                 }
    6728             :             }
    6729             :         }
    6730        2235 :     } else if (PMVSet < PMVMin) {
    6731        1185 :         Tset = Tmin;
    6732           0 :     } else if (PMVSet > PMVMax) {
    6733           0 :         Tset = Tmax;
    6734             :     }
    6735        2235 : }
    6736             : 
    6737    14921929 : void AdjustCoolingSetPointforTempAndHumidityControl(EnergyPlusData &state,
    6738             :                                                     int const TempControlledZoneID,
    6739             :                                                     int const ActualZoneNum // controlled zone actual zone number
    6740             : )
    6741             : {
    6742             :     // SUBROUTINE INFORMATION:
    6743             :     //       AUTHOR         Bereket A Nigusse, FSEC/UCF
    6744             :     //       DATE WRITTEN   Nov 2010
    6745             : 
    6746             :     // PURPOSE OF THIS SUBROUTINE:
    6747             :     //  This subroutine modifies the air cooling setpoint temperature to effect zone air Temperature and humidity control
    6748             :     //  Alter the zone air cooling setpoint if the zone air relative humidity value exceeds the the zone dehumidifying relative humidity setpoint.
    6749             : 
    6750    14921929 :     Real64 ZoneOvercoolRange = 0.0;
    6751    14921929 :     auto &tempControlledZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneID);
    6752             : 
    6753    14921929 :     if (!(state.dataZoneCtrls->AnyZoneTempAndHumidityControl)) return; // do nothing to setpoint
    6754        6639 :     if (!(tempControlledZone.ZoneOvercoolControl)) return;             // do nothing to setpoint
    6755             : 
    6756        6639 :     if (tempControlledZone.OvercoolCntrlModeScheduled) {
    6757           0 :         ZoneOvercoolRange = ScheduleManager::GetCurrentScheduleValue(state, tempControlledZone.ZoneOvercoolRangeSchedIndex);
    6758             :     } else {
    6759        6639 :         ZoneOvercoolRange = tempControlledZone.ZoneOvercoolConstRange;
    6760             :     }
    6761        6639 :     Real64 ZoneOvercoolControlRatio = tempControlledZone.ZoneOvercoolControlRatio;
    6762             : 
    6763             :     // For Dual Setpoint thermostat the overcool range is limited by the temperature difference between cooling and heating setpoints
    6764             :     Real64 MaxAllowedOvercoolRange =
    6765        6639 :         state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ActualZoneNum) - state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ActualZoneNum);
    6766        6639 :     if (MaxAllowedOvercoolRange > 0.0) {
    6767        6639 :         ZoneOvercoolRange = min(ZoneOvercoolRange, MaxAllowedOvercoolRange);
    6768             :     }
    6769             :     // Calculate difference between zone air relative humidity and the dehumidifying setpoint
    6770        6639 :     Real64 RelativeHumidityDiff = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ActualZoneNum).airRelHum -
    6771        6639 :                                   ScheduleManager::GetCurrentScheduleValue(state, tempControlledZone.DehumidifyingSchedIndex);
    6772        6639 :     if (RelativeHumidityDiff > 0.0 && ZoneOvercoolControlRatio > 0.0) {
    6773             :         // proportionally reset the cooling setpoint temperature downward (zone Overcool)
    6774        4906 :         ZoneOvercoolRange = min(ZoneOvercoolRange, RelativeHumidityDiff / ZoneOvercoolControlRatio);
    6775        4906 :         state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ActualZoneNum) -= ZoneOvercoolRange;
    6776             :     }
    6777             : }
    6778             : 
    6779     2804720 : void OverrideAirSetPointsforEMSCntrl(EnergyPlusData &state)
    6780             : {
    6781             : 
    6782             :     // SUBROUTINE INFORMATION:
    6783             :     //       AUTHOR         L. Gu
    6784             :     //       DATE WRITTEN   June 2017
    6785             : 
    6786             :     // PURPOSE OF THIS SUBROUTINE:
    6787             :     // This subroutine overrides the air temperature setpoint based on EMS
    6788             : 
    6789     2804720 :     auto &ZoneThermostatSetPointLo = state.dataHeatBalFanSys->ZoneThermostatSetPointLo;
    6790     2804720 :     auto &ZoneThermostatSetPointHi = state.dataHeatBalFanSys->ZoneThermostatSetPointHi;
    6791             : 
    6792    19716837 :     for (int Loop = 1; Loop <= state.dataZoneCtrls->NumTempControlledZones; ++Loop) {
    6793    16912117 :         auto &tempControlledZone = state.dataZoneCtrls->TempControlledZone(Loop);
    6794    16912117 :         if (tempControlledZone.EMSOverrideHeatingSetPointOn) {
    6795           0 :             int ZoneNum = tempControlledZone.ActualZoneNum;
    6796             : 
    6797           0 :             switch (state.dataHeatBalFanSys->TempControlType(ZoneNum)) {
    6798           0 :             case HVAC::ThermostatType::SingleHeating:
    6799           0 :                 state.dataHeatBalFanSys->TempZoneThermostatSetPoint(ZoneNum) = tempControlledZone.EMSOverrideHeatingSetPointValue;
    6800           0 :                 ZoneThermostatSetPointLo(ZoneNum) = tempControlledZone.EMSOverrideHeatingSetPointValue;
    6801           0 :                 break;
    6802           0 :             case HVAC::ThermostatType::SingleHeatCool:
    6803           0 :                 state.dataHeatBalFanSys->TempZoneThermostatSetPoint(ZoneNum) = tempControlledZone.EMSOverrideHeatingSetPointValue;
    6804           0 :                 ZoneThermostatSetPointLo(ZoneNum) = tempControlledZone.EMSOverrideHeatingSetPointValue;
    6805           0 :                 break;
    6806           0 :             case HVAC::ThermostatType::DualSetPointWithDeadBand:
    6807           0 :                 ZoneThermostatSetPointLo(ZoneNum) = tempControlledZone.EMSOverrideHeatingSetPointValue;
    6808           0 :                 break;
    6809           0 :             default:
    6810           0 :                 break;
    6811             :             }
    6812             :         }
    6813    16912117 :         if (tempControlledZone.EMSOverrideCoolingSetPointOn) {
    6814           0 :             int ZoneNum = tempControlledZone.ActualZoneNum;
    6815             : 
    6816           0 :             switch (state.dataHeatBalFanSys->TempControlType(ZoneNum)) {
    6817           0 :             case HVAC::ThermostatType::SingleCooling:
    6818           0 :                 state.dataHeatBalFanSys->TempZoneThermostatSetPoint(ZoneNum) = tempControlledZone.EMSOverrideCoolingSetPointValue;
    6819           0 :                 ZoneThermostatSetPointHi(ZoneNum) = tempControlledZone.EMSOverrideCoolingSetPointValue;
    6820           0 :                 break;
    6821           0 :             case HVAC::ThermostatType::SingleHeatCool:
    6822           0 :                 state.dataHeatBalFanSys->TempZoneThermostatSetPoint(ZoneNum) = tempControlledZone.EMSOverrideCoolingSetPointValue;
    6823           0 :                 ZoneThermostatSetPointHi(ZoneNum) = tempControlledZone.EMSOverrideCoolingSetPointValue;
    6824           0 :                 break;
    6825           0 :             case HVAC::ThermostatType::DualSetPointWithDeadBand:
    6826           0 :                 ZoneThermostatSetPointHi(ZoneNum) = tempControlledZone.EMSOverrideCoolingSetPointValue;
    6827           0 :                 break;
    6828           0 :             default:
    6829           0 :                 break;
    6830             :             }
    6831             :         }
    6832             :     }
    6833             : 
    6834     2806745 :     for (int Loop = 1; Loop <= state.dataZoneCtrls->NumComfortControlledZones; ++Loop) {
    6835        2025 :         auto &comfortControlledZone = state.dataZoneCtrls->ComfortControlledZone(Loop);
    6836        2025 :         if (comfortControlledZone.EMSOverrideHeatingSetPointOn) {
    6837           0 :             int ZoneNum = comfortControlledZone.ActualZoneNum;
    6838           0 :             switch (state.dataHeatBalFanSys->ComfortControlType(ZoneNum)) {
    6839           0 :             case HVAC::ThermostatType::SingleHeating:
    6840           0 :                 state.dataHeatBalFanSys->TempZoneThermostatSetPoint(ZoneNum) = comfortControlledZone.EMSOverrideHeatingSetPointValue;
    6841           0 :                 ZoneThermostatSetPointLo(ZoneNum) = comfortControlledZone.EMSOverrideHeatingSetPointValue;
    6842           0 :                 break;
    6843           0 :             case HVAC::ThermostatType::SingleHeatCool:
    6844           0 :                 state.dataHeatBalFanSys->TempZoneThermostatSetPoint(ZoneNum) = comfortControlledZone.EMSOverrideHeatingSetPointValue;
    6845           0 :                 ZoneThermostatSetPointLo(ZoneNum) = comfortControlledZone.EMSOverrideHeatingSetPointValue;
    6846           0 :                 break;
    6847           0 :             case HVAC::ThermostatType::DualSetPointWithDeadBand:
    6848           0 :                 ZoneThermostatSetPointLo(ZoneNum) = comfortControlledZone.EMSOverrideHeatingSetPointValue;
    6849           0 :                 break;
    6850           0 :             default:
    6851           0 :                 break;
    6852             :             }
    6853             :         }
    6854             : 
    6855        2025 :         if (comfortControlledZone.EMSOverrideCoolingSetPointOn) {
    6856           0 :             int ZoneNum = comfortControlledZone.ActualZoneNum;
    6857           0 :             switch (static_cast<HVAC::ThermostatType>(state.dataHeatBalFanSys->ComfortControlType(ZoneNum))) {
    6858           0 :             case HVAC::ThermostatType::SingleCooling:
    6859           0 :                 state.dataHeatBalFanSys->TempZoneThermostatSetPoint(ZoneNum) = comfortControlledZone.EMSOverrideCoolingSetPointValue;
    6860           0 :                 ZoneThermostatSetPointHi(ZoneNum) = comfortControlledZone.EMSOverrideCoolingSetPointValue;
    6861           0 :                 break;
    6862           0 :             case HVAC::ThermostatType::SingleHeatCool:
    6863           0 :                 state.dataHeatBalFanSys->TempZoneThermostatSetPoint(ZoneNum) = comfortControlledZone.EMSOverrideCoolingSetPointValue;
    6864           0 :                 ZoneThermostatSetPointHi(ZoneNum) = comfortControlledZone.EMSOverrideCoolingSetPointValue;
    6865           0 :                 break;
    6866           0 :             case HVAC::ThermostatType::DualSetPointWithDeadBand:
    6867           0 :                 ZoneThermostatSetPointHi(ZoneNum) = comfortControlledZone.EMSOverrideCoolingSetPointValue;
    6868           0 :                 break;
    6869           0 :             default:
    6870           0 :                 break;
    6871             :             }
    6872             :         }
    6873             :     }
    6874     2804720 : }
    6875             : 
    6876             : // add values to the LEED tabular report related to schedules used by the thermostat objects
    6877         794 : void FillPredefinedTableOnThermostatSetpoints(EnergyPlusData &state)
    6878             : {
    6879             :     // J.Glazer - Aug 2017
    6880             :     using namespace OutputReportPredefined;
    6881         794 :     std::vector<int> uniqSch;
    6882         794 :     uniqSch.reserve(
    6883         794 :         state.dataZoneTempPredictorCorrector->NumSingleTempHeatingControls + state.dataZoneTempPredictorCorrector->NumSingleTempCoolingControls +
    6884         794 :         state.dataZoneTempPredictorCorrector->NumSingleTempHeatCoolControls + state.dataZoneTempPredictorCorrector->NumDualTempHeatCoolControls * 2);
    6885             :     Real64 setPointAt11;
    6886             :     Real64 setPointAt23;
    6887             :     int numDays;
    6888         794 :     std::string monthAssumed;
    6889         794 :     std::string monthAssumed2;
    6890         794 :     constexpr int wednesday = 4;
    6891             : 
    6892        1248 :     for (int idx = 1; idx <= state.dataZoneTempPredictorCorrector->NumSingleTempHeatingControls; ++idx) {
    6893         454 :         auto &singleHtgSetpoint = state.dataZoneTempPredictorCorrector->SetPointSingleHeating(idx);
    6894         454 :         if (std::find(uniqSch.begin(), uniqSch.end(), singleHtgSetpoint.TempSchedIndex) == uniqSch.end()) {
    6895         445 :             uniqSch.emplace_back(singleHtgSetpoint.TempSchedIndex);
    6896         445 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtFirstObjUsed, singleHtgSetpoint.TempSchedName, singleHtgSetpoint.Name);
    6897             : 
    6898         445 :             std::tie(setPointAt11, numDays, monthAssumed) = temperatureAndCountInSch(state, singleHtgSetpoint.TempSchedIndex, false, wednesday, 11);
    6899         445 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWednesday, singleHtgSetpoint.TempSchedName, setPointAt11);
    6900         445 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWedCnt, singleHtgSetpoint.TempSchedName, numDays);
    6901             : 
    6902         445 :             std::tie(setPointAt23, numDays, monthAssumed) = temperatureAndCountInSch(state, singleHtgSetpoint.TempSchedIndex, false, wednesday, 23);
    6903         445 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWednesday, singleHtgSetpoint.TempSchedName, setPointAt23);
    6904         445 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWedCnt, singleHtgSetpoint.TempSchedName, numDays);
    6905             : 
    6906         445 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtMonthUsed, singleHtgSetpoint.TempSchedName, monthAssumed);
    6907             :         }
    6908             :     }
    6909        1242 :     for (int idx = 1; idx <= state.dataZoneTempPredictorCorrector->NumSingleTempCoolingControls; ++idx) {
    6910         448 :         auto &singleClgSetpoint = state.dataZoneTempPredictorCorrector->SetPointSingleCooling(idx);
    6911         448 :         if (std::find(uniqSch.begin(), uniqSch.end(), singleClgSetpoint.TempSchedIndex) == uniqSch.end()) {
    6912         434 :             uniqSch.emplace_back(singleClgSetpoint.TempSchedIndex);
    6913         434 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtFirstObjUsed, singleClgSetpoint.TempSchedName, singleClgSetpoint.Name);
    6914             : 
    6915         434 :             std::tie(setPointAt11, numDays, monthAssumed) = temperatureAndCountInSch(state, singleClgSetpoint.TempSchedIndex, true, wednesday, 11);
    6916         434 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWednesday, singleClgSetpoint.TempSchedName, setPointAt11);
    6917         434 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWedCnt, singleClgSetpoint.TempSchedName, numDays);
    6918             : 
    6919         434 :             std::tie(setPointAt23, numDays, monthAssumed) = temperatureAndCountInSch(state, singleClgSetpoint.TempSchedIndex, true, wednesday, 23);
    6920         434 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWednesday, singleClgSetpoint.TempSchedName, setPointAt23);
    6921         434 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWedCnt, singleClgSetpoint.TempSchedName, numDays);
    6922             : 
    6923         434 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtMonthUsed, singleClgSetpoint.TempSchedName, monthAssumed);
    6924             :         }
    6925             :     }
    6926         805 :     for (int idx = 1; idx <= state.dataZoneTempPredictorCorrector->NumSingleTempHeatCoolControls; ++idx) {
    6927          11 :         auto &singleHeatCoolSetpoint = state.dataZoneTempPredictorCorrector->SetPointSingleHeatCool(idx);
    6928          11 :         if (std::find(uniqSch.begin(), uniqSch.end(), singleHeatCoolSetpoint.TempSchedIndex) == uniqSch.end()) {
    6929          11 :             uniqSch.emplace_back(singleHeatCoolSetpoint.TempSchedIndex);
    6930          22 :             PreDefTableEntry(
    6931          11 :                 state, state.dataOutRptPredefined->pdChLeedSchStPtFirstObjUsed, singleHeatCoolSetpoint.TempSchedName, singleHeatCoolSetpoint.Name);
    6932             : 
    6933          11 :             std::string schNm = singleHeatCoolSetpoint.TempSchedName + " (summer)";
    6934          11 :             std::tie(setPointAt11, numDays, monthAssumed) =
    6935          22 :                 temperatureAndCountInSch(state, singleHeatCoolSetpoint.TempSchedIndex, true, wednesday, 11);
    6936          11 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWednesday, schNm, setPointAt11);
    6937          11 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWedCnt, schNm, numDays);
    6938             : 
    6939          11 :             std::tie(setPointAt23, numDays, monthAssumed) =
    6940          22 :                 temperatureAndCountInSch(state, singleHeatCoolSetpoint.TempSchedIndex, true, wednesday, 23);
    6941          11 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWednesday, schNm, setPointAt23);
    6942          11 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWedCnt, schNm, numDays);
    6943             : 
    6944          11 :             schNm = singleHeatCoolSetpoint.TempSchedName + " (winter)";
    6945          11 :             std::tie(setPointAt11, numDays, monthAssumed2) =
    6946          22 :                 temperatureAndCountInSch(state, singleHeatCoolSetpoint.TempSchedIndex, false, wednesday, 11);
    6947          11 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWednesday, schNm, setPointAt11);
    6948          11 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWedCnt, schNm, numDays);
    6949             : 
    6950          11 :             std::tie(setPointAt23, numDays, monthAssumed2) =
    6951          22 :                 temperatureAndCountInSch(state, singleHeatCoolSetpoint.TempSchedIndex, false, wednesday, 23);
    6952          11 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWednesday, schNm, setPointAt23);
    6953          11 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWedCnt, schNm, numDays);
    6954             : 
    6955          22 :             PreDefTableEntry(state,
    6956          11 :                              state.dataOutRptPredefined->pdChLeedSchStPtMonthUsed,
    6957             :                              singleHeatCoolSetpoint.TempSchedName,
    6958          22 :                              monthAssumed + " and " + monthAssumed2);
    6959          11 :         }
    6960             :     }
    6961        3247 :     for (int idx = 1; idx <= state.dataZoneTempPredictorCorrector->NumDualTempHeatCoolControls; ++idx) {
    6962        2453 :         auto &dualHeatCoolSetpoint = state.dataZoneTempPredictorCorrector->SetPointDualHeatCool(idx);
    6963        2453 :         if (std::find(uniqSch.begin(), uniqSch.end(), dualHeatCoolSetpoint.HeatTempSchedIndex) == uniqSch.end()) {
    6964         481 :             uniqSch.emplace_back(dualHeatCoolSetpoint.HeatTempSchedIndex);
    6965         962 :             PreDefTableEntry(state,
    6966         481 :                              state.dataOutRptPredefined->pdChLeedSchStPtFirstObjUsed,
    6967             :                              dualHeatCoolSetpoint.HeatTempSetptSchedName,
    6968             :                              dualHeatCoolSetpoint.Name);
    6969             : 
    6970         481 :             std::tie(setPointAt11, numDays, monthAssumed) =
    6971         962 :                 temperatureAndCountInSch(state, dualHeatCoolSetpoint.HeatTempSchedIndex, false, wednesday, 11);
    6972         962 :             PreDefTableEntry(
    6973         481 :                 state, state.dataOutRptPredefined->pdchLeedSchStPt11amWednesday, dualHeatCoolSetpoint.HeatTempSetptSchedName, setPointAt11);
    6974         481 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWedCnt, dualHeatCoolSetpoint.HeatTempSetptSchedName, numDays);
    6975             : 
    6976         481 :             std::tie(setPointAt23, numDays, monthAssumed) =
    6977         962 :                 temperatureAndCountInSch(state, dualHeatCoolSetpoint.HeatTempSchedIndex, false, wednesday, 23);
    6978         962 :             PreDefTableEntry(
    6979         481 :                 state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWednesday, dualHeatCoolSetpoint.HeatTempSetptSchedName, setPointAt23);
    6980         481 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWedCnt, dualHeatCoolSetpoint.HeatTempSetptSchedName, numDays);
    6981             : 
    6982         481 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtMonthUsed, dualHeatCoolSetpoint.HeatTempSetptSchedName, monthAssumed);
    6983             :         }
    6984        2453 :         if (std::find(uniqSch.begin(), uniqSch.end(), dualHeatCoolSetpoint.CoolTempSchedIndex) == uniqSch.end()) {
    6985         475 :             uniqSch.emplace_back(dualHeatCoolSetpoint.CoolTempSchedIndex);
    6986         950 :             PreDefTableEntry(state,
    6987         475 :                              state.dataOutRptPredefined->pdChLeedSchStPtFirstObjUsed,
    6988             :                              dualHeatCoolSetpoint.CoolTempSetptSchedName,
    6989             :                              dualHeatCoolSetpoint.Name);
    6990             : 
    6991         475 :             std::tie(setPointAt11, numDays, monthAssumed) =
    6992         950 :                 temperatureAndCountInSch(state, dualHeatCoolSetpoint.CoolTempSchedIndex, true, wednesday, 11);
    6993         950 :             PreDefTableEntry(
    6994         475 :                 state, state.dataOutRptPredefined->pdchLeedSchStPt11amWednesday, dualHeatCoolSetpoint.CoolTempSetptSchedName, setPointAt11);
    6995         475 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWedCnt, dualHeatCoolSetpoint.CoolTempSetptSchedName, numDays);
    6996             : 
    6997         475 :             std::tie(setPointAt23, numDays, monthAssumed) =
    6998         950 :                 temperatureAndCountInSch(state, dualHeatCoolSetpoint.CoolTempSchedIndex, true, wednesday, 23);
    6999         950 :             PreDefTableEntry(
    7000         475 :                 state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWednesday, dualHeatCoolSetpoint.CoolTempSetptSchedName, setPointAt23);
    7001         475 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWedCnt, dualHeatCoolSetpoint.CoolTempSetptSchedName, numDays);
    7002             : 
    7003         475 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtMonthUsed, dualHeatCoolSetpoint.CoolTempSetptSchedName, monthAssumed);
    7004             :         }
    7005             :     }
    7006         794 : }
    7007             : 
    7008             : // returns the temperature value from a schedule at a certain time for the first day of the week in either January or July
    7009             : std::tuple<Real64, int, std::string>
    7010        3714 : temperatureAndCountInSch(EnergyPlusData &state, int const scheduleIndex, bool const isSummer, int const dayOfWeek, int const hourOfDay)
    7011             : {
    7012             :     // J.Glazer - Aug 2017
    7013             : 
    7014             :     // determine month to use based on hemiphere and season
    7015             :     int monthToUse;
    7016        3714 :     if (isSummer) {
    7017        1840 :         if (state.dataEnvrn->Latitude > 0.) {
    7018        1840 :             monthToUse = 7; // July - summer in northern hemisphere
    7019             :         } else {
    7020           0 :             monthToUse = 1; // January - summer in southern hemisphere
    7021             :         }
    7022             :     } else {
    7023        1874 :         if (state.dataEnvrn->Latitude > 0.) {
    7024        1874 :             monthToUse = 1; // January - winter in northern hemisphere
    7025             :         } else {
    7026           0 :             monthToUse = 7; // July - winter in southern hemisphere
    7027             :         }
    7028             :     }
    7029        3714 :     std::string monthName;
    7030        3714 :     if (monthToUse == 1) {
    7031        1874 :         monthName = "January";
    7032             :     } else {
    7033        1840 :         monthName = "July";
    7034             :     }
    7035             : 
    7036        3714 :     int jdateSelect = General::nthDayOfWeekOfMonth(state, dayOfWeek, 1, monthToUse);
    7037             : 
    7038             :     // determine number of days in year
    7039             :     int DaysInYear;
    7040        3714 :     if (state.dataEnvrn->CurrentYearIsLeapYear) {
    7041           8 :         DaysInYear = 366;
    7042             :     } else {
    7043        3706 :         DaysInYear = 365;
    7044             :     }
    7045             : 
    7046             :     // should adjust date if lands on a holiday but for now assume that it does not
    7047             : 
    7048             :     // adjust time of day for daylight savings time
    7049        3714 :     int hourSelect = hourOfDay + state.dataWeather->DSTIndex(jdateSelect);
    7050             : 
    7051             :     // get the value at the selected time
    7052        3714 :     int constexpr firstTimeStep = 1;
    7053        3714 :     int weekSchIndexSelect = state.dataScheduleMgr->Schedule(scheduleIndex).WeekSchedulePointer(jdateSelect);
    7054        3714 :     int daySchIndexSelect = state.dataScheduleMgr->WeekSchedule(weekSchIndexSelect).DaySchedulePointer(dayOfWeek);
    7055        3714 :     Real64 valueAtSelectTime = state.dataScheduleMgr->DaySchedule(daySchIndexSelect).TSValue(firstTimeStep, hourSelect);
    7056        3714 :     int countOfSame = 0;
    7057             : 
    7058             :     // count the number of times with that same value
    7059     1359332 :     for (int jdateOfYear = 1; jdateOfYear <= DaysInYear; ++jdateOfYear) {
    7060     1355618 :         int wkSch = state.dataScheduleMgr->Schedule(scheduleIndex).WeekSchedulePointer(jdateOfYear);
    7061     1355618 :         if (wkSch == weekSchIndexSelect) { // if same week schedule can short circuit rest of testing and increment counter
    7062     1342790 :             ++countOfSame;
    7063             :         } else {
    7064       12828 :             int daySch = state.dataScheduleMgr->WeekSchedule(wkSch).DaySchedulePointer(dayOfWeek);
    7065       12828 :             if (daySch == daySchIndexSelect) { // if same day schedule can short circuit rest of testing and increment counter
    7066          12 :                 ++countOfSame;
    7067             :             } else {
    7068       12816 :                 Real64 valueAt = state.dataScheduleMgr->DaySchedule(daySch).TSValue(firstTimeStep, hourSelect);
    7069       12816 :                 if (valueAt == valueAtSelectTime) {
    7070        6250 :                     ++countOfSame;
    7071             :                 }
    7072             :             }
    7073             :         }
    7074             :     }
    7075             : 
    7076        7428 :     return std::make_tuple(valueAtSelectTime, countOfSame, monthName);
    7077        3714 : }
    7078             : 
    7079         794 : void FillPredefinedTableOnThermostatSchedules(EnergyPlusData &state)
    7080             : {
    7081             :     // add values to the System Summary tabular report related to schedules used by the thermostat objects
    7082             :     // J.Glazer - March 2024
    7083             :     using OutputReportPredefined::PreDefTableEntry;
    7084         794 :     auto &orp = state.dataOutRptPredefined;
    7085        4975 :     for (int idx = 1; idx <= state.dataZoneCtrls->NumTempControlledZones; ++idx) {
    7086        4181 :         auto &tcz = state.dataZoneCtrls->TempControlledZone(idx);
    7087        4181 :         PreDefTableEntry(state, orp->pdchStatName, tcz.ZoneName, tcz.Name);
    7088        4181 :         PreDefTableEntry(state, orp->pdchStatCtrlTypeSchd, tcz.ZoneName, tcz.ControlTypeSchedName);
    7089       10170 :         for (int ctInx = 1; ctInx <= tcz.NumControlTypes; ++ctInx) {
    7090        5989 :             PreDefTableEntry(state, orp->pdchStatSchdType1, tcz.ZoneName, HVAC::thermostatTypeNames[(int)tcz.ControlTypeEnum(ctInx)]);
    7091        5989 :             PreDefTableEntry(state, orp->pdchStatSchdTypeName1, tcz.ZoneName, tcz.ControlTypeName(1));
    7092        5989 :             switch (tcz.ControlTypeEnum(ctInx)) {
    7093        3662 :             case HVAC::ThermostatType::DualSetPointWithDeadBand:
    7094        7324 :                 PreDefTableEntry(
    7095       10986 :                     state, orp->pdchStatSchdHeatName, tcz.ZoneName, ScheduleManager::GetScheduleName(state, tcz.SchIndx_DualSetPointWDeadBandHeat));
    7096        7324 :                 PreDefTableEntry(
    7097       10986 :                     state, orp->pdchStatSchdCoolName, tcz.ZoneName, ScheduleManager::GetScheduleName(state, tcz.SchIndx_DualSetPointWDeadBandCool));
    7098        3662 :                 break;
    7099          25 :             case HVAC::ThermostatType::SingleHeatCool:
    7100          50 :                 PreDefTableEntry(
    7101          75 :                     state, orp->pdchStatSchdHeatName, tcz.ZoneName, ScheduleManager::GetScheduleName(state, tcz.SchIndx_SingleHeatCoolSetPoint));
    7102          50 :                 PreDefTableEntry(
    7103          75 :                     state, orp->pdchStatSchdCoolName, tcz.ZoneName, ScheduleManager::GetScheduleName(state, tcz.SchIndx_SingleHeatCoolSetPoint));
    7104          25 :                 break;
    7105        1144 :             case HVAC::ThermostatType::SingleCooling:
    7106        2288 :                 PreDefTableEntry(
    7107        3432 :                     state, orp->pdchStatSchdHeatName, tcz.ZoneName, ScheduleManager::GetScheduleName(state, tcz.SchIndx_SingleCoolSetPoint));
    7108        1144 :                 break;
    7109        1158 :             case HVAC::ThermostatType::SingleHeating:
    7110        2316 :                 PreDefTableEntry(
    7111        3474 :                     state, orp->pdchStatSchdCoolName, tcz.ZoneName, ScheduleManager::GetScheduleName(state, tcz.SchIndx_SingleHeatSetPoint));
    7112        1158 :                 break;
    7113             :             }
    7114             :         }
    7115             :     }
    7116         794 : }
    7117             : 
    7118    30004171 : void ZoneSpaceHeatBalanceData::updateTemperatures(EnergyPlusData &state,
    7119             :                                                   bool const ShortenTimeStepSys,
    7120             :                                                   bool const UseZoneTimeStepHistory,
    7121             :                                                   Real64 const PriorTimeStep,
    7122             :                                                   int const zoneNum,
    7123             :                                                   int const spaceNum)
    7124             : {
    7125    30004171 :     assert(zoneNum > 0);
    7126    30004171 :     if (ShortenTimeStepSys) {
    7127             :         // timestep has just shifted from full zone timestep to a new shorter system timestep
    7128             :         // throw away last updates in corrector and rewind for resimulating smaller timestep
    7129     2883026 :         if (spaceNum == 0) {
    7130     2874600 :             if (state.dataHeatBal->Zone(zoneNum).SystemZoneNodeNumber > 0) { // roll back result for zone air node,
    7131     2509240 :                 auto &zoneNode = state.dataLoopNodes->Node(state.dataHeatBal->Zone(zoneNum).SystemZoneNodeNumber);
    7132     2509240 :                 zoneNode.Temp = this->XMAT[0];
    7133     2509240 :                 state.dataHeatBalFanSys->TempTstatAir(zoneNum) = this->XMAT[0];
    7134     2509240 :                 zoneNode.HumRat = this->WPrevZoneTS[0];
    7135     2509240 :                 zoneNode.Enthalpy = Psychrometrics::PsyHFnTdbW(this->XMAT[0], this->WPrevZoneTS[0]);
    7136             :             }
    7137             :         } else {
    7138        8426 :             if (state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber > 0) { // roll back result for space air node,
    7139        7776 :                 auto &spaceNode = state.dataLoopNodes->Node(state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber);
    7140        7776 :                 spaceNode.Temp = this->XMAT[0];
    7141        7776 :                 state.dataHeatBalFanSys->TempTstatAir(zoneNum) = this->XMAT[0];
    7142        7776 :                 spaceNode.HumRat = this->WPrevZoneTS[0];
    7143        7776 :                 spaceNode.Enthalpy = Psychrometrics::PsyHFnTdbW(this->XMAT[0], this->WPrevZoneTS[0]);
    7144             :             }
    7145             :         }
    7146             : 
    7147     2883026 :         if (state.dataHVACGlobal->NumOfSysTimeSteps !=
    7148     2883026 :             state.dataHVACGlobal->NumOfSysTimeStepsLastZoneTimeStep) { // cannot reuse existing DS data, interpolate from zone time
    7149     1415180 :             Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    7150     1415180 :             this->MAT = DownInterpolate4HistoryValues(PriorTimeStep, TimeStepSys, this->XMAT, this->DSXMAT);
    7151     1415180 :             this->airHumRat = DownInterpolate4HistoryValues(PriorTimeStep, TimeStepSys, this->WPrevZoneTS, this->DSWPrevZoneTS);
    7152             : 
    7153     1415180 :             if (spaceNum == 0 && state.dataRoomAir->anyNonMixingRoomAirModel) {
    7154        8643 :                 if (state.dataRoomAir->IsZoneDispVent3Node(zoneNum) || state.dataRoomAir->IsZoneUFAD(zoneNum)) {
    7155             : 
    7156        2788 :                     state.dataRoomAir->MATFloor(zoneNum) = DownInterpolate4HistoryValues(
    7157        2788 :                         PriorTimeStep, TimeStepSys, state.dataRoomAir->XMATFloor(zoneNum), state.dataRoomAir->DSXMATFloor(zoneNum));
    7158        2788 :                     state.dataRoomAir->MATOC(zoneNum) = DownInterpolate4HistoryValues(
    7159        2788 :                         PriorTimeStep, TimeStepSys, state.dataRoomAir->XMATOC(zoneNum), state.dataRoomAir->DSXMATOC(zoneNum));
    7160        2788 :                     state.dataRoomAir->MATMX(zoneNum) = DownInterpolate4HistoryValues(
    7161        2788 :                         PriorTimeStep, TimeStepSys, state.dataRoomAir->XMATMX(zoneNum), state.dataRoomAir->DSXMATMX(zoneNum));
    7162             :                 }
    7163        8643 :                 if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
    7164        2219 :                     for (auto &afnNode : state.dataRoomAir->AFNZoneInfo(zoneNum).Node) {
    7165        1902 :                         afnNode.AirTemp = DownInterpolate4HistoryValues(PriorTimeStep, TimeStepSys, afnNode.AirTempX, afnNode.AirTempDSX);
    7166             : 
    7167        1902 :                         afnNode.HumRat = DownInterpolate4HistoryValues(PriorTimeStep, TimeStepSys, afnNode.HumRatX, afnNode.HumRatDSX);
    7168             :                     }
    7169             :                 }
    7170             :             }
    7171             :         } else { // reuse history data in DS terms from last zone time step to preserve information that would be lost
    7172             :                  // do nothing because DS history would have been pushed prior and should be ready
    7173             :         }
    7174             :     }
    7175             :     // now update the variables actually used in the balance equations.
    7176    30004171 :     if (UseZoneTimeStepHistory) {
    7177    19932378 :         this->ZTM = this->XMAT;
    7178    19932378 :         this->WPrevZoneTSTemp = this->WPrevZoneTS;
    7179             :     } else { // use down-stepped history
    7180    10071793 :         this->ZTM = this->DSXMAT;
    7181    10071793 :         this->WPrevZoneTSTemp = this->DSWPrevZoneTS;
    7182             :     }
    7183    30004171 : }
    7184             : 
    7185    30004171 : void ZoneSpaceHeatBalanceData::calcPredictedSystemLoad(EnergyPlusData &state, Real64 const RAFNFrac, int const zoneNum, int const spaceNum)
    7186             : {
    7187             :     // Calculate the predicted system load for a time step.
    7188             : 
    7189    30004171 :     assert(zoneNum > 0);
    7190    30004171 :     auto const &thisZone = state.dataHeatBal->Zone(zoneNum);
    7191    30004171 :     Real64 const thisTempZoneThermostatSetPoint = state.dataHeatBalFanSys->TempZoneThermostatSetPoint(zoneNum);
    7192    30004171 :     Real64 const thisZoneThermostatSetPointLo = state.dataHeatBalFanSys->ZoneThermostatSetPointLo(zoneNum);
    7193    30004171 :     Real64 const thisZoneThermostatSetPointHi = state.dataHeatBalFanSys->ZoneThermostatSetPointHi(zoneNum);
    7194             : 
    7195    30004171 :     bool thisDeadBandOrSetBack = false;
    7196    30004171 :     Real64 ZoneSetPoint = 0.0;
    7197    30004171 :     Real64 totalLoad = 0.0;
    7198    30004171 :     Real64 LoadToHeatingSetPoint = 0.0;
    7199    30004171 :     Real64 LoadToCoolingSetPoint = 0.0;
    7200             : 
    7201    30004171 :     int zoneNodeNum = thisZone.SystemZoneNodeNumber;
    7202    30004171 :     if (spaceNum > 0) {
    7203       86394 :         zoneNodeNum = state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber;
    7204             :     }
    7205             : 
    7206    30004171 :     switch (state.dataHeatBalFanSys->TempControlType(zoneNum)) {
    7207     4710335 :     case HVAC::ThermostatType::Uncontrolled:
    7208             :         // Uncontrolled Zone
    7209     4710335 :         LoadToHeatingSetPoint = 0.0;
    7210     4710335 :         LoadToCoolingSetPoint = 0.0;
    7211     4710335 :         totalLoad = 0.0;
    7212     4710335 :         break;
    7213     2280846 :     case HVAC::ThermostatType::SingleHeating:
    7214     2280846 :         switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    7215     2280846 :         case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    7216     2280846 :             LoadToHeatingSetPoint = (this->tempDepLoad * thisTempZoneThermostatSetPoint - this->tempIndLoad);
    7217     2280846 :             break;
    7218             :         }
    7219           0 :         case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    7220           0 :             if (this->tempDepLoad == 0.0) { // B=0
    7221           0 :                 LoadToHeatingSetPoint = this->AirPowerCap * (thisTempZoneThermostatSetPoint - this->T1) - this->tempIndLoad;
    7222             :             } else {
    7223           0 :                 Real64 const exp_700_TA(std::exp(min(700.0, -this->tempDepLoad / this->AirPowerCap)));
    7224           0 :                 LoadToHeatingSetPoint =
    7225           0 :                     this->tempDepLoad * (thisTempZoneThermostatSetPoint - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
    7226             :             }
    7227           0 :             break;
    7228             :         }
    7229           0 :         case DataHeatBalance::SolutionAlgo::EulerMethod: {
    7230           0 :             LoadToHeatingSetPoint = this->AirPowerCap * (thisTempZoneThermostatSetPoint - this->T1) +
    7231           0 :                                     this->tempDepLoad * (thisTempZoneThermostatSetPoint) - this->tempIndLoad;
    7232           0 :             break;
    7233             :         }
    7234           0 :         default: {
    7235           0 :             assert(false);
    7236             :         }
    7237             :         }
    7238     2280846 :         if (RAFNFrac > 0.0) LoadToHeatingSetPoint = LoadToHeatingSetPoint / RAFNFrac;
    7239     2280846 :         totalLoad = LoadToHeatingSetPoint;
    7240     2280846 :         ZoneSetPoint = thisTempZoneThermostatSetPoint;
    7241     2280846 :         LoadToCoolingSetPoint = LoadToHeatingSetPoint;
    7242             :         // for consistency with the other cases, use LE instead of LT and don't subtract 1.0 Watt as a way of pushing the zero load
    7243             :         // case over the threshold
    7244     2280846 :         if ((totalLoad) <= 0.0) thisDeadBandOrSetBack = true;
    7245             : 
    7246     2280846 :         break;
    7247     2738978 :     case HVAC::ThermostatType::SingleCooling:
    7248     2738978 :         switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    7249     2738978 :         case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    7250     2738978 :             LoadToCoolingSetPoint = this->tempDepLoad * thisTempZoneThermostatSetPoint - this->tempIndLoad;
    7251     2738978 :             break;
    7252             :         }
    7253           0 :         case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    7254           0 :             if (this->tempDepLoad == 0.0) { // B=0
    7255           0 :                 LoadToCoolingSetPoint = this->AirPowerCap * (thisTempZoneThermostatSetPoint - this->T1) - this->tempIndLoad;
    7256             :             } else {
    7257           0 :                 Real64 const exp_700_TA(std::exp(min(700.0, -this->tempDepLoad / this->AirPowerCap)));
    7258           0 :                 LoadToCoolingSetPoint =
    7259           0 :                     this->tempDepLoad * (thisTempZoneThermostatSetPoint - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
    7260             :             }
    7261           0 :             break;
    7262             :         }
    7263           0 :         case DataHeatBalance::SolutionAlgo::EulerMethod: {
    7264           0 :             LoadToCoolingSetPoint = this->AirPowerCap * (thisTempZoneThermostatSetPoint - this->T1) +
    7265           0 :                                     this->tempDepLoad * thisTempZoneThermostatSetPoint - this->tempIndLoad;
    7266           0 :             break;
    7267             :         }
    7268           0 :         default: {
    7269           0 :             assert(false);
    7270             :         }
    7271             :         }
    7272     2738978 :         if (RAFNFrac > 0.0) LoadToHeatingSetPoint = LoadToHeatingSetPoint / RAFNFrac;
    7273     2738978 :         if (thisZone.HasAdjustedReturnTempByITE && !(state.dataGlobal->BeginSimFlag)) {
    7274           0 :             LoadToCoolingSetPoint = this->tempDepLoad * thisZone.AdjustedReturnTempByITE - this->tempIndLoad;
    7275             :         }
    7276     2738978 :         totalLoad = LoadToCoolingSetPoint;
    7277     2738978 :         ZoneSetPoint = thisTempZoneThermostatSetPoint;
    7278     2738978 :         LoadToHeatingSetPoint = LoadToCoolingSetPoint;
    7279             :         // for consistency with the other cases, use GE instead of GT and don't add 1.0 Watt as a way of pushing the zero load
    7280             :         // case over the threshold
    7281     2738978 :         if ((totalLoad) >= 0.0) thisDeadBandOrSetBack = true;
    7282     2738978 :         break;
    7283       94330 :     case HVAC::ThermostatType::SingleHeatCool:
    7284       94330 :         switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    7285       94330 :         case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    7286       94330 :             LoadToHeatingSetPoint = (this->tempDepLoad * (thisTempZoneThermostatSetPoint) - this->tempIndLoad);
    7287       94330 :             LoadToCoolingSetPoint = (this->tempDepLoad * (thisTempZoneThermostatSetPoint) - this->tempIndLoad);
    7288       94330 :             break;
    7289             :         }
    7290           0 :         case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    7291           0 :             if (this->tempDepLoad == 0.0) { // B=0
    7292           0 :                 LoadToHeatingSetPoint = this->AirPowerCap * (thisTempZoneThermostatSetPoint - this->T1) - this->tempIndLoad;
    7293           0 :                 LoadToCoolingSetPoint = this->AirPowerCap * (thisTempZoneThermostatSetPoint - this->T1) - this->tempIndLoad;
    7294             :             } else {
    7295           0 :                 Real64 const exp_700_TA(std::exp(min(700.0, -this->tempDepLoad / this->AirPowerCap)));
    7296           0 :                 LoadToHeatingSetPoint =
    7297           0 :                     this->tempDepLoad * (thisTempZoneThermostatSetPoint - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
    7298           0 :                 LoadToCoolingSetPoint =
    7299           0 :                     this->tempDepLoad * (thisTempZoneThermostatSetPoint - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
    7300             :             }
    7301           0 :             break;
    7302             :         }
    7303           0 :         case DataHeatBalance::SolutionAlgo::EulerMethod: {
    7304           0 :             LoadToHeatingSetPoint = this->AirPowerCap * (thisTempZoneThermostatSetPoint - this->T1) +
    7305           0 :                                     this->tempDepLoad * thisTempZoneThermostatSetPoint - this->tempIndLoad;
    7306           0 :             LoadToCoolingSetPoint = this->AirPowerCap * (thisTempZoneThermostatSetPoint - this->T1) +
    7307           0 :                                     this->tempDepLoad * thisTempZoneThermostatSetPoint - this->tempIndLoad;
    7308           0 :             break;
    7309             :         }
    7310           0 :         default: {
    7311           0 :             assert(false);
    7312             :         }
    7313             :         }
    7314       94330 :         ZoneSetPoint = thisTempZoneThermostatSetPoint;
    7315       94330 :         if (RAFNFrac > 0.0) LoadToHeatingSetPoint = LoadToHeatingSetPoint / RAFNFrac;
    7316       94330 :         if (RAFNFrac > 0.0) LoadToCoolingSetPoint = LoadToCoolingSetPoint / RAFNFrac;
    7317             : 
    7318       94330 :         if (thisZone.HasAdjustedReturnTempByITE && !(state.dataGlobal->BeginSimFlag)) {
    7319           0 :             LoadToCoolingSetPoint = this->tempDepLoad * thisZone.AdjustedReturnTempByITE - this->tempIndLoad;
    7320             :         }
    7321             : 
    7322             :         // Note that LoadToHeatingSetPoint is generally not equal to LoadToCoolingSetPoint
    7323             :         // when the heating and cooling set-points are equal if the zone is unmixed,
    7324             :         // e.g. displacement ventilation or UFAD, since the stratification is generally not the same in heating and cooling modes
    7325             : 
    7326             :         // Possible combinations:
    7327             :         // 1/  LoadToHeatingSetPoint > 0 & LoadToCoolingSetPoint > 0 -->  Heating required
    7328             :         // 2/  LoadToHeatingSetPoint  >  LoadToCoolingSetPoint       -->  Possible in the unmixed case but should be trapped
    7329             :         //                                                                 as a poor choice of set-points
    7330             :         // 3/  LoadToHeatingSetPoint < 0 & LoadToCoolingSetPoint < 0 -->  Cooling Required
    7331             :         // 4/  LoadToHeatingSetPoint <=0 & LoadToCoolingSetPoint >=0 -->  Dead Band Operation ! includes zero load cases
    7332             :         // First trap bad set-points
    7333       94330 :         if (LoadToHeatingSetPoint > LoadToCoolingSetPoint) {
    7334           0 :             ShowSevereError(state,
    7335             :                             "HVAC::ThermostatType::SingleHeatCool: Effective heating set-point higher than effective cooling set-point - use "
    7336             :                             "DualSetPointWithDeadBand if using unmixed air model");
    7337           0 :             ShowContinueErrorTimeStamp(state, format("occurs in Zone={}", thisZone.Name));
    7338           0 :             ShowContinueError(state,
    7339           0 :                               format("LoadToHeatingSetPoint={:.3R}, LoadToCoolingSetPoint={:.3R}", LoadToHeatingSetPoint, LoadToCoolingSetPoint));
    7340           0 :             ShowContinueError(state, format("Zone TempDepZnLd={:.2R}", this->tempDepLoad));
    7341           0 :             ShowContinueError(state, format("Zone TempIndZnLd={:.2R}", this->tempIndLoad));
    7342           0 :             ShowContinueError(state, format("Zone ThermostatSetPoint={:.2R}", thisTempZoneThermostatSetPoint));
    7343           0 :             ShowFatalError(state, "Program terminates due to above conditions.");
    7344             :         }
    7345             : 
    7346       94330 :         if (LoadToHeatingSetPoint > 0.0 && LoadToCoolingSetPoint > 0.0) {
    7347       47377 :             totalLoad = LoadToHeatingSetPoint;
    7348       46953 :         } else if (LoadToHeatingSetPoint < 0.0 && LoadToCoolingSetPoint < 0.0) {
    7349       46953 :             totalLoad = LoadToCoolingSetPoint;
    7350           0 :         } else if (LoadToHeatingSetPoint <= 0.0 && LoadToCoolingSetPoint >= 0.0) { // deadband includes zero loads
    7351           0 :             totalLoad = 0.0;
    7352           0 :             if (zoneNodeNum > 0) {
    7353           0 :                 ZoneSetPoint = state.dataLoopNodes->Node(zoneNodeNum).Temp;
    7354           0 :                 ZoneSetPoint = max(ZoneSetPoint, thisZoneThermostatSetPointLo); // trap out of deadband
    7355           0 :                 ZoneSetPoint = min(ZoneSetPoint, thisZoneThermostatSetPointHi); // trap out of deadband
    7356             :             }
    7357           0 :             thisDeadBandOrSetBack = true;
    7358             :         } else { // this should never occur!
    7359           0 :             ShowSevereError(state,
    7360             :                             "SingleHeatCoolSetPoint: Unanticipated combination of heating and cooling loads - report to EnergyPlus Development Team");
    7361           0 :             ShowContinueErrorTimeStamp(state, format("occurs in Zone={}", thisZone.Name));
    7362           0 :             ShowContinueError(state,
    7363           0 :                               format("LoadToHeatingSetPoint={:.3R}, LoadToCoolingSetPoint={:.3R}", LoadToHeatingSetPoint, LoadToCoolingSetPoint));
    7364           0 :             ShowContinueError(state, format("Zone TempDepZnLd={:.2R}", this->tempDepLoad));
    7365           0 :             ShowContinueError(state, format("Zone TempIndZnLd={:.2R}", this->tempIndLoad));
    7366           0 :             ShowContinueError(state, format("Zone ThermostatSetPoint={:.2R}", thisTempZoneThermostatSetPoint));
    7367           0 :             ShowFatalError(state, "Program terminates due to above conditions.");
    7368             :         }
    7369       94330 :         break;
    7370    20179682 :     case HVAC::ThermostatType::DualSetPointWithDeadBand:
    7371    20179682 :         switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    7372     8652953 :         case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    7373     8652953 :             LoadToHeatingSetPoint = (this->tempDepLoad * (thisZoneThermostatSetPointLo) - this->tempIndLoad);
    7374     8652953 :             LoadToCoolingSetPoint = (this->tempDepLoad * (thisZoneThermostatSetPointHi) - this->tempIndLoad);
    7375     8652953 :             break;
    7376             :         }
    7377    11495127 :         case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    7378    11495127 :             if (this->tempDepLoad == 0.0) { // B=0
    7379           0 :                 LoadToHeatingSetPoint = this->AirPowerCap * (thisZoneThermostatSetPointLo - this->T1) - this->tempIndLoad;
    7380           0 :                 LoadToCoolingSetPoint = this->AirPowerCap * (thisZoneThermostatSetPointHi - this->T1) - this->tempIndLoad;
    7381             :             } else {
    7382    11495127 :                 Real64 const exp_700_TA(std::exp(min(700.0, -this->tempDepLoad / this->AirPowerCap)));
    7383    11495127 :                 LoadToHeatingSetPoint =
    7384    11495127 :                     this->tempDepLoad * (thisZoneThermostatSetPointLo - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
    7385    11495127 :                 LoadToCoolingSetPoint =
    7386    11495127 :                     this->tempDepLoad * (thisZoneThermostatSetPointHi - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
    7387             :             }
    7388    11495127 :             break;
    7389             :         }
    7390       31602 :         case DataHeatBalance::SolutionAlgo::EulerMethod: {
    7391       31602 :             LoadToHeatingSetPoint =
    7392       31602 :                 this->AirPowerCap * (thisZoneThermostatSetPointLo - this->T1) + this->tempDepLoad * thisZoneThermostatSetPointLo - this->tempIndLoad;
    7393       31602 :             LoadToCoolingSetPoint =
    7394       31602 :                 this->AirPowerCap * (thisZoneThermostatSetPointHi - this->T1) + this->tempDepLoad * thisZoneThermostatSetPointHi - this->tempIndLoad;
    7395       31602 :             break;
    7396             :         }
    7397           0 :         default: {
    7398           0 :             assert(false);
    7399             :         }
    7400             :         }
    7401    20179682 :         if (RAFNFrac > 0.0) LoadToHeatingSetPoint = LoadToHeatingSetPoint / RAFNFrac;
    7402    20179682 :         if (RAFNFrac > 0.0) LoadToCoolingSetPoint = LoadToCoolingSetPoint / RAFNFrac;
    7403             : 
    7404    20179682 :         if (thisZone.HasAdjustedReturnTempByITE && !(state.dataGlobal->BeginSimFlag)) {
    7405       11058 :             LoadToCoolingSetPoint = this->tempDepLoad * thisZone.AdjustedReturnTempByITE - this->tempIndLoad;
    7406             :         }
    7407             : 
    7408             :         // Possible combinations:
    7409             :         // 1/  LoadToHeatingSetPoint > 0 & LoadToCoolingSetPoint > 0 -->  Heating required
    7410             :         // 2/  LoadToHeatingSetPoint  >  LoadToCoolingSetPoint       -->  Possible in the unmixed case but should be trapped
    7411             :         //                                                                  as a poor choice of set-points
    7412             :         // 3/  LoadToHeatingSetPoint < 0 & LoadToCoolingSetPoint < 0 -->  Cooling Required
    7413             :         // 4/  LoadToHeatingSetPoint <=0 & LoadToCoolingSetPoint >=0 -->  Dead Band Operation - includes zero load cases
    7414             :         // First trap bad set-points
    7415    20179682 :         if (LoadToHeatingSetPoint > LoadToCoolingSetPoint) {
    7416           0 :             ShowSevereError(state,
    7417             :                             "DualSetPointWithDeadBand: Effective heating set-point higher than effective cooling set-point - increase "
    7418             :                             "deadband if using unmixed air model");
    7419           0 :             ShowContinueErrorTimeStamp(state, format("occurs in Zone={}", thisZone.Name));
    7420           0 :             ShowContinueError(state,
    7421           0 :                               format("LoadToHeatingSetPoint={:.3R}, LoadToCoolingSetPoint={:.3R}", LoadToHeatingSetPoint, LoadToCoolingSetPoint));
    7422           0 :             ShowContinueError(state, format("Zone TempDepZnLd={:.2R}", this->tempDepLoad));
    7423           0 :             ShowContinueError(state, format("Zone TempIndZnLd={:.2R}", this->tempIndLoad));
    7424           0 :             ShowContinueError(state, format("Zone Heating ThermostatSetPoint={:.2R}", thisZoneThermostatSetPointLo));
    7425           0 :             ShowContinueError(state, format("Zone Cooling ThermostatSetPoint={:.2R}", thisZoneThermostatSetPointHi));
    7426           0 :             ShowFatalError(state, "Program terminates due to above conditions.");
    7427             :         }
    7428             : 
    7429    20179682 :         if (LoadToHeatingSetPoint > 0.0 && LoadToCoolingSetPoint > 0.0) {
    7430     8415899 :             totalLoad = LoadToHeatingSetPoint;
    7431     8415899 :             ZoneSetPoint = thisZoneThermostatSetPointLo;
    7432    11763783 :         } else if (LoadToHeatingSetPoint < 0.0 && LoadToCoolingSetPoint < 0.0) {
    7433     7061912 :             totalLoad = LoadToCoolingSetPoint;
    7434     7061912 :             ZoneSetPoint = thisZoneThermostatSetPointHi;
    7435     4701871 :         } else if (LoadToHeatingSetPoint <= 0.0 && LoadToCoolingSetPoint >= 0.0) { // deadband includes zero loads
    7436             :             // this turns out to cause instabilities sometimes? that lead to setpoint errors if predictor is off.
    7437     4701871 :             totalLoad = 0.0;
    7438     4701871 :             if (zoneNodeNum > 0) {
    7439     4701871 :                 ZoneSetPoint = state.dataLoopNodes->Node(zoneNodeNum).Temp;
    7440     4701871 :                 ZoneSetPoint = max(ZoneSetPoint, thisZoneThermostatSetPointLo); // trap out of deadband
    7441     4701871 :                 ZoneSetPoint = min(ZoneSetPoint, thisZoneThermostatSetPointHi); // trap out of deadband
    7442             :             }
    7443     4701871 :             thisDeadBandOrSetBack = true;
    7444             :         } else { // this should never occur!
    7445           0 :             ShowSevereError(
    7446             :                 state, "DualSetPointWithDeadBand: Unanticipated combination of heating and cooling loads - report to EnergyPlus Development Team");
    7447           0 :             ShowContinueErrorTimeStamp(state, format("occurs in Zone={}", thisZone.Name));
    7448           0 :             ShowContinueError(state,
    7449           0 :                               format("LoadToHeatingSetPoint={:.3R}, LoadToCoolingSetPoint={:.3R}", LoadToHeatingSetPoint, LoadToCoolingSetPoint));
    7450           0 :             ShowContinueError(state, format("Zone Heating Set-point={:.2R}", thisZoneThermostatSetPointLo));
    7451           0 :             ShowContinueError(state, format("Zone Cooling Set-point={:.2R}", thisZoneThermostatSetPointHi));
    7452           0 :             ShowContinueError(state, format("Zone TempDepZnLd={:.2R}", this->tempDepLoad));
    7453           0 :             ShowContinueError(state, format("Zone TempIndZnLd={:.2R}", this->tempIndLoad));
    7454           0 :             ShowContinueError(state, format("Zone ThermostatSetPoint={:.2R}", thisTempZoneThermostatSetPoint));
    7455             : 
    7456           0 :             ShowFatalError(state, "Program terminates due to above conditions.");
    7457             :         }
    7458    20179682 :         break;
    7459           0 :     default:
    7460           0 :         break;
    7461             :     }
    7462             : 
    7463    30004171 :     int systemNodeNumber = 0;
    7464    30004171 :     int stageNum = 0;
    7465    30004171 :     if (spaceNum > 0) {
    7466       86394 :         systemNodeNumber = state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber;
    7467       86394 :         stageNum = state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).StageNum;
    7468       86394 :         assert(stageNum == state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).StageNum);
    7469             :     } else {
    7470    29917777 :         systemNodeNumber = thisZone.SystemZoneNodeNumber;
    7471    29917777 :         stageNum = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).StageNum;
    7472             :     }
    7473             :     // Staged control zone
    7474    30004171 :     if (state.dataZoneTempPredictorCorrector->NumStageCtrZone > 0) {
    7475      122502 :         if (state.dataZoneCtrls->StageZoneLogic(zoneNum)) {
    7476      100893 :             if (stageNum == 0) { // No load
    7477       44373 :                 LoadToHeatingSetPoint = 0.0;
    7478       44373 :                 LoadToCoolingSetPoint = 0.0;
    7479       44373 :                 totalLoad = 0.0;
    7480       44373 :                 if (systemNodeNumber > 0) {
    7481       44373 :                     ZoneSetPoint = state.dataLoopNodes->Node(systemNodeNumber).Temp;
    7482       44373 :                     ZoneSetPoint = max(ZoneSetPoint, thisZoneThermostatSetPointLo); // trap out of deadband
    7483       44373 :                     ZoneSetPoint = min(ZoneSetPoint, thisZoneThermostatSetPointHi); // trap out of deadband
    7484             :                 }
    7485       44373 :                 thisDeadBandOrSetBack = true;
    7486       56520 :             } else if (stageNum < 0) { // Cooling load
    7487       19407 :                 switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    7488       19407 :                 case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    7489       19407 :                     LoadToCoolingSetPoint = (this->tempDepLoad * (thisZoneThermostatSetPointHi) - this->tempIndLoad);
    7490       19407 :                     break;
    7491             :                 }
    7492           0 :                 case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    7493           0 :                     if (this->tempDepLoad == 0.0) { // B=0
    7494           0 :                         LoadToCoolingSetPoint = this->AirPowerCap * (thisZoneThermostatSetPointHi - this->T1) - this->tempIndLoad;
    7495             :                     } else {
    7496           0 :                         Real64 const exp_700_TA(std::exp(min(700.0, -this->tempDepLoad / this->AirPowerCap)));
    7497           0 :                         LoadToCoolingSetPoint =
    7498           0 :                             this->tempDepLoad * (thisZoneThermostatSetPointHi - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
    7499             :                     }
    7500           0 :                     break;
    7501             :                 }
    7502           0 :                 case DataHeatBalance::SolutionAlgo::EulerMethod: {
    7503           0 :                     LoadToCoolingSetPoint = this->AirPowerCap * (thisZoneThermostatSetPointHi - this->T1) +
    7504           0 :                                             this->tempDepLoad * thisZoneThermostatSetPointHi - this->tempIndLoad;
    7505           0 :                     break;
    7506             :                 }
    7507           0 :                 default: {
    7508           0 :                     assert(false);
    7509             :                 }
    7510             :                 }
    7511       19407 :                 totalLoad = LoadToCoolingSetPoint;
    7512       19407 :                 ZoneSetPoint = thisZoneThermostatSetPointHi;
    7513       19407 :                 LoadToHeatingSetPoint = LoadToCoolingSetPoint;
    7514       19407 :                 if ((totalLoad) >= 0.0) thisDeadBandOrSetBack = true;
    7515             :             } else { // Heating load
    7516       37113 :                 switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    7517       37113 :                 case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    7518       37113 :                     LoadToHeatingSetPoint = (this->tempDepLoad * thisZoneThermostatSetPointLo - this->tempIndLoad);
    7519       37113 :                     break;
    7520             :                 }
    7521           0 :                 case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    7522           0 :                     if (this->tempDepLoad == 0.0) { // B=0
    7523           0 :                         LoadToHeatingSetPoint = this->AirPowerCap * (thisZoneThermostatSetPointLo - this->T1) - this->tempIndLoad;
    7524             :                     } else {
    7525           0 :                         Real64 const exp_700_TA(std::exp(min(700.0, -this->tempDepLoad / this->AirPowerCap)));
    7526           0 :                         LoadToHeatingSetPoint =
    7527           0 :                             this->tempDepLoad * (thisZoneThermostatSetPointLo - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
    7528             :                     }
    7529           0 :                     break;
    7530             :                 }
    7531           0 :                 case DataHeatBalance::SolutionAlgo::EulerMethod: {
    7532           0 :                     LoadToHeatingSetPoint = this->AirPowerCap * (thisZoneThermostatSetPointLo - this->T1) +
    7533           0 :                                             this->tempDepLoad * (thisZoneThermostatSetPointLo) - this->tempIndLoad;
    7534           0 :                     break;
    7535             :                 }
    7536           0 :                 default: {
    7537           0 :                     assert(false);
    7538             :                 }
    7539             :                 }
    7540       37113 :                 totalLoad = LoadToHeatingSetPoint;
    7541       37113 :                 ZoneSetPoint = thisZoneThermostatSetPointLo;
    7542       37113 :                 LoadToCoolingSetPoint = LoadToHeatingSetPoint;
    7543       37113 :                 if ((totalLoad) <= 0.0) thisDeadBandOrSetBack = true;
    7544             :             }
    7545             :         }
    7546             :     }
    7547             : 
    7548             :     // If the ZoneNodeNum has been set for a Controlled Zone, then the zone setpoint is placed on the node.
    7549    30004171 :     if (zoneNodeNum > 0) {
    7550    26868270 :         state.dataLoopNodes->Node(zoneNodeNum).TempSetPoint = ZoneSetPoint;
    7551             :     }
    7552             : 
    7553    30004171 :     state.dataZoneEnergyDemand->Setback(zoneNum) = (ZoneSetPoint > this->setPointLast);
    7554             : 
    7555    30004171 :     this->setPointLast = ZoneSetPoint;
    7556    30004171 :     state.dataHeatBalFanSys->TempZoneThermostatSetPoint(zoneNum) = ZoneSetPoint; // needed to fix Issue # 5048
    7557    30004171 :     state.dataZoneEnergyDemand->DeadBandOrSetback(zoneNum) = thisDeadBandOrSetBack;
    7558    30004171 :     state.dataZoneEnergyDemand->CurDeadBandOrSetback(zoneNum) = thisDeadBandOrSetBack;
    7559             : 
    7560             :     // Apply the Zone Multiplier and Load Correction factor as needed
    7561    30004171 :     if (spaceNum > 0) {
    7562       86394 :         state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).reportSensibleLoadsZoneMultiplier(
    7563             :             state, zoneNum, totalLoad, LoadToHeatingSetPoint, LoadToCoolingSetPoint);
    7564             :     } else {
    7565    29917777 :         state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).reportSensibleLoadsZoneMultiplier(
    7566             :             state, zoneNum, totalLoad, LoadToHeatingSetPoint, LoadToCoolingSetPoint);
    7567             :     }
    7568    30004171 : }
    7569             : } // namespace EnergyPlus::ZoneTempPredictorCorrector

Generated by: LCOV version 1.14