LCOV - code coverage report
Current view: top level - EnergyPlus - ConvectionCoefficients.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1562 3143 49.7 %
Date: 2024-08-24 18:31:18 Functions: 85 214 39.7 %

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

Generated by: LCOV version 1.14