LCOV - code coverage report
Current view: top level - EnergyPlus - UFADManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 2.9 % 958 28
Test Date: 2025-06-02 12:03:30 Functions: 14.3 % 7 1

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

Generated by: LCOV version 2.0-1