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
|