LCOV - code coverage report
Current view: top level - EnergyPlus - ConvectionCoefficients.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 50.1 % 3168 1587
Test Date: 2025-06-02 07:23:51 Functions: 40.1 % 212 85

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

Generated by: LCOV version 2.0-1