LCOV - code coverage report
Current view: top level - EnergyPlus - ThermalComfort.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1399 1680 83.3 %
Date: 2023-01-17 19:17:23 Functions: 30 32 93.8 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <algorithm>
      50             : #include <boost/math/tools/roots.hpp>
      51             : #include <cassert>
      52             : #include <cmath>
      53             : 
      54             : // ObjexxFCL Headers
      55             : #include <ObjexxFCL/Fmath.hh>
      56             : #include <ObjexxFCL/string.functions.hh>
      57             : 
      58             : // EnergyPlus Headers
      59             : #include <EnergyPlus/Construction.hh>
      60             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      61             : #include <EnergyPlus/DataEnvironment.hh>
      62             : #include <EnergyPlus/DataHVACGlobals.hh>
      63             : #include <EnergyPlus/DataHeatBalFanSys.hh>
      64             : #include <EnergyPlus/DataHeatBalSurface.hh>
      65             : #include <EnergyPlus/DataHeatBalance.hh>
      66             : #include <EnergyPlus/DataIPShortCuts.hh>
      67             : #include <EnergyPlus/DataPrecisionGlobals.hh>
      68             : #include <EnergyPlus/DataRoomAirModel.hh>
      69             : #include <EnergyPlus/DataViewFactorInformation.hh>
      70             : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      71             : #include <EnergyPlus/FileSystem.hh>
      72             : #include <EnergyPlus/General.hh>
      73             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      74             : #include <EnergyPlus/OutputProcessor.hh>
      75             : #include <EnergyPlus/OutputReportPredefined.hh>
      76             : #include <EnergyPlus/OutputReportTabular.hh>
      77             : #include <EnergyPlus/Psychrometrics.hh>
      78             : #include <EnergyPlus/ScheduleManager.hh>
      79             : #include <EnergyPlus/ThermalComfort.hh>
      80             : #include <EnergyPlus/UtilityRoutines.hh>
      81             : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      82             : 
      83             : namespace EnergyPlus {
      84             : 
      85             : namespace ThermalComfort {
      86             : 
      87             :     // Module containing the routines dealing with the CalcThermalComfortFanger,
      88             :     // CalcThermalComfortPierce, and CalcThermalComfortKSU
      89             : 
      90             :     // MODULE INFORMATION:
      91             :     //       AUTHOR         Jaewook Lee
      92             :     //       DATE WRITTEN   January 2000
      93             :     //       MODIFIED       Rick Strand (for E+ implementation February 2000)
      94             : 
      95             :     // PURPOSE OF THIS MODULE:
      96             :     // To calculate thermal comfort indices based on the
      97             :     // three thermal comfort prediction models (Fanger, Pierce, KSU)
      98             : 
      99             :     // METHODOLOGY EMPLOYED:
     100             :     // For each thermal comfort model type, the subroutines will loop through
     101             :     // the people statements and perform the requested thermal comfort evaluations
     102             : 
     103             :     // Using/Aliasing
     104             :     using DataHeatBalance::PeopleData;
     105             :     using Psychrometrics::PsyRhFnTdbWPb;
     106             :     using ScheduleManager::GetCurrentScheduleValue;
     107             : 
     108     2568314 :     void ManageThermalComfort(EnergyPlusData &state, bool const InitializeOnly) // when called from ZTPC and calculations aren't needed
     109             :     {
     110             : 
     111             :         // SUBROUTINE INFORMATION:
     112             :         //     AUTHOR         Rick Strand
     113             :         //     DATE WRITTEN   February 2000
     114             : 
     115     2568314 :         if (state.dataThermalComforts->FirstTimeFlag) {
     116         771 :             InitThermalComfort(state); // Mainly sets up output stuff
     117         771 :             state.dataThermalComforts->FirstTimeFlag = false;
     118             :         }
     119             : 
     120     2568314 :         if (state.dataGlobal->DayOfSim == 1) {
     121      679130 :             if (state.dataGlobal->HourOfDay < 7) {
     122      174394 :                 state.dataThermalComforts->TemporarySixAMTemperature = 1.868132;
     123      504736 :             } else if (state.dataGlobal->HourOfDay == 7) {
     124       27836 :                 if (state.dataGlobal->TimeStep == 1) {
     125        5058 :                     state.dataThermalComforts->TemporarySixAMTemperature = state.dataEnvrn->OutDryBulbTemp;
     126             :                 }
     127             :             }
     128             :         } else {
     129     1889184 :             if (state.dataGlobal->HourOfDay == 7) {
     130       78716 :                 if (state.dataGlobal->TimeStep == 1) {
     131       14669 :                     state.dataThermalComforts->TemporarySixAMTemperature = state.dataEnvrn->OutDryBulbTemp;
     132             :                 }
     133             :             }
     134             :         }
     135             : 
     136     2568314 :         if (InitializeOnly) return;
     137             : 
     138     2568313 :         if (state.dataGlobal->BeginEnvrnFlag) {
     139        6218 :             state.dataThermalComforts->ZoneOccHrs = 0.0;
     140             :         }
     141             : 
     142     2568313 :         if (!state.dataGlobal->DoingSizing && !state.dataGlobal->WarmupFlag) {
     143      299088 :             CalcThermalComfortFanger(state);
     144      299088 :             if (state.dataHeatBal->AnyThermalComfortPierceModel) CalcThermalComfortPierceASHRAE(state);
     145      299088 :             if (state.dataHeatBal->AnyThermalComfortKSUModel) CalcThermalComfortKSU(state);
     146      299088 :             if (state.dataHeatBal->AnyThermalComfortCoolingEffectModel) CalcThermalComfortCoolingEffectASH(state);
     147      299088 :             if (state.dataHeatBal->AnyThermalComfortAnkleDraftModel) CalcThermalComfortAnkleDraftASH(state);
     148      299088 :             CalcThermalComfortSimpleASH55(state);
     149      299088 :             CalcIfSetPointMet(state);
     150      299088 :             if (state.dataHeatBal->AdaptiveComfortRequested_ASH55) CalcThermalComfortAdaptiveASH55(state, false);
     151      299088 :             if (state.dataHeatBal->AdaptiveComfortRequested_CEN15251) CalcThermalComfortAdaptiveCEN15251(state, false);
     152             :         }
     153             :     }
     154             : 
     155         771 :     void InitThermalComfort(EnergyPlusData &state)
     156             :     {
     157             : 
     158             :         // SUBROUTINE INFORMATION:
     159             :         //     AUTHOR         Rick Strand
     160             :         //     DATE WRITTEN   February 2000
     161             : 
     162             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     163             :         int Loop; // DO loop counter
     164        1542 :         std::string CurrentGroupName;
     165             : 
     166         771 :         state.dataThermalComforts->ThermalComfortData.allocate(state.dataHeatBal->TotPeople);
     167             : 
     168        4641 :         for (Loop = 1; Loop <= state.dataHeatBal->TotPeople; ++Loop) {
     169             : 
     170        3870 :             CurrentGroupName = state.dataHeatBal->People(Loop).Name;
     171             : 
     172             :             // CurrentModuleObject='People'
     173        3870 :             if (state.dataHeatBal->People(Loop).Fanger) {
     174        9752 :                 SetupOutputVariable(state,
     175             :                                     "Zone Thermal Comfort Fanger Model PMV",
     176             :                                     OutputProcessor::Unit::None,
     177        2438 :                                     state.dataThermalComforts->ThermalComfortData(Loop).FangerPMV,
     178             :                                     OutputProcessor::SOVTimeStepType::Zone,
     179             :                                     OutputProcessor::SOVStoreType::State,
     180        4876 :                                     state.dataHeatBal->People(Loop).Name);
     181        9752 :                 SetupOutputVariable(state,
     182             :                                     "Zone Thermal Comfort Fanger Model PPD",
     183             :                                     OutputProcessor::Unit::Perc,
     184        2438 :                                     state.dataThermalComforts->ThermalComfortData(Loop).FangerPPD,
     185             :                                     OutputProcessor::SOVTimeStepType::Zone,
     186             :                                     OutputProcessor::SOVStoreType::State,
     187        4876 :                                     state.dataHeatBal->People(Loop).Name);
     188        9752 :                 SetupOutputVariable(state,
     189             :                                     "Zone Thermal Comfort Clothing Surface Temperature",
     190             :                                     OutputProcessor::Unit::C,
     191        2438 :                                     state.dataThermalComforts->ThermalComfortData(Loop).CloSurfTemp,
     192             :                                     OutputProcessor::SOVTimeStepType::Zone,
     193             :                                     OutputProcessor::SOVStoreType::State,
     194        4876 :                                     state.dataHeatBal->People(Loop).Name);
     195             :             }
     196             : 
     197        3870 :             if (state.dataHeatBal->People(Loop).Pierce) {
     198          44 :                 SetupOutputVariable(state,
     199             :                                     "Zone Thermal Comfort Pierce Model Effective Temperature PMV",
     200             :                                     OutputProcessor::Unit::None,
     201          11 :                                     state.dataThermalComforts->ThermalComfortData(Loop).PiercePMVET,
     202             :                                     OutputProcessor::SOVTimeStepType::Zone,
     203             :                                     OutputProcessor::SOVStoreType::State,
     204          22 :                                     state.dataHeatBal->People(Loop).Name);
     205          44 :                 SetupOutputVariable(state,
     206             :                                     "Zone Thermal Comfort Pierce Model Standard Effective Temperature PMV",
     207             :                                     OutputProcessor::Unit::None,
     208          11 :                                     state.dataThermalComforts->ThermalComfortData(Loop).PiercePMVSET,
     209             :                                     OutputProcessor::SOVTimeStepType::Zone,
     210             :                                     OutputProcessor::SOVStoreType::State,
     211          22 :                                     state.dataHeatBal->People(Loop).Name);
     212          44 :                 SetupOutputVariable(state,
     213             :                                     "Zone Thermal Comfort Pierce Model Discomfort Index",
     214             :                                     OutputProcessor::Unit::None,
     215          11 :                                     state.dataThermalComforts->ThermalComfortData(Loop).PierceDISC,
     216             :                                     OutputProcessor::SOVTimeStepType::Zone,
     217             :                                     OutputProcessor::SOVStoreType::State,
     218          22 :                                     state.dataHeatBal->People(Loop).Name);
     219          44 :                 SetupOutputVariable(state,
     220             :                                     "Zone Thermal Comfort Pierce Model Thermal Sensation Index",
     221             :                                     OutputProcessor::Unit::None,
     222          11 :                                     state.dataThermalComforts->ThermalComfortData(Loop).PierceTSENS,
     223             :                                     OutputProcessor::SOVTimeStepType::Zone,
     224             :                                     OutputProcessor::SOVStoreType::State,
     225          22 :                                     state.dataHeatBal->People(Loop).Name);
     226          44 :                 SetupOutputVariable(state,
     227             :                                     "Zone Thermal Comfort Pierce Model Standard Effective Temperature",
     228             :                                     OutputProcessor::Unit::C,
     229          11 :                                     state.dataThermalComforts->ThermalComfortData(Loop).PierceSET,
     230             :                                     OutputProcessor::SOVTimeStepType::Zone,
     231             :                                     OutputProcessor::SOVStoreType::State,
     232          22 :                                     state.dataHeatBal->People(Loop).Name);
     233             :             }
     234             : 
     235        3870 :             if (state.dataHeatBal->People(Loop).KSU) {
     236          24 :                 SetupOutputVariable(state,
     237             :                                     "Zone Thermal Comfort KSU Model Thermal Sensation Vote",
     238             :                                     OutputProcessor::Unit::None,
     239           6 :                                     state.dataThermalComforts->ThermalComfortData(Loop).KsuTSV,
     240             :                                     OutputProcessor::SOVTimeStepType::Zone,
     241             :                                     OutputProcessor::SOVStoreType::State,
     242          12 :                                     state.dataHeatBal->People(Loop).Name);
     243             :             }
     244             : 
     245        3870 :             if ((state.dataHeatBal->People(Loop).Fanger) || (state.dataHeatBal->People(Loop).Pierce) || (state.dataHeatBal->People(Loop).KSU)) {
     246        9780 :                 SetupOutputVariable(state,
     247             :                                     "Zone Thermal Comfort Mean Radiant Temperature",
     248             :                                     OutputProcessor::Unit::C,
     249        2445 :                                     state.dataThermalComforts->ThermalComfortData(Loop).ThermalComfortMRT,
     250             :                                     OutputProcessor::SOVTimeStepType::Zone,
     251             :                                     OutputProcessor::SOVStoreType::State,
     252        4890 :                                     state.dataHeatBal->People(Loop).Name);
     253        9780 :                 SetupOutputVariable(state,
     254             :                                     "Zone Thermal Comfort Operative Temperature",
     255             :                                     OutputProcessor::Unit::C,
     256        2445 :                                     state.dataThermalComforts->ThermalComfortData(Loop).ThermalComfortOpTemp,
     257             :                                     OutputProcessor::SOVTimeStepType::Zone,
     258             :                                     OutputProcessor::SOVStoreType::State,
     259        4890 :                                     state.dataHeatBal->People(Loop).Name);
     260        9780 :                 SetupOutputVariable(state,
     261             :                                     "Zone Thermal Comfort Clothing Value",
     262             :                                     OutputProcessor::Unit::clo,
     263        2445 :                                     state.dataThermalComforts->ThermalComfortData(Loop).ClothingValue,
     264             :                                     OutputProcessor::SOVTimeStepType::Zone,
     265             :                                     OutputProcessor::SOVStoreType::State,
     266        4890 :                                     state.dataHeatBal->People(Loop).Name);
     267             :             }
     268             : 
     269        3870 :             if (state.dataHeatBal->People(Loop).AdaptiveASH55) {
     270          24 :                 SetupOutputVariable(state,
     271             :                                     "Zone Thermal Comfort ASHRAE 55 Adaptive Model 90% Acceptability Status",
     272             :                                     OutputProcessor::Unit::None,
     273           6 :                                     state.dataThermalComforts->ThermalComfortData(Loop).ThermalComfortAdaptiveASH5590,
     274             :                                     OutputProcessor::SOVTimeStepType::Zone,
     275             :                                     OutputProcessor::SOVStoreType::State,
     276          12 :                                     state.dataHeatBal->People(Loop).Name);
     277          24 :                 SetupOutputVariable(state,
     278             :                                     "Zone Thermal Comfort ASHRAE 55 Adaptive Model 80% Acceptability Status",
     279             :                                     OutputProcessor::Unit::None,
     280           6 :                                     state.dataThermalComforts->ThermalComfortData(Loop).ThermalComfortAdaptiveASH5580,
     281             :                                     OutputProcessor::SOVTimeStepType::Zone,
     282             :                                     OutputProcessor::SOVStoreType::State,
     283          12 :                                     state.dataHeatBal->People(Loop).Name);
     284          24 :                 SetupOutputVariable(state,
     285             :                                     "Zone Thermal Comfort ASHRAE 55 Adaptive Model Running Average Outdoor Air Temperature",
     286             :                                     OutputProcessor::Unit::C,
     287           6 :                                     state.dataThermalComforts->ThermalComfortData(Loop).ASHRAE55RunningMeanOutdoorTemp,
     288             :                                     OutputProcessor::SOVTimeStepType::Zone,
     289             :                                     OutputProcessor::SOVStoreType::State,
     290          12 :                                     state.dataHeatBal->People(Loop).Name);
     291          24 :                 SetupOutputVariable(state,
     292             :                                     "Zone Thermal Comfort ASHRAE 55 Adaptive Model Temperature",
     293             :                                     OutputProcessor::Unit::C,
     294           6 :                                     state.dataThermalComforts->ThermalComfortData(Loop).TComfASH55,
     295             :                                     OutputProcessor::SOVTimeStepType::Zone,
     296             :                                     OutputProcessor::SOVStoreType::State,
     297          12 :                                     state.dataHeatBal->People(Loop).Name);
     298             :             }
     299             : 
     300        3870 :             if (state.dataHeatBal->People(Loop).AdaptiveCEN15251) {
     301           4 :                 SetupOutputVariable(state,
     302             :                                     "Zone Thermal Comfort CEN 15251 Adaptive Model Category I Status",
     303             :                                     OutputProcessor::Unit::None,
     304           1 :                                     state.dataThermalComforts->ThermalComfortData(Loop).ThermalComfortAdaptiveCEN15251CatI,
     305             :                                     OutputProcessor::SOVTimeStepType::Zone,
     306             :                                     OutputProcessor::SOVStoreType::State,
     307           2 :                                     state.dataHeatBal->People(Loop).Name);
     308           4 :                 SetupOutputVariable(state,
     309             :                                     "Zone Thermal Comfort CEN 15251 Adaptive Model Category II Status",
     310             :                                     OutputProcessor::Unit::None,
     311           1 :                                     state.dataThermalComforts->ThermalComfortData(Loop).ThermalComfortAdaptiveCEN15251CatII,
     312             :                                     OutputProcessor::SOVTimeStepType::Zone,
     313             :                                     OutputProcessor::SOVStoreType::State,
     314           2 :                                     state.dataHeatBal->People(Loop).Name);
     315           4 :                 SetupOutputVariable(state,
     316             :                                     "Zone Thermal Comfort CEN 15251 Adaptive Model Category III Status",
     317             :                                     OutputProcessor::Unit::None,
     318           1 :                                     state.dataThermalComforts->ThermalComfortData(Loop).ThermalComfortAdaptiveCEN15251CatIII,
     319             :                                     OutputProcessor::SOVTimeStepType::Zone,
     320             :                                     OutputProcessor::SOVStoreType::State,
     321           2 :                                     state.dataHeatBal->People(Loop).Name);
     322           4 :                 SetupOutputVariable(state,
     323             :                                     "Zone Thermal Comfort CEN 15251 Adaptive Model Running Average Outdoor Air Temperature",
     324             :                                     OutputProcessor::Unit::C,
     325           1 :                                     state.dataThermalComforts->ThermalComfortData(Loop).CEN15251RunningMeanOutdoorTemp,
     326             :                                     OutputProcessor::SOVTimeStepType::Zone,
     327             :                                     OutputProcessor::SOVStoreType::State,
     328           2 :                                     state.dataHeatBal->People(Loop).Name);
     329           4 :                 SetupOutputVariable(state,
     330             :                                     "Zone Thermal Comfort CEN 15251 Adaptive Model Temperature",
     331             :                                     OutputProcessor::Unit::C,
     332           1 :                                     state.dataThermalComforts->ThermalComfortData(Loop).TComfCEN15251,
     333             :                                     OutputProcessor::SOVTimeStepType::Zone,
     334             :                                     OutputProcessor::SOVStoreType::State,
     335           2 :                                     state.dataHeatBal->People(Loop).Name);
     336             :             }
     337        3870 :             if (state.dataHeatBal->People(Loop).CoolingEffectASH55) {
     338           4 :                 SetupOutputVariable(state,
     339             :                                     "Zone Thermal Comfort ASHRAE 55 Elevated Air Speed Cooling Effect",
     340             :                                     OutputProcessor::Unit::C,
     341           1 :                                     state.dataThermalComforts->ThermalComfortData(Loop).CoolingEffectASH55,
     342             :                                     OutputProcessor::SOVTimeStepType::Zone,
     343             :                                     OutputProcessor::SOVStoreType::State,
     344           2 :                                     state.dataHeatBal->People(Loop).Name);
     345           4 :                 SetupOutputVariable(state,
     346             :                                     "Zone Thermal Comfort ASHRAE 55 Elevated Air Speed Cooling Effect Adjusted PMV",
     347             :                                     OutputProcessor::Unit::None,
     348           1 :                                     state.dataThermalComforts->ThermalComfortData(Loop).CoolingEffectAdjustedPMVASH55,
     349             :                                     OutputProcessor::SOVTimeStepType::Zone,
     350             :                                     OutputProcessor::SOVStoreType::State,
     351           2 :                                     state.dataHeatBal->People(Loop).Name);
     352           4 :                 SetupOutputVariable(state,
     353             :                                     "Zone Thermal Comfort ASHRAE 55 Elevated Air Speed Cooling Effect Adjusted PPD",
     354             :                                     OutputProcessor::Unit::None,
     355           1 :                                     state.dataThermalComforts->ThermalComfortData(Loop).CoolingEffectAdjustedPPDASH55,
     356             :                                     OutputProcessor::SOVTimeStepType::Zone,
     357             :                                     OutputProcessor::SOVStoreType::State,
     358           2 :                                     state.dataHeatBal->People(Loop).Name);
     359             :             }
     360        3870 :             if (state.dataHeatBal->People(Loop).AnkleDraftASH55) {
     361           4 :                 SetupOutputVariable(state,
     362             :                                     "Zone Thermal Comfort ASHRAE 55 Ankle Draft PPD",
     363             :                                     OutputProcessor::Unit::None,
     364           1 :                                     state.dataThermalComforts->ThermalComfortData(Loop).AnkleDraftPPDASH55,
     365             :                                     OutputProcessor::SOVTimeStepType::Zone,
     366             :                                     OutputProcessor::SOVStoreType::State,
     367           2 :                                     state.dataHeatBal->People(Loop).Name);
     368             :             }
     369             :         }
     370         771 :         state.dataThermalComforts->ThermalComfortInASH55.allocate(state.dataGlobal->NumOfZones);
     371             : 
     372             :         // ASHRAE 55 Warning. If any people statement for a zone is true, set that zone to true
     373        4641 :         for (Loop = 1; Loop <= state.dataHeatBal->TotPeople; ++Loop) {
     374        3870 :             if (state.dataHeatBal->People(Loop).Show55Warning) {
     375           0 :                 state.dataThermalComforts->ThermalComfortInASH55(state.dataHeatBal->People(Loop).ZonePtr).Enable55Warning = true;
     376             :             }
     377             :         }
     378             : 
     379             :         // CurrentModuleObject='Zone'
     380        5585 :         for (Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
     381       19256 :             SetupOutputVariable(state,
     382             :                                 "Zone Thermal Comfort ASHRAE 55 Simple Model Summer Clothes Not Comfortable Time",
     383             :                                 OutputProcessor::Unit::hr,
     384        4814 :                                 state.dataThermalComforts->ThermalComfortInASH55(Loop).timeNotSummer,
     385             :                                 OutputProcessor::SOVTimeStepType::Zone,
     386             :                                 OutputProcessor::SOVStoreType::Summed,
     387        9628 :                                 state.dataHeatBal->Zone(Loop).Name);
     388       19256 :             SetupOutputVariable(state,
     389             :                                 "Zone Thermal Comfort ASHRAE 55 Simple Model Winter Clothes Not Comfortable Time",
     390             :                                 OutputProcessor::Unit::hr,
     391        4814 :                                 state.dataThermalComforts->ThermalComfortInASH55(Loop).timeNotWinter,
     392             :                                 OutputProcessor::SOVTimeStepType::Zone,
     393             :                                 OutputProcessor::SOVStoreType::Summed,
     394        9628 :                                 state.dataHeatBal->Zone(Loop).Name);
     395       19256 :             SetupOutputVariable(state,
     396             :                                 "Zone Thermal Comfort ASHRAE 55 Simple Model Summer or Winter Clothes Not Comfortable Time",
     397             :                                 OutputProcessor::Unit::hr,
     398        4814 :                                 state.dataThermalComforts->ThermalComfortInASH55(Loop).timeNotEither,
     399             :                                 OutputProcessor::SOVTimeStepType::Zone,
     400             :                                 OutputProcessor::SOVStoreType::Summed,
     401        9628 :                                 state.dataHeatBal->Zone(Loop).Name);
     402             :         }
     403        2313 :         SetupOutputVariable(state,
     404             :                             "Facility Thermal Comfort ASHRAE 55 Simple Model Summer Clothes Not Comfortable Time",
     405             :                             OutputProcessor::Unit::hr,
     406         771 :                             state.dataThermalComforts->AnyZoneTimeNotSimpleASH55Summer,
     407             :                             OutputProcessor::SOVTimeStepType::Zone,
     408             :                             OutputProcessor::SOVStoreType::Summed,
     409        1542 :                             "Facility");
     410        2313 :         SetupOutputVariable(state,
     411             :                             "Facility Thermal Comfort ASHRAE 55 Simple Model Winter Clothes Not Comfortable Time",
     412             :                             OutputProcessor::Unit::hr,
     413         771 :                             state.dataThermalComforts->AnyZoneTimeNotSimpleASH55Winter,
     414             :                             OutputProcessor::SOVTimeStepType::Zone,
     415             :                             OutputProcessor::SOVStoreType::Summed,
     416        1542 :                             "Facility");
     417        2313 :         SetupOutputVariable(state,
     418             :                             "Facility Thermal Comfort ASHRAE 55 Simple Model Summer or Winter Clothes Not Comfortable Time",
     419             :                             OutputProcessor::Unit::hr,
     420         771 :                             state.dataThermalComforts->AnyZoneTimeNotSimpleASH55Either,
     421             :                             OutputProcessor::SOVTimeStepType::Zone,
     422             :                             OutputProcessor::SOVStoreType::Summed,
     423        1542 :                             "Facility");
     424             : 
     425         771 :         state.dataThermalComforts->ThermalComfortSetPoint.allocate(state.dataGlobal->NumOfZones);
     426        5585 :         for (Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
     427       19256 :             SetupOutputVariable(state,
     428             :                                 "Zone Heating Setpoint Not Met Time",
     429             :                                 OutputProcessor::Unit::hr,
     430        4814 :                                 state.dataThermalComforts->ThermalComfortSetPoint(Loop).notMetHeating,
     431             :                                 OutputProcessor::SOVTimeStepType::Zone,
     432             :                                 OutputProcessor::SOVStoreType::Summed,
     433        9628 :                                 state.dataHeatBal->Zone(Loop).Name);
     434       19256 :             SetupOutputVariable(state,
     435             :                                 "Zone Heating Setpoint Not Met While Occupied Time",
     436             :                                 OutputProcessor::Unit::hr,
     437        4814 :                                 state.dataThermalComforts->ThermalComfortSetPoint(Loop).notMetHeatingOccupied,
     438             :                                 OutputProcessor::SOVTimeStepType::Zone,
     439             :                                 OutputProcessor::SOVStoreType::Summed,
     440        9628 :                                 state.dataHeatBal->Zone(Loop).Name);
     441       19256 :             SetupOutputVariable(state,
     442             :                                 "Zone Cooling Setpoint Not Met Time",
     443             :                                 OutputProcessor::Unit::hr,
     444        4814 :                                 state.dataThermalComforts->ThermalComfortSetPoint(Loop).notMetCooling,
     445             :                                 OutputProcessor::SOVTimeStepType::Zone,
     446             :                                 OutputProcessor::SOVStoreType::Summed,
     447        9628 :                                 state.dataHeatBal->Zone(Loop).Name);
     448       19256 :             SetupOutputVariable(state,
     449             :                                 "Zone Cooling Setpoint Not Met While Occupied Time",
     450             :                                 OutputProcessor::Unit::hr,
     451        4814 :                                 state.dataThermalComforts->ThermalComfortSetPoint(Loop).notMetCoolingOccupied,
     452             :                                 OutputProcessor::SOVTimeStepType::Zone,
     453             :                                 OutputProcessor::SOVStoreType::Summed,
     454        9628 :                                 state.dataHeatBal->Zone(Loop).Name);
     455             :         }
     456             : 
     457        2313 :         SetupOutputVariable(state,
     458             :                             "Facility Heating Setpoint Not Met Time",
     459             :                             OutputProcessor::Unit::hr,
     460         771 :                             state.dataThermalComforts->AnyZoneNotMetHeating,
     461             :                             OutputProcessor::SOVTimeStepType::Zone,
     462             :                             OutputProcessor::SOVStoreType::Summed,
     463        1542 :                             "Facility");
     464        2313 :         SetupOutputVariable(state,
     465             :                             "Facility Cooling Setpoint Not Met Time",
     466             :                             OutputProcessor::Unit::hr,
     467         771 :                             state.dataThermalComforts->AnyZoneNotMetCooling,
     468             :                             OutputProcessor::SOVTimeStepType::Zone,
     469             :                             OutputProcessor::SOVStoreType::Summed,
     470        1542 :                             "Facility");
     471        2313 :         SetupOutputVariable(state,
     472             :                             "Facility Heating Setpoint Not Met While Occupied Time",
     473             :                             OutputProcessor::Unit::hr,
     474         771 :                             state.dataThermalComforts->AnyZoneNotMetHeatingOccupied,
     475             :                             OutputProcessor::SOVTimeStepType::Zone,
     476             :                             OutputProcessor::SOVStoreType::Summed,
     477        1542 :                             "Facility");
     478        2313 :         SetupOutputVariable(state,
     479             :                             "Facility Cooling Setpoint Not Met While Occupied Time",
     480             :                             OutputProcessor::Unit::hr,
     481         771 :                             state.dataThermalComforts->AnyZoneNotMetCoolingOccupied,
     482             :                             OutputProcessor::SOVTimeStepType::Zone,
     483             :                             OutputProcessor::SOVStoreType::Summed,
     484        1542 :                             "Facility");
     485             : 
     486         771 :         GetAngleFactorList(state);
     487             : 
     488         771 :         state.dataThermalComforts->ZoneOccHrs.dimension(state.dataGlobal->NumOfZones, 0.0);
     489         771 :     }
     490             : 
     491      308840 :     void CalcThermalComfortFanger(EnergyPlusData &state,
     492             :                                   Optional_int_const PNum,     // People number for thermal comfort control
     493             :                                   Optional<Real64 const> Tset, // Temperature setpoint for thermal comfort control
     494             :                                   Optional<Real64> PMVResult   // PMV value for thermal comfort control
     495             :     )
     496             :     {
     497             : 
     498             :         // SUBROUTINE INFORMATION:
     499             :         //     AUTHOR         Jaewook Lee
     500             :         //     DATE WRITTEN   January 2000
     501             :         //     MODIFIED       Rick Strand (for E+ implementation February 2000)
     502             :         //                    Brent Griffith modifications for CR 5641 (October 2005)
     503             :         //                    L. Gu, Added optional arguments for thermal comfort control (May 2006)
     504             :         //                    T. Hong, added Fanger PPD (April 2009)
     505             : 
     506             :         // PURPOSE OF THIS SUBROUTINE:
     507             :         // This subroutine calculates PMV(Predicted Mean Vote) using the Fanger thermal
     508             :         // comfort model. This subroutine is also used for thermal comfort control by determining
     509             :         // the temperature at which the PMV is equal to a PMV setpoint specified by the user.
     510             : 
     511             :         // METHODOLOGY EMPLOYED:
     512             :         // This subroutine is based heavily upon the work performed by Dan Maloney for
     513             :         // the BLAST program.  Many of the equations are based on the original Fanger
     514             :         // development.  See documentation for further details and references.
     515             : 
     516             :         // REFERENCES:
     517             :         // Maloney, Dan, M.S. Thesis, University of Illinois at Urbana-Champaign
     518             :         // BG note (10/21/2005),  This formulation is based on the the BASIC program
     519             :         // that is included in ASHRAE Standard 55 Normative Appendix D.
     520             : 
     521     1834208 :         for (state.dataThermalComforts->PeopleNum = 1; state.dataThermalComforts->PeopleNum <= state.dataHeatBal->TotPeople;
     522     1525368 :              ++state.dataThermalComforts->PeopleNum) {
     523             : 
     524             :             // Optional argument is used to access people object when thermal comfort control is used
     525     1525368 :             if (present(PNum)) {
     526      725464 :                 if (state.dataThermalComforts->PeopleNum != PNum) continue;
     527             :             }
     528             : 
     529             :             // If optional argument is used do not cycle regardless of thermal comfort reporting type
     530     1505864 :             if ((!state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).Fanger) && (!present(PNum))) continue;
     531             : 
     532      829160 :             state.dataThermalComforts->ZoneNum = state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ZonePtr;
     533      829160 :             auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataThermalComforts->ZoneNum);
     534      829160 :             if (present(PNum)) {
     535        9752 :                 state.dataThermalComforts->AirTemp = Tset;
     536             :             } else {
     537      819408 :                 state.dataThermalComforts->AirTemp = thisZoneHB.ZTAVComf;
     538             :             }
     539      829160 :             if (state.dataRoomAirMod->anyNonMixingRoomAirModel) {
     540        3168 :                 state.dataThermalComforts->ZoneNum = state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ZonePtr;
     541        6336 :                 if (state.dataRoomAirMod->IsZoneDV(state.dataThermalComforts->ZoneNum) ||
     542        3168 :                     state.dataRoomAirMod->IsZoneUI(state.dataThermalComforts->ZoneNum)) {
     543           0 :                     state.dataThermalComforts->AirTemp = state.dataRoomAirMod->TCMF(state.dataThermalComforts->ZoneNum); // PH 3/7/04
     544             :                     // UCSD-CV
     545        3168 :                 } else if (state.dataRoomAirMod->IsZoneCV(state.dataThermalComforts->ZoneNum)) {
     546           0 :                     if (state.dataRoomAirMod->ZoneUCSDCV(state.dataThermalComforts->ZoneNum).VforComfort == DataRoomAirModel::Comfort::Jet) {
     547           0 :                         state.dataThermalComforts->AirTemp = state.dataRoomAirMod->ZTJET(state.dataThermalComforts->ZoneNum);
     548           0 :                     } else if (state.dataRoomAirMod->ZoneUCSDCV(state.dataThermalComforts->ZoneNum).VforComfort ==
     549             :                                DataRoomAirModel::Comfort::Recirculation) {
     550           0 :                         state.dataThermalComforts->AirTemp = state.dataRoomAirMod->ZTJET(state.dataThermalComforts->ZoneNum);
     551             :                     }
     552             :                 }
     553             :             }
     554      829160 :             state.dataThermalComforts->RadTemp = CalcRadTemp(state, state.dataThermalComforts->PeopleNum);
     555             :             // Use mean air temp for calculating RH when thermal comfort control is used
     556      829160 :             if (present(PNum)) {
     557        9752 :                 state.dataThermalComforts->RelHum =
     558       29256 :                     PsyRhFnTdbWPb(state,
     559        9752 :                                   state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataThermalComforts->ZoneNum).MAT,
     560             :                                   thisZoneHB.ZoneAirHumRatAvgComf,
     561        9752 :                                   state.dataEnvrn->OutBaroPress);
     562             :             } else {
     563      819408 :                 state.dataThermalComforts->RelHum =
     564     1638816 :                     PsyRhFnTdbWPb(state, state.dataThermalComforts->AirTemp, thisZoneHB.ZoneAirHumRatAvgComf, state.dataEnvrn->OutBaroPress);
     565             :             }
     566      829160 :             state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).TemperatureInZone = state.dataThermalComforts->AirTemp;
     567      829160 :             state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).RelativeHumidityInZone = state.dataThermalComforts->RelHum * 100.0;
     568             : 
     569             :             // Metabolic rate of body (W/m2)
     570      829160 :             state.dataThermalComforts->ActLevel =
     571      829160 :                 GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ActivityLevelPtr) / BodySurfArea;
     572             :             // Energy consumption by external work (W/m2)
     573      829160 :             state.dataThermalComforts->WorkEff =
     574     1658320 :                 GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).WorkEffPtr) *
     575      829160 :                 state.dataThermalComforts->ActLevel;
     576             :             // Clothing unit
     577             :             Real64 IntermediateClothing;
     578      829160 :             switch (state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).clothingType) {
     579      829016 :             case DataHeatBalance::ClothingType::InsulationSchedule:
     580      829016 :                 state.dataThermalComforts->CloUnit =
     581      829016 :                     GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ClothingPtr);
     582      829016 :                 break;
     583          96 :             case DataHeatBalance::ClothingType::DynamicAshrae55:
     584          96 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortOpTemp =
     585          96 :                     (state.dataThermalComforts->RadTemp + state.dataThermalComforts->AirTemp) / 2.0;
     586          96 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue =
     587          96 :                     state.dataThermalComforts->CloUnit;
     588          96 :                 DynamicClothingModel(state);
     589          96 :                 state.dataThermalComforts->CloUnit =
     590          96 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue;
     591          96 :                 break;
     592          48 :             case DataHeatBalance::ClothingType::CalculationSchedule:
     593          48 :                 IntermediateClothing =
     594          48 :                     GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ClothingMethodPtr);
     595          48 :                 if (IntermediateClothing == 1.0) {
     596          12 :                     state.dataThermalComforts->CloUnit =
     597          12 :                         GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ClothingPtr);
     598          12 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue =
     599          12 :                         state.dataThermalComforts->CloUnit;
     600          36 :                 } else if (IntermediateClothing == 2.0) {
     601          36 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortOpTemp =
     602          36 :                         (state.dataThermalComforts->RadTemp + state.dataThermalComforts->AirTemp) / 2.0;
     603          36 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue =
     604          36 :                         state.dataThermalComforts->CloUnit;
     605          36 :                     DynamicClothingModel(state);
     606          36 :                     state.dataThermalComforts->CloUnit =
     607          36 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue;
     608             :                 } else {
     609           0 :                     state.dataThermalComforts->CloUnit =
     610           0 :                         GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ClothingPtr);
     611           0 :                     ShowWarningError(state,
     612           0 :                                      "PEOPLE=\"" + state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).Name +
     613             :                                          "\", Scheduled clothing value will be used rather than clothing calculation method.");
     614             :                 }
     615          48 :                 break;
     616           0 :             default:
     617           0 :                 ShowSevereError(state,
     618           0 :                                 "PEOPLE=\"" + state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).Name + "\", Incorrect Clothing Type");
     619             :             }
     620             : 
     621      829160 :             if (state.dataRoomAirMod->anyNonMixingRoomAirModel && state.dataRoomAirMod->IsZoneCV(state.dataThermalComforts->ZoneNum)) {
     622           0 :                 if (state.dataRoomAirMod->ZoneUCSDCV(state.dataThermalComforts->ZoneNum).VforComfort == DataRoomAirModel::Comfort::Jet) {
     623           0 :                     state.dataThermalComforts->AirVel = state.dataRoomAirMod->Ujet(state.dataThermalComforts->ZoneNum);
     624           0 :                 } else if (state.dataRoomAirMod->ZoneUCSDCV(state.dataThermalComforts->ZoneNum).VforComfort ==
     625             :                            DataRoomAirModel::Comfort::Recirculation) {
     626           0 :                     state.dataThermalComforts->AirVel = state.dataRoomAirMod->Urec(state.dataThermalComforts->ZoneNum);
     627             :                 } else {
     628           0 :                     state.dataThermalComforts->AirVel = 0.2;
     629             :                 }
     630             :             } else {
     631      829160 :                 state.dataThermalComforts->AirVel =
     632      829160 :                     GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).AirVelocityPtr);
     633             :                 // Ensure air velocity within the reasonable range. Otherwise reccusive warnings is provided
     634      829160 :                 if (present(PNum) && (state.dataThermalComforts->AirVel < 0.1 || state.dataThermalComforts->AirVel > 0.5)) {
     635           0 :                     if (state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).AirVelErrIndex == 0) {
     636           0 :                         ShowWarningMessage(state,
     637           0 :                                            "PEOPLE=\"" + state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).Name +
     638             :                                                "\", Air velocity is beyond the reasonable range (0.1,0.5) for thermal comfort control.");
     639           0 :                         ShowContinueErrorTimeStamp(state, "");
     640             :                     }
     641           0 :                     ShowRecurringWarningErrorAtEnd(state,
     642           0 :                                                    "PEOPLE=\"" + state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).Name +
     643             :                                                        "\",Air velocity is still beyond the reasonable range (0.1,0.5)",
     644           0 :                                                    state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).AirVelErrIndex,
     645           0 :                                                    state.dataThermalComforts->AirVel,
     646           0 :                                                    state.dataThermalComforts->AirVel,
     647             :                                                    _,
     648             :                                                    "[m/s]",
     649             :                                                    "[m/s]");
     650             :                 }
     651             :             }
     652             : 
     653     5804120 :             Real64 PMV = CalcFangerPMV(state,
     654      829160 :                                        state.dataThermalComforts->AirTemp,
     655      829160 :                                        state.dataThermalComforts->RadTemp,
     656      829160 :                                        state.dataThermalComforts->RelHum,
     657      829160 :                                        state.dataThermalComforts->AirVel,
     658      829160 :                                        state.dataThermalComforts->ActLevel,
     659      829160 :                                        state.dataThermalComforts->CloUnit,
     660     1658320 :                                        state.dataThermalComforts->WorkEff);
     661             : 
     662      829160 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).FangerPMV = PMV;
     663             : 
     664             :             // Pass resulting PMV based on temperature setpoint (Tset) when using thermal comfort control
     665      829160 :             if (present(PNum)) {
     666        9752 :                 PMVResult = PMV;
     667             :             }
     668      829160 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortMRT =
     669      829160 :                 state.dataThermalComforts->RadTemp;
     670      829160 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortOpTemp =
     671      829160 :                 (state.dataThermalComforts->RadTemp + state.dataThermalComforts->AirTemp) / 2.0;
     672      829160 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).CloSurfTemp = state.dataThermalComforts->CloSurfTemp;
     673             : 
     674             :             // Calculate the Fanger PPD (Predicted Percentage of Dissatisfied), as a %
     675      829160 :             Real64 PPD = CalcFangerPPD(PMV);
     676      829160 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).FangerPPD = PPD;
     677             :         }
     678      308840 :     }
     679             : 
     680      829640 :     Real64 CalcFangerPMV(
     681             :         EnergyPlusData &state, Real64 AirTemp, Real64 RadTemp, Real64 RelHum, Real64 AirVel, Real64 ActLevel, Real64 CloUnit, Real64 WorkEff)
     682             :     {
     683             : 
     684             :         // Using/Aliasing
     685             :         using Psychrometrics::PsyPsatFnTemp;
     686             : 
     687             :         // SUBROUTINE PARAMETER DEFINITIONS:
     688      829640 :         int constexpr MaxIter(150);             // Limit of iteration
     689      829640 :         Real64 constexpr StopIterCrit(0.00015); // Stop criteria for iteration
     690             : 
     691             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     692             :         Real64 P1;  // Intermediate variables to calculate clothed body ratio and clothing temperature
     693             :         Real64 P2;  // Intermediate variables to calculate clothed body ratio and clothing temperature
     694             :         Real64 P3;  // Intermediate variables to calculate clothed body ratio and clothing temperature
     695             :         Real64 P4;  // Intermediate variables to calculate clothed body ratio and clothing temperature
     696             :         Real64 XF;  // Intermediate variables to calculate clothed body ratio and clothing temperature
     697             :         Real64 XN;  // Intermediate variables to calculate clothed body ratio and clothing temperature
     698             :         Real64 PMV; // temporary variable to store calculated Fanger PMV value
     699             :         // VapPress    = CalcSatVapPressFromTemp(AirTemp)  !original
     700             :         // VapPress    = RelHum*VapPress                   !original might be in torrs
     701             : 
     702      829640 :         state.dataThermalComforts->VapPress = PsyPsatFnTemp(state, AirTemp); // use psych routines inside E+ , returns Pa
     703             : 
     704      829640 :         state.dataThermalComforts->VapPress *= RelHum; // in units of [Pa]
     705             : 
     706      829640 :         state.dataThermalComforts->IntHeatProd = ActLevel - WorkEff;
     707             : 
     708             :         // Compute the Corresponding Clothed Body Ratio
     709      829640 :         state.dataThermalComforts->CloBodyRat = 1.05 + 0.1 * CloUnit; // The ratio of the surface area of the clothed body
     710             :         // to the surface area of nude body
     711             : 
     712      829640 :         if (CloUnit < 0.5) state.dataThermalComforts->CloBodyRat = state.dataThermalComforts->CloBodyRat - 0.05 + 0.1 * CloUnit;
     713             : 
     714      829640 :         state.dataThermalComforts->AbsRadTemp = RadTemp + TAbsConv;
     715      829640 :         state.dataThermalComforts->AbsAirTemp = AirTemp + TAbsConv;
     716             : 
     717      829640 :         state.dataThermalComforts->CloInsul = CloUnit * state.dataThermalComforts->CloBodyRat * 0.155; // Thermal resistance of the clothing // icl
     718             : 
     719      829640 :         P2 = state.dataThermalComforts->CloInsul * 3.96;
     720      829640 :         P3 = state.dataThermalComforts->CloInsul * 100.0;
     721      829640 :         P1 = state.dataThermalComforts->CloInsul * state.dataThermalComforts->AbsAirTemp;                                        // p4
     722      829640 :         P4 = 308.7 - 0.028 * state.dataThermalComforts->IntHeatProd + P2 * pow_4(state.dataThermalComforts->AbsRadTemp / 100.0); // p5
     723             : 
     724             :         // First guess for clothed surface tempeature
     725      829640 :         state.dataThermalComforts->AbsCloSurfTemp = state.dataThermalComforts->AbsAirTemp + (35.5 - AirTemp) / (3.5 * (CloUnit + 0.1));
     726      829640 :         XN = state.dataThermalComforts->AbsCloSurfTemp / 100.0;
     727      829640 :         state.dataThermalComforts->HcFor = 12.1 * std::sqrt(AirVel); // Heat transfer coefficient by forced convection
     728      829640 :         state.dataThermalComforts->IterNum = 0;
     729      829640 :         XF = XN;
     730             : 
     731             :         // COMPUTE SURFACE TEMPERATURE OF CLOTHING BY ITERATIONS
     732     8874048 :         while (((std::abs(XN - XF) > StopIterCrit) || (state.dataThermalComforts->IterNum == 0)) && (state.dataThermalComforts->IterNum < MaxIter)) {
     733     4022204 :             XF = (XF + XN) / 2.0;
     734     4022204 :             state.dataThermalComforts->HcNat =
     735     4022204 :                 2.38 * root_4(std::abs(100.0 * XF - state.dataThermalComforts->AbsAirTemp)); // Heat transfer coefficient by natural convection
     736     4022204 :             state.dataThermalComforts->Hc =
     737     4022204 :                 max(state.dataThermalComforts->HcFor, state.dataThermalComforts->HcNat); // Determination of convective heat transfer coefficient
     738     4022204 :             XN = (P4 + P1 * state.dataThermalComforts->Hc - P2 * pow_4(XF)) / (100.0 + P3 * state.dataThermalComforts->Hc);
     739     4022204 :             ++state.dataThermalComforts->IterNum;
     740     4022204 :             if (state.dataThermalComforts->IterNum > MaxIter) {
     741           0 :                 ShowWarningError(state, "Max iteration exceeded in CalcThermalFanger");
     742             :             }
     743             :         }
     744      829640 :         state.dataThermalComforts->AbsCloSurfTemp = 100.0 * XN;
     745      829640 :         state.dataThermalComforts->CloSurfTemp = state.dataThermalComforts->AbsCloSurfTemp - TAbsConv;
     746             : 
     747             :         // COMPUTE PREDICTED MEAN VOTE
     748             :         // Sensible heat loss
     749             :         // RadHeatLoss = RadSurfEff*CloBodyRat*SkinEmiss*StefanBoltz* &   !original
     750             :         //                            (AbsCloSurfTemp**4 - AbsRadTemp**4) ! Heat loss by radiation
     751             : 
     752             :         // following line is ln 480 in ASHRAE 55 append. D
     753      829640 :         state.dataThermalComforts->RadHeatLoss =
     754     1659280 :             3.96 * state.dataThermalComforts->CloBodyRat *
     755      829640 :             (pow_4(state.dataThermalComforts->AbsCloSurfTemp * 0.01) - pow_4(state.dataThermalComforts->AbsRadTemp * 0.01));
     756             : 
     757     1659280 :         state.dataThermalComforts->ConvHeatLoss = state.dataThermalComforts->CloBodyRat * state.dataThermalComforts->Hc *
     758      829640 :                                                   (state.dataThermalComforts->CloSurfTemp - AirTemp); // Heat loss by convection
     759             : 
     760      829640 :         state.dataThermalComforts->DryHeatLoss = state.dataThermalComforts->RadHeatLoss + state.dataThermalComforts->ConvHeatLoss;
     761             : 
     762             :         // Evaporative heat loss
     763             :         // Heat loss by regulatory sweating
     764      829640 :         state.dataThermalComforts->EvapHeatLossRegComf = 0.0;
     765      829640 :         if (state.dataThermalComforts->IntHeatProd > 58.2) {
     766      829640 :             state.dataThermalComforts->EvapHeatLossRegComf = 0.42 * (state.dataThermalComforts->IntHeatProd - ActLevelConv);
     767             :         }
     768             :         // SkinTempComf = 35.7 - 0.028*IntHeatProd ! Skin temperature required to achieve thermal comfort
     769             :         // SatSkinVapPress = 1.92*SkinTempComf - 25.3 ! Water vapor pressure at required skin temperature
     770             :         // Heat loss by diffusion
     771             :         // EvapHeatLossDiff = 0.4148*(SatSkinVapPress - VapPress) !original
     772      829640 :         state.dataThermalComforts->EvapHeatLossDiff =
     773      829640 :             3.05 * 0.001 *
     774      829640 :             (5733.0 - 6.99 * state.dataThermalComforts->IntHeatProd - state.dataThermalComforts->VapPress); // ln 440 in ASHRAE 55 Append. D
     775             : 
     776      829640 :         state.dataThermalComforts->EvapHeatLoss = state.dataThermalComforts->EvapHeatLossRegComf + state.dataThermalComforts->EvapHeatLossDiff;
     777             :         // Heat loss by respiration
     778             :         // original: LatRespHeatLoss = 0.0023*ActLevel*(44. - VapPress) ! Heat loss by latent respiration
     779      829640 :         state.dataThermalComforts->LatRespHeatLoss =
     780      829640 :             1.7 * 0.00001 * ActLevel * (5867.0 - state.dataThermalComforts->VapPress); // ln 460 in ASHRAE 55 Append. D
     781             : 
     782             :         // LatRespHeatLoss = 0.017251*ActLevel*(5.8662 - VapPress)
     783             :         // V-1.2.2 'fix' BG 3/2005 5th term in LHS Eq (58)  in 2001 HOF Ch. 8
     784             :         // this was wrong because VapPress needed to be kPa
     785             : 
     786      829640 :         state.dataThermalComforts->DryRespHeatLoss = 0.0014 * ActLevel * (34.0 - AirTemp); // Heat loss by dry respiration.
     787             : 
     788      829640 :         state.dataThermalComforts->RespHeatLoss = state.dataThermalComforts->LatRespHeatLoss + state.dataThermalComforts->DryRespHeatLoss;
     789             : 
     790      829640 :         state.dataThermalComforts->ThermSensTransCoef = 0.303 * std::exp(-0.036 * ActLevel) + 0.028; // Thermal transfer coefficient to calculate PMV
     791             : 
     792     2488920 :         PMV = state.dataThermalComforts->ThermSensTransCoef * (state.dataThermalComforts->IntHeatProd - state.dataThermalComforts->EvapHeatLoss -
     793     1659280 :                                                                state.dataThermalComforts->RespHeatLoss - state.dataThermalComforts->DryHeatLoss);
     794             : 
     795      829640 :         return PMV;
     796             :     }
     797             : 
     798      829352 :     Real64 CalcFangerPPD(Real64 PMV)
     799             :     {
     800             :         Real64 PPD;
     801      829352 :         Real64 expTest1 = -0.03353 * pow_4(PMV) - 0.2179 * pow_2(PMV);
     802      829352 :         if (expTest1 > DataPrecisionGlobals::EXP_LowerLimit) {
     803      821659 :             PPD = 100.0 - 95.0 * std::exp(expTest1);
     804             :         } else {
     805        7693 :             PPD = 100.0;
     806             :         }
     807             : 
     808      829352 :         if (PPD < 0.0) {
     809           0 :             PPD = 0.0;
     810      829352 :         } else if (PPD > 100.0) {
     811           0 :             PPD = 100.0;
     812             :         }
     813      829352 :         return PPD;
     814             :     }
     815             : 
     816         384 :     Real64 CalcRelativeAirVelocity(Real64 AirVel, Real64 ActMet)
     817             :     {
     818         384 :         if (ActMet > 1) {
     819         384 :             return AirVel + 0.3 * (ActMet - 1);
     820             :         } else {
     821           0 :             return AirVel;
     822             :         }
     823             :     }
     824             : 
     825        2736 :     void GetThermalComfortInputsASHRAE(EnergyPlusData &state)
     826             :     {
     827        2736 :         state.dataThermalComforts->ZoneNum = state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ZonePtr;
     828        2736 :         auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataThermalComforts->ZoneNum);
     829             :         // (var TA)
     830        2736 :         state.dataThermalComforts->AirTemp = thisZoneHB.ZTAVComf;
     831        2736 :         if (state.dataRoomAirMod->anyNonMixingRoomAirModel) {
     832           0 :             if (state.dataRoomAirMod->IsZoneDV(state.dataThermalComforts->ZoneNum) ||
     833           0 :                 state.dataRoomAirMod->IsZoneUI(state.dataThermalComforts->ZoneNum)) {
     834           0 :                 state.dataThermalComforts->AirTemp = state.dataRoomAirMod->TCMF(state.dataThermalComforts->ZoneNum); // PH 3/7/04
     835             :             }
     836             :         }
     837             :         // (var TR)
     838        2736 :         state.dataThermalComforts->RadTemp = CalcRadTemp(state, state.dataThermalComforts->PeopleNum);
     839             :         // (var RH)
     840        2736 :         state.dataThermalComforts->RelHum =
     841        5472 :             PsyRhFnTdbWPb(state, state.dataThermalComforts->AirTemp, thisZoneHB.ZoneAirHumRatAvgComf, state.dataEnvrn->OutBaroPress);
     842             :         // Metabolic rate of body (W/m2) (var RM, M)
     843        2736 :         state.dataThermalComforts->ActLevel =
     844        2736 :             GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ActivityLevelPtr) / BodySurfAreaPierce;
     845             :         // Energy consumption by external work (W/m2) (var WME)
     846        2736 :         state.dataThermalComforts->WorkEff =
     847        5472 :             GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).WorkEffPtr) *
     848        2736 :             state.dataThermalComforts->ActLevel;
     849             : 
     850             :         // Clothing unit  (var CLO)
     851             :         Real64 IntermediateClothing;
     852        2736 :         switch (state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).clothingType) {
     853        2688 :         case DataHeatBalance::ClothingType::InsulationSchedule:
     854        2688 :             state.dataThermalComforts->CloUnit =
     855        2688 :                 GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ClothingPtr);
     856        2688 :             break;
     857          48 :         case DataHeatBalance::ClothingType::DynamicAshrae55:
     858          48 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortOpTemp =
     859          48 :                 (state.dataThermalComforts->RadTemp + state.dataThermalComforts->AirTemp) / 2.0;
     860          48 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue = state.dataThermalComforts->CloUnit;
     861          48 :             DynamicClothingModel(state);
     862          48 :             state.dataThermalComforts->CloUnit = state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue;
     863          48 :             break;
     864           0 :         case DataHeatBalance::ClothingType::CalculationSchedule:
     865           0 :             IntermediateClothing = GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ClothingMethodPtr);
     866           0 :             if (IntermediateClothing == 1.0) {
     867           0 :                 state.dataThermalComforts->CloUnit =
     868           0 :                     GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ClothingPtr);
     869           0 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue =
     870           0 :                     state.dataThermalComforts->CloUnit;
     871           0 :             } else if (IntermediateClothing == 2.0) {
     872           0 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortOpTemp =
     873           0 :                     (state.dataThermalComforts->RadTemp + state.dataThermalComforts->AirTemp) / 2.0;
     874           0 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue =
     875           0 :                     state.dataThermalComforts->CloUnit;
     876           0 :                 DynamicClothingModel(state);
     877           0 :                 state.dataThermalComforts->CloUnit =
     878           0 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue;
     879             :             } else {
     880           0 :                 state.dataThermalComforts->CloUnit =
     881           0 :                     GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ClothingPtr);
     882           0 :                 ShowWarningError(state, "Scheduled clothing value will be used rather than clothing calculation method.");
     883             :             }
     884           0 :             break;
     885           0 :         default:
     886           0 :             ShowSevereError(state, "Incorrect Clothing Type");
     887             :         }
     888             :         // (var VEL)
     889        2736 :         state.dataThermalComforts->AirVel =
     890        2736 :             GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).AirVelocityPtr);
     891             :         // (var MET)
     892        2736 :         state.dataThermalComforts->ActMet = state.dataThermalComforts->ActLevel / ActLevelConv;
     893        2736 :     }
     894             : 
     895        5424 :     Real64 CalcStandardEffectiveTemp(
     896             :         EnergyPlusData &state, Real64 AirTemp, Real64 RadTemp, Real64 RelHum, Real64 AirVel, Real64 ActMet, Real64 CloUnit, Real64 WorkEff)
     897             :     {
     898             : 
     899             :         // Thermal const
     900        5424 :         constexpr Real64 CloFac(0.25);                  // Clothing factor determined experimentally (var KCLO)
     901        5424 :         constexpr Real64 BodyWeight(69.9);              // (var BODYWEIGHT)
     902        5424 :         constexpr Real64 SweatContConst(170.0);         // Proportionality constant for sweat control; g/m2.hr (var CSW)
     903        5424 :         constexpr Real64 DriCoeffVasodilation(120);     // driving coefficient for vasodilation (var CDIL)
     904        5424 :         constexpr Real64 DriCoeffVasoconstriction(0.5); // (var CSTR)
     905        5424 :         constexpr Real64 MaxSkinBloodFlow(90.0);        // Max. value of skin blood flow
     906        5424 :         constexpr Real64 MinSkinBloodFlow(0.5);         // Min. value of skin blood flow
     907        5424 :         constexpr Real64 RegSweatMax(500);              // Max. value of regulatory sweating; w/m2
     908             : 
     909             :         // Standard condition const
     910             :         // Definition of vascular control signals CoreTempSet, SkinTempSet, and AvgBodyTempSet are the setpoints for core, skin and
     911             :         // average body temperatures corresponding to physiol.  neutrality SkinMassRatSet is the ratio of skin mass to total body mass (skin+core)
     912             :         // Typical values for CoreTempSet, SkinTempSet and SkinMassRatSet are 36.8, 33.7 and 0.10 SkinMassRat is the actual skin to total body mass
     913             :         // ratio
     914        5424 :         constexpr Real64 SkinTempSet(33.7);     // (var TempSkinNeutral)
     915        5424 :         constexpr Real64 CoreTempSet(36.8);     // (var TempCoreNeutral)
     916        5424 :         constexpr Real64 SkinBloodFlowSet(6.3); // (var SkinBloodFlowNeutral)
     917        5424 :         constexpr Real64 SkinMassRatSet(0.1);   // (var ALFA)
     918             : 
     919        5424 :         if (AirVel < 0.1) AirVel = 0.1;
     920             : 
     921             :         // (var VaporPressure)
     922        5424 :         state.dataThermalComforts->VapPress = RelHum * CalcSatVapPressFromTempTorr(AirTemp);
     923        5424 :         Real64 ActLevel = ActLevelConv * ActMet;
     924        5424 :         state.dataThermalComforts->IntHeatProd = ActLevel - WorkEff;
     925             : 
     926             :         // Step 1: CALCULATE VARIABLESS THAT REMAIN CONSTANT FOR AN HOUR
     927        5424 :         Real64 PInAtmospheres = state.dataEnvrn->OutBaroPress / 101325;
     928        5424 :         Real64 RClo = CloUnit * 0.155; // (var RCL)
     929        5424 :         Real64 TotCloFac = 1.0 + 0.15 * CloUnit;
     930        5424 :         Real64 LewisRatio = 2.2 / PInAtmospheres; // Lewis Relation is 2.2 at sea level, 25C (var LR)
     931             :         Real64 EvapEff;                           // evaporative efficiency
     932             : 
     933             :         // APPROXIMATE THE FOLLOWING VALUES TO START
     934        5424 :         state.dataThermalComforts->SkinTemp = SkinTempSet;
     935        5424 :         state.dataThermalComforts->CoreTemp = CoreTempSet;
     936        5424 :         Real64 SkinBloodFlow = SkinBloodFlowSet;
     937        5424 :         Real64 SkinMassRat = SkinMassRatSet;
     938             : 
     939             :         // Mass transfer equation between skin and environment
     940             :         // CloInsul is efficiency of mass transfer for CloUnit.
     941        5424 :         if (CloUnit <= 0) {
     942           0 :             EvapEff = 0.38 * std::pow(AirVel, -0.29); // (var WCRIT)
     943           0 :             state.dataThermalComforts->CloInsul = 1.0;
     944             :         } else {
     945        5424 :             EvapEff = 0.59 * std::pow(AirVel, -0.08); // (var ICL)
     946        5424 :             state.dataThermalComforts->CloInsul = 0.45;
     947             :         }
     948             : 
     949        5424 :         Real64 CorrectedHC = 3.0 * std::pow(PInAtmospheres, 0.53);              // corrected convective heat transfer coefficient
     950        5424 :         Real64 ForcedHC = 8.600001 * std::pow((AirVel * PInAtmospheres), 0.53); // forced convective heat transfer coefficient, W/(m2 °C) (CHCV)
     951        5424 :         state.dataThermalComforts->Hc = std::max(CorrectedHC, ForcedHC);        // (CHC)
     952        5424 :         state.dataThermalComforts->Hr = 4.7;                                    // (CHR)
     953        5424 :         state.dataThermalComforts->EvapHeatLoss = 0.1 * ActMet;
     954        5424 :         Real64 RAir = 1.0 / (TotCloFac * (state.dataThermalComforts->Hc + state.dataThermalComforts->Hr)); // resistance of air layer to dry heat (RA)
     955       10848 :         state.dataThermalComforts->OpTemp = (state.dataThermalComforts->Hr * RadTemp + state.dataThermalComforts->Hc * AirTemp) /
     956        5424 :                                             (state.dataThermalComforts->Hc + state.dataThermalComforts->Hr); // operative temperature (TOP)
     957        5424 :         Real64 ActLevelStart = ActLevel; // ActLevel gets increased by shivering in the following
     958        5424 :         Real64 AvgBodyTempSet = SkinMassRatSet * SkinTempSet + (1.0 - SkinMassRatSet) * CoreTempSet; // (var TempBodyNeutral)
     959             : 
     960             :         // Step 2: BEGIN MINUTE BY MINUTE CALCULATIONS FOR ONE HOUR SIMULATION OF TEMPERATURE REGULATION.
     961             :         // This section simulates the temperature regulation over 1 minute.
     962             :         // Inputs are the physiological data from the previous time step and the current environmental conditions. Loop and must be increased from the
     963             :         // start level, not perpetually increased
     964      330864 :         for (int IterMin = 1; IterMin <= 60; ++IterMin) {
     965             :             // Dry heat balance: solve for CloSurfTemp and Hr, GUESS CloSurfTemp TO START
     966      325440 :             state.dataThermalComforts->CloSurfTemp =
     967      325440 :                 (RAir * state.dataThermalComforts->SkinTemp + RClo * state.dataThermalComforts->OpTemp) / (RAir + RClo);
     968      325440 :             bool converged = false;
     969      997750 :             while (!converged) {
     970      336155 :                 state.dataThermalComforts->Hr =
     971      336155 :                     4.0 * StefanBoltz * std::pow((state.dataThermalComforts->CloSurfTemp + RadTemp) / 2.0 + 273.15, 3) * 0.72;
     972      336155 :                 RAir = 1.0 / (TotCloFac * (state.dataThermalComforts->Hc + state.dataThermalComforts->Hr));
     973      672310 :                 state.dataThermalComforts->OpTemp = (state.dataThermalComforts->Hr * RadTemp + state.dataThermalComforts->Hc * AirTemp) /
     974      336155 :                                                     (state.dataThermalComforts->Hc + state.dataThermalComforts->Hr);
     975      336155 :                 Real64 CloSurfTempNew = (RAir * state.dataThermalComforts->SkinTemp + RClo * state.dataThermalComforts->OpTemp) / (RAir + RClo);
     976      336155 :                 if (std::abs(CloSurfTempNew - state.dataThermalComforts->CloSurfTemp) <= 0.01) {
     977      325440 :                     converged = true;
     978             :                 }
     979      336155 :                 state.dataThermalComforts->CloSurfTemp = CloSurfTempNew;
     980             :             }
     981             : 
     982             :             // CALCULATE THE COMBINED HEAT TRANSFER COEFF. (H)
     983      325440 :             state.dataThermalComforts->H = state.dataThermalComforts->Hr + state.dataThermalComforts->Hc;
     984             :             // Heat flow from Clothing surface to environment
     985      325440 :             state.dataThermalComforts->DryHeatLoss = (state.dataThermalComforts->SkinTemp - state.dataThermalComforts->OpTemp) / (RAir + RClo);
     986             : 
     987             :             // dry and latent respiratory heat losses
     988      325440 :             state.dataThermalComforts->LatRespHeatLoss =
     989      325440 :                 0.0023 * ActLevel * (44.0 - state.dataThermalComforts->VapPress); // latent heat loss due to respiration
     990      325440 :             state.dataThermalComforts->DryRespHeatLoss = 0.0014 * ActLevel * (34.0 - AirTemp);
     991             : 
     992      325440 :             state.dataThermalComforts->RespHeatLoss = state.dataThermalComforts->LatRespHeatLoss + state.dataThermalComforts->DryRespHeatLoss;
     993             : 
     994             :             // Heat flows to skin and core: 5.28 is skin conductance in the absence of skin blood flow
     995      325440 :             state.dataThermalComforts->HeatFlow =
     996      325440 :                 (state.dataThermalComforts->CoreTemp - state.dataThermalComforts->SkinTemp) * (5.28 + 1.163 * SkinBloodFlow);
     997             : 
     998      325440 :             Real64 CoreHeatStorage = ActLevel - state.dataThermalComforts->HeatFlow - state.dataThermalComforts->RespHeatLoss -
     999      325440 :                                      WorkEff; // rate of energy storage in the core
    1000      325440 :             Real64 SkinHeatStorage = state.dataThermalComforts->HeatFlow - state.dataThermalComforts->DryHeatLoss -
    1001      325440 :                                      state.dataThermalComforts->EvapHeatLoss; // rate of energy storage in the skin
    1002             : 
    1003             :             // Thermal capacities
    1004      325440 :             state.dataThermalComforts->CoreThermCap = 0.97 * (1 - SkinMassRat) * BodyWeight;
    1005      325440 :             state.dataThermalComforts->SkinThermCap = 0.97 * SkinMassRat * BodyWeight;
    1006             : 
    1007             :             // Temperature changes in 1 minute
    1008      325440 :             state.dataThermalComforts->CoreTempChange = (CoreHeatStorage * BodySurfAreaPierce / (state.dataThermalComforts->CoreThermCap * 60.0));
    1009      325440 :             state.dataThermalComforts->SkinTempChange = (SkinHeatStorage * BodySurfAreaPierce) / (state.dataThermalComforts->SkinThermCap * 60.0);
    1010             : 
    1011      325440 :             state.dataThermalComforts->CoreTemp += state.dataThermalComforts->CoreTempChange;
    1012      325440 :             state.dataThermalComforts->SkinTemp += state.dataThermalComforts->SkinTempChange;
    1013      325440 :             state.dataThermalComforts->AvgBodyTemp =
    1014      325440 :                 SkinMassRat * state.dataThermalComforts->SkinTemp + (1.0 - SkinMassRat) * state.dataThermalComforts->CoreTemp;
    1015             : 
    1016             :             Real64 SkinThermSigWarm;                                               // vasodialtion signal (WARMS)
    1017             :             Real64 SkinThermSigCold;                                               // vasoconstriction signal
    1018      325440 :             Real64 SkinSignal = state.dataThermalComforts->SkinTemp - SkinTempSet; // thermoregulatory control signal from the skin
    1019      325440 :             if (SkinSignal > 0) {
    1020      130449 :                 SkinThermSigWarm = SkinSignal;
    1021      130449 :                 SkinThermSigCold = 0.0;
    1022             :             } else {
    1023      194991 :                 SkinThermSigCold = -SkinSignal;
    1024      194991 :                 SkinThermSigWarm = 0.0;
    1025             :             }
    1026             : 
    1027             :             Real64 CoreThermSigWarm;                                               // vasodialtion signal (WARMC)
    1028             :             Real64 CoreThermSigCold;                                               // vasoconstriction signal
    1029      325440 :             Real64 CoreSignal = state.dataThermalComforts->CoreTemp - CoreTempSet; // thermoregulatory control signal from the skin, °C
    1030      325440 :             if (CoreSignal > 0) {
    1031      214784 :                 CoreThermSigWarm = CoreSignal;
    1032      214784 :                 CoreThermSigCold = 0.0;
    1033             :             } else {
    1034      110656 :                 CoreThermSigCold = -CoreSignal;
    1035      110656 :                 CoreThermSigWarm = 0.0;
    1036             :             }
    1037             : 
    1038             :             Real64 BodyThermSigWarm; // WARMB
    1039      325440 :             Real64 BodySignal = state.dataThermalComforts->AvgBodyTemp - AvgBodyTempSet;
    1040             : 
    1041      325440 :             if (BodySignal > 0) {
    1042      129060 :                 BodyThermSigWarm = BodySignal;
    1043             :             } else {
    1044      196380 :                 BodyThermSigWarm = 0.0;
    1045             :             }
    1046             : 
    1047      325440 :             state.dataThermalComforts->VasodilationFac = DriCoeffVasodilation * CoreThermSigWarm;
    1048      325440 :             state.dataThermalComforts->VasoconstrictFac = DriCoeffVasoconstriction * SkinThermSigCold;
    1049      325440 :             SkinBloodFlow = (SkinBloodFlowSet + state.dataThermalComforts->VasodilationFac) / (1.0 + state.dataThermalComforts->VasoconstrictFac);
    1050             :             // SkinBloodFlow is never below 0.5 liter/(m2.hr) nor above 90 liter/(m2.hr)
    1051      325440 :             if (SkinBloodFlow < MinSkinBloodFlow) SkinBloodFlow = MinSkinBloodFlow;
    1052      325440 :             if (SkinBloodFlow > MaxSkinBloodFlow) SkinBloodFlow = MaxSkinBloodFlow;
    1053      325440 :             SkinMassRat = 0.0417737 + 0.7451832 / (SkinBloodFlow + 0.585417); // ratio of skin-core masses change with SkinBloodFlow
    1054             : 
    1055      325440 :             Real64 RegSweat = SweatContConst * BodyThermSigWarm * std::exp(SkinThermSigWarm / 10.7); // control of regulatory sweating
    1056      325440 :             if (RegSweat > RegSweatMax) RegSweat = RegSweatMax;
    1057      325440 :             state.dataThermalComforts->EvapHeatLossRegSweat = 0.68 * RegSweat; // heat lost by vaporization sweat
    1058             : 
    1059             :             // adjustment of metabolic heat due to shivering (Stolwijk, Hardy)
    1060      325440 :             state.dataThermalComforts->ShivResponse = 19.4 * SkinThermSigCold * CoreThermSigCold;
    1061      325440 :             ActLevel = ActLevelStart + state.dataThermalComforts->ShivResponse;
    1062             : 
    1063             :             // Evaluation of heat transfer by evaporation at skin surface
    1064      325440 :             Real64 AirEvapHeatResist = 1.0 / (LewisRatio * TotCloFac * state.dataThermalComforts->Hc); // evaporative resistance air layer
    1065      325440 :             Real64 CloEvapHeatResist = RClo / (LewisRatio * state.dataThermalComforts->CloInsul);
    1066      325440 :             Real64 TotEvapHeatResist = AirEvapHeatResist + CloEvapHeatResist;
    1067      325440 :             state.dataThermalComforts->SatSkinVapPress = CalcSatVapPressFromTempTorr(state.dataThermalComforts->SkinTemp); // PSSK
    1068      325440 :             state.dataThermalComforts->EvapHeatLossMax =
    1069      325440 :                 (state.dataThermalComforts->SatSkinVapPress - state.dataThermalComforts->VapPress) / TotEvapHeatResist; // TotEvapHeatResist;
    1070      325440 :             state.dataThermalComforts->SkinWetSweat =
    1071      650880 :                 state.dataThermalComforts->EvapHeatLossRegSweat /
    1072      325440 :                 state.dataThermalComforts->EvapHeatLossMax; // ratio heat loss sweating to max heat loss sweating
    1073             : 
    1074      325440 :             state.dataThermalComforts->SkinWetDiff =
    1075      325440 :                 (1.0 - state.dataThermalComforts->SkinWetSweat) * 0.06; // 0.06 if SkinWetDiff for nonsweating skin --- Kerslake
    1076      325440 :             state.dataThermalComforts->EvapHeatLossDiff = state.dataThermalComforts->SkinWetDiff * state.dataThermalComforts->EvapHeatLossMax;
    1077      325440 :             state.dataThermalComforts->EvapHeatLoss = state.dataThermalComforts->EvapHeatLossRegSweat + state.dataThermalComforts->EvapHeatLossDiff;
    1078      325440 :             state.dataThermalComforts->SkinWetTot = state.dataThermalComforts->EvapHeatLoss / state.dataThermalComforts->EvapHeatLossMax;
    1079             : 
    1080             :             // Beginning of dripping (Sweat not evaporated on skin surface)
    1081      325440 :             if (state.dataThermalComforts->SkinWetTot >= EvapEff) {
    1082       82551 :                 state.dataThermalComforts->SkinWetTot = EvapEff;
    1083       82551 :                 state.dataThermalComforts->SkinWetSweat = EvapEff / 0.94;
    1084       82551 :                 state.dataThermalComforts->EvapHeatLossRegSweat =
    1085       82551 :                     state.dataThermalComforts->SkinWetSweat * state.dataThermalComforts->EvapHeatLossMax;
    1086       82551 :                 state.dataThermalComforts->SkinWetDiff = (1.0 - state.dataThermalComforts->SkinWetSweat) * 0.06;
    1087       82551 :                 state.dataThermalComforts->EvapHeatLossDiff = state.dataThermalComforts->SkinWetDiff * state.dataThermalComforts->EvapHeatLossMax;
    1088       82551 :                 state.dataThermalComforts->EvapHeatLoss =
    1089       82551 :                     state.dataThermalComforts->EvapHeatLossRegSweat + state.dataThermalComforts->EvapHeatLossDiff;
    1090             :             }
    1091             : 
    1092             :             // When EvapHeatLossMax<0. condensation on skin occurs.
    1093      325440 :             if (state.dataThermalComforts->EvapHeatLossMax < 0.0) {
    1094       18882 :                 state.dataThermalComforts->SkinWetDiff = 0.0;
    1095       18882 :                 state.dataThermalComforts->EvapHeatLossDiff = 0.0;
    1096       18882 :                 state.dataThermalComforts->EvapHeatLoss = 0.0;
    1097       18882 :                 state.dataThermalComforts->SkinWetTot = EvapEff;
    1098       18882 :                 state.dataThermalComforts->SkinWetSweat = EvapEff;
    1099       18882 :                 state.dataThermalComforts->EvapHeatLossRegSweat = 0.0;
    1100             :             }
    1101             :             // Vapor pressure at skin (as measured by dewpoint sensors)
    1102      650880 :             state.dataThermalComforts->SkinVapPress = state.dataThermalComforts->SkinWetTot * state.dataThermalComforts->SatSkinVapPress +
    1103      325440 :                                                       (1.0 - state.dataThermalComforts->SkinWetTot) * state.dataThermalComforts->VapPress;
    1104             :         } // END OF MINUTE BY MINUTE TEMPERATURE REGULATION LOOP
    1105             : 
    1106             :         // EvapHeatLossMax is readjusted for EvapEff
    1107        5424 :         state.dataThermalComforts->EvapHeatLossMax *= EvapEff;
    1108             : 
    1109             :         // Step 3: Heat transfer indices in real environment. Computation of comfort indices.
    1110             :         // Inputs to this SECTION are the physiological data from the simulation of temperature regulation loop.
    1111        5424 :         Real64 EffectSkinHeatLoss = state.dataThermalComforts->DryHeatLoss + state.dataThermalComforts->EvapHeatLoss;
    1112             :         // ET*(standardization humidity/REAL(r64) CloUnit, StdAtm and Hc)
    1113        5424 :         state.dataThermalComforts->CloBodyRat = 1.0 + CloFac * CloUnit;
    1114             :         Real64 EffectCloUnit =
    1115        5424 :             CloUnit - (state.dataThermalComforts->CloBodyRat - 1.0) / (0.155 * state.dataThermalComforts->CloBodyRat * state.dataThermalComforts->H);
    1116        5424 :         Real64 EffectCloThermEff = 1.0 / (1.0 + 0.155 * state.dataThermalComforts->Hc * EffectCloUnit);
    1117        5424 :         state.dataThermalComforts->CloPermeatEff =
    1118        5424 :             1.0 / (1.0 + (0.155 / state.dataThermalComforts->CloInsul) * state.dataThermalComforts->Hc * EffectCloUnit);
    1119             :         // Get a low approximation for ET* and solve balance equation by iteration
    1120        5424 :         Real64 ET = state.dataThermalComforts->SkinTemp - EffectSkinHeatLoss / (state.dataThermalComforts->H * EffectCloThermEff);
    1121             :         Real64 EnergyBalErrET;
    1122             :         while (true) {
    1123      258531 :             Real64 StdVapPressET = CalcSatVapPressFromTempTorr(ET); // THE STANDARD VAPOR PRESSURE AT THE EFFECTIVE TEMP : StdVapPressET
    1124      517062 :             EnergyBalErrET = EffectSkinHeatLoss - state.dataThermalComforts->H * EffectCloThermEff * (state.dataThermalComforts->SkinTemp - ET) -
    1125      517062 :                              state.dataThermalComforts->SkinWetTot * LewisRatio * state.dataThermalComforts->Hc *
    1126      517062 :                                  state.dataThermalComforts->CloPermeatEff * (state.dataThermalComforts->SatSkinVapPress - StdVapPressET / 2.0);
    1127      258531 :             if (EnergyBalErrET >= 0.0) break;
    1128      253107 :             ET += 0.1;
    1129      253107 :         }
    1130        5424 :         state.dataThermalComforts->EffTemp = ET;
    1131             : 
    1132             :         // Standard effective temperature SET* standardized humidity.  Hc, CloUnit, StdAtm normalized for given ActLel AirVel
    1133             :         // Standard environment
    1134        5424 :         Real64 StdHr = state.dataThermalComforts->Hr;
    1135             :         Real64 StdHc; // standard conv. heat tr. coeff. (level walking/still air)
    1136        5424 :         if (ActMet <= 0.85) {
    1137           0 :             StdHc = 3.0; // minimum value of Hc at sea leAirVel = 3.0 (AirVel = .137 m/s)
    1138             :         } else {
    1139        5424 :             StdHc = 5.66 * std::pow(ActMet - 0.85, 0.39);
    1140             :         }
    1141        5424 :         if (StdHc <= 3.0) StdHc = 3.0;
    1142        5424 :         Real64 StdH = StdHc + StdHr; // StdH Standard combined heat transfer coefficient
    1143             :         // standard MET - StdCloUnit relation gives SET* = 24 C when PMV = 0
    1144        5424 :         Real64 StdCloUnit = 1.52 / (ActMet - WorkEff / ActLevelConv + 0.6944) - 0.1835;        // RCLOS
    1145        5424 :         Real64 StdRClo = 0.155 * StdCloUnit;                                                   // RCLS
    1146        5424 :         Real64 StdCloBodyRat = 1.0 + CloFac * StdCloUnit;                                      // FACLS
    1147        5424 :         Real64 StdEffectCloThermEff = 1.0 / (1.0 + 0.155 * StdCloBodyRat * StdH * StdCloUnit); // FCLS
    1148        5424 :         Real64 StdCloInsul = state.dataThermalComforts->CloInsul * StdHc / StdH * (1 - StdEffectCloThermEff) /
    1149        5424 :                              (StdHc / StdH - state.dataThermalComforts->CloInsul * StdEffectCloThermEff);
    1150        5424 :         Real64 StdREvap = 1.0 / (LewisRatio * StdCloBodyRat * StdHc);
    1151        5424 :         Real64 StdREvapClo = StdRClo / (LewisRatio * StdCloInsul);
    1152        5424 :         Real64 StdHEvap = 1.0 / (StdREvap + StdREvapClo);
    1153        5424 :         Real64 StdRAir = 1.0 / (StdCloBodyRat * StdH);
    1154        5424 :         Real64 StdHDry = 1.0 / (StdRAir + StdRClo);
    1155             : 
    1156             :         // Get a low approximation for SET* and solve balance equ. by iteration
    1157        5424 :         Real64 StdEffectSkinHeatLoss = state.dataThermalComforts->DryHeatLoss + state.dataThermalComforts->EvapHeatLoss;
    1158        5424 :         Real64 OldSET = round((state.dataThermalComforts->SkinTemp - StdEffectSkinHeatLoss / StdHDry) * 100) / 100;
    1159        5424 :         Real64 delta = 0.0001;
    1160        5424 :         Real64 err = 100.0;
    1161       35146 :         while (std::abs(err) > 0.01) {
    1162       14861 :             Real64 StdVapPressSET_1 = CalcSatVapPressFromTempTorr(OldSET); // StdVapPressSET *= VapPressConv;
    1163             :             Real64 EnergyBalErrSET_1 =
    1164       14861 :                 StdEffectSkinHeatLoss - StdHDry * (state.dataThermalComforts->SkinTemp - OldSET) -
    1165       14861 :                 state.dataThermalComforts->SkinWetTot * StdHEvap * (state.dataThermalComforts->SatSkinVapPress - StdVapPressSET_1 / 2.0);
    1166       14861 :             Real64 StdVapPressSET_2 = CalcSatVapPressFromTempTorr(OldSET + delta);
    1167             :             Real64 EnergyBalErrSET_2 =
    1168       14861 :                 StdEffectSkinHeatLoss - StdHDry * (state.dataThermalComforts->SkinTemp - (OldSET + delta)) -
    1169       14861 :                 state.dataThermalComforts->SkinWetTot * StdHEvap * (state.dataThermalComforts->SatSkinVapPress - StdVapPressSET_2 / 2.0);
    1170       14861 :             Real64 NewSET = OldSET - delta * EnergyBalErrSET_1 / (EnergyBalErrSET_2 - EnergyBalErrSET_1);
    1171       14861 :             err = NewSET - OldSET;
    1172       14861 :             OldSET = NewSET;
    1173             :         }
    1174        5424 :         Real64 SET = OldSET;
    1175             :         // PMV*(PMVET in prgm) uses ET instead of OpTemp
    1176        5424 :         state.dataThermalComforts->DryHeatLossET = StdH * StdEffectCloThermEff * (state.dataThermalComforts->SkinTemp - ET);
    1177             :         // SPMV*(PMVSET in prgm) uses SET instead of OpTemp
    1178        5424 :         state.dataThermalComforts->DryHeatLossSET = StdH * StdEffectCloThermEff * (state.dataThermalComforts->SkinTemp - SET);
    1179        5424 :         return SET;
    1180             :     }
    1181             : 
    1182        1968 :     void CalcThermalComfortPierceASHRAE(EnergyPlusData &state)
    1183             :     {
    1184             :         // This subroutine calculates ET, SET, SETPMV, SETPPD using Pierce two-node model.
    1185             :         // Reference: ANSI/ASHRAE Standard 55-2017 Appendix D.
    1186             : 
    1187        5568 :         for (state.dataThermalComforts->PeopleNum = 1; state.dataThermalComforts->PeopleNum <= state.dataHeatBal->TotPeople;
    1188        3600 :              ++state.dataThermalComforts->PeopleNum) {
    1189             : 
    1190        3600 :             if (!state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).Pierce) continue;
    1191             : 
    1192             :             // STEP 1: Get input (TA, TR, RH, VEL, CLO, MET, WME)
    1193        2352 :             GetThermalComfortInputsASHRAE(state);
    1194             : 
    1195             :             // STEP 2: Calculate SET.
    1196       16464 :             Real64 SET = CalcStandardEffectiveTemp(state,
    1197        2352 :                                                    state.dataThermalComforts->AirTemp,
    1198        2352 :                                                    state.dataThermalComforts->RadTemp,
    1199        2352 :                                                    state.dataThermalComforts->RelHum,
    1200        2352 :                                                    state.dataThermalComforts->AirVel,
    1201        2352 :                                                    state.dataThermalComforts->ActMet,
    1202        2352 :                                                    state.dataThermalComforts->CloUnit,
    1203        4704 :                                                    state.dataThermalComforts->WorkEff);
    1204             : 
    1205             :             // STEP 3: Report SET related variables.
    1206             :             // Fanger's comfort equation. Thermal transfer coefficient to calculate PMV
    1207        2352 :             state.dataThermalComforts->ThermSensTransCoef = 0.303 * std::exp(-0.036 * state.dataThermalComforts->ActLevel) + 0.028;
    1208             :             // Fanger's reg. sweating at comfort threshold (PMV=0) is:
    1209        2352 :             state.dataThermalComforts->EvapHeatLossRegComf = (state.dataThermalComforts->IntHeatProd - ActLevelConv) * 0.42;
    1210        2352 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).PiercePMVET =
    1211        4704 :                 state.dataThermalComforts->ThermSensTransCoef *
    1212        4704 :                 (state.dataThermalComforts->IntHeatProd - state.dataThermalComforts->RespHeatLoss - state.dataThermalComforts->DryHeatLossET -
    1213        4704 :                  state.dataThermalComforts->EvapHeatLossDiff - state.dataThermalComforts->EvapHeatLossRegComf);
    1214        2352 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).PiercePMVSET =
    1215        4704 :                 state.dataThermalComforts->ThermSensTransCoef *
    1216        4704 :                 (state.dataThermalComforts->IntHeatProd - state.dataThermalComforts->RespHeatLoss - state.dataThermalComforts->DryHeatLossSET -
    1217        4704 :                  state.dataThermalComforts->EvapHeatLossDiff - state.dataThermalComforts->EvapHeatLossRegComf);
    1218             : 
    1219             :             // PHeat stress and heat strain indices derived from EvapHeatLoss, DISC (discomfort) varies with relative thermoregulatory strain
    1220        2352 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).PierceDISC =
    1221        4704 :                 5.0 * (state.dataThermalComforts->EvapHeatLossRegSweat - state.dataThermalComforts->EvapHeatLossRegComf) /
    1222        4704 :                 (state.dataThermalComforts->EvapHeatLossMax - state.dataThermalComforts->EvapHeatLossRegComf -
    1223        2352 :                  state.dataThermalComforts->EvapHeatLossDiff);
    1224             : 
    1225             :             // Thermal sensation TSENS as function of mean body temp.-
    1226             :             // AvgBodyTempLow is AvgBodyTemp when DISC is 0. (lower limit of zone of evap. regul.)
    1227        2352 :             Real64 AvgBodyTempLow = (0.185 / ActLevelConv) * (state.dataThermalComforts->ActLevel - state.dataThermalComforts->WorkEff) + 36.313;
    1228             :             // AvgBodyTempHigh is AvgBodyTemp when HSI=100 (upper limit of zone of evap. regul.)
    1229        2352 :             Real64 AvgBodyTempHigh = (0.359 / ActLevelConv) * (state.dataThermalComforts->ActLevel - state.dataThermalComforts->WorkEff) + 36.664;
    1230             : 
    1231             :             // TSENS=DISC=4.7 when HSI =1 00 (HSI is Belding's classic heat stress index)
    1232             :             // In cold, DISC &TSENS are the same and neg. fct of AvgBodyTemp
    1233        2352 :             if (state.dataThermalComforts->AvgBodyTemp > AvgBodyTempLow) {
    1234         888 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).PierceTSENS =
    1235         888 :                     4.7 * (state.dataThermalComforts->AvgBodyTemp - AvgBodyTempLow) / (AvgBodyTempHigh - AvgBodyTempLow);
    1236             : 
    1237             :             } else {
    1238        1464 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).PierceTSENS =
    1239        1464 :                     0.68175 * (state.dataThermalComforts->AvgBodyTemp - AvgBodyTempLow);
    1240        1464 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).PierceDISC =
    1241        1464 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).PierceTSENS;
    1242             :             }
    1243             : 
    1244        2352 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortMRT =
    1245        2352 :                 state.dataThermalComforts->RadTemp;
    1246        2352 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortOpTemp =
    1247        2352 :                 (state.dataThermalComforts->RadTemp + state.dataThermalComforts->AirTemp) / 2.0;
    1248        2352 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).PierceSET = SET;
    1249             :         }
    1250        1968 :     }
    1251             : 
    1252         192 :     void CalcThermalComfortCoolingEffectASH(EnergyPlusData &state)
    1253             :     {
    1254             :         // This subroutine calculates ASHRAE Cooling effect adjusted PMV and PPD
    1255             :         // Reference: ANSI/ASHRAE Standard 55-2017 Appendix D.
    1256             : 
    1257         384 :         for (state.dataThermalComforts->PeopleNum = 1; state.dataThermalComforts->PeopleNum <= state.dataHeatBal->TotPeople;
    1258         192 :              ++state.dataThermalComforts->PeopleNum) {
    1259             : 
    1260         192 :             if (!state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).CoolingEffectASH55) continue;
    1261             : 
    1262             :             // Get input (TA, TR, RH, VEL, CLO, MET, WME)
    1263         192 :             GetThermalComfortInputsASHRAE(state);
    1264             : 
    1265             :             // Calculate elevated air cooling effect using the SET function.
    1266         192 :             Real64 CoolingEffect = 0;
    1267             :             Real64 CoolingEffectAdjustedPMV;
    1268         192 :             CalcCoolingEffectAdjustedPMV(state, CoolingEffect, CoolingEffectAdjustedPMV);
    1269             : 
    1270             :             // Report.
    1271         192 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).CoolingEffectASH55 = CoolingEffect;
    1272         192 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).CoolingEffectAdjustedPMVASH55 =
    1273             :                 CoolingEffectAdjustedPMV;
    1274         192 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).CoolingEffectAdjustedPPDASH55 =
    1275         192 :                 CalcFangerPPD(CoolingEffectAdjustedPMV);
    1276             :         }
    1277         192 :     }
    1278             : 
    1279         192 :     void CalcCoolingEffectAdjustedPMV(EnergyPlusData &state, Real64 &CoolingEffect, Real64 &CoolingEffectAdjustedPMV)
    1280             :     {
    1281             :         // Calculate SET without cooling effect.
    1282         192 :         Real64 RelAirVel = CalcRelativeAirVelocity(state.dataThermalComforts->AirVel, state.dataThermalComforts->ActMet);
    1283        1152 :         Real64 SET = CalcStandardEffectiveTemp(state,
    1284         192 :                                                state.dataThermalComforts->AirTemp,
    1285         192 :                                                state.dataThermalComforts->RadTemp,
    1286         192 :                                                state.dataThermalComforts->RelHum,
    1287             :                                                RelAirVel,
    1288         192 :                                                state.dataThermalComforts->ActMet,
    1289         192 :                                                state.dataThermalComforts->CloUnit,
    1290         384 :                                                state.dataThermalComforts->WorkEff);
    1291             : 
    1292             :         // TODO - This should use the ASHRAE55-2017 PMV calc program. The current Fanger PMV program are not consistent with the new standard.
    1293        1152 :         Real64 ASHRAE55PMV = CalcFangerPMV(state,
    1294         192 :                                            state.dataThermalComforts->AirTemp,
    1295         192 :                                            state.dataThermalComforts->RadTemp,
    1296         192 :                                            state.dataThermalComforts->RelHum,
    1297             :                                            RelAirVel,
    1298         192 :                                            state.dataThermalComforts->ActLevel,
    1299         192 :                                            state.dataThermalComforts->CloUnit,
    1300         384 :                                            state.dataThermalComforts->WorkEff);
    1301             : 
    1302         192 :         Real64 StillAirVel = 0.1;
    1303       25920 :         auto ce_root_function = [&state, &StillAirVel, &SET](Real64 x) {
    1304       23040 :             return CalcStandardEffectiveTemp(state,
    1305        2880 :                                              state.dataThermalComforts->AirTemp - x,
    1306        2880 :                                              state.dataThermalComforts->RadTemp - x,
    1307        2880 :                                              state.dataThermalComforts->RelHum,
    1308             :                                              StillAirVel,
    1309        2880 :                                              state.dataThermalComforts->ActMet,
    1310        2880 :                                              state.dataThermalComforts->CloUnit,
    1311        2880 :                                              state.dataThermalComforts->WorkEff) -
    1312        2880 :                    SET;
    1313        3072 :         };
    1314             : 
    1315        2688 :         auto ce_root_termination = [](Real64 min, Real64 max) { return abs(max - min) <= 0.01; };
    1316         192 :         Real64 lowerBound = 0.0;
    1317         192 :         Real64 upperBound = 50.0;
    1318             : 
    1319             :         try {
    1320         192 :             std::pair<Real64, Real64> solverResult = boost::math::tools::bisect(ce_root_function, lowerBound, upperBound, ce_root_termination);
    1321         192 :             CoolingEffect = (solverResult.first + solverResult.second) / 2;
    1322           0 :         } catch (const std::exception &e) {
    1323           0 :             ShowRecurringWarningErrorAtEnd(state,
    1324           0 :                                            "The cooling effect could not be solved for People=\"" +
    1325           0 :                                                state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).Name + "\"" +
    1326             :                                                "As a result, no cooling effect will be applied to adjust the PMV and PPD results.",
    1327           0 :                                            state.dataThermalComforts->CoolingEffectWarningInd);
    1328           0 :             CoolingEffect = 0;
    1329             :         }
    1330             : 
    1331         192 :         if (CoolingEffect > 0) {
    1332        1152 :             CoolingEffectAdjustedPMV = CalcFangerPMV(state,
    1333         192 :                                                      state.dataThermalComforts->AirTemp - CoolingEffect,
    1334         192 :                                                      state.dataThermalComforts->RadTemp - CoolingEffect,
    1335         192 :                                                      state.dataThermalComforts->RelHum,
    1336             :                                                      StillAirVel,
    1337         192 :                                                      state.dataThermalComforts->ActLevel,
    1338         192 :                                                      state.dataThermalComforts->CloUnit,
    1339         192 :                                                      state.dataThermalComforts->WorkEff);
    1340             :         } else {
    1341           0 :             CoolingEffectAdjustedPMV = ASHRAE55PMV;
    1342             :         }
    1343         192 :     }
    1344             : 
    1345         192 :     void CalcThermalComfortAnkleDraftASH(EnergyPlusData &state)
    1346             :     {
    1347             :         // This subroutine calculates ASHRAE Ankle draft PPD
    1348             :         // Reference: ANSI/ASHRAE Standard 55-2017 Appendix I.
    1349             : 
    1350         384 :         for (state.dataThermalComforts->PeopleNum = 1; state.dataThermalComforts->PeopleNum <= state.dataHeatBal->TotPeople;
    1351         192 :              ++state.dataThermalComforts->PeopleNum) {
    1352             : 
    1353         192 :             if (!state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).AnkleDraftASH55) continue;
    1354             : 
    1355         192 :             GetThermalComfortInputsASHRAE(state);
    1356         192 :             Real64 RelAirVel = CalcRelativeAirVelocity(state.dataThermalComforts->AirVel, state.dataThermalComforts->ActMet);
    1357         192 :             Real64 PPD_AD = -1.0;
    1358         192 :             if (state.dataThermalComforts->ActMet < 1.3 && state.dataThermalComforts->CloUnit < 0.7 && RelAirVel < 0.2) {
    1359             :                 Real64 AnkleAirVel =
    1360          96 :                     GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).AnkleAirVelocityPtr);
    1361         576 :                 Real64 PMV = CalcFangerPMV(state,
    1362          96 :                                            state.dataThermalComforts->AirTemp,
    1363          96 :                                            state.dataThermalComforts->RadTemp,
    1364          96 :                                            state.dataThermalComforts->RelHum,
    1365             :                                            RelAirVel,
    1366          96 :                                            state.dataThermalComforts->ActLevel,
    1367          96 :                                            state.dataThermalComforts->CloUnit,
    1368         192 :                                            state.dataThermalComforts->WorkEff);
    1369          96 :                 PPD_AD = (std::exp(-2.58 + 3.05 * AnkleAirVel - 1.06 * PMV) / (1 + std::exp(-2.58 + 3.05 * AnkleAirVel - 1.06 * PMV))) * 100.0;
    1370             : 
    1371             :             } else {
    1372          96 :                 if (state.dataGlobal->DisplayExtraWarnings) {
    1373           0 :                     if (RelAirVel >= 0.2) {
    1374           0 :                         ShowRecurringWarningErrorAtEnd(
    1375             :                             state,
    1376             :                             "Relative air velocity is above 0.2 m/s in Ankle draft PPD calculations. PPD at ankle draft will be set to -1.0.",
    1377           0 :                             state.dataThermalComforts->AnkleDraftAirVelWarningInd,
    1378             :                             RelAirVel,
    1379             :                             RelAirVel,
    1380             :                             _,
    1381             :                             "[m/s]",
    1382             :                             "[m/s]");
    1383             :                     }
    1384           0 :                     if (state.dataThermalComforts->ActMet >= 1.3) {
    1385           0 :                         ShowRecurringWarningErrorAtEnd(
    1386             :                             state,
    1387             :                             "Metabolic rate is above 1.3 met in Ankle draft PPD calculations. PPD at ankle draft will be set to -1.0.",
    1388           0 :                             state.dataThermalComforts->AnkleDraftActMetWarningInd,
    1389           0 :                             state.dataThermalComforts->ActMet,
    1390           0 :                             state.dataThermalComforts->ActMet,
    1391             :                             _,
    1392             :                             "[m/s]",
    1393             :                             "[m/s]");
    1394             :                     }
    1395           0 :                     if (state.dataThermalComforts->CloUnit >= 0.7) {
    1396           0 :                         ShowRecurringWarningErrorAtEnd(
    1397             :                             state,
    1398             :                             "Clothing unit is above 0.7 in Ankle draft PPD calculations. PPD at ankle draft will be set to -1.0.",
    1399           0 :                             state.dataThermalComforts->AnkleDraftCloUnitWarningInd,
    1400           0 :                             state.dataThermalComforts->CloUnit,
    1401           0 :                             state.dataThermalComforts->CloUnit,
    1402             :                             _,
    1403             :                             "[m/s]",
    1404             :                             "[m/s]");
    1405             :                     }
    1406             :                 }
    1407             :             }
    1408         192 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).AnkleDraftPPDASH55 = PPD_AD;
    1409             :         }
    1410         192 :     }
    1411             : 
    1412         624 :     void CalcThermalComfortKSU(EnergyPlusData &state)
    1413             :     {
    1414             : 
    1415             :         // SUBROUTINE INFORMATION:
    1416             :         //     AUTHOR         Jaewook Lee
    1417             :         //     DATE WRITTEN   January 2000
    1418             :         //     MODIFIED       Rick Strand (for E+ implementation February 2000)
    1419             : 
    1420             :         // PURPOSE OF THIS SUBROUTINE:
    1421             :         // This subroutine calculates TSV using the KSU 2 Node model.
    1422             : 
    1423             :         // METHODOLOGY EMPLOYED:
    1424             :         // This subroutine is based heavily upon the work performed by Dan Maloney for
    1425             :         // the BLAST program.  Many of the equations are based on the original Pierce
    1426             :         // development.  See documentation for further details and references.
    1427             : 
    1428             :         // REFERENCES:
    1429             :         // Maloney, Dan, M.S. Thesis, University of Illinois at Urbana-Champaign
    1430             : 
    1431             :         // SUBROUTINE PARAMETER DEFINITIONS:
    1432         624 :         Real64 constexpr CloEmiss(0.8); // Clothing Emissivity
    1433             : 
    1434             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1435             :         Real64 BodyWt;            // Weight of body, kg
    1436             :         Real64 DayNum;            // Number of days of acclimation
    1437             :         int NumDay;               // Loop counter for DayNum
    1438             :         Real64 EmissAvg;          // Average emissivity
    1439             :         int IncreDayNum;          // Number of days of increment in the outputs as desired
    1440             :         Real64 IntHeatProdMet;    // Internal heat production in MET
    1441             :         Real64 IntHeatProdMetMax; // Maximum value of internal heat production in MET
    1442             :         int LastDayNum;           // Number of days for the last print out
    1443             :         Real64 SkinWetFac;        // Skin wettedness factor
    1444             :         Real64 SkinWetNeut;       // Skin wettedness at neutral state
    1445             :         int StartDayNum;          // Number of days for the first print out
    1446             :         // Unacclimated man = 1, Acclimated man = 14
    1447             :         Real64 SweatSuppFac; // Sweat suppression factor due to skin wettedness
    1448             :         Real64 TempDiffer;   // Temperature difference between the rectal and esophageal temperatures
    1449             :         // If not measured, set it to be 0.5 Deg. C.
    1450             :         int TempIndiceNum;     // Number of temperature indices
    1451             :         Real64 ThermCndctMin;  // Minimum value of thermal conductance
    1452             :         Real64 ThermCndctNeut; // Thermal conductance at neutral state
    1453             :         Real64 TimeExpos;      // Time period in the exposure, hr
    1454             :         Real64 TimeInterval;   // Time interval of outputs desired, hr
    1455             :         Real64 TSVMax;         // Maximum value of thermal sensation vote
    1456             :         Real64 IntermediateClothing;
    1457             : 
    1458         624 :         TempIndiceNum = 2;
    1459             : 
    1460             :         // NEXT GROUP OF VARIABLE ARE FIXED FOR BLAST PROGRAM - UNACCLIMATED MAN
    1461             :         // THE TSV MODEL CAN BE APPLIED TO UNACCLIMATED MAN ONLY.
    1462         624 :         TimeInterval = 1.0;
    1463         624 :         TSVMax = 4.0;
    1464         624 :         StartDayNum = 1;
    1465         624 :         LastDayNum = 1;
    1466         624 :         IncreDayNum = 1;
    1467         624 :         TimeExpos = 1.0;
    1468         624 :         TempDiffer = 0.5;
    1469             : 
    1470        2496 :         for (state.dataThermalComforts->PeopleNum = 1; state.dataThermalComforts->PeopleNum <= state.dataHeatBal->TotPeople;
    1471        1872 :              ++state.dataThermalComforts->PeopleNum) {
    1472             :             // THE NEXT SIX VARIABLES WILL BE READ IN FROM INPUT DECK
    1473        1872 :             if (!state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).KSU) continue;
    1474             : 
    1475        1248 :             state.dataThermalComforts->ZoneNum = state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ZonePtr;
    1476        1248 :             auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataThermalComforts->ZoneNum);
    1477             : 
    1478        1248 :             state.dataThermalComforts->AirTemp = thisZoneHB.ZTAVComf;
    1479        1248 :             if (state.dataRoomAirMod->anyNonMixingRoomAirModel) {
    1480           0 :                 if (state.dataRoomAirMod->IsZoneDV(state.dataThermalComforts->ZoneNum) ||
    1481           0 :                     state.dataRoomAirMod->IsZoneUI(state.dataThermalComforts->ZoneNum)) {
    1482           0 :                     state.dataThermalComforts->AirTemp = state.dataRoomAirMod->TCMF(state.dataThermalComforts->ZoneNum); // PH 3/7/04
    1483             :                 }
    1484             :             }
    1485        1248 :             state.dataThermalComforts->RadTemp = CalcRadTemp(state, state.dataThermalComforts->PeopleNum);
    1486        1248 :             state.dataThermalComforts->RelHum =
    1487        2496 :                 PsyRhFnTdbWPb(state, state.dataThermalComforts->AirTemp, thisZoneHB.ZoneAirHumRatAvgComf, state.dataEnvrn->OutBaroPress);
    1488        1248 :             state.dataThermalComforts->ActLevel =
    1489        1248 :                 GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ActivityLevelPtr) / BodySurfArea;
    1490        1248 :             state.dataThermalComforts->WorkEff =
    1491        2496 :                 GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).WorkEffPtr) *
    1492        1248 :                 state.dataThermalComforts->ActLevel;
    1493             : 
    1494        1248 :             switch (state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).clothingType) {
    1495        1152 :             case DataHeatBalance::ClothingType::InsulationSchedule:
    1496        1152 :                 state.dataThermalComforts->CloUnit =
    1497        1152 :                     GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ClothingPtr);
    1498        1152 :                 break;
    1499          48 :             case DataHeatBalance::ClothingType::DynamicAshrae55:
    1500          48 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortOpTemp =
    1501          48 :                     (state.dataThermalComforts->RadTemp + state.dataThermalComforts->AirTemp) / 2.0;
    1502          48 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue =
    1503          48 :                     state.dataThermalComforts->CloUnit;
    1504          48 :                 DynamicClothingModel(state);
    1505          48 :                 state.dataThermalComforts->CloUnit =
    1506          48 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue;
    1507          48 :                 break;
    1508          48 :             case DataHeatBalance::ClothingType::CalculationSchedule:
    1509          48 :                 IntermediateClothing =
    1510          48 :                     GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ClothingMethodPtr);
    1511          48 :                 if (IntermediateClothing == 1.0) {
    1512          12 :                     state.dataThermalComforts->CloUnit =
    1513          12 :                         GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ClothingPtr);
    1514          12 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue =
    1515          12 :                         state.dataThermalComforts->CloUnit;
    1516          36 :                 } else if (IntermediateClothing == 2.0) {
    1517          36 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortOpTemp =
    1518          36 :                         (state.dataThermalComforts->RadTemp + state.dataThermalComforts->AirTemp) / 2.0;
    1519          36 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue =
    1520          36 :                         state.dataThermalComforts->CloUnit;
    1521          36 :                     DynamicClothingModel(state);
    1522          36 :                     state.dataThermalComforts->CloUnit =
    1523          36 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue;
    1524             :                 } else {
    1525           0 :                     state.dataThermalComforts->CloUnit =
    1526           0 :                         GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ClothingPtr);
    1527           0 :                     ShowWarningError(state,
    1528           0 :                                      "PEOPLE=\"" + state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).Name +
    1529             :                                          "\", Scheduled clothing value will be used rather than clothing calculation method.");
    1530             :                 }
    1531          48 :                 break;
    1532           0 :             default:
    1533           0 :                 ShowSevereError(state,
    1534           0 :                                 "PEOPLE=\"" + state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).Name + "\", Incorrect Clothing Type");
    1535             :             }
    1536             : 
    1537        1248 :             state.dataThermalComforts->AirVel =
    1538        1248 :                 GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).AirVelocityPtr);
    1539        1248 :             state.dataThermalComforts->IntHeatProd = state.dataThermalComforts->ActLevel - state.dataThermalComforts->WorkEff;
    1540             :             // THE FOLLOWING ARE TYPICAL VALUES SET FOR BLAST RUNS
    1541             :             // STANDARD MAN: 70. KG WEIGHT, 1.8 M2 SURFACE AREA
    1542        1248 :             BodyWt = 70.0;
    1543        1248 :             state.dataThermalComforts->CoreTemp = 37.0;
    1544        1248 :             state.dataThermalComforts->SkinTemp = 31.0;
    1545             : 
    1546             :             //   CALCULATIONS NEEDED FOR THE PASSIVE STATE EQUATIONS
    1547        1248 :             state.dataThermalComforts->CoreThermCap = 0.9 * BodyWt * 0.97 / BodySurfArea;
    1548        1248 :             state.dataThermalComforts->SkinThermCap = 0.1 * BodyWt * 0.97 / BodySurfArea;
    1549             :             //   KERSLAKE'S FORMULA (0.05<AirVel<5. M/S)
    1550        1248 :             if (state.dataThermalComforts->AirVel < 0.137) state.dataThermalComforts->AirVel = 0.137;
    1551        1248 :             state.dataThermalComforts->Hc = 8.3 * std::sqrt(state.dataThermalComforts->AirVel);
    1552        1248 :             EmissAvg = RadSurfEff * CloEmiss + (1.0 - RadSurfEff) * 1.0;
    1553             :             //   IBERALL EQUATION
    1554        1248 :             state.dataThermalComforts->Hr = EmissAvg * (3.87 + 0.031 * state.dataThermalComforts->RadTemp);
    1555        1248 :             state.dataThermalComforts->H = state.dataThermalComforts->Hr + state.dataThermalComforts->Hc;
    1556        3744 :             state.dataThermalComforts->OpTemp = (state.dataThermalComforts->Hc * state.dataThermalComforts->AirTemp +
    1557        2496 :                                                  state.dataThermalComforts->Hr * state.dataThermalComforts->RadTemp) /
    1558        1248 :                                                 state.dataThermalComforts->H;
    1559        1248 :             state.dataThermalComforts->VapPress = CalcSatVapPressFromTemp(state.dataThermalComforts->AirTemp);
    1560        1248 :             state.dataThermalComforts->VapPress *= state.dataThermalComforts->RelHum;
    1561        1248 :             state.dataThermalComforts->CloBodyRat = 1.0 + 0.2 * state.dataThermalComforts->CloUnit;
    1562        1248 :             state.dataThermalComforts->CloThermEff =
    1563        1248 :                 1.0 / (1.0 + 0.155 * state.dataThermalComforts->H * state.dataThermalComforts->CloBodyRat * state.dataThermalComforts->CloUnit);
    1564        1248 :             state.dataThermalComforts->CloPermeatEff = 1.0 / (1.0 + 0.143 * state.dataThermalComforts->Hc * state.dataThermalComforts->CloUnit);
    1565             :             //  BASIC INFORMATION FOR THERMAL SENSATION.
    1566        1248 :             IntHeatProdMet = state.dataThermalComforts->IntHeatProd / ActLevelConv;
    1567        1248 :             IntHeatProdMetMax = max(1.0, IntHeatProdMet);
    1568        1248 :             ThermCndctNeut = 12.05 * std::exp(0.2266 * (IntHeatProdMetMax - 1.0));
    1569        1248 :             SkinWetNeut = 0.02 + 0.4 * (1.0 - std::exp(-0.6 * (IntHeatProdMetMax - 1.0)));
    1570        1248 :             ThermCndctMin = (ThermCndctNeut - 5.3) * 0.26074074 + 5.3;
    1571        1248 :             Real64 const ThemCndct_75_fac(1.0 / (75.0 - ThermCndctNeut));
    1572        1248 :             Real64 const ThemCndct_fac(1.0 / (ThermCndctNeut - ThermCndctMin));
    1573             :             //  CALCULATE THE PHYSIOLOGICAL REACTIONS OF AN UNACCLIMATED
    1574             :             //  MAN (LastDayNum = 1), OR AN ACCLIMATED MAN (LastDayNum = 14, IncreDayNum = 13),
    1575        1248 :             assert(IncreDayNum > 0); // Autodesk:F2C++ Loop setup assumption
    1576        2496 :             for (NumDay = StartDayNum; NumDay <= LastDayNum; NumDay += IncreDayNum) {
    1577             :                 //  INITIAL CONDITIONS IN AN EXPOSURE
    1578        1248 :                 DayNum = double(NumDay);
    1579        1248 :                 state.dataThermalComforts->Time = 0.0;
    1580        1248 :                 state.dataThermalComforts->TimeChange = 0.01;
    1581        1248 :                 SweatSuppFac = 1.0;
    1582        1248 :                 state.dataThermalComforts->Temp(1) = state.dataThermalComforts->CoreTemp;
    1583        1248 :                 state.dataThermalComforts->Temp(2) = state.dataThermalComforts->SkinTemp;
    1584        1248 :                 state.dataThermalComforts->Coeff(1) = state.dataThermalComforts->Coeff(2) = 0.0;
    1585             :                 //  PHYSIOLOGICAL ADJUSTMENTS IN HEAT ACCLIMATION.
    1586        1248 :                 state.dataThermalComforts->AcclPattern = 1.0 - std::exp(-0.12 * (DayNum - 1.0));
    1587        1248 :                 state.dataThermalComforts->CoreTempNeut = 36.9 - 0.6 * state.dataThermalComforts->AcclPattern;
    1588        1248 :                 state.dataThermalComforts->SkinTempNeut = 33.8 - 1.6 * state.dataThermalComforts->AcclPattern;
    1589        1248 :                 state.dataThermalComforts->ActLevel -= 0.07 * state.dataThermalComforts->ActLevel * state.dataThermalComforts->AcclPattern;
    1590        1248 :                 Real64 const SkinTempNeut_fac(1.0 / (1.0 - SkinWetNeut));
    1591             :                 //  CALCULATION OF CoreTempChange/TempChange & SkinTempChange/TempChange
    1592        1248 :                 DERIV(state, TempIndiceNum, state.dataThermalComforts->Temp, state.dataThermalComforts->TempChange);
    1593             :                 while (true) {
    1594             :                     //  CALCULATION OF THERMAL SENSATION VOTE (TSV).
    1595             :                     //  THE TSV MODEL CAN BE APPLIED TO UNACCLIMATED MAN ONLY.
    1596      248352 :                     SkinWetFac = (state.dataThermalComforts->SkinWetSweat - SkinWetNeut) * SkinTempNeut_fac;
    1597      124800 :                     state.dataThermalComforts->VasodilationFac = (state.dataThermalComforts->ThermCndct - ThermCndctNeut) * ThemCndct_75_fac;
    1598      124800 :                     state.dataThermalComforts->VasoconstrictFac = (ThermCndctNeut - state.dataThermalComforts->ThermCndct) * ThemCndct_fac;
    1599             :                     //  IF VasodilationFac < 0.0, VASOCONSTRICTION OCCURS AND RESULTS IN COLD SENSATION.
    1600             :                     //  OTHERWISE NORMAL BLOOD FLOW OR VASODILATION OCCURS AND RESULTS IN
    1601             :                     //  THERMAL NEUTRALITY OR WARM SENSATION.
    1602      124800 :                     if (state.dataThermalComforts->VasodilationFac < 0) {
    1603       71093 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).KsuTSV =
    1604      142186 :                             -1.46153 * state.dataThermalComforts->VasoconstrictFac + 3.74721 * pow_2(state.dataThermalComforts->VasoconstrictFac) -
    1605       71093 :                             6.168856 * pow_3(state.dataThermalComforts->VasoconstrictFac);
    1606             :                     } else {
    1607       53707 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).KsuTSV =
    1608       53707 :                             (5.0 - 6.56 * (state.dataThermalComforts->RelHum - 0.50)) * SkinWetFac;
    1609       53707 :                         if (state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).KsuTSV > TSVMax)
    1610           0 :                             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).KsuTSV = TSVMax;
    1611             :                     }
    1612             : 
    1613      124800 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortMRT =
    1614      124800 :                         state.dataThermalComforts->RadTemp;
    1615      124800 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortOpTemp =
    1616      124800 :                         (state.dataThermalComforts->RadTemp + state.dataThermalComforts->AirTemp) / 2.0;
    1617             : 
    1618      124800 :                     state.dataThermalComforts->CoreTemp = state.dataThermalComforts->Temp(1);
    1619      124800 :                     state.dataThermalComforts->SkinTemp = state.dataThermalComforts->Temp(2);
    1620      124800 :                     state.dataThermalComforts->EvapHeatLossSweatPrev = state.dataThermalComforts->EvapHeatLossSweat;
    1621             : 
    1622      624000 :                     RKG(state,
    1623             :                         TempIndiceNum,
    1624      124800 :                         state.dataThermalComforts->TimeChange,
    1625      124800 :                         state.dataThermalComforts->Time,
    1626      124800 :                         state.dataThermalComforts->Temp,
    1627      124800 :                         state.dataThermalComforts->TempChange,
    1628      124800 :                         state.dataThermalComforts->Coeff);
    1629             : 
    1630      124800 :                     if (state.dataThermalComforts->Time > TimeExpos) break;
    1631             :                 }
    1632             :             }
    1633             :         }
    1634         624 :     }
    1635             : 
    1636      625248 :     void DERIV(EnergyPlusData &state,
    1637             :                [[maybe_unused]] int &TempIndiceNum,    // Number of temperature indices  unused1208
    1638             :                [[maybe_unused]] Array1D<Real64> &Temp, // Temperature unused1208
    1639             :                Array1D<Real64> &TempChange             // Change of temperature
    1640             :     )
    1641             :     {
    1642             : 
    1643             :         // SUBROUTINE INFORMATION:
    1644             :         //     AUTHOR         Jaewook Lee
    1645             :         //     DATE WRITTEN   January 2000
    1646             :         //     MODIFIED       Rick Strand (for E+ implementation February 2000)
    1647             : 
    1648             :         // PURPOSE OF THIS SUBROUTINE:
    1649             :         // THIS SUBROUTINE CALCULATES HEAT TRANSFER TERMS INVOLVED IN THE
    1650             :         // THERMOREGULATORY SYSTEM TO OBTAIN THE RATES OF CHANGE OF CoreTemp & SkinTemp
    1651             :         // VIZ., CoreTempChange/TempChange & SkinTempChange/TempChange RESPECTIVELY.
    1652             : 
    1653             :         // METHODOLOGY EMPLOYED:
    1654             :         // This subroutine is based heavily upon the work performed by Dan Maloney for
    1655             :         // the BLAST program.  Many of the equations are based on the original Pierce
    1656             :         // development.  See documentation for further details and references.
    1657             : 
    1658             :         // REFERENCES:
    1659             :         // Maloney, Dan, M.S. Thesis, University of Illinois at Urbana-Champaign
    1660             : 
    1661             :         // Argument array dimensioning
    1662             :         // EP_SIZE_CHECK(Temp, 2);
    1663      625248 :         EP_SIZE_CHECK(TempChange, 2);
    1664             : 
    1665             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1666             :         Real64 ActLevelTot;             // Total activity level
    1667             :         Real64 CoreSignalShiv;          // Core signal when shivering occurs
    1668             :         Real64 CoreSignalShivMax;       // Maximum value of core signal when shivering occurs
    1669             :         Real64 CoreSignalSkinSens;      // The sensitivity of the skin signal increases
    1670             :         Real64 CoreSignalSweatMax;      // Maximum value of core signal when sweating occurs
    1671             :         Real64 CoreSignalSweatWarm;     // Core signal when sweating occurs
    1672             :         Real64 CoreTempSweat;           // Core temperature when sweating occurs
    1673             :         Real64 CoreSignalWarm;          // Warm core signal
    1674             :         Real64 CoreSignalWarmMax;       // Maximum value of warm core signal
    1675             :         Real64 EvapHeatLossDrySweat;    // Evaporative heat loss by sweating when total skin wettedness < 0.4
    1676             :         Real64 Err;                     // Stop criteria for iteration
    1677             :         Real64 ErrPrev;                 // Previous value of stop criteria for iteration
    1678             :         Real64 EvapHeatLossSweatEst;    // Estimated evaporative heat loss by sweating
    1679             :         Real64 EvapHeatLossSweatEstNew; // New value of estimated evaporative heat loss by sweating
    1680             :         Real64 IntHeatProdTot;          // Total internal heat production
    1681             :         Real64 SkinCndctMax;            // Maximum value of skin conductance
    1682             :         Real64 SkinSignalCold;          // Cold skin signal
    1683             :         Real64 SkinSignalColdMax;       // Maximum value of cold skin signal
    1684             :         Real64 SkinSignalSweatCold;     // Cold skin signal for sweat inhibition
    1685             :         Real64 SkinSignalSweatColdMax;  // Maximum value of cold skin signal for sweat inhibition
    1686             :         Real64 SkinCndctDilation;       // Overall skin conductance due to vasodilation
    1687             :         Real64 SkinCndctConstriction;   // Overall skin conductance due to vasoconstriction
    1688             :         Real64 SkinSignalShiv;          // Skin signal when shivering occurs
    1689             :         Real64 SkinSignalShivMax;       // Maximum value of skin signal when shivering occurs
    1690             :         Real64 SkinSignalSweatMax;      // Skin signal when sweating occurs
    1691             :         Real64 SkinSignalSweatWarm;     // Maximum value of skin signal when sweating occurs
    1692             :         Real64 SkinSignalWarm;          // Warm skin signal
    1693             :         Real64 SkinSignalWarmMax;       // Maximum value of warm skin signal
    1694             :         Real64 SkinTempSweat;           // Skin temperature when sweating occurs
    1695             :         Real64 SkinWetSignal;           // Skin wettedness signal
    1696             :         Real64 SweatCtrlFac;            // Sweat control factor
    1697             :         Real64 SweatSuppFac;            // Sweat suppression factor due to skin wettedness
    1698             :         Real64 WeighFac;                // Weighting factor of core siganl
    1699             : 
    1700             :         // THE CONTROLLING SYSTEM.
    1701             :         // THE CONTROLLING SIGNALS :
    1702             :         // SIGNALS FOR KS.
    1703      625248 :         CoreSignalWarm = state.dataThermalComforts->CoreTemp - 36.98;
    1704      625248 :         SkinSignalWarm = state.dataThermalComforts->SkinTemp - 33.8;
    1705      625248 :         SkinSignalCold = 32.1 - state.dataThermalComforts->SkinTemp;
    1706      625248 :         CoreSignalSkinSens = state.dataThermalComforts->CoreTemp - 35.15;
    1707      625248 :         CoreSignalWarmMax = max(0.0, CoreSignalWarm);
    1708      625248 :         SkinSignalWarmMax = max(0.0, SkinSignalWarm);
    1709      625248 :         SkinSignalColdMax = max(0.0, SkinSignalCold);
    1710             : 
    1711             :         // SIGNALS FOR EvapHeatLossSweat.
    1712      625248 :         CoreTempSweat = state.dataThermalComforts->CoreTemp;
    1713      625248 :         if (CoreTempSweat > 38.29) CoreTempSweat = 38.29;
    1714      625248 :         CoreSignalSweatWarm = CoreTempSweat - state.dataThermalComforts->CoreTempNeut;
    1715      625248 :         SkinTempSweat = state.dataThermalComforts->SkinTemp;
    1716      625248 :         if (SkinTempSweat > 36.1) SkinTempSweat = 36.1;
    1717      625248 :         SkinSignalSweatWarm = SkinTempSweat - state.dataThermalComforts->SkinTempNeut;
    1718      625248 :         CoreSignalSweatMax = max(0.0, CoreSignalSweatWarm);
    1719      625248 :         SkinSignalSweatMax = max(0.0, SkinSignalSweatWarm);
    1720      625248 :         SkinSignalSweatCold = 33.37 - state.dataThermalComforts->SkinTemp;
    1721      625248 :         if (state.dataThermalComforts->SkinTempNeut < 33.37)
    1722           0 :             SkinSignalSweatCold = state.dataThermalComforts->SkinTempNeut - state.dataThermalComforts->SkinTemp;
    1723      625248 :         SkinSignalSweatColdMax = max(0.0, SkinSignalSweatCold);
    1724             : 
    1725             :         // SIGNALS FOR SHIVERING.
    1726      625248 :         CoreSignalShiv = 36.9 - state.dataThermalComforts->CoreTemp;
    1727      625248 :         SkinSignalShiv = 32.5 - state.dataThermalComforts->SkinTemp;
    1728      625248 :         CoreSignalShivMax = max(0.0, CoreSignalShiv);
    1729      625248 :         SkinSignalShivMax = max(0.0, SkinSignalShiv);
    1730             : 
    1731             :         // CONTROLLING FUNCTIONS :
    1732             :         // SHIVERING RESPONSE IN W/M**2.
    1733      625248 :         state.dataThermalComforts->ShivResponse = 20.0 * CoreSignalShivMax * SkinSignalShivMax + 5.0 * SkinSignalShivMax;
    1734      625248 :         if (state.dataThermalComforts->CoreTemp >= 37.1) state.dataThermalComforts->ShivResponse = 0.0;
    1735             : 
    1736             :         // SWEAT FUNCTION IN W/M**2.
    1737      625248 :         WeighFac = 260.0 + 70.0 * state.dataThermalComforts->AcclPattern;
    1738      625248 :         SweatCtrlFac = 1.0 + 0.05 * std::pow(SkinSignalSweatColdMax, 2.4);
    1739             : 
    1740             :         // EvapHeatLossDrySweat = SWEAT WHEN SkinWetTot < 0.4.
    1741      625248 :         EvapHeatLossDrySweat =
    1742      625248 :             ((WeighFac * CoreSignalSweatMax + 0.1 * WeighFac * SkinSignalSweatMax) * std::exp(SkinSignalSweatMax / 8.5)) / SweatCtrlFac;
    1743             : 
    1744             :         // MAXIMUM EVAPORATIVE POWER, EvapHeatLossMax, IN W/M**2.
    1745      625248 :         state.dataThermalComforts->SkinVapPress = CalcSatVapPressFromTemp(state.dataThermalComforts->SkinTemp);
    1746     1875744 :         state.dataThermalComforts->EvapHeatLossMax = 2.2 * state.dataThermalComforts->Hc *
    1747     1250496 :                                                      (state.dataThermalComforts->SkinVapPress - state.dataThermalComforts->VapPress) *
    1748      625248 :                                                      state.dataThermalComforts->CloPermeatEff;
    1749      625248 :         if (state.dataThermalComforts->EvapHeatLossMax > 0.0) {
    1750      625248 :             state.dataThermalComforts->SkinWetSweat = EvapHeatLossDrySweat / state.dataThermalComforts->EvapHeatLossMax;
    1751      625248 :             state.dataThermalComforts->EvapHeatLossDiff = 0.408 * (state.dataThermalComforts->SkinVapPress - state.dataThermalComforts->VapPress);
    1752     1250496 :             state.dataThermalComforts->EvapHeatLoss = state.dataThermalComforts->SkinWetSweat * state.dataThermalComforts->EvapHeatLossMax +
    1753      625248 :                                                       (1.0 - state.dataThermalComforts->SkinWetSweat) * state.dataThermalComforts->EvapHeatLossDiff;
    1754      625248 :             state.dataThermalComforts->SkinWetTot = state.dataThermalComforts->EvapHeatLoss / state.dataThermalComforts->EvapHeatLossMax;
    1755      625248 :             if (state.dataThermalComforts->Time == 0.0) {
    1756        2496 :                 state.dataThermalComforts->EvapHeatLossSweat = EvapHeatLossDrySweat;
    1757        2496 :                 state.dataThermalComforts->EvapHeatLossSweatPrev = EvapHeatLossDrySweat;
    1758             :             }
    1759      625248 :             if (state.dataThermalComforts->SkinWetTot > 0.4) {
    1760             : 
    1761             :                 // ITERATION  FOR SWEAT WHEN SkinWetTot IS GREATER THAT 0.4.
    1762       61595 :                 state.dataThermalComforts->IterNum = 0;
    1763       61595 :                 if (state.dataThermalComforts->SkinWetSweat > 1.0) state.dataThermalComforts->SkinWetSweat = 1.0;
    1764             :                 while (true) {
    1765      121113 :                     EvapHeatLossSweatEst = state.dataThermalComforts->EvapHeatLossSweatPrev;
    1766       91354 :                     state.dataThermalComforts->SkinWetSweat = EvapHeatLossSweatEst / state.dataThermalComforts->EvapHeatLossMax;
    1767             : 
    1768       91354 :                     if (state.dataThermalComforts->SkinWetSweat > 1.0) state.dataThermalComforts->SkinWetSweat = 1.0;
    1769             : 
    1770       91354 :                     state.dataThermalComforts->EvapHeatLossDiff =
    1771       91354 :                         0.408 * (state.dataThermalComforts->SkinVapPress - state.dataThermalComforts->VapPress);
    1772       91354 :                     state.dataThermalComforts->EvapHeatLoss =
    1773      182708 :                         (1.0 - state.dataThermalComforts->SkinWetTot) * state.dataThermalComforts->EvapHeatLossDiff +
    1774       91354 :                         state.dataThermalComforts->EvapHeatLossSweat;
    1775       91354 :                     state.dataThermalComforts->SkinWetTot = state.dataThermalComforts->EvapHeatLoss / state.dataThermalComforts->EvapHeatLossMax;
    1776             : 
    1777       91354 :                     if (state.dataThermalComforts->SkinWetTot > 1.0) state.dataThermalComforts->SkinWetTot = 1.0;
    1778             : 
    1779       91354 :                     SkinWetSignal = max(0.0, state.dataThermalComforts->SkinWetTot - 0.4);
    1780       91354 :                     SweatSuppFac = 0.5 + 0.5 * std::exp(-5.6 * SkinWetSignal);
    1781       91354 :                     EvapHeatLossSweatEstNew = SweatSuppFac * EvapHeatLossDrySweat;
    1782             : 
    1783       91354 :                     if (state.dataThermalComforts->IterNum == 0) state.dataThermalComforts->EvapHeatLossSweat = EvapHeatLossSweatEstNew;
    1784             : 
    1785       91354 :                     Err = EvapHeatLossSweatEst - EvapHeatLossSweatEstNew;
    1786             : 
    1787       91354 :                     if (state.dataThermalComforts->IterNum != 0) {
    1788       29759 :                         if ((ErrPrev * Err) < 0.0)
    1789       29687 :                             state.dataThermalComforts->EvapHeatLossSweat = (EvapHeatLossSweatEst + EvapHeatLossSweatEstNew) / 2.0;
    1790       29759 :                         if ((ErrPrev * Err) >= 0.0) state.dataThermalComforts->EvapHeatLossSweat = EvapHeatLossSweatEstNew;
    1791             :                     }
    1792             : 
    1793             :                     // STOP CRITERION FOR THE ITERATION.
    1794       91354 :                     if ((std::abs(Err) <= 0.5) || (state.dataThermalComforts->IterNum >= 10)) break;
    1795       29759 :                     ++state.dataThermalComforts->IterNum;
    1796       29759 :                     state.dataThermalComforts->EvapHeatLossSweatPrev = state.dataThermalComforts->EvapHeatLossSweat;
    1797       29759 :                     ErrPrev = Err;
    1798             :                 }
    1799             : 
    1800             :             } else {
    1801      563653 :                 state.dataThermalComforts->EvapHeatLossSweat = EvapHeatLossDrySweat;
    1802             :             }
    1803             : 
    1804             :         } else {
    1805           0 :             state.dataThermalComforts->SkinWetSweat = 1.0;
    1806           0 :             state.dataThermalComforts->SkinWetTot = 1.0;
    1807           0 :             state.dataThermalComforts->EvapHeatLossSweat = 0.5 * EvapHeatLossDrySweat;
    1808           0 :             state.dataThermalComforts->EvapHeatLoss = state.dataThermalComforts->EvapHeatLossSweat;
    1809             :         }
    1810             : 
    1811             :         // OVERALL SKIN CONDUCTANCE, KS, IN W/M**2/C.
    1812             :         // SkinCndctDilation = EFFECT DUE TO VASODILATION.
    1813             :         // SkinCndctConstriction = EFFECT DUE TO VASOCONSTRICTION.
    1814      625248 :         SkinCndctDilation = 42.45 * CoreSignalWarmMax + 8.15 * std::pow(CoreSignalSkinSens, 0.8) * SkinSignalWarmMax;
    1815      625248 :         SkinCndctConstriction = 1.0 + 0.4 * SkinSignalColdMax;
    1816             :         // ThermCndct IS EQUIVALENT TO KS
    1817      625248 :         state.dataThermalComforts->ThermCndct = 5.3 + (6.75 + SkinCndctDilation) / SkinCndctConstriction;
    1818      625248 :         SkinCndctMax = 75.0 + 10.0 * state.dataThermalComforts->AcclPattern;
    1819      625248 :         if (state.dataThermalComforts->ThermCndct > SkinCndctMax) state.dataThermalComforts->ThermCndct = SkinCndctMax;
    1820             : 
    1821             :         // PASSIVE ENERGY BALANCE EQUATIONS.
    1822             :         // TOTAL METABOLIC HEAT PRODUCTION RATE, ActLevel, IN W/M**2.
    1823      625248 :         ActLevelTot = state.dataThermalComforts->ActLevel + state.dataThermalComforts->ShivResponse;
    1824      625248 :         IntHeatProdTot = ActLevelTot - state.dataThermalComforts->WorkEff;
    1825             :         // RESPIRATION HEAT LOSS, RespHeatLoss, IN W/M**0.
    1826      625248 :         state.dataThermalComforts->LatRespHeatLoss = 0.0023 * ActLevelTot * (44.0 - state.dataThermalComforts->VapPress);
    1827      625248 :         state.dataThermalComforts->DryRespHeatLoss = 0.0014 * ActLevelTot * (34.0 - state.dataThermalComforts->AirTemp);
    1828      625248 :         state.dataThermalComforts->RespHeatLoss = state.dataThermalComforts->LatRespHeatLoss + state.dataThermalComforts->DryRespHeatLoss;
    1829             :         // HEAT FLOW FROM CORE TO SKIN, HeatFlow, IN W/M**2.
    1830      625248 :         state.dataThermalComforts->HeatFlow =
    1831      625248 :             state.dataThermalComforts->ThermCndct * (state.dataThermalComforts->CoreTemp - state.dataThermalComforts->SkinTemp);
    1832             :         // TempChange(1) = CoreTempChange/TempChange, IN C/HR.
    1833     1250496 :         TempChange(1) = (IntHeatProdTot - state.dataThermalComforts->RespHeatLoss - state.dataThermalComforts->HeatFlow) /
    1834      625248 :                         state.dataThermalComforts->CoreThermCap;
    1835      625248 :         if (state.dataThermalComforts->EvapHeatLoss > state.dataThermalComforts->EvapHeatLossMax)
    1836           0 :             state.dataThermalComforts->EvapHeatLoss = state.dataThermalComforts->EvapHeatLossMax;
    1837             : 
    1838             :         // DRY HEAT EXCHANGE BY RADIATION & CONVECTION, R+C, IN W/M**2.
    1839     1875744 :         state.dataThermalComforts->DryHeatLoss = state.dataThermalComforts->H * state.dataThermalComforts->CloBodyRat *
    1840     1250496 :                                                  state.dataThermalComforts->CloThermEff *
    1841      625248 :                                                  (state.dataThermalComforts->SkinTemp - state.dataThermalComforts->OpTemp);
    1842             :         // TempChange(2) = SkinTempChange/TempChange, IN C/HR.
    1843     1250496 :         TempChange(2) = (state.dataThermalComforts->HeatFlow - state.dataThermalComforts->EvapHeatLoss - state.dataThermalComforts->DryHeatLoss) /
    1844      625248 :                         state.dataThermalComforts->SkinThermCap;
    1845      625248 :     }
    1846             : 
    1847      124800 :     void RKG(EnergyPlusData &state, int &NEQ, Real64 &H, Real64 &X, Array1D<Real64> &Y, Array1D<Real64> &DY, Array1D<Real64> &C)
    1848             :     {
    1849             : 
    1850             :         // SUBROUTINE INFORMATION:
    1851             :         //     AUTHOR         Jaewook Lee
    1852             :         //     DATE WRITTEN   January 2000
    1853             :         //     MODIFIED       Rick Strand (for E+ implementation February 2000)
    1854             : 
    1855             :         // PURPOSE OF THIS SUBROUTINE:
    1856             :         // This is a subroutine for integration by Runga-Kutta's method.
    1857             : 
    1858             :         // METHODOLOGY EMPLOYED:
    1859             :         // This subroutine is based heavily upon the work performed by Dan Maloney for
    1860             :         // the BLAST program.  Many of the equations are based on the original Pierce
    1861             :         // development.  See documentation for further details and references.
    1862             : 
    1863             :         // REFERENCES:
    1864             :         // Maloney, Dan, M.S. Thesis, University of Illinois at Urbana-Champaign
    1865             : 
    1866             :         // Argument array dimensioning
    1867      124800 :         EP_SIZE_CHECK(Y, NEQ);
    1868      124800 :         EP_SIZE_CHECK(DY, NEQ);
    1869      124800 :         EP_SIZE_CHECK(C, NEQ);
    1870             : 
    1871             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1872             :         int I;
    1873             :         int J;
    1874             :         Real64 B;
    1875             :         Real64 H2;
    1876             :         static constexpr std::array<Real64, 2> A = {0.29289321881345, 1.70710678118654};
    1877             : 
    1878      124800 :         H2 = 0.5 * H;
    1879             : 
    1880      124800 :         DERIV(state, NEQ, Y, DY);
    1881      374400 :         for (I = 1; I <= NEQ; ++I) {
    1882      249600 :             B = H2 * DY(I) - C(I);
    1883      249600 :             Y(I) += B;
    1884      249600 :             C(I) += 3.0 * B - H2 * DY(I);
    1885             :         }
    1886             : 
    1887      124800 :         X += H2;
    1888             : 
    1889      374400 :         for (J = 0; J < 2; ++J) {
    1890      249600 :             DERIV(state, NEQ, Y, DY);
    1891      748800 :             for (I = 1; I <= NEQ; ++I) {
    1892      499200 :                 B = A[J] * (H * DY(I) - C(I));
    1893      499200 :                 Y(I) += B;
    1894      499200 :                 C(I) += 3.0 * B - A[J] * H * DY(I);
    1895             :             }
    1896             :         }
    1897             : 
    1898      124800 :         X += H2;
    1899      124800 :         DERIV(state, NEQ, Y, DY);
    1900             : 
    1901      374400 :         for (I = 1; I <= NEQ; ++I) {
    1902      249600 :             B = (H * DY(I) - 2.0 * C(I)) / 6.0;
    1903      249600 :             Y(I) += B;
    1904      249600 :             C(I) += 3.0 * B - H2 * DY(I);
    1905             :         }
    1906             : 
    1907      124800 :         DERIV(state, NEQ, Y, DY);
    1908      124800 :     }
    1909             : 
    1910         771 :     void GetAngleFactorList(EnergyPlusData &state)
    1911             :     {
    1912             : 
    1913             :         // SUBROUTINE INFORMATION:
    1914             :         //     AUTHOR         Jaewook Lee
    1915             :         //     DATE WRITTEN   July 2001
    1916             : 
    1917             :         static constexpr std::string_view routineName("GetAngleFactorList: "); // include trailing blank space
    1918         771 :         Real64 constexpr AngleFacLimit(0.01);                                  // To set the limit of sum of angle factors
    1919             : 
    1920         771 :         bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
    1921             :         int IOStatus;
    1922             :         int NumAlphas;  // Number of Alphas from InputProcessor
    1923             :         int NumNumbers; // Number of Numbers from Input Processor
    1924         771 :         auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
    1925             : 
    1926         771 :         cCurrentModuleObject = "ComfortViewFactorAngles";
    1927         771 :         int NumOfAngleFactorLists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    1928         771 :         state.dataThermalComforts->AngleFactorList.allocate(NumOfAngleFactorLists);
    1929             : 
    1930         774 :         for (int Item = 1; Item <= NumOfAngleFactorLists; ++Item) {
    1931             : 
    1932           3 :             Real64 AllAngleFacSummed = 0.0; // Sum of angle factors in each zone
    1933           3 :             auto &thisAngFacList(state.dataThermalComforts->AngleFactorList(Item));
    1934             : 
    1935          21 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1936             :                                                                      cCurrentModuleObject,
    1937             :                                                                      Item,
    1938           3 :                                                                      state.dataIPShortCut->cAlphaArgs,
    1939             :                                                                      NumAlphas,
    1940           3 :                                                                      state.dataIPShortCut->rNumericArgs,
    1941             :                                                                      NumNumbers,
    1942             :                                                                      IOStatus,
    1943           3 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1944           3 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
    1945           3 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1946           3 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1947             : 
    1948           3 :             thisAngFacList.Name = state.dataIPShortCut->cAlphaArgs(1); // no need for verification/uniqueness.
    1949             :             // Ignore ZoneName cAlphaArgs(2)
    1950             : 
    1951           3 :             thisAngFacList.TotAngleFacSurfaces = NumNumbers;
    1952           3 :             thisAngFacList.SurfaceName.allocate(thisAngFacList.TotAngleFacSurfaces);
    1953           3 :             thisAngFacList.SurfacePtr.allocate(thisAngFacList.TotAngleFacSurfaces);
    1954           3 :             thisAngFacList.AngleFactor.allocate(thisAngFacList.TotAngleFacSurfaces);
    1955             : 
    1956          21 :             for (int SurfNum = 1; SurfNum <= thisAngFacList.TotAngleFacSurfaces; ++SurfNum) {
    1957          18 :                 thisAngFacList.SurfaceName(SurfNum) = state.dataIPShortCut->cAlphaArgs(SurfNum + 2);
    1958          18 :                 thisAngFacList.SurfacePtr(SurfNum) =
    1959          18 :                     UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(SurfNum + 2), state.dataSurface->Surface);
    1960          18 :                 thisAngFacList.AngleFactor(SurfNum) = state.dataIPShortCut->rNumericArgs(SurfNum);
    1961             :                 // Error trap for surfaces that do not exist or surfaces not in the zone
    1962          18 :                 if (thisAngFacList.SurfacePtr(SurfNum) == 0) {
    1963           0 :                     ShowSevereError(state,
    1964           0 :                                     cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(SurfNum + 2) +
    1965           0 :                                         ", entered value=" + state.dataIPShortCut->cAlphaArgs(SurfNum + 2));
    1966           0 :                     ShowContinueError(state,
    1967           0 :                                       "ref " + state.dataIPShortCut->cAlphaFieldNames(1) + '=' + state.dataIPShortCut->cAlphaArgs(1) +
    1968           0 :                                           " not found in " + state.dataIPShortCut->cAlphaFieldNames(2) + '=' + state.dataIPShortCut->cAlphaArgs(2));
    1969           0 :                     ErrorsFound = true;
    1970             :                 } else {
    1971             :                     // Found Surface, is it in same enclosure?
    1972          18 :                     auto &thisSurf = state.dataSurface->Surface(thisAngFacList.SurfacePtr(SurfNum));
    1973          18 :                     if (SurfNum == 1) thisAngFacList.EnclosurePtr = thisSurf.RadEnclIndex; // Save enclosure num of first surface
    1974          18 :                     if (thisAngFacList.EnclosurePtr != thisSurf.RadEnclIndex) {
    1975           0 :                         ShowWarningError(state,
    1976           0 :                                          format("{}: For {}=\"{}\", surfaces are not all in the same radiant enclosure.",
    1977             :                                                 routineName,
    1978             :                                                 cCurrentModuleObject,
    1979           0 :                                                 thisAngFacList.Name));
    1980           0 :                         ShowContinueError(
    1981             :                             state,
    1982           0 :                             format("... Surface=\"{}\" is in enclosure=\"{}\"",
    1983           0 :                                    state.dataSurface->Surface(thisAngFacList.SurfacePtr(1)).Name,
    1984           0 :                                    state.dataViewFactor->EnclRadInfo(state.dataSurface->Surface(thisAngFacList.SurfacePtr(1)).RadEnclIndex).Name));
    1985           0 :                         ShowContinueError(state,
    1986           0 :                                           format("... Surface=\"{}\" is in enclosure=\"{}\"",
    1987             :                                                  thisSurf.Name,
    1988           0 :                                                  state.dataViewFactor->EnclRadInfo(thisSurf.RadEnclIndex).Name));
    1989             :                     }
    1990             :                 }
    1991             : 
    1992          18 :                 AllAngleFacSummed += thisAngFacList.AngleFactor(SurfNum);
    1993             :             }
    1994             : 
    1995           3 :             if (std::abs(AllAngleFacSummed - 1.0) > AngleFacLimit) {
    1996           0 :                 ShowSevereError(state, cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", invalid - Sum[AngleFactors]");
    1997           0 :                 ShowContinueError(state,
    1998           0 :                                   format("...Sum of Angle Factors [{:.3R}] should not deviate from expected sum [1.0] by more than limit [{:.3R}].",
    1999             :                                          AllAngleFacSummed,
    2000           0 :                                          AngleFacLimit));
    2001           0 :                 ErrorsFound = true;
    2002             :             }
    2003             :         }
    2004             : 
    2005         771 :         if (ErrorsFound) {
    2006           0 :             ShowFatalError(state, "GetAngleFactorList: Program terminated due to preceding errors.");
    2007             :         }
    2008             : 
    2009        4641 :         for (int Item = 1; Item <= state.dataHeatBal->TotPeople; ++Item) {
    2010        3870 :             auto &thisPeople = state.dataHeatBal->People(Item);
    2011        3870 :             if (thisPeople.MRTCalcType != DataHeatBalance::CalcMRT::AngleFactor) continue;
    2012           3 :             thisPeople.AngleFactorListPtr =
    2013           3 :                 UtilityRoutines::FindItemInList(thisPeople.AngleFactorListName, state.dataThermalComforts->AngleFactorList);
    2014           3 :             int WhichAFList = thisPeople.AngleFactorListPtr;
    2015           3 :             if (WhichAFList == 0 && (thisPeople.Fanger || thisPeople.Pierce || thisPeople.KSU)) {
    2016           0 :                 ShowSevereError(state, format("{}{}=\"{}\", invalid", routineName, cCurrentModuleObject, thisPeople.AngleFactorListName));
    2017           0 :                 ShowSevereError(state, format("... Angle Factor List Name not found for PEOPLE=\"{}\"", thisPeople.Name));
    2018           0 :                 ErrorsFound = true;
    2019             :             } else {
    2020           3 :                 auto &thisAngFacList = state.dataThermalComforts->AngleFactorList(WhichAFList);
    2021           3 :                 if (state.dataHeatBal->space(thisPeople.spaceIndex).radiantEnclosureNum != thisAngFacList.EnclosurePtr &&
    2022           0 :                     (thisPeople.Fanger || thisPeople.Pierce || thisPeople.KSU)) {
    2023           0 :                     ShowWarningError(state,
    2024           0 :                                      format("{}{}=\"{}\", radiant enclosure mismatch.", routineName, cCurrentModuleObject, thisAngFacList.Name));
    2025           0 :                     ShowContinueError(
    2026             :                         state,
    2027           0 :                         format("...Enclosure=\"{}\" doe not match enclosure=\"{}\" for PEOPLE=\"{}\"",
    2028           0 :                                state.dataViewFactor->EnclRadInfo(thisAngFacList.EnclosurePtr).Name,
    2029           0 :                                state.dataViewFactor->EnclRadInfo(state.dataHeatBal->space(thisPeople.spaceIndex).radiantEnclosureNum).Name,
    2030           0 :                                thisPeople.Name));
    2031             :                 }
    2032             :             }
    2033             :         }
    2034             : 
    2035         771 :         if (ErrorsFound) {
    2036           0 :             ShowFatalError(state, "GetAngleFactorList: Program terminated due to preceding errors.");
    2037             :         }
    2038         771 :     }
    2039             : 
    2040         864 :     Real64 CalcAngleFactorMRT(EnergyPlusData &state, int const AngleFacNum)
    2041             :     {
    2042             : 
    2043             :         // SUBROUTINE INFORMATION:
    2044             :         //     AUTHOR         Jaewook Lee
    2045             :         //     DATE WRITTEN   July 2001
    2046             :         //     MODIFIED       November 2017 (R Strand): Added fourth power and emissivity to calculation
    2047             : 
    2048             :         // Return value
    2049             :         Real64 CalcAngleFactorMRT;
    2050             : 
    2051         864 :         Real64 SurfTempEmissAngleFacSummed = 0.0;
    2052         864 :         Real64 SumSurfaceEmissAngleFactor = 0.0;
    2053             : 
    2054         864 :         auto &thisAngFacList(state.dataThermalComforts->AngleFactorList(AngleFacNum));
    2055             : 
    2056        6048 :         for (int SurfNum = 1; SurfNum <= thisAngFacList.TotAngleFacSurfaces; ++SurfNum) {
    2057        5184 :             Real64 SurfaceTemp = state.dataHeatBalSurf->SurfInsideTempHist(1)(thisAngFacList.SurfacePtr(SurfNum)) + DataGlobalConstants::KelvinConv;
    2058             :             Real64 SurfEAF =
    2059        5184 :                 state.dataConstruction->Construct(state.dataSurface->Surface(thisAngFacList.SurfacePtr(SurfNum)).Construction).InsideAbsorpThermal *
    2060        5184 :                 thisAngFacList.AngleFactor(SurfNum);
    2061        5184 :             SurfTempEmissAngleFacSummed += SurfEAF * pow_4(SurfaceTemp);
    2062        5184 :             SumSurfaceEmissAngleFactor += SurfEAF;
    2063             :         }
    2064             : 
    2065         864 :         CalcAngleFactorMRT = root_4(SurfTempEmissAngleFacSummed / SumSurfaceEmissAngleFactor) - DataGlobalConstants::KelvinConv;
    2066             : 
    2067         864 :         return CalcAngleFactorMRT;
    2068             :     }
    2069             : 
    2070        4752 :     Real64 CalcSurfaceWeightedMRT(EnergyPlusData &state, int const SurfNum, bool AverageWithSurface)
    2071             :     {
    2072             : 
    2073             :         // Purpose: Calculate a modified zone MRT that excludes the Surface( SurfNum ).
    2074             :         //          This is necessary for the surface weighted option to not in essence
    2075             :         //          double count SurfNum in the MRT calculation when averaged with the Surface( SurfNum ).
    2076             :         //          Other than that, the method here is the same as CalculateZoneMRT.  Once a modified zone
    2077             :         //          MRT is calculated, the subroutine then calculates and returns the
    2078             :         //          RadTemp (radiant temperature) for use by the thermal comfort routines
    2079             :         //          that is the average of the surface temperature to be weighted and
    2080             :         //          the modified zone MRT.
    2081             : 
    2082             :         // Return value
    2083        4752 :         Real64 CalcSurfaceWeightedMRT = 0.0;
    2084             : 
    2085             :         // Initialize ZoneAESum for all zones and SurfaceAE for all surfaces at the start of the simulation
    2086        4752 :         if (state.dataThermalComforts->FirstTimeSurfaceWeightedFlag) {
    2087          11 :             state.dataThermalComforts->FirstTimeError = true;
    2088          11 :             state.dataThermalComforts->FirstTimeSurfaceWeightedFlag = false;
    2089          72 :             for (auto const &thisRadEnclosure : state.dataViewFactor->EnclRadInfo) {
    2090         593 :                 for (int const SurfNum2 : thisRadEnclosure.SurfacePtr) {
    2091         532 :                     auto &thisSurface2 = state.dataSurface->Surface(SurfNum2);
    2092         532 :                     thisSurface2.AE = thisSurface2.Area * state.dataConstruction->Construct(thisSurface2.Construction).InsideAbsorpThermal;
    2093             :                 }
    2094             :                 // Do NOT include the contribution of the Surface that is being surface weighted in this calculation since it will already be
    2095             :                 // accounted for
    2096         593 :                 for (int const SurfNum1 : thisRadEnclosure.SurfacePtr) {
    2097         532 :                     auto &thisSurface1 = state.dataSurface->Surface(SurfNum1);
    2098         532 :                     thisSurface1.enclAESum = 0.0;
    2099        5706 :                     for (int const SurfNum2 : thisRadEnclosure.SurfacePtr) {
    2100        5174 :                         if (SurfNum2 == SurfNum1) continue;
    2101        4642 :                         auto &thisSurface2 = state.dataSurface->Surface(SurfNum2);
    2102        4642 :                         thisSurface1.enclAESum += thisSurface2.AE;
    2103             :                     }
    2104             :                 }
    2105             :             }
    2106             :         }
    2107             : 
    2108             :         // Calculate the sum of area*emissivity and area*emissivity*temperature for all surfaces in the zone EXCEPT the surface being weighted
    2109        4752 :         Real64 sumAET = 0.0; // Intermediate calculational variable (area*emissivity*T) sum
    2110             : 
    2111        4752 :         auto &thisSurface = state.dataSurface->Surface(SurfNum);
    2112        4752 :         auto &thisRadEnclosure = state.dataViewFactor->EnclRadInfo(thisSurface.RadEnclIndex);
    2113             :         // Recalc SurfaceEnclAESum only if needed due to window shades or EMS
    2114        4752 :         if (thisRadEnclosure.radReCalc) {
    2115           0 :             thisSurface.enclAESum = 0.0;
    2116           0 :             for (int const SurfNum2 : thisRadEnclosure.SurfacePtr) {
    2117           0 :                 if (SurfNum2 == SurfNum) continue;
    2118           0 :                 auto &thisSurface2 = state.dataSurface->Surface(SurfNum2);
    2119           0 :                 thisSurface2.AE = thisSurface2.Area * state.dataConstruction->Construct(thisSurface2.Construction).InsideAbsorpThermal;
    2120           0 :                 thisSurface.enclAESum += thisSurface2.AE;
    2121             :             }
    2122             :         }
    2123       47808 :         for (int const SurfNum2 : thisRadEnclosure.SurfacePtr) {
    2124       43056 :             if (SurfNum2 == SurfNum) continue;
    2125       38304 :             sumAET += state.dataSurface->Surface(SurfNum2).AE * state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfNum2);
    2126             :         }
    2127             : 
    2128             :         // Now weight the MRT
    2129        4752 :         if (thisSurface.enclAESum > 0.01) {
    2130        4752 :             CalcSurfaceWeightedMRT = sumAET / thisSurface.enclAESum;
    2131             :             // if averaged with surface--half comes from the surface used for weighting (SurfNum) and the rest from the calculated MRT that excludes
    2132             :             // this surface
    2133        4752 :             if (AverageWithSurface) {
    2134        2016 :                 CalcSurfaceWeightedMRT = 0.5 * (state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfNum) + CalcSurfaceWeightedMRT);
    2135             :             }
    2136             :         } else {
    2137           0 :             if (state.dataThermalComforts->FirstTimeError) {
    2138           0 :                 int ZoneNum = thisSurface.Zone;
    2139           0 :                 ShowWarningError(
    2140           0 :                     state, "Zone areas*inside surface emissivities are summing to zero, for Zone=\"" + state.dataHeatBal->Zone(ZoneNum).Name + "\"");
    2141           0 :                 ShowContinueError(state, "As a result, MAT will be used for MRT when calculating a surface weighted MRT for this zone.");
    2142           0 :                 state.dataThermalComforts->FirstTimeError = false;
    2143           0 :                 CalcSurfaceWeightedMRT = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
    2144           0 :                 if (AverageWithSurface) {
    2145           0 :                     CalcSurfaceWeightedMRT = 0.5 * (state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfNum) + CalcSurfaceWeightedMRT);
    2146             :                 }
    2147             :             }
    2148             :         }
    2149             : 
    2150        4752 :         return CalcSurfaceWeightedMRT;
    2151             :     }
    2152             : 
    2153      626496 :     Real64 CalcSatVapPressFromTemp(Real64 const Temp)
    2154             :     {
    2155             : 
    2156             :         // FUNCTION INFORMATION:
    2157             :         //     AUTHOR         Jaewook Lee
    2158             :         //     DATE WRITTEN   January 2000
    2159             :         //     MODIFIED       Rick Strand (for E+ implementation February 2000)
    2160             : 
    2161             :         // PURPOSE OF THIS FUNCTION:
    2162             :         // THIS IS A FUNCTION TO CALCULATE THE SATURATED VAPOR PRESSURE
    2163             :         // FROM AIR TEMPERATURE
    2164             : 
    2165             :         // METHODOLOGY EMPLOYED:
    2166             :         // This function is based upon the work performed by Dan Maloney for
    2167             :         // the BLAST program.
    2168             :         // REFERENCES:
    2169             :         // Maloney, Dan, M.S. Thesis, University of Illinois at Urbana-Champaign
    2170             : 
    2171      626496 :         Real64 const XT(Temp / 100.0);
    2172      626496 :         return 6.16796 + 358.1855 * pow_2(XT) - 550.3543 * pow_3(XT) + 1048.8115 * pow_4(XT);
    2173             : 
    2174             :         // Helper function for pierceSET calculates Saturated Vapor Pressure (Torr) at Temperature T (°C)
    2175             :         //        return Math.exp(18.6686 - 4030.183/(T + 235.0));
    2176             :     }
    2177             : 
    2178      619117 :     Real64 CalcSatVapPressFromTempTorr(Real64 const Temp)
    2179             :     {
    2180             :         // Helper function for pierceSET calculates Saturated Vapor Pressure (Torr) at Temperature T (°C)
    2181      619117 :         return std::exp(18.6686 - 4030.183 / (Temp + 235.0));
    2182             :     }
    2183             : 
    2184      834968 :     Real64 CalcRadTemp(EnergyPlusData &state, int const PeopleListNum) // Type of MRT calculation (zone averaged or surface weighted)
    2185             :     {
    2186             : 
    2187             :         // FUNCTION INFORMATION:
    2188             :         //     AUTHOR         Jaewook Lee
    2189             :         //     DATE WRITTEN   November 2000
    2190             :         //     MODIFIED       Rick Strand (for E+ implementation November 2000)
    2191             :         //                    Rick Strand (for high temperature radiant heaters March 2001)
    2192             : 
    2193             :         // PURPOSE OF THIS FUNCTION:
    2194             :         // THIS IS A FUNCTION TO CALCULATE EITHER ZONE AVERAGED MRT OR
    2195             :         // SURFACE WEIGHTED MRT
    2196             : 
    2197             :         // METHODOLOGY EMPLOYED:
    2198             :         // The method here is fairly straight-forward.  If the user has selected
    2199             :         // a zone average MRT calculation, then there is nothing to do other than
    2200             :         // to assign the function value because the zone MRT has already been
    2201             :         // calculated.  Note that this value is an "area-emissivity" weighted value.
    2202             :         // If the user wants to place the occupant "near" a particular surface,
    2203             :         // then at the limit half of the radiant field will be from this surface.
    2204             :         // As a result, an average of the zone MRT and the surface temperature
    2205             :         // is taken to arrive at an approximate radiant temperature.
    2206             :         // If a high temperature radiant heater is present, then this must also be
    2207             :         // taken into account.  The equation used to account for this factor is
    2208             :         // based on equation 49 on page 150 of Fanger's text (see reference below).
    2209             :         // The additional assumptions for EnergyPlus are that the radiant energy
    2210             :         // from the heater must be spread over the average area of a human being
    2211             :         // (see parameter below) and that the emissivity and absorptivity of the
    2212             :         // occupant are equivalent for the dominant wavelength of radiant energy
    2213             :         // from the heater.  These assumptions might be off slightly, but it does
    2214             :         // allow for an approximation of the effects of surfaces and heaters
    2215             :         // within a space.  Future additions might include the effect of direct
    2216             :         // solar energy on occupants.
    2217             : 
    2218             :         // Return value
    2219             :         Real64 CalcRadTemp;
    2220             : 
    2221             :         // Locals
    2222             :         Real64 SurfaceTemp;
    2223             : 
    2224             :         // FUNCTION PARAMETER DEFINITIONS:
    2225      834968 :         Real64 constexpr AreaEff(1.8);                    // Effective area of a "standard" person in meters squared
    2226      834968 :         Real64 constexpr StefanBoltzmannConst(5.6697e-8); // Stefan-Boltzmann constant in W/(m2*K4)
    2227             : 
    2228             :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    2229             :         Real64 ZoneRadTemp;
    2230             : 
    2231      834968 :         switch (state.dataHeatBal->People(PeopleListNum).MRTCalcType) {
    2232      832088 :         case DataHeatBalance::CalcMRT::ZoneAveraged: {
    2233      832088 :             state.dataThermalComforts->RadTemp = state.dataHeatBal->ZoneMRT(state.dataThermalComforts->ZoneNum);
    2234      832088 :         } break;
    2235        2016 :         case DataHeatBalance::CalcMRT::SurfaceWeighted: {
    2236        2016 :             ZoneRadTemp = state.dataHeatBal->ZoneMRT(state.dataThermalComforts->ZoneNum);
    2237        2016 :             SurfaceTemp = state.dataHeatBalSurf->SurfInsideTempHist(1)(state.dataHeatBal->People(PeopleListNum).SurfacePtr);
    2238        2016 :             state.dataThermalComforts->RadTemp = CalcSurfaceWeightedMRT(state, state.dataHeatBal->People(PeopleListNum).SurfacePtr);
    2239        2016 :         } break;
    2240         864 :         case DataHeatBalance::CalcMRT::AngleFactor: {
    2241         864 :             state.dataThermalComforts->RadTemp = CalcAngleFactorMRT(state, state.dataHeatBal->People(PeopleListNum).AngleFactorListPtr);
    2242         864 :         } break;
    2243           0 :         default:
    2244           0 :             break;
    2245             :         }
    2246             : 
    2247             :         // If high temperature radiant heater present and on, then must account for this in MRT calculation
    2248      834968 :         state.dataHeatBalFanSys->ZoneQdotRadHVACToPerson(state.dataThermalComforts->ZoneNum) =
    2249     1669936 :             state.dataHeatBalFanSys->ZoneQHTRadSysToPerson(state.dataThermalComforts->ZoneNum) +
    2250     1669936 :             state.dataHeatBalFanSys->ZoneQCoolingPanelToPerson(state.dataThermalComforts->ZoneNum) +
    2251     1669936 :             state.dataHeatBalFanSys->ZoneQHWBaseboardToPerson(state.dataThermalComforts->ZoneNum) +
    2252     1669936 :             state.dataHeatBalFanSys->ZoneQSteamBaseboardToPerson(state.dataThermalComforts->ZoneNum) +
    2253      834968 :             state.dataHeatBalFanSys->ZoneQElecBaseboardToPerson(state.dataThermalComforts->ZoneNum);
    2254      834968 :         if (state.dataHeatBalFanSys->ZoneQdotRadHVACToPerson(state.dataThermalComforts->ZoneNum) > 0.0) {
    2255        1342 :             state.dataThermalComforts->RadTemp += DataGlobalConstants::KelvinConv; // Convert to Kelvin
    2256        1342 :             state.dataThermalComforts->RadTemp =
    2257        2684 :                 root_4(pow_4(state.dataThermalComforts->RadTemp) +
    2258        1342 :                        (state.dataHeatBalFanSys->ZoneQdotRadHVACToPerson(state.dataThermalComforts->ZoneNum) / AreaEff / StefanBoltzmannConst));
    2259        1342 :             state.dataThermalComforts->RadTemp -= DataGlobalConstants::KelvinConv; // Convert back to Celsius
    2260             :         }
    2261             : 
    2262      834968 :         CalcRadTemp = state.dataThermalComforts->RadTemp;
    2263             : 
    2264      834968 :         return CalcRadTemp;
    2265             :     }
    2266             : 
    2267      299088 :     void CalcThermalComfortSimpleASH55(EnergyPlusData &state)
    2268             :     {
    2269             :         // SUBROUTINE INFORMATION:
    2270             :         //       AUTHOR         Jason Glazer
    2271             :         //       DATE WRITTEN   June 2005
    2272             : 
    2273             :         // PURPOSE OF THIS SUBROUTINE:
    2274             :         //   Determines if the space is within the ASHRAE 55-2004 comfort region
    2275             :         //   based on operative temperature and humidity ratio
    2276             : 
    2277             :         // Using/Aliasing
    2278             :         using OutputReportTabular::isInQuadrilateral;
    2279             :         using namespace OutputReportPredefined;
    2280             : 
    2281             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2282             :         Real64 OperTemp;
    2283             :         Real64 CurAirTemp;
    2284             :         Real64 CurMeanRadiantTemp;
    2285             :         Real64 NumberOccupants;
    2286             :         bool isComfortableWithSummerClothes;
    2287             :         bool isComfortableWithWinterClothes;
    2288             :         int iPeople;
    2289             :         int iZone;
    2290             :         Real64 allowedHours;
    2291             :         bool showWarning;
    2292             : 
    2293      299088 :         state.dataThermalComforts->AnyZoneTimeNotSimpleASH55Summer = 0.0;
    2294      299088 :         state.dataThermalComforts->AnyZoneTimeNotSimpleASH55Winter = 0.0;
    2295      299088 :         state.dataThermalComforts->AnyZoneTimeNotSimpleASH55Either = 0.0;
    2296             : 
    2297             :         // assume the zone is unoccupied
    2298     2109216 :         for (auto &e : state.dataThermalComforts->ThermalComfortInASH55)
    2299     1810128 :             e.ZoneIsOccupied = false;
    2300             :         // loop through the people objects and determine if the zone is currently occupied
    2301     1795200 :         for (iPeople = 1; iPeople <= state.dataHeatBal->TotPeople; ++iPeople) {
    2302     1496112 :             state.dataThermalComforts->ZoneNum = state.dataHeatBal->People(iPeople).ZonePtr;
    2303     2992224 :             NumberOccupants = state.dataHeatBal->People(iPeople).NumberOfPeople *
    2304     1496112 :                               GetCurrentScheduleValue(state, state.dataHeatBal->People(iPeople).NumberOfPeoplePtr);
    2305     1496112 :             if (NumberOccupants > 0) {
    2306      636628 :                 state.dataThermalComforts->ThermalComfortInASH55(state.dataThermalComforts->ZoneNum).ZoneIsOccupied = true;
    2307             :             }
    2308             :         }
    2309             :         // loop through the zones and determine if in simple ashrae 55 comfort regions
    2310     2109216 :         for (iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    2311     1810128 :             if (state.dataThermalComforts->ThermalComfortInASH55(iZone).ZoneIsOccupied) {
    2312      635680 :                 auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(iZone);
    2313             :                 // keep track of occupied hours
    2314      635680 :                 state.dataThermalComforts->ZoneOccHrs(iZone) += state.dataGlobal->TimeStepZone;
    2315      635680 :                 CurAirTemp = thisZoneHB.ZTAVComf;
    2316      635680 :                 if (state.dataRoomAirMod->anyNonMixingRoomAirModel) {
    2317        2524 :                     if (state.dataRoomAirMod->IsZoneDV(iZone) || state.dataRoomAirMod->IsZoneUI(iZone)) {
    2318         808 :                         CurAirTemp = state.dataRoomAirMod->TCMF(iZone);
    2319             :                     }
    2320             :                 }
    2321      635680 :                 CurMeanRadiantTemp = state.dataHeatBal->ZoneMRT(iZone);
    2322      635680 :                 OperTemp = CurAirTemp * 0.5 + CurMeanRadiantTemp * 0.5;
    2323             :                 // for debugging
    2324             :                 // ThermalComfortInASH55(iZone)%dCurAirTemp = CurAirTemp
    2325             :                 // ThermalComfortInASH55(iZone)%dCurMeanRadiantTemp = CurMeanRadiantTemp
    2326             :                 // ThermalComfortInASH55(iZone)%dOperTemp = OperTemp
    2327             :                 // ThermalComfortInASH55(iZone)%dHumidRatio = HumidRatio
    2328             :                 // From ASHRAE Standard 55-2004 Appendix D
    2329             :                 //  Run    AirTemp(C)   RH(%)  Season  HumidRatio
    2330             :                 //   1       19.6        86    Winter    0.012
    2331             :                 //   2       23.9        66    Winter    0.012
    2332             :                 //   3       25.7        15    Winter    0.003
    2333             :                 //   4       21.2        20    Winter    0.003
    2334             :                 //   5       23.6        67    Summer    0.012
    2335             :                 //   6       26.8        56    Summer    0.012
    2336             :                 //   7       27.9        13    Summer    0.003
    2337             :                 //   8       24.7        16    Summer    0.003
    2338             :                 // But the standard says "no recommended lower humidity limit" so it should
    2339             :                 // really extend down to the 0.0 Humidity ratio line.  Extrapolating we get
    2340             :                 // the values that are shown in the following table
    2341             :                 //  Run    AirTemp(C)    Season  HumidRatio
    2342             :                 //   1       19.6        Winter    0.012
    2343             :                 //   2       23.9        Winter    0.012
    2344             :                 //   3       26.3        Winter    0.000
    2345             :                 //   4       21.7        Winter    0.000
    2346             :                 //   5       23.6        Summer    0.012
    2347             :                 //   6       26.8        Summer    0.012
    2348             :                 //   7       28.3        Summer    0.000
    2349             :                 //   8       25.1        Summer    0.000
    2350             :                 // check summer clothing conditions
    2351      635680 :                 isComfortableWithSummerClothes =
    2352      635680 :                     isInQuadrilateral(OperTemp, thisZoneHB.ZoneAirHumRatAvgComf, 25.1, 0.0, 23.6, 0.012, 26.8, 0.012, 28.3, 0.0);
    2353             :                 // check winter clothing conditions
    2354      635680 :                 isComfortableWithWinterClothes =
    2355      635680 :                     isInQuadrilateral(OperTemp, thisZoneHB.ZoneAirHumRatAvgComf, 21.7, 0.0, 19.6, 0.012, 23.9, 0.012, 26.3, 0.0);
    2356      635680 :                 if (isComfortableWithSummerClothes) {
    2357      267125 :                     state.dataThermalComforts->ThermalComfortInASH55(iZone).timeNotSummer = 0.0;
    2358             :                 } else {
    2359      368555 :                     state.dataThermalComforts->ThermalComfortInASH55(iZone).timeNotSummer = state.dataGlobal->TimeStepZone;
    2360      368555 :                     state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotSummer += state.dataGlobal->TimeStepZone;
    2361      368555 :                     state.dataThermalComforts->AnyZoneTimeNotSimpleASH55Summer = state.dataGlobal->TimeStepZone;
    2362             :                 }
    2363      635680 :                 if (isComfortableWithWinterClothes) {
    2364      217656 :                     state.dataThermalComforts->ThermalComfortInASH55(iZone).timeNotWinter = 0.0;
    2365             :                 } else {
    2366      418024 :                     state.dataThermalComforts->ThermalComfortInASH55(iZone).timeNotWinter = state.dataGlobal->TimeStepZone;
    2367      418024 :                     state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotWinter += state.dataGlobal->TimeStepZone;
    2368      418024 :                     state.dataThermalComforts->AnyZoneTimeNotSimpleASH55Winter = state.dataGlobal->TimeStepZone;
    2369             :                 }
    2370      635680 :                 if (isComfortableWithSummerClothes || isComfortableWithWinterClothes) {
    2371      440646 :                     state.dataThermalComforts->ThermalComfortInASH55(iZone).timeNotEither = 0.0;
    2372             :                 } else {
    2373      195034 :                     state.dataThermalComforts->ThermalComfortInASH55(iZone).timeNotEither = state.dataGlobal->TimeStepZone;
    2374      195034 :                     state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotEither += state.dataGlobal->TimeStepZone;
    2375      195034 :                     state.dataThermalComforts->AnyZoneTimeNotSimpleASH55Either = state.dataGlobal->TimeStepZone;
    2376             :                 }
    2377             :             } else {
    2378             :                 // when no one present in that portion of the zone then no one can be uncomfortable
    2379     1174448 :                 state.dataThermalComforts->ThermalComfortInASH55(iZone).timeNotSummer = 0.0;
    2380     1174448 :                 state.dataThermalComforts->ThermalComfortInASH55(iZone).timeNotWinter = 0.0;
    2381     1174448 :                 state.dataThermalComforts->ThermalComfortInASH55(iZone).timeNotEither = 0.0;
    2382             :             }
    2383             :         }
    2384             :         // accumulate total time
    2385      299088 :         state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Summer += state.dataThermalComforts->AnyZoneTimeNotSimpleASH55Summer;
    2386      299088 :         state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Winter += state.dataThermalComforts->AnyZoneTimeNotSimpleASH55Winter;
    2387      299088 :         state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Either += state.dataThermalComforts->AnyZoneTimeNotSimpleASH55Either;
    2388             : 
    2389      299088 :         if (state.dataGlobal->EndDesignDayEnvrnsFlag) {
    2390         788 :             allowedHours = double(state.dataGlobal->NumOfDayInEnvrn) * 24.0 * 0.04;
    2391             :             // first check if warning should be printed
    2392         788 :             showWarning = false;
    2393        5903 :             for (iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    2394        5115 :                 if (state.dataThermalComforts->ThermalComfortInASH55(iZone).Enable55Warning) {
    2395           0 :                     if (state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotEither > allowedHours) {
    2396           0 :                         showWarning = true;
    2397             :                     }
    2398             :                 }
    2399             :             }
    2400             :             // if any zones should be warning print it out
    2401         788 :             if (showWarning) {
    2402           0 :                 ShowWarningError(state, format("More than 4% of time ({:.1R} hours) uncomfortable in one or more zones ", allowedHours));
    2403           0 :                 ShowContinueError(state, "Based on ASHRAE 55-2004 graph (Section 5.2.1.1)");
    2404           0 :                 if (state.dataEnvrn->RunPeriodEnvironment) {
    2405           0 :                     ShowContinueError(state,
    2406           0 :                                       "During Environment [" + state.dataEnvrn->EnvironmentStartEnd + "]: " + state.dataEnvrn->EnvironmentName);
    2407             :                 } else {
    2408           0 :                     ShowContinueError(
    2409           0 :                         state, "During SizingPeriod Environment [" + state.dataEnvrn->EnvironmentStartEnd + "]: " + state.dataEnvrn->EnvironmentName);
    2410             :                 }
    2411           0 :                 for (iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    2412           0 :                     if (state.dataThermalComforts->ThermalComfortInASH55(iZone).Enable55Warning) {
    2413           0 :                         if (state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotEither > allowedHours) {
    2414           0 :                             ShowContinueError(state,
    2415           0 :                                               format("{:.1R} hours were uncomfortable in zone: {}",
    2416           0 :                                                      state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotEither,
    2417           0 :                                                      state.dataHeatBal->Zone(iZone).Name));
    2418             :                         }
    2419             :                     }
    2420             :                 }
    2421             :             }
    2422             :             // put in predefined reports
    2423        5903 :             for (iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    2424       20460 :                 PreDefTableEntry(state,
    2425        5115 :                                  state.dataOutRptPredefined->pdchSCwinterClothes,
    2426        5115 :                                  state.dataHeatBal->Zone(iZone).Name,
    2427        5115 :                                  state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotWinter);
    2428       20460 :                 PreDefTableEntry(state,
    2429        5115 :                                  state.dataOutRptPredefined->pdchSCsummerClothes,
    2430        5115 :                                  state.dataHeatBal->Zone(iZone).Name,
    2431        5115 :                                  state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotSummer);
    2432       20460 :                 PreDefTableEntry(state,
    2433        5115 :                                  state.dataOutRptPredefined->pdchSCeitherClothes,
    2434        5115 :                                  state.dataHeatBal->Zone(iZone).Name,
    2435        5115 :                                  state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotEither);
    2436             :             }
    2437        2364 :             PreDefTableEntry(
    2438        1576 :                 state, state.dataOutRptPredefined->pdchSCwinterClothes, "Facility", state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Winter);
    2439        2364 :             PreDefTableEntry(
    2440        1576 :                 state, state.dataOutRptPredefined->pdchSCsummerClothes, "Facility", state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Summer);
    2441        2364 :             PreDefTableEntry(
    2442        1576 :                 state, state.dataOutRptPredefined->pdchSCeitherClothes, "Facility", state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Either);
    2443             :             // set value for ABUPS report
    2444         788 :             state.dataOutRptPredefined->TotalTimeNotSimpleASH55EitherForABUPS = state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Either;
    2445             :             // reset accumulation for new environment
    2446        5903 :             for (iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    2447        5115 :                 state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotWinter = 0.0;
    2448        5115 :                 state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotSummer = 0.0;
    2449        5115 :                 state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotEither = 0.0;
    2450             :             }
    2451         788 :             state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Winter = 0.0;
    2452         788 :             state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Summer = 0.0;
    2453         788 :             state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Either = 0.0;
    2454             :             // report how the aggregation is conducted
    2455         788 :             switch (state.dataGlobal->KindOfSim) {
    2456         767 :             case DataGlobalConstants::KindOfSim::DesignDay: {
    2457         767 :                 addFootNoteSubTable(state, state.dataOutRptPredefined->pdstSimpleComfort, "Aggregated over the Design Days");
    2458         767 :             } break;
    2459           3 :             case DataGlobalConstants::KindOfSim::RunPeriodDesign: {
    2460           3 :                 addFootNoteSubTable(state, state.dataOutRptPredefined->pdstSimpleComfort, "Aggregated over the RunPeriods for Design");
    2461           3 :             } break;
    2462           2 :             case DataGlobalConstants::KindOfSim::RunPeriodWeather: {
    2463           2 :                 addFootNoteSubTable(state, state.dataOutRptPredefined->pdstSimpleComfort, "Aggregated over the RunPeriods for Weather");
    2464           2 :             } break;
    2465          16 :             default:
    2466          16 :                 break;
    2467             :             }
    2468             :             // report number of occupied hours per week for LEED report
    2469        5903 :             for (iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    2470       20460 :                 PreDefTableEntry(state,
    2471        5115 :                                  state.dataOutRptPredefined->pdchLeedSutHrsWeek,
    2472        5115 :                                  state.dataHeatBal->Zone(iZone).Name,
    2473        5115 :                                  7 * 24 * (state.dataThermalComforts->ZoneOccHrs(iZone) / (state.dataGlobal->NumOfDayInEnvrn * 24)));
    2474             :             }
    2475             :         }
    2476      299088 :     }
    2477             : 
    2478           0 :     void ResetThermalComfortSimpleASH55(EnergyPlusData &state)
    2479             :     {
    2480             :         // Jason Glazer - October 2015
    2481             :         // Reset thermal comfort table gathering arrays to zero for multi-year simulations
    2482             :         // so that only last year is reported in tabular reports
    2483             :         int iZone;
    2484           0 :         for (iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    2485           0 :             state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotWinter = 0.0;
    2486           0 :             state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotSummer = 0.0;
    2487           0 :             state.dataThermalComforts->ThermalComfortInASH55(iZone).totalTimeNotEither = 0.0;
    2488             :         }
    2489           0 :         state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Winter = 0.0;
    2490           0 :         state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Summer = 0.0;
    2491           0 :         state.dataThermalComforts->TotalAnyZoneTimeNotSimpleASH55Either = 0.0;
    2492           0 :     }
    2493             : 
    2494      299088 :     void CalcIfSetPointMet(EnergyPlusData &state)
    2495             :     {
    2496             :         // SUBROUTINE INFORMATION:
    2497             :         //       AUTHOR         Jason Glazer
    2498             :         //       DATE WRITTEN   July 2005
    2499             : 
    2500             :         // PURPOSE OF THIS SUBROUTINE:
    2501             :         //   Report if the setpoint temperature has been met.
    2502             :         //   Add calculation of how far away from setpoint and if setpoint was not met
    2503             :         //   during all times and during occupancy.
    2504             : 
    2505             :         // Using/Aliasing
    2506             :         using namespace OutputReportPredefined;
    2507      299088 :         auto &deviationFromSetPtThresholdClg = state.dataHVACGlobal->deviationFromSetPtThresholdClg;
    2508      299088 :         auto &deviationFromSetPtThresholdHtg = state.dataHVACGlobal->deviationFromSetPtThresholdHtg;
    2509             : 
    2510             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2511             :         Real64 SensibleLoadPredictedNoAdj;
    2512             :         Real64 deltaT;
    2513             :         int iZone;
    2514             :         bool testHeating;
    2515             :         bool testCooling;
    2516             : 
    2517             :         // Get the load predicted - the sign will indicate if heating or cooling
    2518             :         // was called for
    2519      299088 :         state.dataThermalComforts->AnyZoneNotMetHeating = 0.0;
    2520      299088 :         state.dataThermalComforts->AnyZoneNotMetCooling = 0.0;
    2521      299088 :         state.dataThermalComforts->AnyZoneNotMetOccupied = 0.0;
    2522      299088 :         state.dataThermalComforts->AnyZoneNotMetHeatingOccupied = 0.0;
    2523      299088 :         state.dataThermalComforts->AnyZoneNotMetCoolingOccupied = 0.0;
    2524     2109216 :         for (iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    2525     1810128 :             SensibleLoadPredictedNoAdj = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(iZone).TotalOutputRequired;
    2526     1810128 :             state.dataThermalComforts->ThermalComfortSetPoint(iZone).notMetCooling = 0.0;
    2527     1810128 :             state.dataThermalComforts->ThermalComfortSetPoint(iZone).notMetHeating = 0.0;
    2528     1810128 :             state.dataThermalComforts->ThermalComfortSetPoint(iZone).notMetCoolingOccupied = 0.0;
    2529     1810128 :             state.dataThermalComforts->ThermalComfortSetPoint(iZone).notMetHeatingOccupied = 0.0;
    2530             : 
    2531     1810128 :             testHeating = (state.dataHeatBalFanSys->TempControlType(iZone) != DataHVACGlobals::ThermostatType::SingleCooling);
    2532     1810128 :             testCooling = (state.dataHeatBalFanSys->TempControlType(iZone) != DataHVACGlobals::ThermostatType::SingleHeating);
    2533             : 
    2534     1810128 :             if (testHeating && (SensibleLoadPredictedNoAdj > 0)) { // heating
    2535      551142 :                 if (state.dataRoomAirMod->AirModel(iZone).AirModelType != DataRoomAirModel::RoomAirModel::Mixing) {
    2536        2304 :                     deltaT = state.dataHeatBalFanSys->TempTstatAir(iZone) - state.dataHeatBalFanSys->ZoneThermostatSetPointLo(iZone);
    2537             :                 } else {
    2538      548838 :                     if (state.dataZoneTempPredictorCorrector->NumOnOffCtrZone > 0) {
    2539        2016 :                         deltaT = state.dataZoneTempPredictorCorrector->zoneHeatBalance(iZone).ZTAV -
    2540        1008 :                                  state.dataHeatBalFanSys->ZoneThermostatSetPointLoAver(iZone);
    2541             :                     } else {
    2542     1095660 :                         deltaT = state.dataZoneTempPredictorCorrector->zoneHeatBalance(iZone).ZTAV -
    2543      547830 :                                  state.dataHeatBalFanSys->ZoneThermostatSetPointLo(iZone);
    2544             :                     }
    2545             :                 }
    2546     1102284 :                 if (deltaT < deviationFromSetPtThresholdHtg) {
    2547      180304 :                     state.dataThermalComforts->ThermalComfortSetPoint(iZone).notMetHeating = state.dataGlobal->TimeStepZone;
    2548      180304 :                     state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetHeating += state.dataGlobal->TimeStepZone;
    2549      180304 :                     if (state.dataThermalComforts->AnyZoneNotMetHeating == 0.0)
    2550       38721 :                         state.dataThermalComforts->AnyZoneNotMetHeating = state.dataGlobal->TimeStepZone;
    2551      180304 :                     if (state.dataThermalComforts->ThermalComfortInASH55(iZone).ZoneIsOccupied) {
    2552       39716 :                         state.dataThermalComforts->ThermalComfortSetPoint(iZone).notMetHeatingOccupied = state.dataGlobal->TimeStepZone;
    2553       39716 :                         state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetHeatingOccupied += state.dataGlobal->TimeStepZone;
    2554       39716 :                         if (state.dataThermalComforts->AnyZoneNotMetHeatingOccupied == 0.0)
    2555       10186 :                             state.dataThermalComforts->AnyZoneNotMetHeatingOccupied = state.dataGlobal->TimeStepZone;
    2556       39716 :                         if (state.dataThermalComforts->AnyZoneNotMetOccupied == 0.0)
    2557       10177 :                             state.dataThermalComforts->AnyZoneNotMetOccupied = state.dataGlobal->TimeStepZone;
    2558             :                     }
    2559             :                 }
    2560     1258986 :             } else if (testCooling && (SensibleLoadPredictedNoAdj < 0)) { // cooling
    2561      508967 :                 if (state.dataRoomAirMod->AirModel(iZone).AirModelType != DataRoomAirModel::RoomAirModel::Mixing) {
    2562        1848 :                     deltaT = state.dataHeatBalFanSys->TempTstatAir(iZone) - state.dataHeatBalFanSys->ZoneThermostatSetPointHi(iZone);
    2563             :                 } else {
    2564      507119 :                     if (state.dataZoneTempPredictorCorrector->NumOnOffCtrZone > 0) {
    2565        1060 :                         deltaT = state.dataZoneTempPredictorCorrector->zoneHeatBalance(iZone).ZTAV -
    2566         530 :                                  state.dataHeatBalFanSys->ZoneThermostatSetPointHiAver(iZone);
    2567             :                     } else {
    2568     1013178 :                         deltaT = state.dataZoneTempPredictorCorrector->zoneHeatBalance(iZone).ZTAV -
    2569      506589 :                                  state.dataHeatBalFanSys->ZoneThermostatSetPointHi(iZone);
    2570             :                     }
    2571             :                 }
    2572             : 
    2573      508967 :                 if (state.dataHeatBal->Zone(iZone).HasAdjustedReturnTempByITE) {
    2574         960 :                     deltaT = state.dataHeatBalFanSys->TempTstatAir(iZone) - state.dataHeatBal->Zone(iZone).AdjustedReturnTempByITE;
    2575             :                 }
    2576      508967 :                 if (deltaT > deviationFromSetPtThresholdClg) {
    2577       65058 :                     state.dataThermalComforts->ThermalComfortSetPoint(iZone).notMetCooling = state.dataGlobal->TimeStepZone;
    2578       65058 :                     state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetCooling += state.dataGlobal->TimeStepZone;
    2579       65058 :                     if (state.dataThermalComforts->AnyZoneNotMetCooling == 0.0)
    2580       28100 :                         state.dataThermalComforts->AnyZoneNotMetCooling = state.dataGlobal->TimeStepZone;
    2581       65058 :                     if (state.dataThermalComforts->ThermalComfortInASH55(iZone).ZoneIsOccupied) {
    2582       36096 :                         state.dataThermalComforts->ThermalComfortSetPoint(iZone).notMetCoolingOccupied = state.dataGlobal->TimeStepZone;
    2583       36096 :                         state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetCoolingOccupied += state.dataGlobal->TimeStepZone;
    2584       36096 :                         if (state.dataThermalComforts->AnyZoneNotMetCoolingOccupied == 0.0)
    2585       15771 :                             state.dataThermalComforts->AnyZoneNotMetCoolingOccupied = state.dataGlobal->TimeStepZone;
    2586       36096 :                         if (state.dataThermalComforts->AnyZoneNotMetOccupied == 0.0)
    2587       15752 :                             state.dataThermalComforts->AnyZoneNotMetOccupied = state.dataGlobal->TimeStepZone;
    2588             :                     }
    2589             :                 }
    2590             :             }
    2591             :         }
    2592      299088 :         state.dataThermalComforts->TotalAnyZoneNotMetHeating += state.dataThermalComforts->AnyZoneNotMetHeating;
    2593      299088 :         state.dataThermalComforts->TotalAnyZoneNotMetCooling += state.dataThermalComforts->AnyZoneNotMetCooling;
    2594      299088 :         state.dataThermalComforts->TotalAnyZoneNotMetHeatingOccupied += state.dataThermalComforts->AnyZoneNotMetHeatingOccupied;
    2595      299088 :         state.dataThermalComforts->TotalAnyZoneNotMetCoolingOccupied += state.dataThermalComforts->AnyZoneNotMetCoolingOccupied;
    2596      299088 :         state.dataThermalComforts->TotalAnyZoneNotMetOccupied += state.dataThermalComforts->AnyZoneNotMetOccupied;
    2597             : 
    2598             :         // was EndEnvrnsFlag prior to CR7562
    2599      299088 :         if (state.dataGlobal->EndDesignDayEnvrnsFlag) {
    2600        5903 :             for (iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    2601       20460 :                 PreDefTableEntry(state,
    2602        5115 :                                  state.dataOutRptPredefined->pdchULnotMetHeat,
    2603        5115 :                                  state.dataHeatBal->Zone(iZone).Name,
    2604        5115 :                                  state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetHeating);
    2605       20460 :                 PreDefTableEntry(state,
    2606        5115 :                                  state.dataOutRptPredefined->pdchULnotMetCool,
    2607        5115 :                                  state.dataHeatBal->Zone(iZone).Name,
    2608        5115 :                                  state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetCooling);
    2609       20460 :                 PreDefTableEntry(state,
    2610        5115 :                                  state.dataOutRptPredefined->pdchULnotMetHeatOcc,
    2611        5115 :                                  state.dataHeatBal->Zone(iZone).Name,
    2612        5115 :                                  state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetHeatingOccupied);
    2613       20460 :                 PreDefTableEntry(state,
    2614        5115 :                                  state.dataOutRptPredefined->pdchULnotMetCoolOcc,
    2615        5115 :                                  state.dataHeatBal->Zone(iZone).Name,
    2616        5115 :                                  state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetCoolingOccupied);
    2617             :             }
    2618         788 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchULnotMetHeat, "Facility", state.dataThermalComforts->TotalAnyZoneNotMetHeating);
    2619         788 :             PreDefTableEntry(state, state.dataOutRptPredefined->pdchULnotMetCool, "Facility", state.dataThermalComforts->TotalAnyZoneNotMetCooling);
    2620        2364 :             PreDefTableEntry(
    2621        1576 :                 state, state.dataOutRptPredefined->pdchULnotMetHeatOcc, "Facility", state.dataThermalComforts->TotalAnyZoneNotMetHeatingOccupied);
    2622        2364 :             PreDefTableEntry(
    2623        1576 :                 state, state.dataOutRptPredefined->pdchULnotMetCoolOcc, "Facility", state.dataThermalComforts->TotalAnyZoneNotMetCoolingOccupied);
    2624             :             // set value for ABUPS report
    2625         788 :             state.dataOutRptPredefined->TotalNotMetHeatingOccupiedForABUPS = state.dataThermalComforts->TotalAnyZoneNotMetHeatingOccupied;
    2626         788 :             state.dataOutRptPredefined->TotalNotMetCoolingOccupiedForABUPS = state.dataThermalComforts->TotalAnyZoneNotMetCoolingOccupied;
    2627         788 :             state.dataOutRptPredefined->TotalNotMetOccupiedForABUPS = state.dataThermalComforts->TotalAnyZoneNotMetOccupied;
    2628             :             // reset counters
    2629        5903 :             for (iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    2630        5115 :                 state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetHeating = 0.0;
    2631        5115 :                 state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetCooling = 0.0;
    2632        5115 :                 state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetHeatingOccupied = 0.0;
    2633        5115 :                 state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetCoolingOccupied = 0.0;
    2634             :             }
    2635         788 :             state.dataThermalComforts->TotalAnyZoneNotMetHeating = 0.0;
    2636         788 :             state.dataThermalComforts->TotalAnyZoneNotMetCooling = 0.0;
    2637         788 :             state.dataThermalComforts->TotalAnyZoneNotMetHeatingOccupied = 0.0;
    2638         788 :             state.dataThermalComforts->TotalAnyZoneNotMetCoolingOccupied = 0.0;
    2639         788 :             state.dataThermalComforts->TotalAnyZoneNotMetOccupied = 0.0;
    2640             :             // report how the aggregation is conducted
    2641         788 :             switch (state.dataGlobal->KindOfSim) {
    2642         767 :             case DataGlobalConstants::KindOfSim::DesignDay: {
    2643         767 :                 addFootNoteSubTable(state, state.dataOutRptPredefined->pdstUnmetLoads, "Aggregated over the Design Days");
    2644         767 :             } break;
    2645           3 :             case DataGlobalConstants::KindOfSim::RunPeriodDesign: {
    2646           3 :                 addFootNoteSubTable(state, state.dataOutRptPredefined->pdstUnmetLoads, "Aggregated over the RunPeriods for Design");
    2647           3 :             } break;
    2648           2 :             case DataGlobalConstants::KindOfSim::RunPeriodWeather: {
    2649           2 :                 addFootNoteSubTable(state, state.dataOutRptPredefined->pdstUnmetLoads, "Aggregated over the RunPeriods for Weather");
    2650           2 :             } break;
    2651          16 :             default:
    2652          16 :                 break;
    2653             :             }
    2654             :         }
    2655      299088 :     }
    2656             : 
    2657           0 :     void ResetSetPointMet(EnergyPlusData &state)
    2658             :     {
    2659             :         // Jason Glazer - October 2015
    2660             :         // Reset set point not met table gathering arrays to zero for multi-year simulations
    2661             :         // so that only last year is reported in tabular reports
    2662             :         int iZone;
    2663           0 :         for (iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
    2664           0 :             state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetHeating = 0.0;
    2665           0 :             state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetCooling = 0.0;
    2666           0 :             state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetHeatingOccupied = 0.0;
    2667           0 :             state.dataThermalComforts->ThermalComfortSetPoint(iZone).totalNotMetCoolingOccupied = 0.0;
    2668             :         }
    2669           0 :         state.dataThermalComforts->TotalAnyZoneNotMetHeating = 0.0;
    2670           0 :         state.dataThermalComforts->TotalAnyZoneNotMetCooling = 0.0;
    2671           0 :         state.dataThermalComforts->TotalAnyZoneNotMetHeatingOccupied = 0.0;
    2672           0 :         state.dataThermalComforts->TotalAnyZoneNotMetCoolingOccupied = 0.0;
    2673           0 :         state.dataThermalComforts->TotalAnyZoneNotMetOccupied = 0.0;
    2674           0 :     }
    2675             : 
    2676         973 :     void CalcThermalComfortAdaptiveASH55(
    2677             :         EnergyPlusData &state,
    2678             :         bool const initiate,              // true if supposed to initiate
    2679             :         Optional_bool_const wthrsim,      // true if this is a weather simulation
    2680             :         Optional<Real64 const> avgdrybulb // approximate avg drybulb for design day.  will be used as previous period in design day
    2681             :     )
    2682             :     {
    2683             : 
    2684             :         // SUBROUTINE INFORMATION:
    2685             :         //       AUTHOR         Tyler Hoyt
    2686             :         //       DATE WRITTEN   July 2011
    2687             : 
    2688             :         // PURPOSE OF THIS SUBROUTINE:
    2689             :         // Sets up and carries out ASHRAE55-2010 adaptive comfort model calculations.
    2690             :         // Output provided are state variables for the 80% and 90% acceptability limits
    2691             :         // in the model, the comfort temperature, and the 30-day running average or
    2692             :         // monthly average outdoor air temperature as parsed from the .STAT file.
    2693             : 
    2694             :         // METHODOLOGY EMPLOYED:
    2695             :         // In order for the calculations to be possible the user must provide either
    2696             :         // a .STAT file or .EPW file for the purpose of computing a monthly average
    2697             :         // temperature or thirty-day running average. The subroutine need only open
    2698             :         // the relevant file once to initialize, and then operates within the loop.
    2699             : 
    2700             :         // Using/Aliasing
    2701         973 :         auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    2702             :         using OutputReportTabular::GetColumnUsingTabs;
    2703             :         using OutputReportTabular::StrToReal;
    2704             : 
    2705             :         // SUBROUTINE PARAMETER DEFINITIONS:
    2706             : 
    2707             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2708        1933 :         std::string lineAvg;
    2709        1933 :         std::string epwLine;
    2710             :         Real64 dryBulb;
    2711             :         Real64 tComf;
    2712             :         Real64 numOccupants;
    2713             :         int readStat;
    2714             :         int jStartDay;
    2715             :         int calcStartDay;
    2716             :         int calcStartHr;
    2717             :         int calcEndDay;
    2718             :         int calcEndHr;
    2719             :         std::string::size_type pos;
    2720             :         int ind;
    2721             :         int i;
    2722             :         int j;
    2723             :         bool weathersimulation;
    2724             :         Real64 inavgdrybulb;
    2725             : 
    2726         973 :         if (initiate) { // not optional on initiate=true.  would otherwise check for presence
    2727          13 :             weathersimulation = wthrsim;
    2728          13 :             state.dataThermalComforts->avgDryBulbASH = 0.0;
    2729          13 :             state.dataThermalComforts->runningAverageASH = 0.0;
    2730          13 :             state.dataThermalComforts->monthlyTemp = 0.0;
    2731          13 :             inavgdrybulb = avgdrybulb;
    2732             :         } else {
    2733         960 :             weathersimulation = false;
    2734         960 :             inavgdrybulb = 0.0;
    2735             :         }
    2736             : 
    2737         973 :         if (initiate && weathersimulation) {
    2738           5 :             const bool statFileExists = FileSystem::fileExists(state.files.inStatFilePath.filePath);
    2739           5 :             const bool epwFileExists = FileSystem::fileExists(state.files.inputWeatherFilePath.filePath);
    2740             : 
    2741           5 :             readStat = 0;
    2742           5 :             if (statFileExists) {
    2743          10 :                 auto statFile = state.files.inStatFilePath.open(state, "CalcThermalComfortAdapctiveASH55");
    2744         915 :                 while (statFile.good()) {
    2745         915 :                     auto lineIn = statFile.readLine();
    2746         460 :                     if (has(lineIn.data, "Monthly Statistics for Dry Bulb temperatures")) {
    2747          40 :                         for (i = 1; i <= 7; ++i) {
    2748          35 :                             lineIn = statFile.readLine();
    2749             :                         }
    2750           5 :                         lineIn = statFile.readLine();
    2751           5 :                         lineAvg = lineIn.data;
    2752           5 :                         break;
    2753             :                     }
    2754             :                 }
    2755          65 :                 for (i = 1; i <= 12; ++i) {
    2756          60 :                     state.dataThermalComforts->monthlyTemp(i) = StrToReal(GetColumnUsingTabs(lineAvg, i + 2));
    2757             :                 }
    2758           5 :                 state.dataThermalComforts->useStatData = true;
    2759           0 :             } else if (epwFileExists) {
    2760             :                 // determine number of days in year
    2761             :                 int DaysInYear;
    2762           0 :                 if (state.dataEnvrn->CurrentYearIsLeapYear) {
    2763           0 :                     DaysInYear = 366;
    2764             :                 } else {
    2765           0 :                     DaysInYear = 365;
    2766             :                 }
    2767           0 :                 state.dataThermalComforts->DailyAveOutTemp = 0.0;
    2768             : 
    2769           0 :                 auto epwFile = state.files.inputWeatherFilePath.open(state, "CalcThermalComfortAdaptiveASH55");
    2770           0 :                 for (i = 1; i <= 8; ++i) { // Headers
    2771           0 :                     epwLine = epwFile.readLine().data;
    2772             :                 }
    2773           0 :                 jStartDay = state.dataEnvrn->DayOfYear - 1;
    2774           0 :                 calcStartDay = jStartDay - 30;
    2775           0 :                 if (calcStartDay >= 0) {
    2776           0 :                     calcStartHr = 24 * calcStartDay + 1;
    2777           0 :                     for (i = 1; i <= calcStartHr - 1; ++i) {
    2778           0 :                         epwFile.readLine();
    2779             :                     }
    2780           0 :                     for (i = 1; i <= 30; ++i) {
    2781           0 :                         state.dataThermalComforts->avgDryBulbASH = 0.0;
    2782           0 :                         for (j = 1; j <= 24; ++j) {
    2783           0 :                             epwLine = epwFile.readLine().data;
    2784           0 :                             for (ind = 1; ind <= 6; ++ind) {
    2785           0 :                                 pos = index(epwLine, ',');
    2786           0 :                                 epwLine.erase(0, pos + 1);
    2787             :                             }
    2788           0 :                             pos = index(epwLine, ',');
    2789           0 :                             dryBulb = StrToReal(epwLine.substr(0, pos));
    2790           0 :                             state.dataThermalComforts->avgDryBulbASH += (dryBulb / 24.0);
    2791             :                         }
    2792           0 :                         state.dataThermalComforts->DailyAveOutTemp(i) = state.dataThermalComforts->avgDryBulbASH;
    2793             :                     }
    2794             :                 } else { // Do special things for wrapping the epw
    2795           0 :                     calcEndDay = jStartDay;
    2796           0 :                     calcStartDay += DaysInYear;
    2797           0 :                     calcEndHr = 24 * calcEndDay;
    2798           0 :                     calcStartHr = 24 * calcStartDay + 1;
    2799           0 :                     for (i = 1; i <= calcEndDay; ++i) {
    2800           0 :                         state.dataThermalComforts->avgDryBulbASH = 0.0;
    2801           0 :                         for (j = 1; j <= 24; ++j) {
    2802           0 :                             epwLine = epwFile.readLine().data;
    2803           0 :                             for (ind = 1; ind <= 6; ++ind) {
    2804           0 :                                 pos = index(epwLine, ',');
    2805           0 :                                 epwLine.erase(0, pos + 1);
    2806             :                             }
    2807           0 :                             pos = index(epwLine, ',');
    2808           0 :                             dryBulb = StrToReal(epwLine.substr(0, pos));
    2809           0 :                             state.dataThermalComforts->avgDryBulbASH += (dryBulb / 24.0);
    2810             :                         }
    2811           0 :                         state.dataThermalComforts->DailyAveOutTemp(i + 30 - calcEndDay) = state.dataThermalComforts->avgDryBulbASH;
    2812             :                     }
    2813           0 :                     for (i = calcEndHr + 1; i <= calcStartHr - 1; ++i) {
    2814           0 :                         epwLine = epwFile.readLine().data;
    2815             :                     }
    2816           0 :                     for (i = 1; i <= 30 - calcEndDay; ++i) {
    2817           0 :                         state.dataThermalComforts->avgDryBulbASH = 0.0;
    2818           0 :                         for (j = 1; j <= 24; ++j) {
    2819           0 :                             epwLine = epwFile.readLine().data;
    2820           0 :                             for (ind = 1; ind <= 6; ++ind) {
    2821           0 :                                 pos = index(epwLine, ',');
    2822           0 :                                 epwLine.erase(0, pos + 1);
    2823             :                             }
    2824           0 :                             pos = index(epwLine, ',');
    2825           0 :                             dryBulb = StrToReal(epwLine.substr(0, pos));
    2826           0 :                             state.dataThermalComforts->avgDryBulbASH += (dryBulb / 24.0);
    2827             :                         }
    2828           0 :                         state.dataThermalComforts->DailyAveOutTemp(i) = state.dataThermalComforts->avgDryBulbASH;
    2829             :                     }
    2830             :                 }
    2831           0 :                 state.dataThermalComforts->useEpwData = true;
    2832           5 :             }
    2833         968 :         } else if (initiate && !weathersimulation) {
    2834           8 :             state.dataThermalComforts->runningAverageASH = inavgdrybulb;
    2835           8 :             state.dataThermalComforts->monthlyTemp = inavgdrybulb;
    2836           8 :             state.dataThermalComforts->avgDryBulbASH = 0.0;
    2837             :         }
    2838             : 
    2839         973 :         if (initiate) return;
    2840             : 
    2841         960 :         if (state.dataGlobal->BeginDayFlag && state.dataThermalComforts->useEpwData) {
    2842             :             // Update the running average, reset the daily avg
    2843           0 :             state.dataThermalComforts->DailyAveOutTemp(30) = state.dataThermalComforts->avgDryBulbASH;
    2844           0 :             Real64 sum = 0.0;
    2845           0 :             for (i = 1; i <= 29; i++) {
    2846           0 :                 sum += state.dataThermalComforts->DailyAveOutTemp(i);
    2847             :             }
    2848           0 :             state.dataThermalComforts->runningAverageASH = (sum + state.dataThermalComforts->avgDryBulbASH) / 30.0;
    2849           0 :             for (i = 1; i <= 29; i++) {
    2850           0 :                 state.dataThermalComforts->DailyAveOutTemp(i) = state.dataThermalComforts->DailyAveOutTemp(i + 1);
    2851             :             }
    2852           0 :             state.dataThermalComforts->avgDryBulbASH = 0.0;
    2853             :         }
    2854             : 
    2855             :         // If exists BeginMonthFlag we can use it to call InvJulianDay once per month.
    2856         960 :         if (state.dataGlobal->BeginDayFlag && state.dataThermalComforts->useStatData) {
    2857             :             //  CALL InvJulianDay(DayOfYear,pMonth,pDay,0)
    2858             :             //  runningAverageASH = monthlyTemp(pMonth)
    2859           0 :             state.dataThermalComforts->runningAverageASH = state.dataThermalComforts->monthlyTemp(state.dataEnvrn->Month);
    2860             :         }
    2861             : 
    2862             :         // Update the daily average
    2863             :         // IF (BeginHourFlag .and. useEpwData) THEN
    2864         960 :         if (state.dataGlobal->BeginHourFlag) {
    2865         192 :             state.dataThermalComforts->avgDryBulbASH += (state.dataEnvrn->OutDryBulbTemp / 24.0);
    2866             :         }
    2867             : 
    2868        2496 :         for (state.dataThermalComforts->PeopleNum = 1; state.dataThermalComforts->PeopleNum <= state.dataHeatBal->TotPeople;
    2869        1536 :              ++state.dataThermalComforts->PeopleNum) {
    2870        1536 :             if (!state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).AdaptiveASH55) continue;
    2871        1536 :             state.dataThermalComforts->ZoneNum = state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ZonePtr;
    2872        1536 :             state.dataThermalComforts->AirTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataThermalComforts->ZoneNum).ZTAVComf;
    2873        1536 :             if (state.dataRoomAirMod->anyNonMixingRoomAirModel) {
    2874         288 :                 if (state.dataRoomAirMod->IsZoneDV(state.dataThermalComforts->ZoneNum) ||
    2875           0 :                     state.dataRoomAirMod->IsZoneUI(state.dataThermalComforts->ZoneNum)) {
    2876         288 :                     state.dataThermalComforts->AirTemp = state.dataRoomAirMod->TCMF(state.dataThermalComforts->ZoneNum);
    2877             :                 }
    2878             :             }
    2879        1536 :             state.dataThermalComforts->RadTemp = CalcRadTemp(state, state.dataThermalComforts->PeopleNum);
    2880        1536 :             state.dataThermalComforts->OpTemp = (state.dataThermalComforts->AirTemp + state.dataThermalComforts->RadTemp) / 2.0;
    2881        1536 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortOpTemp =
    2882        1536 :                 state.dataThermalComforts->OpTemp;
    2883        1536 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ASHRAE55RunningMeanOutdoorTemp =
    2884        1536 :                 state.dataThermalComforts->runningAverageASH;
    2885        1536 :             if (state.dataThermalComforts->runningAverageASH >= 10.0 && state.dataThermalComforts->runningAverageASH <= 33.5) {
    2886             :                 // Calculate the comfort here  (people/output handling loop)
    2887        1536 :                 numOccupants = state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).NumberOfPeople *
    2888         768 :                                GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).NumberOfPeoplePtr);
    2889         768 :                 tComf = 0.31 * state.dataThermalComforts->runningAverageASH + 17.8;
    2890         768 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).TComfASH55 = tComf;
    2891         768 :                 if (numOccupants > 0) {
    2892         438 :                     if (state.dataThermalComforts->OpTemp < tComf + 2.5 && state.dataThermalComforts->OpTemp > tComf - 2.5) {
    2893             :                         // 80% and 90% limits okay
    2894         336 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveASH5590 = 1;
    2895         336 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveASH5580 = 1;
    2896         102 :                     } else if (state.dataThermalComforts->OpTemp < tComf + 3.5 && state.dataThermalComforts->OpTemp > tComf - 3.5) {
    2897             :                         // 80% only
    2898          41 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveASH5590 = 0;
    2899          41 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveASH5580 = 1;
    2900          41 :                         state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).TimeNotMetASH5590 += SysTimeElapsed;
    2901             :                     } else {
    2902             :                         // Neither
    2903          61 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveASH5590 = 0;
    2904          61 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveASH5580 = 0;
    2905          61 :                         state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).TimeNotMetASH5580 += SysTimeElapsed;
    2906          61 :                         state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).TimeNotMetASH5590 += SysTimeElapsed;
    2907             :                     }
    2908             :                 } else {
    2909             :                     // Unoccupied
    2910         330 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveASH5590 = -1;
    2911         330 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveASH5580 = -1;
    2912             :                 }
    2913             :             } else {
    2914             :                 // Monthly temp out of range
    2915         768 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveASH5590 = -1;
    2916         768 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveASH5580 = -1;
    2917         768 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).TComfASH55 = -1.0;
    2918             :             }
    2919             :         }
    2920             :     }
    2921             : 
    2922         291 :     void CalcThermalComfortAdaptiveCEN15251(
    2923             :         EnergyPlusData &state,
    2924             :         bool const initiate,              // true if supposed to initiate
    2925             :         Optional_bool_const wthrsim,      // true if this is a weather simulation
    2926             :         Optional<Real64 const> avgdrybulb // approximate avg drybulb for design day.  will be used as previous period in design day
    2927             :     )
    2928             :     {
    2929             : 
    2930             :         // SUBROUTINE INFORMATION:
    2931             :         //       AUTHOR         Tyler Hoyt
    2932             :         //       DATE WRITTEN   July 2011
    2933             : 
    2934             :         // PURPOSE OF THIS SUBROUTINE:
    2935             :         // Sets up and carries out CEN-15251 adaptive comfort model calculations.
    2936             :         // Output provided are state variables for the Category I, II, and III
    2937             :         // limits of the model, the comfort temperature, and the 5-day weighted
    2938             :         // moving average of the outdoor air temperature.
    2939             : 
    2940             :         // Using/Aliasing
    2941         291 :         auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    2942             :         using OutputReportTabular::GetColumnUsingTabs;
    2943             :         using OutputReportTabular::StrToReal;
    2944             : 
    2945             :         // SUBROUTINE PARAMETER DEFINITIONS:
    2946             :         static Real64 constexpr alpha(0.8);
    2947             :         static constexpr std::array<Real64, 7> alpha_pow = {0.262144, 0.32768, 0.4096, 0.512, 0.64, 0.8, 1.0}; // alpha^(6-0)
    2948             : 
    2949             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2950         579 :         std::string epwLine;
    2951             :         Real64 dryBulb;
    2952             :         Real64 tComf;
    2953             :         Real64 tComfLow;
    2954             :         Real64 numOccupants;
    2955             :         int readStat;
    2956             :         int jStartDay;
    2957             :         int calcStartDay;
    2958             :         int calcStartHr;
    2959             :         int calcEndDay;
    2960             :         int calcEndHr;
    2961             :         std::string::size_type pos;
    2962             :         int ind;
    2963             :         int i;
    2964             :         int j;
    2965             :         bool weathersimulation;
    2966             :         Real64 inavgdrybulb;
    2967         291 :         int constexpr numHeaderRowsInEpw = 8;
    2968             : 
    2969         291 :         if (initiate) { // not optional on initiate=true.  would otherwise check for presence
    2970           3 :             weathersimulation = wthrsim;
    2971           3 :             inavgdrybulb = avgdrybulb;
    2972           3 :             state.dataThermalComforts->avgDryBulbCEN = 0.0;
    2973           3 :             state.dataThermalComforts->runningAverageCEN = 0.0;
    2974             :         } else {
    2975         288 :             weathersimulation = false;
    2976         288 :             inavgdrybulb = 0.0;
    2977             :         }
    2978             : 
    2979         291 :         if (initiate && weathersimulation) {
    2980           1 :             const bool epwFileExists = FileSystem::fileExists(state.files.inputWeatherFilePath.filePath);
    2981           1 :             readStat = 0;
    2982           1 :             if (epwFileExists) {
    2983             :                 // determine number of days in year
    2984             :                 int DaysInYear;
    2985           1 :                 if (state.dataEnvrn->CurrentYearIsLeapYear) {
    2986           0 :                     DaysInYear = 366;
    2987             :                 } else {
    2988           1 :                     DaysInYear = 365;
    2989             :                 }
    2990             : 
    2991           2 :                 auto epwFile = state.files.inputWeatherFilePath.open(state, "CalcThermalComfortAdaptiveCEN15251");
    2992           9 :                 for (i = 1; i <= numHeaderRowsInEpw; ++i) {
    2993           8 :                     epwFile.readLine();
    2994             :                 }
    2995           1 :                 jStartDay = state.dataEnvrn->DayOfYear - 1;
    2996           1 :                 calcStartDay = jStartDay - 7;
    2997           1 :                 if (calcStartDay > 0) {
    2998           1 :                     calcStartHr = 24 * calcStartDay + 1;
    2999        2713 :                     for (i = 1; i <= calcStartHr - 1; ++i) {
    3000        2712 :                         epwFile.readLine();
    3001             :                     }
    3002           1 :                     state.dataThermalComforts->runningAverageCEN = 0.0;
    3003           8 :                     for (i = 0; i < 7; ++i) {
    3004           7 :                         state.dataThermalComforts->avgDryBulbCEN = 0.0;
    3005         175 :                         for (j = 1; j <= 24; ++j) {
    3006         168 :                             epwLine = epwFile.readLine().data;
    3007        1176 :                             for (ind = 1; ind <= 6; ++ind) {
    3008        1008 :                                 pos = index(epwLine, ',');
    3009        1008 :                                 epwLine.erase(0, pos + 1);
    3010             :                             }
    3011         168 :                             pos = index(epwLine, ',');
    3012         168 :                             dryBulb = StrToReal(epwLine.substr(0, pos));
    3013         168 :                             state.dataThermalComforts->avgDryBulbCEN += (dryBulb / 24.0);
    3014             :                         }
    3015           7 :                         state.dataThermalComforts->runningAverageCEN += alpha_pow[i] * state.dataThermalComforts->avgDryBulbCEN;
    3016             :                     }
    3017             :                 } else { // Do special things for wrapping the epw
    3018           0 :                     calcEndDay = jStartDay;
    3019           0 :                     calcStartDay += DaysInYear;
    3020           0 :                     calcEndHr = 24 * calcEndDay;
    3021           0 :                     calcStartHr = 24 * calcStartDay + 1;
    3022           0 :                     for (i = 1; i <= calcEndDay; ++i) {
    3023           0 :                         state.dataThermalComforts->avgDryBulbCEN = 0.0;
    3024           0 :                         for (j = 1; j <= 24; ++j) {
    3025           0 :                             epwLine = epwFile.readLine().data;
    3026           0 :                             for (ind = 1; ind <= 6; ++ind) {
    3027           0 :                                 pos = index(epwLine, ',');
    3028           0 :                                 epwLine.erase(0, pos + 1);
    3029             :                             }
    3030           0 :                             pos = index(epwLine, ',');
    3031           0 :                             dryBulb = StrToReal(epwLine.substr(0, pos));
    3032           0 :                             state.dataThermalComforts->avgDryBulbCEN += (dryBulb / 24.0);
    3033             :                         }
    3034           0 :                         state.dataThermalComforts->runningAverageCEN += std::pow(alpha, calcEndDay - i) * state.dataThermalComforts->avgDryBulbCEN;
    3035             :                     }
    3036           0 :                     for (i = calcEndHr + 1; i <= calcStartHr - 1; ++i) {
    3037           0 :                         epwFile.readLine();
    3038             :                     }
    3039           0 :                     for (i = 0; i < 7 - calcEndDay; ++i) {
    3040           0 :                         state.dataThermalComforts->avgDryBulbCEN = 0.0;
    3041           0 :                         for (j = 1; j <= 24; ++j) {
    3042           0 :                             epwLine = epwFile.readLine().data;
    3043           0 :                             for (ind = 1; ind <= 6; ++ind) {
    3044           0 :                                 pos = index(epwLine, ',');
    3045           0 :                                 epwLine.erase(0, pos + 1);
    3046             :                             }
    3047           0 :                             pos = index(epwLine, ',');
    3048           0 :                             dryBulb = StrToReal(epwLine.substr(0, pos));
    3049           0 :                             state.dataThermalComforts->avgDryBulbCEN += (dryBulb / 24.0);
    3050             :                         }
    3051           0 :                         state.dataThermalComforts->runningAverageCEN += alpha_pow[i] * state.dataThermalComforts->avgDryBulbCEN;
    3052             :                     }
    3053             :                 }
    3054           1 :                 state.dataThermalComforts->runningAverageCEN *= (1.0 - alpha);
    3055           1 :                 state.dataThermalComforts->avgDryBulbCEN = 0.0;
    3056           1 :                 state.dataThermalComforts->useEpwDataCEN = true;
    3057           1 :                 state.dataThermalComforts->firstDaySet = true;
    3058           1 :             }
    3059         290 :         } else if (initiate && !weathersimulation) {
    3060           2 :             state.dataThermalComforts->runningAverageCEN = inavgdrybulb;
    3061           2 :             state.dataThermalComforts->avgDryBulbCEN = 0.0;
    3062             :         }
    3063         291 :         if (initiate) return;
    3064             : 
    3065         288 :         if (state.dataGlobal->BeginDayFlag && !state.dataThermalComforts->firstDaySet) {
    3066             :             // Update the running average, reset the daily avg
    3067           2 :             state.dataThermalComforts->runningAverageCEN =
    3068           2 :                 alpha * state.dataThermalComforts->runningAverageCEN + (1.0 - alpha) * state.dataThermalComforts->avgDryBulbCEN;
    3069           2 :             state.dataThermalComforts->avgDryBulbCEN = 0.0;
    3070             :         }
    3071             : 
    3072         288 :         state.dataThermalComforts->firstDaySet = false;
    3073             : 
    3074             :         // Update the daily average
    3075         288 :         if (state.dataGlobal->BeginHourFlag) {
    3076          48 :             state.dataThermalComforts->avgDryBulbCEN += (state.dataEnvrn->OutDryBulbTemp / 24.0);
    3077             :         }
    3078             : 
    3079         576 :         for (state.dataThermalComforts->PeopleNum = 1; state.dataThermalComforts->PeopleNum <= state.dataHeatBal->TotPeople;
    3080         288 :              ++state.dataThermalComforts->PeopleNum) {
    3081         288 :             if (!state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).AdaptiveCEN15251) continue;
    3082         288 :             state.dataThermalComforts->ZoneNum = state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).ZonePtr;
    3083         288 :             state.dataThermalComforts->AirTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataThermalComforts->ZoneNum).ZTAVComf;
    3084         288 :             if (state.dataRoomAirMod->anyNonMixingRoomAirModel) {
    3085         288 :                 if (state.dataRoomAirMod->IsZoneDV(state.dataThermalComforts->ZoneNum) ||
    3086           0 :                     state.dataRoomAirMod->IsZoneUI(state.dataThermalComforts->ZoneNum)) {
    3087         288 :                     state.dataThermalComforts->AirTemp = state.dataRoomAirMod->TCMF(state.dataThermalComforts->ZoneNum);
    3088             :                 }
    3089             :             }
    3090         288 :             state.dataThermalComforts->RadTemp = CalcRadTemp(state, state.dataThermalComforts->PeopleNum);
    3091         288 :             state.dataThermalComforts->OpTemp = (state.dataThermalComforts->AirTemp + state.dataThermalComforts->RadTemp) / 2.0;
    3092         288 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortOpTemp =
    3093         288 :                 state.dataThermalComforts->OpTemp;
    3094         288 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).CEN15251RunningMeanOutdoorTemp =
    3095         288 :                 state.dataThermalComforts->runningAverageCEN;
    3096         288 :             if (state.dataThermalComforts->runningAverageCEN >= 10.0 && state.dataThermalComforts->runningAverageCEN <= 30.0) {
    3097             :                 // Calculate the comfort here (people/output handling loop)
    3098         288 :                 numOccupants = state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).NumberOfPeople *
    3099         144 :                                GetCurrentScheduleValue(state, state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).NumberOfPeoplePtr);
    3100         144 :                 tComf = 0.33 * state.dataThermalComforts->runningAverageCEN + 18.8;
    3101         144 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).TComfCEN15251 = tComf;
    3102         144 :                 if (numOccupants > 0) {
    3103          78 :                     if (state.dataThermalComforts->runningAverageCEN < 15) {
    3104           0 :                         tComfLow = 23.75; // Lower limit is constant in this region
    3105             :                     } else {
    3106          78 :                         tComfLow = tComf;
    3107             :                     }
    3108          78 :                     if (state.dataThermalComforts->OpTemp < tComf + 2.0 && state.dataThermalComforts->OpTemp > tComfLow - 2.0) {
    3109             :                         // Within Cat I, II, III Limits
    3110          21 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatI = 1;
    3111          21 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatII = 1;
    3112          21 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatIII = 1;
    3113          57 :                     } else if (state.dataThermalComforts->OpTemp < tComf + 3.0 && state.dataThermalComforts->OpTemp > tComfLow - 3.0) {
    3114             :                         // Within Cat II, III Limits
    3115          16 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatI = 0;
    3116          16 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatII = 1;
    3117          16 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatIII = 1;
    3118          16 :                         state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).TimeNotMetCEN15251CatI += SysTimeElapsed;
    3119          41 :                     } else if (state.dataThermalComforts->OpTemp < tComf + 4.0 && state.dataThermalComforts->OpTemp > tComfLow - 4.0) {
    3120             :                         // Within Cat III Limits
    3121          25 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatI = 0;
    3122          25 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatII = 0;
    3123          25 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatIII = 1;
    3124          25 :                         state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).TimeNotMetCEN15251CatI += SysTimeElapsed;
    3125          25 :                         state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).TimeNotMetCEN15251CatII += SysTimeElapsed;
    3126             :                     } else {
    3127             :                         // None
    3128          16 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatI = 0;
    3129          16 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatII = 0;
    3130          16 :                         state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatIII = 0;
    3131          16 :                         state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).TimeNotMetCEN15251CatI += SysTimeElapsed;
    3132          16 :                         state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).TimeNotMetCEN15251CatII += SysTimeElapsed;
    3133          16 :                         state.dataHeatBal->People(state.dataThermalComforts->PeopleNum).TimeNotMetCEN15251CatIII += SysTimeElapsed;
    3134             :                     }
    3135             :                 } else {
    3136             :                     // Unoccupied
    3137          66 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatI = -1;
    3138          66 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatII = -1;
    3139          66 :                     state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatIII = -1;
    3140             :                 }
    3141             :             } else {
    3142             :                 // Monthly temp out of range
    3143         144 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatI = -1;
    3144         144 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatII = -1;
    3145         144 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ThermalComfortAdaptiveCEN15251CatIII = -1;
    3146         144 :                 state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).TComfCEN15251 = -1.0;
    3147             :             }
    3148             :         }
    3149             :     }
    3150             : 
    3151         264 :     void DynamicClothingModel(EnergyPlusData &state)
    3152             :     {
    3153             :         // SUBROUTINE INFORMATION:
    3154             :         //       AUTHOR         Kwang Ho Lee
    3155             :         //       DATE WRITTEN   June 2013
    3156             : 
    3157             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3158             :         Real64 TemporaryVariable;
    3159             : 
    3160         264 :         if (state.dataThermalComforts->TemporarySixAMTemperature < -5.0) {
    3161          96 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue = 1.0;
    3162         168 :         } else if ((state.dataThermalComforts->TemporarySixAMTemperature >= -5.0) && (state.dataThermalComforts->TemporarySixAMTemperature < 5.0)) {
    3163          72 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue =
    3164          72 :                 0.818 - 0.0364 * state.dataThermalComforts->TemporarySixAMTemperature;
    3165          96 :         } else if ((state.dataThermalComforts->TemporarySixAMTemperature >= 5.0) && (state.dataThermalComforts->TemporarySixAMTemperature < 26.0)) {
    3166          96 :             TemporaryVariable = -0.1635 - 0.0066 * state.dataThermalComforts->TemporarySixAMTemperature;
    3167          96 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue = std::pow(10.0, TemporaryVariable);
    3168           0 :         } else if (state.dataThermalComforts->TemporarySixAMTemperature >= 26.0) {
    3169           0 :             state.dataThermalComforts->ThermalComfortData(state.dataThermalComforts->PeopleNum).ClothingValue = 0.46;
    3170             :         }
    3171         264 :     }
    3172             : 
    3173             : } // namespace ThermalComfort
    3174             : 
    3175        2313 : } // namespace EnergyPlus

Generated by: LCOV version 1.13