LCOV - code coverage report
Current view: top level - EnergyPlus - UFADManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 656 946 69.3 %
Date: 2024-08-24 18:31:18 Functions: 7 7 100.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cmath>
      50             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Array1D.hh>
      53             : #include <ObjexxFCL/Fmath.hh>
      54             : #include <ObjexxFCL/member.functions.hh>
      55             : 
      56             : // EnergyPlus Headers
      57             : #include <EnergyPlus/Autosizing/Base.hh>
      58             : #include <EnergyPlus/ConvectionCoefficients.hh>
      59             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      60             : #include <EnergyPlus/DataEnvironment.hh>
      61             : #include <EnergyPlus/DataHVACGlobals.hh>
      62             : #include <EnergyPlus/DataHeatBalFanSys.hh>
      63             : #include <EnergyPlus/DataHeatBalSurface.hh>
      64             : #include <EnergyPlus/DataHeatBalance.hh>
      65             : #include <EnergyPlus/DataLoopNode.hh>
      66             : #include <EnergyPlus/DataRoomAirModel.hh>
      67             : #include <EnergyPlus/DataSizing.hh>
      68             : #include <EnergyPlus/DataSurfaces.hh>
      69             : #include <EnergyPlus/DataZoneEquipment.hh>
      70             : #include <EnergyPlus/General.hh>
      71             : #include <EnergyPlus/InternalHeatGains.hh>
      72             : #include <EnergyPlus/Psychrometrics.hh>
      73             : #include <EnergyPlus/UFADManager.hh>
      74             : #include <EnergyPlus/UtilityRoutines.hh>
      75             : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      76             : 
      77             : namespace EnergyPlus {
      78             : 
      79             : namespace RoomAir {
      80             : 
      81             :     // Module containing the routines dealing with the UnderFloor Air
      82             :     // Distribution zone model
      83             : 
      84             :     // MODULE INFORMATION:
      85             :     //       AUTHOR         Fred Buhl
      86             :     //       DATE WRITTEN   August 2005
      87             : 
      88             :     // PURPOSE OF THIS MODULE:
      89             :     // Encapsulate the routines that do the simulation of the UCSD UFAD non-uniform
      90             :     // zone models
      91             : 
      92             :     // METHODOLOGY EMPLOYED:
      93             :     // 2-node zone model with the node heights varying as a function of internal loads
      94             :     // and supply air flow (and other factors)
      95             : 
      96             :     // REFERENCES:
      97             :     // See the EnergyPlus Engineering Reference and the PhD thesis of Anna Liu, UC San Diego
      98             : 
      99             :     // OTHER NOTES:
     100             :     // na
     101             : 
     102             :     // Using/Aliasing
     103             :     using namespace DataLoopNode;
     104             :     using namespace DataEnvironment;
     105             :     using namespace DataHeatBalance;
     106             :     using namespace DataHeatBalSurface;
     107             :     using namespace DataSurfaces;
     108             :     using Convect::CalcDetailedHcInForDVModel;
     109             : 
     110       17315 :     void ManageUFAD(EnergyPlusData &state,
     111             :                     int const ZoneNum,               // index number for the specified zone
     112             :                     RoomAirModel const ZoneModelType // type of zone model; UCSDUFI = 6
     113             :     )
     114             :     {
     115             : 
     116             :         // SUBROUTINE INFORMATION:
     117             :         //       AUTHOR         Fred Buhl
     118             :         //       DATE WRITTEN   August, 2005
     119             :         //       MODIFIED       na
     120             :         //       RE-ENGINEERED  na
     121             : 
     122             :         // PURPOSE OF THIS SUBROUTINE:
     123             :         // Manages the simulation of the 2-node nonuniform zone models for underfloor air
     124             :         // distribution systems (UFAD). Called from RoomAirManager, ManageAirModel
     125             : 
     126             :         // METHODOLOGY EMPLOYED:
     127             :         // uses Init and Calc routines in the standard EPlus manner to manage the calculation
     128             :         // Note that much of the initialization is done in RoomAirManager, SharedDVCVUFDataInit
     129             : 
     130             :         // Using/Aliasing
     131             :         using namespace DataLoopNode;
     132             :         using namespace DataEnvironment;
     133             :         using namespace DataHeatBalance;
     134             :         using namespace DataHeatBalSurface;
     135             :         using namespace DataSurfaces;
     136             :         using Convect::CalcDetailedHcInForDVModel;
     137             : 
     138             :         // input was obtained in RoomAirManager, GetUFADIntZoneData
     139             : 
     140       17315 :         InitUFAD(state, ZoneNum, ZoneModelType); // initialize some module variables
     141             : 
     142       17315 :         switch (ZoneModelType) {
     143        3463 :         case RoomAirModel::UFADInt: { // UCSD UFAD interior zone model
     144             :             // simulate room airflow using the UCSDUFI model
     145        3463 :             CalcUFADInt(state, ZoneNum);
     146        3463 :         } break;
     147       13852 :         case RoomAirModel::UFADExt: { // UCSD UFAD exterior zone model
     148             :             // simulate room airflow using the UCSDUFE model
     149       13852 :             CalcUFADExt(state, ZoneNum);
     150       13852 :         } break;
     151           0 :         default:
     152           0 :             break;
     153             :         }
     154       17315 :     }
     155             : 
     156       17315 :     void InitUFAD(EnergyPlusData &state,
     157             :                   int const ZoneNum,
     158             :                   RoomAirModel const ZoneModelType // type of zone model; UCSDUFI = 6
     159             :     )
     160             :     {
     161             : 
     162             :         // SUBROUTINE INFORMATION:
     163             :         //       AUTHOR         Fred Buhl
     164             :         //       DATE WRITTEN   August 2005
     165             : 
     166             :         // PURPOSE OF THIS SUBROUTINE:
     167             :         // initialize arrays & variables used by the UCSD UFAD zone models
     168             : 
     169             :         // METHODOLOGY EMPLOYED:
     170             :         // Note that much of the initialization is done in RoomAirManager, SharedDVCVUFDataInit
     171             : 
     172       17315 :         Real64 NumShadesDown(0.0);
     173             : 
     174             :         // Do the one time initializations
     175       17315 :         if (state.dataUFADManager->MyOneTimeFlag) {
     176           1 :             state.dataUFADManager->HeightFloorSubzoneTop = 0.2;
     177           1 :             state.dataUFADManager->ThickOccupiedSubzoneMin = 0.2;
     178           1 :             state.dataUFADManager->HeightIntMassDefault = 2.0;
     179           1 :             state.dataUFADManager->MyOneTimeFlag = false;
     180           1 :             state.dataUFADManager->MySizeFlag.dimension(state.dataGlobal->NumOfZones, true);
     181             :         }
     182             : 
     183       17315 :         if (state.dataUFADManager->MySizeFlag(ZoneNum)) {
     184           5 :             SizeUFAD(state, ZoneNum, ZoneModelType);
     185           5 :             state.dataUFADManager->MySizeFlag(ZoneNum) = false;
     186             :         }
     187             : 
     188             :         // initialize these variables every timestep
     189             : 
     190       17315 :         state.dataUFADManager->HeightIntMass = state.dataUFADManager->HeightIntMassDefault;
     191       17315 :         state.dataRoomAir->ZoneUFADGamma(ZoneNum) = 0.0;
     192       17315 :         state.dataRoomAir->ZoneUFADPowInPlumes(ZoneNum) = 0.0;
     193       17315 :         NumShadesDown = 0.0;
     194       38093 :         for (int Ctd = state.dataRoomAir->PosZ_Window(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Window(ZoneNum).end; ++Ctd) {
     195       20778 :             int SurfNum = state.dataRoomAir->APos_Window(Ctd);
     196       20778 :             if (SurfNum == 0) continue;
     197       20778 :             auto &surf = state.dataSurface->Surface(SurfNum);
     198       20778 :             if (surf.ExtBoundCond == ExternalEnvironment || surf.ExtBoundCond == OtherSideCoefNoCalcExt ||
     199           0 :                 surf.ExtBoundCond == OtherSideCoefCalcExt || surf.ExtBoundCond == OtherSideCondModeledExt) {
     200       20778 :                 if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
     201           0 :                     ++NumShadesDown;
     202             :                 }
     203             :             }
     204             :         }
     205       17315 :         if (ZoneModelType == RoomAirModel::UFADExt) {
     206       13852 :             auto &zoneUE = state.dataRoomAir->ZoneUFAD(state.dataRoomAir->ZoneUFADPtr(ZoneNum));
     207       13852 :             zoneUE.ShadeDown = (zoneUE.NumExtWin > 1.0) && (NumShadesDown / zoneUE.NumExtWin >= 0.5);
     208             :         }
     209       17315 :     }
     210             : 
     211           5 :     void SizeUFAD(EnergyPlusData &state,
     212             :                   int const ZoneNum,
     213             :                   RoomAirModel const model // type of zone model; UCSDUFI = 6
     214             :     )
     215             :     {
     216             : 
     217             :         // SUBROUTINE INFORMATION:
     218             :         //       AUTHOR         Fred Buhl
     219             :         //       DATE WRITTEN   August 2005
     220             : 
     221             :         // PURPOSE OF THIS SUBROUTINE:
     222             :         // set some smart defaults for UFAD systems
     223             : 
     224             :         // METHODOLOGY EMPLOYED:
     225             :         // use data from Center for Built Environment
     226             : 
     227             :         using DataSizing::AutoSize;
     228             : 
     229             :         // This is for both UFADInt and UFADExt
     230           5 :         auto &zoneU = state.dataRoomAir->ZoneUFAD(state.dataRoomAir->ZoneUFADPtr(ZoneNum));
     231             : 
     232             :         std::string_view cCMO = (model == RoomAirModel::UFADExt) ? "RoomAirSettings:UnderFloorAirDistributionExterior"
     233           5 :                                                                  : "RoomAirSettings:UnderFloorAirDistributionInterior";
     234             : 
     235           5 :         Real64 NumberOfOccupants = 0.0;
     236          30 :         for (auto const &people : state.dataHeatBal->People) {
     237          25 :             if (people.ZonePtr == ZoneNum) NumberOfOccupants += people.NumberOfPeople;
     238           5 :         }
     239             : 
     240           5 :         if (model == RoomAirModel::UFADExt) {
     241             :             // calculate total window width in zone
     242          10 :             for (int Ctd = state.dataRoomAir->PosZ_Window(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Window(ZoneNum).end; ++Ctd) {
     243           6 :                 int SurfNum = state.dataRoomAir->APos_Window(Ctd);
     244           6 :                 if (SurfNum == 0) continue;
     245           6 :                 auto &surf = state.dataSurface->Surface(SurfNum);
     246           6 :                 if (surf.ExtBoundCond == ExternalEnvironment || surf.ExtBoundCond == OtherSideCoefNoCalcExt ||
     247           0 :                     surf.ExtBoundCond == OtherSideCoefCalcExt || surf.ExtBoundCond == OtherSideCondModeledExt) {
     248           6 :                     zoneU.WinWidth += surf.Width;
     249           6 :                     ++zoneU.NumExtWin;
     250             :                 }
     251             :             }
     252           4 :             if (zoneU.WinWidth <= 0.0) {
     253           0 :                 ShowWarningError(
     254             :                     state,
     255           0 :                     format("For RoomAirSettings:UnderFloorAirDistributionExterior for Zone {} there are no exterior windows.", zoneU.ZoneName));
     256           0 :                 ShowContinueError(state, "  The zone will be treated as a UFAD interior zone");
     257             :             }
     258             :         } // if (model == RoomAirModel::UFADExt)
     259             : 
     260           5 :         if (zoneU.DiffArea == AutoSize) {
     261           5 :             constexpr std::array<Real64, (int)Diffuser::Num> diffArea = {0.0075, 0.035, 0.0060, 0.03, 0.0075};
     262           5 :             zoneU.DiffArea = diffArea[(int)zoneU.DiffuserType];
     263             :             // 4 ft x 4 inches; 75 cfm per linear foot; area is .025 m2/m
     264             : 
     265           5 :             BaseSizer::reportSizerOutput(state, cCMO, zoneU.ZoneName, "Design effective area of diffuser", zoneU.DiffArea);
     266             :         }
     267           5 :         if (zoneU.DiffAngle == AutoSize) {
     268           5 :             constexpr std::array<Real64, (int)Diffuser::Num> diffAngle = {28.0, 45.0, 73.0, 15.0, 28.0};
     269           5 :             zoneU.DiffAngle = diffAngle[(int)zoneU.DiffuserType];
     270             : 
     271           5 :             BaseSizer::reportSizerOutput(state, cCMO, zoneU.ZoneName, "Angle between diffuser slots and the vertical", zoneU.DiffAngle);
     272             :         }
     273           5 :         if (zoneU.TransHeight == AutoSize) {
     274           0 :             zoneU.CalcTransHeight = true;
     275           0 :             zoneU.TransHeight = 0.0;
     276             :         } else {
     277           5 :             zoneU.CalcTransHeight = false;
     278             :         }
     279             : 
     280           5 :         if (zoneU.DiffuserType != Diffuser::Custom &&
     281           5 :             (zoneU.A_Kc != Constant::AutoCalculate || zoneU.B_Kc != Constant::AutoCalculate || zoneU.C_Kc != Constant::AutoCalculate ||
     282           5 :              zoneU.D_Kc != Constant::AutoCalculate || zoneU.E_Kc != Constant::AutoCalculate)) {
     283           0 :             ShowWarningError(state,
     284           0 :                              format("For {} for Zone {}, input for Coefficients A - E will be "
     285             :                                     "ignored when Floor Diffuser Type = {}.",
     286             :                                     cCMO,
     287           0 :                                     zoneU.ZoneName,
     288           0 :                                     diffuserNamesUC[(int)zoneU.DiffuserType]));
     289           0 :             ShowContinueError(state, "  To input these Coefficients, use Floor Diffuser Type = Custom.");
     290             :         }
     291             : 
     292           5 :         if (zoneU.DiffuserType == Diffuser::Swirl) {
     293           1 :             zoneU.A_Kc = 0.0;
     294           1 :             zoneU.B_Kc = 0.0;
     295           1 :             zoneU.C_Kc = 0.6531;
     296           1 :             zoneU.D_Kc = 0.0069;
     297           1 :             zoneU.E_Kc = -0.00004;
     298           4 :         } else if (zoneU.DiffuserType == Diffuser::VarArea) {
     299           0 :             zoneU.A_Kc = 0.0;
     300           0 :             zoneU.B_Kc = 0.0;
     301           0 :             zoneU.C_Kc = (model == RoomAirModel::UFADExt) ? 0.83 : 0.88;
     302           0 :             zoneU.D_Kc = 0.0;
     303           0 :             zoneU.E_Kc = 0.0;
     304           4 :         } else if (zoneU.DiffuserType == Diffuser::DisplVent) {
     305           0 :             zoneU.A_Kc = 0.0;
     306           0 :             zoneU.B_Kc = 0.0;
     307           0 :             zoneU.C_Kc = 0.67;
     308           0 :             zoneU.D_Kc = 0.0;
     309           0 :             zoneU.E_Kc = 0.0;
     310           4 :         } else if (zoneU.DiffuserType == Diffuser::LinBarGrille) {
     311           4 :             zoneU.A_Kc = 0.0;
     312           4 :             zoneU.B_Kc = 0.0;
     313           4 :             zoneU.C_Kc = (model == RoomAirModel::UFADExt) ? 0.8214 : 0.8;
     314           4 :             zoneU.D_Kc = (model == RoomAirModel::UFADExt) ? -0.0263 : 0.0;
     315           4 :             zoneU.E_Kc = (model == RoomAirModel::UFADExt) ? 0.0014 : 0.0;
     316           0 :         } else if (zoneU.A_Kc == Constant::AutoCalculate || zoneU.B_Kc == Constant::AutoCalculate || zoneU.C_Kc == Constant::AutoCalculate ||
     317           0 :                    zoneU.D_Kc == Constant::AutoCalculate || zoneU.E_Kc == Constant::AutoCalculate) {
     318           0 :             ShowFatalError(state,
     319           0 :                            format("For {} for Zone {}, input for Coefficients A - E must be "
     320             :                                   "specified when Floor Diffuser Type = Custom.",
     321             :                                   cCMO,
     322           0 :                                   zoneU.ZoneName));
     323             :         }
     324             : 
     325           5 :         if (zoneU.PowerPerPlume == Constant::AutoCalculate) {
     326             : 
     327           5 :             zoneU.PowerPerPlume = sumUFADConvGainPerPlume(state, ZoneNum, NumberOfOccupants);
     328             : 
     329           5 :             BaseSizer::reportSizerOutput(state, cCMO, zoneU.ZoneName, "Power per plume [W]", zoneU.PowerPerPlume);
     330             : 
     331           5 :             if (zoneU.DiffusersPerZone == AutoSize) {
     332           5 :                 zoneU.DiffusersPerZone = (NumberOfOccupants > 0.0) ? NumberOfOccupants : 1.0;
     333           5 :                 BaseSizer::reportSizerOutput(state, cCMO, zoneU.ZoneName, "Number of diffusers per zone", zoneU.DiffusersPerZone);
     334             :             }
     335             :         }
     336             : 
     337           5 :         if (zoneU.DiffusersPerZone == AutoSize) {
     338           0 :             zoneU.DiffusersPerZone = (NumberOfOccupants > 0.0) ? NumberOfOccupants : 1.0;
     339             : 
     340           0 :             BaseSizer::reportSizerOutput(state, cCMO, zoneU.ZoneName, "Number of diffusers per zone", zoneU.DiffusersPerZone);
     341             :         }
     342           5 :     }
     343             : 
     344           5 :     Real64 sumUFADConvGainPerPlume(EnergyPlusData &state, int const zoneNum, Real64 const numOccupants)
     345             :     {
     346           5 :         Real64 zoneElecConv(0.0); // zone elec equip design convective gain [W]
     347          30 :         for (auto const &zoneElectric : state.dataHeatBal->ZoneElectric) {
     348          25 :             if (zoneElectric.ZonePtr == zoneNum) {
     349           5 :                 zoneElecConv += zoneElectric.DesignLevel * zoneElectric.FractionConvected;
     350             :             }
     351           5 :         }
     352             : 
     353           5 :         Real64 zoneGasConv(0.0); // zone gas equip design convective gain [W]
     354           5 :         for (auto const &zoneGas : state.dataHeatBal->ZoneGas) {
     355           0 :             if (zoneGas.ZonePtr == zoneNum) {
     356           0 :                 zoneGasConv += zoneGas.DesignLevel * zoneGas.FractionConvected;
     357             :             }
     358           5 :         }
     359             : 
     360           5 :         Real64 zoneOthEqConv(0.0); // zone other equip design convective gain [W]
     361           5 :         for (auto const &zoneOtherEq : state.dataHeatBal->ZoneOtherEq) {
     362           0 :             if (zoneOtherEq.ZonePtr == zoneNum) {
     363           0 :                 zoneOthEqConv += zoneOtherEq.DesignLevel * zoneOtherEq.FractionConvected;
     364             :             }
     365           5 :         }
     366             : 
     367           5 :         Real64 zoneHWEqConv(0.0); // zone hot water equip design convective gain [W]
     368           5 :         for (auto const &zoneHWEq : state.dataHeatBal->ZoneHWEq) {
     369           0 :             if (zoneHWEq.ZonePtr == zoneNum) {
     370           0 :                 zoneHWEqConv += zoneHWEq.DesignLevel * zoneHWEq.FractionConvected;
     371             :             }
     372           5 :         }
     373             : 
     374           5 :         Real64 zoneSteamEqConv(0.0); // zone steam equip design convective gain [W]
     375           5 :         for (auto const &zoneSteamEq : state.dataHeatBal->ZoneSteamEq) {
     376           0 :             if (zoneSteamEq.ZonePtr == zoneNum) {
     377           0 :                 zoneSteamEqConv += zoneSteamEq.DesignLevel * zoneSteamEq.FractionConvected;
     378             :             }
     379           5 :         }
     380             : 
     381           5 :         Real64 numPlumes = (numOccupants > 0.0) ? numOccupants : 1.0;
     382             : 
     383           5 :         return (numOccupants * 73.0 + zoneElecConv + zoneGasConv + zoneOthEqConv + zoneHWEqConv + zoneSteamEqConv) / numPlumes;
     384             :     }
     385             : 
     386       78321 :     void HcUFAD(EnergyPlusData &state, int const ZoneNum, Real64 const FractionHeight, UFADConvCoef &ufadCC)
     387             :     {
     388             : 
     389             :         // SUBROUTINE INFORMATION:
     390             :         //       AUTHOR         G. Carrilho da Graca
     391             :         //       DATE WRITTEN   February 2004
     392             : 
     393             :         // PURPOSE OF THIS SUBROUTINE:
     394             :         // Main subroutine for convection calculation in the UCSD Displacement Ventilation model.
     395             :         // It calls CalcDetailedHcInForDVModel for convection coefficient
     396             :         // initial calculations and averages the final result comparing the position of the surface with
     397             :         // the interface subzone height.
     398             : 
     399             :         // Using/Aliasing
     400             :         using namespace DataEnvironment;
     401             :         using namespace DataHeatBalance;
     402             : 
     403             :         // Is the air flow model for this zone set to UCSDDV Displacement Ventilation?
     404       78321 :         if (!state.dataRoomAir->IsZoneUFAD(ZoneNum)) return;
     405             : 
     406       78321 :         ufadCC.HAT_MX = 0.0;    // HAT_MX Convection Coefficient times Area times Temperature for the upper subzone
     407       78321 :         ufadCC.HAT_MXWin = 0.0; // HAT_MX Convection Coefficient times Area times Temperature for the upper subzone (windows only)
     408       78321 :         ufadCC.HA_MX = 0.0;     // HA_MX Convection Coefficient times Area for the upper subzone
     409       78321 :         ufadCC.HA_MXWin = 0.0;  // HA_MX Convection Coefficient times Area for the upper subzone (windows only)
     410       78321 :         ufadCC.HAT_OC = 0.0;    // HAT_OC Convection Coefficient times Area times Temperature for the lower subzone
     411       78321 :         ufadCC.HAT_OCWin = 0.0; // HAT_OC Convection Coefficient times Area times Temperature for the lower subzone (windows only)
     412       78321 :         ufadCC.HA_OC = 0.0;     // HA_OC Convection Coefficient times Area for the lower subzone
     413       78321 :         ufadCC.HA_OCWin = 0.0;  // HA_OC Convection Coefficient times Area for the lower subzone (windows only)
     414       78321 :         ufadCC.HAT_FLOOR = 0.0; // HAT_FLOOR Convection Coefficient times Area times Temperature for the floor(?) subzone
     415       78321 :         ufadCC.HA_FLOOR = 0.0;  // HA_FLOOR Convection Coefficient times Area for the floor(?) subzone
     416             : 
     417       78321 :         Real64 zoneCeilingHeight1 = state.dataRoomAir->ZoneCeilingHeight1(ZoneNum);
     418       78321 :         Real64 zoneCeilingHeight2 = state.dataRoomAir->ZoneCeilingHeight2(ZoneNum);
     419             : 
     420       78321 :         Real64 LayH = FractionHeight * (zoneCeilingHeight2 - zoneCeilingHeight1); // Height of the Occupied/Mixed subzone interface
     421             : 
     422             :         // WALL Hc, HA and HAT calculation
     423      391605 :         for (int Ctd = state.dataRoomAir->PosZ_Wall(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Wall(ZoneNum).end; ++Ctd) {
     424      313284 :             int SurfNum = state.dataRoomAir->APos_Wall(Ctd);
     425      313284 :             if (SurfNum == 0) continue;
     426             : 
     427      313284 :             auto &surf = state.dataSurface->Surface(SurfNum);
     428      313284 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
     429      313284 :             state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
     430      313284 :             Real64 ZSupSurf = maxval(surf.Vertex, &Vector::z) - zoneCeilingHeight1; // highest height for this surface
     431      313284 :             Real64 ZInfSurf = minval(surf.Vertex, &Vector::z) - zoneCeilingHeight1; // lowest height for this surface
     432             : 
     433             :             // The Wall surface is in the upper subzone
     434      313284 :             if (ZInfSurf > LayH) {
     435           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
     436           0 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     437           0 :                 state.dataRoomAir->HWall(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
     438           0 :                 ufadCC.HAT_MX += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWall(Ctd);
     439           0 :                 ufadCC.HA_MX += surf.Area * state.dataRoomAir->HWall(Ctd);
     440             :             }
     441             : 
     442             :             // The Wall surface is in the lower subzone
     443      313284 :             if (ZSupSurf < LayH) {
     444           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
     445           0 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     446           0 :                 state.dataRoomAir->HWall(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
     447           0 :                 ufadCC.HAT_OC += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWall(Ctd);
     448           0 :                 ufadCC.HA_OC += surf.Area * state.dataRoomAir->HWall(Ctd);
     449             :             }
     450             : 
     451      313284 :             if (std::abs(ZInfSurf - ZSupSurf) < 1.e-10) {
     452           0 :                 ShowSevereError(state, "RoomAirModelUFAD:HcUCSDUF: Surface values will cause divide by zero.");
     453           0 :                 ShowContinueError(state, format("Zone=\"{}\", Surface=\"{}\".", state.dataHeatBal->Zone(surf.Zone).Name, surf.Name));
     454           0 :                 ShowContinueError(state, format("ZInfSurf=[{:.4R}], LayH=[{:.4R}].", ZInfSurf, LayH));
     455           0 :                 ShowContinueError(state, format("ZSupSurf=[{:.4R}], LayH=[{:.4R}].", ZSupSurf, LayH));
     456           0 :                 ShowFatalError(state, "...Previous condition causes termination.");
     457             :             }
     458             : 
     459             :             // The Wall surface is partially in upper and partially in lower subzone
     460      313284 :             if (ZInfSurf <= LayH && ZSupSurf >= LayH) {
     461      313284 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
     462      313284 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     463      313284 :                 Real64 HLU = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the upper area of surface
     464      313284 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
     465      313284 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     466      313284 :                 Real64 HLD = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the lower area of surface
     467      313284 :                 Real64 TmedDV = ((ZSupSurf - LayH) * state.dataRoomAir->ZTMX(ZoneNum) + (LayH - ZInfSurf) * state.dataRoomAir->ZTOC(ZoneNum)) /
     468      313284 :                                 (ZSupSurf - ZInfSurf); // Average temperature for DV
     469      313284 :                 state.dataRoomAir->HWall(Ctd) = ((LayH - ZInfSurf) * HLD + (ZSupSurf - LayH) * HLU) / (ZSupSurf - ZInfSurf);
     470      313284 :                 ufadCC.HAT_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLU;
     471      313284 :                 ufadCC.HA_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * HLU;
     472      313284 :                 ufadCC.HAT_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLD;
     473      313284 :                 ufadCC.HA_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * HLD;
     474      313284 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = TmedDV;
     475             :             }
     476             : 
     477      313284 :             state.dataRoomAir->UFADHcIn(SurfNum) = state.dataRoomAir->HWall(Ctd);
     478             : 
     479             :         } // END WALL
     480             : 
     481             :         // WINDOW Hc, HA and HAT CALCULATION
     482      172543 :         for (int Ctd = state.dataRoomAir->PosZ_Window(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Window(ZoneNum).end; ++Ctd) {
     483       94222 :             int SurfNum = state.dataRoomAir->APos_Window(Ctd);
     484       94222 :             if (SurfNum == 0) continue;
     485             : 
     486       94222 :             auto &surf = state.dataSurface->Surface(SurfNum);
     487       94222 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
     488       94222 :             state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
     489             : 
     490       94222 :             if (surf.Tilt > 10.0 && surf.Tilt < 170.0) { // Window Wall
     491       94222 :                 Real64 ZSupSurf = maxval(surf.Vertex, &Vector::z) - zoneCeilingHeight1;
     492       94222 :                 Real64 ZInfSurf = minval(surf.Vertex, &Vector::z) - zoneCeilingHeight1;
     493             : 
     494       94222 :                 if (ZInfSurf > LayH) {
     495       21789 :                     state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
     496       21789 :                     CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     497       21789 :                     state.dataRoomAir->HWindow(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
     498       21789 :                     ufadCC.HAT_MX += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWindow(Ctd);
     499       21789 :                     ufadCC.HA_MX += surf.Area * state.dataRoomAir->HWindow(Ctd);
     500       21789 :                     ufadCC.HAT_MXWin += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWindow(Ctd);
     501       21789 :                     ufadCC.HA_MXWin += surf.Area * state.dataRoomAir->HWindow(Ctd);
     502             :                 }
     503             : 
     504       94222 :                 if (ZSupSurf < LayH) {
     505           0 :                     state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
     506           0 :                     CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     507           0 :                     state.dataRoomAir->HWindow(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
     508           0 :                     ufadCC.HAT_OC += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWindow(Ctd);
     509           0 :                     ufadCC.HA_OC += surf.Area * state.dataRoomAir->HWindow(Ctd);
     510           0 :                     ufadCC.HAT_OCWin += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWindow(Ctd);
     511           0 :                     ufadCC.HA_OCWin += surf.Area * state.dataRoomAir->HWindow(Ctd);
     512             :                 }
     513             : 
     514       94222 :                 if (ZInfSurf <= LayH && ZSupSurf >= LayH) {
     515       72433 :                     state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
     516       72433 :                     CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     517       72433 :                     Real64 HLU = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the upper area of surface
     518       72433 :                     state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
     519       72433 :                     CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     520       72433 :                     Real64 HLD = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the lower area of surface
     521       72433 :                     Real64 TmedDV = ((ZSupSurf - LayH) * state.dataRoomAir->ZTMX(ZoneNum) + (LayH - ZInfSurf) * state.dataRoomAir->ZTOC(ZoneNum)) /
     522       72433 :                                     (ZSupSurf - ZInfSurf); // Average temperature
     523             : 
     524       72433 :                     state.dataRoomAir->HWindow(Ctd) = ((LayH - ZInfSurf) * HLD + (ZSupSurf - LayH) * HLU) / (ZSupSurf - ZInfSurf);
     525       72433 :                     ufadCC.HAT_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLU;
     526       72433 :                     ufadCC.HA_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * HLU;
     527       72433 :                     ufadCC.HAT_MXWin += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLU;
     528       72433 :                     ufadCC.HA_MXWin += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * HLU;
     529       72433 :                     ufadCC.HAT_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLD;
     530       72433 :                     ufadCC.HA_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * HLD;
     531       72433 :                     ufadCC.HAT_OCWin += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLD;
     532       72433 :                     ufadCC.HA_OCWin += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * HLD;
     533       72433 :                     state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = TmedDV;
     534             :                 }
     535             :             }
     536             : 
     537       94222 :             if (surf.Tilt <= 10.0) { // Window Ceiling
     538           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
     539           0 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     540           0 :                 state.dataRoomAir->HWindow(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
     541           0 :                 ufadCC.HAT_MX += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWindow(Ctd);
     542           0 :                 ufadCC.HA_MX += surf.Area * state.dataRoomAir->HWindow(Ctd);
     543       94222 :             } else if (surf.Tilt >= 170.0) { // Window Floor
     544           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
     545           0 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     546           0 :                 state.dataRoomAir->HWindow(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
     547           0 :                 ufadCC.HAT_OC += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWindow(Ctd);
     548           0 :                 ufadCC.HA_OC += surf.Area * state.dataRoomAir->HWindow(Ctd);
     549             :             }
     550             : 
     551       94222 :             state.dataRoomAir->UFADHcIn(SurfNum) = state.dataRoomAir->HWindow(Ctd);
     552             : 
     553             :         } // END WINDOW
     554             : 
     555             :         // DOOR Hc, HA and HAT CALCULATION
     556       78321 :         for (int Ctd = state.dataRoomAir->PosZ_Door(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Door(ZoneNum).end; ++Ctd) { // DOOR
     557           0 :             int SurfNum = state.dataRoomAir->APos_Door(Ctd);
     558           0 :             if (SurfNum == 0) continue;
     559           0 :             auto &surf = state.dataSurface->Surface(SurfNum);
     560           0 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
     561           0 :             state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
     562             : 
     563           0 :             Real64 ZSupSurf = maxval(surf.Vertex, &Vector::z) - zoneCeilingHeight1;
     564           0 :             Real64 ZInfSurf = minval(surf.Vertex, &Vector::z) - zoneCeilingHeight1;
     565             : 
     566           0 :             if (ZInfSurf > LayH) {
     567           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
     568           0 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     569           0 :                 state.dataRoomAir->HDoor(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
     570           0 :                 ufadCC.HAT_MX += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HDoor(Ctd);
     571           0 :                 ufadCC.HA_MX += surf.Area * state.dataRoomAir->HDoor(Ctd);
     572             :             }
     573             : 
     574           0 :             if (ZSupSurf < LayH) {
     575           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
     576           0 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     577           0 :                 state.dataRoomAir->HDoor(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
     578           0 :                 ufadCC.HAT_OC += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HDoor(Ctd);
     579           0 :                 ufadCC.HA_OC += surf.Area * state.dataRoomAir->HDoor(Ctd);
     580             :             }
     581             : 
     582           0 :             if (ZInfSurf <= LayH && ZSupSurf >= LayH) {
     583           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
     584           0 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     585           0 :                 Real64 HLU = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the upper area of surface
     586           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
     587           0 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     588           0 :                 Real64 HLD = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the lower area of surface
     589           0 :                 Real64 TmedDV = ((ZSupSurf - LayH) * state.dataRoomAir->ZTMX(ZoneNum) + (LayH - ZInfSurf) * state.dataRoomAir->ZTOC(ZoneNum)) /
     590           0 :                                 (ZSupSurf - ZInfSurf); // Average temperature
     591           0 :                 state.dataRoomAir->HDoor(Ctd) = ((LayH - ZInfSurf) * HLD + (ZSupSurf - LayH) * HLU) / (ZSupSurf - ZInfSurf);
     592           0 :                 ufadCC.HAT_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLU;
     593           0 :                 ufadCC.HA_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * HLU;
     594           0 :                 ufadCC.HAT_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLD;
     595           0 :                 ufadCC.HA_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * HLD;
     596           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = TmedDV;
     597             :             }
     598             : 
     599           0 :             state.dataRoomAir->UFADHcIn(SurfNum) = state.dataRoomAir->HDoor(Ctd);
     600             : 
     601             :         } // END DOOR
     602             : 
     603             :         // INTERNAL Hc, HA and HAT CALCULATION
     604       78321 :         state.dataUFADManager->HeightIntMass = min(state.dataUFADManager->HeightIntMassDefault, (zoneCeilingHeight2 - zoneCeilingHeight1));
     605       78321 :         for (int Ctd = state.dataRoomAir->PosZ_Internal(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Internal(ZoneNum).end; ++Ctd) {
     606           0 :             int SurfNum = state.dataRoomAir->APos_Internal(Ctd);
     607           0 :             if (SurfNum == 0) continue;
     608             : 
     609           0 :             auto &surf = state.dataSurface->Surface(SurfNum);
     610           0 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
     611           0 :             state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
     612           0 :             Real64 ZSupSurf = state.dataUFADManager->HeightIntMass;
     613           0 :             Real64 ZInfSurf = 0.0;
     614             : 
     615           0 :             if (ZSupSurf < LayH) {
     616           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
     617           0 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     618           0 :                 state.dataRoomAir->HInternal(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
     619           0 :                 ufadCC.HAT_OC += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HInternal(Ctd);
     620           0 :                 ufadCC.HA_OC += surf.Area * state.dataRoomAir->HInternal(Ctd);
     621             :             }
     622             : 
     623           0 :             if (ZInfSurf <= LayH && ZSupSurf >= LayH) {
     624           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
     625           0 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     626           0 :                 Real64 HLU = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the upper area of surface
     627           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
     628           0 :                 CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     629           0 :                 Real64 HLD = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the lower area of surface
     630           0 :                 Real64 TmedDV = ((ZSupSurf - LayH) * state.dataRoomAir->ZTMX(ZoneNum) + (LayH - ZInfSurf) * state.dataRoomAir->ZTOC(ZoneNum)) /
     631           0 :                                 (ZSupSurf - ZInfSurf); // Average temperature
     632           0 :                 state.dataRoomAir->HInternal(Ctd) = ((LayH - ZInfSurf) * HLD + (ZSupSurf - LayH) * HLU) / (ZSupSurf - ZInfSurf);
     633           0 :                 ufadCC.HAT_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLU;
     634           0 :                 ufadCC.HA_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * HLU;
     635           0 :                 ufadCC.HAT_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLD;
     636           0 :                 ufadCC.HA_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * HLD;
     637           0 :                 state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = TmedDV;
     638             :             }
     639             : 
     640           0 :             state.dataRoomAir->UFADHcIn(SurfNum) = state.dataRoomAir->HInternal(Ctd);
     641             :         } // END INTERNAL
     642             : 
     643             :         // CEILING Hc, HA and HAT CALCULATION
     644      156642 :         for (int Ctd = state.dataRoomAir->PosZ_Ceiling(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Ceiling(ZoneNum).end; ++Ctd) {
     645       78321 :             int SurfNum = state.dataRoomAir->APos_Ceiling(Ctd);
     646       78321 :             if (SurfNum == 0) continue;
     647       78321 :             auto &surf = state.dataSurface->Surface(SurfNum);
     648             : 
     649       78321 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
     650       78321 :             state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
     651       78321 :             state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
     652       78321 :             CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     653       78321 :             state.dataRoomAir->HCeiling(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
     654       78321 :             ufadCC.HAT_MX += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HCeiling(Ctd);
     655       78321 :             ufadCC.HA_MX += surf.Area * state.dataRoomAir->HCeiling(Ctd);
     656       78321 :             state.dataRoomAir->UFADHcIn(SurfNum) = state.dataRoomAir->HCeiling(Ctd);
     657             :         } // END CEILING
     658             : 
     659             :         // FLOOR Hc, HA and HAT CALCULATION
     660      156642 :         for (int Ctd = state.dataRoomAir->PosZ_Floor(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Floor(ZoneNum).end; ++Ctd) {
     661       78321 :             int SurfNum = state.dataRoomAir->APos_Floor(Ctd);
     662       78321 :             if (SurfNum == 0) continue;
     663       78321 :             auto &surf = state.dataSurface->Surface(SurfNum);
     664             : 
     665       78321 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
     666       78321 :             state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
     667       78321 :             state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTFloor(ZoneNum);
     668       78321 :             CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
     669       78321 :             state.dataRoomAir->HFloor(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
     670       78321 :             ufadCC.HAT_OC += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HFloor(Ctd);
     671       78321 :             ufadCC.HA_OC += surf.Area * state.dataRoomAir->HFloor(Ctd);
     672       78321 :             state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTFloor(ZoneNum);
     673       78321 :             state.dataRoomAir->UFADHcIn(SurfNum) = state.dataRoomAir->HFloor(Ctd);
     674             :         } // END FLOOR
     675             :     }
     676             : 
     677             :     static constexpr std::array<DataHeatBalance::IntGainType, 51> IntGainTypesOccupied = {
     678             :         DataHeatBalance::IntGainType::People,
     679             :         DataHeatBalance::IntGainType::WaterHeaterMixed,
     680             :         DataHeatBalance::IntGainType::WaterHeaterStratified,
     681             :         DataHeatBalance::IntGainType::ThermalStorageChilledWaterMixed,
     682             :         DataHeatBalance::IntGainType::ThermalStorageChilledWaterStratified,
     683             :         DataHeatBalance::IntGainType::ElectricEquipment,
     684             :         DataHeatBalance::IntGainType::ElectricEquipmentITEAirCooled,
     685             :         DataHeatBalance::IntGainType::GasEquipment,
     686             :         DataHeatBalance::IntGainType::HotWaterEquipment,
     687             :         DataHeatBalance::IntGainType::SteamEquipment,
     688             :         DataHeatBalance::IntGainType::OtherEquipment,
     689             :         DataHeatBalance::IntGainType::IndoorGreen,
     690             :         DataHeatBalance::IntGainType::ZoneBaseboardOutdoorTemperatureControlled,
     691             :         DataHeatBalance::IntGainType::GeneratorFuelCell,
     692             :         DataHeatBalance::IntGainType::WaterUseEquipment,
     693             :         DataHeatBalance::IntGainType::GeneratorMicroCHP,
     694             :         DataHeatBalance::IntGainType::ElectricLoadCenterTransformer,
     695             :         DataHeatBalance::IntGainType::ElectricLoadCenterInverterSimple,
     696             :         DataHeatBalance::IntGainType::ElectricLoadCenterInverterFunctionOfPower,
     697             :         DataHeatBalance::IntGainType::ElectricLoadCenterInverterLookUpTable,
     698             :         DataHeatBalance::IntGainType::ElectricLoadCenterStorageBattery,
     699             :         DataHeatBalance::IntGainType::ElectricLoadCenterStorageLiIonNmcBattery,
     700             :         DataHeatBalance::IntGainType::ElectricLoadCenterStorageSimple,
     701             :         DataHeatBalance::IntGainType::PipeIndoor,
     702             :         DataHeatBalance::IntGainType::RefrigerationCase,
     703             :         DataHeatBalance::IntGainType::RefrigerationCompressorRack,
     704             :         DataHeatBalance::IntGainType::RefrigerationSystemAirCooledCondenser,
     705             :         DataHeatBalance::IntGainType::RefrigerationSystemSuctionPipe,
     706             :         DataHeatBalance::IntGainType::RefrigerationSecondaryReceiver,
     707             :         DataHeatBalance::IntGainType::RefrigerationSecondaryPipe,
     708             :         DataHeatBalance::IntGainType::RefrigerationWalkIn,
     709             :         DataHeatBalance::IntGainType::RefrigerationTransSysAirCooledGasCooler,
     710             :         DataHeatBalance::IntGainType::RefrigerationTransSysSuctionPipeMT,
     711             :         DataHeatBalance::IntGainType::RefrigerationTransSysSuctionPipeLT,
     712             :         DataHeatBalance::IntGainType::Pump_VarSpeed,
     713             :         DataHeatBalance::IntGainType::Pump_ConSpeed,
     714             :         DataHeatBalance::IntGainType::Pump_Cond,
     715             :         DataHeatBalance::IntGainType::PumpBank_VarSpeed,
     716             :         DataHeatBalance::IntGainType::PumpBank_ConSpeed,
     717             :         DataHeatBalance::IntGainType::PlantComponentUserDefined,
     718             :         DataHeatBalance::IntGainType::CoilUserDefined,
     719             :         DataHeatBalance::IntGainType::ZoneHVACForcedAirUserDefined,
     720             :         DataHeatBalance::IntGainType::AirTerminalUserDefined,
     721             :         DataHeatBalance::IntGainType::PackagedTESCoilTank,
     722             :         DataHeatBalance::IntGainType::SecCoolingDXCoilSingleSpeed,
     723             :         DataHeatBalance::IntGainType::SecHeatingDXCoilSingleSpeed,
     724             :         DataHeatBalance::IntGainType::SecCoolingDXCoilTwoSpeed,
     725             :         DataHeatBalance::IntGainType::SecCoolingDXCoilMultiSpeed,
     726             :         DataHeatBalance::IntGainType::SecHeatingDXCoilMultiSpeed,
     727             :         DataHeatBalance::IntGainType::ElectricLoadCenterConverter,
     728             :         DataHeatBalance::IntGainType::FanSystemModel};
     729             : 
     730             :     static constexpr std::array<DataHeatBalance::IntGainType, 2> IntGainTypesUpSubzone = {DataHeatBalance::IntGainType::DaylightingDeviceTubular,
     731             :                                                                                           DataHeatBalance::IntGainType::Lights};
     732             : 
     733             :     // Explicitly list internal gains not applicable for UFAD
     734             :     // Explicitly list internal gains not applicable for Displacement Vent
     735             :     static constexpr std::array<DataHeatBalance::IntGainType, 2> ExcludedIntGainTypes = {
     736             :         DataHeatBalance::IntGainType::ZoneContaminantSourceAndSinkCarbonDioxide,
     737             :         DataHeatBalance::IntGainType::ZoneContaminantSourceAndSinkGenericContam};
     738             : 
     739        3463 :     void CalcUFADInt(EnergyPlusData &state, int const ZoneNum) // index number for the specified zone
     740             :     {
     741             : 
     742             :         // SUBROUTINE INFORMATION:
     743             :         //       AUTHOR         Fred Buhl
     744             :         //       DATE WRITTEN   August 2005
     745             :         //       MODIFIED       Brent Griffith June 2008 for new interpolation and time history
     746             :         //       RE-ENGINEERED  na
     747             : 
     748             :         // PURPOSE OF THIS SUBROUTINE:
     749             :         // Using the UCSD UFAD interior zone model, this subroutine calculates the  occupied subzone height,
     750             :         // surface heat transfer coefficients, the occupied subzone temperature, and the upper subzone temperature.
     751             : 
     752             :         // METHODOLOGY EMPLOYED:
     753             :         // The zone is divided into 2 subzones with a variable transition height.
     754             : 
     755             :         // REFERENCES:
     756             :         // The model is described in the EnergyPlus Engineering Reference in Anna Liu's UCSD PhD thesis.
     757             : 
     758             :         // Using/Aliasing
     759             :         using Psychrometrics::PsyCpAirFnW;
     760             :         using Psychrometrics::PsyRhoAirFnPbTdbW;
     761        3463 :         Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
     762        3463 :         Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
     763             : 
     764             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     765             : 
     766             :         Real64 HeightFrac; // Fractional height of transition between occupied and upper subzones
     767             :         Real64 Gamma;      // dimensionless height parameter; higher gamma means interface height will be
     768             :         // higher, smaller gamma means interface height will be lower.
     769             :         Real64 ZTAveraged;
     770             : 
     771             :         // Exact solution or Euler method
     772        3463 :         if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
     773           0 :             if (state.dataHVACGlobal->ShortenTimeStepSysRoomAir && TimeStepSys < state.dataGlobal->TimeStepZone) {
     774           0 :                 if (state.dataHVACGlobal->PreviousTimeStep < state.dataGlobal->TimeStepZone) {
     775           0 :                     state.dataRoomAir->Zone1OC(ZoneNum) = state.dataRoomAir->ZoneM2OC(ZoneNum);
     776           0 :                     state.dataRoomAir->Zone1MX(ZoneNum) = state.dataRoomAir->ZoneM2MX(ZoneNum);
     777             :                 } else {
     778           0 :                     state.dataRoomAir->Zone1OC(ZoneNum) = state.dataRoomAir->ZoneMXOC(ZoneNum);
     779           0 :                     state.dataRoomAir->Zone1MX(ZoneNum) = state.dataRoomAir->ZoneMXMX(ZoneNum);
     780             :                 }
     781             :             } else {
     782           0 :                 state.dataRoomAir->Zone1OC(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
     783           0 :                 state.dataRoomAir->Zone1MX(ZoneNum) = state.dataRoomAir->ZTMX(ZoneNum);
     784             :             }
     785             :         }
     786             : 
     787        3463 :         auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
     788        3463 :         bool MIXFLAG = false;
     789        3463 :         state.dataRoomAir->UFADHcIn = state.dataHeatBalSurf->SurfHConvInt;
     790        3463 :         Real64 SumSysMCp = 0.0;  // Sum of system mass flow rate * specific heat for this zone [W/K]
     791        3463 :         Real64 SumSysMCpT = 0.0; // Sum of system mass flow rate * specific heat * temperature for this zone [W]
     792        3463 :         Real64 TSupK = 0.0;      // supply temperature [K]
     793        3463 :         Real64 SumSysM = 0.0;    // Sum of systems mass flow rate [kg/s]
     794        3463 :         Real64 TotSysFlow = 0.0; // [m3/s]
     795        3463 :         int ZoneMult = state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier;
     796        3463 :         Real64 CeilingHeight = state.dataRoomAir->ZoneCeilingHeight2(ZoneNum) - state.dataRoomAir->ZoneCeilingHeight1(ZoneNum);
     797             : 
     798        3463 :         auto &zoneU = state.dataRoomAir->ZoneUFAD(state.dataRoomAir->ZoneUFADPtr(ZoneNum));
     799        3463 :         Real64 HeightThermostat = zoneU.ThermostatHeight; // height of the thermostat above the floor [m]
     800        3463 :         Real64 HeightComfort = zoneU.ComfortHeight;       // height at which comfort temperature is calculated
     801        3463 :         Real64 TempDiffCritRep = zoneU.TempTrigger;       // Minimum temperature difference between upper and occupied subzones for reporting
     802        3463 :         Real64 DiffArea = zoneU.DiffArea;                 // diffuser effective area [m2]
     803        3463 :         Real64 ThrowAngle = Constant::DegToRadians * zoneU.DiffAngle; // diffuser slot angle relative to vertical [radians]
     804        3463 :         Real64 SourceHeight = 0.0;                                    // height of plume sources above the floor [m]
     805        3463 :         Real64 NumDiffusers = zoneU.DiffusersPerZone;
     806        3463 :         Real64 PowerPerPlume = zoneU.PowerPerPlume;
     807             :         // gains from occupants, task lighting, elec equip, gas equip, other equip, hot water equip, steam equip,
     808             :         // baseboards (nonthermostatic), water heater skin loss
     809        3463 :         Real64 ConvGainsOccSubzone = InternalHeatGains::SumInternalConvectionGainsByTypes(state, ZoneNum, IntGainTypesOccupied);
     810             : 
     811             :         // Add heat to return air if zonal system (no return air) or cycling system (return air frequently very
     812             :         // low or zero)
     813        3463 :         if (state.dataHeatBal->Zone(ZoneNum).NoHeatToReturnAir) {
     814           0 :             ConvGainsOccSubzone += InternalHeatGains::SumReturnAirConvectionGainsByTypes(state, ZoneNum, IntGainTypesOccupied);
     815             :         }
     816             : 
     817             :         // Add convection from pool cover to occupied region
     818        3463 :         ConvGainsOccSubzone += state.dataHeatBalFanSys->SumConvPool(ZoneNum);
     819             : 
     820             :         // gains from lights (ceiling), tubular daylighting devices, high temp radiant heaters
     821             : 
     822        3463 :         Real64 ConvGainsUpSubzone = InternalHeatGains::SumInternalConvectionGainsByTypes(state, ZoneNum, IntGainTypesUpSubzone);
     823        3463 :         ConvGainsUpSubzone += state.dataHeatBalFanSys->SumConvHTRadSys(ZoneNum);
     824        3463 :         if (state.dataHeatBal->Zone(ZoneNum).NoHeatToReturnAir) {
     825           0 :             ConvGainsUpSubzone += InternalHeatGains::SumReturnAirConvectionGainsByTypes(state, ZoneNum, IntGainTypesUpSubzone);
     826             :         }
     827             : 
     828             :         // Make sure all types of internal gains have been gathered
     829        3463 :         assert((int)(size(IntGainTypesOccupied) + size(IntGainTypesUpSubzone) + size(ExcludedIntGainTypes)) ==
     830             :                (int)DataHeatBalance::IntGainType::Num);
     831             : 
     832        3463 :         Real64 ConvGains = ConvGainsOccSubzone + ConvGainsUpSubzone + thisZoneHB.SysDepZoneLoadsLagged;
     833        3463 :         Real64 ZoneEquipConfigNum = zoneU.ZoneEquipPtr;
     834        3463 :         if (ZoneEquipConfigNum > 0) {
     835        3463 :             auto const &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigNum);
     836        6926 :             for (int InNodeIndex = 1; InNodeIndex <= zoneEquipConfig.NumInletNodes; ++InNodeIndex) {
     837        3463 :                 Real64 NodeTemp = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(InNodeIndex)).Temp;
     838        3463 :                 Real64 MassFlowRate = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(InNodeIndex)).MassFlowRate;
     839        3463 :                 Real64 CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
     840        3463 :                 SumSysMCp += MassFlowRate * CpAir;
     841        3463 :                 SumSysMCpT += MassFlowRate * CpAir * NodeTemp;
     842        3463 :                 TotSysFlow += MassFlowRate / PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, NodeTemp, thisZoneHB.airHumRat);
     843        3463 :                 TSupK += MassFlowRate * NodeTemp;
     844        3463 :                 SumSysM += MassFlowRate;
     845             :             }
     846        3463 :             if (TotSysFlow > 0.0) {
     847        3041 :                 TSupK = TSupK / SumSysM + Constant::Kelvin;
     848             :             } else {
     849         422 :                 TSupK = 0.0;
     850             :             }
     851             :         }
     852             :         // mass flow rate * specific heat for this zone for infiltration, ventilation, mixing [W/K]
     853        3463 :         Real64 SumMCp = thisZoneHB.MCPI + thisZoneHB.MCPV + thisZoneHB.MCPM + thisZoneHB.MCPE + thisZoneHB.MCPC + thisZoneHB.MDotCPOA;
     854             :         // mass flow rate * specific heat* temp for this zone for infiltration, ventilation, mixing [W]
     855        3463 :         Real64 SumMCpT = thisZoneHB.MCPTI + thisZoneHB.MCPTV + thisZoneHB.MCPTM + thisZoneHB.MCPTE + thisZoneHB.MCPTC +
     856        3463 :                          thisZoneHB.MDotCPOA * state.dataHeatBal->Zone(ZoneNum).OutDryBulbTemp;
     857        3463 :         Real64 MCp_Total = SumMCp + SumSysMCp;    // total mass flow rate * specific heat for this zone [W/K]
     858        3463 :         Real64 MCpT_Total = SumMCpT + SumSysMCpT; // total mass flow rate * specific heat* temp for this zone [W]
     859             :         // For the York MIT diffusers (variable area) the area varies with the flow rate. Assume 400 ft/min velocity
     860             :         // at the diffuser, and a design flow rate of 150 cfm (.0708 m3/s). Then the design area for each diffuser is
     861             :         // 150 ft3/min / 400 ft/min = .375 ft2 = .035 m2. This is adjusted each time step by
     862             :         // (TotSysFlow/(NumDiffusers*.0708))*.035
     863        3463 :         if (zoneU.DiffuserType == Diffuser::VarArea) {
     864           0 :             DiffArea = 0.035 * TotSysFlow / (0.0708 * NumDiffusers);
     865             :         }
     866             :         // initial estimate of convective transfer from surfaces; assume HeightFrac is 0.5.
     867        3463 :         UFADConvCoef ufadCC;
     868        3463 :         HcUFAD(state, ZoneNum, 0.5, ufadCC);
     869        3463 :         Real64 PowerInPlumes = ConvGains + ufadCC.HAT_OC - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum) + ufadCC.HAT_MX -
     870        3463 :                                ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum);
     871             : 
     872        3463 :         Real64 NumberOfPlumes = (PowerPerPlume > 0.0 && PowerInPlumes > 0.0) ? (PowerInPlumes / PowerPerPlume) : 1.0;
     873        3463 :         Real64 NumDiffusersPerPlume = (PowerPerPlume > 0.0 && PowerInPlumes > 0.0) ? (NumDiffusers / NumberOfPlumes) : 1.0;
     874             : 
     875        3463 :         if ((PowerInPlumes <= 0.0) || (TotSysFlow == 0.0) || (TSupK - Constant::Kelvin) > thisZoneHB.MAT) {
     876             :             // The system will mix
     877        1778 :             HeightFrac = 0.0;
     878             :         } else {
     879        1685 :             Gamma = std::pow(TotSysFlow * std::cos(ThrowAngle), 1.5) /
     880        1685 :                     (NumberOfPlumes * std::pow(NumDiffusersPerPlume * DiffArea, 1.25) * std::sqrt(0.0281 * 0.001 * PowerInPlumes));
     881        1685 :             if (zoneU.CalcTransHeight) {
     882           0 :                 HeightFrac = (std::sqrt(NumDiffusersPerPlume * DiffArea) * (7.43 * std::log(Gamma) - 1.35) + 0.5 * SourceHeight) / CeilingHeight;
     883             :             } else {
     884        1685 :                 HeightFrac = zoneU.TransHeight / CeilingHeight;
     885             :             }
     886        1685 :             HeightFrac = max(0.0, min(1.0, HeightFrac));
     887        8416 :             for (int Ctd = 1; Ctd <= 4; ++Ctd) {
     888        6734 :                 HcUFAD(state, ZoneNum, HeightFrac, ufadCC);
     889        6734 :                 PowerInPlumes = ConvGains + ufadCC.HAT_OC - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum) + ufadCC.HAT_MX -
     890        6734 :                                 ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum);
     891        6734 :                 if (PowerPerPlume > 0.0 && PowerInPlumes > 0.0) {
     892        6731 :                     NumberOfPlumes = PowerInPlumes / PowerPerPlume;
     893        6731 :                     NumDiffusersPerPlume = NumDiffusers / NumberOfPlumes;
     894             :                 } else {
     895           3 :                     NumberOfPlumes = 1.0;
     896           3 :                     NumDiffusersPerPlume = 1.0;
     897             :                 }
     898        6734 :                 if (PowerInPlumes <= 0.0) break;
     899        6731 :                 Gamma = std::pow(TotSysFlow * std::cos(ThrowAngle), 1.5) /
     900        6731 :                         (NumberOfPlumes * std::pow(NumDiffusersPerPlume * DiffArea, 1.25) * std::sqrt(0.0281 * 0.001 * PowerInPlumes));
     901        6731 :                 if (zoneU.CalcTransHeight) {
     902           0 :                     HeightFrac = (std::sqrt(NumDiffusersPerPlume * DiffArea) * (7.43 * std::log(Gamma) - 1.35) + 0.5 * SourceHeight) / CeilingHeight;
     903             :                 } else {
     904        6731 :                     HeightFrac = zoneU.TransHeight / CeilingHeight;
     905             :                 }
     906        6731 :                 HeightFrac = max(0.0, min(1.0, HeightFrac));
     907        6731 :                 state.dataRoomAir->HeightTransition(ZoneNum) = HeightFrac * CeilingHeight;
     908        6731 :                 Real64 GainsFrac = zoneU.A_Kc * std::pow(Gamma, zoneU.B_Kc) + zoneU.C_Kc + zoneU.D_Kc * Gamma + zoneU.E_Kc * pow_2(Gamma);
     909        6731 :                 GainsFrac = max(0.6, min(GainsFrac, 1.0));
     910        6731 :                 state.dataRoomAir->AIRRATOC(ZoneNum) =
     911        6731 :                     state.dataHeatBal->Zone(ZoneNum).Volume *
     912        6731 :                     (state.dataRoomAir->HeightTransition(ZoneNum) - min(state.dataRoomAir->HeightTransition(ZoneNum), 0.2)) / CeilingHeight *
     913        6731 :                     state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpSens *
     914        6731 :                     PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, state.dataRoomAir->MATOC(ZoneNum), thisZoneHB.airHumRat) *
     915        6731 :                     PsyCpAirFnW(thisZoneHB.airHumRat) / TimeStepSysSec;
     916        6731 :                 state.dataRoomAir->AIRRATMX(ZoneNum) =
     917        6731 :                     state.dataHeatBal->Zone(ZoneNum).Volume * (CeilingHeight - state.dataRoomAir->HeightTransition(ZoneNum)) / CeilingHeight *
     918        6731 :                     state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpSens *
     919        6731 :                     PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, state.dataRoomAir->MATMX(ZoneNum), thisZoneHB.airHumRat) *
     920        6731 :                     PsyCpAirFnW(thisZoneHB.airHumRat) / TimeStepSysSec;
     921             : 
     922        6731 :                 if (state.dataHVACGlobal->UseZoneTimeStepHistory) {
     923        4432 :                     state.dataRoomAir->ZTMOC(ZoneNum)[2] = state.dataRoomAir->XMATOC(ZoneNum)[2];
     924        4432 :                     state.dataRoomAir->ZTMOC(ZoneNum)[1] = state.dataRoomAir->XMATOC(ZoneNum)[1];
     925        4432 :                     state.dataRoomAir->ZTMOC(ZoneNum)[0] = state.dataRoomAir->XMATOC(ZoneNum)[0];
     926             : 
     927        4432 :                     state.dataRoomAir->ZTMMX(ZoneNum)[2] = state.dataRoomAir->XMATMX(ZoneNum)[2];
     928        4432 :                     state.dataRoomAir->ZTMMX(ZoneNum)[1] = state.dataRoomAir->XMATMX(ZoneNum)[1];
     929        4432 :                     state.dataRoomAir->ZTMMX(ZoneNum)[0] = state.dataRoomAir->XMATMX(ZoneNum)[0];
     930             : 
     931             :                 } else {
     932        2299 :                     state.dataRoomAir->ZTMOC(ZoneNum)[2] = state.dataRoomAir->DSXMATOC(ZoneNum)[2];
     933        2299 :                     state.dataRoomAir->ZTMOC(ZoneNum)[1] = state.dataRoomAir->DSXMATOC(ZoneNum)[1];
     934        2299 :                     state.dataRoomAir->ZTMOC(ZoneNum)[0] = state.dataRoomAir->DSXMATOC(ZoneNum)[0];
     935             : 
     936        2299 :                     state.dataRoomAir->ZTMMX(ZoneNum)[2] = state.dataRoomAir->DSXMATMX(ZoneNum)[2];
     937        2299 :                     state.dataRoomAir->ZTMMX(ZoneNum)[1] = state.dataRoomAir->DSXMATMX(ZoneNum)[1];
     938        2299 :                     state.dataRoomAir->ZTMMX(ZoneNum)[0] = state.dataRoomAir->DSXMATMX(ZoneNum)[0];
     939             :                 }
     940             : 
     941        6731 :                 Real64 AirCap = state.dataRoomAir->AIRRATOC(ZoneNum);
     942        6731 :                 Real64 TempHistTerm = AirCap * (3.0 * state.dataRoomAir->ZTMOC(ZoneNum)[0] - (3.0 / 2.0) * state.dataRoomAir->ZTMOC(ZoneNum)[1] +
     943        6731 :                                                 (1.0 / 3.0) * state.dataRoomAir->ZTMOC(ZoneNum)[2]);
     944             :                 // Formerly CoefSumha, coef in zone temp equation with dimensions of h*A
     945        6731 :                 Real64 TempDepCoef = GainsFrac * ufadCC.HA_OC + MCp_Total;
     946        6731 :                 Real64 TempIndCoef = GainsFrac * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum)) +
     947        6731 :                                      MCpT_Total + thisZoneHB.NonAirSystemResponse / ZoneMult;
     948        6731 :                 switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
     949        6731 :                 case DataHeatBalance::SolutionAlgo::ThirdOrder: {
     950        6731 :                     state.dataRoomAir->ZTOC(ZoneNum) =
     951        6731 :                         (TempHistTerm + GainsFrac * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum)) +
     952        6731 :                          MCpT_Total + thisZoneHB.NonAirSystemResponse / ZoneMult) /
     953        6731 :                         ((11.0 / 6.0) * AirCap + GainsFrac * ufadCC.HA_OC + MCp_Total);
     954        6731 :                 } break;
     955           0 :                 case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
     956           0 :                     if (TempDepCoef == 0.0) { // B=0
     957           0 :                         state.dataRoomAir->ZTOC(ZoneNum) = state.dataRoomAir->Zone1OC(ZoneNum) + TempIndCoef / AirCap;
     958             :                     } else {
     959           0 :                         state.dataRoomAir->ZTOC(ZoneNum) =
     960           0 :                             (state.dataRoomAir->Zone1OC(ZoneNum) - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) +
     961           0 :                             TempIndCoef / TempDepCoef;
     962             :                     }
     963           0 :                 } break;
     964           0 :                 case DataHeatBalance::SolutionAlgo::EulerMethod: {
     965           0 :                     state.dataRoomAir->ZTOC(ZoneNum) = (AirCap * state.dataRoomAir->Zone1OC(ZoneNum) + TempIndCoef) / (AirCap + TempDepCoef);
     966           0 :                 } break;
     967           0 :                 default:
     968           0 :                     break;
     969             :                 }
     970        6731 :                 AirCap = state.dataRoomAir->AIRRATMX(ZoneNum);
     971        6731 :                 TempHistTerm = AirCap * (3.0 * state.dataRoomAir->ZTMMX(ZoneNum)[0] - (3.0 / 2.0) * state.dataRoomAir->ZTMMX(ZoneNum)[1] +
     972        6731 :                                          (1.0 / 3.0) * state.dataRoomAir->ZTMMX(ZoneNum)[2]);
     973        6731 :                 TempDepCoef = (1.0 - GainsFrac) * ufadCC.HA_MX + MCp_Total;
     974        6731 :                 TempIndCoef = (1.0 - GainsFrac) * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum)) +
     975        6731 :                               state.dataRoomAir->ZTOC(ZoneNum) * MCp_Total;
     976        6731 :                 switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
     977        6731 :                 case DataHeatBalance::SolutionAlgo::ThirdOrder: {
     978        6731 :                     state.dataRoomAir->ZTMX(ZoneNum) =
     979        6731 :                         (TempHistTerm +
     980        6731 :                          (1.0 - GainsFrac) * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum)) +
     981        6731 :                          state.dataRoomAir->ZTOC(ZoneNum) * MCp_Total) /
     982        6731 :                         ((11.0 / 6.0) * AirCap + (1.0 - GainsFrac) * ufadCC.HA_MX + MCp_Total);
     983        6731 :                 } break;
     984           0 :                 case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
     985           0 :                     if (TempDepCoef == 0.0) { // B=0
     986           0 :                         state.dataRoomAir->ZTMX(ZoneNum) = state.dataRoomAir->Zone1MX(ZoneNum) + TempIndCoef / AirCap;
     987             :                     } else {
     988           0 :                         state.dataRoomAir->ZTMX(ZoneNum) =
     989           0 :                             (state.dataRoomAir->Zone1MX(ZoneNum) - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) +
     990           0 :                             TempIndCoef / TempDepCoef;
     991             :                     }
     992           0 :                 } break;
     993           0 :                 case DataHeatBalance::SolutionAlgo::EulerMethod: {
     994           0 :                     state.dataRoomAir->ZTMX(ZoneNum) = (AirCap * state.dataRoomAir->Zone1MX(ZoneNum) + TempIndCoef) / (AirCap + TempDepCoef);
     995           0 :                 } break;
     996           0 :                 default:
     997           0 :                     break;
     998             :                 }
     999        6731 :                 state.dataRoomAir->ZTFloor(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
    1000             :             }
    1001        1685 :             if (PowerInPlumes <= 0.0) {
    1002           3 :                 HeightFrac = 0.0;
    1003           3 :                 state.dataRoomAir->AirModel(ZoneNum).SimAirModel = false;
    1004           3 :                 state.dataRoomAir->ZoneUFADGamma(ZoneNum) = 0.0;
    1005           3 :                 state.dataRoomAir->ZoneUFADPowInPlumes(ZoneNum) = 0.0;
    1006             :             } else {
    1007        1682 :                 state.dataRoomAir->AirModel(ZoneNum).SimAirModel = true;
    1008        1682 :                 state.dataRoomAir->ZoneUFADGamma(ZoneNum) = Gamma;
    1009        1682 :                 state.dataRoomAir->ZoneUFADPowInPlumes(ZoneNum) = PowerInPlumes;
    1010             :             }
    1011             :         }
    1012             : 
    1013             :         //=============================== M I X E D  Calculation ==============================================
    1014        6530 :         if (state.dataRoomAir->ZTMX(ZoneNum) < state.dataRoomAir->ZTOC(ZoneNum) || MCp_Total <= 0.0 ||
    1015        3067 :             HeightFrac * CeilingHeight < state.dataUFADManager->ThickOccupiedSubzoneMin) {
    1016        1791 :             MIXFLAG = true;
    1017        1791 :             HeightFrac = 0.0;
    1018        1791 :             state.dataRoomAir->AvgTempGrad(ZoneNum) = 0.0;
    1019        1791 :             state.dataRoomAir->MaxTempGrad(ZoneNum) = 0.0;
    1020        1791 :             state.dataRoomAir->AirModel(ZoneNum).SimAirModel = false;
    1021        1791 :             Real64 AirCap = thisZoneHB.AirPowerCap;
    1022        1791 :             Real64 TempHistTerm = AirCap * (3.0 * thisZoneHB.ZTM[0] - (3.0 / 2.0) * thisZoneHB.ZTM[1] + (1.0 / 3.0) * thisZoneHB.ZTM[2]);
    1023             : 
    1024        7164 :             for (int Ctd = 1; Ctd <= 3; ++Ctd) {
    1025        5373 :                 Real64 TempDepCoef = ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total;
    1026        5373 :                 Real64 const thisZoneT1 = thisZoneHB.T1;
    1027             :                 // Formerly CoefSumhat, coef in zone temp equation with dimensions of h*A(T1
    1028        5373 :                 Real64 TempIndCoef = ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total;
    1029        5373 :                 switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    1030        5373 :                 case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    1031        5373 :                     ZTAveraged = (TempHistTerm + ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total) /
    1032        5373 :                                  ((11.0 / 6.0) * AirCap + ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total);
    1033        5373 :                 } break;
    1034           0 :                 case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    1035           0 :                     if (TempDepCoef == 0.0) { // B=0
    1036           0 :                         ZTAveraged = thisZoneT1 + TempIndCoef / AirCap;
    1037             :                     } else {
    1038           0 :                         ZTAveraged =
    1039           0 :                             (thisZoneT1 - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) + TempIndCoef / TempDepCoef;
    1040             :                     }
    1041           0 :                 } break;
    1042           0 :                 case DataHeatBalance::SolutionAlgo::EulerMethod: {
    1043           0 :                     ZTAveraged = (AirCap * thisZoneT1 + TempIndCoef) / (AirCap + TempDepCoef);
    1044           0 :                 } break;
    1045           0 :                 default:
    1046           0 :                     break;
    1047             :                 }
    1048        5373 :                 state.dataRoomAir->ZTOC(ZoneNum) = ZTAveraged;
    1049        5373 :                 state.dataRoomAir->ZTMX(ZoneNum) = ZTAveraged;
    1050        5373 :                 state.dataRoomAir->ZTFloor(ZoneNum) = ZTAveraged;
    1051        5373 :                 HcUFAD(state, ZoneNum, HeightFrac, ufadCC);
    1052        5373 :                 TempDepCoef = ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total;
    1053        5373 :                 TempIndCoef = ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total;
    1054        5373 :                 switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    1055        5373 :                 case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    1056        5373 :                     ZTAveraged = (TempHistTerm + ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total) /
    1057        5373 :                                  ((11.0 / 6.0) * AirCap + ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total);
    1058        5373 :                 } break;
    1059           0 :                 case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    1060           0 :                     if (TempDepCoef == 0.0) { // B=0
    1061           0 :                         ZTAveraged = thisZoneT1 + TempIndCoef / AirCap;
    1062             :                     } else {
    1063           0 :                         ZTAveraged =
    1064           0 :                             (thisZoneT1 - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) + TempIndCoef / TempDepCoef;
    1065             :                     }
    1066           0 :                 } break;
    1067           0 :                 case DataHeatBalance::SolutionAlgo::EulerMethod: {
    1068           0 :                     ZTAveraged = (AirCap * thisZoneT1 + TempIndCoef) / (AirCap + TempDepCoef);
    1069           0 :                 } break;
    1070           0 :                 default:
    1071           0 :                     break;
    1072             :                 }
    1073        5373 :                 state.dataRoomAir->ZTOC(ZoneNum) = ZTAveraged;
    1074        5373 :                 state.dataRoomAir->ZTMX(ZoneNum) = ZTAveraged;
    1075        5373 :                 state.dataRoomAir->ZTFloor(ZoneNum) = ZTAveraged;
    1076             :             }
    1077             :         }
    1078             :         //=========================================================================================
    1079             : 
    1080             :         // Comfort temperature and temperature at the thermostat/temperature control sensor
    1081             : 
    1082        3463 :         state.dataRoomAir->HeightTransition(ZoneNum) = HeightFrac * CeilingHeight;
    1083        3463 :         Real64 HeightUpSubzoneAve = (CeilingHeight + state.dataRoomAir->HeightTransition(ZoneNum)) / 2.0;
    1084        3463 :         Real64 HeightOccupiedSubzoneAve = state.dataRoomAir->HeightTransition(ZoneNum) / 2.0;
    1085             :         // Comfort temperature
    1086             : 
    1087        3463 :         if (MIXFLAG) {
    1088        1791 :             state.dataRoomAir->TCMF(ZoneNum) = ZTAveraged;
    1089             :         } else {
    1090        1672 :             if (HeightComfort < HeightOccupiedSubzoneAve) {
    1091           0 :                 state.dataRoomAir->TCMF(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
    1092        1672 :             } else if (HeightComfort >= HeightOccupiedSubzoneAve && HeightComfort < HeightUpSubzoneAve) {
    1093        3344 :                 state.dataRoomAir->TCMF(ZoneNum) = (state.dataRoomAir->ZTOC(ZoneNum) * (HeightUpSubzoneAve - HeightComfort) +
    1094        1672 :                                                     state.dataRoomAir->ZTMX(ZoneNum) * (HeightComfort - HeightOccupiedSubzoneAve)) /
    1095        1672 :                                                    (HeightUpSubzoneAve - HeightOccupiedSubzoneAve);
    1096           0 :             } else if (HeightComfort >= HeightUpSubzoneAve && HeightComfort <= CeilingHeight) {
    1097           0 :                 state.dataRoomAir->TCMF(ZoneNum) = state.dataRoomAir->ZTMX(ZoneNum);
    1098             :             } else {
    1099           0 :                 ShowFatalError(state,
    1100           0 :                                format("UFAD comfort height is above ceiling or below floor in Zone: {}", state.dataHeatBal->Zone(ZoneNum).Name));
    1101             :             }
    1102             :         }
    1103             : 
    1104             :         // Temperature at the thermostat/temperature control sensor
    1105             : 
    1106        3463 :         if (MIXFLAG) {
    1107        1791 :             state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = ZTAveraged;
    1108             :         } else {
    1109        1672 :             if (HeightThermostat < HeightOccupiedSubzoneAve) {
    1110           0 :                 state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
    1111        1672 :             } else if (HeightThermostat >= HeightOccupiedSubzoneAve && HeightThermostat < HeightUpSubzoneAve) {
    1112        3344 :                 state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = (state.dataRoomAir->ZTOC(ZoneNum) * (HeightUpSubzoneAve - HeightThermostat) +
    1113        1672 :                                                                   state.dataRoomAir->ZTMX(ZoneNum) * (HeightThermostat - HeightOccupiedSubzoneAve)) /
    1114        1672 :                                                                  (HeightUpSubzoneAve - HeightOccupiedSubzoneAve);
    1115           0 :             } else if (HeightThermostat >= HeightUpSubzoneAve && HeightThermostat <= CeilingHeight) {
    1116           0 :                 state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = state.dataRoomAir->ZTMX(ZoneNum);
    1117             :             } else {
    1118           0 :                 ShowFatalError(state,
    1119           0 :                                format("Underfloor air distribution thermostat height is above ceiling or below floor in Zone: {}",
    1120           0 :                                       state.dataHeatBal->Zone(ZoneNum).Name));
    1121             :             }
    1122             :         }
    1123             : 
    1124             :         // Temperature gradients
    1125        3463 :         if ((HeightUpSubzoneAve - HeightOccupiedSubzoneAve) > 0.1) {
    1126        3463 :             state.dataRoomAir->AvgTempGrad(ZoneNum) =
    1127        3463 :                 (state.dataRoomAir->ZTMX(ZoneNum) - state.dataRoomAir->ZTOC(ZoneNum)) / (HeightUpSubzoneAve - HeightOccupiedSubzoneAve);
    1128             :         } else {
    1129           0 :             state.dataRoomAir->AvgTempGrad(ZoneNum) = 0.0;
    1130             :         }
    1131             : 
    1132        3463 :         if (MIXFLAG) {
    1133        1791 :             state.dataRoomAir->ZoneUFADMixedFlag(ZoneNum) = 1;
    1134        1791 :             state.dataRoomAir->AirModel(ZoneNum).SimAirModel = false;
    1135             :         } else {
    1136        1672 :             state.dataRoomAir->ZoneUFADMixedFlag(ZoneNum) = 0;
    1137        1672 :             state.dataRoomAir->AirModel(ZoneNum).SimAirModel = true;
    1138             :         }
    1139             : 
    1140        3463 :         if (ZoneEquipConfigNum > 0) {
    1141        3463 :             int ZoneNodeNum = state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber;
    1142        3463 :             state.dataLoopNodes->Node(ZoneNodeNum).Temp = state.dataRoomAir->ZTMX(ZoneNum);
    1143             :         }
    1144             : 
    1145        3463 :         if (MIXFLAG) {
    1146        1791 :             state.dataRoomAir->Phi(ZoneNum) = 1.0;
    1147             :         } else {
    1148        1672 :             state.dataRoomAir->Phi(ZoneNum) =
    1149        1672 :                 (state.dataRoomAir->ZTOC(ZoneNum) - (TSupK - Constant::Kelvin)) / (state.dataRoomAir->ZTMX(ZoneNum) - (TSupK - Constant::Kelvin));
    1150             :         }
    1151             : 
    1152             :         // Mixed for reporting purposes
    1153        3463 :         if ((MIXFLAG) || ((state.dataRoomAir->ZTMX(ZoneNum) - state.dataRoomAir->ZTOC(ZoneNum)) < TempDiffCritRep)) {
    1154        1791 :             state.dataRoomAir->ZoneUFADMixedFlagRep(ZoneNum) = 1.0;
    1155        1791 :             state.dataRoomAir->HeightTransition(ZoneNum) = 0.0;
    1156        1791 :             state.dataRoomAir->AvgTempGrad(ZoneNum) = 0.0;
    1157             :         } else {
    1158        1672 :             state.dataRoomAir->ZoneUFADMixedFlagRep(ZoneNum) = 0.0;
    1159             :         }
    1160        3463 :     }
    1161             : 
    1162       13852 :     void CalcUFADExt(EnergyPlusData &state, int const ZoneNum) // index number for the specified zone
    1163             :     {
    1164             :         // SUBROUTINE INFORMATION:
    1165             :         //       AUTHOR         Fred Buhl
    1166             :         //       DATE WRITTEN   January 2006
    1167             :         //       MODIFIED       Brent Griffith June 2008 for new interpolation and time history
    1168             :         //       RE-ENGINEERED  na
    1169             : 
    1170             :         // PURPOSE OF THIS SUBROUTINE:
    1171             :         // Using the UCSD UFAD exterior zone model, this subroutine calculates the  occupied subzone height,
    1172             :         // surface heat transfer coefficients, the occupied subzone temperature, and the upper subzone temperature.
    1173             : 
    1174             :         // METHODOLOGY EMPLOYED:
    1175             :         // The zone is divided into 2 subzones with a variable transition height.
    1176             : 
    1177             :         // REFERENCES:
    1178             :         // The model is described in the EnergyPlus Engineering Reference in Anna Liu's UCSD PhD thesis.
    1179             : 
    1180             :         // Using/Aliasing
    1181             :         using Psychrometrics::PsyCpAirFnW;
    1182             :         using Psychrometrics::PsyRhoAirFnPbTdbW;
    1183       13852 :         Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    1184       13852 :         Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    1185             :         using InternalHeatGains::SumInternalConvectionGainsByTypes;
    1186             :         using InternalHeatGains::SumReturnAirConvectionGainsByTypes;
    1187             : 
    1188             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1189             : 
    1190             :         Real64 PowerInPlumesPerMeter; // Power in Plumes per meter of window length [W/m]
    1191             :         Real64 ZTAveraged;
    1192             : 
    1193             :         // Exact solution or Euler method
    1194       13852 :         if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
    1195           0 :             if (state.dataHVACGlobal->ShortenTimeStepSysRoomAir && TimeStepSys < state.dataGlobal->TimeStepZone) {
    1196           0 :                 if (state.dataHVACGlobal->PreviousTimeStep < state.dataGlobal->TimeStepZone) {
    1197           0 :                     state.dataRoomAir->Zone1OC(ZoneNum) = state.dataRoomAir->ZoneM2OC(ZoneNum);
    1198           0 :                     state.dataRoomAir->Zone1MX(ZoneNum) = state.dataRoomAir->ZoneM2MX(ZoneNum);
    1199             :                 } else {
    1200           0 :                     state.dataRoomAir->Zone1OC(ZoneNum) = state.dataRoomAir->ZoneMXOC(ZoneNum);
    1201           0 :                     state.dataRoomAir->Zone1MX(ZoneNum) = state.dataRoomAir->ZoneMXMX(ZoneNum);
    1202             :                 }
    1203             :             } else {
    1204           0 :                 state.dataRoomAir->Zone1OC(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
    1205           0 :                 state.dataRoomAir->Zone1MX(ZoneNum) = state.dataRoomAir->ZTMX(ZoneNum);
    1206             :             }
    1207             :         }
    1208             : 
    1209       13852 :         auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
    1210       13852 :         Real64 HeightFrac = 0.0; // Fractional height of transition between occupied and upper subzones
    1211       13852 :         bool MIXFLAG = false;
    1212       13852 :         state.dataRoomAir->UFADHcIn = state.dataHeatBalSurf->SurfHConvInt;
    1213       13852 :         Real64 SumSysMCp = 0.0;     // Sum of system mass flow rate * specific heat for this zone [W/K]
    1214       13852 :         Real64 SumSysMCpT = 0.0;    // Sum of system mass flow rate * specific heat * temperature for this zone [W]
    1215       13852 :         Real64 TotSysFlow = 0.0;    // [m3/s]
    1216       13852 :         Real64 TSupK = 0.0;         // supply temperature [K]
    1217       13852 :         Real64 SumSysM = 0.0;       // Sum of systems mass flow rate [kg/s]
    1218       13852 :         Real64 PowerInPlumes = 0.0; // [W]
    1219       13852 :         Real64 Gamma = 0.0;         // dimensionless height parameter; higher gamma means interface height will be
    1220             :         // higher, smaller gamma means interface height will be lower.
    1221       13852 :         int ZoneMult = state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier;
    1222       13852 :         Real64 CeilingHeight = state.dataRoomAir->ZoneCeilingHeight2(ZoneNum) - state.dataRoomAir->ZoneCeilingHeight1(ZoneNum);
    1223             : 
    1224       13852 :         auto &zoneU = state.dataRoomAir->ZoneUFAD(state.dataRoomAir->ZoneUFADPtr(ZoneNum));
    1225       13852 :         Real64 HeightThermostat = zoneU.ThermostatHeight; // height of the thermostat above the floor [m]
    1226       13852 :         Real64 HeightComfort = zoneU.ComfortHeight;       // height at which comfort temperature is calculated
    1227       13852 :         Real64 TempDiffCritRep = zoneU.TempTrigger;       // Minimum temperature difference between upper and occupied subzones for reporting
    1228       13852 :         Real64 DiffArea = zoneU.DiffArea;                 // diffuser effective area [m2]
    1229       13852 :         Real64 ThrowAngle = Constant::DegToRadians * zoneU.DiffAngle; // diffuser slot angle relative to vertical [radians]
    1230       13852 :         Real64 SourceHeight = zoneU.HeatSrcHeight;                    // height of plume sources above the floor [m]
    1231       13852 :         Real64 NumDiffusers = zoneU.DiffusersPerZone;
    1232       13852 :         Real64 PowerPerPlume = zoneU.PowerPerPlume;
    1233             :         // gains from occupants, task lighting, elec equip, gas equip, other equip, hot water equip, steam equip,
    1234             :         // baseboards (nonthermostatic), water heater skin loss
    1235       13852 :         Real64 ConvGainsOccSubzone = SumInternalConvectionGainsByTypes(state, ZoneNum, IntGainTypesOccupied);
    1236             : 
    1237             :         // Add heat to return air if zonal system (no return air) or cycling system (return air frequently very
    1238             :         // low or zero)
    1239       13852 :         if (state.dataHeatBal->Zone(ZoneNum).NoHeatToReturnAir) {
    1240           0 :             ConvGainsOccSubzone += SumReturnAirConvectionGainsByTypes(state, ZoneNum, IntGainTypesOccupied);
    1241             :         }
    1242             : 
    1243             :         // Add convection from pool cover to occupied region
    1244       13852 :         ConvGainsOccSubzone += state.dataHeatBalFanSys->SumConvPool(ZoneNum);
    1245             : 
    1246             :         // gains from lights (ceiling), tubular daylighting devices, high temp radiant heaters
    1247             :         Real64 ConvGainsUpSubzone =
    1248       13852 :             SumInternalConvectionGainsByTypes(state, ZoneNum, IntGainTypesUpSubzone); // convective heat gains into the upper subzone [W]
    1249       13852 :         ConvGainsUpSubzone += state.dataHeatBalFanSys->SumConvHTRadSys(ZoneNum);
    1250       13852 :         if (state.dataHeatBal->Zone(ZoneNum).NoHeatToReturnAir) {
    1251           0 :             ConvGainsUpSubzone += SumReturnAirConvectionGainsByTypes(state, ZoneNum, IntGainTypesUpSubzone);
    1252             :         }
    1253       13852 :         Real64 ConvGains =
    1254       13852 :             ConvGainsOccSubzone + ConvGainsUpSubzone + thisZoneHB.SysDepZoneLoadsLagged; // total zone convective gains (excluding surfaces) [W]
    1255       13852 :         int ZoneEquipConfigNum = zoneU.ZoneEquipPtr;
    1256       13852 :         if (ZoneEquipConfigNum > 0) {
    1257       13852 :             auto const &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigNum);
    1258       27704 :             for (int InNodeIndex = 1; InNodeIndex <= zoneEquipConfig.NumInletNodes; ++InNodeIndex) {
    1259       13852 :                 Real64 NodeTemp = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(InNodeIndex)).Temp;
    1260       13852 :                 Real64 MassFlowRate = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(InNodeIndex)).MassFlowRate;
    1261       13852 :                 Real64 CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
    1262       13852 :                 SumSysMCp += MassFlowRate * CpAir;
    1263       13852 :                 SumSysMCpT += MassFlowRate * CpAir * NodeTemp;
    1264       13852 :                 TotSysFlow += MassFlowRate / PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, NodeTemp, thisZoneHB.airHumRat);
    1265       13852 :                 TSupK += MassFlowRate * NodeTemp;
    1266       13852 :                 SumSysM += MassFlowRate;
    1267             :             }
    1268       13852 :             if (TotSysFlow > 0.0) {
    1269       12683 :                 TSupK = TSupK / SumSysM + Constant::Kelvin;
    1270             :             } else {
    1271        1169 :                 TSupK = 0.0;
    1272             :             }
    1273             :         }
    1274             : 
    1275             :         // mass flow rate * specific heat for this zone for infiltration, ventilation, mixing [W/K]
    1276       13852 :         Real64 SumMCp = thisZoneHB.MCPI + thisZoneHB.MCPV + thisZoneHB.MCPM + thisZoneHB.MDotCPOA;
    1277             :         // mass flow rate * specific heat* temp for this zone for infiltration, ventilation, mixing [W]
    1278             :         Real64 SumMCpT =
    1279       13852 :             thisZoneHB.MCPTI + thisZoneHB.MCPTV + thisZoneHB.MCPTM + thisZoneHB.MDotCPOA * state.dataHeatBal->Zone(ZoneNum).OutDryBulbTemp;
    1280             : 
    1281       13852 :         Real64 MCp_Total = SumMCp + SumSysMCp;    // total mass flow rate * specific heat for this zone [W/K]
    1282       13852 :         Real64 MCpT_Total = SumMCpT + SumSysMCpT; // total mass flow rate * specific heat* temp for this zone [W]
    1283             : 
    1284             :         // For the York MIT diffusers (variable area) the area varies with the flow rate. Assume 400 ft/min velocity
    1285             :         // at the diffuser, and a design flow rate of 150 cfm (.0708 m3/s). Then the design area for each diffuser is
    1286             :         // 150 ft3/min / 400 ft/min = .375 ft2 = .035 m2. This is adjusted each time step by
    1287             :         //               (TotSysFlow/(NumDiffusers*.0708))*.035
    1288       13852 :         if (zoneU.DiffuserType == Diffuser::VarArea) {
    1289           0 :             DiffArea = 0.035 * TotSysFlow / (0.0708 * NumDiffusers);
    1290             :         }
    1291             :         // initial estimate of convective transfer from surfaces; assume HeightFrac is 0.5.
    1292       13852 :         UFADConvCoef ufadCC;
    1293       13852 :         HcUFAD(state, ZoneNum, 0.5, ufadCC);
    1294       27704 :         Real64 ConvGainsWindows = ufadCC.HAT_MXWin + ufadCC.HAT_OCWin - // ZoneEquipConfig index for this UFAD zone
    1295       13852 :                                   ufadCC.HA_MXWin * state.dataRoomAir->ZTMX(ZoneNum) - ufadCC.HA_OCWin * state.dataRoomAir->ZTOC(ZoneNum);
    1296       13852 :         PowerInPlumes = ConvGains + ufadCC.HAT_OC - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum) + ufadCC.HAT_MX -
    1297       13852 :                         ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum);
    1298             :         // NumberOfPlumes = PowerInPlumes / PowerPerPlume
    1299       13852 :         Real64 NumberOfPlumes = (PowerPerPlume > 0.0 && PowerInPlumes > 0.0) ? (PowerInPlumes / PowerPerPlume) : 1.0;
    1300       13852 :         Real64 NumDiffusersPerPlume = (PowerPerPlume > 0.0 && PowerInPlumes > 0.0) ? (NumDiffusers / NumberOfPlumes) : 1.0;
    1301             : 
    1302       13852 :         if ((PowerInPlumes <= 0.0) || (TotSysFlow == 0.0) || (TSupK - Constant::Kelvin) > thisZoneHB.MAT) {
    1303             :             // The system will mix
    1304        7026 :             HeightFrac = 0.0;
    1305             :         } else {
    1306        6826 :             if (PowerInPlumes > 0.0) {
    1307        6826 :                 if (zoneU.WinWidth > 0.0) { // exterior zone formula
    1308        6826 :                     PowerInPlumesPerMeter = PowerInPlumes / zoneU.WinWidth;
    1309        6826 :                     Gamma =
    1310        6826 :                         (TotSysFlow * std::cos(ThrowAngle)) / (NumDiffusers * DiffArea * std::pow(0.0281 * 0.001 * PowerInPlumesPerMeter, 0.333333));
    1311             :                 } else { // interior zone formula
    1312           0 :                     Gamma = std::pow(TotSysFlow * std::cos(ThrowAngle), 1.5) /
    1313           0 :                             (NumberOfPlumes * std::pow(NumDiffusersPerPlume * DiffArea, 1.25) * std::sqrt(0.0281 * 0.001 * PowerInPlumes));
    1314             :                 }
    1315             :             } else {
    1316           0 :                 Gamma = 1000.0;
    1317             :             }
    1318        6826 :             if (zoneU.CalcTransHeight) {
    1319           0 :                 if (zoneU.WinWidth > 0.0) { // use exterior zone formula
    1320           0 :                     HeightFrac = (std::sqrt(DiffArea) * (11.03 * std::log(Gamma) - 10.73) + 0.5 * SourceHeight) / CeilingHeight;
    1321             :                 } else { // use interior zone formula
    1322           0 :                     HeightFrac = (std::sqrt(NumDiffusersPerPlume * DiffArea) * (7.43 * std::log(Gamma) - 1.35) + 0.5 * SourceHeight) / CeilingHeight;
    1323             :                 }
    1324             :             } else {
    1325        6826 :                 HeightFrac = zoneU.TransHeight / CeilingHeight;
    1326             :             }
    1327        6826 :             HeightFrac = max(0.0, min(1.0, HeightFrac));
    1328        6826 :             Real64 GainsFrac = zoneU.A_Kc * std::pow(Gamma, zoneU.B_Kc) + zoneU.C_Kc + zoneU.D_Kc * Gamma + zoneU.E_Kc * pow_2(Gamma);
    1329        6826 :             GainsFrac = max(0.7, min(GainsFrac, 1.0));
    1330        6826 :             if (zoneU.ShadeDown) {
    1331           0 :                 GainsFrac -= 0.2;
    1332             :             }
    1333        6826 :             state.dataRoomAir->ZoneUFADPowInPlumes(ZoneNum) = PowerInPlumes;
    1334       33839 :             for (int Ctd = 1; Ctd <= 4; ++Ctd) {
    1335       27110 :                 HcUFAD(state, ZoneNum, HeightFrac, ufadCC);
    1336       27110 :                 ConvGainsWindows = ufadCC.HAT_MXWin + ufadCC.HAT_OCWin - ufadCC.HA_MXWin * state.dataRoomAir->ZTMX(ZoneNum) -
    1337       27110 :                                    ufadCC.HA_OCWin * state.dataRoomAir->ZTOC(ZoneNum);
    1338       27110 :                 ConvGainsWindows = max(ConvGainsWindows, 0.0);
    1339       27110 :                 PowerInPlumes = ConvGains + ufadCC.HAT_OC - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum) + ufadCC.HAT_MX -
    1340       27110 :                                 ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum);
    1341             :                 // NumberOfPlumes = PowerInPlumes / PowerPerPlume
    1342       27110 :                 NumberOfPlumes = 1.0;
    1343       27110 :                 if (PowerInPlumes <= 0.0) break;
    1344       27013 :                 if (zoneU.WinWidth > 0.0) { // use exterior zone formula
    1345       27013 :                     PowerInPlumesPerMeter = PowerInPlumes / zoneU.WinWidth;
    1346       27013 :                     Gamma =
    1347       27013 :                         (TotSysFlow * std::cos(ThrowAngle)) / (NumDiffusers * DiffArea * std::pow(0.0281 * 0.001 * PowerInPlumesPerMeter, 0.333333));
    1348             :                 } else { // use interior zone formula
    1349           0 :                     Gamma = std::pow(TotSysFlow * std::cos(ThrowAngle), 1.5) /
    1350           0 :                             (NumberOfPlumes * std::pow(NumDiffusersPerPlume * DiffArea, 1.25) * std::sqrt(0.0281 * 0.001 * PowerInPlumes));
    1351             :                 }
    1352       27013 :                 if (zoneU.CalcTransHeight) {
    1353           0 :                     if (zoneU.WinWidth > 0.0) { // exterior zone formula
    1354           0 :                         HeightFrac = (std::sqrt(DiffArea) * (11.03 * std::log(Gamma) - 10.73) + 0.5 * SourceHeight) / CeilingHeight;
    1355             :                     } else { // interior zone formula
    1356           0 :                         HeightFrac =
    1357           0 :                             (std::sqrt(NumDiffusersPerPlume * DiffArea) * (7.43 * std::log(Gamma) - 1.35) + 0.5 * SourceHeight) / CeilingHeight;
    1358             :                     }
    1359             :                 } else {
    1360       27013 :                     HeightFrac = zoneU.TransHeight / CeilingHeight;
    1361             :                 }
    1362       27013 :                 HeightFrac = min(1.0, HeightFrac);
    1363       27013 :                 state.dataRoomAir->HeightTransition(ZoneNum) = HeightFrac * CeilingHeight;
    1364       27013 :                 Real64 GainsFrac = zoneU.A_Kc * std::pow(Gamma, zoneU.B_Kc) + zoneU.C_Kc + zoneU.D_Kc * Gamma + zoneU.E_Kc * pow_2(Gamma);
    1365       27013 :                 GainsFrac = max(0.7, min(GainsFrac, 1.0));
    1366       27013 :                 if (zoneU.ShadeDown) {
    1367           0 :                     GainsFrac -= 0.2;
    1368             :                 }
    1369       27013 :                 state.dataRoomAir->AIRRATOC(ZoneNum) =
    1370       27013 :                     state.dataHeatBal->Zone(ZoneNum).Volume *
    1371       27013 :                     (state.dataRoomAir->HeightTransition(ZoneNum) - min(state.dataRoomAir->HeightTransition(ZoneNum), 0.2)) / CeilingHeight *
    1372       27013 :                     state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpSens *
    1373       27013 :                     PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, state.dataRoomAir->MATOC(ZoneNum), thisZoneHB.airHumRat) *
    1374       27013 :                     PsyCpAirFnW(thisZoneHB.airHumRat) / TimeStepSysSec;
    1375       27013 :                 state.dataRoomAir->AIRRATMX(ZoneNum) =
    1376       27013 :                     state.dataHeatBal->Zone(ZoneNum).Volume * (CeilingHeight - state.dataRoomAir->HeightTransition(ZoneNum)) / CeilingHeight *
    1377       27013 :                     state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpSens *
    1378       27013 :                     PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, state.dataRoomAir->MATMX(ZoneNum), thisZoneHB.airHumRat) *
    1379       27013 :                     PsyCpAirFnW(thisZoneHB.airHumRat) / TimeStepSysSec;
    1380             : 
    1381       27013 :                 if (state.dataHVACGlobal->UseZoneTimeStepHistory) {
    1382       17604 :                     state.dataRoomAir->ZTMOC(ZoneNum)[2] = state.dataRoomAir->XMATOC(ZoneNum)[2];
    1383       17604 :                     state.dataRoomAir->ZTMOC(ZoneNum)[1] = state.dataRoomAir->XMATOC(ZoneNum)[1];
    1384       17604 :                     state.dataRoomAir->ZTMOC(ZoneNum)[0] = state.dataRoomAir->XMATOC(ZoneNum)[0];
    1385             : 
    1386       17604 :                     state.dataRoomAir->ZTMMX(ZoneNum)[2] = state.dataRoomAir->XMATMX(ZoneNum)[2];
    1387       17604 :                     state.dataRoomAir->ZTMMX(ZoneNum)[1] = state.dataRoomAir->XMATMX(ZoneNum)[1];
    1388       17604 :                     state.dataRoomAir->ZTMMX(ZoneNum)[0] = state.dataRoomAir->XMATMX(ZoneNum)[0];
    1389             : 
    1390             :                 } else {
    1391        9409 :                     state.dataRoomAir->ZTMOC(ZoneNum)[2] = state.dataRoomAir->DSXMATOC(ZoneNum)[2];
    1392        9409 :                     state.dataRoomAir->ZTMOC(ZoneNum)[1] = state.dataRoomAir->DSXMATOC(ZoneNum)[1];
    1393        9409 :                     state.dataRoomAir->ZTMOC(ZoneNum)[0] = state.dataRoomAir->DSXMATOC(ZoneNum)[0];
    1394             : 
    1395        9409 :                     state.dataRoomAir->ZTMMX(ZoneNum)[2] = state.dataRoomAir->DSXMATMX(ZoneNum)[2];
    1396        9409 :                     state.dataRoomAir->ZTMMX(ZoneNum)[1] = state.dataRoomAir->DSXMATMX(ZoneNum)[1];
    1397        9409 :                     state.dataRoomAir->ZTMMX(ZoneNum)[0] = state.dataRoomAir->DSXMATMX(ZoneNum)[0];
    1398             :                 }
    1399             : 
    1400       27013 :                 Real64 AirCap = state.dataRoomAir->AIRRATOC(ZoneNum);
    1401       27013 :                 Real64 TempHistTerm = AirCap * (3.0 * state.dataRoomAir->ZTMOC(ZoneNum)[0] - (3.0 / 2.0) * state.dataRoomAir->ZTMOC(ZoneNum)[1] +
    1402       27013 :                                                 (1.0 / 3.0) * state.dataRoomAir->ZTMOC(ZoneNum)[2]);
    1403       27013 :                 Real64 TempDepCoef = GainsFrac * ufadCC.HA_OC + MCp_Total;
    1404       27013 :                 Real64 TempIndCoef = GainsFrac * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum)) +
    1405       27013 :                                      MCpT_Total + thisZoneHB.NonAirSystemResponse / ZoneMult;
    1406       27013 :                 switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    1407       27013 :                 case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    1408       27013 :                     state.dataRoomAir->ZTOC(ZoneNum) =
    1409       27013 :                         (TempHistTerm + GainsFrac * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum)) +
    1410       27013 :                          MCpT_Total + thisZoneHB.NonAirSystemResponse / ZoneMult) /
    1411       27013 :                         ((11.0 / 6.0) * AirCap + GainsFrac * ufadCC.HA_OC + MCp_Total);
    1412       27013 :                 } break;
    1413           0 :                 case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    1414           0 :                     if (TempDepCoef == 0.0) { // B=0
    1415           0 :                         state.dataRoomAir->ZTOC(ZoneNum) = state.dataRoomAir->Zone1OC(ZoneNum) + TempIndCoef / AirCap;
    1416             :                     } else {
    1417           0 :                         state.dataRoomAir->ZTOC(ZoneNum) =
    1418           0 :                             (state.dataRoomAir->Zone1OC(ZoneNum) - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) +
    1419           0 :                             TempIndCoef / TempDepCoef;
    1420             :                     }
    1421           0 :                 } break;
    1422           0 :                 case DataHeatBalance::SolutionAlgo::EulerMethod: {
    1423           0 :                     state.dataRoomAir->ZTOC(ZoneNum) = (AirCap * state.dataRoomAir->Zone1OC(ZoneNum) + TempIndCoef) / (AirCap + TempDepCoef);
    1424           0 :                 } break;
    1425           0 :                 default:
    1426           0 :                     break;
    1427             :                 }
    1428       27013 :                 AirCap = state.dataRoomAir->AIRRATMX(ZoneNum);
    1429       27013 :                 TempHistTerm = AirCap * (3.0 * state.dataRoomAir->ZTMMX(ZoneNum)[0] - (3.0 / 2.0) * state.dataRoomAir->ZTMMX(ZoneNum)[1] +
    1430       27013 :                                          (1.0 / 3.0) * state.dataRoomAir->ZTMMX(ZoneNum)[2]);
    1431       27013 :                 TempDepCoef = (1.0 - GainsFrac) * ufadCC.HA_MX + MCp_Total;
    1432       27013 :                 TempIndCoef = (1.0 - GainsFrac) * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum)) +
    1433       27013 :                               state.dataRoomAir->ZTOC(ZoneNum) * MCp_Total;
    1434       27013 :                 switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    1435       27013 :                 case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    1436       27013 :                     state.dataRoomAir->ZTMX(ZoneNum) =
    1437       27013 :                         (TempHistTerm +
    1438       27013 :                          (1.0 - GainsFrac) * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum)) +
    1439       27013 :                          state.dataRoomAir->ZTOC(ZoneNum) * MCp_Total) /
    1440       27013 :                         ((11.0 / 6.0) * AirCap + (1.0 - GainsFrac) * ufadCC.HA_MX + MCp_Total);
    1441       27013 :                 } break;
    1442           0 :                 case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    1443           0 :                     if (TempDepCoef == 0.0) { // B=0
    1444           0 :                         state.dataRoomAir->ZTMX(ZoneNum) = state.dataRoomAir->Zone1MX(ZoneNum) + TempIndCoef / AirCap;
    1445             :                     } else {
    1446           0 :                         state.dataRoomAir->ZTMX(ZoneNum) =
    1447           0 :                             (state.dataRoomAir->Zone1MX(ZoneNum) - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) +
    1448           0 :                             TempIndCoef / TempDepCoef;
    1449             :                     }
    1450           0 :                 } break;
    1451           0 :                 case DataHeatBalance::SolutionAlgo::EulerMethod: {
    1452           0 :                     state.dataRoomAir->ZTMX(ZoneNum) = (AirCap * state.dataRoomAir->Zone1MX(ZoneNum) + TempIndCoef) / (AirCap + TempDepCoef);
    1453           0 :                 } break;
    1454           0 :                 default:
    1455           0 :                     break;
    1456             :                 }
    1457       27013 :                 state.dataRoomAir->ZTFloor(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
    1458             :             }
    1459        6826 :             if (PowerInPlumes <= 0.0) {
    1460          97 :                 HeightFrac = 0.0;
    1461          97 :                 state.dataRoomAir->AirModel(ZoneNum).SimAirModel = false;
    1462          97 :                 state.dataRoomAir->ZoneUFADGamma(ZoneNum) = 0.0;
    1463          97 :                 state.dataRoomAir->ZoneUFADPowInPlumes(ZoneNum) = 0.0;
    1464          97 :                 state.dataRoomAir->ZoneUFADPowInPlumesfromWindows(ZoneNum) = 0.0;
    1465             :             } else {
    1466        6729 :                 state.dataRoomAir->AirModel(ZoneNum).SimAirModel = true;
    1467        6729 :                 state.dataRoomAir->ZoneUFADGamma(ZoneNum) = Gamma;
    1468        6729 :                 state.dataRoomAir->ZoneUFADPowInPlumes(ZoneNum) = PowerInPlumes;
    1469        6729 :                 state.dataRoomAir->ZoneUFADPowInPlumesfromWindows(ZoneNum) = ConvGainsWindows;
    1470             :             }
    1471             :         }
    1472             : 
    1473             :         //=============================== M I X E D  Calculation ==============================================
    1474       26440 :         if (state.dataRoomAir->ZTMX(ZoneNum) < state.dataRoomAir->ZTOC(ZoneNum) || MCp_Total <= 0.0 ||
    1475       12588 :             HeightFrac * CeilingHeight < state.dataUFADManager->ThickOccupiedSubzoneMin) {
    1476        7263 :             MIXFLAG = true;
    1477        7263 :             HeightFrac = 0.0;
    1478        7263 :             Real64 const thisZoneT1 = thisZoneHB.T1;
    1479             : 
    1480        7263 :             state.dataRoomAir->AvgTempGrad(ZoneNum) = 0.0;
    1481        7263 :             state.dataRoomAir->MaxTempGrad(ZoneNum) = 0.0;
    1482        7263 :             state.dataRoomAir->AirModel(ZoneNum).SimAirModel = false;
    1483        7263 :             Real64 AirCap = thisZoneHB.AirPowerCap;
    1484        7263 :             Real64 TempHistTerm = AirCap * (3.0 * thisZoneHB.ZTM[0] - (3.0 / 2.0) * thisZoneHB.ZTM[1] + (1.0 / 3.0) * thisZoneHB.ZTM[2]);
    1485             : 
    1486       29052 :             for (int Ctd = 1; Ctd <= 3; ++Ctd) {
    1487       21789 :                 Real64 TempDepCoef = ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total;
    1488       21789 :                 Real64 TempIndCoef = ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total;
    1489       21789 :                 switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    1490       21789 :                 case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    1491       21789 :                     ZTAveraged = (TempHistTerm + ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total) /
    1492       21789 :                                  ((11.0 / 6.0) * AirCap + ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total);
    1493       21789 :                 } break;
    1494           0 :                 case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    1495           0 :                     if (TempDepCoef == 0.0) { // B=0
    1496           0 :                         ZTAveraged = thisZoneT1 + TempIndCoef / AirCap;
    1497             :                     } else {
    1498           0 :                         ZTAveraged =
    1499           0 :                             (thisZoneT1 - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) + TempIndCoef / TempDepCoef;
    1500             :                     }
    1501           0 :                 } break;
    1502           0 :                 case DataHeatBalance::SolutionAlgo::EulerMethod: {
    1503           0 :                     ZTAveraged = (AirCap * thisZoneT1 + TempIndCoef) / (AirCap + TempDepCoef);
    1504           0 :                 } break;
    1505           0 :                 default:
    1506           0 :                     break;
    1507             :                 }
    1508       21789 :                 state.dataRoomAir->ZTOC(ZoneNum) = ZTAveraged;
    1509       21789 :                 state.dataRoomAir->ZTMX(ZoneNum) = ZTAveraged;
    1510       21789 :                 state.dataRoomAir->ZTFloor(ZoneNum) = ZTAveraged;
    1511       21789 :                 HcUFAD(state, ZoneNum, HeightFrac, ufadCC);
    1512       21789 :                 TempDepCoef = ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total;
    1513       21789 :                 TempIndCoef = ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total;
    1514       21789 :                 switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
    1515       21789 :                 case DataHeatBalance::SolutionAlgo::ThirdOrder: {
    1516       21789 :                     ZTAveraged = (TempHistTerm + ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total) /
    1517       21789 :                                  ((11.0 / 6.0) * AirCap + ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total);
    1518       21789 :                 } break;
    1519           0 :                 case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
    1520           0 :                     if (TempDepCoef == 0.0) { // B=0
    1521           0 :                         ZTAveraged = thisZoneT1 + TempIndCoef / AirCap;
    1522             :                     } else {
    1523           0 :                         ZTAveraged =
    1524           0 :                             (thisZoneT1 - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) + TempIndCoef / TempDepCoef;
    1525             :                     }
    1526           0 :                 } break;
    1527           0 :                 case DataHeatBalance::SolutionAlgo::EulerMethod: {
    1528           0 :                     ZTAveraged = (AirCap * thisZoneT1 + TempIndCoef) / (AirCap + TempDepCoef);
    1529           0 :                 } break;
    1530           0 :                 default:
    1531           0 :                     break;
    1532             :                 }
    1533       21789 :                 state.dataRoomAir->ZTOC(ZoneNum) = ZTAveraged;
    1534       21789 :                 state.dataRoomAir->ZTMX(ZoneNum) = ZTAveraged;
    1535       21789 :                 state.dataRoomAir->ZTFloor(ZoneNum) = ZTAveraged;
    1536             :             }
    1537             :         }
    1538             :         //=========================================================================================
    1539             : 
    1540             :         // Comfort temperature and temperature at the thermostat/temperature control sensor
    1541             : 
    1542       13852 :         Real64 HeightUpSubzoneAve = (CeilingHeight + state.dataRoomAir->HeightTransition(ZoneNum)) / 2.0;
    1543       13852 :         Real64 HeightOccupiedSubzoneAve = state.dataRoomAir->HeightTransition(ZoneNum) / 2.0;
    1544             :         // Comfort temperature
    1545             : 
    1546       13852 :         if (MIXFLAG) {
    1547        7263 :             state.dataRoomAir->TCMF(ZoneNum) = ZTAveraged;
    1548             :         } else {
    1549        6589 :             if (HeightComfort < HeightOccupiedSubzoneAve) {
    1550           0 :                 state.dataRoomAir->TCMF(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
    1551        6589 :             } else if (HeightComfort >= HeightOccupiedSubzoneAve && HeightComfort < HeightUpSubzoneAve) {
    1552       13178 :                 state.dataRoomAir->TCMF(ZoneNum) = (state.dataRoomAir->ZTOC(ZoneNum) * (HeightUpSubzoneAve - HeightComfort) +
    1553        6589 :                                                     state.dataRoomAir->ZTMX(ZoneNum) * (HeightComfort - HeightOccupiedSubzoneAve)) /
    1554        6589 :                                                    (HeightUpSubzoneAve - HeightOccupiedSubzoneAve);
    1555           0 :             } else if (HeightComfort >= HeightUpSubzoneAve && HeightComfort <= CeilingHeight) {
    1556           0 :                 state.dataRoomAir->TCMF(ZoneNum) = state.dataRoomAir->ZTMX(ZoneNum);
    1557             :             } else {
    1558           0 :                 ShowFatalError(state,
    1559           0 :                                format("UFAD comfort height is above ceiling or below floor in Zone: {}", state.dataHeatBal->Zone(ZoneNum).Name));
    1560             :             }
    1561             :         }
    1562             : 
    1563             :         // Temperature at the thermostat/temperature control sensor
    1564             : 
    1565       13852 :         if (MIXFLAG) {
    1566        7263 :             state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = ZTAveraged;
    1567             :         } else {
    1568        6589 :             if (HeightThermostat < HeightOccupiedSubzoneAve) {
    1569           0 :                 state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
    1570        6589 :             } else if (HeightThermostat >= HeightOccupiedSubzoneAve && HeightThermostat < HeightUpSubzoneAve) {
    1571       13178 :                 state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = (state.dataRoomAir->ZTOC(ZoneNum) * (HeightUpSubzoneAve - HeightThermostat) +
    1572        6589 :                                                                   state.dataRoomAir->ZTMX(ZoneNum) * (HeightThermostat - HeightOccupiedSubzoneAve)) /
    1573        6589 :                                                                  (HeightUpSubzoneAve - HeightOccupiedSubzoneAve);
    1574           0 :             } else if (HeightThermostat >= HeightUpSubzoneAve && HeightThermostat <= CeilingHeight) {
    1575           0 :                 state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = state.dataRoomAir->ZTMX(ZoneNum);
    1576             :             } else {
    1577           0 :                 ShowFatalError(state,
    1578           0 :                                format("Underfloor air distribution thermostat height is above ceiling or below floor in Zone: {}",
    1579           0 :                                       state.dataHeatBal->Zone(ZoneNum).Name));
    1580             :             }
    1581             :         }
    1582             : 
    1583             :         // Temperature gradients
    1584       13852 :         if ((HeightUpSubzoneAve - HeightOccupiedSubzoneAve) > 0.1) {
    1585       13852 :             state.dataRoomAir->AvgTempGrad(ZoneNum) =
    1586       13852 :                 (state.dataRoomAir->ZTMX(ZoneNum) - state.dataRoomAir->ZTOC(ZoneNum)) / (HeightUpSubzoneAve - HeightOccupiedSubzoneAve);
    1587             :         } else {
    1588           0 :             state.dataRoomAir->AvgTempGrad(ZoneNum) = 0.0;
    1589             :         }
    1590             : 
    1591       13852 :         if (MIXFLAG) {
    1592        7263 :             state.dataRoomAir->ZoneUFADMixedFlag(ZoneNum) = 1;
    1593        7263 :             state.dataRoomAir->AirModel(ZoneNum).SimAirModel = false;
    1594             :         } else {
    1595        6589 :             state.dataRoomAir->ZoneUFADMixedFlag(ZoneNum) = 0;
    1596        6589 :             state.dataRoomAir->AirModel(ZoneNum).SimAirModel = true;
    1597             :         }
    1598             : 
    1599       13852 :         if (ZoneEquipConfigNum > 0) {
    1600       13852 :             int ZoneNodeNum = state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber;
    1601       13852 :             state.dataLoopNodes->Node(ZoneNodeNum).Temp = state.dataRoomAir->ZTMX(ZoneNum);
    1602             :         }
    1603             : 
    1604       13852 :         if (MIXFLAG) {
    1605        7263 :             state.dataRoomAir->Phi(ZoneNum) = 1.0;
    1606             :         } else {
    1607        6589 :             state.dataRoomAir->Phi(ZoneNum) =
    1608        6589 :                 (state.dataRoomAir->ZTOC(ZoneNum) - (TSupK - Constant::Kelvin)) / (state.dataRoomAir->ZTMX(ZoneNum) - (TSupK - Constant::Kelvin));
    1609             :         }
    1610             : 
    1611             :         // Mixed for reporting purposes
    1612       13852 :         if ((MIXFLAG) || ((state.dataRoomAir->ZTMX(ZoneNum) - state.dataRoomAir->ZTOC(ZoneNum)) < TempDiffCritRep)) {
    1613        7263 :             state.dataRoomAir->ZoneUFADMixedFlagRep(ZoneNum) = 1.0;
    1614        7263 :             state.dataRoomAir->HeightTransition(ZoneNum) = 0.0;
    1615        7263 :             state.dataRoomAir->AvgTempGrad(ZoneNum) = 0.0;
    1616             :         } else {
    1617        6589 :             state.dataRoomAir->ZoneUFADMixedFlagRep(ZoneNum) = 0.0;
    1618             :         }
    1619       13852 :     }
    1620             : 
    1621             : } // namespace RoomAir
    1622             : } // namespace EnergyPlus

Generated by: LCOV version 1.14