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