LCOV - code coverage report
Current view: top level - EnergyPlus - ConvectionCoefficients.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 35.3 % 3101 1096
Test Date: 2025-05-22 16:09:37 Functions: 28.8 % 212 61

            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 <algorithm>
      50              : #include <cassert>
      51              : #include <cmath>
      52              : #include <numeric>
      53              : #include <string>
      54              : #include <unordered_map>
      55              : #include <unordered_set>
      56              : 
      57              : // ObjexxFCL Headers
      58              : #include <ObjexxFCL/Array.functions.hh>
      59              : #include <ObjexxFCL/Fmath.hh>
      60              : #include <ObjexxFCL/member.functions.hh>
      61              : 
      62              : // EnergyPlus Headers
      63              : #include <EnergyPlus/Construction.hh>
      64              : #include <EnergyPlus/ConvectionCoefficients.hh>
      65              : #include <EnergyPlus/ConvectionConstants.hh>
      66              : #include <EnergyPlus/CurveManager.hh>
      67              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      68              : #include <EnergyPlus/DataEnvironment.hh>
      69              : #include <EnergyPlus/DataErrorTracking.hh>
      70              : #include <EnergyPlus/DataHVACGlobals.hh>
      71              : #include <EnergyPlus/DataHeatBalSurface.hh>
      72              : #include <EnergyPlus/DataHeatBalance.hh>
      73              : #include <EnergyPlus/DataIPShortCuts.hh>
      74              : #include <EnergyPlus/DataLoopNode.hh>
      75              : #include <EnergyPlus/DataRoomAirModel.hh>
      76              : #include <EnergyPlus/DataSurfaces.hh>
      77              : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      78              : #include <EnergyPlus/DataZoneEquipment.hh>
      79              : #include <EnergyPlus/General.hh>
      80              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      81              : #include <EnergyPlus/Material.hh>
      82              : #include <EnergyPlus/Psychrometrics.hh>
      83              : #include <EnergyPlus/ScheduleManager.hh>
      84              : #include <EnergyPlus/SurfaceGeometry.hh>
      85              : #include <EnergyPlus/UtilityRoutines.hh>
      86              : #include <EnergyPlus/Vectors.hh>
      87              : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      88              : 
      89              : namespace EnergyPlus::Convect {
      90              : 
      91              : // Module containing the routines dealing with the convection coefficients
      92              : 
      93              : // MODULE INFORMATION:
      94              : //       AUTHOR         Rick Strand
      95              : //       DATE WRITTEN   August 2000
      96              : //       MODIFIED       Brent Griffith, August 2010 expanded model choices
      97              : //       RE-ENGINEERED  na
      98              : 
      99              : // PURPOSE OF THIS MODULE:
     100              : // This module contains the routines dealing with convection coefficients.
     101              : // This module collects correlations/calculations for both the interior and exterior
     102              : // Manages a portion of the input and calculations for Hc values for use in surface heat balances.
     103              : 
     104              : // METHODOLOGY EMPLOYED:
     105              : // Subroutines are called to fill the variable HConvIn with the convection coefficient at
     106              : // the inside face.  or outside face for the current surface.
     107              : 
     108              : using namespace DataLoopNode;
     109              : using namespace DataHeatBalance;
     110              : using namespace DataSurfaces;
     111              : using namespace DataVectorTypes;
     112              : 
     113              : // Coefficients that modify the convection coeff based on surface roughness
     114              : std::array<Real64, 6> const RoughnessMultiplier{2.17, 1.67, 1.52, 1.13, 1.11, 1.0};
     115              : constexpr std::array<std::string_view, (int)RefTemp::Num> RefTempNamesUC{"MEANAIRTEMPERATURE", "ADJACENTAIRTEMPERATURE", "SUPPLYAIRTEMPERATURE"};
     116              : constexpr std::array<std::string_view, (int)RefWind::Num> RefWindNamesUC{
     117              :     "WEATHERFILE", "HEIGHTADJUST", "PARALLELCOMPONENT", "PARALLELCOMPONENTHEIGHTADJUST"};
     118              : 
     119              : enum class ConvSurfDeltaT
     120              : {
     121              :     Invalid = -1,
     122              :     Positive,
     123              :     Zero,
     124              :     Negative,
     125              :     Num
     126              : };
     127              : 
     128              : // parameters, by zone, for flow regimes for adaptive convection on inside face
     129              : enum class InConvFlowRegime
     130              : {
     131              :     Invalid = -1,
     132              :     A1, // In-floor heating or in-ceiling cooling
     133              :     A2, // In-wall heating
     134              :     A3, // no HVAC system, all buoyancy
     135              :     B,  // Convective heater in zone
     136              :     C,  // central mechanical air
     137              :     D,  // zone mechanical air
     138              :     E,  // mixed. mechanical air and buoyancy
     139              :     Num
     140              : };
     141              : 
     142       250116 : void InitIntConvCoeff(EnergyPlusData &state,
     143              :                       const Array1D<Real64> &SurfaceTemperatures,    // Temperature of surfaces for evaluation of HcIn
     144              :                       ObjexxFCL::Optional_int_const ZoneToResimulate // if passed in, then only calculate surfaces that have this zone
     145              : )
     146              : {
     147              : 
     148              :     // SUBROUTINE INFORMATION:
     149              :     //       AUTHOR         Rick Strand
     150              :     //       DATE WRITTEN   March 1998
     151              :     //       MODIFIED       Dan Fisher, Nov 2000
     152              :     //                      Sep 2011 LKL/BG - resimulate only zones needing it for Radiant systems
     153              :     //       RE-ENGINEERED  na
     154              : 
     155              :     // PURPOSE OF THIS SUBROUTINE:
     156              :     // This subroutine initializes the arrays associated with interior
     157              :     // surface convection.  The main parameter which is initialized
     158              :     // in this routine is HConvIn, the convection coefficient on the
     159              :     // inside surface.
     160              : 
     161              :     // METHODOLOGY EMPLOYED:
     162              :     // Determine the temperature difference between the surface and the
     163              :     // zone air for the last time step and then base the calculation
     164              :     // of the convection coefficient on that value and the surface tilt.
     165              : 
     166              :     // REFERENCES:
     167              :     // (I)BLAST legacy routine VARTMP
     168              :     // 1.  Passive Solar Extension of the BLAST Program
     169              :     //       Appendix E. p. 17,18
     170              :     // 2.  ASHRAE
     171              :     //       Simple Algorithm:    ASHRAE Handbook of Fundamentals 1985, p. 23.2, Table 1
     172              :     //       Detailed Algorithm:  ASHRAE Handbook of Fundamentals 2001, p. 3.12, Table 5
     173              :     // 3.  Walton, G. N. 1983. Thermal Analysis Research Program (TARP) Reference Manual,
     174              :     //     NBSSIR 83-2655, National Bureau of Standards, "Surface Inside Heat Balances", pp 79-80
     175              :     // 4.  Fisher, D.E. and C.O. Pedersen, Convective Heat Transfer in Building Energy and
     176              :     //       Thermal Load Calculations, ASHRAE Transactions, vol. 103, Pt. 2, 1997, p.137
     177              :     // 5.  ISO Standard 15099:2003e
     178              : 
     179       250116 :     auto const &Zone = state.dataHeatBal->Zone;
     180       250116 :     auto const &Surface = state.dataSurface->Surface;
     181              : 
     182       250116 :     if (state.dataConvect->GetUserSuppliedConvectionCoeffs) {
     183          116 :         GetUserConvCoeffs(state);
     184          116 :         state.dataConvect->GetUserSuppliedConvectionCoeffs = false;
     185              :     }
     186              : 
     187       250116 :     if (state.dataConvect->NodeCheck) { // done once when conditions are ready...
     188       344739 :         if (!state.dataGlobal->SysSizingCalc && !state.dataGlobal->ZoneSizingCalc && state.dataZoneEquip->ZoneEquipInputsFilled &&
     189       130843 :             allocated(state.dataLoopNodes->Node)) {
     190           57 :             state.dataConvect->NodeCheck = false;
     191          123 :             for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
     192           66 :                 auto &zone = state.dataHeatBal->Zone(ZoneNum);
     193           66 :                 if (zone.IntConvAlgo != HcInt::CeilingDiffuser) continue;
     194            0 :                 if (zone.SystemZoneNodeNumber != 0) continue;
     195            0 :                 ShowSevereError(
     196              :                     state,
     197            0 :                     format("InitInteriorConvectionCoeffs: Inside Convection=CeilingDiffuser, but no system inlet node defined, Zone={}", zone.Name));
     198            0 :                 ShowContinueError(state, format("Defaulting inside convection to TARP. Check ZoneHVAC:EquipmentConnections for Zone={}", zone.Name));
     199            0 :                 zone.IntConvAlgo = HcInt::ASHRAETARP;
     200              :             }
     201              :             // insert one-time setup for adaptive inside face
     202              :         }
     203              :     }
     204              : 
     205       251662 :     if (state.dataConvect->ActiveSurfaceCheck && !state.dataGlobal->SysSizingCalc && !state.dataGlobal->ZoneSizingCalc &&
     206         1546 :         state.dataZoneEquip->ZoneEquipSimulatedOnce) {
     207           89 :         SetupAdaptiveConvRadiantSurfaceData(state);
     208           89 :         state.dataConvect->ActiveSurfaceCheck = false;
     209              :     }
     210              : 
     211       250116 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataConvect->MyEnvirnFlag) {
     212          483 :         bool anyAdaptiveConvectionAlgorithm = false;
     213         4701 :         for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     214         4218 :             if (state.dataSurface->surfIntConv(SurfNum).model == HcInt::AdaptiveConvectionAlgorithm) {
     215            0 :                 anyAdaptiveConvectionAlgorithm = true;
     216            0 :                 break;
     217              :             }
     218              :         }
     219         1157 :         for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
     220          674 :             if (state.dataHeatBal->Zone(ZoneNum).IntConvAlgo == HcInt::AdaptiveConvectionAlgorithm) {
     221            0 :                 anyAdaptiveConvectionAlgorithm = true;
     222            0 :                 break;
     223              :             }
     224              :         }
     225          483 :         if (anyAdaptiveConvectionAlgorithm) {
     226              :             // need to clear out node conditions because dynamic assignments will be affected
     227            0 :             if (state.dataLoopNodes->NumOfNodes > 0 && allocated(state.dataLoopNodes->Node)) {
     228            0 :                 for (auto &e : state.dataLoopNodes->Node) {
     229            0 :                     e.Temp = state.dataLoopNodes->DefaultNodeValues.Temp;
     230            0 :                     e.TempMin = state.dataLoopNodes->DefaultNodeValues.TempMin;
     231            0 :                     e.TempMax = state.dataLoopNodes->DefaultNodeValues.TempMax;
     232            0 :                     e.TempSetPoint = state.dataLoopNodes->DefaultNodeValues.TempSetPoint;
     233            0 :                     e.MassFlowRate = state.dataLoopNodes->DefaultNodeValues.MassFlowRate;
     234            0 :                     e.MassFlowRateMin = state.dataLoopNodes->DefaultNodeValues.MassFlowRateMin;
     235            0 :                     e.MassFlowRateMax = state.dataLoopNodes->DefaultNodeValues.MassFlowRateMax;
     236            0 :                     e.MassFlowRateMinAvail = state.dataLoopNodes->DefaultNodeValues.MassFlowRateMinAvail;
     237            0 :                     e.MassFlowRateMaxAvail = state.dataLoopNodes->DefaultNodeValues.MassFlowRateMaxAvail;
     238            0 :                     e.MassFlowRateSetPoint = state.dataLoopNodes->DefaultNodeValues.MassFlowRateSetPoint;
     239            0 :                     e.Quality = state.dataLoopNodes->DefaultNodeValues.Quality;
     240            0 :                     e.Press = state.dataLoopNodes->DefaultNodeValues.Press;
     241            0 :                     e.Enthalpy = state.dataLoopNodes->DefaultNodeValues.Enthalpy;
     242            0 :                     e.HumRat = state.dataLoopNodes->DefaultNodeValues.HumRat;
     243            0 :                     e.HumRatMin = state.dataLoopNodes->DefaultNodeValues.HumRatMin;
     244            0 :                     e.HumRatMax = state.dataLoopNodes->DefaultNodeValues.HumRatMax;
     245            0 :                     e.HumRatSetPoint = state.dataLoopNodes->DefaultNodeValues.HumRatSetPoint;
     246            0 :                     e.TempSetPointHi = state.dataLoopNodes->DefaultNodeValues.TempSetPointHi;
     247            0 :                     e.TempSetPointLo = state.dataLoopNodes->DefaultNodeValues.TempSetPointLo;
     248              :                 }
     249            0 :                 if (allocated(state.dataLoopNodes->MoreNodeInfo)) {
     250            0 :                     for (auto &e : state.dataLoopNodes->MoreNodeInfo) {
     251            0 :                         e.WetBulbTemp = state.dataLoopNodes->DefaultNodeValues.Temp;
     252            0 :                         e.RelHumidity = 0.0;
     253            0 :                         e.ReportEnthalpy = state.dataLoopNodes->DefaultNodeValues.Enthalpy;
     254            0 :                         e.VolFlowRateStdRho = 0.0;
     255            0 :                         e.VolFlowRateCrntRho = 0.0;
     256            0 :                         e.Density = 0.0;
     257              :                     }
     258              :                 }
     259              :             }
     260              :         }
     261          483 :         state.dataConvect->MyEnvirnFlag = false;
     262              :     }
     263              : 
     264       250116 :     if (!state.dataGlobal->BeginEnvrnFlag) state.dataConvect->MyEnvirnFlag = true;
     265              : 
     266       586958 :     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
     267       336842 :         switch (Zone(ZoneNum).IntConvAlgo) {
     268            0 :         case HcInt::CeilingDiffuser:
     269            0 :             CalcCeilingDiffuserIntConvCoeff(state, ZoneNum, SurfaceTemperatures);
     270            0 :             break;
     271            0 :         case HcInt::TrombeWall:
     272            0 :             CalcTrombeWallIntConvCoeff(state, ZoneNum, SurfaceTemperatures);
     273            0 :             break;
     274       336842 :         default:;
     275              :             // nothing
     276              :         }
     277              :     }
     278              : 
     279       586958 :     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
     280       336842 :         auto const &zone = state.dataHeatBal->Zone(ZoneNum);
     281       709987 :         for (int spaceNum : zone.spaceIndexes) {
     282       373145 :             auto const &thisSpace = state.dataHeatBal->space(spaceNum);
     283       373145 :             Real64 spaceMAT = state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).MAT;
     284      2448713 :             for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
     285              : 
     286      2075568 :                 if (present(ZoneToResimulate)) {
     287            0 :                     if ((ZoneNum != ZoneToResimulate) && (state.dataSurface->SurfAdjacentZone(SurfNum) != ZoneToResimulate)) {
     288            0 :                         continue; // skip surfaces that are not associated with this zone
     289              :                     }
     290              :                 }
     291      2075568 :                 auto const &surface = Surface(SurfNum);
     292      2075568 :                 if (state.dataSurface->UseRepresentativeSurfaceCalculations) {
     293            0 :                     int repSurfNum = surface.RepresentativeCalcSurfNum;
     294            0 :                     if (SurfNum != repSurfNum) continue;
     295              :                 }
     296              : 
     297      2075568 :                 HcInt intConvAlgo = state.dataSurface->surfIntConv(SurfNum).model;
     298      2075568 :                 if (intConvAlgo == HcInt::SetByZone) {
     299      2075568 :                     intConvAlgo = zone.IntConvAlgo;
     300              :                 }
     301              : 
     302      2075568 :                 switch (intConvAlgo) {
     303            0 :                 case HcInt::Value:
     304              :                 case HcInt::Schedule:
     305              :                 case HcInt::UserCurve: {
     306            0 :                     state.dataHeatBalSurf->SurfHConvInt(SurfNum) = SetIntConvCoeff(state, SurfNum);
     307              :                     // Establish some lower limit to avoid a zero convection coefficient (and potential divide by zero problems)
     308            0 :                     if (state.dataHeatBalSurf->SurfHConvInt(SurfNum) < state.dataHeatBal->LowHConvLimit)
     309            0 :                         state.dataHeatBalSurf->SurfHConvInt(SurfNum) = state.dataHeatBal->LowHConvLimit;
     310            0 :                 } break;
     311              : 
     312       133032 :                 case HcInt::ASHRAESimple: {
     313       133032 :                     CalcASHRAESimpleIntConvCoeff(state, SurfNum, SurfaceTemperatures(SurfNum), spaceMAT);
     314              :                     // Establish some lower limit to avoid a zero convection coefficient (and potential divide by zero problems)
     315       133032 :                     if (state.dataHeatBalSurf->SurfHConvInt(SurfNum) < state.dataHeatBal->LowHConvLimit)
     316            0 :                         state.dataHeatBalSurf->SurfHConvInt(SurfNum) = state.dataHeatBal->LowHConvLimit;
     317       133032 :                 } break;
     318              : 
     319      1942536 :                 case HcInt::ASHRAETARP: {
     320      1942536 :                     if (!state.dataConstruction->Construct(Surface(SurfNum).Construction).TypeIsWindow) {
     321      1866044 :                         CalcASHRAEDetailedIntConvCoeff(state, SurfNum, SurfaceTemperatures(SurfNum), spaceMAT);
     322              :                     } else {
     323        76492 :                         CalcISO15099WindowIntConvCoeff(state, SurfNum, SurfaceTemperatures(SurfNum), spaceMAT);
     324              :                     }
     325              : 
     326              :                     // Establish some lower limit to avoid a zero convection coefficient (and potential divide by zero problems)
     327      1942536 :                     if (state.dataHeatBalSurf->SurfHConvInt(SurfNum) < state.dataHeatBal->LowHConvLimit)
     328            0 :                         state.dataHeatBalSurf->SurfHConvInt(SurfNum) = state.dataHeatBal->LowHConvLimit;
     329      1942536 :                 } break;
     330              : 
     331            0 :                 case HcInt::AdaptiveConvectionAlgorithm: {
     332            0 :                     ManageIntAdaptiveConvAlgo(state, SurfNum);
     333            0 :                 } break;
     334              : 
     335            0 :                 case HcInt::CeilingDiffuser:
     336              :                 case HcInt::TrombeWall: {
     337              :                     // Already done above and can't be at individual surface
     338            0 :                 } break;
     339              : 
     340            0 :                 case HcInt::ASTMC1340: {
     341            0 :                     CalcASTMC1340ConvCoeff(state, SurfNum, SurfaceTemperatures(SurfNum), spaceMAT);
     342            0 :                 } break;
     343              : 
     344            0 :                 default: {
     345            0 :                     ShowFatalError(state, "Unhandled convection coefficient algorithm."); // assert?
     346            0 :                 } break;
     347              :                 }
     348              : 
     349      2075568 :                 if (state.dataSurface->SurfEMSOverrideIntConvCoef(SurfNum)) {
     350            0 :                     state.dataHeatBalSurf->SurfHConvInt(SurfNum) = state.dataSurface->SurfEMSValueForIntConvCoef(SurfNum);
     351            0 :                     if (Surface(SurfNum).ExtBoundCond == DataSurfaces::KivaFoundation) {
     352            0 :                         Real64 hConst = state.dataSurface->SurfEMSValueForIntConvCoef(SurfNum);
     353            0 :                         state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].in = KIVA_CONST_CONV(hConst);
     354              :                     }
     355              :                 }
     356              : 
     357              :             } // for (surface)
     358              :         }     // for (space)
     359              :     }         // for (zone)
     360              : 
     361       586958 :     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
     362       709987 :         for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
     363       373145 :             auto const &thisSpace = state.dataHeatBal->space(spaceNum);
     364       461769 :             for (int SurfNum = thisSpace.WindowSurfaceFirst; SurfNum <= thisSpace.WindowSurfaceLast; ++SurfNum) {
     365        88624 :                 auto const &surface(Surface(SurfNum));
     366        88624 :                 if (state.dataSurface->UseRepresentativeSurfaceCalculations) {
     367            0 :                     int repSurfNum = surface.RepresentativeCalcSurfNum;
     368            0 :                     if (SurfNum != repSurfNum) continue;
     369              :                 }
     370        88624 :                 if (Surface(SurfNum).ExtBoundCond == ExternalEnvironment) {
     371        88624 :                     state.dataHeatBalSurf->SurfHConvInt(SurfNum) =
     372        88624 :                         state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataHeatBalSurf->SurfWinCoeffAdjRatio(SurfNum);
     373              :                 }
     374              :             }
     375              :         }
     376              :     }
     377       250116 : }
     378              : 
     379      1387175 : void InitExtConvCoeff(EnergyPlusData &state,
     380              :                       int const SurfNum,                          // Surface number (in Surface derived type)
     381              :                       Real64 const HMovInsul,                     // Equivalent convection coefficient of movable insulation
     382              :                       Material::SurfaceRoughness const Roughness, // Roughness index (1-6), see DataHeatBalance parameters
     383              :                       Real64 const AbsExt,                        // Exterior thermal absorptance
     384              :                       Real64 const TempExt,                       // Exterior surface temperature (C)
     385              :                       Real64 &HExt,                               // Convection coefficient to exterior air
     386              :                       Real64 &HSky,                               // "Convection" coefficient to sky temperature
     387              :                       Real64 &HGround,                            // "Convection" coefficient to ground temperature
     388              :                       Real64 &HAir,                               // Radiation to Air Component
     389              :                       Real64 &HSrdSurf                            // Radiation to surrounding surfaces
     390              : )
     391              : {
     392              : 
     393              :     // SUBROUTINE INFORMATION:
     394              :     //       AUTHOR         George Walton
     395              :     //       DATE WRITTEN   January 1990
     396              :     //       RE-ENGINEERED  Mar98 (RKS); Sep03 (LKL): Add additional flavors of Ext Convection Coeff.
     397              :     //                      Dec03 (PGE): Re-eng'd ASHRAEDetailed to match BLAST and TARP.
     398              :     //                      Aug04 (PGE): Corrected error for calculating local wind speeds for different terrains.
     399              :     //                      Aug 2010 B. Griffith.  for outside air convection, added new adaptive convection algorithm etc.
     400              : 
     401              :     // PURPOSE OF THIS SUBROUTINE:
     402              :     // This subroutine determines the outside convection coefficient for
     403              :     // a particular surface.
     404              : 
     405              :     // METHODOLOGY EMPLOYED:
     406              :     // Based on the properties of a particular surface, determine what the
     407              :     // outside convection coefficients are for outside air, the sky, and
     408              :     // the ground.  Convection coefficients for the sky and ground are
     409              :     // actually linearized radiation coefficients.  The ground surface is
     410              :     // assumed to be the same temperature as the outside air.
     411              : 
     412              :     // REFERENCES:
     413              :     // (I)BLAST legacy routine OCNVCO
     414              :     // TARP Reference Manual, "Surface Outside Heat Balances", pp 71ff
     415              : 
     416              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     417              :     Real64 SurfWindSpeed;  // Local wind speed at height of the heat transfer surface (m/s)
     418              :     Real64 Hn;             // Natural part of exterior convection
     419              :     Real64 Hf;             // Forced part of exterior convection
     420              :     Real64 rCalcPerimeter; // approximation for Perimeter
     421              : 
     422      1387175 :     auto const &surface = state.dataSurface->Surface(SurfNum);
     423              : 
     424      1387175 :     if (state.dataConvect->GetUserSuppliedConvectionCoeffs) {
     425            1 :         GetUserConvCoeffs(state);
     426            1 :         state.dataConvect->GetUserSuppliedConvectionCoeffs = false;
     427              :     }
     428              : 
     429      1387175 :     Real64 TAir = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
     430      1387175 :     Real64 TSurf = TempExt + Constant::Kelvin;
     431      1387175 :     Real64 TSky = state.dataEnvrn->SkyTempKelvin;
     432      1387175 :     Real64 TGround = TAir;
     433      1387175 :     HSrdSurf = 0.0;
     434              : 
     435      1387175 :     if (surface.SurfHasSurroundingSurfProperty) {
     436            6 :         int SrdSurfsNum = surface.SurfSurroundingSurfacesNum;
     437            6 :         if (state.dataSurface->SurroundingSurfsProperty(SrdSurfsNum).skyTempSched != nullptr) {
     438            3 :             TSky = state.dataSurface->SurroundingSurfsProperty(SrdSurfsNum).skyTempSched->getCurrentVal() + Constant::Kelvin;
     439              :         }
     440            6 :         HSrdSurf = SurroundingSurfacesRadCoeffAverage(state, SurfNum, TSurf, AbsExt);
     441              :     }
     442      1387175 :     if (surface.UseSurfPropertyGndSurfTemp) {
     443            3 :         int gndSurfsNum = surface.SurfPropertyGndSurfIndex;
     444            3 :         TGround = state.dataSurface->GroundSurfsProperty(gndSurfsNum).SurfsTempAvg + Constant::Kelvin;
     445              :     }
     446              : 
     447      1387175 :     int BaseSurf = surface.BaseSurf; // If this is a base surface, BaseSurf = SurfNum
     448              : 
     449      1387175 :     Real64 SurfWindDir = state.dataSurface->SurfOutWindDir(SurfNum);
     450              : 
     451      1387175 :     if (!surface.ExtWind) {
     452        86363 :         SurfWindSpeed = 0.0; // No wind exposure
     453      1300812 :     } else if (surface.Class == SurfaceClass::Window && state.dataSurface->SurfWinShadingFlag(SurfNum) == WinShadingType::ExtShade) {
     454            0 :         SurfWindSpeed = 0.0; // Assume zero wind speed at outside glass surface of window with exterior shade
     455              :     } else {
     456      1300812 :         SurfWindSpeed = state.dataSurface->SurfOutWindSpeed(SurfNum);
     457              :     }
     458              : 
     459              :     // Check if exterior is to be set by user
     460      1387175 :     HcExt extConvAlgo = state.dataSurface->surfExtConv(SurfNum).model;
     461      1387175 :     if (extConvAlgo == HcExt::SetByZone) {
     462      1387155 :         extConvAlgo = state.dataHeatBal->Zone(surface.Zone).ExtConvAlgo;
     463              :     }
     464              : 
     465      1387175 :     switch (extConvAlgo) {
     466            0 :     case HcExt::Value:
     467              :     case HcExt::Schedule:
     468              :     case HcExt::UserCurve: {
     469            0 :         HExt = SetExtConvCoeff(state, SurfNum);
     470            0 :     } break;
     471              : 
     472        63686 :     case HcExt::ASHRAESimple: {
     473        63686 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
     474            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f = [](double, double, double, double windSpeed) -> double {
     475            0 :                 return windSpeed;
     476            0 :             };
     477            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].out = [=](double, double, double hfTerm, double, double) -> double {
     478            0 :                 return CalcASHRAESimpExtConvCoeff(Roughness, hfTerm);
     479            0 :             };
     480              :         } else {
     481        63686 :             HExt = CalcASHRAESimpExtConvCoeff(Roughness, SurfWindSpeed); // includes radiation to sky, ground, and air
     482              :         }
     483        63686 :     } break;
     484              : 
     485            0 :     case HcExt::ASHRAETARP:
     486              :     case HcExt::BLASTHcOutside:
     487              :     case HcExt::TarpHcOutside: {
     488              :         //   Convection is split into forced and natural components. The total
     489              :         //   convective heat transfer coefficient is the sum of these components.
     490              :         //   Coefficients for subsurfaces are handled in a special way.  The values for perimeter and gross area
     491              :         //   are actually referencing the base surface because a subsurface does not initiate a completely new
     492              :         //   thermal boundary layer (although it may add some additional complexity that cannot be accounted for
     493              :         //   here).  The values for height (Z) and roughness do, however, come from the subsurface.
     494              :         //   BLAST algorithm has been replaced by this one since it was identical except for the standard wind
     495              :         //   speed measurement height which was only different because of unit conversions:  10 m vs. 30 ft (= 9.14 m).
     496              :         //   ASHRAE/BLAST REFERENCES:
     497              :         //   ?
     498              :         //   TARP REFERENCES:
     499              :         //   Walton, G. N.  1983.  Thermal Analysis Research Program Reference Manual.
     500              :         //   National Bureau of Standards.  NBSSIR 83-2655.
     501              : 
     502              :         // due to outlying calculations when perimeter is very small compared to area, use Perimeter
     503              :         // approximation calculation
     504              : 
     505            0 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
     506            0 :             if (surface.Class == SurfaceClass::Wall) {
     507            0 :                 auto const &fnd = state.dataSurfaceGeometry->kivaManager.surfaceMap[SurfNum].get_instance(0).first->foundation;
     508            0 :                 const double length = fnd.netPerimeter;
     509            0 :                 const double height = fnd.wall.heightAboveGrade;
     510            0 :                 const double area = length * height;
     511            0 :                 const double perim = 2.0 * (length + height);
     512            0 :                 state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f = [=](double, double, double, double windSpeed) -> double {
     513              :                     // Average windward and leeward since all walls use same algorithm
     514            0 :                     double windwardHf = CalcSparrowWindward(Roughness, perim, area, windSpeed);
     515            0 :                     double leewardHf = CalcSparrowLeeward(Roughness, perim, area, windSpeed);
     516            0 :                     return (windwardHf + leewardHf) / 2.0;
     517            0 :                 };
     518              :             } else { // Slab (used for exterior grade convection)
     519              :                 // Assume very large area for grade (relative to perimeter).
     520            0 :                 constexpr double area = 9999999.;
     521            0 :                 constexpr double perim = 1.;
     522            0 :                 state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f = [=](double, double, double, double windSpeed) -> double {
     523            0 :                     return CalcSparrowWindward(Roughness, perim, area, windSpeed);
     524            0 :                 };
     525              :             }
     526            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].out =
     527            0 :                 [=](double Tsurf, double Tamb, double hfTerm, double, double cosTilt) -> double {
     528            0 :                 Real64 Ts = Tsurf;
     529            0 :                 if (HMovInsul > 0.0) Ts = (HMovInsul * Tsurf + hfTerm * Tamb) / (HMovInsul + hfTerm);
     530            0 :                 return CalcASHRAETARPNatural(Ts, Tamb, cosTilt) + hfTerm;
     531            0 :             };
     532              :         } else {
     533            0 :             if (state.dataSurface->Surface(BaseSurf).GrossArea != 0.0 && state.dataSurface->Surface(BaseSurf).Height != 0.0) {
     534            0 :                 rCalcPerimeter = 2.0 * (state.dataSurface->Surface(BaseSurf).GrossArea / state.dataSurface->Surface(BaseSurf).Height +
     535            0 :                                         state.dataSurface->Surface(BaseSurf).Height);
     536            0 :                 Hf = CalcHfExteriorSparrow(SurfWindSpeed,
     537            0 :                                            state.dataSurface->Surface(BaseSurf).GrossArea,
     538              :                                            rCalcPerimeter,
     539            0 :                                            surface.CosTilt,
     540            0 :                                            surface.Azimuth,
     541              :                                            Roughness,
     542              :                                            SurfWindDir);
     543              :             } else {
     544            0 :                 Hf = 0.0;
     545              :             }
     546            0 :             if (HMovInsul > 0.0) TSurf = (HMovInsul * TSurf + Hf * TAir) / (HMovInsul + Hf);
     547            0 :             Hn = CalcASHRAETARPNatural(TSurf, TAir, surface.CosTilt);
     548            0 :             HExt = Hn + Hf;
     549              :         }
     550            0 :     } break;
     551              : 
     552           10 :     case HcExt::MoWiTTHcOutside: {
     553           10 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
     554            0 :             if (surface.Class == SurfaceClass::Wall) {
     555            0 :                 state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f = [=](double, double, double, double windSpeed) -> double {
     556              :                     // Average windward and leeward since all walls use same algorithm
     557            0 :                     double windwardHf = CalcMoWITTForcedWindward(windSpeed);
     558            0 :                     double leewardHf = CalcMoWITTForcedLeeward(windSpeed);
     559            0 :                     return (windwardHf + leewardHf) / 2.0;
     560            0 :                 };
     561              :             } else {
     562            0 :                 state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f = [=](double, double, double, double windSpeed) -> double {
     563            0 :                     return CalcMoWITTForcedWindward(windSpeed);
     564            0 :                 };
     565              :             }
     566            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].out =
     567            0 :                 [=](double Tsurf, double Tamb, double hfTerm, double, double) -> double {
     568            0 :                 Real64 Hn = CalcMoWITTNatural(Tsurf - Tamb);
     569            0 :                 return std::sqrt(pow_2(Hn) + pow_2(hfTerm));
     570            0 :             };
     571              :         } else {
     572              :             // NOTE: Movable insulation is not taken into account here
     573           10 :             if (Windward(surface.CosTilt, surface.Azimuth, SurfWindDir)) {
     574            8 :                 HExt = CalcMoWITTWindward(TAir - TSurf, SurfWindSpeed);
     575              :             } else { // leeward
     576            2 :                 HExt = CalcMoWITTLeeward(TAir - TSurf, SurfWindSpeed);
     577              :             }
     578              :         }
     579           10 :     } break;
     580              : 
     581      1323479 :     case HcExt::DOE2HcOutside: {
     582      1323479 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
     583            0 :             if (surface.Class == SurfaceClass::Wall) {
     584            0 :                 state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f = [=](double, double, double, double windSpeed) -> double {
     585              :                     // Average windward and leeward since all walls use same algorithm
     586            0 :                     double windwardHf = CalcMoWITTForcedWindward(windSpeed);
     587            0 :                     double leewardHf = CalcMoWITTForcedLeeward(windSpeed);
     588            0 :                     return (windwardHf + leewardHf) / 2.0;
     589            0 :                 };
     590              :             } else {
     591            0 :                 state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f = [=](double, double, double, double windSpeed) -> double {
     592            0 :                     return CalcMoWITTForcedWindward(windSpeed);
     593            0 :                 };
     594              :             }
     595            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].out =
     596            0 :                 [=](double Tsurf, double Tamb, double hfTerm, double, double cosTilt) -> double {
     597            0 :                 Real64 Hf = CalcDOE2Forced(Tsurf, Tamb, cosTilt, hfTerm, Roughness);
     598            0 :                 Real64 Ts = Tsurf;
     599            0 :                 if (HMovInsul > 0.0) {
     600            0 :                     Ts = (HMovInsul * TSurf + Hf * Tamb) / (HMovInsul + Hf);
     601              :                 }
     602              : 
     603            0 :                 Real64 Hn = CalcASHRAETARPNatural(Ts, Tamb, cosTilt);
     604            0 :                 return Hn + Hf;
     605            0 :             };
     606              :         } else {
     607      1323479 :             if (Windward(surface.CosTilt, surface.Azimuth, SurfWindDir)) {
     608       886623 :                 Hf = CalcDOE2Windward(TSurf, TAir, surface.CosTilt, SurfWindSpeed, Roughness);
     609              :             } else { // leeward
     610       436856 :                 Hf = CalcDOE2Leeward(TSurf, TAir, surface.CosTilt, SurfWindSpeed, Roughness);
     611              :             }
     612      1323479 :             if (HMovInsul > 0.0) {
     613            2 :                 TSurf = (HMovInsul * TSurf + Hf * TAir) / (HMovInsul + Hf);
     614              :             }
     615              : 
     616      1323479 :             Hn = CalcASHRAETARPNatural(TSurf, TAir, surface.CosTilt);
     617              :             // Better if there was iteration for movable insulation?
     618      1323479 :             HExt = Hn + Hf;
     619              :         }
     620      1323479 :     } break;
     621              : 
     622            0 :     case HcExt::AdaptiveConvectionAlgorithm: {
     623            0 :         HExt = ManageExtAdaptiveConvAlgo(state, SurfNum);
     624            0 :     } break;
     625              : 
     626            0 :     default: {
     627            0 :         ShowFatalError(state, format("InitExtConvection Coefficients: invalid parameter -- outside convection type, Surface={}", surface.Name));
     628            0 :     } break;
     629              :     }
     630              : 
     631      1387175 :     if (state.dataSurface->SurfEMSOverrideExtConvCoef(SurfNum)) {
     632            0 :         HExt = state.dataSurface->SurfEMSValueForExtConvCoef(SurfNum);
     633            0 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
     634            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f = KIVA_HF_ZERO;
     635            0 :             Real64 hConst = state.dataSurface->SurfEMSValueForExtConvCoef(SurfNum);
     636            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].out = KIVA_CONST_CONV(hConst);
     637              :         }
     638              :     }
     639              : 
     640      1387175 :     HExt = HExt * state.dataHeatBalSurf->SurfWinCoeffAdjRatio(SurfNum);
     641              : 
     642      1387175 :     if (TSurf == TSky || extConvAlgo == HcExt::ASHRAESimple) {
     643        63686 :         HSky = 0.0;
     644              :     } else {
     645              :         // Compute sky radiation coefficient
     646      1323489 :         HSky = Constant::StefanBoltzmann * AbsExt * surface.ViewFactorSkyIR * state.dataSurface->SurfAirSkyRadSplit(SurfNum) *
     647      1323489 :                (pow_4(TSurf) - pow_4(TSky)) / (TSurf - TSky);
     648              :     }
     649              : 
     650      1387175 :     if (TSurf == TAir || extConvAlgo == HcExt::ASHRAESimple) {
     651        66266 :         HGround = 0.0;
     652        66266 :         HAir = 0.0;
     653              :     } else {
     654              :         // Compute ground radiation coefficient
     655      1320909 :         HGround = Constant::StefanBoltzmann * AbsExt * surface.ViewFactorGroundIR * (pow_4(TSurf) - pow_4(TGround)) / (TSurf - TGround);
     656              : 
     657              :         // Compute air radiation coefficient
     658      1320909 :         HAir = Constant::StefanBoltzmann * AbsExt * surface.ViewFactorSkyIR * (1.0 - state.dataSurface->SurfAirSkyRadSplit(SurfNum)) *
     659      1320909 :                (pow_4(TSurf) - pow_4(TAir)) / (TSurf - TAir);
     660              :     }
     661      1387175 : }
     662              : 
     663            0 : Real64 CalcHfExteriorSparrow(Real64 const SurfWindSpeed,                 // Local wind speed at height of the heat transfer surface (m/s)
     664              :                              Real64 const GrossArea,                     // Gross surface area {m2}
     665              :                              Real64 const Perimeter,                     // Surface perimeter length {m}
     666              :                              Real64 const CosTilt,                       // Cosine of the Surface Tilt Angle
     667              :                              Real64 const Azimuth,                       // Facing angle (degrees) of the surface outward normal
     668              :                              Material::SurfaceRoughness const Roughness, // Surface roughness index (6=very smooth, 5=smooth, 4=medium smooth,
     669              :                              Real64 const WindDirection                  // Wind (compass) direction (degrees)
     670              : )
     671              : {
     672            0 :     if (Windward(CosTilt, Azimuth, WindDirection)) {
     673            0 :         return CalcSparrowWindward(Roughness, Perimeter, GrossArea, SurfWindSpeed);
     674              :     } else {
     675            0 :         return CalcSparrowLeeward(Roughness, Perimeter, GrossArea, SurfWindSpeed);
     676              :     }
     677              : }
     678              : 
     679      1323492 : bool Windward(Real64 const CosTilt,      // Cosine of the surface tilt angle
     680              :               Real64 const Azimuth,      // or Facing, Direction the surface outward normal faces (degrees)
     681              :               Real64 const WindDirection // Wind direction measured clockwise from geographic North
     682              : )
     683              : {
     684              : 
     685              :     // FUNCTION INFORMATION:
     686              :     //       AUTHOR         Linda K. Lawrie
     687              :     //       DATE WRITTEN   September 2003
     688              : 
     689              :     // PURPOSE OF THIS FUNCTION:
     690              :     // This function determines if a surface is "windward" or "leeward" (that is,
     691              :     // into / against the wind (true) or in shelter from wind (false).
     692              : 
     693              :     // METHODOLOGY EMPLOYED:
     694              :     // Leeward is defined as greater than 100 degrees from normal incidence.
     695              :     // Note that a sufficiently horizontal surface is always considered windward.
     696              : 
     697              :     // REFERENCES:
     698              :     //   Walton, G. N.  1981.  Passive solar extension of the Building Loads
     699              :     //   Analysis and System Thermodynamics (BLAST) program.  Technical Report,
     700              :     //   United States Army Construction Engineering Research Laboratory,
     701              :     //   Champaign, IL.
     702              : 
     703              :     // Surface is horizontal
     704      1323492 :     if (std::abs(CosTilt) >= 0.98) return true;
     705              : 
     706       999759 :     Real64 Diff = std::abs(WindDirection - Azimuth); // Difference between the wind direction and the surface azimuth
     707       999759 :     if ((Diff - 180.0) > 0.001) Diff -= 360.0;
     708       999759 :     return ((std::abs(Diff) - 90.0) <= 0.001);
     709              : }
     710              : 
     711          123 : void GetUserConvCoeffs(EnergyPlusData &state)
     712              : {
     713              : 
     714              :     // SUBROUTINE INFORMATION:
     715              :     //       AUTHOR         Linda K. Lawrie
     716              :     //       DATE WRITTEN   February 2003
     717              :     //       MODIFIED       November 2004; add more "user supplied convection coefficients"
     718              : 
     719              :     // PURPOSE OF THIS SUBROUTINE:
     720              :     // This subroutine gets the input for the object "Convection Coefficients" which
     721              :     // can be specified by a user to override the "normally" calculated convection coefficients.  The
     722              :     // change (November 2004) allows the user to specify down to the "surface level" the
     723              :     // exterior or interior algorithm to be used.
     724              : 
     725              :     // SUBROUTINE PARAMETER DEFINITIONS:
     726              :     static constexpr std::string_view RoutineName("GetUserConvectionCoefficients");
     727              : 
     728              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     729          123 :     Array1D_string Alphas(9);
     730          123 :     Array1D<Real64> Numbers(2);
     731              :     int NumAlphas;
     732              :     int NumNumbers;
     733              :     int Status;
     734          123 :     bool ErrorsFound(false);
     735          123 :     std::string CurrentModuleObject;
     736              : 
     737          123 :     auto &Zone = state.dataHeatBal->Zone;
     738          123 :     auto &Surface = state.dataSurface->Surface;
     739              : 
     740          123 :     auto &ipsc = state.dataIPShortCut;
     741              : 
     742              :     // first get user-defined H models so they can be processed for later objects
     743          123 :     CurrentModuleObject = "SurfaceConvectionAlgorithm:Inside:UserCurve";
     744          123 :     int TotHcIntUserCurves = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     745          123 :     state.dataConvect->hcIntUserCurve.allocate(TotHcIntUserCurves);
     746          125 :     for (int Loop = 1; Loop <= TotHcIntUserCurves; ++Loop) {
     747            4 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     748              :                                                                  CurrentModuleObject,
     749              :                                                                  Loop,
     750            2 :                                                                  ipsc->cAlphaArgs,
     751              :                                                                  NumAlphas,
     752            2 :                                                                  ipsc->rNumericArgs,
     753              :                                                                  NumNumbers,
     754              :                                                                  Status,
     755            2 :                                                                  ipsc->lNumericFieldBlanks,
     756            2 :                                                                  ipsc->lAlphaFieldBlanks,
     757            2 :                                                                  ipsc->cAlphaFieldNames,
     758            2 :                                                                  ipsc->cNumericFieldNames);
     759            2 :         auto &intConvUserCurve = state.dataConvect->hcIntUserCurve(Loop);
     760            2 :         intConvUserCurve.Name = ipsc->cAlphaArgs(1);
     761              : 
     762            2 :         ErrorObjectHeader eoh{RoutineName, CurrentModuleObject, intConvUserCurve.Name};
     763            2 :         intConvUserCurve.refTempType = static_cast<RefTemp>(getEnumValue(RefTempNamesUC, ipsc->cAlphaArgs(2)));
     764            2 :         if (intConvUserCurve.refTempType == RefTemp::Invalid) {
     765            0 :             ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(2), ipsc->cAlphaArgs(2));
     766            0 :             ErrorsFound = true;
     767              :         }
     768              : 
     769            2 :         if (!ipsc->lAlphaFieldBlanks(3)) {
     770            2 :             intConvUserCurve.hcFnTempDiffCurveNum = Curve::GetCurveIndex(state, ipsc->cAlphaArgs(3));
     771            2 :             if (intConvUserCurve.hcFnTempDiffCurveNum == 0) {
     772            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
     773            0 :                 ErrorsFound = true;
     774              :             } else { // check type
     775            2 :                 auto const *curve = state.dataCurveManager->curves(intConvUserCurve.hcFnTempDiffCurveNum);
     776            2 :                 if (curve->numDims != 1) {
     777            0 :                     ErrorsFound = true;
     778            0 :                     Curve::ShowSevereCurveDims(state, eoh, ipsc->cAlphaFieldNames(3), curve->Name, "1", curve->numDims);
     779              :                 }
     780              :             }
     781              :         } else {
     782            0 :             intConvUserCurve.hcFnTempDiffCurveNum = 0;
     783              :         }
     784              : 
     785            2 :         if (!ipsc->lAlphaFieldBlanks(4)) {
     786            0 :             intConvUserCurve.hcFnTempDiffDivHeightCurveNum = Curve::GetCurveIndex(state, ipsc->cAlphaArgs(4));
     787            0 :             if (intConvUserCurve.hcFnTempDiffDivHeightCurveNum == 0) {
     788            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
     789            0 :                 ErrorsFound = true;
     790              :             } else { // check type
     791            0 :                 auto const *curve = state.dataCurveManager->curves(intConvUserCurve.hcFnTempDiffDivHeightCurveNum);
     792            0 :                 if (curve->numDims != 1) {
     793            0 :                     ErrorsFound = true;
     794            0 :                     Curve::ShowSevereCurveDims(state, eoh, ipsc->cAlphaFieldNames(4), curve->Name, "1", curve->numDims);
     795              :                 }
     796              :             }
     797              :         } else {
     798            2 :             intConvUserCurve.hcFnTempDiffDivHeightCurveNum = 0;
     799              :         }
     800              : 
     801            2 :         if (!ipsc->lAlphaFieldBlanks(5)) {
     802            0 :             intConvUserCurve.hcFnACHCurveNum = Curve::GetCurveIndex(state, ipsc->cAlphaArgs(5));
     803            0 :             if (intConvUserCurve.hcFnACHCurveNum == 0) {
     804            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
     805            0 :                 ErrorsFound = true;
     806              :             } else { // check type
     807            0 :                 auto const *curve = state.dataCurveManager->curves(intConvUserCurve.hcFnACHCurveNum);
     808            0 :                 if (curve->numDims != 1) {
     809            0 :                     ErrorsFound = true;
     810            0 :                     Curve::ShowSevereCurveDims(state, eoh, ipsc->cAlphaFieldNames(5), curve->Name, "1", curve->numDims);
     811              :                 }
     812              :             }
     813              :         } else {
     814            2 :             intConvUserCurve.hcFnACHCurveNum = 0;
     815              :         }
     816              : 
     817            2 :         if (!ipsc->lAlphaFieldBlanks(6)) {
     818            0 :             intConvUserCurve.hcFnACHDivPerimLengthCurveNum = Curve::GetCurveIndex(state, ipsc->cAlphaArgs(6));
     819            0 :             if (intConvUserCurve.hcFnACHDivPerimLengthCurveNum == 0) {
     820            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(6), ipsc->cAlphaArgs(6));
     821            0 :                 ErrorsFound = true;
     822              :             } else { // check type
     823            0 :                 auto const *curve = state.dataCurveManager->curves(intConvUserCurve.hcFnACHDivPerimLengthCurveNum);
     824            0 :                 if (curve->numDims != 1) {
     825            0 :                     ErrorsFound = true;
     826            0 :                     Curve::ShowSevereCurveDims(state, eoh, ipsc->cAlphaFieldNames(6), curve->Name, "1", curve->numDims);
     827              :                 }
     828              :             }
     829              :         } else {
     830            2 :             intConvUserCurve.hcFnACHDivPerimLengthCurveNum = 0;
     831              :         }
     832              : 
     833              :     } // end of 'SurfaceConvectionAlgorithm:Inside:UserCurve'
     834              : 
     835          123 :     CurrentModuleObject = "SurfaceConvectionAlgorithm:Outside:UserCurve";
     836          123 :     int TotOutsideHcUserCurves = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     837          123 :     state.dataConvect->hcExtUserCurve.allocate(TotOutsideHcUserCurves);
     838          125 :     for (int Loop = 1; Loop <= TotOutsideHcUserCurves; ++Loop) {
     839            4 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     840              :                                                                  CurrentModuleObject,
     841              :                                                                  Loop,
     842            2 :                                                                  ipsc->cAlphaArgs,
     843              :                                                                  NumAlphas,
     844            2 :                                                                  ipsc->rNumericArgs,
     845              :                                                                  NumNumbers,
     846              :                                                                  Status,
     847            2 :                                                                  ipsc->lNumericFieldBlanks,
     848            2 :                                                                  ipsc->lAlphaFieldBlanks,
     849            2 :                                                                  ipsc->cAlphaFieldNames,
     850            2 :                                                                  ipsc->cNumericFieldNames);
     851              : 
     852            2 :         auto &extConvUserCurve = state.dataConvect->hcExtUserCurve(Loop);
     853              : 
     854            2 :         extConvUserCurve.Name = ipsc->cAlphaArgs(1);
     855              : 
     856            2 :         ErrorObjectHeader eoh{RoutineName, CurrentModuleObject, extConvUserCurve.Name};
     857            2 :         extConvUserCurve.windSpeedType = static_cast<RefWind>(getEnumValue(RefWindNamesUC, Util::makeUPPER(ipsc->cAlphaArgs(2))));
     858            2 :         if (extConvUserCurve.windSpeedType == RefWind::Invalid) {
     859            0 :             ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(2), ipsc->cAlphaArgs(2));
     860            0 :             ErrorsFound = true;
     861              :         }
     862              : 
     863              :         // A3 , \field Hf Function of Wind Speed Curve Name
     864            2 :         if (!ipsc->lAlphaFieldBlanks(3)) {
     865            2 :             extConvUserCurve.hfFnWindSpeedCurveNum = Curve::GetCurveIndex(state, ipsc->cAlphaArgs(3));
     866            2 :             if (extConvUserCurve.hfFnWindSpeedCurveNum == 0) {
     867            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(3), ipsc->cAlphaArgs(3));
     868            0 :                 ErrorsFound = true;
     869              :             } else { // check type
     870            2 :                 auto const *curve = state.dataCurveManager->curves(extConvUserCurve.hfFnWindSpeedCurveNum);
     871            2 :                 if (curve->numDims != 1) {
     872            0 :                     ErrorsFound = true;
     873            0 :                     Curve::ShowSevereCurveDims(state, eoh, ipsc->cAlphaFieldNames(3), curve->Name, "1", curve->numDims);
     874              :                 }
     875              :             }
     876              :         } else {
     877            0 :             extConvUserCurve.hfFnWindSpeedCurveNum = 0;
     878              :         }
     879              : 
     880              :         //  A4 , \field Hn Function of Temperature Difference Curve Name
     881            2 :         if (!ipsc->lAlphaFieldBlanks(4)) {
     882            0 :             extConvUserCurve.hnFnTempDiffCurveNum = Curve::GetCurveIndex(state, ipsc->cAlphaArgs(4));
     883            0 :             if (extConvUserCurve.hnFnTempDiffCurveNum == 0) {
     884            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(4), ipsc->cAlphaArgs(4));
     885            0 :                 ErrorsFound = true;
     886              :             } else { // check type
     887            0 :                 auto const *curve = state.dataCurveManager->curves(extConvUserCurve.hnFnTempDiffCurveNum);
     888            0 :                 if (curve->numDims != 1) {
     889            0 :                     ErrorsFound = true;
     890            0 :                     Curve::ShowSevereCurveDims(state, eoh, ipsc->cAlphaFieldNames(4), curve->Name, "1", curve->numDims);
     891              :                 }
     892              :             }
     893              :         } else {
     894            2 :             extConvUserCurve.hnFnTempDiffCurveNum = 0;
     895              :         }
     896              : 
     897              :         //  A5 , \field Hn Function of Temperature Difference Divided by Height Curve Name
     898            2 :         if (!ipsc->lAlphaFieldBlanks(5)) {
     899            0 :             extConvUserCurve.hnFnTempDiffDivHeightCurveNum = Curve::GetCurveIndex(state, ipsc->cAlphaArgs(5));
     900            0 :             if (extConvUserCurve.hnFnTempDiffDivHeightCurveNum == 0) {
     901            0 :                 ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(5), ipsc->cAlphaArgs(5));
     902            0 :                 ErrorsFound = true;
     903              :             } else { // check type
     904            0 :                 auto const *curve = state.dataCurveManager->curves(extConvUserCurve.hnFnTempDiffDivHeightCurveNum);
     905            0 :                 if (curve->numDims != 1) {
     906            0 :                     ErrorsFound = true;
     907            0 :                     Curve::ShowSevereCurveDims(state, eoh, ipsc->cAlphaFieldNames(5), curve->Name, "1", curve->numDims);
     908              :                 }
     909              :             }
     910              :         } else {
     911            2 :             extConvUserCurve.hnFnTempDiffDivHeightCurveNum = 0;
     912              :         }
     913              : 
     914              :     } // 'SurfaceConvectionAlgorithm:Outside:UserCurve'
     915              : 
     916              :     // now get user directed overrides at the surface level.
     917          123 :     state.dataSurface->TotUserIntConvModels = 0;
     918          123 :     state.dataSurface->TotUserExtConvModels = 0;
     919          123 :     CurrentModuleObject = "SurfaceProperty:ConvectionCoefficients:MultipleSurface";
     920          123 :     int Count = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     921          125 :     for (int Loop = 1; Loop <= Count; ++Loop) {
     922            4 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     923              :                                                                  CurrentModuleObject,
     924              :                                                                  Loop,
     925              :                                                                  Alphas,
     926              :                                                                  NumAlphas,
     927              :                                                                  Numbers,
     928              :                                                                  NumNumbers,
     929              :                                                                  Status,
     930            2 :                                                                  ipsc->lNumericFieldBlanks,
     931            2 :                                                                  ipsc->lAlphaFieldBlanks,
     932            2 :                                                                  ipsc->cAlphaFieldNames,
     933            2 :                                                                  ipsc->cNumericFieldNames);
     934            2 :         if (Alphas(2) == "INSIDE") {
     935            1 :             ++state.dataSurface->TotUserIntConvModels;
     936            1 :         } else if (Alphas(2) == "OUTSIDE") {
     937            1 :             ++state.dataSurface->TotUserExtConvModels;
     938              :         }
     939              : 
     940            2 :         if (Alphas(6) == "INSIDE") {
     941            1 :             ++state.dataSurface->TotUserIntConvModels;
     942            1 :         } else if (Alphas(6) == "OUTSIDE") {
     943            1 :             ++state.dataSurface->TotUserExtConvModels;
     944              :         }
     945            2 :         if (NumAlphas >= 2 && ipsc->lAlphaFieldBlanks(2)) {
     946            0 :             ShowWarningError(state,
     947            0 :                              format("GetUserConvectionCoefficients: {}, for {}={}", CurrentModuleObject, ipsc->cAlphaFieldNames(1), Alphas(1)));
     948            0 :             ShowContinueError(state, format("{} is blank and rest of fields will not be processed.", ipsc->cAlphaFieldNames(2)));
     949              :         }
     950            2 :         if (NumAlphas >= 6 && ipsc->lAlphaFieldBlanks(6)) {
     951            0 :             ShowWarningError(state,
     952            0 :                              format("GetUserConvectionCoefficients: {}, for {}={}", CurrentModuleObject, ipsc->cAlphaFieldNames(1), Alphas(1)));
     953            0 :             ShowContinueError(state, format("{} is blank and rest of fields will not be processed.", ipsc->cAlphaFieldNames(6)));
     954              :         }
     955              :     }
     956          123 :     CurrentModuleObject = "SurfaceProperty:ConvectionCoefficients";
     957          123 :     Count = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     958          125 :     for (int Loop = 1; Loop <= Count; ++Loop) {
     959            4 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     960              :                                                                  CurrentModuleObject,
     961              :                                                                  Loop,
     962              :                                                                  Alphas,
     963              :                                                                  NumAlphas,
     964              :                                                                  Numbers,
     965              :                                                                  NumNumbers,
     966              :                                                                  Status,
     967            2 :                                                                  ipsc->lNumericFieldBlanks,
     968            2 :                                                                  ipsc->lAlphaFieldBlanks,
     969            2 :                                                                  ipsc->cAlphaFieldNames,
     970            2 :                                                                  ipsc->cNumericFieldNames);
     971            2 :         if (Alphas(2) == "INSIDE") {
     972            1 :             ++state.dataSurface->TotUserIntConvModels;
     973            1 :         } else if (Alphas(2) == "OUTSIDE") {
     974            1 :             ++state.dataSurface->TotUserExtConvModels;
     975              :         }
     976              : 
     977            2 :         if (Alphas(6) == "INSIDE") {
     978            1 :             ++state.dataSurface->TotUserIntConvModels;
     979            1 :         } else if (Alphas(6) == "OUTSIDE") {
     980            1 :             ++state.dataSurface->TotUserExtConvModels;
     981              :         }
     982            2 :         if (NumAlphas >= 2 && ipsc->lAlphaFieldBlanks(2)) {
     983            0 :             ShowWarningError(state,
     984            0 :                              format("GetUserConvectionCoefficients: {}, for {}={}", CurrentModuleObject, ipsc->cAlphaFieldNames(1), Alphas(1)));
     985            0 :             ShowContinueError(state, format("{} is blank and rest of fields will not be processed.", ipsc->cAlphaFieldNames(2)));
     986              :         }
     987            2 :         if (NumAlphas >= 6 && ipsc->lAlphaFieldBlanks(6)) {
     988            0 :             ShowWarningError(state,
     989            0 :                              format("GetUserConvectionCoefficients: {}, for {}={}", CurrentModuleObject, ipsc->cAlphaFieldNames(1), Alphas(1)));
     990            0 :             ShowContinueError(state, format("{} is blank and rest of fields will not be processed.", ipsc->cAlphaFieldNames(6)));
     991              :         }
     992              :     }
     993              : 
     994          123 :     state.dataSurface->userIntConvModels.allocate(state.dataSurface->TotUserIntConvModels);
     995          123 :     state.dataSurface->userExtConvModels.allocate(state.dataSurface->TotUserExtConvModels);
     996              : 
     997          123 :     state.dataSurface->TotUserIntConvModels = 0;
     998          123 :     state.dataSurface->TotUserExtConvModels = 0;
     999              : 
    1000              :     //   Now, get for real and check for consistency
    1001          123 :     CurrentModuleObject = "SurfaceProperty:ConvectionCoefficients";
    1002          123 :     Count = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
    1003          125 :     for (int Loop = 1; Loop <= Count; ++Loop) {
    1004            4 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1005              :                                                                  CurrentModuleObject,
    1006              :                                                                  Loop,
    1007              :                                                                  Alphas,
    1008              :                                                                  NumAlphas,
    1009              :                                                                  Numbers,
    1010              :                                                                  NumNumbers,
    1011              :                                                                  Status,
    1012            2 :                                                                  ipsc->lNumericFieldBlanks,
    1013            2 :                                                                  ipsc->lAlphaFieldBlanks,
    1014            2 :                                                                  ipsc->cAlphaFieldNames,
    1015            2 :                                                                  ipsc->cNumericFieldNames);
    1016              : 
    1017            2 :         ErrorObjectHeader eoh{RoutineName, CurrentModuleObject, ""};
    1018            2 :         int surfNum = Util::FindItemInList(Alphas(1), Surface);
    1019              : 
    1020            2 :         if (surfNum == 0) {
    1021            0 :             ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(1), Alphas(1));
    1022            0 :             ErrorsFound = true;
    1023            0 :             continue;
    1024              :         }
    1025              : 
    1026            6 :         for (int Pass = 1, Ptr = 2, FieldNo = 2, NumField = 1; Pass <= 2; ++Pass, Ptr += 4, FieldNo += 4, ++NumField) {
    1027              : 
    1028            4 :             if (Alphas(Ptr).empty()) continue;
    1029              : 
    1030            4 :             if (Alphas(Ptr) == "OUTSIDE") {
    1031            2 :                 if (Surface(surfNum).OSCPtr > 0) {
    1032            0 :                     ShowSevereError(
    1033              :                         state,
    1034            0 :                         format("GetUserSuppliedConvectionCoefficients: {}, OUTSIDE {} cannot be specified for OtherSideCoefficient Surface={}",
    1035              :                                CurrentModuleObject,
    1036              :                                CurrentModuleObject,
    1037              :                                Alphas(1)));
    1038            0 :                     ErrorsFound = true;
    1039              :                 }
    1040              : 
    1041            2 :                 HcExt hcExt = static_cast<HcExt>(getEnumValue(HcExtNamesUC, Alphas(Ptr + 1)));
    1042              : 
    1043            2 :                 switch (hcExt) {
    1044              : 
    1045            0 :                 case HcExt::ASHRAESimpleCombined:
    1046              :                 case HcExt::TarpHcOutside:
    1047              :                 case HcExt::MoWiTTHcOutside:
    1048              :                 case HcExt::DOE2HcOutside:
    1049              :                 case HcExt::AdaptiveConvectionAlgorithm: {
    1050            0 :                     ApplyExtConvValue(state, surfNum, hcExt, 0);
    1051            0 :                 } break;
    1052              : 
    1053            2 :                 case HcExt::Value: {
    1054            2 :                     ++state.dataSurface->TotUserExtConvModels;
    1055            2 :                     auto &userExtConvModel = state.dataSurface->userExtConvModels(state.dataSurface->TotUserExtConvModels);
    1056            2 :                     userExtConvModel.SurfaceName = Alphas(1);
    1057            2 :                     userExtConvModel.WhichSurface = surfNum;
    1058            2 :                     if (Numbers(NumField) < state.dataHeatBal->LowHConvLimit || Numbers(NumField) > state.dataHeatBal->HighHConvLimit) {
    1059            0 :                         ShowSevereError(state, format("{}{}=\"{}, out of range value", RoutineName, CurrentModuleObject, Alphas(1)));
    1060            0 :                         ShowContinueError(state,
    1061            0 :                                           format("{}={}, {}=[{:.5R}].",
    1062            0 :                                                  ipsc->cAlphaFieldNames(Ptr),
    1063              :                                                  Alphas(Ptr),
    1064            0 :                                                  ipsc->cNumericFieldNames(NumField),
    1065              :                                                  Numbers(NumField)));
    1066            0 :                         ShowContinueError(state,
    1067            0 :                                           format("Out-of-range from low/high limits=[>={:.9R}, <={:.1R}].",
    1068            0 :                                                  state.dataHeatBal->LowHConvLimit,
    1069            0 :                                                  state.dataHeatBal->HighHConvLimit));
    1070            0 :                         ShowContinueError(state, "Limits are set (or default) in HeatBalanceAlgorithm object.");
    1071            0 :                         ErrorsFound = true;
    1072              :                     }
    1073            2 :                     userExtConvModel.overrideType = OverrideType::Value;
    1074            2 :                     userExtConvModel.OverrideValue = Numbers(NumField);
    1075            2 :                     if (!ipsc->lAlphaFieldBlanks(Ptr + 2)) {
    1076            1 :                         ShowWarningError(state, format("{}{}=\"{}, duplicate value", RoutineName, CurrentModuleObject, Alphas(1)));
    1077            2 :                         ShowContinueError(state,
    1078            4 :                                           format("Since VALUE is used for \"{}\", {}={} is ignored.",
    1079            1 :                                                  ipsc->cAlphaFieldNames(FieldNo + 2),
    1080            1 :                                                  ipsc->cAlphaFieldNames(Ptr + 2),
    1081              :                                                  Alphas(Ptr + 2)));
    1082              :                     }
    1083            2 :                     ApplyExtConvValue(state, surfNum, hcExt, state.dataSurface->TotUserExtConvModels);
    1084            2 :                 } break;
    1085              : 
    1086            0 :                 case HcExt::Schedule: { // Schedule
    1087            0 :                     ++state.dataSurface->TotUserExtConvModels;
    1088            0 :                     auto &userExtConvModel = state.dataSurface->userExtConvModels(state.dataSurface->TotUserExtConvModels);
    1089            0 :                     userExtConvModel.SurfaceName = Alphas(1);
    1090            0 :                     userExtConvModel.WhichSurface = surfNum;
    1091            0 :                     userExtConvModel.overrideType = OverrideType::Schedule;
    1092            0 :                     if ((userExtConvModel.sched = Sched::GetSchedule(state, Alphas(Ptr + 2))) == nullptr) {
    1093            0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(Ptr + 2), Alphas(Ptr + 2));
    1094            0 :                         ErrorsFound = true;
    1095            0 :                     } else if (!userExtConvModel.sched->checkMinMaxVals(
    1096            0 :                                    state, Clusive::In, state.dataHeatBal->LowHConvLimit, Clusive::In, state.dataHeatBal->HighHConvLimit)) {
    1097            0 :                         Sched::ShowSevereBadMinMax(state,
    1098              :                                                    eoh,
    1099            0 :                                                    ipsc->cAlphaFieldNames(Ptr + 2),
    1100            0 :                                                    Alphas(Ptr + 2),
    1101              :                                                    Clusive::In,
    1102            0 :                                                    state.dataHeatBal->LowHConvLimit,
    1103              :                                                    Clusive::In,
    1104            0 :                                                    state.dataHeatBal->HighHConvLimit,
    1105              :                                                    "Limits are set (or default) in HeatBalanceAlgorithm object.");
    1106            0 :                         ErrorsFound = true;
    1107              :                     }
    1108            0 :                     ApplyExtConvValue(state, surfNum, hcExt, state.dataSurface->TotUserExtConvModels);
    1109            0 :                 } break;
    1110              : 
    1111            0 :                 case HcExt::UserCurve: { // User curve
    1112            0 :                     ++state.dataSurface->TotUserExtConvModels;
    1113            0 :                     auto &userExtConvModel = state.dataSurface->userExtConvModels(state.dataSurface->TotUserExtConvModels);
    1114            0 :                     userExtConvModel.SurfaceName = Alphas(1);
    1115            0 :                     userExtConvModel.WhichSurface = surfNum;
    1116            0 :                     userExtConvModel.overrideType = OverrideType::UserCurve;
    1117            0 :                     userExtConvModel.UserCurveIndex = Util::FindItemInList(Alphas(Ptr + 3), state.dataConvect->hcExtUserCurve);
    1118            0 :                     if (userExtConvModel.UserCurveIndex == 0) {
    1119            0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(Ptr + 3), Alphas(Ptr + 3));
    1120            0 :                         ErrorsFound = true;
    1121              :                     }
    1122            0 :                     ApplyExtConvValue(state, surfNum, hcExt, state.dataSurface->TotUserExtConvModels);
    1123            0 :                 } break;
    1124              : 
    1125            0 :                 case HcExt::UserValue: // Unhandled cases < HcExt::UserCurve
    1126              :                 case HcExt::UserSchedule:
    1127              :                 case HcExt::SetByZone:
    1128              :                 case HcExt::ASHRAETARP:
    1129              :                 case HcExt::BLASTHcOutside:
    1130              :                 case HcExt::None: {
    1131            0 :                     ShowSevereError(state, format("{}{}=\"{}, check input", RoutineName, CurrentModuleObject, Alphas(1)));
    1132            0 :                     ShowContinueError(state, format("Check Input Entered :{}", Alphas(Ptr + 1)));
    1133            0 :                     ErrorsFound = true;
    1134            0 :                 } break;
    1135              : 
    1136            0 :                 default: { // ExtValue > HcExt::UserCurve
    1137              :                     // specificmodel
    1138            0 :                     ++state.dataSurface->TotUserExtConvModels;
    1139            0 :                     auto &userExtConvModel = state.dataSurface->userExtConvModels(state.dataSurface->TotUserExtConvModels);
    1140            0 :                     userExtConvModel.SurfaceName = Alphas(1);
    1141            0 :                     userExtConvModel.WhichSurface = surfNum;
    1142            0 :                     userExtConvModel.overrideType = OverrideType::SpecifiedModel;
    1143            0 :                     userExtConvModel.HcExtModelEq = hcExt;
    1144            0 :                     ApplyExtConvValue(state, surfNum, hcExt, state.dataSurface->TotUserExtConvModels);
    1145            0 :                 } break;
    1146              :                 } // switch (ExtValue)
    1147              : 
    1148            2 :             } else if (Alphas(Ptr) == "INSIDE") {
    1149              : 
    1150            2 :                 if (state.dataSurface->surfIntConv(surfNum).userModelNum != 0) {
    1151            0 :                     ShowSevereError(state, format("{}{}=\"{}, duplicate (inside)", RoutineName, CurrentModuleObject, Alphas(1)));
    1152            0 :                     ShowContinueError(state, "Duplicate (Inside) assignment attempt.");
    1153            0 :                     ErrorsFound = true;
    1154            0 :                     continue;
    1155              :                 }
    1156              : 
    1157            2 :                 HcInt hcInt = static_cast<HcInt>(getEnumValue(HcIntNamesUC, Alphas(Ptr + 1)));
    1158              : 
    1159            2 :                 switch (hcInt) {
    1160              :                 // Are these not used anymore? They can be deleted then
    1161            0 :                 case HcInt::UserValue:
    1162              :                 case HcInt::UserSchedule:
    1163              :                 case HcInt::SetByZone: {
    1164            0 :                     ShowSevereError(state, format("{}{}=\"{}, invalid value", RoutineName, CurrentModuleObject, Alphas(1)));
    1165            0 :                     ShowContinueError(state, format("Invalid Value Entered, for {}={}", ipsc->cAlphaFieldNames(Ptr), Alphas(Ptr)));
    1166            0 :                     ShowContinueError(state, format("invalid value in {}={}", ipsc->cAlphaFieldNames(Ptr + 1), Alphas(Ptr + 1)));
    1167            0 :                     ErrorsFound = true;
    1168            0 :                 } break;
    1169              : 
    1170            0 :                 case HcInt::CeilingDiffuser:
    1171              :                 case HcInt::TrombeWall: {
    1172            0 :                     ShowSevereError(state, format("{}{}=\"{}, invalid value", RoutineName, CurrentModuleObject, Alphas(1)));
    1173            0 :                     ShowContinueError(state, format("Invalid Value Entered, for {}={}", ipsc->cAlphaFieldNames(Ptr), Alphas(Ptr)));
    1174            0 :                     ShowContinueError(state,
    1175            0 :                                       format("invalid value in {}={}\". This type is only applicable at a Zone level.",
    1176            0 :                                              ipsc->cAlphaFieldNames(Ptr + 1),
    1177              :                                              Alphas(Ptr + 1)));
    1178            0 :                     ErrorsFound = true;
    1179            0 :                 } break;
    1180              : 
    1181            0 :                 case HcInt::ASHRAESimple:
    1182              :                 case HcInt::ASHRAETARP:
    1183              :                 case HcInt::AdaptiveConvectionAlgorithm:
    1184              :                 case HcInt::ASTMC1340: {
    1185            0 :                     ApplyIntConvValue(state, surfNum, hcInt, 0);
    1186            0 :                 } break;
    1187              : 
    1188            2 :                 case HcInt::Value: {
    1189            2 :                     ++state.dataSurface->TotUserIntConvModels;
    1190            2 :                     auto &userIntConvModel = state.dataSurface->userIntConvModels(state.dataSurface->TotUserIntConvModels);
    1191            2 :                     userIntConvModel.SurfaceName = Alphas(1);
    1192            2 :                     userIntConvModel.WhichSurface = surfNum;
    1193            2 :                     if (Numbers(NumField) < state.dataHeatBal->LowHConvLimit || Numbers(NumField) > state.dataHeatBal->HighHConvLimit) {
    1194            0 :                         ShowSevereBadMinMax(state,
    1195              :                                             eoh,
    1196            0 :                                             ipsc->cNumericFieldNames(NumField),
    1197            0 :                                             Numbers(NumField),
    1198              :                                             Clusive::In,
    1199            0 :                                             state.dataHeatBal->LowHConvLimit,
    1200              :                                             Clusive::In,
    1201            0 :                                             state.dataHeatBal->HighHConvLimit,
    1202              :                                             "Limits are set (or default) in HeatBalanceAlgorithm object.");
    1203            0 :                         ErrorsFound = true;
    1204              :                     }
    1205            2 :                     userIntConvModel.overrideType = OverrideType::Value;
    1206            2 :                     userIntConvModel.OverrideValue = Numbers(NumField);
    1207            2 :                     if (!ipsc->lAlphaFieldBlanks(Ptr + 2)) {
    1208            1 :                         ShowWarningError(state, format("{}{}=\"{}, duplicate value", RoutineName, CurrentModuleObject, Alphas(1)));
    1209            2 :                         ShowContinueError(state,
    1210            4 :                                           format("Since VALUE is used for \"{}\", {}={} is ignored.",
    1211            1 :                                                  ipsc->cAlphaFieldNames(FieldNo + 1),
    1212            1 :                                                  ipsc->cAlphaFieldNames(Ptr + 2),
    1213              :                                                  Alphas(Ptr + 2)));
    1214              :                     }
    1215            2 :                     ApplyIntConvValue(state, surfNum, hcInt, state.dataSurface->TotUserIntConvModels);
    1216            2 :                 } break;
    1217              : 
    1218            0 :                 case HcInt::Schedule: {
    1219            0 :                     ++state.dataSurface->TotUserIntConvModels;
    1220            0 :                     auto &userIntConvModel = state.dataSurface->userIntConvModels(state.dataSurface->TotUserIntConvModels);
    1221            0 :                     userIntConvModel.SurfaceName = Alphas(1);
    1222            0 :                     userIntConvModel.WhichSurface = surfNum;
    1223            0 :                     userIntConvModel.overrideType = OverrideType::Schedule;
    1224            0 :                     if ((userIntConvModel.sched = Sched::GetSchedule(state, Alphas(Ptr + 2))) == nullptr) {
    1225            0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(Ptr + 2), Alphas(Ptr + 2));
    1226            0 :                         ErrorsFound = true;
    1227            0 :                     } else if (!userIntConvModel.sched->checkMinMaxVals(
    1228            0 :                                    state, Clusive::In, state.dataHeatBal->LowHConvLimit, Clusive::In, state.dataHeatBal->HighHConvLimit)) {
    1229            0 :                         Sched::ShowSevereBadMinMax(state,
    1230              :                                                    eoh,
    1231            0 :                                                    ipsc->cAlphaFieldNames(Ptr + 2),
    1232            0 :                                                    Alphas(Ptr + 2),
    1233              :                                                    Clusive::In,
    1234            0 :                                                    state.dataHeatBal->LowHConvLimit,
    1235              :                                                    Clusive::In,
    1236            0 :                                                    state.dataHeatBal->HighHConvLimit,
    1237              :                                                    "Limits are set (or default) in HeatBalanceAlgorithm object.");
    1238            0 :                         ErrorsFound = true;
    1239              :                     }
    1240            0 :                     ApplyIntConvValue(state, surfNum, hcInt, state.dataSurface->TotUserIntConvModels);
    1241            0 :                 } break;
    1242              : 
    1243            0 :                 case HcInt::UserCurve: {
    1244            0 :                     ++state.dataSurface->TotUserIntConvModels;
    1245            0 :                     auto &userIntConvModel = state.dataSurface->userIntConvModels(state.dataSurface->TotUserIntConvModels);
    1246            0 :                     userIntConvModel.SurfaceName = Alphas(1);
    1247            0 :                     userIntConvModel.WhichSurface = surfNum;
    1248            0 :                     userIntConvModel.overrideType = OverrideType::UserCurve;
    1249            0 :                     userIntConvModel.UserCurveIndex = Util::FindItemInList(Alphas(Ptr + 3), state.dataConvect->hcIntUserCurve);
    1250            0 :                     if (userIntConvModel.UserCurveIndex == 0) {
    1251            0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(Ptr + 3), Alphas(Ptr + 3));
    1252            0 :                         ErrorsFound = true;
    1253              :                     }
    1254            0 :                     ApplyIntConvValue(state, surfNum, hcInt, state.dataSurface->TotUserIntConvModels);
    1255            0 :                 } break;
    1256              : 
    1257            0 :                 default: { // > HcInt::UserCurve
    1258              :                     // specificmodel
    1259            0 :                     ++state.dataSurface->TotUserIntConvModels;
    1260            0 :                     auto &userIntConvModel = state.dataSurface->userIntConvModels(state.dataSurface->TotUserIntConvModels);
    1261            0 :                     userIntConvModel.SurfaceName = Alphas(1);
    1262            0 :                     userIntConvModel.WhichSurface = surfNum;
    1263            0 :                     userIntConvModel.overrideType = OverrideType::SpecifiedModel;
    1264            0 :                     userIntConvModel.HcIntModelEq = hcInt;
    1265            0 :                     ApplyIntConvValue(state, surfNum, hcInt, state.dataSurface->TotUserIntConvModels);
    1266            0 :                 } break;
    1267              :                 } // switch(HcInt)
    1268              :             }     // if ("INSIDE")
    1269              :         }         // for (pass)
    1270              :     }             // for (Loop)
    1271              : 
    1272          123 :     CurrentModuleObject = "SurfaceProperty:ConvectionCoefficients:MultipleSurface";
    1273          123 :     Count = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
    1274          125 :     for (int Loop = 1; Loop <= Count; ++Loop) {
    1275            4 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1276              :                                                                  CurrentModuleObject,
    1277              :                                                                  Loop,
    1278              :                                                                  Alphas,
    1279              :                                                                  NumAlphas,
    1280              :                                                                  Numbers,
    1281              :                                                                  NumNumbers,
    1282              :                                                                  Status,
    1283            2 :                                                                  ipsc->lNumericFieldBlanks,
    1284            2 :                                                                  ipsc->lAlphaFieldBlanks,
    1285            2 :                                                                  ipsc->cAlphaFieldNames,
    1286            2 :                                                                  ipsc->cNumericFieldNames);
    1287              :         // Check Field 1 for validity
    1288            2 :         ErrorObjectHeader eoh{RoutineName, CurrentModuleObject, ""};
    1289            2 :         SurfaceFilter surfaceFilter = static_cast<SurfaceFilter>(getEnumValue(SurfaceFilterNamesUC, Alphas(1)));
    1290              : 
    1291            6 :         for (int Pass = 1, Ptr = 2, FieldNo = 2, NumField = 1; Pass <= 2; ++Pass, Ptr += 4, FieldNo += 4, ++NumField) {
    1292              : 
    1293            4 :             if (Alphas(Ptr).empty()) continue;
    1294              : 
    1295            4 :             if (Alphas(Ptr) == "OUTSIDE") {
    1296              : 
    1297            2 :                 HcExt hcExt = static_cast<HcExt>(getEnumValue(HcExtNamesUC, Alphas(Ptr + 1)));
    1298              : 
    1299            2 :                 switch (hcExt) {
    1300              : 
    1301              :                 // Are these not used anymore? Can just get rid of them and let these inputs become HcExt::Invalid;
    1302            0 :                 case HcExt::SetByZone:
    1303              :                 case HcExt::BLASTHcOutside:
    1304              :                 case HcExt::UserValue:
    1305              :                 case HcExt::UserSchedule: {
    1306            0 :                     ShowSevereError(state, format("{}{}=\"{}, check input", RoutineName, CurrentModuleObject, Alphas(1)));
    1307            0 :                     ShowContinueError(state, format("Check Input Entered :{}", Alphas(Ptr + 1)));
    1308            0 :                     ErrorsFound = true;
    1309            0 :                 } break;
    1310              : 
    1311            2 :                 case HcExt::ASHRAESimple:
    1312              :                 case HcExt::ASHRAETARP:
    1313              :                 case HcExt::MoWiTTHcOutside:
    1314              :                 case HcExt::DOE2HcOutside:
    1315              :                 case HcExt::AdaptiveConvectionAlgorithm: {
    1316            2 :                     ApplyExtConvValueMulti(state, surfaceFilter, hcExt, 0);
    1317            2 :                 } break;
    1318              : 
    1319            0 :                 case HcExt::Value: {
    1320              :                     // SimpleValueAssignment via userExtConvModels array
    1321            0 :                     ++state.dataSurface->TotUserExtConvModels;
    1322            0 :                     auto &userExtConvModel = state.dataSurface->userExtConvModels(state.dataSurface->TotUserExtConvModels);
    1323            0 :                     userExtConvModel.SurfaceName = Alphas(Ptr);
    1324            0 :                     userExtConvModel.WhichSurface = -999;
    1325            0 :                     if (Numbers(NumField) < state.dataHeatBal->LowHConvLimit || Numbers(NumField) > state.dataHeatBal->HighHConvLimit) {
    1326            0 :                         ShowSevereBadMinMax(state,
    1327              :                                             eoh,
    1328            0 :                                             ipsc->cNumericFieldNames(NumField),
    1329            0 :                                             Numbers(NumField),
    1330              :                                             Clusive::In,
    1331            0 :                                             state.dataHeatBal->LowHConvLimit,
    1332              :                                             Clusive::In,
    1333            0 :                                             state.dataHeatBal->HighHConvLimit,
    1334              :                                             "Limits are set (or default) in HeatBalanceAlgorithm object.");
    1335            0 :                         ErrorsFound = true;
    1336              :                     }
    1337            0 :                     userExtConvModel.overrideType = OverrideType::Value;
    1338            0 :                     userExtConvModel.OverrideValue = Numbers(NumField);
    1339            0 :                     if (!ipsc->lAlphaFieldBlanks(Ptr + 2)) {
    1340            0 :                         ShowWarningError(state, format("{}{}=\"{}, duplicate value", RoutineName, CurrentModuleObject, Alphas(1)));
    1341            0 :                         ShowContinueError(state,
    1342            0 :                                           format("Since VALUE is used for \"{}\", {}={} is ignored.",
    1343            0 :                                                  ipsc->cAlphaFieldNames(FieldNo + 2),
    1344            0 :                                                  ipsc->cAlphaFieldNames(Ptr + 2),
    1345              :                                                  Alphas(Ptr + 2)));
    1346              :                     }
    1347            0 :                     ApplyExtConvValueMulti(state, surfaceFilter, hcExt, state.dataSurface->TotUserExtConvModels);
    1348            0 :                 } break;
    1349              : 
    1350            0 :                 case HcExt::Schedule: {
    1351            0 :                     ++state.dataSurface->TotUserExtConvModels;
    1352            0 :                     auto &userExtConvModel = state.dataSurface->userExtConvModels(state.dataSurface->TotUserExtConvModels);
    1353            0 :                     userExtConvModel.SurfaceName = Alphas(Ptr);
    1354            0 :                     userExtConvModel.WhichSurface = -999;
    1355            0 :                     userExtConvModel.overrideType = OverrideType::Schedule;
    1356            0 :                     if ((userExtConvModel.sched = Sched::GetSchedule(state, Alphas(Ptr + 2))) == nullptr) {
    1357            0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(Ptr + 2), Alphas(Ptr + 2));
    1358            0 :                         ErrorsFound = true;
    1359            0 :                     } else if (!userExtConvModel.sched->checkMinMaxVals(
    1360            0 :                                    state, Clusive::In, state.dataHeatBal->LowHConvLimit, Clusive::In, state.dataHeatBal->HighHConvLimit)) {
    1361            0 :                         Sched::ShowSevereBadMinMax(state,
    1362              :                                                    eoh,
    1363            0 :                                                    ipsc->cAlphaFieldNames(Ptr + 2),
    1364            0 :                                                    Alphas(Ptr + 2),
    1365              :                                                    Clusive::In,
    1366            0 :                                                    state.dataHeatBal->LowHConvLimit,
    1367              :                                                    Clusive::In,
    1368            0 :                                                    state.dataHeatBal->HighHConvLimit,
    1369              :                                                    "Limits are set (or default) in HeatBalanceAlgorithm object.");
    1370            0 :                         ErrorsFound = true;
    1371              :                     }
    1372            0 :                     ApplyExtConvValueMulti(state, surfaceFilter, hcExt, state.dataSurface->TotUserExtConvModels);
    1373            0 :                 } break;
    1374              : 
    1375            0 :                 case HcExt::UserCurve: { // User curve
    1376            0 :                     ++state.dataSurface->TotUserExtConvModels;
    1377            0 :                     auto &userExtConvModel = state.dataSurface->userExtConvModels(state.dataSurface->TotUserExtConvModels);
    1378            0 :                     userExtConvModel.SurfaceName = Alphas(Ptr);
    1379            0 :                     userExtConvModel.WhichSurface = -999;
    1380            0 :                     userExtConvModel.overrideType = OverrideType::UserCurve;
    1381            0 :                     userExtConvModel.UserCurveIndex = Util::FindItemInList(Alphas(Ptr + 3), state.dataConvect->hcExtUserCurve);
    1382            0 :                     if (userExtConvModel.UserCurveIndex == 0) {
    1383            0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(Ptr + 3), Alphas(Ptr + 3));
    1384            0 :                         ErrorsFound = true;
    1385              :                     }
    1386            0 :                     ApplyExtConvValueMulti(state, surfaceFilter, hcExt, state.dataSurface->TotUserExtConvModels);
    1387            0 :                 } break;
    1388              : 
    1389            0 :                 default: { // > HcExt::UserCurve
    1390              :                     // specificmodel
    1391            0 :                     ++state.dataSurface->TotUserExtConvModels;
    1392            0 :                     auto &userExtConvModel = state.dataSurface->userExtConvModels(state.dataSurface->TotUserExtConvModels);
    1393            0 :                     userExtConvModel.SurfaceName = Alphas(Ptr);
    1394            0 :                     userExtConvModel.WhichSurface = -999;
    1395            0 :                     userExtConvModel.overrideType = OverrideType::SpecifiedModel;
    1396            0 :                     userExtConvModel.HcExtModelEq = hcExt;
    1397            0 :                     ApplyExtConvValueMulti(state, surfaceFilter, hcExt, state.dataSurface->TotUserExtConvModels);
    1398            0 :                 } break;
    1399              :                 } // switch (hcExt)
    1400              : 
    1401            2 :             } else if (Alphas(Ptr) == "INSIDE") {
    1402            2 :                 HcInt hcInt = static_cast<HcInt>(getEnumValue(HcIntNamesUC, Alphas(Ptr + 1)));
    1403              : 
    1404            2 :                 switch (hcInt) {
    1405              : 
    1406              :                 // Are these not used anymore? We can delete them and let them become HcInt::Invalid
    1407            0 :                 case HcInt::SetByZone:
    1408              :                 case HcInt::UserValue:
    1409              :                 case HcInt::UserSchedule: {
    1410            0 :                     ShowSevereError(state, format("{}{}=\"{}, invalid value", RoutineName, CurrentModuleObject, Alphas(1)));
    1411            0 :                     ShowContinueError(state, format(" Invalid {} entered={}", ipsc->cAlphaFieldNames(Ptr + 1), Alphas(Ptr + 1)));
    1412            0 :                     ErrorsFound = true;
    1413            0 :                 } break;
    1414              : 
    1415            0 :                 case HcInt::CeilingDiffuser:
    1416              :                 case HcInt::TrombeWall: {
    1417            0 :                     ShowSevereError(state, format("{}{}=\"{}, invalid value", RoutineName, CurrentModuleObject, Alphas(1)));
    1418            0 :                     ShowContinueError(state, format(" Invalid {} entered={}", ipsc->cAlphaFieldNames(Ptr), Alphas(Ptr)));
    1419            0 :                     ShowContinueError(state,
    1420            0 :                                       format("invalid value in {}={}\". This type is only applicable at a Zone level.",
    1421            0 :                                              ipsc->cAlphaFieldNames(Ptr + 1),
    1422              :                                              Alphas(Ptr + 1)));
    1423            0 :                     ErrorsFound = true;
    1424            0 :                 } break;
    1425              : 
    1426            0 :                 case HcInt::ASHRAESimple:
    1427              :                 case HcInt::ASHRAETARP:
    1428              :                 case HcInt::AdaptiveConvectionAlgorithm:
    1429              :                 case HcInt::ASTMC1340: {
    1430            0 :                     ApplyIntConvValueMulti(state, surfaceFilter, hcInt, 0);
    1431            0 :                 } break;
    1432              : 
    1433            0 :                 case HcInt::Value: {
    1434              :                     // SimpleValueAssignment via userExtConvModels array
    1435            0 :                     ++state.dataSurface->TotUserIntConvModels;
    1436            0 :                     auto &userIntConvModel = state.dataSurface->userIntConvModels(state.dataSurface->TotUserIntConvModels);
    1437            0 :                     userIntConvModel.SurfaceName = Alphas(Ptr);
    1438            0 :                     userIntConvModel.WhichSurface = -999;
    1439            0 :                     if (Numbers(NumField) < state.dataHeatBal->LowHConvLimit || Numbers(NumField) > state.dataHeatBal->HighHConvLimit) {
    1440            0 :                         ShowSevereBadMinMax(state,
    1441              :                                             eoh,
    1442            0 :                                             ipsc->cNumericFieldNames(NumField),
    1443            0 :                                             Numbers(NumField),
    1444              :                                             Clusive::In,
    1445            0 :                                             state.dataHeatBal->LowHConvLimit,
    1446              :                                             Clusive::In,
    1447            0 :                                             state.dataHeatBal->HighHConvLimit,
    1448              :                                             "Limits are set (or default) in HeatBalanceAlgorithm object.");
    1449            0 :                         ErrorsFound = true;
    1450              :                     }
    1451            0 :                     userIntConvModel.overrideType = OverrideType::Value;
    1452            0 :                     userIntConvModel.OverrideValue = Numbers(NumField);
    1453            0 :                     if (!ipsc->lAlphaFieldBlanks(Ptr + 2)) {
    1454            0 :                         ShowWarningError(state, format("{}{}=\"{}, duplicate value", RoutineName, CurrentModuleObject, Alphas(1)));
    1455            0 :                         ShowContinueError(state,
    1456            0 :                                           format("Since VALUE is used for \"{}\", {}={} is ignored.",
    1457            0 :                                                  ipsc->cAlphaFieldNames(FieldNo + 2),
    1458            0 :                                                  ipsc->cAlphaFieldNames(Ptr + 2),
    1459              :                                                  Alphas(Ptr + 2)));
    1460              :                     }
    1461            0 :                     ApplyIntConvValueMulti(state, surfaceFilter, hcInt, state.dataSurface->TotUserIntConvModels);
    1462            0 :                 } break;
    1463              : 
    1464            0 :                 case HcInt::Schedule: {
    1465            0 :                     ++state.dataSurface->TotUserIntConvModels;
    1466            0 :                     auto &userIntConvModel = state.dataSurface->userIntConvModels(state.dataSurface->TotUserIntConvModels);
    1467            0 :                     userIntConvModel.SurfaceName = Alphas(Ptr);
    1468            0 :                     userIntConvModel.WhichSurface = -999;
    1469            0 :                     userIntConvModel.overrideType = OverrideType::Schedule;
    1470            0 :                     if ((userIntConvModel.sched = Sched::GetSchedule(state, Alphas(Ptr + 2))) == nullptr) {
    1471            0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(Ptr + 2), Alphas(Ptr + 2));
    1472            0 :                         ErrorsFound = true;
    1473            0 :                     } else if (!userIntConvModel.sched->checkMinMaxVals(state,
    1474              :                                                                         Clusive::In,
    1475            0 :                                                                         state.dataHeatBal->LowHConvLimit, // >=
    1476              :                                                                         Clusive::In,
    1477            0 :                                                                         state.dataHeatBal->HighHConvLimit)) { // <=
    1478            0 :                         Sched::ShowSevereBadMinMax(state,
    1479              :                                                    eoh,
    1480            0 :                                                    ipsc->cAlphaFieldNames(Ptr + 2),
    1481            0 :                                                    Alphas(Ptr + 2),
    1482              :                                                    Clusive::In,
    1483            0 :                                                    state.dataHeatBal->LowHConvLimit,
    1484              :                                                    Clusive::In,
    1485            0 :                                                    state.dataHeatBal->HighHConvLimit,
    1486              :                                                    "Limits are set (or default) in HeatBalanceAlgorithm object.");
    1487            0 :                         ErrorsFound = true;
    1488              :                     }
    1489            0 :                     ApplyIntConvValueMulti(state, surfaceFilter, hcInt, state.dataSurface->TotUserIntConvModels);
    1490            0 :                 } break;
    1491              : 
    1492            0 :                 case HcInt::UserCurve: {
    1493            0 :                     ++state.dataSurface->TotUserIntConvModels;
    1494            0 :                     auto &userIntConvModel = state.dataSurface->userIntConvModels(state.dataSurface->TotUserIntConvModels);
    1495            0 :                     userIntConvModel.SurfaceName = Alphas(Ptr);
    1496            0 :                     userIntConvModel.WhichSurface = -999;
    1497            0 :                     userIntConvModel.overrideType = OverrideType::UserCurve;
    1498            0 :                     userIntConvModel.UserCurveIndex = Util::FindItemInList(Alphas(Ptr + 3), state.dataConvect->hcIntUserCurve);
    1499            0 :                     if (userIntConvModel.UserCurveIndex == 0) {
    1500            0 :                         ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(Ptr + 3), Alphas(Ptr + 3));
    1501            0 :                         ErrorsFound = true;
    1502              :                     }
    1503            0 :                     ApplyIntConvValueMulti(state, surfaceFilter, hcInt, state.dataSurface->TotUserIntConvModels);
    1504            0 :                 } break;
    1505              : 
    1506            2 :                 default: { // > HcInt::UserCurve
    1507              :                     // specificmodel
    1508            2 :                     ++state.dataSurface->TotUserIntConvModels;
    1509            2 :                     auto &userIntConvModel = state.dataSurface->userIntConvModels(state.dataSurface->TotUserIntConvModels);
    1510            2 :                     userIntConvModel.SurfaceName = Alphas(Ptr);
    1511            2 :                     userIntConvModel.WhichSurface = -999;
    1512            2 :                     userIntConvModel.overrideType = OverrideType::SpecifiedModel;
    1513            2 :                     userIntConvModel.HcIntModelEq = hcInt;
    1514            2 :                     ApplyIntConvValueMulti(state, surfaceFilter, hcInt, state.dataSurface->TotUserIntConvModels);
    1515            2 :                 } break;
    1516              :                 } // switch (hcIn)
    1517              : 
    1518              :             } else { // Error Case
    1519            0 :                 ShowSevereError(state, format("{}{}=\"{}, invalid value", RoutineName, CurrentModuleObject, Alphas(1)));
    1520            0 :                 ShowContinueError(state, format(" Invalid {} entered={}", ipsc->cAlphaFieldNames(Ptr), Alphas(Ptr)));
    1521            0 :                 ErrorsFound = true;
    1522              :             }
    1523              :         } // for (Pass)
    1524              :     }     // for (Loop)
    1525              : 
    1526          232 :     if (state.dataHeatBal->DefaultExtConvAlgo == HcExt::ASHRAESimple ||
    1527          233 :         std::any_of(Zone.begin(), Zone.end(), [](DataHeatBalance::ZoneData const &e) { return e.ExtConvAlgo == HcExt::ASHRAESimple; })) {
    1528           14 :         Count = 0;
    1529           16 :         for (int Loop = 1; Loop <= state.dataSurface->TotUserExtConvModels; ++Loop) {
    1530            2 :             auto const &userExtConvModel = state.dataSurface->userExtConvModels(Loop);
    1531            2 :             int SurfNum = userExtConvModel.WhichSurface;
    1532              :             // Tests show that Zone will override the simple convection specification of global.
    1533            2 :             if (SurfNum <= 0) continue;               // ignore this error condition
    1534            2 :             if (Surface(SurfNum).Zone == 0) continue; // ignore this error condition
    1535            0 :             if (Zone(Surface(SurfNum).Zone).ExtConvAlgo == HcExt::ASHRAESimple &&
    1536            0 :                 ((userExtConvModel.overrideType == OverrideType::SpecifiedModel && userExtConvModel.HcExtModelEq != HcExt::ASHRAESimple) ||
    1537            0 :                  userExtConvModel.overrideType != OverrideType::SpecifiedModel)) {
    1538            0 :                 ++Count;
    1539            0 :                 if (state.dataGlobal->DisplayExtraWarnings) {
    1540            0 :                     ShowSevereError(state, format("{}Surface=\"{}\", mixed algorithms.", RoutineName, userExtConvModel.SurfaceName));
    1541            0 :                     ShowContinueError(
    1542              :                         state, "Zone Outside Convection Algorithm specifies \"SimpleCombined\". SimpleCombined will be used for this surface.");
    1543              :                 }
    1544              :             }
    1545              :         }
    1546           14 :         if (Count > 0) {
    1547            0 :             ShowSevereMessage(state,
    1548            0 :                               format("{}{}", RoutineName, format("{} surfaces had different outside convection algorithms specified when", Count)));
    1549            0 :             ShowContinueError(state,
    1550              :                               "the Zone Outside Convection Algorithm specifies \"SimpleCombined\". SimpleCombined will be used for these surfaces.");
    1551            0 :             if (!state.dataGlobal->DisplayExtraWarnings) {
    1552            0 :                 ShowContinueError(state, "Use OutputDiagnostics,DisplayExtraWarnings; to see specific instances.");
    1553            0 :                 state.dataErrTracking->TotalSevereErrors += Count;
    1554              :             }
    1555              :         }
    1556              :     }
    1557              : 
    1558              :     // get SurfaceConvectionAlgorithm:Inside:AdaptiveModelSelections
    1559              : 
    1560          123 :     CurrentModuleObject = "SurfaceConvectionAlgorithm:Inside:AdaptiveModelSelections";
    1561          123 :     Count = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
    1562          123 :     if (Count == 1) {
    1563           10 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1564              :                                                                  CurrentModuleObject,
    1565              :                                                                  1,
    1566            5 :                                                                  ipsc->cAlphaArgs,
    1567              :                                                                  NumAlphas,
    1568            5 :                                                                  ipsc->rNumericArgs,
    1569              :                                                                  NumNumbers,
    1570              :                                                                  Status,
    1571            5 :                                                                  ipsc->lNumericFieldBlanks,
    1572            5 :                                                                  ipsc->lAlphaFieldBlanks,
    1573            5 :                                                                  ipsc->cAlphaFieldNames,
    1574            5 :                                                                  ipsc->cNumericFieldNames);
    1575              :         // state.dataConvect->intAdaptiveConvAlgo.Name = ipsc->cAlphaArgs(1); // not used by E+, unique object
    1576            5 :         ErrorObjectHeader eoh{RoutineName, CurrentModuleObject, ipsc->cAlphaArgs(1)};
    1577              : 
    1578            5 :         auto &intAlgo = state.dataConvect->intAdaptiveConvAlgo;
    1579          230 :         for (int iInConvClass = 0, i = 2; iInConvClass < (int)IntConvClass::Num && i <= NumAlphas; ++iInConvClass, i += 2) {
    1580              : 
    1581          225 :             intAlgo.intConvClassEqNums[iInConvClass] = static_cast<HcInt>(getEnumValue(HcIntNamesUC, ipsc->cAlphaArgs(i)));
    1582              : 
    1583          225 :             if (intAlgo.intConvClassEqNums[iInConvClass] == HcInt::Invalid) {
    1584            0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(i), ipsc->cAlphaArgs(i));
    1585            0 :                 ErrorsFound = true;
    1586          225 :             } else if (intAlgo.intConvClassEqNums[iInConvClass] == HcInt::UserCurve) {
    1587            2 :                 intAlgo.intConvClassUserCurveNums[iInConvClass] = Util::FindItemInList(ipsc->cAlphaArgs(i + 1), state.dataConvect->hcIntUserCurve);
    1588            2 :                 if (intAlgo.intConvClassUserCurveNums[iInConvClass] == 0) {
    1589            0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(i + 1), ipsc->cAlphaArgs(i + 1));
    1590            0 :                     ErrorsFound = true;
    1591              :                 }
    1592              :             }
    1593              :         } // for (iInConvClass)
    1594              :     }
    1595              : 
    1596          123 :     CurrentModuleObject = "SurfaceConvectionAlgorithm:Outside:AdaptiveModelSelections";
    1597          123 :     Count = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
    1598          123 :     if (Count == 1) {
    1599           10 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1600              :                                                                  CurrentModuleObject,
    1601              :                                                                  1,
    1602            5 :                                                                  ipsc->cAlphaArgs,
    1603              :                                                                  NumAlphas,
    1604            5 :                                                                  ipsc->rNumericArgs,
    1605              :                                                                  NumNumbers,
    1606              :                                                                  Status,
    1607            5 :                                                                  ipsc->lNumericFieldBlanks,
    1608            5 :                                                                  ipsc->lAlphaFieldBlanks,
    1609            5 :                                                                  ipsc->cAlphaFieldNames,
    1610            5 :                                                                  ipsc->cNumericFieldNames);
    1611              : 
    1612              :         // state.dataConvect->ExtAdaptiveConvAlgo.Name = ipsc->cAlphaArgs(1); // not used by E+, unique object
    1613            5 :         ErrorObjectHeader eoh{RoutineName, CurrentModuleObject, ipsc->cAlphaArgs(1)};
    1614            5 :         auto &extAlgo = state.dataConvect->extAdaptiveConvAlgo;
    1615              : 
    1616           10 :         for (int iOutConvClass = 0, i = 2; i < (int)ExtConvClass::Num && i <= NumAlphas; ++iOutConvClass, i += 2) {
    1617              : 
    1618            5 :             extAlgo.extConvClass2EqNums[iOutConvClass] = static_cast<HcExt>(getEnumValue(HcExtNamesUC, ipsc->cAlphaArgs(i)));
    1619              : 
    1620            5 :             if (extAlgo.extConvClass2EqNums[iOutConvClass] == HcExt::Invalid) {
    1621            0 :                 ShowSevereInvalidKey(state, eoh, ipsc->cAlphaFieldNames(i), ipsc->cAlphaArgs(i));
    1622            0 :                 ErrorsFound = true;
    1623              : 
    1624            5 :             } else if (extAlgo.extConvClass2EqNums[iOutConvClass] == HcExt::UserCurve) {
    1625            2 :                 extAlgo.extConvClass2UserCurveNums[iOutConvClass] = Util::FindItemInList(ipsc->cAlphaArgs(i + 1), state.dataConvect->hcExtUserCurve);
    1626            2 :                 if (extAlgo.extConvClass2UserCurveNums[iOutConvClass] == 0) {
    1627            0 :                     ShowSevereItemNotFound(state, eoh, ipsc->cAlphaFieldNames(i + 1), ipsc->cAlphaArgs(i + 1));
    1628            0 :                     ErrorsFound = true;
    1629              :                 }
    1630              :             }
    1631              :         } // for (iOutConvClass)
    1632              :     }     // if (Count == 1)
    1633              : 
    1634          123 :     if (ErrorsFound) {
    1635            0 :         ShowFatalError(state, format("{}Errors found getting input.  Program termination.", RoutineName));
    1636              :     }
    1637              : 
    1638          123 :     SetupAdaptiveConvStaticMetaData(state);
    1639          123 : }
    1640              : 
    1641            2 : void ApplyIntConvValue(EnergyPlusData &state, int surfNum, HcInt model, int convUserCoeffNum)
    1642              : {
    1643            2 :     auto &surfIntConv = state.dataSurface->surfIntConv(surfNum);
    1644            2 :     if (convUserCoeffNum == 0) {
    1645            0 :         surfIntConv.model = model;
    1646            2 :     } else if (surfIntConv.userModelNum == 0) {
    1647            2 :         surfIntConv.model = model;
    1648            2 :         surfIntConv.userModelNum = convUserCoeffNum;
    1649              :     } else {
    1650            0 :         ShowWarningError(state,
    1651            0 :                          format("User Supplied Convection Coefficients not overwriting already assigned value for (Inside) in Surface={}",
    1652            0 :                                 state.dataSurface->Surface(surfNum).Name));
    1653              :     }
    1654            2 : }
    1655              : 
    1656            2 : void ApplyIntConvValueMulti(EnergyPlusData &state, SurfaceFilter surfaceFilter, HcInt model, int userModelNum)
    1657              : {
    1658              : 
    1659              :     // SUBROUTINE INFORMATION:
    1660              :     //       AUTHOR         Linda Lawrie
    1661              :     //       DATE WRITTEN   November 2004
    1662              : 
    1663              :     // PURPOSE OF THIS SUBROUTINE:
    1664              :     // This subroutine applies a convection type to a set of surfaces.
    1665              : 
    1666            2 :     if (state.dataSurface->SurfaceFilterLists[(int)surfaceFilter].size() == 0) {
    1667            4 :         ShowWarningError(state,
    1668            4 :                          format("User Supplied Convection Coefficients, Multiple Surface Assignments=\"{}\", there were no surfaces of that type "
    1669              :                                 "found for Inside assignment.",
    1670            2 :                                 SurfaceFilterNamesUC[(int)surfaceFilter]));
    1671            2 :         return;
    1672              :     }
    1673              : 
    1674            0 :     int numWarnings = 0;
    1675            0 :     for (int surfNum : state.dataSurface->SurfaceFilterLists[(int)surfaceFilter]) {
    1676            0 :         auto &surfIntConv = state.dataSurface->surfIntConv(surfNum);
    1677            0 :         if (userModelNum == 0) {
    1678            0 :             surfIntConv.model = model;
    1679            0 :         } else if (surfIntConv.userModelNum == 0) {
    1680            0 :             surfIntConv.model = model;
    1681            0 :             surfIntConv.userModelNum = userModelNum;
    1682            0 :         } else if (state.dataGlobal->DisplayExtraWarnings) {
    1683            0 :             ShowWarningError(state,
    1684            0 :                              format("User Supplied Convection Coefficients, Multiple Surface Assignments=\"{}\", not overwriting already "
    1685              :                                     "assigned value for (Inside) in Surface={}",
    1686            0 :                                     SurfaceFilterNamesUC[(int)surfaceFilter],
    1687            0 :                                     state.dataSurface->Surface(surfNum).Name));
    1688              :         } else {
    1689            0 :             ++numWarnings;
    1690              :         }
    1691              :     } // for (surfNum)
    1692              : 
    1693            0 :     if (!state.dataGlobal->DisplayExtraWarnings && numWarnings > 0) {
    1694            0 :         ShowWarningError(state,
    1695            0 :                          format("User Supplied Convection Coefficients, Multiple Surface Assignments=\"{}\", not overwriting already assigned "
    1696              :                                 "values for {} Inside assignments.",
    1697            0 :                                 SurfaceFilterNamesUC[(int)surfaceFilter],
    1698              :                                 numWarnings));
    1699              :     }
    1700              : }
    1701              : 
    1702            2 : void ApplyExtConvValue(EnergyPlusData &state, int surfNum, HcExt model, int userModelNum)
    1703              : {
    1704            2 :     if (state.dataSurface->Surface(surfNum).OSCPtr > 0) return;
    1705              : 
    1706            2 :     auto &surfExtConv = state.dataSurface->surfExtConv(surfNum);
    1707            2 :     if (userModelNum == 0) {
    1708            0 :         surfExtConv.model = model;
    1709            2 :     } else if (surfExtConv.userModelNum == 0) {
    1710            2 :         surfExtConv.model = model;
    1711            2 :         surfExtConv.userModelNum = userModelNum;
    1712              :     } else {
    1713            0 :         ShowWarningError(state,
    1714            0 :                          format("User Supplied Convection Coefficients not overwriting already assigned value for (Outside) in Surface={}",
    1715            0 :                                 state.dataSurface->Surface(surfNum).Name));
    1716              :     }
    1717              : }
    1718              : 
    1719            2 : void ApplyExtConvValueMulti(EnergyPlusData &state, SurfaceFilter surfaceFilter, HcExt model, int convUserCoeffNum)
    1720              : {
    1721              : 
    1722              :     // SUBROUTINE INFORMATION:
    1723              :     //       AUTHOR         Linda Lawrie
    1724              :     //       DATE WRITTEN   November 2004
    1725              : 
    1726              :     // PURPOSE OF THIS SUBROUTINE:
    1727              :     // This subroutine applies a convection type to a set of surfaces.
    1728              : 
    1729            2 :     if (state.dataSurface->SurfaceFilterLists[(int)surfaceFilter].size() == 0) {
    1730            2 :         return;
    1731              :     }
    1732              : 
    1733            0 :     int numWarnings = 0;
    1734            0 :     for (int surfNum : state.dataSurface->SurfaceFilterLists[(int)surfaceFilter]) {
    1735            0 :         if (state.dataSurface->Surface(surfNum).OSCPtr > 0) continue;
    1736            0 :         auto &surfExtConv = state.dataSurface->surfExtConv(surfNum);
    1737            0 :         if (convUserCoeffNum == 0) {
    1738            0 :             surfExtConv.model = model;
    1739            0 :         } else if (surfExtConv.userModelNum == 0) {
    1740            0 :             surfExtConv.model = model;
    1741            0 :             surfExtConv.userModelNum = convUserCoeffNum;
    1742            0 :         } else if (state.dataGlobal->DisplayExtraWarnings) {
    1743            0 :             ShowWarningError(state,
    1744            0 :                              format("User Supplied Convection Coefficients, Multiple Surface Assignments=\"{}\", not overwriting already "
    1745              :                                     "assigned value for (Outside) in Surface={}",
    1746            0 :                                     SurfaceFilterNamesUC[(int)surfaceFilter],
    1747            0 :                                     state.dataSurface->Surface(surfNum).Name));
    1748              :         } else {
    1749            0 :             ++numWarnings;
    1750              :         }
    1751              :     } // for (surfNum)
    1752              : 
    1753            0 :     if (!state.dataGlobal->DisplayExtraWarnings && numWarnings > 0) {
    1754            0 :         ShowWarningError(state,
    1755            0 :                          format("User Supplied Convection Coefficients, Multiple Surface Assignments=\"{}\", not overwriting already assigned "
    1756              :                                 "values for {} Outside assignments.",
    1757            0 :                                 SurfaceFilterNamesUC[(int)surfaceFilter],
    1758              :                                 numWarnings));
    1759              :     }
    1760              : }
    1761              : 
    1762        63688 : Real64 CalcASHRAESimpExtConvCoeff(Material::SurfaceRoughness const Roughness, // Integer index for roughness, relates to parameter array indices
    1763              :                                   Real64 const SurfWindSpeed                  // Current wind speed, m/s
    1764              : )
    1765              : {
    1766              : 
    1767              :     // FUNCTION INFORMATION:
    1768              :     //       AUTHOR         Rick Strand
    1769              :     //       DATE WRITTEN   August 2000
    1770              : 
    1771              :     // PURPOSE OF THIS FUNCTION:
    1772              :     // This subroutine calculates the exterior convection coefficient
    1773              :     // using the ASHRAE Simple Method from a correlation from Figure 1
    1774              :     // on p. 22.4 of the 1989 ASHRAE Handbook of Fundamentals.
    1775              :     // This is a combined coefficient that includes radiation to sky, ground, and air.
    1776              : 
    1777              :     // REFERENCES:
    1778              :     // ASHRAE Handbook of Fundamentals 1989, p.22.4
    1779              : 
    1780              :     // FUNCTION PARAMETER DEFINITIONS:
    1781              :     constexpr static std::array<Real64, 6> D = {11.58, 12.49, 10.79, 8.23, 10.22, 8.23};
    1782              :     constexpr static std::array<Real64, 6> E = {5.894, 4.065, 4.192, 4.00, 3.100, 3.33};
    1783              :     constexpr static std::array<Real64, 6> F = {0.0, 0.028, 0.0, -0.057, 0.0, -0.036};
    1784              : 
    1785        63688 :     return D[(int)Roughness] + E[(int)Roughness] * SurfWindSpeed + F[(int)Roughness] * pow_2(SurfWindSpeed);
    1786              : }
    1787              : 
    1788       133042 : Real64 CalcASHRAESimpleIntConvCoeff(Real64 const Tsurf, Real64 const Tamb, Real64 const cosTilt)
    1789              : {
    1790              :     // SUBROUTINE INFORMATION:
    1791              :     //       AUTHOR         Rick Strand
    1792              :     //       DATE WRITTEN   August 2000
    1793              : 
    1794              :     // PURPOSE OF THIS FUNCTION:
    1795              :     // This subroutine calculates the interior convection coefficient for a surface.
    1796              : 
    1797              :     // METHODOLOGY EMPLOYED:
    1798              :     // The convection coefficients are taken directly from the TARP Reference Manual.  TARP calculated
    1799              :     // its coefficients using the surface conductances for e=0.9 found in ASHRAE Handbook of Fundamentals
    1800              :     // 1985 in Table 1 on p. 23.2, but subtracted off the radiative component which was estimated at
    1801              :     // 1.02 * 0.9 = 0.918 BTU/h-ft2-F.  Coefficients were then converted to SI units to yield the values
    1802              :     // in this subroutine.
    1803              : 
    1804              :     // REFERENCES:
    1805              :     // 1.  Walton, G. N. 1983. Thermal Analysis Research Program (TARP) Reference Manual,
    1806              :     //     NBSSIR 83-2655, National Bureau of Standards, "Surface Inside Heat Balances", pp 79.
    1807              :     // 2.  ASHRAE Handbook of Fundamentals 1985, p. 23.2, Table 1.
    1808              : 
    1809              :     //      +---------------------+-----------+---------------------------------------------+------------------+-----------------+-------------+
    1810              :     //      |      Situation      | DeltaTemp |                   CosTilt                   | cos(tilt)*deltaT | Convection Type | Coefficient |
    1811              :     //      +---------------------+-----------+---------------------------------------------+------------------+-----------------+-------------+
    1812              :     //      | Vertical Surface    | N/A       | -0.3827 to 0.3827 (67.5 to 112.5 degrees)   | N/A              | Normal          |       3.076 |
    1813              :     //      | Horizontal Surface  | Positive  | 0.9238 to 1.0 (0 to 22.5 degrees)           | Positive         | Enhanced        |       4.043 |
    1814              :     //      | Horizontal Surface  | Positive  | -0.9238 to -1.0 (157.5 to 180 degrees)      | Negative         | Reduced         |       0.948 |
    1815              :     //      | Horizontal Surface  | Negative  | 0.9239 to 1.0 (0 to 22.5 degrees)           | Negative         | Reduced         |       0.948 |
    1816              :     //      | Horizontal Surface  | Negative  | -0.9239 to -1.0 (157.5 to 180 degrees)      | Positive         | Enhanced        |       4.040 |
    1817              :     //      | Tilted Surface      | Positive  | 0.3827 to 0.9239 (22.5 to 67.5 degrees)     | Positive         | Enhanced        |       3.870 |
    1818              :     //      | Tilted Surface      | Negative  | -0.3827 to -0.9239 (157.5 to 157.5 degrees) | Positive         | Enhanced        |       3.870 |
    1819              :     //      | Tilted Surface      | Negative  | 0.3827 to 0.9239 (22.5 to 67.5 degrees)     | Negative         | Reduced         |       2.281 |
    1820              :     //      | Tilted Surface      | Positive  | -0.3827 to -0.9239 (157.5 to 157.5 degrees) | Negative         | Reduced         |       2.281 |
    1821              :     //      +---------------------+-----------+---------------------------------------------+------------------+-----------------+-------------+
    1822              : 
    1823              :     // Set HConvIn using the proper correlation based on DeltaTemp and Cosine of the Tilt of the Surface
    1824       133042 :     if (std::abs(cosTilt) < 0.3827) { // Vertical Surface
    1825        87344 :         return 3.076;
    1826              :     } else {
    1827        45698 :         Real64 DeltaTempCosTilt = (Tamb - Tsurf) * cosTilt;
    1828        45698 :         if (std::abs(cosTilt) >= 0.9239) { // Horizontal Surface
    1829        45696 :             if (DeltaTempCosTilt > 0.0) {  // Enhanced Convection
    1830        26787 :                 return 4.040;
    1831        18909 :             } else if (DeltaTempCosTilt < 0.0) { // Reduced Convection
    1832        18817 :                 return 0.948;
    1833              :             } else { // Zero DeltaTemp
    1834           92 :                 return 3.076;
    1835              :             }
    1836              :         } else {                          // tilted surface
    1837            2 :             if (DeltaTempCosTilt > 0.0) { // Enhanced Convection
    1838            1 :                 return 3.870;
    1839            1 :             } else if (DeltaTempCosTilt < 0.0) { // Reduced Convection
    1840            1 :                 return 2.281;
    1841              :             } else { // Zero DeltaTemp
    1842            0 :                 return 3.076;
    1843              :             }
    1844              :         }
    1845              :     }
    1846              : }
    1847              : 
    1848       133033 : void CalcASHRAESimpleIntConvCoeff(EnergyPlusData &state,
    1849              :                                   int const SurfNum,                  // surface number for which coefficients are being calculated
    1850              :                                   Real64 const SurfaceTemperature,    // Temperature of surface for evaluation of HcIn
    1851              :                                   Real64 const ZoneMeanAirTemperature // Mean Air Temperature of Zone
    1852              : )
    1853              : {
    1854       133033 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    1855       133033 :     if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    1856            0 :         state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].in = [](double Tsurf, double Tamb, double, double, double cosTilt) -> double {
    1857            0 :             return CalcASHRAESimpleIntConvCoeff(Tsurf, Tamb, cosTilt);
    1858            0 :         };
    1859              :     } else {
    1860       133033 :         state.dataHeatBalSurf->SurfHConvInt(SurfNum) = CalcASHRAESimpleIntConvCoeff(SurfaceTemperature, ZoneMeanAirTemperature, surface.CosTilt);
    1861              :     }
    1862              : 
    1863              :     // Establish some lower limit to avoid a zero convection coefficient (and potential divide by zero problems)
    1864       133033 :     state.dataHeatBalSurf->SurfHConvInt(SurfNum) = max(state.dataHeatBalSurf->SurfHConvInt(SurfNum), state.dataHeatBal->LowHConvLimit);
    1865       133033 : }
    1866              : 
    1867      4513032 : Real64 CalcASHRAETARPNatural(Real64 const Tsurf, Real64 const Tamb, Real64 const cosTilt)
    1868              : {
    1869              :     // SUBROUTINE INFORMATION:
    1870              :     //       AUTHOR         Rick Strand
    1871              :     //       DATE WRITTEN   August 2000
    1872              : 
    1873              :     // PURPOSE OF THIS FUNCTION:
    1874              :     // This subroutine calculates the convection coefficient for a surface.
    1875              : 
    1876              :     // NOTE:
    1877              :     // Because surface tilts are given with respect to the outward normal, applications for interior
    1878              :     // surfaces should use a negative cos(Tilt).
    1879              : 
    1880              :     // METHODOLOGY EMPLOYED:
    1881              :     // The algorithm for convection coefficients is taken directly from the TARP Reference Manual.
    1882              :     // ASHRAE Handbook of Fundamentals 2001, p. 3.12, Table 5 gives equations for natural convection
    1883              :     // heat transfer coefficients in the turbulent range for large, vertical plates and for large,
    1884              :     // horizontal plates facing upward when heated (or downward when cooled).  A note in the text
    1885              :     // also gives an approximation for large, horizontal places facing downward when heated (or
    1886              :     // upward when cooled) recommending that it should be half of the facing upward value.
    1887              :     // TARP then adds a curve fit as a function of the cosine of the tilt angle to provide intermediate
    1888              :     // values between vertical and horizontal.  The curve fit values at the extremes match the ASHRAE
    1889              :     // values very well.
    1890              : 
    1891              :     // REFERENCES:
    1892              :     // 1.  Walton, G. N. 1983. Thermal Analysis Research Program (TARP) Reference Manual,
    1893              :     //     NBSSIR 83-2655, National Bureau of Standards, "Surface Inside Heat Balances", pp 79-80.
    1894              :     // 2.  ASHRAE Handbook of Fundamentals 2001, p. 3.12, Table 5.
    1895              : 
    1896      4513032 :     Real64 DeltaTemp = Tsurf - Tamb;
    1897              : 
    1898              :     // Set HConvIn using the proper correlation based on DeltaTemp and Surface (Cosine Tilt)
    1899              : 
    1900      4513032 :     if ((DeltaTemp == 0.0) || (cosTilt == 0.0)) { // Vertical Surface
    1901              : 
    1902        20975 :         return CalcASHRAEVerticalWall(DeltaTemp);
    1903              : 
    1904      4492057 :     } else if (((DeltaTemp < 0.0) && (cosTilt < 0.0)) || ((DeltaTemp > 0.0) && (cosTilt > 0.0))) { // Enhanced Convection
    1905              : 
    1906      2056128 :         return CalcWaltonUnstableHorizontalOrTilt(DeltaTemp, cosTilt);
    1907              : 
    1908              :     } else { // (((DeltaTemp > 0.0) && (cosTilt < 0.0)) || ((DeltaTemp < 0.0) && (cosTilt > 0.0))) // Reduced Convection
    1909              : 
    1910      2435929 :         return CalcWaltonStableHorizontalOrTilt(DeltaTemp, cosTilt);
    1911              : 
    1912              :     } // ...end of IF-THEN block to set HConvIn
    1913              : }
    1914              : 
    1915      1866044 : void CalcASHRAEDetailedIntConvCoeff(EnergyPlusData &state,
    1916              :                                     int const SurfNum,                  // surface number for which coefficients are being calculated
    1917              :                                     Real64 const SurfaceTemperature,    // Temperature of surface for evaluation of HcIn
    1918              :                                     Real64 const ZoneMeanAirTemperature // Mean Air Temperature of Zone
    1919              : )
    1920              : {
    1921      1866044 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    1922      1866044 :     if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    1923            0 :         state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].in = [](double Tsurf, double Tamb, double, double, double cosTilt) -> double {
    1924            0 :             return CalcASHRAETARPNatural(Tsurf, Tamb, cosTilt);
    1925            0 :         };
    1926              :     } else {
    1927      1866044 :         state.dataHeatBalSurf->SurfHConvInt(SurfNum) = CalcASHRAETARPNatural(
    1928      1866044 :             SurfaceTemperature, ZoneMeanAirTemperature, -surface.CosTilt); // negative CosTilt because CosTilt is relative to exterior
    1929              :     }
    1930              : 
    1931              :     // Establish some lower limit to avoid a zero convection coefficient (and potential divide by zero problems)
    1932      1866044 :     if (state.dataHeatBalSurf->SurfHConvInt(SurfNum) < state.dataHeatBal->LowHConvLimit)
    1933        11166 :         state.dataHeatBalSurf->SurfHConvInt(SurfNum) = state.dataHeatBal->LowHConvLimit;
    1934      1866044 : }
    1935              : 
    1936            5 : void CalcDetailedHcInForDVModel(EnergyPlusData &state,
    1937              :                                 int const SurfNum,                             // surface number for which coefficients are being calculated
    1938              :                                 const Array1D<Real64> &SurfaceTemperatures,    // Temperature of surfaces for evaluation of HcIn
    1939              :                                 Array1D<Real64> &HcIn,                         // Interior Convection Coeff Array
    1940              :                                 ObjexxFCL::Optional<Array1S<Real64> const> Vhc // Velocity array for forced convection coeff calculation
    1941              : )
    1942              : {
    1943              : 
    1944              :     // SUBROUTINE INFORMATION:
    1945              :     //       AUTHOR         Rick Strand
    1946              :     //       DATE WRITTEN   August 2000
    1947              :     //       MODIFIED       Used for DV model; Feb 2004, LKL
    1948              : 
    1949              :     // PURPOSE OF THIS FUNCTION:
    1950              :     // This subroutine calculates the interior convection coefficient for a surface.
    1951              : 
    1952              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1953              :     Real64 TAirConv;
    1954              :     Real64 Hf;
    1955            5 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    1956              : 
    1957            5 :     if (surface.HeatTransSurf) { // Only treat heat transfer surfaces
    1958              : 
    1959              :         // UCSD
    1960              :         {
    1961            5 :             if (state.dataSurface->SurfTAirRef(SurfNum) == DataSurfaces::RefAirTemp::AdjacentAirTemp) {
    1962            5 :                 TAirConv = state.dataHeatBal->SurfTempEffBulkAir(SurfNum);
    1963              :             } else {
    1964              :                 // currently set to mean air temp but should add error warning here
    1965            0 :                 TAirConv = state.dataZoneTempPredictorCorrector->zoneHeatBalance(surface.Zone).MAT;
    1966              :             }
    1967              :         }
    1968              : 
    1969            5 :         assert(state.dataRoomAir->AirModel.allocated());
    1970            5 :         if (state.dataRoomAir->AirModel(surface.Zone).AirModel == RoomAir::RoomAirModel::DispVent3Node ||
    1971            6 :             state.dataRoomAir->AirModel(surface.Zone).AirModel == RoomAir::RoomAirModel::UFADInt ||
    1972            1 :             state.dataRoomAir->AirModel(surface.Zone).AirModel == RoomAir::RoomAirModel::UFADExt) {
    1973              : 
    1974              :             // Set HConvIn using the proper correlation based on DeltaTemp and CosTiltSurf
    1975            4 :             if (state.dataSurface->surfIntConv(SurfNum).userModelNum != 0) {
    1976              : 
    1977            0 :                 HcIn(SurfNum) = SetIntConvCoeff(state, SurfNum);
    1978              : 
    1979              :             } else {
    1980            4 :                 HcIn(SurfNum) = CalcASHRAETARPNatural(SurfaceTemperatures(SurfNum),
    1981              :                                                       TAirConv,
    1982            4 :                                                       -surface.CosTilt); // negative CosTilt because CosTilt is relative to exterior
    1983              :             }
    1984              : 
    1985            1 :         } else if (state.dataRoomAir->AirModel(surface.Zone).AirModel == RoomAir::RoomAirModel::CrossVent) {
    1986              : 
    1987            1 :             Hf = 4.3 * Vhc()(surface.Zone);
    1988              : 
    1989              :             // Set HConvIn using the proper correlation based on DeltaTemp and CosTiltSurf
    1990            1 :             if (state.dataSurface->surfIntConv(SurfNum).userModelNum != 0) {
    1991              : 
    1992            0 :                 HcIn(SurfNum) = SetIntConvCoeff(state, SurfNum);
    1993              : 
    1994              :             } else {
    1995            1 :                 HcIn(SurfNum) = CalcASHRAETARPNatural(SurfaceTemperatures(SurfNum),
    1996              :                                                       TAirConv,
    1997            1 :                                                       -surface.CosTilt); // negative CosTilt because CosTilt is relative to exterior
    1998            1 :                 HcIn(SurfNum) = std::pow(std::pow(HcIn(SurfNum), 3.2) + std::pow(Hf, 3.2), 1.0 / 3.2);
    1999              :             }
    2000              :         }
    2001              :     }
    2002              : 
    2003              :     // Establish some lower limit to avoid a zero convection coefficient (and potential divide by zero problems)
    2004            5 :     if (HcIn(SurfNum) < state.dataHeatBal->LowHConvLimit) HcIn(SurfNum) = state.dataHeatBal->LowHConvLimit;
    2005            5 : }
    2006              : 
    2007           14 : Real64 CalcZoneSystemACH(EnergyPlusData &state, int const ZoneNum)
    2008              : {
    2009              : 
    2010           14 :     if (!allocated(state.dataLoopNodes->Node)) {
    2011            1 :         return 0.0;
    2012              :     } else {
    2013              :         // Set local variables
    2014           13 :         Real64 ZoneVolume = state.dataHeatBal->Zone(ZoneNum).Volume;
    2015           13 :         Real64 ZoneVolFlowRate = CalcZoneSystemVolFlowRate(state, ZoneNum);
    2016              : 
    2017              :         // Calculate ACH
    2018           13 :         return ZoneVolFlowRate / ZoneVolume * Constant::rSecsInHour;
    2019              :     }
    2020              : }
    2021              : 
    2022            6 : Real64 CalcZoneSupplyAirTemp(EnergyPlusData &state, int const ZoneNum)
    2023              : {
    2024              : 
    2025            6 :     int ZoneNode = state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber;
    2026            6 :     if (ZoneNode <= 0) return state.dataLoopNodes->Node(ZoneNode).Temp;
    2027              : 
    2028            6 :     auto &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(ZoneNum);
    2029            6 :     auto &zoneEquipList = state.dataZoneEquip->ZoneEquipList(zoneEquipConfig.EquipListIndex);
    2030              : 
    2031            6 :     int zoneInletNodeNum = 0;
    2032              : 
    2033            6 :     Real64 SumMdotTemp = 0.0;
    2034            6 :     Real64 SumMdot = 0.0;
    2035              : 
    2036           12 :     for (int EquipNum = 1; EquipNum <= zoneEquipList.NumOfEquipTypes; ++EquipNum) {
    2037              : 
    2038            6 :         auto &equipData = zoneEquipList.EquipData(EquipNum);
    2039            6 :         if (equipData.NumOutlets == 0) continue;
    2040              : 
    2041            0 :         zoneInletNodeNum = equipData.OutletNodeNums(1);
    2042            0 :         if (zoneInletNodeNum == 0) continue;
    2043              : 
    2044            0 :         auto const &zoneInletNode = state.dataLoopNodes->Node(zoneInletNodeNum);
    2045            0 :         if (zoneInletNode.MassFlowRate > 0.0) {
    2046            0 :             SumMdotTemp += zoneInletNode.MassFlowRate * zoneInletNode.Temp;
    2047            0 :             SumMdot += zoneInletNode.MassFlowRate;
    2048              :         }
    2049              :     }
    2050              : 
    2051            6 :     if (SumMdot > 0.0) return SumMdotTemp / SumMdot; // mass flow weighted inlet temperature
    2052              : 
    2053            6 :     if (zoneInletNodeNum > 0) {
    2054            0 :         return state.dataLoopNodes->Node(zoneInletNodeNum).Temp;
    2055              :     } else {
    2056            6 :         return state.dataLoopNodes->Node(ZoneNode).Temp;
    2057              :     }
    2058              : }
    2059              : 
    2060           13 : Real64 CalcZoneSystemVolFlowRate(EnergyPlusData &state, int const ZoneNum)
    2061              : {
    2062           13 :     auto const &zone = state.dataHeatBal->Zone(ZoneNum);
    2063              : 
    2064           13 :     if (state.dataGlobal->BeginEnvrnFlag || zone.SystemZoneNodeNumber <= 0) return 0.0;
    2065              : 
    2066           13 :     auto const &zoneNode = state.dataLoopNodes->Node(zone.SystemZoneNodeNumber);
    2067           13 :     int ZoneMult = zone.Multiplier * zone.ListMultiplier;
    2068           26 :     Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(
    2069           13 :         state, state.dataEnvrn->OutBaroPress, zoneNode.Temp, Psychrometrics::PsyWFnTdpPb(state, zoneNode.Temp, state.dataEnvrn->OutBaroPress));
    2070           13 :     return zoneNode.MassFlowRate / (AirDensity * ZoneMult);
    2071              : }
    2072              : 
    2073            6 : Real64 CalcCeilingDiffuserACH(EnergyPlusData &state, int const ZoneNum)
    2074              : {
    2075            6 :     constexpr Real64 MinFlow(0.01); // Minimum mass flow rate
    2076            6 :     constexpr Real64 MaxACH(100.0); // Maximum ceiling diffuser correlation limit
    2077              : 
    2078            6 :     auto const &zone = state.dataHeatBal->Zone(ZoneNum);
    2079              : 
    2080            6 :     Real64 ACH = CalcZoneSystemACH(state, ZoneNum); // Air changes per hour
    2081              : 
    2082              :     Real64 ZoneMassFlowRate;
    2083            6 :     Real64 ZoneMult = zone.Multiplier * zone.ListMultiplier;
    2084            6 :     int ZoneNode = zone.SystemZoneNodeNumber; // Zone node as defined in system simulation
    2085            6 :     if (!state.dataGlobal->BeginEnvrnFlag && ZoneNode > 0) {
    2086            6 :         ZoneMassFlowRate = state.dataLoopNodes->Node(ZoneNode).MassFlowRate / ZoneMult;
    2087              :     } else { // because these are not updated yet for new environment
    2088            0 :         ZoneMassFlowRate = 0.0;
    2089              :     }
    2090              : 
    2091            6 :     if (ZoneMassFlowRate < MinFlow) {
    2092            0 :         ACH = 0.0;
    2093              :     } else {
    2094              :         // Calculate ACH
    2095            6 :         ACH = min(ACH, MaxACH);
    2096            6 :         ACH = max(ACH, 0.0);
    2097              :     }
    2098              : 
    2099            6 :     return ACH;
    2100              : }
    2101              : 
    2102            0 : Real64 CalcCeilingDiffuserIntConvCoeff(EnergyPlusData &state,
    2103              :                                        Real64 const ACH, // [1/hr] air system air change rate
    2104              :                                        Real64 const Tsurf,
    2105              :                                        Real64 const Tair,
    2106              :                                        Real64 const cosTilt,
    2107              :                                        Real64 const humRat,
    2108              :                                        Real64 const height,
    2109              :                                        bool const isWindow)
    2110              : {
    2111              :     // SUBROUTINE INFORMATION:
    2112              :     //       AUTHOR         Rick Strand
    2113              :     //       DATE WRITTEN   August 2000
    2114              : 
    2115              :     // PURPOSE OF THIS FUNCTION:
    2116              :     // This subroutine calculates the interior convection coefficients
    2117              :     // for ceiling diffusers correlated to the outlet air temperature.
    2118              : 
    2119              :     // REFERENCES:
    2120              :     // Fisher, D.E. and C.O. Pedersen, Convective Heat Transfer in Building Energy and
    2121              :     //       Thermal Load Calculations, ASHRAE Transactions, vol. 103, Pt. 2, 1997, p.137
    2122              : 
    2123              :     // OTHER NOTES:
    2124              :     // The correlations shown below differ from (and are less accurate than) those shown
    2125              :     // in the reference above (Fisher 1997).  They have been reformulated with an outlet
    2126              :     // temperature reference in order to accommodate the structure of the EnergyPlus code.
    2127              : 
    2128              :     // If the Ceiling Diffuser option is selected the following correlations are used.
    2129              :     // The development of the ceiling diffuser convection correlations is shown in reference 4.
    2130              :     // The correlations shown below differ from (and are less accurate than) those shown in reference 4 because they have been
    2131              :     // reformulated with an outlet temperature reference in order to accommodate the structure of the
    2132              :     // EnergyPlus code.
    2133              : 
    2134              :     // Set HConvIn using the proper correlation based on Surface Tilt
    2135              :     static const Real64 cos45(sqrt(2.) / 2.0);
    2136              : 
    2137            0 :     if (cosTilt < -cos45) {
    2138            0 :         return CalcFisherPedersenCeilDiffuserFloor(state, ACH, Tsurf, Tair, cosTilt, humRat, height, isWindow); // Floor correlation
    2139            0 :     } else if (cosTilt > cos45) {
    2140            0 :         return CalcFisherPedersenCeilDiffuserCeiling(state, ACH, Tsurf, Tair, cosTilt, humRat, height, isWindow); // Ceiling correlation
    2141              :     } else {
    2142            0 :         return CalcFisherPedersenCeilDiffuserWalls(state, ACH, Tsurf, Tair, cosTilt, humRat, height, isWindow); // Wall correlation
    2143              :     }
    2144              : }
    2145              : 
    2146            0 : void CalcCeilingDiffuserIntConvCoeff(EnergyPlusData &state,
    2147              :                                      int const ZoneNum,
    2148              :                                      const Array1D<Real64> &SurfaceTemperatures) // zone number for which coefficients are being calculated
    2149              : {
    2150              : 
    2151            0 :     Real64 ACH = CalcCeilingDiffuserACH(state, ZoneNum);
    2152              : 
    2153            0 :     Real64 AirHumRat = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).airHumRatAvg;
    2154              : 
    2155            0 :     for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
    2156            0 :         auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    2157            0 :         for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
    2158            0 :             auto const &surface = state.dataSurface->Surface(SurfNum);
    2159            0 :             if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    2160            0 :                 Real64 height = surface.Height;
    2161            0 :                 bool isWindow = state.dataConstruction->Construct(surface.Construction).TypeIsWindow;
    2162            0 :                 state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].in =
    2163            0 :                     [=, &state](double Tsurf, double Tamb, double, double, double cosTilt) -> double {
    2164            0 :                     return CalcCeilingDiffuserIntConvCoeff(state, ACH, Tsurf, Tamb, cosTilt, AirHumRat, height, isWindow);
    2165            0 :                 };
    2166              :             } else {
    2167            0 :                 state.dataHeatBalSurf->SurfHConvInt(SurfNum) =
    2168            0 :                     CalcCeilingDiffuserIntConvCoeff(state,
    2169              :                                                     ACH,
    2170            0 :                                                     SurfaceTemperatures(SurfNum),
    2171            0 :                                                     state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT,
    2172            0 :                                                     surface.CosTilt,
    2173              :                                                     AirHumRat,
    2174            0 :                                                     surface.Height,
    2175            0 :                                                     state.dataConstruction->Construct(surface.Construction).TypeIsWindow);
    2176              :                 // Establish some lower limit to avoid a zero convection coefficient (and potential divide by zero problems)
    2177            0 :                 if (state.dataHeatBalSurf->SurfHConvInt(SurfNum) < state.dataHeatBal->LowHConvLimit)
    2178            0 :                     state.dataHeatBalSurf->SurfHConvInt(SurfNum) = state.dataHeatBal->LowHConvLimit;
    2179              :             }
    2180              :         } // SurfNum
    2181              :     }
    2182            0 : }
    2183              : 
    2184              : // CalcCeilingDiffuserInletCorr should replace CalcCeilingDiffuser (above), if ZoneTempPredictorCorrector can
    2185              : // ever be made to work correctly with the inlet air temperature.
    2186              : 
    2187            0 : void CalcCeilingDiffuserInletCorr(EnergyPlusData &state,
    2188              :                                   int const ZoneNum,                         // Zone number
    2189              :                                   const Array1S<Real64> &SurfaceTemperatures // For CalcASHRAEDetailed, if called
    2190              : )
    2191              : {
    2192              : 
    2193              :     // SUBROUTINE INFORMATION:
    2194              :     //       AUTHOR         Rick Strand
    2195              :     //       DATE WRITTEN   August 2000
    2196              :     //       RE-ENGINEERED  July 2003 (Peter Graham Ellis)
    2197              :     //       MODIFIED       July 2003, (CC) set a flag for reference temperature so that supply air temperature
    2198              :     //                                      is used as the reference in the inside heat balance calculations
    2199              : 
    2200              :     // PURPOSE OF THIS FUNCTION:
    2201              :     // This subroutine calculates the interior convection coefficients
    2202              :     // for ceiling diffusers correlated to the inlet air temperature.
    2203              : 
    2204              :     // REFERENCES:
    2205              :     // Fisher, D.E. and C.O. Pedersen, Convective Heat Transfer in Building Energy and
    2206              :     //   Thermal Load Calculations, ASHRAE Transactions, vol. 103, Pt. 2, 1997, p.137
    2207              : 
    2208              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2209            0 :     Real64 constexpr MinFlow(0.01); // Minimum mass flow rate
    2210            0 :     Real64 constexpr MaxACH(100.0); // Maximum ceiling diffuser correlation limit
    2211              :     Real64 ACH;                     // Air changes per hour
    2212              : 
    2213            0 :     auto const &zone = state.dataHeatBal->Zone(ZoneNum);
    2214              : 
    2215            0 :     if (state.dataGlobal->SysSizingCalc || state.dataGlobal->ZoneSizingCalc || !allocated(state.dataLoopNodes->Node)) {
    2216            0 :         ACH = 0.0;
    2217              :     } else {
    2218              :         // Set local variables
    2219            0 :         Real64 ZoneVolume = zone.Volume;
    2220            0 :         Real64 ZoneMult = zone.Multiplier * zone.ListMultiplier;
    2221            0 :         auto const &zoneNode = state.dataLoopNodes->Node(zone.SystemZoneNodeNumber);
    2222            0 :         Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(
    2223            0 :             state, state.dataEnvrn->OutBaroPress, zoneNode.Temp, Psychrometrics::PsyWFnTdpPb(state, zoneNode.Temp, state.dataEnvrn->OutBaroPress));
    2224            0 :         Real64 ZoneMassFlowRate = zoneNode.MassFlowRate / ZoneMult;
    2225              : 
    2226            0 :         if (ZoneMassFlowRate < MinFlow) {
    2227            0 :             ACH = 0.0;
    2228              :         } else {
    2229              :             // Calculate ACH (AR: can we please stop with these unparenthesized multiple divides? / / )
    2230            0 :             ACH = ZoneMassFlowRate / AirDensity / ZoneVolume * Constant::rSecsInHour;
    2231              :             // Limit ACH to range of correlation
    2232            0 :             ACH = min(ACH, MaxACH);
    2233            0 :             ACH = max(ACH, 0.0);
    2234              :         }
    2235              :     }
    2236              : 
    2237            0 :     for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
    2238            0 :         auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    2239            0 :         for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
    2240            0 :             if (ACH <= 3.0) { // Use the other convection algorithm
    2241            0 :                 if (!state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).TypeIsWindow) {
    2242            0 :                     CalcASHRAEDetailedIntConvCoeff(
    2243            0 :                         state, SurfNum, SurfaceTemperatures(SurfNum), state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).MAT);
    2244              :                 } else {
    2245            0 :                     CalcISO15099WindowIntConvCoeff(
    2246            0 :                         state, SurfNum, SurfaceTemperatures(SurfNum), state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).MAT);
    2247              :                 }
    2248              :             } else { // Use forced convection correlations
    2249            0 :                 Real64 Tilt = state.dataSurface->Surface(SurfNum).Tilt;
    2250              : 
    2251              :                 // assume that reference air temp for user defined convection coefficient is the mean air temperature (=MAT)
    2252              :                 // Calculate the convection coefficient based on inlet (supply) air conditions
    2253            0 :                 if (Tilt < 45.0) {
    2254            0 :                     state.dataHeatBalSurf->SurfHConvInt(SurfNum) = 0.49 * std::pow(ACH, 0.8); // Ceiling correlation
    2255            0 :                 } else if (Tilt > 135.0) {
    2256            0 :                     state.dataHeatBalSurf->SurfHConvInt(SurfNum) = 0.13 * std::pow(ACH, 0.8); // Floor correlation
    2257              :                 } else {
    2258            0 :                     state.dataHeatBalSurf->SurfHConvInt(SurfNum) = 0.19 * std::pow(ACH, 0.8); // Wall correlation
    2259              :                 }
    2260              :                 // set flag for reference air temperature
    2261            0 :                 state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneSupplyAirTemp;
    2262            0 :                 state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
    2263              :             }
    2264              : 
    2265              :             // Establish some lower limit to avoid a zero convection coefficient (and potential divide by zero problems)
    2266            0 :             if (state.dataHeatBalSurf->SurfHConvInt(SurfNum) < state.dataHeatBal->LowHConvLimit)
    2267            0 :                 state.dataHeatBalSurf->SurfHConvInt(SurfNum) = state.dataHeatBal->LowHConvLimit;
    2268              : 
    2269              :         } // SurfNum
    2270              :     }
    2271            0 :     if (ACH > 100.0) ShowWarningError(state, "CeilingDiffuser convection correlation is out of range: ACH > 100");
    2272            0 : }
    2273              : 
    2274            0 : void CalcTrombeWallIntConvCoeff(EnergyPlusData &state,
    2275              :                                 int const ZoneNum,                         // Zone number for which coefficients are being calculated
    2276              :                                 const Array1D<Real64> &SurfaceTemperatures // Temperature of surfaces for evaluation of HcIn
    2277              : )
    2278              : {
    2279              : 
    2280              :     // SUBROUTINE INFORMATION:
    2281              :     //       AUTHOR         Peter Graham Ellis
    2282              : 
    2283              :     // PURPOSE OF THIS FUNCTION:
    2284              :     // This subroutine calculates the interior convection coefficient
    2285              :     // using the Trombe Wall correlation ?????
    2286              : 
    2287              :     // SUBROUTINE PARAMETER DEFINITIONS:
    2288            0 :     constexpr Real64 g(9.81);     // gravity constant (m/s**2)
    2289            0 :     constexpr Real64 v(15.89e-6); // kinematic viscosity (m**2/s) for air at 300 K
    2290            0 :     constexpr Real64 k(0.0263);   // thermal conductivity (W/m K) for air at 300 K
    2291            0 :     constexpr Real64 Pr(0.71);    // Prandtl number for air at ?
    2292              : 
    2293              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2294            0 :     int Surf1 = 0; // first major wall surface
    2295            0 :     int Surf2 = 0; // second major wall surface
    2296              : 
    2297              :     // If the Trombe Wall option is selected the following correlations
    2298              :     // will be used based on references by .....
    2299              :     // tall enclosed rectangular cavity
    2300              : 
    2301              :     // This routine assumes that the major Trombe wall surfaces are of the
    2302              :     // "WALL" class and are vertical.  The important heat transfer surfaces
    2303              :     // are assumed to have exactly equal widths AND must have a greater
    2304              :     // width than the side surfaces.
    2305              : 
    2306            0 :     auto const &zone = state.dataHeatBal->Zone(ZoneNum);
    2307            0 :     Real64 H = zone.CeilingHeight; // height of enclosure
    2308            0 :     Real64 minorW = 100000.0;      // width of enclosure (narrow dimension) // An impossibly big width
    2309            0 :     Real64 majorW = 0.0;           // width of major surface
    2310              : 
    2311            0 :     Real64 HConvNet = 0.0; // net heat transfer coefficient from wall to wall
    2312              : 
    2313              :     // determine major width and minor width
    2314            0 :     for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
    2315            0 :         auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    2316            0 :         for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
    2317            0 :             auto const &surface = state.dataSurface->Surface(SurfNum);
    2318            0 :             if (surface.Class != SurfaceClass::Wall) continue;
    2319              : 
    2320            0 :             if (surface.Width > majorW) {
    2321            0 :                 majorW = surface.Width;
    2322              :             }
    2323            0 :             if (surface.Width < minorW) {
    2324            0 :                 minorW = surface.Width;
    2325              :             }
    2326              :         }
    2327              : 
    2328              :         // assign major surfaces
    2329            0 :         for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
    2330            0 :             auto const &surface = state.dataSurface->Surface(SurfNum);
    2331            0 :             if (surface.Class != SurfaceClass::Wall) continue;
    2332              : 
    2333            0 :             if (surface.Width == majorW) {
    2334            0 :                 if (Surf1 == 0) {
    2335            0 :                     Surf1 = SurfNum;
    2336              :                 } else {
    2337            0 :                     Surf2 = SurfNum;
    2338              : 
    2339            0 :                     break; // both major surfaces are now assigned
    2340              :                 }
    2341              :             }
    2342              :         }
    2343              :     }
    2344              : 
    2345              :     // check to make sure major surfaces were found
    2346            0 :     if (Surf1 > 0 && Surf2 > 0) {
    2347            0 :         Real64 gapW = minorW;
    2348            0 :         Real64 asp = H / gapW; // aspect ratio H/gapW // This calc should only be done once for the zone
    2349              : 
    2350              :         // make sure inside surface is hot, outside is cold
    2351              :         // NOTE: this is not ideal.  could have circumstances that reverse this?
    2352              :         Real64 Tso, Tsi;
    2353            0 :         if (SurfaceTemperatures(Surf1) > SurfaceTemperatures(Surf2)) {
    2354            0 :             Tsi = SurfaceTemperatures(Surf1) + Constant::Kelvin;
    2355            0 :             Tso = SurfaceTemperatures(Surf2) + Constant::Kelvin;
    2356              :         } else {
    2357            0 :             Tso = SurfaceTemperatures(Surf1) + Constant::Kelvin;
    2358            0 :             Tsi = SurfaceTemperatures(Surf2) + Constant::Kelvin;
    2359              :         }
    2360              : 
    2361            0 :         Real64 beta = 2.0 / (Tso + Tsi);                                       // volumetric thermal expansion coefficient
    2362            0 :         Real64 Gr = (g * beta * std::abs(Tsi - Tso) * pow_3(gapW)) / pow_2(v); // Grashof // curve fit for v = v(T)?
    2363            0 :         Real64 Nu = CalcNusselt(state, Surf2, asp, Tso, Tsi, Gr, Pr);          // Nusselt // curve fit for Pr = Pr(T)?
    2364              : 
    2365            0 :         HConvNet = (k / gapW) * Nu; // curve fit for k = k(T)?
    2366              : 
    2367              :     } else {
    2368              :         // fatal Error msg "heat transfer surfaces not found"
    2369              :     }
    2370              : 
    2371              :     // Assign convection coefficients
    2372            0 :     for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
    2373            0 :         auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    2374            0 :         for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
    2375            0 :             auto const &surface = state.dataSurface->Surface(SurfNum);
    2376              :             // Use ASHRAESimple correlation to give values for all the minor surfaces
    2377            0 :             CalcASHRAESimpleIntConvCoeff(
    2378            0 :                 state, SurfNum, SurfaceTemperatures(SurfNum), state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).MAT);
    2379              : 
    2380              :             // assign the convection coefficent to the major surfaces and any subsurfaces on them
    2381            0 :             if ((surface.BaseSurf == Surf1) || (surface.BaseSurf == Surf2)) {
    2382            0 :                 if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    2383            0 :                     ShowFatalError(state, format("Trombe wall convection model not applicable for foundation surface ={}", surface.Name));
    2384              :                 }
    2385            0 :                 state.dataHeatBalSurf->SurfHConvInt(SurfNum) = 2.0 * HConvNet;
    2386              :             }
    2387              : 
    2388              :             // Establish some lower limit to avoid a zero convection coefficient (and potential divide by zero problems)
    2389            0 :             if (state.dataHeatBalSurf->SurfHConvInt(SurfNum) < state.dataHeatBal->LowHConvLimit)
    2390            0 :                 state.dataHeatBalSurf->SurfHConvInt(SurfNum) = state.dataHeatBal->LowHConvLimit;
    2391              :         } // for (surfNum)
    2392              :     }     // for (spaceNum)
    2393            0 : }
    2394              : 
    2395            0 : Real64 CalcNusselt(EnergyPlusData &state,
    2396              :                    int const SurfNum, // Surface number
    2397              :                    Real64 const asp,  // Aspect ratio: window height to gap width
    2398              :                    Real64 const tso,  // Temperature of gap surface closest to outside (K)
    2399              :                    Real64 const tsi,  // Temperature of gap surface closest to zone (K)
    2400              :                    Real64 const gr,   // Gap gas Grashof number
    2401              :                    Real64 const pr)   // Gap gas Prandtl number
    2402              : {
    2403              : 
    2404              :     // SUBROUTINE INFORMATION:
    2405              :     //       AUTHOR         Peter Graham Ellis, based on code adapted by Fred Winkelmann
    2406              :     //                      from Window5 subroutine NusseltNumber
    2407              :     //       DATE WRITTEN   September 2001
    2408              : 
    2409              :     // PURPOSE OF THIS SUBROUTINE:
    2410              :     // Finds the Nusselt number for gas-filled gaps between isothermal solid layers.
    2411              :     // The gap may be filled with a single gas or a gas mixture.
    2412              : 
    2413              :     // METHODOLOGY EMPLOYED:
    2414              :     // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
    2415              :     // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
    2416              :     // The equation numbers below correspond to those in the standard.
    2417              : 
    2418              :     // REFERENCES:
    2419              :     // Window5 source code; ISO 15099
    2420              : 
    2421            0 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    2422              : 
    2423            0 :     Real64 tilt = surface.Tilt;
    2424            0 :     Real64 tiltr = tilt * Constant::DegToRad;
    2425            0 :     Real64 costilt = surface.CosTilt;
    2426            0 :     Real64 sintilt = surface.SinTilt;
    2427            0 :     Real64 ra = gr * pr; // Rayleigh number
    2428              :     //! fw if (ra > 2.0e6): error that outside range of Rayleigh number?
    2429              : 
    2430              :     Real64 gnu901; // Nusselt number temporary variables for
    2431            0 :     if (ra <= 1.0e4)
    2432            0 :         gnu901 = 1.0 + 1.7596678e-10 * std::pow(ra, 2.2984755); // eq. 51
    2433            0 :     else if (ra > 1.0e4 && ra <= 5.0e4)
    2434            0 :         gnu901 = 0.028154 * std::pow(ra, 0.4134); // eq. 50
    2435              :     else
    2436            0 :         gnu901 = 0.0673838 * std::pow(ra, 1.0 / 3.0); // eq. 49
    2437              : 
    2438            0 :     Real64 gnu902 = 0.242 * std::pow(ra / asp, 0.272); // eq. 52
    2439            0 :     Real64 gnu90 = max(gnu901, gnu902);
    2440              : 
    2441            0 :     if (tso > tsi) {                          // window heated from above
    2442            0 :         return 1.0 + (gnu90 - 1.0) * sintilt; // eq. 53
    2443              :     }
    2444              : 
    2445              :     // window heated from below
    2446            0 :     if (tilt >= 60.0) {
    2447            0 :         Real64 g = 0.5 * std::pow(1.0 + std::pow(ra / 3160.0, 20.6), -0.1);     // eq. 47
    2448            0 :         Real64 gnu601a = 1.0 + pow_7(0.0936 * std::pow(ra, 0.314) / (1.0 + g)); // eq. 45
    2449            0 :         Real64 gnu601 = std::pow(gnu601a, 0.142857);
    2450              :         // For any aspect ratio
    2451            0 :         Real64 gnu602 = (0.104 + 0.175 / asp) * std::pow(ra, 0.283); // eq. 46
    2452            0 :         Real64 gnu60 = max(gnu601, gnu602);
    2453              : 
    2454              :         // linear interpolation for layers inclined at angles between 60 and 90 deg
    2455            0 :         return ((90.0 - tilt) * gnu60 + (tilt - 60.0) * gnu90) / 30.0;
    2456              : 
    2457              :     } else { // eq. 42
    2458            0 :         Real64 cra = ra * costilt;
    2459            0 :         Real64 a = 1.0 - 1708.0 / cra;
    2460            0 :         Real64 b = std::pow(cra / 5830.0, 0.33333) - 1.0; // LKL- replace .333 with OneThird?
    2461            0 :         Real64 gnua = (std::abs(a) + a) / 2.0;
    2462            0 :         Real64 gnub = (std::abs(b) + b) / 2.0;
    2463            0 :         Real64 ang = 1708.0 * std::pow(std::sin(1.8 * tiltr), 1.6);
    2464            0 :         return 1.0 + 1.44 * gnua * (1.0 - ang / cra) + gnub;
    2465              :     }
    2466              : }
    2467              : 
    2468            0 : Real64 SetExtConvCoeff(EnergyPlusData &state, int const SurfNum) // Surface Number
    2469              : {
    2470              : 
    2471              :     // FUNCTION INFORMATION:
    2472              :     //       AUTHOR         Linda K. Lawrie
    2473              :     //       DATE WRITTEN   May 1998
    2474              : 
    2475              :     // PURPOSE OF THIS FUNCTION:
    2476              :     // This function accesses the data structure for the User
    2477              :     // Supplied Exterior Convection Coefficients and returns that
    2478              :     // as the result of this function.  The surface has already
    2479              :     // been verified to have user supplied exterior convection values.
    2480              : 
    2481              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    2482            0 :     Real64 HExt = 0.0; // Will become the returned value
    2483              : 
    2484            0 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    2485            0 :     auto &surfExtConv = state.dataSurface->surfExtConv(SurfNum);
    2486            0 :     auto const &userExtConvModel = state.dataSurface->userExtConvModels(surfExtConv.userModelNum);
    2487              : 
    2488            0 :     switch (userExtConvModel.overrideType) {
    2489            0 :     case OverrideType::Value: {
    2490            0 :         HExt = userExtConvModel.OverrideValue;
    2491            0 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    2492            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f = KIVA_HF_ZERO;
    2493            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].out = KIVA_CONST_CONV(HExt);
    2494              :         }
    2495            0 :         surfExtConv.hfModelEq = HcExt::UserValue; // reporting
    2496            0 :         surfExtConv.hnModelEq = HcExt::None;      // reporting
    2497            0 :     } break;
    2498              : 
    2499            0 :     case OverrideType::Schedule: {
    2500            0 :         HExt = userExtConvModel.sched->getCurrentVal();
    2501              :         // Need to check for validity
    2502            0 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    2503            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f = KIVA_HF_ZERO;
    2504            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].out = KIVA_CONST_CONV(HExt);
    2505              :         }
    2506            0 :         surfExtConv.hfModelEq = HcExt::UserSchedule; // reporting
    2507            0 :         surfExtConv.hnModelEq = HcExt::None;         // reporting
    2508            0 :     } break;
    2509              : 
    2510            0 :     case OverrideType::UserCurve: {
    2511            0 :         HExt = CalcUserDefinedExtHcModel(state, SurfNum, userExtConvModel.UserCurveIndex);
    2512              :         // Kiva convection handled in function above
    2513            0 :         surfExtConv.hfModelEq = HcExt::UserCurve; // reporting
    2514            0 :         surfExtConv.hnModelEq = HcExt::None;      // reporting
    2515            0 :     } break;
    2516              : 
    2517            0 :     case OverrideType::SpecifiedModel: {
    2518            0 :         HExt = EvaluateExtHcModels(state, SurfNum, userExtConvModel.HcExtModelEq, userExtConvModel.HcExtModelEq);
    2519              :         // Kiva convection handled in function above
    2520            0 :         surfExtConv.hfModelEq = userExtConvModel.HcExtModelEq; // reporting
    2521            0 :         surfExtConv.hnModelEq = userExtConvModel.HcExtModelEq; // reporting
    2522            0 :     } break;
    2523              : 
    2524            0 :     default:
    2525            0 :         assert(false);
    2526              :     }
    2527              : 
    2528            0 :     surfExtConv.hfModelEqRpt = HcExtReportVals[(int)surfExtConv.hfModelEq];
    2529            0 :     surfExtConv.hnModelEqRpt = HcExtReportVals[(int)surfExtConv.hnModelEq];
    2530              : 
    2531            0 :     return HExt;
    2532              : }
    2533              : 
    2534            0 : Real64 SetIntConvCoeff(EnergyPlusData &state, int const SurfNum) // Surface Number
    2535              : {
    2536              : 
    2537              :     // FUNCTION INFORMATION:
    2538              :     //       AUTHOR         Linda K. Lawrie
    2539              :     //       DATE WRITTEN   May 1998
    2540              : 
    2541              :     // PURPOSE OF THIS FUNCTION:
    2542              :     // This function accesses the data structure for the User
    2543              :     // Supplied Interior Convection Coefficients and returns that
    2544              :     // as the result of this function.  The surface has already
    2545              :     // been verified to have user supplied interior convection values.
    2546              : 
    2547            0 :     Real64 HInt = 0.0; // Will become the returned value
    2548              : 
    2549            0 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    2550            0 :     auto &surfIntConv = state.dataSurface->surfIntConv(SurfNum);
    2551            0 :     auto const &userIntConvModel = state.dataSurface->userIntConvModels(surfIntConv.userModelNum);
    2552              : 
    2553            0 :     switch (userIntConvModel.overrideType) {
    2554            0 :     case OverrideType::Value: {
    2555            0 :         HInt = userIntConvModel.OverrideValue;
    2556            0 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    2557            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].in = KIVA_CONST_CONV(HInt);
    2558              :         }
    2559            0 :         surfIntConv.hcModelEq = HcInt::UserValue; // reporting
    2560            0 :         surfIntConv.hcModelEqRpt = HcIntReportVals[(int)surfIntConv.hcModelEq];
    2561            0 :     } break;
    2562              : 
    2563            0 :     case OverrideType::Schedule: {
    2564            0 :         HInt = userIntConvModel.sched->getCurrentVal();
    2565              :         // Need to check for validity
    2566            0 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    2567            0 :             state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].in = KIVA_CONST_CONV(HInt);
    2568              :         }
    2569            0 :         surfIntConv.hcModelEq = HcInt::UserSchedule; // reporting
    2570            0 :         surfIntConv.hcModelEqRpt = HcIntReportVals[(int)surfIntConv.hcModelEq];
    2571            0 :     } break;
    2572              : 
    2573            0 :     case OverrideType::UserCurve: {
    2574            0 :         HInt = CalcUserDefinedIntHcModel(state, SurfNum, userIntConvModel.UserCurveIndex);
    2575              :         // Kiva convection handled in function above
    2576            0 :         surfIntConv.hcModelEq = HcInt::UserCurve; // reporting
    2577            0 :         surfIntConv.hcModelEqRpt = HcIntReportVals[(int)surfIntConv.hcModelEq];
    2578            0 :     } break;
    2579            0 :     case OverrideType::SpecifiedModel: {
    2580            0 :         HInt = EvaluateIntHcModels(state, SurfNum, userIntConvModel.HcIntModelEq);
    2581              :         // Kiva convection handled in function above
    2582            0 :         surfIntConv.hcModelEq = userIntConvModel.HcIntModelEq;
    2583            0 :         surfIntConv.hcModelEqRpt = HcIntReportVals[(int)surfIntConv.hcModelEq];
    2584            0 :     } break;
    2585            0 :     default: {
    2586            0 :         assert(false);
    2587              :     }
    2588              :     }
    2589              : 
    2590            0 :     return HInt;
    2591              : }
    2592              : 
    2593       206020 : Real64 CalcISO15099WindowIntConvCoeff(EnergyPlusData &state,
    2594              :                                       Real64 const SurfaceTemperature, // Temperature of surface for evaluation of HcIn
    2595              :                                       Real64 const AirTemperature,     // Mean Air Temperature of Zone (or adjacent air temperature)
    2596              :                                       Real64 const AirHumRat,          // air humidity ratio
    2597              :                                       Real64 const Height,             // window cavity height [m]
    2598              :                                       Real64 TiltDeg,                  // glazing tilt in degrees
    2599              :                                       Real64 const sineTilt            // sine of glazing tilt
    2600              : )
    2601              : {
    2602              : 
    2603              :     // SUBROUTINE INFORMATION:
    2604              :     //       AUTHOR         B. Griffith
    2605              :     //       DATE WRITTEN   January 2009
    2606              :     //       MODIFIED       BG May 2009, added EMS override for window coeffs.
    2607              : 
    2608              :     // PURPOSE OF THIS SUBROUTINE:
    2609              :     // Calculate interior surface convection coefficients for windows
    2610              : 
    2611              :     // METHODOLOGY EMPLOYED:
    2612              :     // correlation documented in ISO 15099, Section 8.3.2.2
    2613              : 
    2614              :     // REFERENCES:
    2615              :     // Internation Standard ISO 15099. Thermal performance of windows, doors and shading devices -- Detailed Calculations
    2616              :     // First Edition 2003-11-15. ISO 15099:2003(E)
    2617              : 
    2618              :     // Locals
    2619              :     static constexpr Real64 OneThird((1.0 / 3.0)); // 1/3 in highest precision
    2620       206020 :     static Real64 const pow_5_25(0.56 * root_4(1.0E+5));
    2621       206020 :     static Real64 const pow_11_25(0.56 * root_4(1.0E+11));
    2622              :     static Real64 const pow_11_2(0.58 * std::pow(1.0E+11, 0.2));
    2623              :     static constexpr std::string_view RoutineName("WindowTempsForNominalCond");
    2624              : 
    2625              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2626       206020 :     Real64 constexpr g(9.81); // acceleration due to gravity [m/s2]
    2627       206020 :     Real64 Nuint(0.0);        // Nusselt number for interior surface convection
    2628              : 
    2629       206020 :     Real64 SurfTempKelvin = SurfaceTemperature + Constant::Kelvin;
    2630       206020 :     Real64 AirTempKelvin = AirTemperature + Constant::Kelvin;
    2631       206020 :     Real64 DeltaTemp = SurfaceTemperature - AirTemperature;
    2632              : 
    2633              :     // protect against wildly out of range temperatures
    2634       206020 :     if ((AirTempKelvin < 200.0) || (AirTempKelvin > 400.0)) { // out of range
    2635            0 :         return state.dataHeatBal->LowHConvLimit;
    2636              :     }
    2637       206020 :     if ((SurfTempKelvin < 180.0) || (SurfTempKelvin > 450.0)) { // out of range
    2638            0 :         return state.dataHeatBal->LowHConvLimit;
    2639              :     }
    2640              : 
    2641              :     // mean film temperature
    2642       206020 :     Real64 TmeanFilmKelvin = AirTempKelvin + 0.25 * (DeltaTemp); // eq. 133 in ISO 15099
    2643       206020 :     Real64 TmeanFilm = TmeanFilmKelvin - 273.15;
    2644              : 
    2645              :     // density of air [kg/m3]
    2646       206020 :     Real64 rho = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, TmeanFilm, AirHumRat, RoutineName);
    2647              : 
    2648              :     // the following properties are probably for dry air, should maybe be remade for moist-air
    2649       206020 :     Real64 lambda = 2.873E-3 + 7.76E-5 * TmeanFilmKelvin; // thermal conductivity of air [W/m-K] // Table B.1 in ISO 15099,
    2650       206020 :     Real64 mu = 3.723E-6 + 4.94E-8 * TmeanFilmKelvin;     // dynamic viscosity of air [kg/m-s] // Table B.2 in ISO 15099
    2651       206020 :     Real64 Cp = Psychrometrics::PsyCpAirFnW(AirHumRat);   // specific heat of air [J/kg-K]
    2652              : 
    2653              :     // four cases depending on tilt and DeltaTemp (heat flow direction )
    2654       206020 :     if (DeltaTemp > 0.0) TiltDeg = 180.0 - TiltDeg; // complement angle if cooling situation
    2655              : 
    2656              :     // Rayleigh number for cavity height [ Non dim]
    2657       206020 :     Real64 RaH = (pow_2(rho) * pow_3(Height) * g * Cp * (std::abs(DeltaTemp))) / (TmeanFilmKelvin * mu * lambda); // eq 132 in ISO 15099
    2658              : 
    2659              :     // case a)
    2660       206020 :     if ((0.0 <= TiltDeg) && (TiltDeg < 15.0)) {
    2661              : 
    2662            7 :         Nuint = 0.13 * std::pow(RaH, OneThird);
    2663              : 
    2664              :         // case b)
    2665       206013 :     } else if ((15.0 <= TiltDeg) && (TiltDeg <= 90.0)) {
    2666              : 
    2667              :         // Rayleigh number for slanted cavity
    2668       206010 :         Real64 RaCV = 2.5E+5 * std::pow(std::exp(0.72 * TiltDeg) / sineTilt, 0.2); // eq. 137
    2669              : 
    2670       206010 :         if (RaH <= RaCV) {
    2671       197461 :             Nuint = 0.56 * root_4(RaH * sineTilt); // eq. 135 in ISO 15099
    2672              :         } else {
    2673         8549 :             Nuint = 0.13 * (std::pow(RaH, OneThird) - std::pow(RaCV, OneThird)) + 0.56 * root_4(RaCV * sineTilt); // eq. 136 in ISO 15099
    2674              :         }
    2675              : 
    2676              :         // case c)
    2677       206013 :     } else if ((90.0 < TiltDeg) && (TiltDeg <= 179.0)) {
    2678              :         // bound by applicability
    2679            0 :         if (RaH * sineTilt < 1.0E+5) {
    2680            0 :             Nuint = pow_5_25; // bounded
    2681            0 :         } else if (RaH * sineTilt >= 1.0E+11) {
    2682            0 :             Nuint = pow_11_25; // bounded
    2683              :         } else {
    2684            0 :             Nuint = 0.56 * root_4(RaH * sineTilt); // eq.. 138
    2685              :         }
    2686              : 
    2687              :         // case d)
    2688            3 :     } else if ((179.0 < TiltDeg) && (TiltDeg <= 180.0)) {
    2689              : 
    2690            3 :         if (RaH > 1.0E+11) {
    2691            0 :             Nuint = pow_11_2; // bounded
    2692              :         } else {
    2693            3 :             Nuint = 0.58 * std::pow(RaH, 0.2);
    2694              :         }
    2695              : 
    2696              :     } else {
    2697            0 :         assert(false);
    2698              :     }
    2699              : 
    2700       206020 :     return Nuint * lambda / Height;
    2701              : }
    2702              : 
    2703       206019 : void CalcISO15099WindowIntConvCoeff(EnergyPlusData &state,
    2704              :                                     int const SurfNum,               // surface number for which coefficients are being calculated
    2705              :                                     Real64 const SurfaceTemperature, // Temperature of surface for evaluation of HcIn
    2706              :                                     Real64 const AirTemperature      // Mean Air Temperature of Zone (or adjacent air temperature)
    2707              : )
    2708              : {
    2709       206019 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    2710              : 
    2711              :     // Get humidity ratio
    2712              :     Real64 AirHumRat =
    2713       206019 :         (surface.spaceNum > 0) ? state.dataZoneTempPredictorCorrector->spaceHeatBalance(surface.spaceNum).airHumRatAvg : state.dataEnvrn->OutHumRat;
    2714              : 
    2715       206019 :     Real64 Height = surface.Height;
    2716       206019 :     Real64 TiltDeg = surface.Tilt;
    2717       206019 :     Real64 sineTilt = surface.SinTilt;
    2718              : 
    2719       206019 :     if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    2720            0 :         ShowFatalError(state, format("ISO15099 convection model not applicable for foundation surface ={}", surface.Name));
    2721              :     }
    2722              : 
    2723       206019 :     state.dataHeatBalSurf->SurfHConvInt(SurfNum) =
    2724       206019 :         CalcISO15099WindowIntConvCoeff(state, SurfaceTemperature, AirTemperature, AirHumRat, Height, TiltDeg, sineTilt);
    2725              : 
    2726              :     // EMS override point (Violates Standard 15099?  throw warning? scary.
    2727       206019 :     if (state.dataSurface->SurfEMSOverrideIntConvCoef(SurfNum))
    2728            0 :         state.dataHeatBalSurf->SurfHConvInt(SurfNum) = state.dataSurface->SurfEMSValueForIntConvCoef(SurfNum);
    2729              :     else
    2730       206019 :         state.dataHeatBalSurf->SurfHConvInt(SurfNum) *= state.dataHeatBalSurf->SurfWinCoeffAdjRatio(SurfNum);
    2731              : 
    2732              :     // Establish some lower limit to avoid a zero convection coefficient (and potential divide by zero problems)
    2733       206019 :     if (state.dataHeatBalSurf->SurfHConvInt(SurfNum) < state.dataHeatBal->LowHConvLimit)
    2734          242 :         state.dataHeatBalSurf->SurfHConvInt(SurfNum) = state.dataHeatBal->LowHConvLimit;
    2735       206019 : }
    2736              : 
    2737          123 : void SetupAdaptiveConvStaticMetaData(EnergyPlusData &state)
    2738              : {
    2739              : 
    2740              :     // SUBROUTINE INFORMATION:
    2741              :     //       AUTHOR         Brent Griffith
    2742              :     //       DATE WRITTEN   Aug 2010
    2743              : 
    2744              :     // PURPOSE OF THIS SUBROUTINE:
    2745              :     // do one-time setup needed to store static data for adaptive convection algorithm
    2746              : 
    2747              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2748              :     Real64 thisZoneHorizHydralicDiameter;
    2749              :     bool DoReport;
    2750              : 
    2751          123 :     Real64 BldgVolumeSum = 0.0;
    2752          257 :     for (int ZoneLoop = 1; ZoneLoop <= state.dataGlobal->NumOfZones; ++ZoneLoop) {
    2753          134 :         auto const &zone = state.dataHeatBal->Zone(ZoneLoop);
    2754          134 :         BldgVolumeSum += zone.Volume * zone.Multiplier * zone.ListMultiplier;
    2755          134 :         Real64 PerimExtLengthSum = 0.0; // init
    2756          134 :         int ExtWallCount = 0;           // init
    2757          134 :         int ExtWindowCount = 0;         // init
    2758              :         // model perimeter of bounding horizontal rectangle from max and min x and y values
    2759          134 :         Real64 thisZoneSimplePerim = 2.0 * (zone.MaximumY - zone.MinimumY) + 2.0 * (zone.MaximumX - zone.MinimumX);
    2760          134 :         if (thisZoneSimplePerim > 0.0) {
    2761          134 :             thisZoneHorizHydralicDiameter = 4.0 * zone.FloorArea / thisZoneSimplePerim;
    2762            0 :         } else if (zone.FloorArea > 0.0) {
    2763            0 :             thisZoneHorizHydralicDiameter = std::sqrt(zone.FloorArea);
    2764              :         }
    2765              : 
    2766          134 :         Real64 thisWWR = (zone.ExtGrossWallArea > 0.0) ? (zone.ExtWindowArea / zone.ExtGrossWallArea) : -999.0; // throw error?
    2767              : 
    2768          286 :         for (int spaceNum : zone.spaceIndexes) {
    2769          152 :             auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    2770              :             // first pass thru this zones surfaces to gather data
    2771          960 :             for (int SurfLoop = thisSpace.HTSurfaceFirst; SurfLoop <= thisSpace.HTSurfaceLast; ++SurfLoop) {
    2772          808 :                 auto const &surf = state.dataSurface->Surface(SurfLoop);
    2773              :                 // first catch exterior walls and do summations
    2774          808 :                 if (surf.ExtBoundCond != ExternalEnvironment) continue;
    2775              : 
    2776          546 :                 if (surf.Class == SurfaceClass::Wall) {
    2777          356 :                     PerimExtLengthSum += surf.Width;
    2778          356 :                     ++ExtWallCount;
    2779          190 :                 } else if (surf.Class == SurfaceClass::Window || surf.Class == SurfaceClass::GlassDoor) {
    2780           49 :                     ++ExtWindowCount;
    2781              :                 }
    2782              :             }
    2783              :         }
    2784          286 :         for (int spaceNum : state.dataHeatBal->Zone(ZoneLoop).spaceIndexes) {
    2785          152 :             auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    2786              :             // second pass thru zone surfs to fill data
    2787          960 :             for (int SurfLoop = thisSpace.HTSurfaceFirst; SurfLoop <= thisSpace.HTSurfaceLast; ++SurfLoop) {
    2788          808 :                 auto &surfIntConv = state.dataSurface->surfIntConv(SurfLoop);
    2789          808 :                 surfIntConv.zoneWallHeight = zone.CeilingHeight;
    2790          808 :                 surfIntConv.zonePerimLength = PerimExtLengthSum;
    2791          808 :                 surfIntConv.zoneHorizHydrDiam = thisZoneHorizHydralicDiameter;
    2792          808 :                 surfIntConv.windowWallRatio = thisWWR;
    2793              :             } // 2nd pass over surfaces.
    2794              :         }
    2795              : 
    2796              :         // third pass for window locations
    2797          134 :         if ((ExtWindowCount > 0) && (ExtWallCount > 0)) {
    2798           64 :             for (int spaceNum : state.dataHeatBal->Zone(ZoneLoop).spaceIndexes) {
    2799           32 :                 auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    2800              : 
    2801          256 :                 for (int SurfLoop = thisSpace.HTSurfaceFirst; SurfLoop <= thisSpace.HTSurfaceLast; ++SurfLoop) {
    2802          224 :                     auto const &surf = state.dataSurface->Surface(SurfLoop);
    2803          224 :                     auto &surfIntConv = state.dataSurface->surfIntConv(SurfLoop);
    2804          224 :                     if (surf.ExtBoundCond != ExternalEnvironment) continue;
    2805              : 
    2806          162 :                     if (surf.Class == SurfaceClass::Window || surf.Class == SurfaceClass::GlassDoor) {
    2807              : 
    2808           49 :                         if (surfIntConv.windowWallRatio < 0.5) {
    2809           36 :                             surfIntConv.windowLocation =
    2810           36 :                                 (surf.Centroid.z < zone.Centroid.z) ? IntConvWinLoc::LowerPartOfExteriorWall : IntConvWinLoc::UpperPartOfExteriorWall;
    2811              :                         } else {
    2812           13 :                             surfIntConv.windowLocation = IntConvWinLoc::LargePartOfExteriorWall;
    2813              :                         }
    2814              : 
    2815           49 :                         auto const &baseSurf = state.dataSurface->Surface(surf.BaseSurf);
    2816           49 :                         auto &baseSurfIntConv = state.dataSurface->surfIntConv(surf.BaseSurf);
    2817           49 :                         if (baseSurf.ExtBoundCond != ExternalEnvironment) continue;
    2818           49 :                         if (baseSurf.Class != SurfaceClass::Wall) continue;
    2819              : 
    2820           46 :                         baseSurfIntConv.windowLocation =
    2821           46 :                             (baseSurf.Centroid.z < surf.Centroid.z) ? IntConvWinLoc::WindowAboveThis : IntConvWinLoc::WindowBelowThis;
    2822              : 
    2823          159 :                     } else if (surf.Class == SurfaceClass::Wall && surfIntConv.windowLocation == IntConvWinLoc::NotSet) {
    2824           88 :                         surfIntConv.windowLocation =
    2825           88 :                             (surf.Centroid.z < zone.Centroid.z) ? IntConvWinLoc::WindowAboveThis : IntConvWinLoc::WindowBelowThis;
    2826              :                     }
    2827              :                 }
    2828              :             } // third pass over surfaces
    2829              :         }
    2830              :     } // loop over zones for inside face parameters
    2831              : 
    2832          123 :     state.dataConvect->CubeRootOfOverallBuildingVolume = std::pow(BldgVolumeSum, 1.0 / 3.0);
    2833              : 
    2834          123 :     SurfaceGeometry::GeoSummary geoSummaryRoof;
    2835          123 :     SurfaceGeometry::GetGeoSummaryRoof(state, geoSummaryRoof);
    2836              : 
    2837          123 :     state.dataConvect->RoofLongAxisOutwardAzimuth = geoSummaryRoof.Azimuth;
    2838              : 
    2839              :     // Calculate facade areas, perimeters, and heights.
    2840              :     // Why are these calculations so quick and dirty while the roof calcluation is much more detailed?
    2841          123 :     std::array<SurfaceGeometry::GeoSummary, (int)DataSurfaces::Compass8::Num> geoSummaryFacades;
    2842              : 
    2843              :     // first pass over surfaces for outside face params
    2844          951 :     for (auto const &surf : state.dataSurface->Surface) {
    2845          828 :         if (surf.ExtBoundCond != ExternalEnvironment) {
    2846          262 :             continue;
    2847              :         }
    2848          566 :         if (!surf.HeatTransSurf) {
    2849           20 :             continue;
    2850              :         }
    2851          546 :         if ((surf.Tilt < 45.0) || (surf.Tilt >= 135.0)) continue; // not a vertical wall
    2852              : 
    2853          403 :         DataSurfaces::Compass8 compass8 = AzimuthToCompass8(surf.Azimuth);
    2854              : 
    2855          403 :         Real64 x_min = Constant::BigNumber;
    2856          403 :         Real64 x_max = -Constant::BigNumber;
    2857          403 :         Real64 y_min = Constant::BigNumber;
    2858          403 :         Real64 y_max = -Constant::BigNumber;
    2859          403 :         Real64 z_min = Constant::BigNumber;
    2860          403 :         Real64 z_max = -Constant::BigNumber;
    2861              : 
    2862         2013 :         for (auto const &v : surf.Vertex) {
    2863         1610 :             if (v.x < x_min) {
    2864          498 :                 x_min = v.x;
    2865         1112 :             } else if (v.x > x_max) {
    2866          559 :                 x_max = v.x;
    2867              :             }
    2868         1610 :             if (v.y < y_min) {
    2869          500 :                 y_min = v.y;
    2870         1110 :             } else if (v.y > y_max) {
    2871          498 :                 y_max = v.y;
    2872              :             }
    2873         1610 :             if (v.z < z_min) {
    2874          806 :                 z_min = v.z;
    2875          804 :             } else if (v.z > z_max) {
    2876          804 :                 z_max = v.z;
    2877              :             }
    2878              :         }
    2879              : 
    2880          403 :         auto &facade = geoSummaryFacades[(int)compass8];
    2881          403 :         facade.Area += surf.Area;
    2882          403 :         facade.Zmax = max(z_max, facade.Zmax);
    2883          403 :         facade.Zmin = min(z_min, facade.Zmin);
    2884          403 :         facade.Ymax = max(y_max, facade.Ymax);
    2885          403 :         facade.Ymin = min(y_min, facade.Ymin);
    2886          403 :         facade.Xmax = max(x_max, facade.Xmax);
    2887          403 :         facade.Xmin = min(x_min, facade.Xmin);
    2888              :     } // fist loop over surfaces for outside face params
    2889              : 
    2890         1107 :     for (auto &facade : geoSummaryFacades) {
    2891          984 :         facade.Perimeter = 2.0 * std::sqrt(pow_2(facade.Xmax - facade.Xmin) + pow_2(facade.Ymax - facade.Ymin)) + 2.0 * (facade.Zmax - facade.Zmin);
    2892          984 :         facade.Height = facade.Zmax - facade.Zmin;
    2893              :     }
    2894          947 :     for (int surfNum = 1; surfNum <= state.dataSurface->TotSurfaces; ++surfNum) {
    2895          824 :         auto const &surf = state.dataSurface->Surface(surfNum);
    2896          824 :         if (surf.ExtBoundCond != ExternalEnvironment) continue;
    2897          562 :         if (!surf.HeatTransSurf) continue;
    2898              : 
    2899          546 :         Real64 z_min = Constant::BigNumber;
    2900          546 :         Real64 z_max = -Constant::BigNumber;
    2901         2728 :         for (auto const &v : surf.Vertex) {
    2902         2182 :             if (v.z < z_min) {
    2903          951 :                 z_min = v.z;
    2904         1231 :             } else if (v.z > z_max) {
    2905          949 :                 z_max = v.z;
    2906              :             }
    2907              :         }
    2908          546 :         Real64 z_del = z_max - z_min;
    2909              : 
    2910          546 :         auto &surfExtConv = state.dataSurface->surfExtConv(surfNum);
    2911          546 :         if ((surf.Tilt >= 45.0) && (surf.Tilt < 135.0)) { // treat as vertical wall
    2912          403 :             DataSurfaces::Compass8 compass8 = AzimuthToCompass8(surf.Azimuth);
    2913          403 :             auto const &facade = geoSummaryFacades[(int)compass8];
    2914              : 
    2915          403 :             surfExtConv.faceArea = max(facade.Area, surf.GrossArea);
    2916          403 :             surfExtConv.facePerimeter = max(facade.Perimeter, surf.Perimeter);
    2917          403 :             surfExtConv.faceHeight = max(facade.Height, z_del);
    2918          546 :         } else if (surf.Tilt < 45.0) { // assume part of roof
    2919          106 :             surfExtConv.faceArea = max(geoSummaryRoof.Area, surf.GrossArea);
    2920          106 :             surfExtConv.facePerimeter = max(geoSummaryRoof.Perimeter, surf.Perimeter);
    2921          106 :             surfExtConv.faceHeight = max(geoSummaryRoof.Height, z_del);
    2922           37 :         } else if (surf.Tilt >= 135.0) { // assume floor over exterior, just use surface's geometry
    2923           37 :             surfExtConv.faceArea = surf.GrossArea;
    2924           37 :             surfExtConv.facePerimeter = surf.Perimeter;
    2925           37 :             surfExtConv.faceHeight = z_del;
    2926              :         }
    2927              :     } // second pass thru surfs for outside face convection params.
    2928              : 
    2929              :     // now send to EIO if surface reporting selected
    2930          369 :     General::ScanForReports(state, "Surfaces", DoReport, "Details");
    2931          123 :     if (DoReport) { // echo out static geometry data related to convection models
    2932              :         static constexpr std::string_view Format_900("! <Surface Convection Parameters>, Surface Name, Outside Model Assignment, Outside "
    2933              :                                                      "Area [m2], Outside Perimeter [m], Outside Height "
    2934              :                                                      "[m], Inside Model Assignment, Inside Height [m], Inside Perimeter Envelope [m], Inside "
    2935              :                                                      "Hydraulic Diameter [m], Window Wall Ratio, "
    2936              :                                                      "Window Location, Near Radiant {{Yes/No}}, Has Active HVAC {{Yes/No}}\n");
    2937            0 :         print(state.files.eio, Format_900); // header
    2938            0 :         for (int SurfLoop : state.dataSurface->AllSurfaceListReportOrder) {
    2939            0 :             auto const &surf = state.dataSurface->Surface(SurfLoop);
    2940            0 :             auto const &surfExtConv = state.dataSurface->surfExtConv(SurfLoop);
    2941            0 :             auto const &surfIntConv = state.dataSurface->surfIntConv(SurfLoop);
    2942              : 
    2943            0 :             if (!surf.HeatTransSurf) continue;
    2944              : 
    2945              :             static constexpr std::string_view Format_901(
    2946              :                 "Surface Convection Parameters,{},{},{:.2R},{:.2R},{:.2R},{},{:.2R},{:.2R},{:.2R},{:.2R},{},{},{}\n");
    2947              : 
    2948              :             // This reporting rubric (using numbers instead of strings, using negative numbers for "built-in" coefficients) is stupid,
    2949              :             // but we are maintaining compatiblity here
    2950            0 :             int hcExtRptNum = surfExtConv.userModelNum;
    2951            0 :             if (hcExtRptNum == 0) hcExtRptNum = -Convect::HcExtReportVals[(int)surfExtConv.model];
    2952              : 
    2953            0 :             int hcIntRptNum = surfIntConv.userModelNum;
    2954            0 :             if (hcIntRptNum == 0) hcIntRptNum = -Convect::HcIntReportVals[(int)surfIntConv.model];
    2955              : 
    2956            0 :             print(state.files.eio,
    2957              :                   Format_901,
    2958            0 :                   surf.Name,
    2959              :                   hcExtRptNum,
    2960            0 :                   surfExtConv.faceArea,
    2961            0 :                   surfExtConv.facePerimeter,
    2962            0 :                   surfExtConv.faceHeight,
    2963              :                   hcIntRptNum,
    2964            0 :                   surfIntConv.zoneWallHeight,
    2965            0 :                   surfIntConv.zonePerimLength,
    2966            0 :                   surfIntConv.zoneHorizHydrDiam,
    2967            0 :                   surfIntConv.windowWallRatio,
    2968            0 :                   surfIntConv.windowLocation,
    2969            0 :                   surfIntConv.getsRadiantHeat ? "Yes" : "No",
    2970            0 :                   surfIntConv.hasActiveInIt ? "Yes" : "No");
    2971              : 
    2972              :             // [m] length of perimeter zone's exterior wall | [m] hydraulic diameter, usually 4 times the zone floor area div by
    2973              :             // perimeter | [-] area of windows over area of exterior wall for zone | relative location of window in zone for
    2974              :             // interior Hc models
    2975              :         }
    2976              : 
    2977              :         // if display advanced reports also dump meta group data used for convection geometry
    2978            0 :         if (state.dataGlobal->DisplayAdvancedReportVariables) {
    2979              :             static constexpr std::string_view Format_8000 =
    2980              :                 "! <Building Convection Parameters:{} Facade>, Perimeter, Height, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax \n";
    2981              :             static constexpr std::string_view Format_8001 =
    2982              :                 "Building Convection Parameters:{} Facade, {:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R}\n";
    2983              : 
    2984            0 :             for (int c8 = 0; c8 < (int)DataSurfaces::Compass8::Num; ++c8) {
    2985              : 
    2986              :                 // header for north facade
    2987            0 :                 print(state.files.eio, Format_8000, DataSurfaces::compass8Names[c8]);
    2988              : 
    2989            0 :                 auto const &facade = geoSummaryFacades[c8];
    2990            0 :                 print(state.files.eio,
    2991              :                       Format_8001,
    2992            0 :                       DataSurfaces::compass8Names[c8],
    2993            0 :                       facade.Perimeter,
    2994            0 :                       facade.Height,
    2995            0 :                       facade.Xmin,
    2996            0 :                       facade.Xmax,
    2997            0 :                       facade.Ymin,
    2998            0 :                       facade.Ymax,
    2999            0 :                       facade.Zmin,
    3000            0 :                       facade.Zmax);
    3001              :             }
    3002              : 
    3003              :             static constexpr std::string_view Format_8800(
    3004              :                 "! <Building Convection Parameters:Roof>, Area [m2], Perimeter [m], Height [m], Tilt [deg], Azimuth [deg]\n");
    3005            0 :             print(state.files.eio, Format_8800); // header for roof
    3006              :             static constexpr std::string_view Format_8801("Building Convection Parameters:Roof,{:.2R},{:.2R},{:.2R},{:.2R},{:.2R}");
    3007            0 :             print(state.files.eio,
    3008              :                   Format_8801,
    3009              :                   geoSummaryRoof.Area,
    3010              :                   geoSummaryRoof.Perimeter,
    3011              :                   geoSummaryRoof.Height,
    3012              :                   geoSummaryRoof.Tilt,
    3013              :                   geoSummaryRoof.Azimuth);
    3014              :         } // Display
    3015              :     }     // Do Report
    3016          123 : }
    3017              : 
    3018           89 : void SetupAdaptiveConvRadiantSurfaceData(EnergyPlusData &state)
    3019              : {
    3020              : 
    3021              :     // SUBROUTINE INFORMATION:
    3022              :     //       AUTHOR         Brent Griffith
    3023              :     //       DATE WRITTEN   Sept 2011
    3024              : 
    3025              :     // PURPOSE OF THIS SUBROUTINE:
    3026              :     // identify Zones that have active radiant elements for convection model classifications
    3027              : 
    3028              :     // METHODOLOGY EMPLOYED:
    3029              :     // Need to fill in values for ZoneEquipConfig%InWallActiveElement, ZoneEquipConfig%InCeilingActiveElement
    3030              :     // and ZoneEquipConfig(ZoneNum)%InFloorActiveElement.
    3031              : 
    3032          187 :     for (int ZoneLoop = 1; ZoneLoop <= state.dataGlobal->NumOfZones; ++ZoneLoop) {
    3033           98 :         int activeWallCount = 0;
    3034           98 :         Real64 activeWallArea = 0.0;
    3035           98 :         int activeCeilingCount = 0;
    3036           98 :         Real64 activeCeilingArea = 0.0;
    3037           98 :         int activeFloorCount = 0;
    3038           98 :         Real64 activeFloorArea = 0.0;
    3039              : 
    3040           98 :         auto const &zone = state.dataHeatBal->Zone(ZoneLoop);
    3041          214 :         for (int spaceNum : zone.spaceIndexes) {
    3042          116 :             auto const &thisSpace = state.dataHeatBal->space(spaceNum);
    3043          698 :             for (int SurfLoop = thisSpace.HTSurfaceFirst; SurfLoop <= thisSpace.HTSurfaceLast; ++SurfLoop) {
    3044          582 :                 auto const &surface = state.dataSurface->Surface(SurfLoop);
    3045          582 :                 if (!state.dataSurface->surfIntConv(SurfLoop).hasActiveInIt) continue;
    3046            0 :                 if (surface.Class == SurfaceClass::Wall || surface.Class == SurfaceClass::Door) {
    3047            0 :                     ++activeWallCount;
    3048            0 :                     activeWallArea += surface.Area;
    3049            0 :                 } else if (surface.Class == SurfaceClass::Roof) {
    3050            0 :                     ++activeCeilingCount;
    3051            0 :                     activeCeilingArea += surface.Area;
    3052            0 :                 } else if (surface.Class == SurfaceClass::Floor) {
    3053            0 :                     ++activeFloorCount;
    3054            0 :                     activeFloorArea += surface.Area;
    3055              :                 }
    3056              :             }
    3057              :         } // surface loop
    3058              : 
    3059           98 :         auto &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(ZoneLoop);
    3060           98 :         zoneEquipConfig.InWallActiveElement = (activeWallCount > 0 && activeWallArea > 0.0);
    3061           98 :         zoneEquipConfig.InCeilingActiveElement = (activeCeilingCount > 0 && activeCeilingArea > 0.0);
    3062           98 :         zoneEquipConfig.InFloorActiveElement = (activeFloorCount > 0 && activeFloorArea > 0);
    3063              :     } // zone loop
    3064           89 : }
    3065              : 
    3066            0 : void ManageIntAdaptiveConvAlgo(EnergyPlusData &state,
    3067              :                                int const SurfNum) // surface number for which coefficients are being calculated
    3068              : {
    3069              : 
    3070              :     // SUBROUTINE INFORMATION:
    3071              :     //       AUTHOR         Brent Griffith
    3072              :     //       DATE WRITTEN   Aug 2010
    3073              : 
    3074              :     // PURPOSE OF THIS SUBROUTINE:
    3075              :     // This subroutine manages the calculation of interior convection coefficient for a surface.
    3076              : 
    3077              :     // METHODOLOGY EMPLOYED:
    3078              :     // This routine implements the Adaptive Convection Algorithm developed by IB-M 2000 and IB-M 2002
    3079              :     //  - first calls a large routine, DynamicIntConvSurfaceClassification, that has most of the complex logic
    3080              :     //  - then calls a straightforward routine that maps the classification to model equation
    3081              :     //  - then calls a routine with a large case statement that calls model equations.
    3082              : 
    3083              :     // USE STATEMENTS:
    3084              : 
    3085              :     // this next call sets up the flow regime and assigns a classification to surface
    3086              :     //  TODO: candidate for rework to do zone level calcs once rather than for each surface
    3087            0 :     DynamicIntConvSurfaceClassification(state, SurfNum);
    3088              : 
    3089              :     // simple worker routine takes surface classification and fills in model to use (IntConvHcModelEq) for that surface
    3090            0 :     MapIntConvClassToHcModels(state, SurfNum);
    3091              : 
    3092            0 :     state.dataHeatBalSurf->SurfHConvInt(SurfNum) = EvaluateIntHcModels(state, SurfNum, state.dataSurface->surfIntConv(SurfNum).hcModelEq);
    3093            0 : }
    3094              : 
    3095            0 : Real64 ManageExtAdaptiveConvAlgo(EnergyPlusData &state,
    3096              :                                  int const SurfNum) // surface number for which coefficients are being calculated
    3097              : {
    3098              : 
    3099              :     // SUBROUTINE INFORMATION:
    3100              :     //       AUTHOR         Brent Griffith
    3101              :     //       DATE WRITTEN   Aug 2010
    3102              : 
    3103              :     // PURPOSE OF THIS SUBROUTINE:
    3104              :     // This subroutine calculates the convection coefficient for the outside face of a surface
    3105              : 
    3106              :     // METHODOLOGY EMPLOYED:
    3107              :     // This routine implements an adaptive structure and classification system for outdoor
    3108              :     //   It calls a series of separable worker routines
    3109              : 
    3110            0 :     DynamicExtConvSurfaceClassification(state, SurfNum);
    3111              : 
    3112            0 :     MapExtConvClassToHcModels(state, SurfNum);
    3113              : 
    3114            0 :     auto const &surfExtConv = state.dataSurface->surfExtConv(SurfNum);
    3115            0 :     return EvaluateExtHcModels(state, SurfNum, surfExtConv.hnModelEq, surfExtConv.hfModelEq);
    3116              : }
    3117              : 
    3118            6 : Real64 EvaluateIntHcModels(EnergyPlusData &state, int const SurfNum, HcInt const ConvModelEquationNum)
    3119              : {
    3120              : 
    3121              :     // SUBROUTINE INFORMATION:
    3122              :     //       AUTHOR         Brent Griffith
    3123              :     //       DATE WRITTEN   Aug 2010
    3124              : 
    3125              :     // PURPOSE OF THIS SUBROUTINE:
    3126              :     // central case statement for calling inside convection models
    3127              : 
    3128              :     // METHODOLOGY EMPLOYED:
    3129              :     //  - fills value for Hc by calling the appropriate convection model, usually as a function.
    3130              :     //     preparation of argument values for the function calls is contained in each Case block (repeats)
    3131              :     //  - also updates the reference air temperature type for use in the surface heat balance calcs
    3132              : 
    3133            6 :     Real64 tmpHc = 0.0;
    3134              : 
    3135            6 :     auto const &thisSurface = state.dataSurface->Surface(SurfNum);
    3136            6 :     auto const &surfIntConv = state.dataSurface->surfIntConv(SurfNum);
    3137              : 
    3138            6 :     int const ZoneNum = thisSurface.Zone;
    3139            6 :     int const spaceNum = thisSurface.spaceNum;
    3140            6 :     Real64 const Tsurface = state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfNum);
    3141            6 :     Real64 const Tzone = state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).MAT;
    3142              : 
    3143            6 :     auto &HnFn = state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].in;
    3144              :     // now call appropriate function to calculate Hc
    3145            6 :     switch (ConvModelEquationNum) {
    3146              : 
    3147            0 :     case HcInt::UserCurve: {
    3148            0 :         tmpHc = CalcUserDefinedIntHcModel(state, SurfNum, surfIntConv.hcUserCurveNum);
    3149            0 :     } break;
    3150              : 
    3151            0 :     case HcInt::ASHRAEVerticalWall: {
    3152            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3153            0 :             HnFn = [](double Tsurf, double Tamb, double, double, double) -> double { return CalcASHRAEVerticalWall(Tsurf - Tamb); };
    3154              :         } else {
    3155            0 :             tmpHc = CalcASHRAEVerticalWall((Tsurface - Tzone));
    3156              :         }
    3157            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3158              : 
    3159            0 :     } break;
    3160              : 
    3161            0 :     case HcInt::WaltonUnstableHorizontalOrTilt: {
    3162            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3163            0 :             HnFn = [](double Tsurf, double Tamb, double, double, double cosTilt) -> double {
    3164            0 :                 return CalcWaltonUnstableHorizontalOrTilt(Tsurf - Tamb, cosTilt);
    3165            0 :             };
    3166              :         } else {
    3167            0 :             tmpHc = CalcWaltonUnstableHorizontalOrTilt((Tsurface - Tzone), thisSurface.CosTilt); // TODO verify CosTilt in vs out
    3168              :         }
    3169            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3170            0 :     } break;
    3171              : 
    3172            0 :     case HcInt::WaltonStableHorizontalOrTilt: {
    3173            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3174            0 :             HnFn = [](double Tsurf, double Tamb, double, double, double cosTilt) -> double {
    3175            0 :                 return CalcWaltonStableHorizontalOrTilt(Tsurf - Tamb, cosTilt);
    3176            0 :             };
    3177              :         } else {
    3178            0 :             tmpHc = CalcWaltonStableHorizontalOrTilt((Tsurface - Tzone), thisSurface.CosTilt); // TODO verify CosTilt in vs out
    3179              :         }
    3180            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3181            0 :     } break;
    3182              : 
    3183            2 :     case HcInt::FisherPedersenCeilDiffuserFloor: {
    3184            2 :         Real64 AirChangeRate = CalcCeilingDiffuserACH(state, ZoneNum);
    3185            2 :         Real64 AirHumRat = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).airHumRatAvg;
    3186            2 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3187              : 
    3188            0 :             HnFn = [=, &state](double Tsurf, double Tamb, double, double, double cosTilt) -> double {
    3189            0 :                 return CalcFisherPedersenCeilDiffuserFloor(state, AirChangeRate, Tsurf, Tamb, cosTilt, AirHumRat, thisSurface.Height);
    3190            0 :             };
    3191              :         } else {
    3192            2 :             tmpHc = CalcFisherPedersenCeilDiffuserFloor(state,
    3193              :                                                         AirChangeRate,
    3194              :                                                         Tsurface,
    3195              :                                                         Tzone,
    3196            2 :                                                         thisSurface.CosTilt,
    3197              :                                                         AirHumRat,
    3198            2 :                                                         thisSurface.Height,
    3199            2 :                                                         state.dataConstruction->Construct(thisSurface.Construction).TypeIsWindow);
    3200              :         }
    3201            2 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3202            2 :     } break;
    3203              : 
    3204            2 :     case HcInt::FisherPedersenCeilDiffuserCeiling: {
    3205            2 :         Real64 AirChangeRate = CalcCeilingDiffuserACH(state, ZoneNum);
    3206            2 :         Real64 AirHumRat = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).airHumRatAvg;
    3207            2 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3208              : 
    3209            0 :             HnFn = [=, &state](double Tsurf, double Tamb, double, double, double cosTilt) -> double {
    3210            0 :                 return CalcFisherPedersenCeilDiffuserCeiling(state, AirChangeRate, Tsurf, Tamb, cosTilt, AirHumRat, thisSurface.Height);
    3211            0 :             };
    3212              :         } else {
    3213            2 :             tmpHc = CalcFisherPedersenCeilDiffuserCeiling(state,
    3214              :                                                           AirChangeRate,
    3215              :                                                           Tsurface,
    3216              :                                                           Tzone,
    3217            2 :                                                           thisSurface.CosTilt,
    3218              :                                                           AirHumRat,
    3219            2 :                                                           thisSurface.Height,
    3220            2 :                                                           state.dataConstruction->Construct(thisSurface.Construction).TypeIsWindow);
    3221              :         }
    3222            2 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3223            2 :     } break;
    3224              : 
    3225            2 :     case HcInt::FisherPedersenCeilDiffuserWalls: {
    3226            2 :         Real64 AirChangeRate = CalcCeilingDiffuserACH(state, ZoneNum);
    3227            2 :         Real64 AirHumRat = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).airHumRatAvg;
    3228            2 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3229              : 
    3230            0 :             HnFn = [=, &state](double Tsurf, double Tamb, double, double, double cosTilt) -> double {
    3231            0 :                 return CalcFisherPedersenCeilDiffuserWalls(state, AirChangeRate, Tsurf, Tamb, cosTilt, AirHumRat, thisSurface.Height);
    3232            0 :             };
    3233              :         } else {
    3234            2 :             tmpHc = CalcFisherPedersenCeilDiffuserWalls(state,
    3235              :                                                         AirChangeRate,
    3236              :                                                         Tsurface,
    3237              :                                                         Tzone,
    3238            2 :                                                         thisSurface.CosTilt,
    3239              :                                                         AirHumRat,
    3240            2 :                                                         thisSurface.Height,
    3241            2 :                                                         state.dataConstruction->Construct(thisSurface.Construction).TypeIsWindow);
    3242              :         }
    3243            2 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3244            0 :             HnFn = [=](double, double, double, double, double) -> double { return tmpHc; };
    3245              :         }
    3246            2 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3247            2 :     } break;
    3248              : 
    3249            0 :     case HcInt::AlamdariHammondStableHorizontal: {
    3250            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3251            0 :             Real64 HorizHydrDiam = surfIntConv.zoneHorizHydrDiam;
    3252            0 :             HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double {
    3253            0 :                 return CalcAlamdariHammondStableHorizontal(Tsurf - Tamb, HorizHydrDiam);
    3254            0 :             };
    3255              :         } else {
    3256            0 :             tmpHc = CalcAlamdariHammondStableHorizontal(state, (Tsurface - Tzone), surfIntConv.zoneHorizHydrDiam, SurfNum);
    3257              :         }
    3258            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3259            0 :     } break;
    3260              : 
    3261            0 :     case HcInt::AlamdariHammondVerticalWall: {
    3262            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3263            0 :             Real64 WallHeight = surfIntConv.zoneWallHeight;
    3264            0 :             HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double {
    3265            0 :                 return CalcAlamdariHammondVerticalWall(Tsurf - Tamb, WallHeight);
    3266            0 :             };
    3267              :         } else {
    3268            0 :             tmpHc = CalcAlamdariHammondVerticalWall(state, (Tsurface - Tzone), surfIntConv.zoneWallHeight, SurfNum);
    3269              :         }
    3270            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3271            0 :     } break;
    3272              : 
    3273            0 :     case HcInt::AlamdariHammondUnstableHorizontal: {
    3274            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3275            0 :             Real64 HorizHydrDiam = surfIntConv.zoneHorizHydrDiam;
    3276            0 :             HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double {
    3277            0 :                 return CalcAlamdariHammondStableHorizontal(Tsurf - Tamb, HorizHydrDiam);
    3278            0 :             };
    3279              :         } else {
    3280            0 :             tmpHc = CalcAlamdariHammondUnstableHorizontal(state, (Tsurface - Tzone), surfIntConv.zoneHorizHydrDiam, SurfNum);
    3281              :         }
    3282            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3283            0 :     } break;
    3284              : 
    3285            0 :     case HcInt::KhalifaEq3WallAwayFromHeat: {
    3286            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3287            0 :             HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double { return CalcKhalifaEq3WallAwayFromHeat(Tsurf - Tamb); };
    3288              :         } else {
    3289            0 :             tmpHc = CalcKhalifaEq3WallAwayFromHeat((Tsurface - Tzone));
    3290              :         }
    3291            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3292            0 :     } break;
    3293              : 
    3294            0 :     case HcInt::KhalifaEq4CeilingAwayFromHeat: {
    3295            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3296            0 :             HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double { return CalcKhalifaEq4CeilingAwayFromHeat(Tsurf - Tamb); };
    3297              :         } else {
    3298            0 :             tmpHc = CalcKhalifaEq4CeilingAwayFromHeat((Tsurface - Tzone));
    3299              :         }
    3300            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3301            0 :     } break;
    3302              : 
    3303            0 :     case HcInt::KhalifaEq5WallNearHeat: {
    3304            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3305            0 :             HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double { return CalcKhalifaEq5WallsNearHeat(Tsurf - Tamb); };
    3306              :         } else {
    3307            0 :             tmpHc = CalcKhalifaEq5WallsNearHeat((Tsurface - Tzone));
    3308              :         }
    3309            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3310            0 :     } break;
    3311              : 
    3312            0 :     case HcInt::KhalifaEq6NonHeatedWalls: {
    3313            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3314            0 :             HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double { return CalcKhalifaEq6NonHeatedWalls(Tsurf - Tamb); };
    3315              :         } else {
    3316            0 :             tmpHc = CalcKhalifaEq6NonHeatedWalls((Tsurface - Tzone));
    3317              :         }
    3318            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3319            0 :     } break;
    3320              : 
    3321            0 :     case HcInt::KhalifaEq7Ceiling: {
    3322            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3323            0 :             HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double { return CalcKhalifaEq7Ceiling(Tsurf - Tamb); };
    3324              :         } else {
    3325            0 :             tmpHc = CalcKhalifaEq7Ceiling((Tsurface - Tzone));
    3326              :         }
    3327            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3328            0 :     } break;
    3329              : 
    3330            0 :     case HcInt::AwbiHattonHeatedFloor: {
    3331            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3332            0 :             Real64 HorizHydrDiam = surfIntConv.zoneHorizHydrDiam;
    3333            0 :             HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double {
    3334            0 :                 return CalcAwbiHattonHeatedFloor(Tsurf - Tamb, HorizHydrDiam);
    3335            0 :             };
    3336              :         } else {
    3337            0 :             tmpHc = CalcAwbiHattonHeatedFloor((Tsurface - Tzone), surfIntConv.zoneHorizHydrDiam);
    3338              :         }
    3339            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3340            0 :     } break;
    3341              : 
    3342            0 :     case HcInt::AwbiHattonHeatedWall: {
    3343            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3344            0 :             Real64 HorizHydrDiam = surfIntConv.zoneHorizHydrDiam;
    3345            0 :             HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double { return CalcAwbiHattonHeatedWall(Tsurf - Tamb, HorizHydrDiam); };
    3346              :         } else {
    3347            0 :             tmpHc = CalcAwbiHattonHeatedWall((Tsurface - Tzone), surfIntConv.zoneHorizHydrDiam);
    3348              :         }
    3349            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3350            0 :     } break;
    3351              : 
    3352            0 :     case HcInt::BeausoleilMorrisonMixedAssistingWall: {
    3353            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3354            0 :             HnFn = [=, &state](double Tsurf, double Tamb, double, double, double) -> double {
    3355            0 :                 return CalcBeausoleilMorrisonMixedAssistedWall(
    3356            0 :                     Tsurf - Tamb, surfIntConv.zoneWallHeight, Tsurf, CalcZoneSupplyAirTemp(state, ZoneNum), CalcZoneSystemACH(state, ZoneNum));
    3357            0 :             };
    3358              :         } else {
    3359            0 :             tmpHc = CalcBeausoleilMorrisonMixedAssistedWall(state, (Tsurface - Tzone), surfIntConv.zoneWallHeight, Tsurface, ZoneNum);
    3360              :         }
    3361            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3362            0 :     } break;
    3363              : 
    3364            0 :     case HcInt::BeausoleilMorrisonMixedOppossingWall: {
    3365            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3366            0 :             HnFn = [=, &state](double Tsurf, double Tamb, double, double, double) -> double {
    3367            0 :                 return CalcBeausoleilMorrisonMixedOpposingWall(
    3368            0 :                     Tsurf - Tamb, surfIntConv.zoneWallHeight, Tsurf, CalcZoneSupplyAirTemp(state, ZoneNum), CalcZoneSystemACH(state, ZoneNum));
    3369            0 :             };
    3370              :         } else {
    3371            0 :             tmpHc = CalcBeausoleilMorrisonMixedOpposingWall(state, (Tsurface - Tzone), surfIntConv.zoneWallHeight, Tsurface, ZoneNum);
    3372              :         }
    3373            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3374            0 :     } break;
    3375              : 
    3376            0 :     case HcInt::BeausoleilMorrisonMixedStableCeiling: {
    3377            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3378            0 :             HnFn = [=, &state](double Tsurf, double Tamb, double, double, double) -> double {
    3379            0 :                 return CalcBeausoleilMorrisonMixedStableCeiling(
    3380            0 :                     Tsurf - Tamb, surfIntConv.zoneHorizHydrDiam, Tsurf, CalcZoneSupplyAirTemp(state, ZoneNum), CalcZoneSystemACH(state, ZoneNum));
    3381            0 :             };
    3382              :         } else {
    3383            0 :             tmpHc = CalcBeausoleilMorrisonMixedStableCeiling(state, (Tsurface - Tzone), surfIntConv.zoneHorizHydrDiam, Tsurface, ZoneNum);
    3384              :         }
    3385            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3386            0 :     } break;
    3387              : 
    3388            0 :     case HcInt::BeausoleilMorrisonMixedUnstableCeiling: {
    3389            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3390            0 :             HnFn = [=, &state](double Tsurf, double Tamb, double, double, double) -> double {
    3391            0 :                 return CalcBeausoleilMorrisonMixedUnstableCeiling(
    3392            0 :                     Tsurf - Tamb, surfIntConv.zoneHorizHydrDiam, Tsurf, CalcZoneSupplyAirTemp(state, ZoneNum), CalcZoneSystemACH(state, ZoneNum));
    3393            0 :             };
    3394              :         } else {
    3395            0 :             tmpHc = CalcBeausoleilMorrisonMixedUnstableCeiling(state, (Tsurface - Tzone), surfIntConv.zoneHorizHydrDiam, Tsurface, ZoneNum);
    3396              :         }
    3397            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3398            0 :     } break;
    3399              : 
    3400            0 :     case HcInt::BeausoleilMorrisonMixedStableFloor: {
    3401            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3402            0 :             HnFn = [=, &state](double Tsurf, double Tamb, double, double, double) -> double {
    3403            0 :                 return CalcBeausoleilMorrisonMixedStableFloor(
    3404            0 :                     Tsurf - Tamb, surfIntConv.zoneHorizHydrDiam, Tsurf, CalcZoneSupplyAirTemp(state, ZoneNum), CalcZoneSystemACH(state, ZoneNum));
    3405            0 :             };
    3406              :         } else {
    3407            0 :             tmpHc = CalcBeausoleilMorrisonMixedStableFloor(state, (Tsurface - Tzone), surfIntConv.zoneHorizHydrDiam, Tsurface, ZoneNum);
    3408              :         }
    3409            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3410            0 :     } break;
    3411              : 
    3412            0 :     case HcInt::BeausoleilMorrisonMixedUnstableFloor: {
    3413            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3414            0 :             HnFn = [=, &state](double Tsurf, double Tamb, double, double, double) -> double {
    3415            0 :                 return CalcBeausoleilMorrisonMixedUnstableFloor(
    3416            0 :                     Tsurf - Tamb, surfIntConv.zoneHorizHydrDiam, Tsurf, CalcZoneSupplyAirTemp(state, ZoneNum), CalcZoneSystemACH(state, ZoneNum));
    3417            0 :             };
    3418              :         } else {
    3419            0 :             tmpHc = CalcBeausoleilMorrisonMixedUnstableFloor(state, (Tsurface - Tzone), surfIntConv.zoneHorizHydrDiam, Tsurface, ZoneNum);
    3420              :         }
    3421            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3422            0 :     } break;
    3423              : 
    3424            0 :     case HcInt::FohannoPolidoriVerticalWall: {
    3425            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3426            0 :             Real64 QdotConvection = -state.dataHeatBalSurf->SurfQdotConvInPerArea(SurfNum);
    3427            0 :             Real64 WallHeight = surfIntConv.zoneWallHeight;
    3428            0 :             HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double {
    3429            0 :                 return CalcFohannoPolidoriVerticalWall(Tsurf - Tamb,
    3430              :                                                        WallHeight,
    3431              :                                                        Tsurf - Constant::Kelvin, // Kiva already uses Kelvin, but algorithm expects C
    3432            0 :                                                        QdotConvection);
    3433            0 :             };
    3434              :         } else {
    3435            0 :             tmpHc = CallCalcFohannoPolidoriVerticalWall(
    3436            0 :                 state, (Tsurface - Tzone), surfIntConv.zoneWallHeight, Tsurface, -state.dataHeatBalSurf->SurfQdotConvInPerArea(SurfNum), SurfNum);
    3437              :         }
    3438            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3439            0 :     } break;
    3440              : 
    3441            0 :     case HcInt::KaradagChilledCeiling: {
    3442            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3443            0 :             HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double { return CalcKaradagChilledCeiling(Tsurf - Tamb); };
    3444              :         } else {
    3445            0 :             tmpHc = CalcKaradagChilledCeiling((Tsurface - Tzone));
    3446              :         }
    3447            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3448            0 :     } break;
    3449              : 
    3450            0 :     case HcInt::ISO15099Windows: {
    3451            0 :         CalcISO15099WindowIntConvCoeff(state, SurfNum, Tsurface, Tzone);
    3452            0 :         tmpHc = state.dataHeatBalSurf->SurfHConvInt(SurfNum);
    3453            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3454            0 :     } break;
    3455              : 
    3456            0 :     case HcInt::GoldsteinNovoselacCeilingDiffuserWindow: {
    3457            0 :         tmpHc = CalcGoldsteinNovoselacCeilingDiffuserWindow(
    3458            0 :             state, surfIntConv.zonePerimLength, surfIntConv.windowWallRatio, surfIntConv.windowLocation, ZoneNum);
    3459            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3460            0 :             HnFn = [=](double, double, double, double, double) -> double { return tmpHc; };
    3461              :         }
    3462            0 :         if (state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber > 0) {
    3463            0 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneSupplyAirTemp;
    3464              :         } else {
    3465            0 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3466              :         }
    3467            0 :     } break;
    3468              : 
    3469            0 :     case HcInt::GoldsteinNovoselacCeilingDiffuserWalls: {
    3470            0 :         tmpHc = CalcGoldsteinNovoselacCeilingDiffuserWall(state, surfIntConv.zonePerimLength, surfIntConv.windowLocation, ZoneNum);
    3471            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3472            0 :             HnFn = [=](double, double, double, double, double) -> double { return tmpHc; };
    3473              :         }
    3474            0 :         if (state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber > 0) {
    3475            0 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneSupplyAirTemp;
    3476              :         } else {
    3477            0 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3478              :         }
    3479            0 :     } break;
    3480              : 
    3481            0 :     case HcInt::GoldsteinNovoselacCeilingDiffuserFloor: {
    3482            0 :         tmpHc = CalcGoldsteinNovoselacCeilingDiffuserFloor(surfIntConv.zonePerimLength, ZoneNum);
    3483            0 :         if (thisSurface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3484            0 :             HnFn = [=](double, double, double, double, double) -> double { return tmpHc; };
    3485              :         }
    3486            0 :         if (state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber > 0) {
    3487            0 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneSupplyAirTemp;
    3488              :         } else {
    3489            0 :             state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    3490              :         }
    3491            0 :     } break;
    3492            0 :     default: {
    3493            0 :         assert(false);
    3494              :     } break;
    3495              :     } // switch (ConvModelEqNum)
    3496              : 
    3497            6 :     state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
    3498              : 
    3499            6 :     if (tmpHc < AdaptiveHcIntLowLimit) tmpHc = AdaptiveHcIntLowLimit;
    3500              : 
    3501            6 :     return tmpHc;
    3502              : }
    3503              : 
    3504            0 : Real64 EvaluateExtHcModels(EnergyPlusData &state, int const SurfNum, HcExt const NaturalConvModelEqNum, HcExt const ForcedConvModelEqNum)
    3505              : {
    3506              : 
    3507              :     // SUBROUTINE INFORMATION:
    3508              :     //       AUTHOR         Brent Griffith
    3509              :     //       DATE WRITTEN   Aug 2010
    3510              : 
    3511              :     // PURPOSE OF THIS SUBROUTINE:
    3512              :     // central case statement for evaluating exterior specific convection models
    3513              : 
    3514              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3515            0 :     Real64 Hf(0.0); // the forced, or wind driven portion of film coefficient
    3516            0 :     Real64 Hn(0.0); // the natural, or buoyancy driven portion of film coefficient
    3517              :     Real64 SurfWindSpeed;
    3518              :     Real64 SurfWindDir;
    3519              :     Real64 HydraulicDiameter;
    3520              : 
    3521              :     // Kiva callback functions
    3522            0 :     Kiva::ForcedConvectionTerm HfTermFn;
    3523            0 :     Kiva::ConvectionAlgorithm HfFn(KIVA_CONST_CONV(0.0));
    3524            0 :     Kiva::ConvectionAlgorithm HnFn(KIVA_CONST_CONV(0.0));
    3525              : 
    3526            0 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    3527            0 :     auto const &surfExtConv = state.dataSurface->surfExtConv(SurfNum);
    3528            0 :     auto const &SurfQdotConvOutRepPerArea = state.dataHeatBalSurf->SurfQdotConvOutPerArea;
    3529            0 :     Real64 SurfOutTemp = state.dataHeatBalSurf->SurfOutsideTempHist(1)(SurfNum);
    3530              : 
    3531              :     // first call Hn models
    3532            0 :     switch (NaturalConvModelEqNum) {
    3533            0 :     case HcExt::None: {
    3534            0 :         Hn = 0.0;
    3535            0 :         HnFn = KIVA_CONST_CONV(0.0);
    3536            0 :     } break;
    3537              : 
    3538            0 :     case HcExt::UserCurve: {
    3539            0 :         Hn = CalcUserDefinedExtHcModel(state, SurfNum, surfExtConv.hnUserCurveNum);
    3540            0 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3541            0 :             HnFn = [=, &state](double Tsurf, double Tamb, double HfTerm, double Roughness, double CosTilt) -> double {
    3542              :                 // Remove Hfterm since this is only used for the natural convection portion
    3543            0 :                 return state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].out(Tsurf, Tamb, HfTerm, Roughness, CosTilt) - HfTerm;
    3544            0 :             };
    3545              :         }
    3546            0 :     } break;
    3547              : 
    3548            0 :     case HcExt::NaturalASHRAEVerticalWall: {
    3549            0 :         Hn = CalcASHRAEVerticalWall((SurfOutTemp - state.dataSurface->SurfOutDryBulbTemp(SurfNum)));
    3550            0 :         HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double { return CalcASHRAEVerticalWall(Tsurf - Tamb); };
    3551            0 :     } break;
    3552              : 
    3553            0 :     case HcExt::NaturalWaltonUnstableHorizontalOrTilt: {
    3554            0 :         Hn = CalcWaltonUnstableHorizontalOrTilt((SurfOutTemp - state.dataSurface->SurfOutDryBulbTemp(SurfNum)),
    3555            0 :                                                 surface.CosTilt); // TODO verify CosTilt in vs out
    3556            0 :         HnFn = [=](double Tsurf, double Tamb, double, double, double cosTilt) -> double {
    3557            0 :             return CalcWaltonUnstableHorizontalOrTilt(Tsurf - Tamb, cosTilt);
    3558            0 :         };
    3559            0 :     } break;
    3560              : 
    3561            0 :     case HcExt::NaturalWaltonStableHorizontalOrTilt: {
    3562            0 :         Hn = CalcWaltonStableHorizontalOrTilt((SurfOutTemp - state.dataSurface->SurfOutDryBulbTemp(SurfNum)),
    3563            0 :                                               surface.CosTilt); // TODO verify CosTilt in vs out
    3564            0 :         HnFn = [=](double Tsurf, double Tamb, double, double, double cosTilt) -> double {
    3565            0 :             return CalcWaltonStableHorizontalOrTilt(Tsurf - Tamb, cosTilt);
    3566            0 :         };
    3567            0 :     } break;
    3568              : 
    3569            0 :     case HcExt::AlamdariHammondVerticalWall: {
    3570            0 :         Real64 FaceHeight = surfExtConv.faceHeight;
    3571            0 :         Hn = CalcAlamdariHammondVerticalWall(state, (SurfOutTemp - state.dataSurface->SurfOutDryBulbTemp(SurfNum)), FaceHeight, SurfNum);
    3572            0 :         HnFn = [=](double Tsurf, double Tamb, double, double, double) -> double { return CalcAlamdariHammondVerticalWall(Tsurf - Tamb, FaceHeight); };
    3573            0 :     } break;
    3574              : 
    3575            0 :     case HcExt::FohannoPolidoriVerticalWall: {
    3576            0 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3577              :             // Not compatible with Kiva (Exterior surfaces in Kiva are not currently reported. Also need to add cell-level convection.)
    3578            0 :             ShowFatalError(state, format("Fohanno Polidori convection model not applicable for foundation surface ={}", surface.Name));
    3579              :         }
    3580            0 :         Hn = CallCalcFohannoPolidoriVerticalWall(state,
    3581            0 :                                                  (SurfOutTemp - state.dataSurface->SurfOutDryBulbTemp(SurfNum)),
    3582            0 :                                                  surfExtConv.faceHeight,
    3583              :                                                  SurfOutTemp,
    3584            0 :                                                  -SurfQdotConvOutRepPerArea(SurfNum),
    3585              :                                                  SurfNum);
    3586            0 :     } break;
    3587              : 
    3588            0 :     case HcExt::AlamdariHammondStableHorizontal: {
    3589            0 :         if (surfExtConv.facePerimeter > 0.0) {
    3590            0 :             HydraulicDiameter = 4.0 * surfExtConv.faceArea / surfExtConv.facePerimeter;
    3591              :         } else {
    3592            0 :             HydraulicDiameter = std::sqrt(surfExtConv.faceArea);
    3593              :         }
    3594            0 :         Hn = CalcAlamdariHammondStableHorizontal(state, (SurfOutTemp - state.dataSurface->SurfOutDryBulbTemp(SurfNum)), HydraulicDiameter, SurfNum);
    3595            0 :     } break;
    3596              : 
    3597            0 :     case HcExt::AlamdariHammondUnstableHorizontal: {
    3598            0 :         if (surfExtConv.facePerimeter > 0.0) {
    3599            0 :             HydraulicDiameter = 4.0 * surfExtConv.faceArea / surfExtConv.facePerimeter;
    3600              :         } else {
    3601            0 :             HydraulicDiameter = std::sqrt(surfExtConv.faceArea);
    3602              :         }
    3603            0 :         Hn = CalcAlamdariHammondUnstableHorizontal(state, (SurfOutTemp - state.dataSurface->SurfOutDryBulbTemp(SurfNum)), HydraulicDiameter, SurfNum);
    3604            0 :     } break;
    3605            0 :     default: {
    3606            0 :         assert(false);
    3607              :     }
    3608              :     } // switch (NaturalConvModelEqNum)
    3609              : 
    3610            0 :     if (!surface.ExtWind) {
    3611            0 :         SurfWindSpeed = 0.0; // No wind exposure
    3612            0 :     } else if (surface.Class == SurfaceClass::Window && state.dataSurface->SurfWinShadingFlag(SurfNum) == WinShadingType::ExtShade) {
    3613            0 :         SurfWindSpeed = 0.0; // Assume zero wind speed at outside glass surface of window with exterior shade
    3614              :     } else {
    3615            0 :         SurfWindSpeed = state.dataSurface->SurfOutWindSpeed(SurfNum);
    3616              :     }
    3617              : 
    3618              :     Material::SurfaceRoughness Roughness =
    3619            0 :         state.dataMaterial->materials(state.dataConstruction->Construct(surface.Construction).LayerPoint(1))->Roughness;
    3620              : 
    3621            0 :     switch (ForcedConvModelEqNum) {
    3622            0 :     case HcExt::None: {
    3623            0 :         Hf = 0.0;
    3624            0 :         HfTermFn = KIVA_HF_DEF;
    3625            0 :         HfFn = KIVA_CONST_CONV(0.0);
    3626            0 :     } break;
    3627              : 
    3628            0 :     case HcExt::UserCurve: {
    3629            0 :         Hf = CalcUserDefinedExtHcModel(state, SurfNum, surfExtConv.hfUserCurveNum);
    3630            0 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3631            0 :             HfTermFn = state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f;
    3632            0 :             HnFn = state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].out;
    3633              :         }
    3634            0 :     } break;
    3635              : 
    3636            0 :     case HcExt::SparrowWindward: {
    3637            0 :         Hf = CalcSparrowWindward(state, Roughness, surfExtConv.facePerimeter, surfExtConv.faceArea, SurfWindSpeed, SurfNum);
    3638              : 
    3639            0 :         if (surface.Class == SurfaceClass::Floor) { // used for exterior grade
    3640              :             // Assume very large area for grade (relative to perimeter).
    3641            0 :             constexpr double area = 9999999.;
    3642            0 :             constexpr double perim = 1.;
    3643            0 :             HfTermFn = [=](double, double, double, double windSpeed) -> double { return CalcSparrowWindward(Roughness, perim, area, windSpeed); };
    3644              :         } else {
    3645            0 :             if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3646            0 :                 auto const &fnd = state.dataSurfaceGeometry->kivaManager.surfaceMap[SurfNum].get_instance(0).first->foundation;
    3647            0 :                 const double length = fnd.netPerimeter;
    3648            0 :                 const double height = fnd.wall.heightAboveGrade;
    3649            0 :                 const double area = length * height;
    3650            0 :                 const double perim = 2.0 * (length + height);
    3651            0 :                 HfTermFn = [=](double, double, double, double windSpeed) -> double {
    3652              :                     // Average windward and leeward since all walls use same algorithm
    3653            0 :                     double windwardHf = CalcSparrowWindward(Roughness, perim, area, windSpeed);
    3654            0 :                     double leewardHf = CalcSparrowLeeward(Roughness, perim, area, windSpeed);
    3655            0 :                     return (windwardHf + leewardHf) / 2.0;
    3656            0 :                 };
    3657              :             }
    3658              :         }
    3659            0 :         HfFn = [](double, double, double HfTerm, double, double) -> double { return HfTerm; };
    3660            0 :     } break;
    3661              : 
    3662            0 :     case HcExt::SparrowLeeward: {
    3663            0 :         Hf = CalcSparrowLeeward(state, Roughness, surfExtConv.facePerimeter, surfExtConv.faceArea, SurfWindSpeed, SurfNum);
    3664            0 :         if (surface.Class == SurfaceClass::Floor) { // used for exterior grade
    3665              :             // Assume very large area for grade (relative to perimeter).
    3666            0 :             constexpr double area = 9999999.;
    3667            0 :             constexpr double perim = 1.;
    3668            0 :             HfTermFn = [=](double, double, double, double windSpeed) -> double { return CalcSparrowLeeward(Roughness, perim, area, windSpeed); };
    3669              :         } else {
    3670            0 :             if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3671            0 :                 auto const &fnd = state.dataSurfaceGeometry->kivaManager.surfaceMap[SurfNum].get_instance(0).first->foundation;
    3672            0 :                 const double length = fnd.netPerimeter;
    3673            0 :                 const double height = fnd.wall.heightAboveGrade;
    3674            0 :                 const double area = length * height;
    3675            0 :                 const double perim = 2.0 * (length + height);
    3676            0 :                 HfTermFn = [=](double, double, double, double windSpeed) -> double {
    3677              :                     // Average windward and leeward since all walls use same algorithm
    3678            0 :                     double windwardHf = CalcSparrowWindward(Roughness, perim, area, windSpeed);
    3679            0 :                     double leewardHf = CalcSparrowLeeward(Roughness, perim, area, windSpeed);
    3680            0 :                     return (windwardHf + leewardHf) / 2.0;
    3681            0 :                 };
    3682              :             }
    3683              :         }
    3684            0 :         HfFn = [](double, double, double HfTerm, double, double) -> double { return HfTerm; };
    3685            0 :     } break;
    3686              : 
    3687            0 :     case HcExt::MoWiTTWindward: {
    3688            0 :         Hf = CalcMoWITTWindward(SurfOutTemp - state.dataSurface->SurfOutDryBulbTemp(SurfNum), SurfWindSpeed);
    3689            0 :         if (surface.Class == SurfaceClass::Floor) { // used for exterior grade
    3690            0 :             HfTermFn = [=](double, double, double, double windSpeed) -> double { return CalcMoWITTForcedWindward(windSpeed); };
    3691              :         } else {
    3692            0 :             HfTermFn = [=](double, double, double, double windSpeed) -> double {
    3693              :                 // Average windward and leeward since all walls use same algorithm
    3694            0 :                 double windwardHf = CalcMoWITTForcedWindward(windSpeed);
    3695            0 :                 double leewardHf = CalcMoWITTForcedLeeward(windSpeed);
    3696            0 :                 return (windwardHf + leewardHf) / 2.0;
    3697            0 :             };
    3698              :         }
    3699            0 :         HfFn = [](double, double, double HfTerm, double, double) -> double { return HfTerm; };
    3700            0 :     } break;
    3701              : 
    3702            0 :     case HcExt::MoWiTTLeeward: {
    3703            0 :         Hf = CalcMoWITTLeeward((SurfOutTemp - state.dataSurface->SurfOutDryBulbTemp(SurfNum)), SurfWindSpeed);
    3704            0 :         if (surface.Class == SurfaceClass::Floor) { // used for exterior grade
    3705            0 :             HfTermFn = [=](double, double, double, double windSpeed) -> double { return CalcMoWITTForcedLeeward(windSpeed); };
    3706              :         } else {
    3707            0 :             HfTermFn = [=](double, double, double, double windSpeed) -> double {
    3708              :                 // Average windward and leeward since all walls use same algorithm
    3709            0 :                 double windwardHf = CalcMoWITTForcedWindward(windSpeed);
    3710            0 :                 double leewardHf = CalcMoWITTForcedLeeward(windSpeed);
    3711            0 :                 return (windwardHf + leewardHf) / 2.0;
    3712            0 :             };
    3713              :         }
    3714            0 :         HfFn = [](double, double, double HfTerm, double, double) -> double { return HfTerm; };
    3715            0 :     } break;
    3716              : 
    3717            0 :     case HcExt::DOE2Windward: {
    3718            0 :         Hf = CalcDOE2Windward(SurfOutTemp, state.dataSurface->SurfOutDryBulbTemp(SurfNum), surface.CosTilt, SurfWindSpeed, Roughness);
    3719            0 :         if (surface.Class == SurfaceClass::Floor) { // used for exterior grade
    3720            0 :             HfTermFn = [=](double, double, double, double windSpeed) -> double { return CalcMoWITTForcedWindward(windSpeed); };
    3721              :         } else {
    3722            0 :             HfTermFn = [=](double, double, double, double windSpeed) -> double {
    3723              :                 // Average windward and leeward since all walls use same algorithm
    3724            0 :                 double windwardHf = CalcMoWITTForcedWindward(windSpeed);
    3725            0 :                 double leewardHf = CalcMoWITTForcedLeeward(windSpeed);
    3726            0 :                 return (windwardHf + leewardHf) / 2.0;
    3727            0 :             };
    3728              :         }
    3729            0 :         HfFn = [](double, double, double HfTerm, double, double) -> double { return HfTerm; };
    3730            0 :     } break;
    3731              : 
    3732            0 :     case HcExt::DOE2Leeward: {
    3733            0 :         Hf = CalcDOE2Leeward(SurfOutTemp, state.dataSurface->SurfOutDryBulbTemp(SurfNum), surface.CosTilt, SurfWindSpeed, Roughness);
    3734            0 :         if (surface.Class == SurfaceClass::Floor) { // used for exterior grade
    3735            0 :             HfTermFn = [=](double, double, double, double windSpeed) -> double { return CalcMoWITTForcedWindward(windSpeed); };
    3736              :         } else {
    3737            0 :             HfTermFn = [=](double, double, double, double windSpeed) -> double {
    3738              :                 // Average windward and leeward since all walls use same algorithm
    3739            0 :                 double windwardHf = CalcMoWITTForcedWindward(windSpeed);
    3740            0 :                 double leewardHf = CalcMoWITTForcedLeeward(windSpeed);
    3741            0 :                 return (windwardHf + leewardHf) / 2.0;
    3742            0 :             };
    3743              :         }
    3744            0 :         HfFn = [=](double Tsurf, double Tamb, double hfTerm, double, double cosTilt) -> double {
    3745            0 :             return CalcDOE2Forced(Tsurf, Tamb, cosTilt, hfTerm, Roughness);
    3746            0 :         };
    3747            0 :     } break;
    3748              : 
    3749            0 :     case HcExt::NusseltJurges: {
    3750            0 :         Hf = CalcNusseltJurges(SurfWindSpeed);
    3751            0 :         HfTermFn = [=](double, double, double, double windSpeed) -> double { return CalcNusseltJurges(windSpeed); };
    3752            0 :         HfFn = [](double, double, double HfTerm, double, double) -> double { return HfTerm; };
    3753            0 :     } break;
    3754              : 
    3755            0 :     case HcExt::McAdams: {
    3756            0 :         Hf = CalcMcAdams(SurfWindSpeed);
    3757            0 :         HfTermFn = [=](double, double, double, double windSpeed) -> double { return CalcMcAdams(windSpeed); };
    3758            0 :         HfFn = [](double, double, double HfTerm, double, double) -> double { return HfTerm; };
    3759            0 :     } break;
    3760              : 
    3761            0 :     case HcExt::Mitchell: {
    3762            0 :         Hf = CalcMitchell(state, SurfWindSpeed, state.dataConvect->CubeRootOfOverallBuildingVolume, SurfNum);
    3763            0 :         HfTermFn = [&](double, double, double, double windSpeed) -> double {
    3764            0 :             return CalcMitchell(windSpeed, state.dataConvect->CubeRootOfOverallBuildingVolume);
    3765            0 :         };
    3766            0 :         HfFn = [](double, double, double HfTerm, double, double) -> double { return HfTerm; };
    3767            0 :     } break;
    3768              : 
    3769            0 :     case HcExt::ClearRoof: {
    3770            0 :         SurfWindDir = state.dataSurface->SurfOutWindDir(SurfNum);
    3771            0 :         Hf = CalcClearRoof(state,
    3772              :                            SurfNum,
    3773              :                            SurfOutTemp,
    3774            0 :                            state.dataSurface->SurfOutDryBulbTemp(SurfNum),
    3775              :                            SurfWindSpeed,
    3776              :                            SurfWindDir,
    3777            0 :                            surfExtConv.faceArea,
    3778            0 :                            surfExtConv.facePerimeter);
    3779            0 :         HfTermFn = [=](double, double, double, double windSpeed) -> double { return windSpeed; };
    3780            0 :         if (surface.Class == SurfaceClass::Floor) { // used for exterior grade
    3781              :             // Assume very large area for grade (relative to perimeter).
    3782            0 :             constexpr double area = 9999999.;
    3783            0 :             constexpr double perim = 1.;
    3784            0 :             HfFn = [=, &state](double Tsurf, double Tamb, double hfTerm, double, double) -> double {
    3785            0 :                 return CalcClearRoof(state, Tsurf, Tamb, hfTerm, area, perim, Roughness);
    3786            0 :             };
    3787              :         } else {
    3788            0 :             if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3789            0 :                 auto const &fnd = state.dataSurfaceGeometry->kivaManager.surfaceMap[SurfNum].get_instance(0).first->foundation;
    3790            0 :                 const double length = fnd.netPerimeter;
    3791            0 :                 const double height = fnd.wall.heightAboveGrade;
    3792            0 :                 const double area = length * height;
    3793            0 :                 const double perim = 2.0 * (length + height);
    3794            0 :                 HfFn = [=, &state](double Tsurf, double Tamb, double hfTerm, double, double) -> double {
    3795            0 :                     return CalcClearRoof(state, Tsurf, Tamb, hfTerm, area, perim, Roughness);
    3796            0 :                 };
    3797              :             }
    3798              :         }
    3799            0 :     } break;
    3800              : 
    3801            0 :     case HcExt::BlockenWindward: {
    3802            0 :         Hf = CalcBlockenWindward(state, state.dataEnvrn->WindSpeed, state.dataEnvrn->WindDir, surface.Azimuth, SurfNum);
    3803              :         // Not compatible with Kiva (doesn't use weather station windspeed)
    3804            0 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3805            0 :             ShowFatalError(state, format("Blocken Windward convection model not applicable for foundation surface ={}", surface.Name));
    3806              :         }
    3807            0 :     } break;
    3808              : 
    3809            0 :     case HcExt::EmmelVertical: {
    3810            0 :         Hf = CalcEmmelVertical(state.dataEnvrn->WindSpeed, state.dataEnvrn->WindDir, surface.Azimuth);
    3811              :         // Not compatible with Kiva (doesn't use weather station windspeed)
    3812            0 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3813            0 :             ShowFatalError(state, format("Emmel Vertical convection model not applicable for foundation surface ={}", surface.Name));
    3814              :         }
    3815            0 :     } break;
    3816              : 
    3817            0 :     case HcExt::EmmelRoof: {
    3818            0 :         Hf = CalcEmmelRoof(state.dataEnvrn->WindSpeed, state.dataEnvrn->WindDir, state.dataConvect->RoofLongAxisOutwardAzimuth);
    3819              :         // Not compatible with Kiva (doesn't use weather station windspeed)
    3820            0 :         if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3821            0 :             ShowFatalError(state, format("Emmel Roof convection model not applicable for foundation surface ={}", surface.Name));
    3822              :         }
    3823            0 :         break;
    3824              :     } break;
    3825              : 
    3826            0 :     default: {
    3827            0 :         assert(false);
    3828              :     }
    3829              :     } // swtich (ForcedConvModelEqNum)
    3830              : 
    3831            0 :     Real64 Hc = Hf + Hn;
    3832              : 
    3833            0 :     if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    3834            0 :         state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f = HfTermFn;
    3835            0 :         state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].out =
    3836            0 :             [=](double Tsurf, double Tamb, double HfTerm, double Roughness, double cosTilt) -> double {
    3837            0 :             Real64 hcExt = HfFn(Tsurf, Tamb, HfTerm, Roughness, cosTilt) + HnFn(Tsurf, Tamb, HfTerm, Roughness, cosTilt);
    3838            0 :             if (hcExt < AdaptiveHcExtLowLimit) hcExt = AdaptiveHcExtLowLimit;
    3839            0 :             return hcExt;
    3840            0 :         };
    3841            0 :         Hc = 0.0; // Not used in Kiva
    3842              :     }
    3843              : 
    3844            0 :     if (Hc < AdaptiveHcExtLowLimit) Hc = AdaptiveHcExtLowLimit;
    3845            0 :     return Hc;
    3846            0 : }
    3847              : 
    3848            0 : void DynamicExtConvSurfaceClassification(EnergyPlusData &state, int const SurfNum) // surface number
    3849              : {
    3850              : 
    3851              :     // SUBROUTINE INFORMATION:
    3852              :     //       AUTHOR         B. Griffith
    3853              :     //       DATE WRITTEN   August 2010
    3854              : 
    3855              :     // METHODOLOGY EMPLOYED:
    3856              :     // Decide surface classification based on wind and buoyancy, class, orientation
    3857              : 
    3858            0 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    3859            0 :     auto &surfExtConv = state.dataSurface->surfExtConv(SurfNum);
    3860              : 
    3861            0 :     Real64 surfWindDir = state.dataSurface->SurfOutWindDir(SurfNum);
    3862              : 
    3863            0 :     if (surface.Class == SurfaceClass::Roof ||
    3864            0 :         (surface.Class == SurfaceClass::Floor && surface.ExtBoundCond == DataSurfaces::KivaFoundation) // Applies to exterior grade
    3865              :     ) {
    3866              :         Real64 DeltaTemp =
    3867            0 :             (surface.ExtBoundCond == DataSurfaces::KivaFoundation)
    3868            0 :                 ? (state.dataSurfaceGeometry->kivaManager.surfaceMap[SurfNum].results.Tconv - state.dataSurface->SurfOutDryBulbTemp(SurfNum))
    3869            0 :                 : (state.dataHeatBalSurf->SurfOutsideTempHist(1)(SurfNum) - state.dataSurface->SurfOutDryBulbTemp(SurfNum));
    3870              : 
    3871            0 :         surfExtConv.convClass = (DeltaTemp < 0.0) ? ExtConvClass::RoofStable : ExtConvClass::RoofUnstable;
    3872              : 
    3873            0 :     } else {
    3874            0 :         surfExtConv.convClass =
    3875            0 :             Windward(surface.CosTilt, surface.Azimuth, surfWindDir) ? ExtConvClass::WindwardVertWall : ExtConvClass::LeewardVertWall;
    3876              :     }
    3877            0 : }
    3878              : 
    3879            0 : void MapExtConvClassToHcModels(EnergyPlusData &state, int const SurfNum) // surface number
    3880              : {
    3881              : 
    3882              :     // SUBROUTINE INFORMATION:
    3883              :     //       AUTHOR         Brent Griffith
    3884              :     //       DATE WRITTEN   Aug 2010
    3885              : 
    3886              :     // Use these arrays to convert general surface classifications to
    3887              :     // specific classifications for both wind-driven and natural
    3888              :     // convection
    3889              :     static constexpr std::array<ExtConvClass2, (int)ExtConvClass::Num> WindConvectionExtConvClass2s = {
    3890              :         ExtConvClass2::WindConvection_WallWindward, // WindwardWall
    3891              :         ExtConvClass2::WindConvection_WallLeeward,  // LeewardWall
    3892              :         ExtConvClass2::WindConvection_HorizRoof,    // RoofStable
    3893              :         ExtConvClass2::WindConvection_HorizRoof     // RoofUnstable
    3894              :     };
    3895              : 
    3896              :     static constexpr std::array<ExtConvClass2, (int)ExtConvClass::Num> NaturalConvectionExtConvClass2s = {
    3897              :         ExtConvClass2::NaturalConvection_VertWall,     // WindwardWall
    3898              :         ExtConvClass2::NaturalConvection_VertWall,     // LeewardWall
    3899              :         ExtConvClass2::NaturalConvection_StableHoriz,  // RoofStable
    3900              :         ExtConvClass2::NaturalConvection_UnstableHoriz // RoofUnstable
    3901              :     };
    3902              : 
    3903            0 :     auto &surfExtConv = state.dataSurface->surfExtConv(SurfNum);
    3904              : 
    3905            0 :     ExtConvClass outConvClass = surfExtConv.convClass;
    3906            0 :     surfExtConv.convClassRpt = ExtConvClassReportVals[(int)outConvClass];
    3907              : 
    3908            0 :     ExtConvClass2 outConvClass2Wind = WindConvectionExtConvClass2s[(int)outConvClass];
    3909            0 :     ExtConvClass2 outConvClass2Natural = NaturalConvectionExtConvClass2s[(int)outConvClass];
    3910              : 
    3911            0 :     surfExtConv.hfModelEq = state.dataConvect->extAdaptiveConvAlgo.extConvClass2EqNums[(int)outConvClass2Wind];
    3912            0 :     surfExtConv.hfModelEqRpt = HcExtReportVals[(int)surfExtConv.hfModelEq];
    3913              : 
    3914            0 :     if (surfExtConv.hfModelEq == HcExt::UserCurve) {
    3915            0 :         surfExtConv.hfUserCurveNum = state.dataConvect->extAdaptiveConvAlgo.extConvClass2UserCurveNums[(int)outConvClass2Wind];
    3916              :     }
    3917              : 
    3918            0 :     surfExtConv.hnModelEq = state.dataConvect->extAdaptiveConvAlgo.extConvClass2EqNums[(int)outConvClass2Natural];
    3919            0 :     surfExtConv.hnModelEqRpt = HcExtReportVals[(int)surfExtConv.hnModelEq];
    3920            0 :     if (surfExtConv.hnModelEq == HcExt::UserCurve) {
    3921            0 :         surfExtConv.hnUserCurveNum = state.dataConvect->extAdaptiveConvAlgo.extConvClass2UserCurveNums[(int)outConvClass2Natural];
    3922              :     }
    3923            0 : }
    3924              : 
    3925           28 : void DynamicIntConvSurfaceClassification(EnergyPlusData &state, int const SurfNum) // surface number
    3926              : {
    3927              : 
    3928              :     // SUBROUTINE INFORMATION:
    3929              :     //       AUTHOR        Brent Griffith
    3930              :     //       DATE WRITTEN   Aug 2010
    3931              : 
    3932              :     // PURPOSE OF THIS SUBROUTINE:
    3933              :     // collects dynamic updates needed for adaptive convection algorithm
    3934              : 
    3935              :     // METHODOLOGY EMPLOYED:
    3936              :     // Decide flow regime to set IntConvClassification done by zone using the following rules
    3937              : 
    3938              :     // Using zone flow regime, and surface's characteristics assign IntConvHcModelEq
    3939              : 
    3940              :     // SUBROUTINE PARAMETER DEFINITIONS:
    3941           28 :     Real64 constexpr g(9.81);                     // gravity constant (m/s**2)
    3942           28 :     Real64 constexpr v(15.89e-6);                 // kinematic viscosity (m**2/s) for air at 300 K
    3943           28 :     Real64 constexpr ActiveDelTempThreshold(1.5); // deg C, temperature difference for surfaces to be considered "active"
    3944              : 
    3945              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3946           28 :     int PriorityEquipOn(0);
    3947           28 :     constexpr int MaxZoneEquipmentOn{11};
    3948           28 :     constexpr int MaxZoneEquipmentIdx{MaxZoneEquipmentOn - 1};
    3949           28 :     std::array<int, MaxZoneEquipmentOn> HeatingPriorityStack{};
    3950           28 :     std::array<int, MaxZoneEquipmentOn> CoolingPriorityStack{};
    3951           28 :     std::array<InConvFlowRegime, MaxZoneEquipmentOn> FlowRegimeStack{};
    3952           28 :     FlowRegimeStack.fill(InConvFlowRegime::Invalid);
    3953           28 :     int EquipOnCount(0);
    3954           28 :     InConvFlowRegime FinalFlowRegime(InConvFlowRegime::Invalid);
    3955           28 :     Real64 Tmin(std::numeric_limits<float>::max()); // temporary min surf temp
    3956           28 :     Real64 Tmax(std::numeric_limits<float>::min()); // temporary max surf temp
    3957           28 :     Real64 GrH(0.0);                                // Grashof number for zone height H
    3958           28 :     Real64 Re(0.0);                                 // Reynolds number for zone air system flow
    3959           28 :     Real64 Ri(0.0);                                 // Richardson Number, Gr/Re**2 for determining mixed regime
    3960           28 :     Real64 AirDensity(0.0);                         // temporary zone air density
    3961           28 :     Real64 DeltaTemp(0.0);                          // temporary temperature difference (Tsurf - Tair)
    3962              : 
    3963           28 :     auto &surface = state.dataSurface->Surface(SurfNum);
    3964           28 :     int zoneNum = surface.Zone;
    3965           28 :     int spaceNum = surface.spaceNum;
    3966           28 :     auto &zone = state.dataHeatBal->Zone(zoneNum);
    3967              : 
    3968           28 :     EquipOnCount = 0;
    3969              : 
    3970              :     // HVAC connections
    3971           28 :     if (!zone.IsControlled) { // no HVAC control
    3972            0 :         FlowRegimeStack[0] = InConvFlowRegime::A3;
    3973              :     } else { // is controlled, lets see by how and if that means is currently active
    3974              : 
    3975           28 :         auto &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(surface.Zone);
    3976           28 :         auto const &zoneNode = state.dataLoopNodes->Node(zone.SystemZoneNodeNumber);
    3977              : 
    3978           28 :         if (!(zoneEquipConfig.EquipListIndex > 0) || state.dataGlobal->SysSizingCalc || state.dataGlobal->ZoneSizingCalc ||
    3979            0 :             !state.dataZoneEquip->ZoneEquipSimulatedOnce) {
    3980           28 :             FlowRegimeStack[0] = InConvFlowRegime::A3;
    3981              :         } else {
    3982              : 
    3983            0 :             auto &zoneEquipList = state.dataZoneEquip->ZoneEquipList(zoneEquipConfig.EquipListIndex);
    3984            0 :             for (int EquipNum = 1; EquipNum <= zoneEquipList.NumOfEquipTypes; ++EquipNum) {
    3985              : 
    3986            0 :                 switch (zoneEquipList.EquipType(EquipNum)) {
    3987            0 :                 case DataZoneEquipment::ZoneEquipType::AirDistributionUnit:
    3988              :                 case DataZoneEquipment::ZoneEquipType::PurchasedAir: {
    3989            0 :                     if (!allocated(zoneEquipList.EquipData(EquipNum).OutletNodeNums)) continue;
    3990              : 
    3991              :                     // get inlet node, not zone node if possible
    3992            0 :                     int zoneInletNodeNum = zoneEquipList.EquipData(EquipNum).OutletNodeNums(1);
    3993            0 :                     if ((zoneInletNodeNum > 0 && state.dataLoopNodes->Node(zoneInletNodeNum).MassFlowRate > 0.0) ||
    3994            0 :                         (zoneInletNodeNum <= 0 && zoneNode.MassFlowRate > 0.0)) {
    3995            0 :                         EquipOnCount = min(EquipOnCount + 1, MaxZoneEquipmentIdx);
    3996            0 :                         FlowRegimeStack[EquipOnCount] = InConvFlowRegime::C;
    3997            0 :                         HeatingPriorityStack[EquipOnCount] = zoneEquipList.HeatingPriority(EquipNum);
    3998            0 :                         CoolingPriorityStack[EquipOnCount] = zoneEquipList.CoolingPriority(EquipNum);
    3999              :                     }
    4000            0 :                 } break;
    4001            0 :                 case DataZoneEquipment::ZoneEquipType::WindowAirConditioner:
    4002              :                 case DataZoneEquipment::ZoneEquipType::PackagedTerminalHeatPump:
    4003              :                 case DataZoneEquipment::ZoneEquipType::PackagedTerminalAirConditioner:
    4004              :                 case DataZoneEquipment::ZoneEquipType::DehumidifierDX:
    4005              :                 case DataZoneEquipment::ZoneEquipType::PackagedTerminalHeatPumpWaterToAir:
    4006              :                 case DataZoneEquipment::ZoneEquipType::FourPipeFanCoil:
    4007              :                 case DataZoneEquipment::ZoneEquipType::UnitVentilator:
    4008              :                 case DataZoneEquipment::ZoneEquipType::UnitHeater:
    4009              :                 case DataZoneEquipment::ZoneEquipType::OutdoorAirUnit: {
    4010            0 :                     if (!allocated(zoneEquipList.EquipData(EquipNum).OutletNodeNums)) continue;
    4011              : 
    4012            0 :                     int zoneInletNodeNum = zoneEquipList.EquipData(EquipNum).OutletNodeNums(1);
    4013            0 :                     if ((zoneInletNodeNum > 0 && state.dataLoopNodes->Node(zoneInletNodeNum).MassFlowRate > 0.0) ||
    4014            0 :                         (zoneInletNodeNum <= 0 && zoneNode.MassFlowRate > 0.0)) {
    4015              : 
    4016            0 :                         EquipOnCount = min(EquipOnCount + 1, MaxZoneEquipmentIdx);
    4017            0 :                         FlowRegimeStack[EquipOnCount] = InConvFlowRegime::D;
    4018            0 :                         HeatingPriorityStack[EquipOnCount] = zoneEquipList.HeatingPriority(EquipNum);
    4019            0 :                         CoolingPriorityStack[EquipOnCount] = zoneEquipList.CoolingPriority(EquipNum);
    4020              :                     }
    4021            0 :                 } break;
    4022            0 :                 case DataZoneEquipment::ZoneEquipType::CoolingPanel:
    4023              :                 case DataZoneEquipment::ZoneEquipType::BaseboardSteam:
    4024              :                 case DataZoneEquipment::ZoneEquipType::BaseboardConvectiveWater:
    4025              :                 case DataZoneEquipment::ZoneEquipType::BaseboardConvectiveElectric:
    4026              :                 case DataZoneEquipment::ZoneEquipType::BaseboardWater: {
    4027            0 :                     if (zoneEquipList.EquipData(EquipNum).ON) {
    4028            0 :                         EquipOnCount = min(EquipOnCount + 1, MaxZoneEquipmentIdx);
    4029            0 :                         FlowRegimeStack[EquipOnCount] = InConvFlowRegime::B;
    4030            0 :                         HeatingPriorityStack[EquipOnCount] = zoneEquipList.HeatingPriority(EquipNum);
    4031            0 :                         CoolingPriorityStack[EquipOnCount] = zoneEquipList.CoolingPriority(EquipNum);
    4032              :                     }
    4033            0 :                 } break;
    4034              :                     // Is this the same case as above?
    4035            0 :                 case DataZoneEquipment::ZoneEquipType::BaseboardElectric:
    4036              :                 case DataZoneEquipment::ZoneEquipType::HighTemperatureRadiant: {
    4037            0 :                     if (zoneEquipList.EquipData(EquipNum).ON) {
    4038            0 :                         EquipOnCount = min(EquipOnCount + 1, MaxZoneEquipmentIdx);
    4039            0 :                         FlowRegimeStack[EquipOnCount] = InConvFlowRegime::B;
    4040            0 :                         HeatingPriorityStack[EquipOnCount] = zoneEquipList.HeatingPriority(EquipNum);
    4041            0 :                         CoolingPriorityStack[EquipOnCount] = zoneEquipList.CoolingPriority(EquipNum);
    4042              :                     }
    4043            0 :                 } break;
    4044            0 :                 case DataZoneEquipment::ZoneEquipType::VentilatedSlab:
    4045              :                 case DataZoneEquipment::ZoneEquipType::LowTemperatureRadiantConstFlow:
    4046              :                 case DataZoneEquipment::ZoneEquipType::LowTemperatureRadiantVarFlow:
    4047              :                 case DataZoneEquipment::ZoneEquipType::LowTemperatureRadiantElectric: {
    4048            0 :                     if (zoneEquipConfig.InFloorActiveElement) {
    4049            0 :                         for (int spaceNumLoop : zone.spaceIndexes) {
    4050            0 :                             auto const &thisSpace = state.dataHeatBal->space(spaceNumLoop);
    4051              : 
    4052            0 :                             for (int SurfLoop = thisSpace.HTSurfaceFirst; SurfLoop <= thisSpace.HTSurfaceLast; ++SurfLoop) {
    4053              : 
    4054            0 :                                 if (!state.dataSurface->surfIntConv(SurfLoop).hasActiveInIt) continue;
    4055            0 :                                 auto const &surfaceLoop = state.dataSurface->Surface(SurfLoop);
    4056            0 :                                 if (surfaceLoop.Class != SurfaceClass::Floor) continue;
    4057              : 
    4058            0 :                                 Real64 DeltaTempLoop = state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfLoop) -
    4059            0 :                                                        state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNumLoop).MAT;
    4060            0 :                                 if (DeltaTempLoop > ActiveDelTempThreshold) { // assume heating with floor
    4061              :                                     // system ON is not enough because floor surfaces can continue to heat because of thermal capacity
    4062            0 :                                     EquipOnCount = min(EquipOnCount + 1, MaxZoneEquipmentIdx);
    4063            0 :                                     FlowRegimeStack[EquipOnCount] = InConvFlowRegime::A1;
    4064            0 :                                     HeatingPriorityStack[EquipOnCount] = zoneEquipList.HeatingPriority(EquipNum);
    4065            0 :                                     CoolingPriorityStack[EquipOnCount] = zoneEquipList.CoolingPriority(EquipNum);
    4066            0 :                                     break;
    4067              :                                 } // if (DeltaTemp)
    4068              :                             }     // for (SurfLoop)
    4069              :                         }         // for (spaceNumLoop)
    4070              :                     }             // if (InFloorActiveElement)
    4071              : 
    4072            0 :                     if (zoneEquipConfig.InCeilingActiveElement) {
    4073            0 :                         for (int spaceNumLoop : zone.spaceIndexes) {
    4074            0 :                             auto const &thisSpace = state.dataHeatBal->space(spaceNumLoop);
    4075              : 
    4076            0 :                             for (int SurfLoop = thisSpace.HTSurfaceFirst; SurfLoop <= thisSpace.HTSurfaceLast; ++SurfLoop) {
    4077            0 :                                 if (!state.dataSurface->surfIntConv(SurfLoop).hasActiveInIt) continue;
    4078            0 :                                 auto const &surfaceLoop = state.dataSurface->Surface(SurfLoop);
    4079            0 :                                 if (surfaceLoop.Class != SurfaceClass::Roof) continue;
    4080              : 
    4081            0 :                                 Real64 DeltaTempLoop = state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfLoop) -
    4082            0 :                                                        state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNumLoop).MAT;
    4083            0 :                                 if (DeltaTempLoop < ActiveDelTempThreshold) { // assume cooling with ceiling
    4084              :                                     // system ON is not enough because  surfaces can continue to cool because of thermal capacity
    4085            0 :                                     EquipOnCount = min(EquipOnCount + 1, MaxZoneEquipmentIdx);
    4086            0 :                                     FlowRegimeStack[EquipOnCount] = InConvFlowRegime::A1;
    4087            0 :                                     HeatingPriorityStack[EquipOnCount] = zoneEquipList.HeatingPriority(EquipNum);
    4088            0 :                                     CoolingPriorityStack[EquipOnCount] = zoneEquipList.CoolingPriority(EquipNum);
    4089            0 :                                     break;
    4090              :                                 } // if (DeltaTempLoop)
    4091              :                             }     // for (SurfLoop)
    4092              :                         }         // for (spaceNumLoop)
    4093              :                     }             // if (InCeilingActiveElement)
    4094              : 
    4095            0 :                     if (zoneEquipConfig.InWallActiveElement) {
    4096            0 :                         for (int spaceNumLoop : zone.spaceIndexes) {
    4097            0 :                             auto const &thisSpace = state.dataHeatBal->space(spaceNumLoop);
    4098              : 
    4099            0 :                             for (int SurfLoop = thisSpace.HTSurfaceFirst; SurfLoop <= thisSpace.HTSurfaceLast; ++SurfLoop) {
    4100            0 :                                 if (!state.dataSurface->surfIntConv(SurfLoop).hasActiveInIt) continue;
    4101            0 :                                 auto const &surface_test = state.dataSurface->Surface(SurfLoop);
    4102            0 :                                 if (surface_test.Class != SurfaceClass::Wall && surface_test.Class != SurfaceClass::Door) continue;
    4103              : 
    4104            0 :                                 DeltaTemp = state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfLoop) -
    4105            0 :                                             state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNumLoop).MAT;
    4106            0 :                                 if (DeltaTemp > ActiveDelTempThreshold) { // assume heating with wall panel
    4107              :                                     // system ON is not enough because  surfaces can continue to heat because of thermal capacity
    4108            0 :                                     EquipOnCount = min(EquipOnCount + 1, MaxZoneEquipmentIdx);
    4109            0 :                                     FlowRegimeStack[EquipOnCount] = InConvFlowRegime::A2;
    4110            0 :                                     HeatingPriorityStack[EquipOnCount] = zoneEquipList.HeatingPriority(EquipNum);
    4111            0 :                                     CoolingPriorityStack[EquipOnCount] = zoneEquipList.CoolingPriority(EquipNum);
    4112              :                                 } else { // not heating, no special models wall cooling so use simple buoyancy
    4113            0 :                                     EquipOnCount = min(EquipOnCount + 1, MaxZoneEquipmentIdx);
    4114            0 :                                     FlowRegimeStack[EquipOnCount] = InConvFlowRegime::A3;
    4115            0 :                                     HeatingPriorityStack[EquipOnCount] = zoneEquipList.HeatingPriority(EquipNum);
    4116            0 :                                     CoolingPriorityStack[EquipOnCount] = zoneEquipList.CoolingPriority(EquipNum);
    4117              :                                 } // else (DeltaTemp)
    4118              :                             }     // for (SurfLoop)
    4119              :                         }         // for (spaceNumLoop)
    4120              :                     }             // if (InWallActiveElement)
    4121            0 :                 } break;
    4122            0 :                 default:; // nothing
    4123              :                 }
    4124              : 
    4125              :             } // for (EquipNum)
    4126              :         }
    4127              :     }
    4128              : 
    4129              :     // now select which equipment type is dominant compared to all those that are ON
    4130           28 :     if (EquipOnCount > 0) {
    4131            0 :         if (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).predictedRate >= 0.0) { // heating load
    4132            0 :             PriorityEquipOn = 1;
    4133            0 :             for (int EquipOnLoop = 1; EquipOnLoop <= EquipOnCount; ++EquipOnLoop) {
    4134              :                 // assume highest priority/first sim order is dominant for flow regime
    4135            0 :                 if (HeatingPriorityStack[EquipOnLoop] < HeatingPriorityStack[PriorityEquipOn]) {
    4136            0 :                     PriorityEquipOn = EquipOnLoop;
    4137              :                 }
    4138              :             }
    4139            0 :         } else if (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).predictedRate < 0.0) { // cooling load
    4140            0 :             PriorityEquipOn = 1;
    4141            0 :             for (int EquipOnLoop = 1; EquipOnLoop <= EquipOnCount; ++EquipOnLoop) {
    4142              :                 // assume highest priority/first sim order is dominant for flow regime
    4143            0 :                 if (CoolingPriorityStack[EquipOnLoop] < CoolingPriorityStack[PriorityEquipOn]) {
    4144            0 :                     PriorityEquipOn = EquipOnLoop;
    4145              :                 }
    4146              :             }
    4147              :         }
    4148            0 :         FinalFlowRegime = FlowRegimeStack[PriorityEquipOn];
    4149              :     } else {
    4150              :         // no equipment on, so simple buoyancy flow regime
    4151           28 :         FinalFlowRegime = InConvFlowRegime::A3;
    4152              :     }
    4153              : 
    4154              :     // now if flow regimes C or D, then check for Mixed regime or very low flow rates
    4155           28 :     if ((FinalFlowRegime == InConvFlowRegime::C) || (FinalFlowRegime == InConvFlowRegime::D)) {
    4156              : 
    4157            0 :         auto const &zoneNode = state.dataLoopNodes->Node(zone.SystemZoneNodeNumber);
    4158              :         // Calculate Grashof, Reynolds, and Richardson numbers for the zone
    4159              :         // Grashof for zone air based on largest delta T between surfaces and zone height
    4160            0 :         for (int spaceNumLoop : zone.spaceIndexes) {
    4161            0 :             auto const &thisSpace = state.dataHeatBal->space(spaceNumLoop);
    4162            0 :             for (int surfNum = thisSpace.HTSurfaceFirst; surfNum <= thisSpace.HTSurfaceLast; ++surfNum) {
    4163            0 :                 Real64 SurfTemp = state.dataHeatBalSurf->SurfInsideTempHist(1)(surfNum);
    4164            0 :                 if (SurfTemp < Tmin)
    4165            0 :                     Tmin = SurfTemp;
    4166            0 :                 else if (SurfTemp > Tmax)
    4167            0 :                     Tmax = SurfTemp;
    4168              :             }
    4169              :         }
    4170            0 :         GrH = (g * (Tmax - Tmin) * pow_3(zone.CeilingHeight)) /
    4171            0 :               ((state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum).MAT + Constant::Kelvin) * pow_2(v));
    4172              : 
    4173              :         // Reynolds number = Vdot supply / v * cube root of zone volume (Goldstein and Noveselac 2010)
    4174            0 :         if (zoneNode.MassFlowRate > 0.0) {
    4175            0 :             AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state,
    4176            0 :                                                            state.dataEnvrn->OutBaroPress,
    4177            0 :                                                            zoneNode.Temp,
    4178            0 :                                                            Psychrometrics::PsyWFnTdpPb(state, zoneNode.Temp, state.dataEnvrn->OutBaroPress));
    4179            0 :             Re = zoneNode.MassFlowRate / (v * AirDensity * std::pow(zone.Volume, 1.0 / 3.0));
    4180              :         } else {
    4181            0 :             Re = 0.0;
    4182              :         }
    4183              : 
    4184            0 :         if (Re > 0.0) {
    4185            0 :             Ri = GrH / pow_2(Re); // Richardson Number
    4186            0 :             if (Ri > 10.0) {      // natural convection expected
    4187            0 :                 FinalFlowRegime = InConvFlowRegime::A3;
    4188            0 :             } else if (Ri < 0.1) { // forced
    4189              :                 // no change, already a forced regime
    4190              :             } else { // mixed
    4191            0 :                 FinalFlowRegime = InConvFlowRegime::E;
    4192              :             }
    4193              :         } else { // natural convection expected
    4194            0 :             FinalFlowRegime = InConvFlowRegime::A3;
    4195              :         }
    4196              :     }
    4197              : 
    4198              :     static constexpr std::array<std::array<IntConvClass, (int)ConvSurfDeltaT::Num>,
    4199              :                                 (int)SurfOrientation::Num>
    4200              :         A1{{
    4201              :             {IntConvClass::A1_FloorHeatCeilCool_StableHoriz,     // HorizontalDown, Positive
    4202              :              IntConvClass::A1_FloorHeatCeilCool_StableHoriz,     // HorizontalDown, Zero
    4203              :              IntConvClass::A1_FloorHeatCeilCool_UnstableHoriz},  // HorizontalDown, Negative
    4204              :             {IntConvClass::A1_FloorHeatCeilCool_StableTilted,    // TiltedDownward, Positive
    4205              :              IntConvClass::A1_FloorHeatCeilCool_StableTilted,    // TiltedDownward, Zero
    4206              :              IntConvClass::A1_FloorHeatCeilCool_UnstableTilted}, // TiltedDownward, Negative
    4207              :             {IntConvClass::A1_FloorHeatCeilCool_VertWalls,       // Vertical, Positive
    4208              :              IntConvClass::A1_FloorHeatCeilCool_VertWalls,       // Vertical, Zero
    4209              :              IntConvClass::A1_FloorHeatCeilCool_VertWalls},      // Vertical, Negative
    4210              :             {IntConvClass::A1_FloorHeatCeilCool_UnstableTilted,  // TiltedUpward, Positive
    4211              :              IntConvClass::A1_FloorHeatCeilCool_StableTilted,    // TiltedUpward, Zero
    4212              :              IntConvClass::A1_FloorHeatCeilCool_StableTilted},   // TiltedUpward, Negative
    4213              :             {IntConvClass::A1_FloorHeatCeilCool_UnstableHoriz,   // HorizontalUp, Positive
    4214              :              IntConvClass::A1_FloorHeatCeilCool_StableHoriz,     // HorizontalUp, Zero
    4215              :              IntConvClass::A1_FloorHeatCeilCool_StableHoriz}     // HorizontalUp, Negative
    4216              :         }};
    4217              : 
    4218              :     static constexpr std::array<std::array<IntConvClass, (int)ConvSurfDeltaT::Num>,
    4219              :                                 (int)SurfOrientation::Num>
    4220              :         A2{{
    4221              :             {IntConvClass::A2_WallPanelHeat_StableHoriz,         // HorizontalDown, Positive
    4222              :              IntConvClass::A2_WallPanelHeat_StableHoriz,         // HorizontalDown, Zero
    4223              :              IntConvClass::A2_WallPanelHeat_UnstableHoriz},      // HorizontalDown, Negative
    4224              :             {IntConvClass::A2_WallPanelHeat_StableTilted,        // TiltedDownward, Positive
    4225              :              IntConvClass::A2_WallPanelHeat_StableTilted,        // TiltedDownward, Zero
    4226              :              IntConvClass::A2_WallPanelHeat_UnstableTilted},     // TiltedDownward, Negative
    4227              :             {IntConvClass::A2_WallPanelHeat_VertWallsNonHeated,  // Vertical, Positive
    4228              :              IntConvClass::A2_WallPanelHeat_VertWallsNonHeated,  // Vertical, Zero
    4229              :              IntConvClass::A2_WallPanelHeat_VertWallsNonHeated}, // Vertical, Negative
    4230              :             {IntConvClass::A2_WallPanelHeat_UnstableTilted,      // TiltedUpward, Positive
    4231              :              IntConvClass::A2_WallPanelHeat_StableTilted,        // TiltedUpward, Zero
    4232              :              IntConvClass::A2_WallPanelHeat_StableTilted},       // TiltedUpward, Negative
    4233              :             {IntConvClass::A2_WallPanelHeat_UnstableHoriz,       // HorizontalUp, Positive
    4234              :              IntConvClass::A2_WallPanelHeat_StableHoriz,         // HorizontalUp, Zero
    4235              :              IntConvClass::A2_WallPanelHeat_StableHoriz}         // HorizontalUp, Negative
    4236              :         }};
    4237              : 
    4238              :     static constexpr std::array<std::array<IntConvClass, (int)ConvSurfDeltaT::Num>,
    4239              :                                 (int)SurfOrientation::Num>
    4240              :         A3{{
    4241              :             {IntConvClass::A3_SimpleBuoy_StableHoriz,     // HorizontalDown, Positive
    4242              :              IntConvClass::A3_SimpleBuoy_StableHoriz,     // HorizontalDown, Zero
    4243              :              IntConvClass::A3_SimpleBuoy_UnstableHoriz},  // HorizontalDown, Negative
    4244              :             {IntConvClass::A3_SimpleBuoy_StableTilted,    // TiltedDownward, Positive
    4245              :              IntConvClass::A3_SimpleBuoy_StableTilted,    // TiltedDownward, Zero
    4246              :              IntConvClass::A3_SimpleBuoy_UnstableTilted}, // TiltedDownward, Negative
    4247              :             {IntConvClass::A3_SimpleBuoy_VertWalls,       // Vertical, Positive
    4248              :              IntConvClass::A3_SimpleBuoy_VertWalls,       // Vertical, Zero
    4249              :              IntConvClass::A3_SimpleBuoy_VertWalls},      // Vertical, Negative
    4250              :             {IntConvClass::A3_SimpleBuoy_UnstableTilted,  // TiltedUpward, Positive
    4251              :              IntConvClass::A3_SimpleBuoy_StableTilted,    // TiltedUpward, Zero
    4252              :              IntConvClass::A3_SimpleBuoy_StableTilted},   // TiltedUpward, Negative
    4253              :             {IntConvClass::A3_SimpleBuoy_UnstableHoriz,   // HorizontalUp, Positive
    4254              :              IntConvClass::A3_SimpleBuoy_StableHoriz,     // HorizontalUp, Zero
    4255              :              IntConvClass::A3_SimpleBuoy_StableHoriz}     // HorizontalUp, Negative
    4256              :         }};
    4257              : 
    4258              :     static constexpr std::array<std::array<IntConvClass, (int)ConvSurfDeltaT::Num>,
    4259              :                                 (int)SurfOrientation::Num>
    4260              :         B{{
    4261              :             {IntConvClass::B_ConvectiveHeat_StableHoriz,     // HorizontalDown, Positive
    4262              :              IntConvClass::B_ConvectiveHeat_StableHoriz,     // HorizontalDown, Zero
    4263              :              IntConvClass::B_ConvectiveHeat_UnstableHoriz},  // HorizontalDown, Negative
    4264              :             {IntConvClass::B_ConvectiveHeat_StableTilted,    // TiltedDownward, Positive
    4265              :              IntConvClass::B_ConvectiveHeat_StableTilted,    // TiltedDownward, Zero
    4266              :              IntConvClass::B_ConvectiveHeat_UnstableTilted}, // TiltedDownward, Negative
    4267              :             {IntConvClass::B_ConvectiveHeat_VertWalls,       // Vertical, Positive
    4268              :              IntConvClass::B_ConvectiveHeat_VertWalls,       // Vertical, Zero
    4269              :              IntConvClass::B_ConvectiveHeat_VertWalls},      // Vertical, Negative
    4270              :             {IntConvClass::B_ConvectiveHeat_UnstableTilted,  // TiltedUpward, Positive
    4271              :              IntConvClass::B_ConvectiveHeat_StableTilted,    // TiltedUpward, Zero
    4272              :              IntConvClass::B_ConvectiveHeat_StableTilted},   // TiltedUpward, Negative
    4273              :             {IntConvClass::B_ConvectiveHeat_UnstableHoriz,   // HorizontalUp, Positive
    4274              :              IntConvClass::B_ConvectiveHeat_StableHoriz,     // HorizontalUp, Zero
    4275              :              IntConvClass::B_ConvectiveHeat_StableHoriz}     // HorizontalUp, Negative
    4276              :         }};
    4277              : 
    4278              :     static constexpr std::array<std::array<IntConvClass, (int)ConvSurfDeltaT::Num>,
    4279              :                                 (int)SurfOrientation::Num>
    4280              :         D{{
    4281              :             {IntConvClass::D_ZoneFanCirc_StableHoriz,     // HorizontalDown, Positive
    4282              :              IntConvClass::D_ZoneFanCirc_StableHoriz,     // HorizontalDown, Zero
    4283              :              IntConvClass::D_ZoneFanCirc_UnstableHoriz},  // HorizontalDown, Negative
    4284              :             {IntConvClass::D_ZoneFanCirc_StableTilted,    // TiltedDownward, Positive
    4285              :              IntConvClass::D_ZoneFanCirc_StableTilted,    // TiltedDownward, Zero
    4286              :              IntConvClass::D_ZoneFanCirc_UnstableTilted}, // TiltedDownward, Negative
    4287              :             {IntConvClass::D_ZoneFanCirc_Walls,           // Vertical, Positive
    4288              :              IntConvClass::D_ZoneFanCirc_Walls,           // Vertical, Zero
    4289              :              IntConvClass::D_ZoneFanCirc_Walls},          // Vertical, Negative
    4290              :             {IntConvClass::D_ZoneFanCirc_UnstableTilted,  // TiltedUpward, Positive
    4291              :              IntConvClass::D_ZoneFanCirc_StableTilted,    // TiltedUpward, Zero
    4292              :              IntConvClass::D_ZoneFanCirc_StableTilted},   // TiltedUpward, Negative
    4293              :             {IntConvClass::D_ZoneFanCirc_UnstableHoriz,   // HorizontalUp, Positive
    4294              :              IntConvClass::D_ZoneFanCirc_StableHoriz,     // HorizontalUp, Zero
    4295              :              IntConvClass::D_ZoneFanCirc_StableHoriz}     // HorizontalUp, Negative
    4296              :         }};
    4297              : 
    4298           28 :     auto DeltaTempLambda = [](Real64 surfTemp, Real64 airTemp) {
    4299           28 :         Real64 deltaT = surfTemp - airTemp;
    4300           28 :         if (deltaT > 0.0) {
    4301           14 :             return (int)ConvSurfDeltaT::Positive;
    4302           14 :         } else if (deltaT < 0.0) {
    4303           14 :             return (int)ConvSurfDeltaT::Negative;
    4304              :         } else {
    4305            0 :             return (int)ConvSurfDeltaT::Zero;
    4306              :         }
    4307              :     };
    4308              : 
    4309              :     // now finish out specific model eq for this surface
    4310              : 
    4311              :     int iDeltaTemp =
    4312           28 :         DeltaTempLambda(state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfNum), state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).MAT);
    4313           28 :     int iConvOrient = int(surface.convOrientation);
    4314              : 
    4315           28 :     auto &surfIntConv = state.dataSurface->surfIntConv(SurfNum);
    4316           28 :     switch (FinalFlowRegime) {
    4317            0 :     case InConvFlowRegime::A1: {
    4318              : 
    4319            0 :         switch (surface.Class) {
    4320            0 :         case SurfaceClass::Wall:
    4321              :         case SurfaceClass::Door:
    4322              :         case SurfaceClass::IntMass: {
    4323            0 :             surfIntConv.convClass = A1[iConvOrient][iDeltaTemp];
    4324            0 :         } break;
    4325            0 :         case SurfaceClass::Roof: {
    4326            0 :             surfIntConv.convClass = (surfIntConv.hasActiveInIt) ? IntConvClass::A1_FloorHeatCeilCool_ChilledCeil : A1[iConvOrient][iDeltaTemp];
    4327            0 :         } break;
    4328            0 :         case SurfaceClass::Floor: {
    4329            0 :             surfIntConv.convClass = (surfIntConv.hasActiveInIt) ? IntConvClass::A1_FloorHeatCeilCool_HeatedFloor : A1[iConvOrient][iDeltaTemp];
    4330            0 :         } break;
    4331            0 :         case SurfaceClass::Window:
    4332              :         case SurfaceClass::GlassDoor:
    4333              :         case SurfaceClass::TDD_Diffuser: {
    4334            0 :             surfIntConv.convClass = IntConvClass::A1_FloorHeatCeilCool_Windows;
    4335            0 :         } break;
    4336            0 :         default:
    4337            0 :             assert(false);
    4338              :         }
    4339              : 
    4340            0 :         if (surfIntConv.convClass == IntConvClass::Invalid) {
    4341            0 :             ShowSevereError(state, format("DynamicIntConvSurfaceClassification: failed to resolve Hc model for A1 surface named{}", surface.Name));
    4342              :         }
    4343              : 
    4344            0 :     } break; // A1
    4345              : 
    4346            0 :     case InConvFlowRegime::A2: {
    4347              : 
    4348            0 :         switch (surface.Class) {
    4349            0 :         case SurfaceClass::Roof:
    4350              :         case SurfaceClass::Floor:
    4351              :         case SurfaceClass::IntMass: {
    4352            0 :             surfIntConv.convClass = A2[iConvOrient][iDeltaTemp];
    4353            0 :         } break;
    4354            0 :         case SurfaceClass::Wall:
    4355              :         case SurfaceClass::Door: {
    4356            0 :             surfIntConv.convClass = (surfIntConv.hasActiveInIt) ? IntConvClass::A2_WallPanelHeat_HeatedVerticalWall : A2[iConvOrient][iDeltaTemp];
    4357            0 :         } break;
    4358            0 :         case SurfaceClass::Window:
    4359              :         case SurfaceClass::GlassDoor:
    4360              :         case SurfaceClass::TDD_Diffuser: {
    4361            0 :             surfIntConv.convClass = IntConvClass::A2_WallPanelHeat_Windows;
    4362            0 :         } break;
    4363            0 :         default:
    4364            0 :             assert(false);
    4365              :         }
    4366              : 
    4367            0 :         if (surfIntConv.convClass == IntConvClass::Invalid) {
    4368            0 :             ShowSevereError(state, format("DynamicIntConvSurfaceClassification: failed to resolve Hc model for A2 surface named{}", surface.Name));
    4369              :         }
    4370              : 
    4371            0 :     } break; // A2
    4372              : 
    4373           28 :     case InConvFlowRegime::A3: {
    4374              : 
    4375           28 :         switch (surface.Class) {
    4376           28 :         case SurfaceClass::Wall:
    4377              :         case SurfaceClass::Door:
    4378              :         case SurfaceClass::Roof:
    4379              :         case SurfaceClass::Floor: {
    4380           28 :             surfIntConv.convClass = A3[iConvOrient][iDeltaTemp];
    4381           28 :         } break;
    4382            0 :         case SurfaceClass::IntMass: {
    4383              :             // assume horizontal upwards
    4384            0 :             surfIntConv.convClass = A3[int(SurfOrientation::HorizontalUp)][iDeltaTemp];
    4385            0 :         } break;
    4386            0 :         case SurfaceClass::Window:
    4387              :         case SurfaceClass::GlassDoor:
    4388              :         case SurfaceClass::TDD_Diffuser: {
    4389            0 :             surfIntConv.convClass = IntConvClass::A3_SimpleBuoy_Windows;
    4390            0 :         } break;
    4391            0 :         default:
    4392            0 :             assert(false);
    4393              :         }
    4394              : 
    4395           28 :         if (surfIntConv.convClass == IntConvClass::Invalid) {
    4396            0 :             ShowSevereError(state, format("DynamicIntConvSurfaceClassification: failed to resolve Hc model for A3 surface named{}", surface.Name));
    4397              :         }
    4398              : 
    4399           28 :     } break; // A3
    4400              : 
    4401            0 :     case InConvFlowRegime::B: {
    4402              : 
    4403            0 :         switch (surface.Class) {
    4404            0 :         case SurfaceClass::Wall:
    4405              :         case SurfaceClass::Door: {
    4406            0 :             surfIntConv.convClass = (surfIntConv.getsRadiantHeat) ? IntConvClass::B_ConvectiveHeat_VertWallsNearHeat : B[iConvOrient][iDeltaTemp];
    4407            0 :         } break;
    4408            0 :         case SurfaceClass::Roof:
    4409              :         case SurfaceClass::Floor: {
    4410            0 :             surfIntConv.convClass = B[iConvOrient][iDeltaTemp];
    4411            0 :         } break;
    4412            0 :         case SurfaceClass::Window:
    4413              :         case SurfaceClass::GlassDoor:
    4414              :         case SurfaceClass::TDD_Diffuser: {
    4415            0 :             surfIntConv.convClass = IntConvClass::B_ConvectiveHeat_Windows;
    4416            0 :         } break;
    4417            0 :         case SurfaceClass::IntMass: {
    4418              :             // assume horizontal upwards
    4419            0 :             surfIntConv.convClass = B[int(SurfOrientation::HorizontalUp)][iDeltaTemp];
    4420            0 :         } break;
    4421            0 :         default:
    4422            0 :             assert(false);
    4423              :         }
    4424              : 
    4425            0 :         if (surfIntConv.convClass == IntConvClass::Invalid) {
    4426            0 :             ShowSevereError(state, format("DynamicIntConvSurfaceClassification: failed to resolve Hc model for B surface named{}", surface.Name));
    4427              :         }
    4428            0 :     } break; // B
    4429              : 
    4430            0 :     case InConvFlowRegime::C: {
    4431              : 
    4432            0 :         switch (surface.Class) {
    4433            0 :         case SurfaceClass::Wall:
    4434              :         case SurfaceClass::Door: {
    4435            0 :             surfIntConv.convClass = IntConvClass::C_CentralAirHeat_Walls;
    4436            0 :         } break;
    4437            0 :         case SurfaceClass::Roof: {
    4438            0 :             surfIntConv.convClass = IntConvClass::C_CentralAirHeat_Ceiling;
    4439            0 :         } break;
    4440            0 :         case SurfaceClass::Floor: {
    4441            0 :             surfIntConv.convClass = IntConvClass::C_CentralAirHeat_Floor;
    4442            0 :         } break;
    4443            0 :         case SurfaceClass::Window:
    4444              :         case SurfaceClass::GlassDoor:
    4445              :         case SurfaceClass::TDD_Diffuser: {
    4446            0 :             surfIntConv.convClass = IntConvClass::C_CentralAirHeat_Windows;
    4447            0 :         } break;
    4448            0 :         case SurfaceClass::IntMass: {
    4449            0 :             surfIntConv.convClass = IntConvClass::C_CentralAirHeat_Floor;
    4450            0 :         } break;
    4451            0 :         default:
    4452            0 :             assert(false);
    4453              :         }
    4454              : 
    4455            0 :         if (surfIntConv.convClass == IntConvClass::Invalid) {
    4456            0 :             ShowSevereError(state, format("DynamicIntConvSurfaceClassification: failed to resolve Hc model for C surface named{}", surface.Name));
    4457              :         }
    4458              : 
    4459            0 :     } break; // C
    4460              : 
    4461            0 :     case InConvFlowRegime::D: {
    4462              : 
    4463            0 :         switch (surface.Class) {
    4464            0 :         case SurfaceClass::Wall:
    4465              :         case SurfaceClass::Door:
    4466              :         case SurfaceClass::Roof:
    4467              :         case SurfaceClass::Floor: {
    4468            0 :             surfIntConv.convClass = D[iConvOrient][iDeltaTemp];
    4469            0 :         } break;
    4470            0 :         case SurfaceClass::Window:
    4471              :         case SurfaceClass::GlassDoor:
    4472              :         case SurfaceClass::TDD_Diffuser: {
    4473            0 :             surfIntConv.convClass = IntConvClass::D_ZoneFanCirc_Windows;
    4474            0 :         } break;
    4475            0 :         case SurfaceClass::IntMass: {
    4476              :             // assume horizontal upwards.
    4477            0 :             surfIntConv.convClass = D[int(SurfOrientation::HorizontalUp)][iDeltaTemp];
    4478            0 :         } break;
    4479            0 :         default:
    4480            0 :             assert(false);
    4481              :         }
    4482              : 
    4483            0 :         if (surfIntConv.convClass == IntConvClass::Invalid) {
    4484            0 :             ShowSevereError(state, format("DynamicIntConvSurfaceClassification: failed to resolve Hc model for D surface named{}", surface.Name));
    4485              :         }
    4486              : 
    4487            0 :     } break; // D
    4488              : 
    4489            0 :     case InConvFlowRegime::E: {
    4490              :         Real64 deltaTemp =
    4491            0 :             state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfNum) - state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).MAT;
    4492              : 
    4493            0 :         switch (surface.Class) {
    4494            0 :         case SurfaceClass::Wall:
    4495              :         case SurfaceClass::Door: {
    4496            0 :             switch (FlowRegimeStack[PriorityEquipOn]) {
    4497            0 :             case InConvFlowRegime::C: {
    4498              :                 // assume forced flow is down along wall (ceiling diffuser)
    4499            0 :                 surfIntConv.convClass = (deltaTemp > 0.0) ? IntConvClass::E_MixedBuoy_OpposFlowWalls
    4500              :                                                           :                            // surface is hotter so plume upwards and forces oppose
    4501              :                                             IntConvClass::E_MixedBuoy_AssistFlowWalls; // surface is cooler so plume down and forces assist
    4502            0 :             } break;
    4503            0 :             case InConvFlowRegime::D: {
    4504              :                 // assume forced flow is upward along wall (perimeter zone HVAC with fan)
    4505            0 :                 surfIntConv.convClass = (deltaTemp > 0.0) ? IntConvClass::E_MixedBuoy_AssistFlowWalls
    4506              :                                                           :                           // surface is hotter so plume up and forces assist
    4507              :                                             IntConvClass::E_MixedBuoy_OpposFlowWalls; // surface is cooler so plume downward and forces oppose
    4508            0 :             } break;
    4509            0 :             default:
    4510            0 :                 assert(false);
    4511              :             }
    4512              : 
    4513            0 :         } break;
    4514              : 
    4515            0 :         case SurfaceClass::Roof: {
    4516            0 :             surfIntConv.convClass = (deltaTemp > 0.0) ? // surface is hotter so stable
    4517              :                                         IntConvClass::E_MixedBuoy_StableCeiling
    4518              :                                                       : IntConvClass::E_MixedBuoy_UnstableCeiling;
    4519            0 :         } break;
    4520            0 :         case SurfaceClass::Floor: {
    4521            0 :             surfIntConv.convClass = (deltaTemp > 0.0) ? // surface is hotter so unstable
    4522              :                                         IntConvClass::E_MixedBuoy_UnstableFloor
    4523              :                                                       : IntConvClass::E_MixedBuoy_StableFloor;
    4524            0 :         } break;
    4525            0 :         case SurfaceClass::Window: {
    4526              :         case SurfaceClass::GlassDoor:
    4527              :         case SurfaceClass::TDD_Diffuser: {
    4528            0 :             surfIntConv.convClass = IntConvClass::E_MixedBuoy_Windows;
    4529            0 :         } break;
    4530            0 :         case SurfaceClass::IntMass: {
    4531            0 :             surfIntConv.convClass = (deltaTemp > 0.0) ? IntConvClass::E_MixedBuoy_UnstableFloor : IntConvClass::E_MixedBuoy_StableFloor;
    4532            0 :         } break;
    4533            0 :         default:
    4534            0 :             assert(false);
    4535              :         }
    4536              : 
    4537              :             if (surfIntConv.convClass == IntConvClass::Invalid) {
    4538              :                 ShowSevereError(state,
    4539              :                                 format("DynamicIntConvSurfaceClassification: failed to resolve Hc model for E surface named {}", surface.Name));
    4540              :             }
    4541              :         }
    4542            0 :     } break; // E
    4543              : 
    4544            0 :     default:
    4545            0 :         ShowSevereError(state,
    4546            0 :                         format("DynamicIntConvSurfaceClassification: failed to determine zone flow regime for surface named {}", surface.Name));
    4547              :     }
    4548              : 
    4549              :     // Set report var after surface has been classified
    4550           28 :     surfIntConv.convClassRpt = IntConvClassReportVals[(int)surfIntConv.convClass];
    4551           28 : }
    4552              : 
    4553            0 : void MapIntConvClassToHcModels(EnergyPlusData &state, int const SurfNum) // surface pointer index
    4554              : {
    4555              : 
    4556              :     // SUBROUTINE INFORMATION:
    4557              :     //       AUTHOR         Brent Griffith
    4558              :     //       DATE WRITTEN   Aug 2010
    4559              : 
    4560              :     // PURPOSE OF THIS SUBROUTINE:
    4561              :     // Map Hc model equation data from central structure to surface structure
    4562              : 
    4563              :     // METHODOLOGY EMPLOYED:
    4564              :     // Long case statement depends on surface classification determined in DynamicIntConvSurfaceClassification
    4565              :     // then simply map data stored in InsideFaceAdaptiveConvectionAlgo into the surface's structure
    4566              :     // if model type is user-defined, also store the index to the user curve to be used.
    4567              : 
    4568            0 :     auto &surfIntConv = state.dataSurface->surfIntConv(SurfNum);
    4569            0 :     IntConvClass intConvClass = surfIntConv.convClass;
    4570            0 :     assert(intConvClass != IntConvClass::Invalid);
    4571              : 
    4572            0 :     switch (intConvClass) {
    4573              :     // A few cases require special handling
    4574            0 :     case IntConvClass::C_CentralAirHeat_Walls: {
    4575            0 :         if ((surfIntConv.zonePerimLength == 0.0) &&
    4576            0 :             (state.dataConvect->intAdaptiveConvAlgo.intConvClassEqNums[(int)intConvClass] == HcInt::GoldsteinNovoselacCeilingDiffuserWalls)) {
    4577              :             // no perimeter, Goldstein Novolselac model not good so revert to fisher pedersen model
    4578            0 :             surfIntConv.hcModelEq = HcInt::FisherPedersenCeilDiffuserWalls;
    4579            0 :             surfIntConv.hcModelEqRpt = HcIntReportVals[(int)surfIntConv.hcModelEq];
    4580              :         } else {
    4581            0 :             surfIntConv.hcModelEq = state.dataConvect->intAdaptiveConvAlgo.intConvClassEqNums[(int)intConvClass];
    4582            0 :             surfIntConv.hcModelEqRpt = HcIntReportVals[(int)surfIntConv.hcModelEq];
    4583              :         }
    4584            0 :         if (surfIntConv.hcModelEq == HcInt::UserCurve) {
    4585            0 :             surfIntConv.hcUserCurveNum = state.dataConvect->intAdaptiveConvAlgo.intConvClassUserCurveNums[(int)intConvClass];
    4586              :         }
    4587            0 :     } break;
    4588              : 
    4589            0 :     case IntConvClass::C_CentralAirHeat_Floor: {
    4590            0 :         if ((surfIntConv.zonePerimLength == 0.0) &&
    4591            0 :             (state.dataConvect->intAdaptiveConvAlgo.intConvClassEqNums[(int)intConvClass] == HcInt::GoldsteinNovoselacCeilingDiffuserFloor)) {
    4592              :             // no perimeter, Goldstein Novolselac model not good so revert to fisher pedersen model
    4593            0 :             surfIntConv.hcModelEq = HcInt::FisherPedersenCeilDiffuserFloor;
    4594            0 :             surfIntConv.hcModelEqRpt = HcIntReportVals[(int)surfIntConv.hcModelEq];
    4595              :         } else {
    4596            0 :             surfIntConv.hcModelEq = state.dataConvect->intAdaptiveConvAlgo.intConvClassEqNums[(int)intConvClass];
    4597            0 :             surfIntConv.hcModelEqRpt = HcIntReportVals[(int)surfIntConv.hcModelEq];
    4598              :         }
    4599            0 :         if (surfIntConv.hcModelEq == HcInt::UserCurve) {
    4600            0 :             surfIntConv.hcUserCurveNum = state.dataConvect->intAdaptiveConvAlgo.intConvClassUserCurveNums[(int)intConvClass];
    4601              :         }
    4602            0 :     } break;
    4603              : 
    4604            0 :     case IntConvClass::C_CentralAirHeat_Windows: {
    4605            0 :         if ((surfIntConv.zonePerimLength == 0.0) &&
    4606            0 :             (state.dataConvect->intAdaptiveConvAlgo.intConvClassEqNums[(int)intConvClass] == HcInt::GoldsteinNovoselacCeilingDiffuserWindow)) {
    4607              :             // no perimeter, Goldstein Novolselac model not good so revert to ISO15099
    4608            0 :             surfIntConv.hcModelEq = HcInt::ISO15099Windows;
    4609            0 :             surfIntConv.hcModelEqRpt = HcIntReportVals[(int)surfIntConv.hcModelEq];
    4610              :         } else {
    4611            0 :             surfIntConv.hcModelEq = state.dataConvect->intAdaptiveConvAlgo.intConvClassEqNums[(int)intConvClass];
    4612            0 :             surfIntConv.hcModelEqRpt = HcIntReportVals[(int)surfIntConv.hcModelEq];
    4613              :         }
    4614            0 :         if (surfIntConv.hcModelEq == HcInt::UserCurve) {
    4615            0 :             surfIntConv.hcUserCurveNum = state.dataConvect->intAdaptiveConvAlgo.intConvClassUserCurveNums[(int)intConvClass];
    4616              :         }
    4617            0 :     } break;
    4618              : 
    4619            0 :     default: { // Invalid has been asserted above so we can use default here
    4620            0 :         surfIntConv.hcModelEq = state.dataConvect->intAdaptiveConvAlgo.intConvClassEqNums[(int)intConvClass];
    4621            0 :         surfIntConv.hcModelEqRpt = HcIntReportVals[(int)surfIntConv.hcModelEq];
    4622            0 :         if (surfIntConv.hcModelEq == HcInt::UserCurve) {
    4623            0 :             surfIntConv.hcUserCurveNum = state.dataConvect->intAdaptiveConvAlgo.intConvClassUserCurveNums[(int)intConvClass];
    4624              :         }
    4625              :     }
    4626              :     } // switch (intConvClass)
    4627            0 : }
    4628              : 
    4629            0 : Real64 CalcUserDefinedIntHcModel(EnergyPlusData &state, int const SurfNum, int const UserCurveNum)
    4630              : {
    4631              : 
    4632              :     // SUBROUTINE INFORMATION:
    4633              :     //       AUTHOR         Brent Griffith
    4634              :     //       DATE WRITTEN   Aug 2010
    4635              : 
    4636              :     // PURPOSE OF THIS SUBROUTINE:
    4637              :     // calculate user-defined convection correlations for inside face
    4638              : 
    4639              :     // METHODOLOGY EMPLOYED:
    4640              :     // call curve objects to evaluate user's model equation
    4641              :     // prepare independent parameters for x values
    4642              : 
    4643              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4644              :     Real64 tmpAirTemp;
    4645              :     Real64 AirChangeRate;
    4646              : 
    4647            0 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    4648            0 :     int zoneNum = state.dataSurface->Surface(SurfNum).Zone;
    4649            0 :     int spaceNum = state.dataSurface->Surface(SurfNum).spaceNum;
    4650            0 :     auto const &zone = state.dataHeatBal->Zone(zoneNum);
    4651              : 
    4652            0 :     Real64 SumMdotTemp = 0.0;
    4653            0 :     Real64 SumMdot = 0.0;
    4654            0 :     Real64 SupplyAirTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum).MAT;
    4655            0 :     if (zone.IsControlled) {
    4656            0 :         auto const &zoneNode = state.dataLoopNodes->Node(zone.SystemZoneNodeNumber);
    4657            0 :         Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(
    4658            0 :             state, state.dataEnvrn->OutBaroPress, zoneNode.Temp, Psychrometrics::PsyWFnTdpPb(state, zoneNode.Temp, state.dataEnvrn->OutBaroPress));
    4659            0 :         AirChangeRate = (zoneNode.MassFlowRate * Constant::rSecsInHour) / (AirDensity * zone.Volume);
    4660              : 
    4661            0 :         auto const &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(surface.Zone);
    4662            0 :         if (zoneEquipConfig.EquipListIndex > 0) {
    4663            0 :             auto const &zoneEquipList = state.dataZoneEquip->ZoneEquipList(zoneEquipConfig.EquipListIndex);
    4664            0 :             for (int EquipNum = 1; EquipNum <= zoneEquipList.NumOfEquipTypes; ++EquipNum) {
    4665            0 :                 if (!allocated(zoneEquipList.EquipData(EquipNum).OutletNodeNums)) continue;
    4666              : 
    4667            0 :                 int zoneInletNodeNum = zoneEquipList.EquipData(EquipNum).OutletNodeNums(1);
    4668            0 :                 if (zoneInletNodeNum <= 0) continue;
    4669            0 :                 auto const &zoneInletNode = state.dataLoopNodes->Node(zoneInletNodeNum);
    4670            0 :                 if (zoneInletNode.MassFlowRate > 0.0) { // Technically speaking, this check is not necessary since x += 0.0 is x.
    4671            0 :                     SumMdotTemp += zoneInletNode.MassFlowRate * zoneInletNode.Temp;
    4672              :                 }
    4673              :             } // for (EquipNum)
    4674              :         }
    4675            0 :         if (SumMdot > 0.0) {
    4676            0 :             SupplyAirTemp = SumMdotTemp / SumMdot; // mass flow weighted inlet temperature
    4677              :         }
    4678              :     }
    4679              : 
    4680            0 :     auto &userCurve = state.dataConvect->hcIntUserCurve(UserCurveNum);
    4681            0 :     auto const &surfIntConv = state.dataSurface->surfIntConv(SurfNum);
    4682              : 
    4683            0 :     switch (userCurve.refTempType) {
    4684            0 :     case RefTemp::MeanAirTemp:
    4685            0 :         tmpAirTemp = state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).MAT;
    4686            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneMeanAirTemp;
    4687            0 :         break;
    4688            0 :     case RefTemp::AdjacentAirTemp:
    4689            0 :         tmpAirTemp = state.dataHeatBal->SurfTempEffBulkAir(SurfNum);
    4690            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
    4691            0 :         break;
    4692            0 :     case RefTemp::SupplyAirTemp:
    4693            0 :         tmpAirTemp = SupplyAirTemp;
    4694            0 :         state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::ZoneSupplyAirTemp;
    4695            0 :         break;
    4696            0 :     default:
    4697            0 :         assert(false);
    4698              :     }
    4699              : 
    4700            0 :     state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
    4701              : 
    4702            0 :     Real64 HcFnTempDiff(0.0), HcFnTempDiffDivHeight(0.0), HcFnACH(0.0), HcFnACHDivPerimLength(0.0);
    4703            0 :     Kiva::ConvectionAlgorithm HcFnTempDiffFn(KIVA_CONST_CONV(0.0)), HcFnTempDiffDivHeightFn(KIVA_CONST_CONV(0.0));
    4704            0 :     if (userCurve.hcFnTempDiffCurveNum > 0) {
    4705              :         HcFnTempDiff =
    4706            0 :             Curve::CurveValue(state, userCurve.hcFnTempDiffCurveNum, std::abs(state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfNum) - tmpAirTemp));
    4707            0 :         HcFnTempDiffFn = [&](double Tsurf, double Tamb, double, double, double) -> double {
    4708            0 :             return Curve::CurveValue(state, userCurve.hcFnTempDiffCurveNum, std::abs(Tsurf - Tamb));
    4709            0 :         };
    4710              :     }
    4711              : 
    4712            0 :     if (userCurve.hcFnTempDiffDivHeightCurveNum > 0) {
    4713              :         HcFnTempDiffDivHeight =
    4714            0 :             Curve::CurveValue(state,
    4715              :                               userCurve.hcFnTempDiffDivHeightCurveNum,
    4716            0 :                               (std::abs(state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfNum) - tmpAirTemp) / surfIntConv.zoneWallHeight));
    4717            0 :         HcFnTempDiffDivHeightFn = [=, &state](double Tsurf, double Tamb, double, double, double) -> double {
    4718            0 :             return Curve::CurveValue(state, userCurve.hcFnTempDiffDivHeightCurveNum, std::abs(Tsurf - Tamb) / surfIntConv.zoneWallHeight);
    4719            0 :         };
    4720              :     }
    4721              : 
    4722            0 :     if (userCurve.hcFnACHCurveNum > 0) {
    4723            0 :         HcFnACH = Curve::CurveValue(state, userCurve.hcFnACHCurveNum, AirChangeRate);
    4724              :     }
    4725              : 
    4726            0 :     if (userCurve.hcFnACHDivPerimLengthCurveNum > 0) {
    4727            0 :         HcFnACHDivPerimLength = Curve::CurveValue(state, userCurve.hcFnACHDivPerimLengthCurveNum, (AirChangeRate / surfIntConv.zonePerimLength));
    4728              :     }
    4729              : 
    4730            0 :     if (state.dataSurface->Surface(SurfNum).ExtBoundCond == DataSurfaces::KivaFoundation) {
    4731            0 :         state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].in =
    4732            0 :             [=](double Tsurf, double Tamb, double HfTerm, double Roughness, double CosTilt) -> double {
    4733            0 :             return HcFnTempDiffFn(Tsurf, Tamb, HfTerm, Roughness, CosTilt) + HcFnTempDiffDivHeightFn(Tsurf, Tamb, HfTerm, Roughness, CosTilt) +
    4734            0 :                    HcFnACH + HcFnACHDivPerimLength;
    4735            0 :         };
    4736            0 :         return 0.0;
    4737              :     } else {
    4738            0 :         return HcFnTempDiff + HcFnTempDiffDivHeight + HcFnACH + HcFnACHDivPerimLength;
    4739              :     }
    4740              : }
    4741              : 
    4742            0 : Real64 CalcUserDefinedExtHcModel(EnergyPlusData &state, int const SurfNum, int const UserCurveNum)
    4743              : {
    4744              : 
    4745              :     // SUBROUTINE INFORMATION:
    4746              :     //       AUTHOR         Brent Griffith
    4747              :     //       DATE WRITTEN   Aug 2010
    4748              : 
    4749              :     // PURPOSE OF THIS SUBROUTINE:
    4750              :     // calculate user-defined convection correlations for outside face
    4751              : 
    4752              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4753              :     Real64 windVel;
    4754              :     Real64 Theta;
    4755              :     Real64 ThetaRad;
    4756              : 
    4757            0 :     auto &userCurve = state.dataConvect->hcExtUserCurve(UserCurveNum);
    4758            0 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    4759              : 
    4760            0 :     switch (userCurve.windSpeedType) {
    4761            0 :     case RefWind::WeatherFile:
    4762            0 :         windVel = state.dataEnvrn->WindSpeed;
    4763            0 :         break;
    4764            0 :     case RefWind::AtZ:
    4765            0 :         windVel = state.dataSurface->SurfOutWindSpeed(SurfNum);
    4766            0 :         break;
    4767            0 :     case RefWind::ParallelComp:
    4768              :         // WindSpeed , WindDir, surface Azimuth
    4769            0 :         Theta = CalcWindSurfaceTheta(state.dataEnvrn->WindDir, surface.Azimuth);
    4770            0 :         ThetaRad = Theta * Constant::DegToRad;
    4771            0 :         break;
    4772            0 :     case RefWind::ParallelCompAtZ:
    4773              :         // Surface WindSpeed , Surface WindDir, surface Azimuth
    4774            0 :         Theta = CalcWindSurfaceTheta(state.dataSurface->SurfOutWindDir(SurfNum), surface.Azimuth);
    4775            0 :         ThetaRad = Theta * Constant::DegToRad;
    4776            0 :         windVel = std::cos(ThetaRad) * state.dataSurface->SurfOutWindSpeed(SurfNum);
    4777            0 :         break;
    4778            0 :     default:
    4779            0 :         assert(false);
    4780              :     }
    4781              : 
    4782            0 :     Kiva::ForcedConvectionTerm HfFnWindSpeedFn(KIVA_HF_DEF);
    4783            0 :     Kiva::ConvectionAlgorithm HnFnTempDiffFn(KIVA_CONST_CONV(0.0)), HnFnTempDiffDivHeightFn(KIVA_CONST_CONV(0.0));
    4784              : 
    4785            0 :     Real64 HfFnWindSpeed(0.0), HnFnTempDiff(0.0), HnFnTempDiffDivHeight(0.0);
    4786              : 
    4787            0 :     if (userCurve.hfFnWindSpeedCurveNum > 0) {
    4788            0 :         HfFnWindSpeed = Curve::CurveValue(state, userCurve.hfFnWindSpeedCurveNum, windVel);
    4789            0 :         HfFnWindSpeedFn = [&](double, double, double, double windSpeed) -> double {
    4790            0 :             return Curve::CurveValue(state, userCurve.hfFnWindSpeedCurveNum, windSpeed);
    4791            0 :         };
    4792              :     }
    4793              : 
    4794            0 :     auto const &surfExtConv = state.dataSurface->surfExtConv(SurfNum);
    4795              : 
    4796            0 :     Real64 surfDeltaTemp = std::abs(state.dataHeatBalSurf->SurfInsideTempHist(1)(SurfNum) - state.dataSurface->SurfOutDryBulbTemp(SurfNum));
    4797            0 :     if (userCurve.hnFnTempDiffCurveNum > 0) {
    4798            0 :         HnFnTempDiff = Curve::CurveValue(state, userCurve.hnFnTempDiffCurveNum, surfDeltaTemp);
    4799            0 :         HnFnTempDiffFn = [&](double Tsurf, double Tamb, double, double, double) -> double {
    4800            0 :             return Curve::CurveValue(state, userCurve.hnFnTempDiffCurveNum, std::abs(Tsurf - Tamb));
    4801            0 :         };
    4802              :     }
    4803              : 
    4804            0 :     if (userCurve.hnFnTempDiffDivHeightCurveNum > 0) {
    4805            0 :         if (surfExtConv.faceHeight > 0.0) {
    4806            0 :             HnFnTempDiffDivHeight = Curve::CurveValue(state, userCurve.hnFnTempDiffDivHeightCurveNum, surfDeltaTemp / surfExtConv.faceHeight);
    4807            0 :             HnFnTempDiffDivHeightFn = [=, &state](double Tsurf, double Tamb, double, double, double) -> double {
    4808            0 :                 return Curve::CurveValue(state, userCurve.hnFnTempDiffDivHeightCurveNum, (std::abs(Tsurf - Tamb) / surfExtConv.faceHeight));
    4809            0 :             };
    4810              :         }
    4811              :     }
    4812              : 
    4813            0 :     if (surface.ExtBoundCond == DataSurfaces::KivaFoundation) {
    4814            0 :         state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].f = HfFnWindSpeedFn;
    4815            0 :         state.dataSurfaceGeometry->kivaManager.surfaceConvMap[SurfNum].out =
    4816            0 :             [=](double Tsurf, double Tamb, double HfTerm, double Roughness, double CosTilt) -> double {
    4817            0 :             return HnFnTempDiffFn(Tsurf, Tamb, HfTerm, Roughness, CosTilt) + HnFnTempDiffDivHeightFn(Tsurf, Tamb, HfTerm, Roughness, CosTilt) +
    4818            0 :                    HfTerm;
    4819            0 :         };
    4820              :     }
    4821            0 :     return HfFnWindSpeed + HnFnTempDiff + HnFnTempDiffDivHeight;
    4822              : }
    4823              : 
    4824              : //** Begin catalog of Hc equation functions. **** !*************************************************
    4825              : 
    4826            5 : Real64 CalcFisherPedersenCeilDiffuserFloor(EnergyPlusData &state,
    4827              :                                            Real64 const ACH, // [1/hr] air system air change rate
    4828              :                                            Real64 const Tsurf,
    4829              :                                            Real64 const Tair,
    4830              :                                            Real64 const cosTilt,
    4831              :                                            Real64 const humRat,
    4832              :                                            Real64 const height,
    4833              :                                            bool const isWindow)
    4834              : {
    4835              : 
    4836              :     // AUTHOR: Brent Griffith (Aug 2010)
    4837              :     // PURPOSE OF THIS FUNCTION: Calculate the model equation by Fisher and Pedersen for floors with ceiling diffusers
    4838              :     // REFERENCE: Fisher, D.E. and C.O. Pedersen, Convective Heat Transfer in Building Energy and Thermal Load Calculations,
    4839              :     //            ASHRAE Transactions, vol. 103, Pt. 2, 1997, p.13
    4840              : 
    4841            5 :     if (ACH >= 3.0) {
    4842            2 :         return 3.873 + 0.082 * std::pow(ACH, 0.98);
    4843              :     } else {                               // Revert to purely natural convection
    4844            3 :         Real64 Hforced = 4.11365377688938; // Value of Hforced when ACH=3
    4845            3 :         return CalcFisherPedersenCeilDiffuserNatConv(state, Hforced, ACH, Tsurf, Tair, cosTilt, humRat, height, isWindow);
    4846              :     }
    4847              : }
    4848              : 
    4849            5 : Real64 CalcFisherPedersenCeilDiffuserCeiling(EnergyPlusData &state,
    4850              :                                              Real64 const ACH, // [1/hr] air system air change rate
    4851              :                                              Real64 const Tsurf,
    4852              :                                              Real64 const Tair,
    4853              :                                              Real64 const cosTilt,
    4854              :                                              Real64 const humRat,
    4855              :                                              Real64 const height,
    4856              :                                              bool const isWindow)
    4857              : {
    4858              : 
    4859              :     // AUTHOR: Brent Griffith (Aug 2010)
    4860              :     // PURPOSE OF THIS FUNCTION: Calculate the model equation by Fisher and Pedersen for floors with ceiling diffusers
    4861              :     // REFERENCE: Fisher, D.E. and C.O. Pedersen, Convective Heat Transfer in Building Energy and Thermal Load Calculations,
    4862              :     //            ASHRAE Transactions, vol. 103, Pt. 2, 1997, p.13
    4863              : 
    4864            5 :     if (ACH >= 3.0) {
    4865            2 :         return 2.234 + 4.099 * std::pow(ACH, 0.503);
    4866              :     } else {                               // Revert to purely natural convection
    4867            3 :         Real64 Hforced = 9.35711423763866; // Value of Hforced when ACH=3
    4868            3 :         return CalcFisherPedersenCeilDiffuserNatConv(state, Hforced, ACH, Tsurf, Tair, cosTilt, humRat, height, isWindow);
    4869              :     }
    4870              : }
    4871              : 
    4872            5 : Real64 CalcFisherPedersenCeilDiffuserWalls(EnergyPlusData &state,
    4873              :                                            Real64 const ACH, // [1/hr] air system air change rate
    4874              :                                            Real64 const Tsurf,
    4875              :                                            Real64 const Tair,
    4876              :                                            Real64 const cosTilt,
    4877              :                                            Real64 const humRat,
    4878              :                                            Real64 const height,
    4879              :                                            bool const isWindow)
    4880              : {
    4881              : 
    4882              :     // AUTHOR: Brent Griffith (Aug 2010)
    4883              :     // PURPOSE OF THIS FUNCTION: Calculate the model equation by Fisher and Pedersen for floors with ceiling diffusers
    4884              :     // REFERENCE: Fisher, D.E. and C.O. Pedersen, Convective Heat Transfer in Building Energy and Thermal Load Calculations,
    4885              :     //            ASHRAE Transactions, vol. 103, Pt. 2, 1997, p.13
    4886              : 
    4887            5 :     if (ACH >= 3.0) {
    4888            2 :         return 1.208 + 1.012 * std::pow(ACH, 0.604);
    4889              :     } else {                               // Revert to purely natural convection
    4890            3 :         Real64 Hforced = 3.17299636062606; // Value of Hforced when ACH=3
    4891            3 :         return CalcFisherPedersenCeilDiffuserNatConv(state, Hforced, ACH, Tsurf, Tair, cosTilt, humRat, height, isWindow);
    4892              :     }
    4893              : }
    4894              : 
    4895           14 : Real64 CalcFisherPedersenCeilDiffuserNatConv(EnergyPlusData &state,
    4896              :                                              Real64 const Hforced,
    4897              :                                              Real64 const ACH,
    4898              :                                              Real64 const Tsurf,
    4899              :                                              Real64 const Tair,
    4900              :                                              Real64 const cosTilt,
    4901              :                                              Real64 const humRat,
    4902              :                                              Real64 const height,
    4903              :                                              bool const isWindow)
    4904              : {
    4905              : 
    4906              :     Real64 Hnatural;
    4907              : 
    4908           14 :     if (isWindow) {                        // Unlikely for a floor, but okay...
    4909            1 :         Real64 const tilt = acos(cosTilt); // outward facing tilt
    4910            1 :         Real64 const sinTilt = sin(tilt);
    4911            1 :         Hnatural = CalcISO15099WindowIntConvCoeff(state, Tsurf, Tair, humRat, height, tilt, sinTilt);
    4912              :     } else {
    4913           13 :         Hnatural = CalcASHRAETARPNatural(Tsurf, Tair, -cosTilt); // negative cosTilt because interior of surface
    4914              :     }
    4915           14 :     if (ACH <= 0.5) {
    4916            9 :         return Hnatural;
    4917              :     } else {
    4918            5 :         return Hnatural + ((Hforced - Hnatural) * ((ACH - 0.5) / 2.5)); // range for interpolation goes from ACH=0.5 to ACH=3.0 or a range of 2.5
    4919              :     }
    4920              : }
    4921              : 
    4922            0 : Real64 CalcAlamdariHammondUnstableHorizontal(Real64 const DeltaTemp,        // [C] temperature difference between surface and air
    4923              :                                              Real64 const HydraulicDiameter // [m] characteristic size, = (4 * area) / perimeter
    4924              : )
    4925              : {
    4926              : 
    4927              :     // FUNCTION INFORMATION:
    4928              :     //       AUTHOR         Brent Griffith
    4929              :     //       DATE WRITTEN   Jul 2010
    4930              : 
    4931              :     // PURPOSE OF THIS FUNCTION:
    4932              :     // Calculate model equation for Alamdari and Hammond
    4933              :     // This function only for the Unstable heat flow direction for horizontal surfaces
    4934              : 
    4935              :     // REFERENCES:
    4936              :     // Alamdari, F. and G.P. Hammond. 1983. Improved data correlations
    4937              :     // for buoyancy-driven convection in rooms.  Building Services Engineering
    4938              :     // Research & Technology. Vol. 4, No. 3.
    4939              : 
    4940            0 :     return std::pow(pow_6(1.4 * std::pow(std::abs(DeltaTemp) / HydraulicDiameter, 0.25)) + (1.63 * pow_2(DeltaTemp)),
    4941            0 :                     1.0 / 6.0); // Tuned pow_6( std::pow( std::abs( DeltaTemp ), 1.0/3.0 ) ) changed to pow_2( DeltaTemp )
    4942              : }
    4943              : 
    4944            0 : Real64 CalcAlamdariHammondUnstableHorizontal(EnergyPlusData &state,
    4945              :                                              Real64 const DeltaTemp,         // [C] temperature difference between surface and air
    4946              :                                              Real64 const HydraulicDiameter, // [m] characteristic size, = (4 * area) / perimeter
    4947              :                                              int const SurfNum               // for messages
    4948              : )
    4949              : {
    4950            0 :     std::string_view constexpr routineName = "CalcAlamdariHammondUnstableHorizontal";
    4951            0 :     if (HydraulicDiameter > 0.0) {
    4952            0 :         return CalcAlamdariHammondUnstableHorizontal(DeltaTemp, HydraulicDiameter);
    4953              :     } else {
    4954            0 :         ErrorObjectHeader eoh{routineName, "Surface", state.dataSurface->Surface(SurfNum).Name};
    4955            0 :         ShowWarningHydraulicDiameterZero(state, state.dataConvect->AHUnstableHorizontalErrorIDX, eoh);
    4956            0 :         return 9.999;
    4957              :     }
    4958              : }
    4959              : 
    4960            0 : Real64 CalcAlamdariHammondStableHorizontal(Real64 const DeltaTemp,        // [C] temperature difference between surface and air
    4961              :                                            Real64 const HydraulicDiameter // [m] characteristic size, = (4 * area) / perimeter
    4962              : )
    4963              : {
    4964              : 
    4965              :     // FUNCTION INFORMATION:
    4966              :     //       AUTHOR         Brent Griffith
    4967              :     //       DATE WRITTEN   Jul 2010
    4968              : 
    4969              :     // PURPOSE OF THIS FUNCTION:
    4970              :     // Calculate model equation for Alamdari and Hammond
    4971              :     // This function only for the Stable heat flow direction for horizontal surfaces
    4972              : 
    4973              :     // REFERENCES:
    4974              :     // Alamdari, F. and G.P. Hammond. 1983. Improved data correlations
    4975              :     // for buoyancy-driven convection in rooms.  Building Services Engineering
    4976              :     // Research & Technology. Vol. 4, No. 3.
    4977              : 
    4978            0 :     return 0.6 * std::pow(std::abs(DeltaTemp) / pow_2(HydraulicDiameter), 0.2);
    4979              : }
    4980              : 
    4981            0 : Real64 CalcAlamdariHammondStableHorizontal(EnergyPlusData &state,
    4982              :                                            Real64 const DeltaTemp,         // [C] temperature difference between surface and air
    4983              :                                            Real64 const HydraulicDiameter, // [m] characteristic size, = (4 * area) / perimeter
    4984              :                                            int const SurfNum               // for messages
    4985              : )
    4986              : {
    4987            0 :     std::string_view constexpr routineName = "CalcAlamdariHammondStableHorizontal";
    4988            0 :     if (HydraulicDiameter > 0.0) {
    4989            0 :         return CalcAlamdariHammondStableHorizontal(DeltaTemp, HydraulicDiameter);
    4990              :     } else {
    4991            0 :         ErrorObjectHeader eoh{routineName, "Surface", state.dataSurface->Surface(SurfNum).Name};
    4992            0 :         ShowWarningHydraulicDiameterZero(state, state.dataConvect->AHStableHorizontalErrorIDX, eoh);
    4993            0 :         if (DeltaTemp == 0.0 && !state.dataGlobal->WarmupFlag) {
    4994            0 :             ShowWarningDeltaTempZero(state, state.dataConvect->BMMixedAssistedWallErrorIDX1, eoh);
    4995              :         }
    4996            0 :         return 9.999;
    4997              :     }
    4998              : }
    4999              : 
    5000            0 : Real64 CalcAlamdariHammondVerticalWall(Real64 const DeltaTemp, // [C] temperature difference between surface and air
    5001              :                                        Real64 const Height)
    5002              : {
    5003              : 
    5004              :     // FUNCTION INFORMATION:
    5005              :     //       AUTHOR         Brent Griffith
    5006              :     //       DATE WRITTEN   Jul 2010
    5007              : 
    5008              :     // PURPOSE OF THIS FUNCTION:
    5009              :     // Calculate model equation for Alamdari and Hammond
    5010              :     // This function only for the vertical wall surfaces
    5011              : 
    5012              :     // METHODOLOGY EMPLOYED:
    5013              :     // isolate function for equation.
    5014              : 
    5015              :     // REFERENCES:
    5016              :     // Alamdari, F. and G.P. Hammond. 1983. Improved data correlations
    5017              :     // for buoyancy-driven convection in rooms.  Building Services Engineering
    5018              :     // Research & Technology. Vol. 4, No. 3.
    5019              : 
    5020            0 :     return std::pow(pow_6(1.5 * std::pow(std::abs(DeltaTemp) / Height, 0.25)) + (1.23 * pow_2(DeltaTemp)),
    5021            0 :                     1.0 / 6.0); // Tuned pow_6( std::pow( std::abs( DeltaTemp ), 1.0/3.0 ) ) changed to pow_2( DeltaTemp )
    5022              : }
    5023              : 
    5024            0 : Real64 CalcAlamdariHammondVerticalWall(EnergyPlusData &state,
    5025              :                                        Real64 const DeltaTemp, // [C] temperature difference between surface and air
    5026              :                                        Real64 const Height,    // [m] characteristic size, = zone height
    5027              :                                        int const SurfNum       // for messages
    5028              : )
    5029              : {
    5030            0 :     std::string_view constexpr routineName = "CalcAlamdariHammondVerticalWall";
    5031              : 
    5032            0 :     if (Height > 0.0) {
    5033            0 :         return CalcAlamdariHammondVerticalWall(DeltaTemp, Height);
    5034              :     } else {
    5035            0 :         ErrorObjectHeader eoh{routineName, "Surface", state.dataSurface->Surface(SurfNum).Name};
    5036            0 :         ShowWarningHydraulicDiameterZero(state, state.dataConvect->AHVerticalWallErrorIDX, eoh);
    5037            0 :         return 9.999;
    5038              :     }
    5039              : }
    5040              : 
    5041            0 : Real64 CalcKhalifaEq3WallAwayFromHeat(Real64 const DeltaTemp) // [C] temperature difference between surface and air
    5042              : {
    5043              : 
    5044              :     // FUNCTION INFORMATION:
    5045              :     //       AUTHOR         Brent Griffith
    5046              :     //       DATE WRITTEN   Jul 2010
    5047              : 
    5048              :     // PURPOSE OF THIS FUNCTION:
    5049              :     // Calculate model equation for Khalifa's Eq 3 for Walls Away From Heat
    5050              : 
    5051              :     // METHODOLOGY EMPLOYED:
    5052              :     // isolate function for equation.
    5053              : 
    5054              :     // REFERENCES:
    5055              :     // Khalifa AJN. 1989 Heat transfer processes in buildings. Ph.D. Thesis,
    5056              :     //   University of Wales College of Cardiff, Cardiff, UK.
    5057              :     // Equations actually from Beausoleil-Morrison 2000 who referenced Khalifa
    5058              :     // Beausoleil-Morrison, I. 2000. The adaptive coupling of heat and
    5059              :     //  air flow modeling within dynamic whole-building simulations.
    5060              :     //  PhD. Thesis. University of Strathclyde, Glasgow, UK.
    5061              : 
    5062            0 :     return 2.07 * std::pow(std::abs(DeltaTemp), 0.23);
    5063              : }
    5064              : 
    5065            0 : Real64 CalcKhalifaEq4CeilingAwayFromHeat(Real64 const DeltaTemp) // [C] temperature difference between surface and air
    5066              : {
    5067              : 
    5068              :     // FUNCTION INFORMATION:
    5069              :     //       AUTHOR         Brent Griffith
    5070              :     //       DATE WRITTEN   Jul 2010
    5071              : 
    5072              :     // PURPOSE OF THIS FUNCTION:
    5073              :     // Calculate model equation for Khalifa's Eq 4 for Ceilings Away From Heat
    5074              : 
    5075              :     // REFERENCES:
    5076              :     // Khalifa AJN. 1989 Heat transfer processes in buildings. Ph.D. Thesis,
    5077              :     //   University of Wales College of Cardiff, Cardiff, UK.
    5078              :     // Equations actually from Beausoleil-Morrison 2000 who referenced Khalifa
    5079              :     // Beausoleil-Morrison, I. 2000. The adaptive coupling of heat and
    5080              :     //  air flow modeling within dynamic whole-building simulations.
    5081              :     //  PhD. Thesis. University of Strathclyde, Glasgow, UK.
    5082              : 
    5083            0 :     return 2.72 * std::pow(std::abs(DeltaTemp), 0.13);
    5084              : }
    5085              : 
    5086            0 : Real64 CalcKhalifaEq5WallsNearHeat(Real64 const DeltaTemp) // [C] temperature difference between surface and air
    5087              : {
    5088              : 
    5089              :     // FUNCTION INFORMATION:
    5090              :     //       AUTHOR         Brent Griffith
    5091              :     //       DATE WRITTEN   Jul 2010
    5092              : 
    5093              :     // PURPOSE OF THIS FUNCTION:
    5094              :     // Calculate model equation for Khalifa's Eq 5 for Walls near the heater
    5095              : 
    5096              :     // REFERENCES:
    5097              :     // Khalifa AJN. 1989 Heat transfer processes in buildings. Ph.D. Thesis,
    5098              :     //   University of Wales College of Cardiff, Cardiff, UK.
    5099              :     // Equations actually from Beausoleil-Morrison 2000 who referenced Khalifa
    5100              :     // Beausoleil-Morrison, I. 2000. The adaptive coupling of heat and
    5101              :     //  air flow modeling within dynamic whole-building simulations.
    5102              :     //  PhD. Thesis. University of Strathclyde, Glasgow, UK.
    5103              : 
    5104            0 :     return 1.98 * std::pow(std::abs(DeltaTemp), 0.32);
    5105              : }
    5106              : 
    5107            0 : Real64 CalcKhalifaEq6NonHeatedWalls(Real64 const DeltaTemp) // [C] temperature difference between surface and air
    5108              : {
    5109              : 
    5110              :     // FUNCTION INFORMATION:
    5111              :     //       AUTHOR         Brent Griffith
    5112              :     //       DATE WRITTEN   Jul 2010
    5113              : 
    5114              :     // PURPOSE OF THIS FUNCTION:
    5115              :     // Calculate model equation for Khalifa's Eq 6 for non-heated walls
    5116              : 
    5117              :     // REFERENCES:
    5118              :     // Khalifa AJN. 1989 Heat transfer processes in buildings. Ph.D. Thesis,
    5119              :     //   University of Wales College of Cardiff, Cardiff, UK.
    5120              :     // Equations actually from Beausoleil-Morrison 2000 who referenced Khalifa
    5121              :     // Beausoleil-Morrison, I. 2000. The adaptive coupling of heat and
    5122              :     //  air flow modeling within dynamic whole-building simulations.
    5123              :     //  PhD. Thesis. University of Strathclyde, Glasgow, UK.
    5124              : 
    5125            0 :     return 2.30 * std::pow(std::abs(DeltaTemp), 0.24);
    5126              : }
    5127              : 
    5128            0 : Real64 CalcKhalifaEq7Ceiling(Real64 const DeltaTemp) // [C] temperature difference between surface and air
    5129              : {
    5130              : 
    5131              :     // FUNCTION INFORMATION:
    5132              :     //       AUTHOR         Brent Griffith
    5133              :     //       DATE WRITTEN   Jul 2010
    5134              : 
    5135              :     // PURPOSE OF THIS FUNCTION:
    5136              :     // Calculate model equation for Khalifa's Eq 7 for ceilings
    5137              : 
    5138              :     // REFERENCES:
    5139              :     // Khalifa AJN. 1989 Heat transfer processes in buildings. Ph.D. Thesis,
    5140              :     //   University of Wales College of Cardiff, Cardiff, UK.
    5141              :     // Equations actually from Beausoleil-Morrison 2000 who referenced Khalifa
    5142              :     // Beausoleil-Morrison, I. 2000. The adaptive coupling of heat and
    5143              :     //  air flow modeling within dynamic whole-building simulations.
    5144              :     //  PhD. Thesis. University of Strathclyde, Glasgow, UK.
    5145              : 
    5146            0 :     return 3.10 * std::pow(std::abs(DeltaTemp), 0.17);
    5147              : }
    5148              : 
    5149            0 : Real64 CalcAwbiHattonHeatedFloor(Real64 const DeltaTemp,        // [C] temperature difference between surface and air
    5150              :                                  Real64 const HydraulicDiameter // [m] characteristic size, = (4 * area) / perimeter
    5151              : )
    5152              : {
    5153              : 
    5154              :     // FUNCTION INFORMATION:
    5155              :     //       AUTHOR         Brent Griffith
    5156              :     //       DATE WRITTEN   Jul 2010
    5157              : 
    5158              :     // PURPOSE OF THIS FUNCTION:
    5159              :     // Calculate model equation for Awbi and Hatton for heated floors
    5160              : 
    5161              :     // METHODOLOGY EMPLOYED:
    5162              :     // apply numerical protection for low values of hydraulic diameter
    5163              : 
    5164              :     // REFERENCES:
    5165              :     // Awbi, H.B. and A. Hatton. 1999. Natural convection from heated room surfaces.
    5166              :     //   Energy and Buildings 30 (1999) 233-244.
    5167              :     //   This function is for equation 15 in the reference
    5168              : 
    5169            0 :     if (HydraulicDiameter > 1.0) {
    5170            0 :         return 2.175 * std::pow(std::abs(DeltaTemp), 0.308) / std::pow(HydraulicDiameter, 0.076);
    5171              :     } else {
    5172            0 :         Real64 const pow_fac(2.175 / std::pow(1.0, 0.076));
    5173            0 :         return pow_fac * std::pow(std::abs(DeltaTemp), 0.308);
    5174              :     }
    5175              : }
    5176              : 
    5177            0 : Real64 CalcAwbiHattonHeatedWall(Real64 const DeltaTemp,        // [C] temperature difference between surface and air
    5178              :                                 Real64 const HydraulicDiameter // [m] characteristic size, = (4 * area) / perimeter
    5179              : )
    5180              : {
    5181              : 
    5182              :     // FUNCTION INFORMATION:
    5183              :     //       AUTHOR         Brent Griffith
    5184              :     //       DATE WRITTEN   Jul 2010
    5185              : 
    5186              :     // PURPOSE OF THIS FUNCTION:
    5187              :     // Calculate model equation for Awbi and Hatton for heated walls
    5188              : 
    5189              :     // REFERENCES:
    5190              :     // Awbi, H.B. and A. Hatton. 1999. Natural convection from heated room surfaces.
    5191              :     //   Energy and Buildings 30 (1999) 233-244.
    5192              :     //   This function is for equation 12 in the reference
    5193              : 
    5194            0 :     return 1.823 * std::pow(std::abs(DeltaTemp), 0.293) / std::pow(max(HydraulicDiameter, 1.0), 0.121);
    5195              : }
    5196              : 
    5197            2 : Real64 CalcBeausoleilMorrisonMixedAssistedWall(Real64 const DeltaTemp,     // [C] temperature difference between surface and air
    5198              :                                                Real64 const Height,        // [m] characteristic size
    5199              :                                                Real64 const SurfTemp,      // [C] surface temperature
    5200              :                                                Real64 const SupplyAirTemp, // [C] temperature of supply air into zone
    5201              :                                                Real64 const AirChangeRate  // [ACH] [1/hour] supply air ACH for zone
    5202              : )
    5203              : {
    5204              : 
    5205              :     // FUNCTION INFORMATION:
    5206              :     //       AUTHOR         Brent Griffith
    5207              :     //       DATE WRITTEN   Jul 2010
    5208              : 
    5209              :     // PURPOSE OF THIS FUNCTION:
    5210              :     // Calculate model equation Beausoleil-Morrison's mixed flow regime
    5211              :     // with mechanical and buoyancy forces assisting each other along a Wall
    5212              : 
    5213              :     // REFERENCES:
    5214              :     // Beausoleil-Morrison, I. 2000. The adaptive coupling of heat and
    5215              :     //  air flow modeling within dynamic whole-building simulations.
    5216              :     //  PhD. Thesis. University of Strathclyde, Glasgow, UK.
    5217              : 
    5218              :     Real64 cofpow =
    5219            2 :         std::sqrt(pow_6(1.5 * std::pow(std::abs(DeltaTemp) / Height, 0.25)) + std::pow(1.23 * pow_2(DeltaTemp), 1.0 / 6.0)) +
    5220            2 :         pow_3(((SurfTemp - SupplyAirTemp) / std::abs(DeltaTemp)) *
    5221            2 :               (-0.199 + 0.190 * std::pow(AirChangeRate,
    5222            2 :                                          0.8))); // Tuned pow_6( std::pow( std::abs( DeltaTemp ), 1.0/3.0 ) ) changed to pow_2( DeltaTemp )
    5223            2 :     Real64 Hc = std::pow(std::abs(cofpow),
    5224              :                          1.0 / 3.0); // Tuned pow_6( std::pow( std::abs( DeltaTemp ), 1.0/3.0 ) ) changed to pow_2( DeltaTemp )
    5225            2 :     if (cofpow < 0.0) {
    5226            1 :         Hc = -Hc;
    5227              :     }
    5228            2 :     return Hc;
    5229              : }
    5230              : 
    5231            3 : Real64 CalcBeausoleilMorrisonMixedAssistedWall(EnergyPlusData &state,
    5232              :                                                Real64 const DeltaTemp, // [C] temperature difference between surface and air
    5233              :                                                Real64 const Height,    // [m] characteristic size
    5234              :                                                Real64 const SurfTemp,  // [C] surface temperature
    5235              :                                                int const ZoneNum       // index of zone for messaging
    5236              : )
    5237              : {
    5238            3 :     std::string_view constexpr routineName = "CalcBeausoleilMorrisonMixedAssistedWall";
    5239              : 
    5240            3 :     if ((std::abs(DeltaTemp) > HVAC::SmallTempDiff) && (Height != 0.0)) {
    5241            1 :         Real64 SupplyAirTemp = CalcZoneSupplyAirTemp(state, ZoneNum);
    5242            1 :         Real64 AirChangeRate = CalcZoneSystemACH(state, ZoneNum);
    5243            1 :         return CalcBeausoleilMorrisonMixedAssistedWall(DeltaTemp, Height, SurfTemp, SupplyAirTemp, AirChangeRate);
    5244              :     } else {
    5245            2 :         ErrorObjectHeader eoh{routineName, "Zone", state.dataHeatBal->Zone(ZoneNum).Name};
    5246            2 :         if (Height == 0.0) {
    5247            1 :             ShowWarningHydraulicDiameterZero(state, state.dataConvect->BMMixedAssistedWallErrorIDX2, eoh);
    5248              :         }
    5249            2 :         if (DeltaTemp == 0.0 && !state.dataGlobal->WarmupFlag) {
    5250            1 :             ShowWarningDeltaTempZero(state, state.dataConvect->BMMixedAssistedWallErrorIDX1, eoh);
    5251              :         }
    5252            2 :         return 9.999;
    5253              :     }
    5254              : }
    5255              : 
    5256            2 : Real64 CalcBeausoleilMorrisonMixedOpposingWall(Real64 const DeltaTemp,     // [C] temperature difference between surface and air
    5257              :                                                Real64 const Height,        // [m] characteristic size
    5258              :                                                Real64 const SurfTemp,      // [C] surface temperature
    5259              :                                                Real64 const SupplyAirTemp, // [C] temperature of supply air into zone
    5260              :                                                Real64 const AirChangeRate  // [ACH] [1/hour] supply air ACH for zone
    5261              : )
    5262              : {
    5263              : 
    5264              :     // FUNCTION INFORMATION:
    5265              :     //       AUTHOR         Brent Griffith
    5266              :     //       DATE WRITTEN   Jul 2010
    5267              : 
    5268              :     // PURPOSE OF THIS FUNCTION:
    5269              :     // Calculate model equation Beausoleil-Morrison's mixed flow regime
    5270              :     // with mechanical and buoyancy forces opposing each other along a Wall
    5271              : 
    5272              :     // REFERENCES:
    5273              :     // Beausoleil-Morrison, I. 2000. The adaptive coupling of heat and
    5274              :     //  air flow modeling within dynamic whole-building simulations.
    5275              :     //  PhD. Thesis. University of Strathclyde, Glasgow, UK.
    5276              : 
    5277            2 :     Real64 HcTmp1 = 9.999;
    5278            2 :     Real64 HcTmp2 = 9.999;
    5279              : 
    5280            2 :     if (Height != 0.0) {
    5281              :         Real64 cofpow =
    5282            2 :             std::sqrt(pow_6(1.5 * std::pow(std::abs(DeltaTemp) / Height, 0.25)) + std::pow(1.23 * pow_2(DeltaTemp), 1.0 / 6.0)) -
    5283            2 :             pow_3(((SurfTemp - SupplyAirTemp) / std::abs(DeltaTemp)) *
    5284            2 :                   (-0.199 + 0.190 * std::pow(AirChangeRate,
    5285            2 :                                              0.8))); // Tuned pow_6( std::pow( std::abs( DeltaTemp ), 1.0/3.0 ) ) changed to pow_2( DeltaTemp )
    5286            2 :         HcTmp1 = std::pow(std::abs(cofpow),
    5287              :                           1.0 / 3.0); // Tuned pow_6( std::pow( std::abs( DeltaTemp ), 1.0/3.0 ) ) changed to pow_2( DeltaTemp )
    5288            2 :         if (cofpow < 0.0) {
    5289            0 :             HcTmp1 = -HcTmp1;
    5290              :         }
    5291              : 
    5292            2 :         HcTmp2 = 0.8 * std::pow(pow_6(1.5 * std::pow(std::abs(DeltaTemp) / Height, 0.25)) + (1.23 * pow_2(DeltaTemp)),
    5293              :                                 1.0 / 6.0); // Tuned pow_6( std::pow( std::abs( DeltaTemp ), 1.0/3.0 ) ) changed to pow_2( DeltaTemp )
    5294              :     }
    5295              : 
    5296            2 :     Real64 HcTmp3 = 0.8 * ((SurfTemp - SupplyAirTemp) / std::abs(DeltaTemp)) * (-0.199 + 0.190 * std::pow(AirChangeRate, 0.8));
    5297              : 
    5298            2 :     return max(max(HcTmp1, HcTmp2), HcTmp3);
    5299              : }
    5300              : 
    5301            3 : Real64 CalcBeausoleilMorrisonMixedOpposingWall(EnergyPlusData &state,
    5302              :                                                Real64 const DeltaTemp, // [C] temperature difference between surface and air
    5303              :                                                Real64 const Height,    // [m] characteristic size
    5304              :                                                Real64 const SurfTemp,  // [C] surface temperature
    5305              :                                                int const ZoneNum       // index of zone for messaging
    5306              : )
    5307              : {
    5308            3 :     std::string_view constexpr routineName = "CalcBeausoleilMorrisonMixedOpposingWall";
    5309            3 :     ErrorObjectHeader eoh{routineName, "Zone", state.dataHeatBal->Zone(ZoneNum).Name};
    5310            3 :     if (std::abs(DeltaTemp) > HVAC::SmallTempDiff) { // protect divide by zero
    5311              : 
    5312            2 :         if (Height == 0.0) {
    5313            1 :             ShowWarningHydraulicDiameterZero(state, state.dataConvect->BMMixedOpposingWallErrorIDX2, eoh);
    5314            1 :             return 9.999;
    5315              :         }
    5316            1 :         Real64 SupplyAirTemp = CalcZoneSupplyAirTemp(state, ZoneNum);
    5317            1 :         Real64 AirChangeRate = CalcZoneSystemACH(state, ZoneNum);
    5318            1 :         return CalcBeausoleilMorrisonMixedOpposingWall(DeltaTemp, Height, SurfTemp, SupplyAirTemp, AirChangeRate);
    5319              : 
    5320              :     } else {
    5321            1 :         if (!state.dataGlobal->WarmupFlag) {
    5322            1 :             ShowWarningDeltaTempZero(state, state.dataConvect->BMMixedOpposingWallErrorIDX1, eoh);
    5323              :         }
    5324            1 :         return 9.999;
    5325              :     }
    5326              : }
    5327              : 
    5328            2 : Real64 CalcBeausoleilMorrisonMixedStableFloor(Real64 const DeltaTemp,         // [C] temperature difference between surface and air
    5329              :                                               Real64 const HydraulicDiameter, // [m] characteristic size, = (4 * area) / perimeter
    5330              :                                               Real64 const SurfTemp,          // [C] surface temperature
    5331              :                                               Real64 const SupplyAirTemp,     // [C] temperature of supply air into zone
    5332              :                                               Real64 const AirChangeRate      // [ACH] [1/hour] supply air ACH for zone
    5333              : )
    5334              : {
    5335              : 
    5336              :     // FUNCTION INFORMATION:
    5337              :     //       AUTHOR         Brent Griffith
    5338              :     //       DATE WRITTEN   Jul 2010
    5339              : 
    5340              :     // PURPOSE OF THIS FUNCTION:
    5341              :     // Calculate model equation Beausoleil-Morrison's mixed flow regime
    5342              :     // with mechanical and buoyancy forces acting on an thermally stable floor
    5343              : 
    5344              :     // REFERENCES:
    5345              :     // Beausoleil-Morrison, I. 2000. The adaptive coupling of heat and
    5346              :     //  air flow modeling within dynamic whole-building simulations.
    5347              :     //  PhD. Thesis. University of Strathclyde, Glasgow, UK.
    5348              : 
    5349            2 :     Real64 cofpow = pow_3(0.6 * std::pow(std::abs(DeltaTemp) / HydraulicDiameter, 0.2)) +
    5350            2 :                     pow_3(((SurfTemp - SupplyAirTemp) / std::abs(DeltaTemp)) * (0.159 + 0.116 * std::pow(AirChangeRate, 0.8)));
    5351            2 :     Real64 Hc = std::pow(std::abs(cofpow), 1.0 / 3.0);
    5352            2 :     if (cofpow < 0.0) {
    5353            1 :         Hc = -Hc;
    5354              :     }
    5355            2 :     return Hc;
    5356              : }
    5357              : 
    5358            6 : void ShowWarningHydraulicDiameterZero(EnergyPlusData &state, int &errorIdx, ErrorObjectHeader const &eoh)
    5359              : {
    5360            6 :     if (errorIdx == 0) {
    5361            6 :         ShowWarningMessage(state, format("{}: Convection model not evaluated (would divide by zero)", eoh.routineName));
    5362           12 :         ShowContinueError(
    5363           12 :             state, format("Effective hydraulic diameter is zero, convection model not applicable for {} named {}", eoh.objectType, eoh.objectName));
    5364           18 :         ShowContinueError(state, "Convection heat transfer coefficient set to 9.999 [W/m2-K] and the simulation continues");
    5365              :     }
    5366           42 :     ShowRecurringWarningErrorAtEnd(state,
    5367           12 :                                    format("{}: Convection model not evaluated because effective hydraulic diameter is zero "
    5368              :                                           "and set to 9.999 [W/m2-K]",
    5369            6 :                                           eoh.routineName),
    5370              :                                    errorIdx);
    5371            6 : }
    5372              : 
    5373            6 : void ShowWarningDeltaTempZero(EnergyPlusData &state, int &errorIdx, ErrorObjectHeader const &eoh)
    5374              : {
    5375            6 :     if (errorIdx == 0) {
    5376            6 :         ShowWarningMessage(state, format("{}: Convection model not evaluated (would divide by zero)", eoh.routineName));
    5377           12 :         ShowContinueError(state, "The temperature difference between surface and air is zero");
    5378            6 :         ShowContinueError(state, format("Occurs for {} named {}", eoh.objectType, eoh.objectName));
    5379           18 :         ShowContinueError(state, "Convection surface heat transfer coefficient set to 9.999 [W/m2-K] and the simulation continues");
    5380              :     }
    5381              : 
    5382           42 :     ShowRecurringWarningErrorAtEnd(state,
    5383           12 :                                    format("{}: Convection model not evaluated because of zero temperature "
    5384              :                                           "difference and set to 9.999 [W/m2-K]",
    5385            6 :                                           eoh.routineName),
    5386              :                                    errorIdx);
    5387            6 : }
    5388              : 
    5389            0 : void ShowWarningWindowLocation(EnergyPlusData &state, int &errorIdx, ErrorObjectHeader const &eoh, IntConvWinLoc winLoc)
    5390              : {
    5391            0 :     if (errorIdx == 0) {
    5392            0 :         ShowSevereMessage(state, format("{}: Convection model not evaluated (bad relative window location)", eoh.routineName));
    5393            0 :         ShowContinueError(state, format("Value for window location = {}", winLoc));
    5394            0 :         ShowContinueError(state, format("Occurs for {} named {}", eoh.objectType, eoh.objectName));
    5395            0 :         ShowContinueError(state, "Convection surface heat transfer coefficient set to 9.999 [W/m2-K] and the simulation continues");
    5396              :     }
    5397            0 :     ShowRecurringSevereErrorAtEnd(state,
    5398            0 :                                   format("{}: Convection model not evaluated because bad window "
    5399              :                                          "location and set to 9.999 [W/m2-K]",
    5400            0 :                                          eoh.routineName),
    5401              :                                   errorIdx);
    5402            0 : }
    5403              : 
    5404            0 : void ShowWarningPerimeterLengthZero(EnergyPlusData &state, int &errorIdx, ErrorObjectHeader const &eoh)
    5405              : {
    5406            0 :     if (errorIdx == 0) {
    5407            0 :         ShowWarningError(state, format("{}: Convection model not evaluated (zero zone exterior perimeter length)", eoh.routineName));
    5408            0 :         ShowContinueError(state, "Value for zone exterior perimeter length = 0.0");
    5409            0 :         ShowContinueError(state, format("Occurs for {} named {}", eoh.objectType, eoh.objectName));
    5410            0 :         ShowContinueError(state, "Convection surface heat transfer coefficient set to 9.999 [W/m2-K] and the simulation continues");
    5411              :     }
    5412            0 :     ShowRecurringSevereErrorAtEnd(state,
    5413            0 :                                   format("{}: Convection model not evaluated because bad perimeter "
    5414              :                                          "length and set to 9.999 [W/m2-K]",
    5415            0 :                                          eoh.routineName),
    5416              :                                   errorIdx);
    5417            0 : }
    5418              : 
    5419            0 : void ShowWarningFaceAreaZero(EnergyPlusData &state, int &errorIdx, ErrorObjectHeader const &eoh)
    5420              : {
    5421            0 :     if (errorIdx == 0) {
    5422            0 :         ShowSevereMessage(state, format("{}: Convection model not evaluated (bad face area)", eoh.routineName));
    5423            0 :         ShowContinueError(state, "Value for effective face area = 0.0");
    5424            0 :         ShowContinueError(state, format("Occurs for {} named {}", eoh.objectType, eoh.objectName));
    5425            0 :         ShowContinueError(state, "Convection surface heat transfer coefficient set to 9.999 [W/m2-K] and the simulation continues");
    5426              :     }
    5427            0 :     ShowRecurringSevereErrorAtEnd(
    5428            0 :         state, format("{}: Convection model not evaluated because bad face area and set to 9.999 [W/m2-k]", eoh.routineName), errorIdx);
    5429            0 : }
    5430              : 
    5431            3 : Real64 CalcBeausoleilMorrisonMixedStableFloor(EnergyPlusData &state,
    5432              :                                               Real64 const DeltaTemp,         // [C] temperature difference between surface and air
    5433              :                                               Real64 const HydraulicDiameter, // [m] characteristic size, = (4 * area) / perimeter
    5434              :                                               Real64 const SurfTemp,          // [C] surface temperature
    5435              :                                               int const ZoneNum               // index of zone for messaging
    5436              : )
    5437              : {
    5438            3 :     std::string_view constexpr routineName = "CalcBeausoleilMorrisonMixedStableFloor";
    5439              : 
    5440            3 :     if ((HydraulicDiameter != 0.0) && (std::abs(DeltaTemp) > HVAC::SmallTempDiff)) {
    5441            1 :         Real64 SupplyAirTemp = CalcZoneSupplyAirTemp(state, ZoneNum);
    5442            1 :         Real64 AirChangeRate = CalcZoneSystemACH(state, ZoneNum);
    5443            1 :         return CalcBeausoleilMorrisonMixedStableFloor(DeltaTemp, HydraulicDiameter, SurfTemp, SupplyAirTemp, AirChangeRate);
    5444              :     } else {
    5445            2 :         ErrorObjectHeader eoh{routineName, "Zone", state.dataHeatBal->Zone(ZoneNum).Name};
    5446            2 :         if (HydraulicDiameter == 0.0) {
    5447            1 :             ShowWarningHydraulicDiameterZero(state, state.dataConvect->BMMixedStableFloorErrorIDX1, eoh);
    5448              :         }
    5449            2 :         if (DeltaTemp == 0.0 && !state.dataGlobal->WarmupFlag) {
    5450            1 :             ShowWarningDeltaTempZero(state, state.dataConvect->BMMixedStableFloorErrorIDX2, eoh);
    5451              :         }
    5452            2 :         return 9.999;
    5453              :     }
    5454              : }
    5455              : 
    5456            2 : Real64 CalcBeausoleilMorrisonMixedUnstableFloor(Real64 const DeltaTemp,         // [C] temperature difference between surface and air
    5457              :                                                 Real64 const HydraulicDiameter, // [m] characteristic size, = (4 * area) / perimeter
    5458              :                                                 Real64 const SurfTemp,          // [C] surface temperature
    5459              :                                                 Real64 const SupplyAirTemp,     // [C] temperature of supply air into zone
    5460              :                                                 Real64 const AirChangeRate      // [ACH] [1/hour] supply air ACH for zone
    5461              : )
    5462              : {
    5463              : 
    5464              :     // FUNCTION INFORMATION:
    5465              :     //       AUTHOR         Brent Griffith
    5466              :     //       DATE WRITTEN   Jul 2010
    5467              : 
    5468              :     // PURPOSE OF THIS FUNCTION:
    5469              :     // Calculate model equation Beausoleil-Morrison's mixed flow regime
    5470              :     // with mechanical and buoyancy forces acting on an thermally unstable floor
    5471              : 
    5472              :     // REFERENCES:
    5473              :     // Beausoleil-Morrison, I. 2000. The adaptive coupling of heat and
    5474              :     //  air flow modeling within dynamic whole-building simulations.
    5475              :     //  PhD. Thesis. University of Strathclyde, Glasgow, UK.
    5476              : 
    5477              :     Real64 cofpow =
    5478            2 :         std::sqrt(pow_6(1.4 * std::pow(std::abs(DeltaTemp) / HydraulicDiameter, 0.25)) + pow_6(1.63 * std::pow(std::abs(DeltaTemp), 1.0 / 3.0))) +
    5479            2 :         pow_3(((SurfTemp - SupplyAirTemp) / std::abs(DeltaTemp)) * (0.159 + 0.116 * std::pow(AirChangeRate, 0.8)));
    5480            2 :     Real64 Hc = std::pow(std::abs(cofpow), 1.0 / 3.0);
    5481            2 :     if (cofpow < 0.0) {
    5482            1 :         Hc = -Hc;
    5483              :     }
    5484              : 
    5485            2 :     return Hc;
    5486              : }
    5487              : 
    5488            3 : Real64 CalcBeausoleilMorrisonMixedUnstableFloor(EnergyPlusData &state,
    5489              :                                                 Real64 const DeltaTemp,         // [C] temperature difference between surface and air
    5490              :                                                 Real64 const HydraulicDiameter, // [m] characteristic size, = (4 * area) / perimeter
    5491              :                                                 Real64 const SurfTemp,          // [C] surface temperature
    5492              :                                                 int const ZoneNum               // index of zone for messaging
    5493              : )
    5494              : {
    5495            3 :     std::string_view constexpr routineName = "CalcBeausoleilMorrisonMixedUnstableFloor";
    5496            3 :     if ((HydraulicDiameter != 0.0) && (std::abs(DeltaTemp) > HVAC::SmallTempDiff)) {
    5497            1 :         Real64 SupplyAirTemp = CalcZoneSupplyAirTemp(state, ZoneNum);
    5498            1 :         Real64 AirChangeRate = CalcZoneSystemACH(state, ZoneNum);
    5499            1 :         return CalcBeausoleilMorrisonMixedUnstableFloor(DeltaTemp, HydraulicDiameter, SurfTemp, SupplyAirTemp, AirChangeRate);
    5500              :     } else {
    5501            2 :         ErrorObjectHeader eoh{routineName, "Zone", state.dataHeatBal->Zone(ZoneNum).Name};
    5502            2 :         if (HydraulicDiameter == 0.0) {
    5503            1 :             ShowWarningHydraulicDiameterZero(state, state.dataConvect->BMMixedUnstableFloorErrorIDX1, eoh);
    5504              :         }
    5505              : 
    5506            2 :         if (DeltaTemp == 0.0 && !state.dataGlobal->WarmupFlag) {
    5507            1 :             ShowWarningDeltaTempZero(state, state.dataConvect->BMMixedUnstableFloorErrorIDX2, eoh);
    5508              :         }
    5509            2 :         return 9.999;
    5510              :     }
    5511              : }
    5512              : 
    5513            2 : Real64 CalcBeausoleilMorrisonMixedStableCeiling(Real64 const DeltaTemp,         // [C] temperature difference between surface and air
    5514              :                                                 Real64 const HydraulicDiameter, // [m] characteristic size, = (4 * area) / perimeter
    5515              :                                                 Real64 const SurfTemp,          // [C] surface temperature
    5516              :                                                 Real64 const SupplyAirTemp,     // [C] temperature of supply air into zone
    5517              :                                                 Real64 const AirChangeRate      // [ACH] [1/hour] supply air ACH for zone
    5518              : )
    5519              : {
    5520              : 
    5521              :     // FUNCTION INFORMATION:
    5522              :     //       AUTHOR         Brent Griffith
    5523              :     //       DATE WRITTEN   Jul 2010
    5524              : 
    5525              :     // PURPOSE OF THIS FUNCTION:
    5526              :     // Calculate model equation Beausoleil-Morrison's mixed flow regime
    5527              :     // with mechanical and buoyancy forces acting on a thermally stable ceiling
    5528              : 
    5529              :     // REFERENCES:
    5530              :     // Beausoleil-Morrison, I. 2000. The adaptive coupling of heat and
    5531              :     //  air flow modeling within dynamic whole-building simulations.
    5532              :     //  PhD. Thesis. University of Strathclyde, Glasgow, UK.
    5533              : 
    5534            2 :     Real64 cofpow = pow_3(0.6 * std::pow(std::abs(DeltaTemp) / HydraulicDiameter, 0.2)) +
    5535            2 :                     pow_3(((SurfTemp - SupplyAirTemp) / std::abs(DeltaTemp)) * (-0.166 + 0.484 * std::pow(AirChangeRate, 0.8)));
    5536            2 :     Real64 Hc = std::pow(std::abs(cofpow), 1.0 / 3.0);
    5537            2 :     if (cofpow < 0.0) {
    5538            1 :         Hc = -Hc;
    5539              :     }
    5540            2 :     return Hc;
    5541              : }
    5542              : 
    5543            3 : Real64 CalcBeausoleilMorrisonMixedStableCeiling(EnergyPlusData &state,
    5544              :                                                 Real64 const DeltaTemp,         // [C] temperature difference between surface and air
    5545              :                                                 Real64 const HydraulicDiameter, // [m] characteristic size, = (4 * area) / perimeter
    5546              :                                                 Real64 const SurfTemp,          // [C] surface temperature
    5547              :                                                 int const ZoneNum               // index of zone for messaging
    5548              : )
    5549              : {
    5550            3 :     std::string_view constexpr routineName = "CalcBeausoleilMorrisonMixedStableCeiling";
    5551            3 :     if ((HydraulicDiameter != 0.0) && (std::abs(DeltaTemp) > HVAC::SmallTempDiff)) {
    5552            1 :         Real64 SupplyAirTemp = CalcZoneSupplyAirTemp(state, ZoneNum);
    5553            1 :         Real64 AirChangeRate = CalcZoneSystemACH(state, ZoneNum);
    5554            1 :         return CalcBeausoleilMorrisonMixedStableCeiling(DeltaTemp, HydraulicDiameter, SurfTemp, SupplyAirTemp, AirChangeRate);
    5555              :     } else {
    5556            2 :         ErrorObjectHeader eoh{routineName, "Zone", state.dataHeatBal->Zone(ZoneNum).Name};
    5557              : 
    5558            2 :         if (HydraulicDiameter == 0.0) {
    5559            1 :             ShowWarningHydraulicDiameterZero(state, state.dataConvect->BMMixedStableCeilingErrorIDX1, eoh);
    5560              :         }
    5561            2 :         if (DeltaTemp == 0.0 && !state.dataGlobal->WarmupFlag) {
    5562            1 :             ShowWarningDeltaTempZero(state, state.dataConvect->BMMixedStableCeilingErrorIDX2, eoh);
    5563              :         }
    5564            2 :         return 9.999;
    5565              :     }
    5566              : }
    5567              : 
    5568            2 : Real64 CalcBeausoleilMorrisonMixedUnstableCeiling(Real64 const DeltaTemp,         // [C] temperature difference between surface and air
    5569              :                                                   Real64 const HydraulicDiameter, // [m] characteristic size, = (4 * area) / perimeter
    5570              :                                                   Real64 const SurfTemp,          // [C] surface temperature
    5571              :                                                   Real64 const SupplyAirTemp,     // [C] temperature of supply air into zone
    5572              :                                                   Real64 const AirChangeRate      // [ACH] [1/hour] supply air ACH for zone
    5573              : )
    5574              : {
    5575              : 
    5576              :     // FUNCTION INFORMATION:
    5577              :     //       AUTHOR         Brent Griffith
    5578              :     //       DATE WRITTEN   Jul 2010
    5579              : 
    5580              :     // PURPOSE OF THIS FUNCTION:
    5581              :     // Calculate model equation Beausoleil-Morrison's mixed flow regime
    5582              :     // with mechanical and buoyancy forces acting on a thermally unstable ceiling
    5583              : 
    5584              :     // REFERENCES:
    5585              :     // Beausoleil-Morrison, I. 2000. The adaptive coupling of heat and
    5586              :     //  air flow modeling within dynamic whole-building simulations.
    5587              :     //  PhD. Thesis. University of Strathclyde, Glasgow, UK.
    5588              : 
    5589              :     Real64 cofpow =
    5590            2 :         std::sqrt(pow_6(1.4 * std::pow(std::abs(DeltaTemp) / HydraulicDiameter, 0.25)) + pow_6(1.63 * std::pow(std::abs(DeltaTemp), 1.0 / 3.0))) +
    5591            2 :         pow_3(((SurfTemp - SupplyAirTemp) / std::abs(DeltaTemp)) * (-0.166 + 0.484 * std::pow(AirChangeRate, 0.8)));
    5592            2 :     Real64 Hc = std::pow(std::abs(cofpow), 1.0 / 3.0);
    5593            2 :     if (cofpow < 0.0) {
    5594            1 :         Hc = -Hc;
    5595              :     }
    5596            2 :     return Hc;
    5597              : }
    5598              : 
    5599            3 : Real64 CalcBeausoleilMorrisonMixedUnstableCeiling(EnergyPlusData &state,
    5600              :                                                   Real64 const DeltaTemp,         // [C] temperature difference between surface and air
    5601              :                                                   Real64 const HydraulicDiameter, // [m] characteristic size, = (4 * area) / perimeter
    5602              :                                                   Real64 const SurfTemp,          // [C] surface temperature
    5603              :                                                   int const ZoneNum               // index of zone for messaging
    5604              : )
    5605              : {
    5606            3 :     std::string_view constexpr routineName = "CalcBeausoleilMorrisonMixedUnstableCeiling";
    5607              : 
    5608            3 :     if ((HydraulicDiameter != 0.0) && (std::abs(DeltaTemp) > HVAC::SmallTempDiff)) {
    5609            1 :         Real64 SupplyAirTemp = CalcZoneSupplyAirTemp(state, ZoneNum);
    5610            1 :         Real64 AirChangeRate = CalcZoneSystemACH(state, ZoneNum);
    5611            1 :         return CalcBeausoleilMorrisonMixedUnstableCeiling(DeltaTemp, HydraulicDiameter, SurfTemp, SupplyAirTemp, AirChangeRate);
    5612              :     } else {
    5613            2 :         ErrorObjectHeader eoh{routineName, "Zone", state.dataHeatBal->Zone(ZoneNum).Name};
    5614            2 :         if (HydraulicDiameter == 0.0) {
    5615            1 :             ShowWarningHydraulicDiameterZero(state, state.dataConvect->BMMixedUnstableCeilingErrorIDX1, eoh);
    5616              :         }
    5617            2 :         if (DeltaTemp == 0.0 && !state.dataGlobal->WarmupFlag) {
    5618            1 :             ShowWarningDeltaTempZero(state, state.dataConvect->BMMixedUnstableCeilingErrorIDX2, eoh);
    5619              :         }
    5620            2 :         return 9.999;
    5621              :     }
    5622              : }
    5623              : 
    5624            0 : Real64 CalcFohannoPolidoriVerticalWall(Real64 const DeltaTemp, // [C] temperature difference between surface and air
    5625              :                                        Real64 const Height,    // [m] characteristic size, height of zone
    5626              :                                        Real64 const SurfTemp,  // [C] surface temperature
    5627              :                                        Real64 const QdotConv   // [W/m2] heat flux rate for rayleigh #
    5628              : )
    5629              : {
    5630              : 
    5631              :     // FUNCTION INFORMATION:
    5632              :     //       AUTHOR         Brent Griffith
    5633              :     //       DATE WRITTEN   Jul 2010
    5634              : 
    5635              :     // PURPOSE OF THIS FUNCTION:
    5636              :     // Calculate model equation for natural convection
    5637              : 
    5638              :     // REFERENCES:
    5639              :     // Fohanno, S., and G. Polidori. 2006. Modelling of natural convective heat transfer
    5640              :     // at an internal surface. Energy and Buildings 38 (2006) 548 - 553
    5641              : 
    5642              :     // FUNCTION PARAMETER DEFINITIONS:
    5643            0 :     Real64 constexpr g = 9.81;     // gravity constant (m/s**2)  // Constant::Gravity is 9.807
    5644            0 :     Real64 constexpr v = 15.89e-6; // kinematic viscosity (m**2/s) for air at 300 K
    5645            0 :     Real64 constexpr k = 0.0263;   // thermal conductivity (W/m K) for air at 300 K
    5646            0 :     Real64 constexpr Pr = 0.71;    // Prandtl number for air at ?
    5647              : 
    5648            0 :     Real64 BetaFilm = 1.0 / (Constant::Kelvin + SurfTemp + 0.5 * DeltaTemp); // TODO check sign on DeltaTemp
    5649            0 :     Real64 RaH = (g * BetaFilm * QdotConv * pow_4(Height) * Pr) / (k * pow_2(v));
    5650              : 
    5651            0 :     if (RaH <= 6.3e09) {
    5652            0 :         return 1.332 * std::pow(std::abs(DeltaTemp) / Height, 0.25);
    5653              :     } else {
    5654            0 :         return 1.235 * std::exp(0.0467 * Height) * std::pow(std::abs(DeltaTemp), 0.316);
    5655              :     }
    5656              : }
    5657              : 
    5658            0 : Real64 CallCalcFohannoPolidoriVerticalWall(EnergyPlusData &state,
    5659              :                                            Real64 const DeltaTemp, // [C] temperature difference between surface and air
    5660              :                                            Real64 const Height,    // [m] characteristic size, height of zone
    5661              :                                            Real64 const SurfTemp,  // [C] surface temperature
    5662              :                                            Real64 const QdotConv,  // [W/m2] heat flux rate for rayleigh #
    5663              :                                            int const SurfNum       // for messages
    5664              : )
    5665              : {
    5666            0 :     std::string_view constexpr routineName = "CalcFohannoPolidoriVerticalWall";
    5667            0 :     if (Height > 0.0) {
    5668            0 :         return CalcFohannoPolidoriVerticalWall(DeltaTemp, Height, SurfTemp, QdotConv);
    5669              :     } else {
    5670            0 :         ErrorObjectHeader eoh{routineName, "Surface", state.dataSurface->Surface(SurfNum).Name};
    5671              :         // bad value for Height, but we have little info to identify calling culprit
    5672            0 :         ShowWarningHydraulicDiameterZero(state, state.dataConvect->CalcFohannoPolidoriVerticalWallErrorIDX, eoh);
    5673            0 :         return 9.999;
    5674              :     }
    5675              : }
    5676              : 
    5677            0 : Real64 CalcKaradagChilledCeiling(Real64 const DeltaTemp) // [C] temperature difference between surface and air
    5678              : {
    5679              : 
    5680              :     // FUNCTION INFORMATION:
    5681              :     //       AUTHOR         Brent Griffith
    5682              :     //       DATE WRITTEN   Jul 2010
    5683              : 
    5684              :     // PURPOSE OF THIS FUNCTION:
    5685              :     // Calculate model equation for natural convection developed by Karadag for chilled ceilings
    5686              : 
    5687              :     // REFERENCES:
    5688              :     // Karadag, R. 2009. New approach relevant to total heat transfer coefficient
    5689              :     //   including the effect of radiation and convection at the ceiling in a cooled
    5690              :     //   ceiling room.  Applied Thermal Engineering 29 (2009) 1561-1565
    5691              :     //    This function is for equation 8 in the reference
    5692              : 
    5693            0 :     return 3.1 * std::pow(std::abs(DeltaTemp), 0.22);
    5694              : }
    5695              : 
    5696            0 : Real64 CalcGoldsteinNovoselacCeilingDiffuserWindow(Real64 const AirSystemFlowRate,        // [m3/s] air system flow rate
    5697              :                                                    Real64 const ZoneExtPerimLength,       // [m] length of zone perimeter with exterior walls
    5698              :                                                    Real64 const WindWallRatio,            // [ ] fraction of window area to wall area for zone
    5699              :                                                    IntConvWinLoc const WindowLocationType // index for location types
    5700              : )
    5701              : {
    5702              : 
    5703              :     // FUNCTION INFORMATION:
    5704              :     //       AUTHOR         Brent Griffith
    5705              :     //       DATE WRITTEN   Aug 2010
    5706              : 
    5707              :     // PURPOSE OF THIS FUNCTION:
    5708              :     // Calculate model equation for windows in zones with slot diffusers on them
    5709              :     //  developed by Novoselac for RP-1416
    5710              : 
    5711              :     // REFERENCES:
    5712              :     // Goldstien, K. and A. Novoselac. 2010. Convective Heat Transfer in Rooms
    5713              :     //  With Ceiling Slot Diffusers (RP-1416). HVAC&R Research Journal TBD
    5714              : 
    5715            0 :     if (ZoneExtPerimLength > 0.0) {
    5716            0 :         if (WindWallRatio <= 0.5) {
    5717              : 
    5718            0 :             switch (WindowLocationType) {
    5719            0 :             case IntConvWinLoc::UpperPartOfExteriorWall:
    5720              :             case IntConvWinLoc::LargePartOfExteriorWall:
    5721              :             case IntConvWinLoc::NotSet:
    5722            0 :                 return 0.117 * std::pow(AirSystemFlowRate / ZoneExtPerimLength, 0.8);
    5723            0 :             case IntConvWinLoc::LowerPartOfExteriorWall:
    5724            0 :                 return 0.093 * std::pow(AirSystemFlowRate / ZoneExtPerimLength, 0.8);
    5725            0 :             default:
    5726            0 :                 assert(false);
    5727              :                 return 9.999;
    5728              :             }
    5729              : 
    5730              :         } else {
    5731            0 :             return 0.103 * std::pow(AirSystemFlowRate / ZoneExtPerimLength, 0.8);
    5732              :         }
    5733              :     } else {
    5734            0 :         return 9.999;
    5735              :     }
    5736              : }
    5737              : 
    5738            0 : Real64 CalcGoldsteinNovoselacCeilingDiffuserWindow(EnergyPlusData &state,
    5739              :                                                    Real64 const zoneExtPerimLength, // [m] length of zone perimeter with exterior walls
    5740              :                                                    Real64 const WindWallRatio,      // [ ] fraction of window area to wall area for zone
    5741              :                                                    IntConvWinLoc const winLoc,      // index for location types
    5742              :                                                    int const ZoneNum                // for messages
    5743              : )
    5744              : {
    5745            0 :     std::string_view constexpr routineName = "CalcGoldsteinNovoselacCeilingDiffuserWindow";
    5746            0 :     ErrorObjectHeader eoh{routineName, "Zone", state.dataHeatBal->Zone(ZoneNum).Name};
    5747              : 
    5748            0 :     Real64 AirSystemFlowRate = CalcZoneSystemVolFlowRate(state, ZoneNum);
    5749              : 
    5750            0 :     if (zoneExtPerimLength > 0.0) {
    5751            0 :         if (WindWallRatio <= 0.5) {
    5752            0 :             if (winLoc != IntConvWinLoc::UpperPartOfExteriorWall && winLoc != IntConvWinLoc::LowerPartOfExteriorWall &&
    5753            0 :                 winLoc != IntConvWinLoc::LargePartOfExteriorWall && winLoc != IntConvWinLoc::NotSet) {
    5754              :                 // Should we not be returning 9.999 here as we do everywhere else?
    5755            0 :                 ShowWarningWindowLocation(state, state.dataConvect->CalcGoldsteinNovoselacCeilingDiffuserWindowErrorIDX1, eoh, winLoc);
    5756              :             }
    5757              :         }
    5758              :     } else {
    5759            0 :         ShowWarningPerimeterLengthZero(state, state.dataConvect->CalcGoldsteinNovoselacCeilingDiffuserWindowErrorIDX2, eoh);
    5760              :     }
    5761            0 :     return CalcGoldsteinNovoselacCeilingDiffuserWindow(AirSystemFlowRate, zoneExtPerimLength, WindWallRatio, winLoc);
    5762              : }
    5763              : 
    5764            0 : Real64 CalcGoldsteinNovoselacCeilingDiffuserWall(Real64 const AirSystemFlowRate,        // [m3/s] air system flow rate
    5765              :                                                  Real64 const ZoneExtPerimLength,       // [m] length of zone perimeter with exterior walls
    5766              :                                                  IntConvWinLoc const WindowLocationType // index for location types
    5767              : )
    5768              : {
    5769              : 
    5770              :     // FUNCTION INFORMATION:
    5771              :     //       AUTHOR         Brent Griffith
    5772              :     //       DATE WRITTEN   Aug 2010
    5773              : 
    5774              :     // PURPOSE OF THIS FUNCTION:
    5775              :     // Calculate model equation for exterior walls in zones with slot diffusers on them
    5776              :     //  developed by Novoselac for RP-1416
    5777              : 
    5778              :     // REFERENCES:
    5779              :     // Goldstien, K. and A. Novoselac. 2010. Convective Heat Transfer in Rooms
    5780              :     //  With Ceiling Slot Diffusers (RP-1416). HVAC&R Research Journal TBD
    5781              : 
    5782            0 :     if (ZoneExtPerimLength > 0.0) {
    5783              : 
    5784            0 :         switch (WindowLocationType) {
    5785            0 :         case IntConvWinLoc::WindowAboveThis:
    5786              :         case IntConvWinLoc::NotSet:
    5787            0 :             return 0.063 * std::pow(AirSystemFlowRate / ZoneExtPerimLength, 0.8);
    5788            0 :         case IntConvWinLoc::WindowBelowThis:
    5789            0 :             return 0.093 * std::pow(AirSystemFlowRate / ZoneExtPerimLength, 0.8);
    5790            0 :         default:
    5791            0 :             assert(false);
    5792              :             return 9.999;
    5793              :         }
    5794              :     } else {
    5795            0 :         return 9.999;
    5796              :     }
    5797              : }
    5798              : 
    5799            0 : Real64 CalcGoldsteinNovoselacCeilingDiffuserWall(EnergyPlusData &state,
    5800              :                                                  Real64 const zoneExtPerimLength, // [m] length of zone perimeter with exterior walls
    5801              :                                                  IntConvWinLoc const winLoc,      // index for location types
    5802              :                                                  int const ZoneNum                // for messages
    5803              : )
    5804              : {
    5805            0 :     std::string_view constexpr routineName = "CalcGoldsteinNovoselacCeilingDiffuserWall";
    5806            0 :     ErrorObjectHeader eoh{routineName, "Zone", state.dataHeatBal->Zone(ZoneNum).Name};
    5807            0 :     Real64 AirSystemFlowRate = CalcZoneSystemVolFlowRate(state, ZoneNum);
    5808              : 
    5809              :     // Should we not be returning 9.999 under these conditions?
    5810            0 :     if (zoneExtPerimLength > 0.0) {
    5811            0 :         if (winLoc != IntConvWinLoc::WindowAboveThis && winLoc != IntConvWinLoc::WindowBelowThis && winLoc != IntConvWinLoc::NotSet) {
    5812            0 :             ShowWarningWindowLocation(state, state.dataConvect->CalcGoldsteinNovoselacCeilingDiffuserWallErrorIDX1, eoh, winLoc);
    5813              :         }
    5814              :     } else {
    5815            0 :         ShowWarningPerimeterLengthZero(state, state.dataConvect->CalcGoldsteinNovoselacCeilingDiffuserWallErrorIDX2, eoh);
    5816              :     }
    5817            0 :     return CalcGoldsteinNovoselacCeilingDiffuserWall(AirSystemFlowRate, zoneExtPerimLength, winLoc);
    5818              : }
    5819              : 
    5820            0 : Real64 CalcGoldsteinNovoselacCeilingDiffuserFloor(Real64 const AirSystemFlowRate, // [m3/s] air system flow rate
    5821              :                                                   Real64 const ZoneExtPerimLength // [m] length of zone perimeter with exterior walls
    5822              : )
    5823              : {
    5824              : 
    5825              :     // FUNCTION INFORMATION:
    5826              :     //       AUTHOR         Brent Griffith
    5827              :     //       DATE WRITTEN   Aug 2010
    5828              : 
    5829              :     // PURPOSE OF THIS FUNCTION:
    5830              :     // Calculate model equation for floors in zones with slot diffusers on them
    5831              :     //  developed by Novoselac for RP-1416
    5832              : 
    5833              :     // REFERENCES:
    5834              :     // Goldstien, K. and A. Novoselac. 2010. Convective Heat Transfer in Rooms
    5835              :     //  With Ceiling Slot Diffusers (RP-1416). HVAC&R Research Journal TBD
    5836              : 
    5837            0 :     if (ZoneExtPerimLength > 0.0) {
    5838            0 :         return 0.048 * std::pow(AirSystemFlowRate / ZoneExtPerimLength, 0.8);
    5839              :     } else {
    5840            0 :         return 9.999; // safe but noticeable
    5841              :     }
    5842              : }
    5843              : 
    5844            0 : Real64 CalcGoldsteinNovoselacCeilingDiffuserFloor(EnergyPlusData &state,
    5845              :                                                   Real64 const ZoneExtPerimLength, // [m] length of zone perimeter with exterior walls
    5846              :                                                   int const ZoneNum                // for messages
    5847              : )
    5848              : {
    5849            0 :     std::string_view constexpr routineName = "CalcGoldsteinNovoselacCeilingDiffuserFloor";
    5850            0 :     Real64 AirSystemFlowRate = CalcZoneSystemVolFlowRate(state, ZoneNum);
    5851              : 
    5852            0 :     if (ZoneExtPerimLength <= 0.0) {
    5853            0 :         ErrorObjectHeader eoh{routineName, "Zone", state.dataHeatBal->Zone(ZoneNum).Name};
    5854            0 :         ShowWarningPerimeterLengthZero(state, state.dataConvect->CalcGoldsteinNovoselacCeilingDiffuserFloorErrorIDX, eoh);
    5855              :         // return 9.999?
    5856              :     }
    5857            0 :     return CalcGoldsteinNovoselacCeilingDiffuserFloor(AirSystemFlowRate, ZoneExtPerimLength);
    5858              : }
    5859              : 
    5860            0 : Real64 CalcSparrowWindward(Material::SurfaceRoughness const RoughnessIndex, Real64 const FacePerimeter, Real64 const FaceArea, Real64 const WindAtZ)
    5861              : {
    5862              : 
    5863              :     // FUNCTION INFORMATION:
    5864              :     //       AUTHOR         Brent Griffith
    5865              :     //       DATE WRITTEN   Aug 2010
    5866              : 
    5867              :     // PURPOSE OF THIS FUNCTION:
    5868              :     // Calculate Sparrow Hf for windward surfaces
    5869              : 
    5870              :     // REFERENCES:
    5871              : 
    5872              :     //   1. TARP Reference Manual, "Surface Outside Heat Balances", pp 71ff
    5873              :     //   2. Sparrow, E. M., J. W. Ramsey, and E. A. Mass.  1979.  Effect of finite
    5874              :     //   width on heat transfer and fluid flow about an inclined rectangular plate.
    5875              :     //   Journal of Heat Transfer 101:  204.
    5876              :     //   3. McClellan, T.M.  1996.  Investigation of a heat balance cooling load
    5877              :     //   procedure with a detailed study of outside heat transfer parameters.
    5878              :     //   M.S. Thesis, Department of Mechanical and Industrial Engineering,
    5879              :     //   University of Illinois at Urbana-Champaign.
    5880              : 
    5881            0 :     return 2.537 * RoughnessMultiplier[(int)RoughnessIndex] * std::sqrt(FacePerimeter * WindAtZ / FaceArea);
    5882              : }
    5883              : 
    5884            0 : Real64 CalcSparrowLeeward(Material::SurfaceRoughness const RoughnessIndex, Real64 const FacePerimeter, Real64 const FaceArea, Real64 const WindAtZ)
    5885              : {
    5886              : 
    5887              :     // FUNCTION INFORMATION:
    5888              :     //       AUTHOR         Brent Griffith
    5889              :     //       DATE WRITTEN   Aug 2010
    5890              : 
    5891              :     // PURPOSE OF THIS FUNCTION:
    5892              :     // Calculate Sparrow Hf for leeward surfaces
    5893              : 
    5894              :     // REFERENCES:
    5895              : 
    5896              :     //   1. TARP Reference Manual, "Surface Outside Heat Balances", pp 71ff
    5897              :     //   2. Sparrow, E. M., J. W. Ramsey, and E. A. Mass.  1979.  Effect of finite
    5898              :     //   width on heat transfer and fluid flow about an inclined rectangular plate.
    5899              :     //   Journal of Heat Transfer 101:  204.
    5900              :     //   3. McClellan, T.M.  1996.  Investigation of a heat balance cooling load
    5901              :     //   procedure with a detailed study of outside heat transfer parameters.
    5902              :     //   M.S. Thesis, Department of Mechanical and Industrial Engineering,
    5903              :     //   University of Illinois at Urbana-Champaign.
    5904              : 
    5905            0 :     return 0.5 * CalcSparrowWindward(RoughnessIndex, FacePerimeter, FaceArea, WindAtZ);
    5906              : }
    5907              : 
    5908            0 : Real64 CalcSparrowWindward(EnergyPlusData &state,
    5909              :                            Material::SurfaceRoughness const RoughnessIndex,
    5910              :                            Real64 const FacePerimeter,
    5911              :                            Real64 const FaceArea,
    5912              :                            Real64 const WindAtZ,
    5913              :                            int const SurfNum)
    5914              : {
    5915            0 :     std::string_view constexpr routineName = "CalcSparrowWindward";
    5916              : 
    5917            0 :     if (FaceArea > 0.0) {
    5918            0 :         return CalcSparrowWindward(RoughnessIndex, FacePerimeter, FaceArea, WindAtZ);
    5919              : 
    5920              :     } else {
    5921            0 :         ErrorObjectHeader eoh{routineName, "Surface", state.dataSurface->Surface(SurfNum).Name};
    5922            0 :         ShowWarningFaceAreaZero(state, state.dataConvect->CalcSparrowWindwardErrorIDX, eoh);
    5923            0 :         return 9.999; // safe but noticeable
    5924              :     }
    5925              : }
    5926              : 
    5927            0 : Real64 CalcSparrowLeeward(EnergyPlusData &state,
    5928              :                           Material::SurfaceRoughness const RoughnessIndex,
    5929              :                           Real64 const FacePerimeter,
    5930              :                           Real64 const FaceArea,
    5931              :                           Real64 const WindAtZ,
    5932              :                           int const SurfNum)
    5933              : {
    5934            0 :     std::string_view constexpr routineName = "CalcSparrowLeeward";
    5935              : 
    5936            0 :     if (FaceArea > 0.0) {
    5937            0 :         return CalcSparrowLeeward(RoughnessIndex, FacePerimeter, FaceArea, WindAtZ);
    5938              :     } else {
    5939            0 :         ErrorObjectHeader eoh{routineName, "Surface", state.dataSurface->Surface(SurfNum).Name};
    5940            0 :         ShowWarningFaceAreaZero(state, state.dataConvect->CalcSparrowLeewardErrorIDX, eoh);
    5941            0 :         return 9.999; // safe but noticeable
    5942              :     }
    5943              : }
    5944              : 
    5945           10 : Real64 CalcMoWITTNatural(Real64 DeltaTemp)
    5946              : {
    5947           10 :     Real64 constexpr temp_fac(0.84);
    5948           10 :     return temp_fac * std::pow(std::abs(DeltaTemp), 1.0 / 3.0);
    5949              : }
    5950              : 
    5951       886631 : Real64 CalcMoWITTForcedWindward(Real64 const WindAtZ)
    5952              : {
    5953       886631 :     Real64 constexpr wind_fac(3.26); // = a, Constant, W/(m2K(m/s)^b)
    5954       886631 :     Real64 constexpr wind_exp(0.89); // = b
    5955       886631 :     return wind_fac * std::pow(WindAtZ, wind_exp);
    5956              : }
    5957              : 
    5958       436858 : Real64 CalcMoWITTForcedLeeward(Real64 const WindAtZ)
    5959              : {
    5960       436858 :     Real64 constexpr wind_fac(3.55);  // = a, Constant, W/(m2K(m/s)^b)
    5961       436858 :     Real64 constexpr wind_exp(0.617); // = b
    5962       436858 :     return wind_fac * std::pow(WindAtZ, wind_exp);
    5963              : }
    5964              : 
    5965            8 : Real64 CalcMoWITTWindward(Real64 const DeltaTemp, Real64 const WindAtZ)
    5966              : {
    5967              : 
    5968              :     // FUNCTION INFORMATION:
    5969              :     //       AUTHOR         Brent Griffith
    5970              :     //       DATE WRITTEN   Aug 2010
    5971              : 
    5972              :     // PURPOSE OF THIS FUNCTION:
    5973              :     // calculate MoWITT Hc equation for windward surfaces
    5974              : 
    5975              :     // REFERENCES:
    5976              :     //   Yazdanian, M. and J.H. Klems.  1994.  Measurement of the exterior convective
    5977              :     //   film coefficient for windows in low-rise buildings.
    5978              :     //   ASHRAE Transactions 100(1):  1087.
    5979              : 
    5980            8 :     Real64 Hn = CalcMoWITTNatural(DeltaTemp);
    5981            8 :     Real64 Hf = CalcMoWITTForcedWindward(WindAtZ);
    5982            8 :     return std::sqrt(pow_2(Hn) + pow_2(Hf));
    5983              : }
    5984              : 
    5985            2 : Real64 CalcMoWITTLeeward(Real64 const DeltaTemp, Real64 const WindAtZ)
    5986              : {
    5987              : 
    5988              :     // FUNCTION INFORMATION:
    5989              :     //       AUTHOR         Brent Griffith
    5990              :     //       DATE WRITTEN   Aug 2010
    5991              : 
    5992              :     // PURPOSE OF THIS FUNCTION:
    5993              :     // calculate MoWITT Hc equation for leeward surfaces
    5994              : 
    5995              :     // REFERENCES:
    5996              :     //   Yazdanian, M. and J.H. Klems.  1994.  Measurement of the exterior convective
    5997              :     //   film coefficient for windows in low-rise buildings.
    5998              :     //   ASHRAE Transactions 100(1):  1087.
    5999              : 
    6000            2 :     Real64 Hn = CalcMoWITTNatural(DeltaTemp);
    6001            2 :     Real64 Hf = CalcMoWITTForcedLeeward(WindAtZ);
    6002            2 :     return std::sqrt(pow_2(Hn) + pow_2(Hf));
    6003              : }
    6004              : 
    6005      1323479 : Real64 CalcDOE2Forced(
    6006              :     Real64 const SurfaceTemp, Real64 const AirTemp, Real64 const CosineTilt, Real64 const HfSmooth, Material::SurfaceRoughness const RoughnessIndex)
    6007              : {
    6008              :     // This allows costly HfSmooth to be calculated independently (avoids excessive use of std::pow() in Kiva)
    6009      1323479 :     Real64 Hn = CalcASHRAETARPNatural(SurfaceTemp, AirTemp, CosineTilt);
    6010      1323479 :     Real64 HcSmooth = std::sqrt(pow_2(Hn) + pow_2(HfSmooth));
    6011      1323479 :     return RoughnessMultiplier[(int)RoughnessIndex] * (HcSmooth - Hn);
    6012              : }
    6013              : 
    6014       886623 : Real64 CalcDOE2Windward(
    6015              :     Real64 const SurfaceTemp, Real64 const AirTemp, Real64 const CosineTilt, Real64 const WindAtZ, Material::SurfaceRoughness const RoughnessIndex)
    6016              : {
    6017              :     // FUNCTION INFORMATION:
    6018              :     //       AUTHOR         Brent Griffith
    6019              :     //       DATE WRITTEN   Aug 2010
    6020              :     //       RE-ENGINEERED  na
    6021              : 
    6022              :     // PURPOSE OF THIS FUNCTION:
    6023              :     // calculate DOE-2 Hf equation for windward surfaces
    6024              : 
    6025              :     // REFERENCES:
    6026              :     //   Lawrence Berkeley Laboratory.  1994.  DOE2.1E-053 source code.
    6027              :     //   Yazdanian, M. and J.H. Klems.  1994.  Measurement of the exterior convective
    6028              :     //   film coefficient for windows in low-rise buildings.
    6029              :     //   ASHRAE Transactions 100(1):  1087.
    6030       886623 :     Real64 HfSmooth = CalcMoWITTForcedWindward(WindAtZ);
    6031              : 
    6032       886623 :     return CalcDOE2Forced(SurfaceTemp, AirTemp, CosineTilt, HfSmooth, RoughnessIndex);
    6033              : }
    6034              : 
    6035       436856 : Real64 CalcDOE2Leeward(
    6036              :     Real64 const SurfaceTemp, Real64 const AirTemp, Real64 const CosineTilt, Real64 const WindAtZ, Material::SurfaceRoughness const RoughnessIndex)
    6037              : {
    6038              :     // FUNCTION INFORMATION:
    6039              :     //       AUTHOR         Brent Griffith
    6040              :     //       DATE WRITTEN   Aug 2010
    6041              : 
    6042              :     // PURPOSE OF THIS FUNCTION:
    6043              :     // calculate DOE-2 Hf equation for leeward surfaces
    6044              : 
    6045              :     // REFERENCES:
    6046              :     //   Lawrence Berkeley Laboratory.  1994.  DOE2.1E-053 source code.
    6047              :     //   Yazdanian, M. and J.H. Klems.  1994.  Measurement of the exterior convective
    6048              :     //   film coefficient for windows in low-rise buildings.
    6049              :     //   ASHRAE Transactions 100(1):  1087.
    6050              : 
    6051       436856 :     Real64 HfSmooth = CalcMoWITTForcedLeeward(WindAtZ);
    6052              : 
    6053       436856 :     return CalcDOE2Forced(SurfaceTemp, AirTemp, CosineTilt, HfSmooth, RoughnessIndex);
    6054              : }
    6055              : 
    6056            0 : Real64 CalcNusseltJurges(Real64 const WindAtZ)
    6057              : {
    6058              : 
    6059              :     // FUNCTION INFORMATION:
    6060              :     //       AUTHOR         Brent Griffith
    6061              :     //       DATE WRITTEN   Aug 2010
    6062              : 
    6063              :     // PURPOSE OF THIS FUNCTION:
    6064              :     // calculate model equation for forced convection using Nusselt Jurges correlation
    6065              :     // model is attributed to Nusselt and Jurges but the equation is recast in current units
    6066              :     // by Palyvos
    6067              : 
    6068              :     // REFERENCES:
    6069              :     // 1. Nusselt, W., W. Jurges. 1922. Die Kuhlung einer ebenen Wand durch einen Luftstrom
    6070              :     //     (The cooling of a plane wall by an air flow). Gesundheits Ingenieur 52, Heft, 45, Jargang.
    6071              :     // 2. Palyvos, J.A., 2008. A survey of wind convection coefficient correlations for building
    6072              :     //     envelope energy systems' modeling. Applied Thermal Engineering 28 (2008) 801-808. Elsevier.
    6073              : 
    6074            0 :     return 5.8 + 3.94 * WindAtZ;
    6075              : }
    6076              : 
    6077            0 : Real64 CalcMcAdams(Real64 const WindAtZ)
    6078              : {
    6079              : 
    6080              :     // FUNCTION INFORMATION:
    6081              :     //       AUTHOR         Brent Griffith
    6082              :     //       DATE WRITTEN   Aug 2010
    6083              : 
    6084              :     // PURPOSE OF THIS FUNCTION:
    6085              :     // calculate model equation for forced convection using McAdams correlation
    6086              :     // model is attributed to McAdams but the equation is as recast in current units
    6087              :     // by Palyvos
    6088              : 
    6089              :     // REFERENCES:
    6090              :     // 1. McAdams, W.H., 1954. Heat Transmission, third ed., McGraw-Hill, New York.
    6091              :     // 2. Palyvos, J.A., 2008. A survey of wind convection coefficient correlations for building
    6092              :     //     envelope energy systems' modeling. Applied Thermal Engineering 28 (2008) 801-808. Elsevier.
    6093              : 
    6094            0 :     return 5.8 + 3.8 * WindAtZ;
    6095              : }
    6096              : 
    6097            0 : Real64 CalcMitchell(Real64 const WindAtZ, Real64 const LengthScale)
    6098              : {
    6099              : 
    6100              :     // FUNCTION INFORMATION:
    6101              :     //       AUTHOR         Brent Griffith
    6102              :     //       DATE WRITTEN   Aug 2010
    6103              : 
    6104              :     // PURPOSE OF THIS FUNCTION:
    6105              :     // calculate model equation for forced convection using Mitchell correlation
    6106              :     // model is attributed to Mitchell but the equation is as recast in current units
    6107              :     // by Palyvos
    6108              : 
    6109              :     // REFERENCES:
    6110              :     // 1. Mitchell, J.W., 1976. Heat transfer from spheres and other animal forms. Biophy. J. 16 (1976) 561
    6111              :     // 2. Palyvos, J.A., 2008. A survey of wind convection coefficient correlations for building
    6112              :     //     envelope energy systems' modeling. Applied Thermal Engineering 28 (2008) 801-808. Elsevier.
    6113              : 
    6114            0 :     return 8.6 * std::pow(WindAtZ, 0.6) / std::pow(LengthScale, 0.4);
    6115              : }
    6116              : 
    6117            0 : Real64 CalcMitchell(EnergyPlusData &state, Real64 const WindAtZ, Real64 const LengthScale, int const SurfNum)
    6118              : {
    6119            0 :     if (LengthScale > 0.0) {
    6120            0 :         return CalcMitchell(WindAtZ, LengthScale);
    6121              :     } else {
    6122            0 :         if (state.dataConvect->CalcMitchellErrorIDX == 0) {
    6123            0 :             ShowSevereMessage(state, "CalcMitchell: Convection model not evaluated (bad length scale)");
    6124            0 :             ShowContinueError(state, format("Value for effective length scale = {:.5R}", LengthScale));
    6125            0 :             ShowContinueError(state, format("Occurs for surface named = {}", state.dataSurface->Surface(SurfNum).Name));
    6126            0 :             ShowContinueError(state, "Convection surface heat transfer coefficient set to 9.999 [W/m2-K] and the simulation continues");
    6127              :         }
    6128            0 :         ShowRecurringSevereErrorAtEnd(state,
    6129              :                                       "CalcMitchell: Convection model not evaluated because bad length scale and set to 9.999 [W/m2-k]",
    6130            0 :                                       state.dataConvect->CalcMitchellErrorIDX);
    6131            0 :         return 9.999; // safe but noticeable
    6132              :     }
    6133              : }
    6134              : 
    6135          409 : Real64 CalcWindSurfaceTheta(Real64 const WindDir, Real64 const SurfAzimuth)
    6136              : {
    6137              :     // Computes the angle theta between the wind direction and the surface azimuth
    6138              :     // Should always be a value between 0-180 deg
    6139              : 
    6140          409 :     Real64 windDir = std::fmod(WindDir, 360);
    6141          409 :     Real64 surfAzi = std::fmod(SurfAzimuth, 360);
    6142          409 :     Real64 theta = std::abs(windDir - surfAzi);
    6143          409 :     if (theta > 180) {
    6144           40 :         return abs(theta - 360);
    6145              :     } else {
    6146          369 :         return theta;
    6147              :     }
    6148              : }
    6149              : 
    6150           75 : Real64 CalcBlockenWindward(EnergyPlusData &state,
    6151              :                            Real64 const WindAt10m,
    6152              :                            Real64 const WindDir,     // Wind direction measured clockwise from geographic North
    6153              :                            Real64 const SurfAzimuth, // or Facing, Direction the surface outward normal faces (degrees)
    6154              :                            int const SurfNum)
    6155              : {
    6156              : 
    6157              :     // FUNCTION INFORMATION:
    6158              :     //       AUTHOR         Brent Griffith
    6159              :     //       DATE WRITTEN   Aug 2010
    6160              : 
    6161              :     // PURPOSE OF THIS FUNCTION:
    6162              :     // calculate model equation for forced convection using Blocken correlation
    6163              : 
    6164              :     // REFERENCES:
    6165              :     // Blocken, B., T. Defraeye, D. Derome, J. Carmeliet. 2009.
    6166              :     //  High-Resolution CFD Simulations for Forced Convection
    6167              :     //   Heat Transfer Coefficients at the Facade of a Low-Rise Building.
    6168              :     //   Building and Environment 44 (2009) 2396 - 2412.
    6169              : 
    6170           75 :     Real64 Theta = CalcWindSurfaceTheta(WindDir, SurfAzimuth); // angle between wind and surface azimuth
    6171              : 
    6172           75 :     if (Theta <= 11.25) {
    6173           15 :         return 4.6 * std::pow(WindAt10m, 0.89);
    6174           60 :     } else if (Theta <= 33.75) {
    6175           15 :         return 5.0 * std::pow(WindAt10m, 0.8);
    6176           45 :     } else if (Theta <= 56.25) {
    6177           15 :         return 4.6 * std::pow(WindAt10m, 0.84);
    6178           30 :     } else if (Theta <= 100.0) {
    6179           15 :         return 4.5 * std::pow(WindAt10m, 0.81);
    6180              :     } else {
    6181           15 :         if (state.dataConvect->CalcBlockenWindwardErrorIDX == 0) {
    6182            2 :             ShowSevereMessage(state, "CalcBlockenWindward: Convection model wind angle calculation suspect (developer issue)");
    6183            1 :             ShowContinueError(state, format("Value for theta angle = {:.5R}", Theta));
    6184            1 :             ShowContinueError(state, format("Occurs for surface named = {}", state.dataSurface->Surface(SurfNum).Name));
    6185            3 :             ShowContinueError(state, "Convection model uses EmmelVertical correlation and the simulation continues");
    6186              :         }
    6187          105 :         ShowRecurringSevereErrorAtEnd(
    6188           15 :             state, "CalcBlockenWindward: Convection model wind angle calculation suspect.", state.dataConvect->CalcBlockenWindwardErrorIDX);
    6189           15 :         return CalcEmmelVertical(WindAt10m, WindDir, SurfAzimuth);
    6190              :     }
    6191              : }
    6192              : 
    6193           90 : Real64 CalcEmmelVertical(Real64 const WindAt10m,
    6194              :                          Real64 const WindDir,     // Wind direction measured clockwise from geographic North
    6195              :                          Real64 const SurfAzimuth) // or Facing, Direction the surface outward normal faces (degrees)
    6196              : {
    6197              : 
    6198              :     // FUNCTION INFORMATION:
    6199              :     //       AUTHOR         Brent Griffith
    6200              :     //       DATE WRITTEN   Aug 2010
    6201              : 
    6202              :     // PURPOSE OF THIS FUNCTION:
    6203              :     // calculate model equation for forced convection using Emmel correlation
    6204              :     // for vertical walls
    6205              : 
    6206              :     // REFERENCES:
    6207              :     // Emmel, M.G., M.O. Abadie, N. Mendes. 2007. New external convective
    6208              :     //   heat transfer coefficient correlations for isolated low-rise buildings.
    6209              :     //   Energy and Buildings 39 (2007) 335- 342
    6210              : 
    6211           90 :     Real64 Theta = CalcWindSurfaceTheta(WindDir, SurfAzimuth); // angle between wind and surface azimuth
    6212              : 
    6213           90 :     if (Theta <= 22.5) {
    6214           15 :         return 5.15 * std::pow(WindAt10m, 0.81);
    6215           75 :     } else if (Theta <= 67.5) {
    6216           15 :         return 3.34 * std::pow(WindAt10m, 0.84);
    6217           60 :     } else if (Theta <= 112.5) {
    6218           15 :         return 4.78 * std::pow(WindAt10m, 0.71);
    6219           45 :     } else if (Theta <= 157.5) {
    6220           30 :         return 4.05 * std::pow(WindAt10m, 0.77);
    6221              :     } else {
    6222           15 :         return 3.54 * std::pow(WindAt10m, 0.76);
    6223              :     }
    6224              : }
    6225              : 
    6226           75 : Real64 CalcEmmelRoof(Real64 const WindAt10m,
    6227              :                      Real64 const WindDir,                // Wind direction measured clockwise from geographic North
    6228              :                      Real64 const LongAxisOutwardAzimuth) // or Facing, Direction the surface outward normal faces (degrees)
    6229              : {
    6230              : 
    6231              :     // FUNCTION INFORMATION:
    6232              :     //       AUTHOR         Brent Griffith
    6233              :     //       DATE WRITTEN   Aug 2010
    6234              : 
    6235              :     // PURPOSE OF THIS FUNCTION:
    6236              :     // calculate model equation for forced convection using Emmel correlation
    6237              :     // for horizontal roofs
    6238              : 
    6239              :     // REFERENCES:
    6240              :     // Emmel, M.G., M.O. Abadie, N. Mendes. 2007. New external convective
    6241              :     //   heat transfer coefficient correlations for isolated low-rise buildings.
    6242              :     //    Energy and Buildings 39 (2007) 335- 342
    6243              : 
    6244           75 :     Real64 Theta = CalcWindSurfaceTheta(WindDir, LongAxisOutwardAzimuth); // angle between wind and surface azimuth
    6245              : 
    6246           75 :     if (Theta <= 22.5) {
    6247           15 :         return 5.11 * std::pow(WindAt10m, 0.78);
    6248           60 :     } else if (Theta <= 67.5) {
    6249           15 :         return 4.60 * std::pow(WindAt10m, 0.79);
    6250           45 :     } else if (Theta <= 112.5) {
    6251           15 :         return 3.67 * std::pow(WindAt10m, 0.85);
    6252           30 :     } else if (Theta <= 157.5) {
    6253           15 :         return 4.60 * std::pow(WindAt10m, 0.79);
    6254              :     } else {
    6255           15 :         return 5.11 * std::pow(WindAt10m, 0.78);
    6256              :     }
    6257              : }
    6258              : 
    6259            1 : Real64 CalcClearRoof(EnergyPlusData &state,
    6260              :                      Real64 const SurfTemp,
    6261              :                      Real64 const AirTemp,
    6262              :                      Real64 const WindAtZ,
    6263              :                      Real64 const RoofArea,
    6264              :                      Real64 const RoofPerimeter,
    6265              :                      Material::SurfaceRoughness const RoughnessIndex)
    6266              : {
    6267              : 
    6268              :     // FUNCTION PARAMETER DEFINITIONS:
    6269            1 :     Real64 constexpr g = 9.81;     // gravity constant (m/s**2)
    6270            1 :     Real64 constexpr v = 15.89e-6; // kinematic viscosity (m**2/s) for air at 300 K
    6271            1 :     Real64 constexpr k = 0.0263;   // thermal conductivity (W/m K) for air at 300 K
    6272            1 :     Real64 constexpr Pr = 0.71;    // Prandtl number for air at ?
    6273              : 
    6274              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    6275              :     Real64 eta;
    6276              : 
    6277              :     // find x, don't know x. avoid time consuming geometry algorithm
    6278            1 :     Real64 x = std::sqrt(RoofArea) / 2.0; // quick simplification, geometry routines to develop
    6279              : 
    6280            1 :     Real64 Ln = (RoofPerimeter > 0.0) ? (RoofArea / RoofPerimeter) : std::sqrt(RoofArea);
    6281            1 :     Real64 DeltaTemp = SurfTemp - AirTemp;
    6282            1 :     Real64 BetaFilm = 1.0 / (Constant::Kelvin + SurfTemp + 0.5 * DeltaTemp);
    6283            1 :     Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, AirTemp, state.dataEnvrn->OutHumRat);
    6284              : 
    6285            1 :     Real64 GrLn = g * pow_2(AirDensity) * pow_3(Ln) * std::abs(DeltaTemp) * BetaFilm / pow_2(v);
    6286            1 :     Real64 RaLn = GrLn * Pr;
    6287              : 
    6288            1 :     Real64 Rex = WindAtZ * AirDensity * x / v;
    6289              : 
    6290            1 :     Real64 Rf = RoughnessMultiplier[(int)RoughnessIndex];
    6291            1 :     if (Rex > 0.1) { // avoid zero and crazy small denominators
    6292            1 :         Real64 tmp = std::log1p(GrLn / pow_2(Rex));
    6293            1 :         eta = tmp / (1.0 + tmp);
    6294              :     } else {
    6295            0 :         eta = 1.0; // forced convection gone because no wind
    6296              :     }
    6297              : 
    6298            1 :     return eta * (k / Ln) * 0.15 * std::pow(RaLn, 1.0 / 3.0) + (k / x) * Rf * 0.0296 * std::pow(Rex, 0.8) * std::pow(Pr, 1.0 / 3.0);
    6299              : }
    6300              : 
    6301            3 : Real64 CalcClearRoof(EnergyPlusData &state,
    6302              :                      int const SurfNum,
    6303              :                      Real64 const SurfTemp,
    6304              :                      Real64 const AirTemp,
    6305              :                      Real64 const WindAtZ,
    6306              :                      [[maybe_unused]] Real64 const WindDirect, // Wind direction measured clockwise from geographic North
    6307              :                      Real64 const RoofArea,
    6308              :                      Real64 const RoofPerimeter)
    6309              : {
    6310              :     Material::SurfaceRoughness const RoughnessIndex =
    6311            3 :         state.dataMaterial->materials(state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).LayerPoint(1))->Roughness;
    6312              :     // find x, don't know x. avoid time consuming geometry algorithm
    6313            3 :     Real64 x = std::sqrt(RoofArea) / 2.0; // quick simplification, geometry routines to develop
    6314              : 
    6315            3 :     if (x > 0.0) {
    6316            1 :         return CalcClearRoof(state, SurfTemp, AirTemp, WindAtZ, RoofArea, RoofPerimeter, RoughnessIndex);
    6317              :     } else {
    6318            2 :         if (state.dataSurface->Surface(SurfNum).ExtBoundCond != DataSurfaces::OtherSideCondModeledExt) {
    6319            1 :             if (state.dataConvect->CalcClearRoofErrorIDX == 0) {
    6320            2 :                 ShowSevereMessage(state, "CalcClearRoof: Convection model not evaluated (bad value for distance to roof edge)");
    6321            1 :                 ShowContinueError(state, format("Value for distance to roof edge ={:.3R}", x));
    6322            1 :                 ShowContinueError(state, format("Occurs for surface named = {}", state.dataSurface->Surface(SurfNum).Name));
    6323            3 :                 ShowContinueError(state, "Convection surface heat transfer coefficient set to 9.999 [W/m2-K] and the simulation continues");
    6324              :             }
    6325            8 :             ShowRecurringSevereErrorAtEnd(
    6326              :                 state,
    6327              :                 "CalcClearRoof: Convection model not evaluated because bad value for distance to roof edge and set to 9.999 [W/m2-k]",
    6328            1 :                 state.dataConvect->CalcClearRoofErrorIDX);
    6329              :         }
    6330            2 :         return 9.9999; // safe but noticeable
    6331              :     }
    6332              : }
    6333              : 
    6334            0 : void CalcASTMC1340ConvCoeff(EnergyPlusData &state,
    6335              :                             int const SurfNum,                  // surface number for which coefficients are being calculated
    6336              :                             Real64 const SurfaceTemperature,    // Temperature of surface for evaluation of HcIn
    6337              :                             Real64 const ZoneMeanAirTemperature // Mean Air Temperature of Zone
    6338              : )
    6339              : {
    6340            0 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    6341              : 
    6342            0 :     int ZoneNum = surface.Zone;
    6343            0 :     Real64 Volume = state.dataHeatBal->Zone(ZoneNum).Volume; // Volume of the zone in m3
    6344            0 :     Real64 Vair = std::pow(Volume, 1.0 / 3.0) * CalcZoneSystemACH(state, ZoneNum) / 3600;
    6345              : 
    6346            0 :     state.dataHeatBalSurf->SurfHConvInt(SurfNum) =
    6347            0 :         CalcASTMC1340ConvCoeff(state, SurfNum, SurfaceTemperature, ZoneMeanAirTemperature, Vair, surface.Tilt);
    6348              : 
    6349              :     // Establish some lower limit to avoid a zero convection coefficient (and potential divide by zero problems)
    6350            0 :     if (state.dataHeatBalSurf->SurfHConvInt(SurfNum) < state.dataHeatBal->LowHConvLimit)
    6351            0 :         state.dataHeatBalSurf->SurfHConvInt(SurfNum) = state.dataHeatBal->LowHConvLimit;
    6352            0 : }
    6353              : 
    6354            3 : Real64 CalcASTMC1340ConvCoeff(EnergyPlusData &state, int const SurfNum, Real64 const Tsurf, Real64 const Tair, Real64 const Vair, Real64 const Tilt)
    6355              : {
    6356              :     // FUNCTION INFORMATION:
    6357              :     //       AUTHOR         Dareum Nam
    6358              :     //       DATE WRITTEN   Feb 2021
    6359              : 
    6360              :     // PURPOSE OF THIS FUNCTION:
    6361              :     // Calculate the inside convection coefficient for attic zones containing radiant barriers
    6362              : 
    6363              :     // REFERENCES:
    6364              :     // 1. ASTM C1340: Standard Practice for Estimation of Heat Gain or Loss Through Ceilings Under Attics
    6365              :     // Containing Radiant Barriers by Use of a Computer Program
    6366              :     // 2. Fontanini, A. D., Aguilar, J. L. C., Mitchell, M. S., Kosny, J., Merket, N., DeGraw, J. W., & Lee, E. (2018).
    6367              :     // Predicting the performance of radiant technologies in attics: Reducing the discrepancies between attic specific
    6368              :     // and whole-building energy models. Energy and Buildings, 169, 69-83.
    6369              : 
    6370              :     Real64 Nun; // Nusselt number for natural convection
    6371              :     Real64 Nuf; // Nusselt number for forced convection
    6372              :     Real64 Grc; // Critical Grashof number
    6373              : 
    6374            3 :     constexpr Real64 g = Constant::Gravity; // Acceleration of gravity, m/s2
    6375              : 
    6376            3 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    6377              : 
    6378              :     // Characteristic length: the length along the heat flow direction
    6379              :     // (the square root of surface area for floors and ceilings,
    6380              :     // average height for gables and walls, and length of pitched roof
    6381              :     // from soffit to ridge) Surface Outside Face Outdoor Air Wind
    6382              :     // Speed (for exterior surfaces)
    6383            3 :     Real64 L = (Tilt == 0 || Tilt == 180) ? std::sqrt(surface.Area) : surface.Height;
    6384              :     // The velocity of the air stream in m/s, (for interior surfaces)
    6385            3 :     Real64 v = (surface.ExtBoundCond == 0) ? state.dataSurface->SurfOutWindSpeed(SurfNum) : Vair;
    6386              :     // Prandtl number
    6387            3 :     Real64 Pr = 0.7880 - (2.631 * std::pow(10, -4) * (Tair + 273.15));
    6388              :     // Volume coefficient of expansion of air, 1/K
    6389            3 :     Real64 beta_SI = 1 / (Tair + 273.15);
    6390              :     // Density of air, kg/m3
    6391            3 :     Real64 rho_SI = (22.0493 / (Tair + 273.15)) * 16;
    6392              :     // Specific heat of air, J/kg.k
    6393            3 :     Real64 cp_SI = 0.068559 * (3.4763 + (1.066 * std::pow(10, -4) * (Tair + 273.15))) * 4186.8;
    6394            3 :     Real64 dv = (241.9 * std::pow(10, -7)) * (145.8 * (Tair + 273.15) * std::pow((Tair + 273.15), 0.5)) / ((Tair + 273.15) + 110.4);
    6395              :     // Kinematic viscosity of air, m2/s
    6396            3 :     Real64 visc = dv * (0.45359237 / (0.3048 * 3600)) / rho_SI;
    6397            3 :     Real64 k_SI_n = (0.6325 * std::pow(10, -5) * std::pow((Tair + 273.15), 0.5) * 241.77);
    6398            3 :     Real64 k_SI_d = (1.0 + (245.4 * std::pow(10, (-12 / (Tair + 273.15)))) / (Tair + 273.15));
    6399              :     // Thermal conductivity of air, W/m.K
    6400            3 :     Real64 k_SI = 1.730735 * (k_SI_n / k_SI_d);
    6401              : 
    6402              :     // Temperature difference between TSurf and Tair
    6403            3 :     Real64 DeltaTemp = Tsurf - Tair;
    6404              : 
    6405              :     // Rayleigh number
    6406            3 :     Real64 Ra = std::abs(g * beta_SI * rho_SI * cp_SI * DeltaTemp * (L * L * L)) / (visc * k_SI);
    6407              :     // Reynolds number
    6408            3 :     Real64 Re = (v * L) / visc;
    6409              : 
    6410              :     // Natural convection (Nun)
    6411            3 :     if (Tilt == 0) {         // Horizontal surface: Roof
    6412            1 :         if (DeltaTemp > 0) { // heat flow down
    6413            1 :             Nun = 0.58 * std::pow(Ra, 0.2);
    6414            0 :         } else if (Ra < 8000000) { // heat flow up
    6415            0 :             Nun = 0.54 * std::pow(Ra, 0.25);
    6416              :         } else {
    6417            0 :             Nun = 0.15 * std::pow(Ra, 1.0 / 3.0);
    6418              :         }
    6419            2 :     } else if (Tilt > 0 && Tilt < 90) { // Tilted roof
    6420            1 :         if (DeltaTemp > 0) {            // heat flow down
    6421            0 :             if (Tilt < 2) {
    6422            0 :                 Nun = 0.58 * std::pow(Ra, 0.2);
    6423              :             } else {
    6424            0 :                 Nun = 0.56 * std::pow(Ra * (std::sin(Tilt * Constant::DegToRad)), 0.25);
    6425              :             }
    6426              :         } else { // heat flow up
    6427            1 :             if (Tilt < 15) {
    6428            0 :                 Grc = 1000000;
    6429            1 :             } else if (Tilt <= 75.0) {
    6430            1 :                 Grc = std::pow(10, Tilt / (1.1870 + (0.0870 * Tilt)));
    6431              :             } else {
    6432            0 :                 Grc = 5000000000;
    6433              :             }
    6434            1 :             if ((Ra / Pr) <= Grc) {
    6435            0 :                 Nun = 0.56 * std::pow(Ra * (std::sin(Tilt * 3.14159 / 180)), 0.25);
    6436              :             } else {
    6437            1 :                 Nun = 0.14 * (std::pow(Ra, Constant::OneThird) - std::pow(Grc * Pr, Constant::OneThird)) +
    6438            1 :                       0.56 * std::pow(Grc * Pr * (std::sin(Tilt * Constant::DegToRad)), 0.25);
    6439              :             }
    6440              :         }
    6441            1 :     } else if (Tilt == 180) { // Horizontal surface: Floor
    6442            0 :         if (DeltaTemp <= 0) { // heat flow down
    6443            0 :             Nun = 0.58 * std::pow(Ra, 0.2);
    6444            0 :         } else if (Ra < 8000000) { // heat flow up
    6445            0 :             Nun = 0.54 * std::pow(Ra, 0.25);
    6446              :         } else {
    6447            0 :             Nun = 0.15 * std::pow(Ra, 1.0 / 3.0);
    6448              :         }
    6449            1 :     } else if (Tilt > 90 && Tilt < 180) { // Tilted Floor
    6450            0 :         if (DeltaTemp <= 0) {             // heat flow down
    6451            0 :             if (Tilt > 178) {
    6452            0 :                 Nun = 0.58 * std::pow(Ra, 0.2);
    6453              :             } else {
    6454            0 :                 Nun = 0.56 * std::pow(Ra * (std::sin(Tilt * Constant::DegToRad)), 0.25);
    6455              :             }
    6456              :         } else { // heat flow up
    6457            0 :             if (Tilt > 165) {
    6458            0 :                 Grc = 1000000;
    6459            0 :             } else if (Tilt <= 105.0) {
    6460            0 :                 Grc = std::pow(10, Tilt / (1.1870 + (0.0870 * Tilt)));
    6461              :             } else {
    6462            0 :                 Grc = 5000000000;
    6463              :             }
    6464            0 :             if ((Ra / Pr) <= Grc) {
    6465            0 :                 Nun = 0.56 * std::pow(Ra * (std::sin(Tilt * Constant::DegToRad)), 0.25);
    6466              :             } else {
    6467            0 :                 Nun = 0.14 * (std::pow(Ra, Constant::OneThird) - std::pow(Grc * Pr, Constant::OneThird)) +
    6468            0 :                       0.56 * std::pow(Grc * Pr * (std::sin(Tilt * Constant::DegToRad)), 0.25);
    6469              :             }
    6470              :         }
    6471              :     } else { // Vertical wall (Tilt = 90)
    6472            1 :         if (Ra < 1000000000) {
    6473            0 :             Nun = 0.59 * std::pow(Ra, 0.25);
    6474              :         } else {
    6475            1 :             Nun = 0.10 * std::pow(Ra, 1.0 / 3.0);
    6476              :         }
    6477              :     }
    6478              : 
    6479              :     // Forced convection (Nuf)
    6480            3 :     if (Re < 500000) {
    6481            1 :         Nuf = 0.664 * std::pow(Pr, 1.0 / 3.0) * std::pow(Re, 0.5);
    6482              :     } else {
    6483            2 :         Nuf = std::pow(Pr, 1.0 / 3.0) * ((0.037 * std::pow(Re, 0.8)) - 850);
    6484              :     }
    6485              : 
    6486              :     // Combined convection coefficient
    6487            3 :     Real64 hf = Nuf * k_SI / L;
    6488            3 :     Real64 hn = Nun * k_SI / L;
    6489            3 :     return std::pow((std::pow(hf, 3) + std::pow(hn, 3)), 1.0 / 3.0);
    6490              : }
    6491              : 
    6492         2337 : SurfOrientation GetSurfConvOrientation(Real64 const Tilt)
    6493              : {
    6494         2337 :     if (Tilt < 5.0) {
    6495          318 :         return SurfOrientation::HorizontalDown;
    6496         2019 :     } else if ((Tilt >= 5.0) && (Tilt < 85.0)) {
    6497           97 :         return SurfOrientation::TiltedDownward;
    6498         1922 :     } else if ((Tilt >= 85.0) && (Tilt < 95.0)) {
    6499         1439 :         return SurfOrientation::Vertical;
    6500          483 :     } else if ((Tilt >= 95.0) && (Tilt < 175.0)) {
    6501           30 :         return SurfOrientation::TiltedUpward;
    6502          453 :     } else if (Tilt >= 175.0) {
    6503          453 :         return SurfOrientation::HorizontalUp;
    6504              :     } else {
    6505            0 :         return SurfOrientation::Invalid;
    6506              :     }
    6507              : }
    6508              : 
    6509            9 : Real64 SurroundingSurfacesRadCoeffAverage(EnergyPlusData &state, int const SurfNum, Real64 const TSurfK, Real64 const AbsExt)
    6510              : {
    6511              :     // compute exterior surfaces LW radiation transfer coefficient to surrounding surfaces
    6512              :     // the surface.SrdSurfTemp is weighed by surrounding surfaces view factor
    6513            9 :     Real64 HSrdSurf = 0.0;
    6514            9 :     auto const &surface = state.dataSurface->Surface(SurfNum);
    6515            9 :     Real64 SrdSurfsTK = surface.SrdSurfTemp + Constant::Kelvin;
    6516            9 :     if (TSurfK != SrdSurfsTK) {
    6517            9 :         HSrdSurf = Constant::StefanBoltzmann * AbsExt * surface.ViewFactorSrdSurfs * (pow_4(TSurfK) - pow_4(SrdSurfsTK)) / (TSurfK - SrdSurfsTK);
    6518              :     }
    6519            9 :     return HSrdSurf;
    6520              : }
    6521              : 
    6522              : } // namespace EnergyPlus::Convect
        

Generated by: LCOV version 2.0-1