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