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 <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array1D.hh>
53 : #include <ObjexxFCL/member.functions.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Autosizing/Base.hh>
57 : #include <EnergyPlus/ConvectionCoefficients.hh>
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataEnvironment.hh>
60 : #include <EnergyPlus/DataHVACGlobals.hh>
61 : #include <EnergyPlus/DataHeatBalFanSys.hh>
62 : #include <EnergyPlus/DataHeatBalSurface.hh>
63 : #include <EnergyPlus/DataHeatBalance.hh>
64 : #include <EnergyPlus/DataLoopNode.hh>
65 : #include <EnergyPlus/DataRoomAirModel.hh>
66 : #include <EnergyPlus/DataSizing.hh>
67 : #include <EnergyPlus/DataSurfaces.hh>
68 : #include <EnergyPlus/DataZoneEquipment.hh>
69 : #include <EnergyPlus/General.hh>
70 : #include <EnergyPlus/InternalHeatGains.hh>
71 : #include <EnergyPlus/Psychrometrics.hh>
72 : #include <EnergyPlus/UFADManager.hh>
73 : #include <EnergyPlus/UtilityRoutines.hh>
74 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
75 :
76 : namespace EnergyPlus {
77 :
78 : namespace RoomAir {
79 :
80 : // Module containing the routines dealing with the UnderFloor Air
81 : // Distribution zone model
82 :
83 : // MODULE INFORMATION:
84 : // AUTHOR Fred Buhl
85 : // DATE WRITTEN August 2005
86 :
87 : // PURPOSE OF THIS MODULE:
88 : // Encapsulate the routines that do the simulation of the UCSD UFAD non-uniform
89 : // zone models
90 :
91 : // METHODOLOGY EMPLOYED:
92 : // 2-node zone model with the node heights varying as a function of internal loads
93 : // and supply air flow (and other factors)
94 :
95 : // REFERENCES:
96 : // See the EnergyPlus Engineering Reference and the PhD thesis of Anna Liu, UC San Diego
97 :
98 : // OTHER NOTES:
99 : // na
100 :
101 : // Using/Aliasing
102 : using namespace DataLoopNode;
103 : using namespace DataEnvironment;
104 : using namespace DataHeatBalance;
105 : using namespace DataHeatBalSurface;
106 : using namespace DataSurfaces;
107 : using Convect::CalcDetailedHcInForDVModel;
108 :
109 0 : void ManageUFAD(EnergyPlusData &state,
110 : int const ZoneNum, // index number for the specified zone
111 : RoomAirModel const ZoneModelType // type of zone model; UCSDUFI = 6
112 : )
113 : {
114 :
115 : // SUBROUTINE INFORMATION:
116 : // AUTHOR Fred Buhl
117 : // DATE WRITTEN August, 2005
118 : // MODIFIED na
119 : // RE-ENGINEERED na
120 :
121 : // PURPOSE OF THIS SUBROUTINE:
122 : // Manages the simulation of the 2-node nonuniform zone models for underfloor air
123 : // distribution systems (UFAD). Called from RoomAirManager, ManageAirModel
124 :
125 : // METHODOLOGY EMPLOYED:
126 : // uses Init and Calc routines in the standard EPlus manner to manage the calculation
127 : // Note that much of the initialization is done in RoomAirManager, SharedDVCVUFDataInit
128 :
129 : // Using/Aliasing
130 : using namespace DataLoopNode;
131 : using namespace DataEnvironment;
132 : using namespace DataHeatBalance;
133 : using namespace DataHeatBalSurface;
134 : using namespace DataSurfaces;
135 : using Convect::CalcDetailedHcInForDVModel;
136 :
137 : // input was obtained in RoomAirManager, GetUFADIntZoneData
138 :
139 0 : InitUFAD(state, ZoneNum, ZoneModelType); // initialize some module variables
140 :
141 0 : switch (ZoneModelType) {
142 0 : case RoomAirModel::UFADInt: { // UCSD UFAD interior zone model
143 : // simulate room airflow using the UCSDUFI model
144 0 : CalcUFADInt(state, ZoneNum);
145 0 : } break;
146 0 : case RoomAirModel::UFADExt: { // UCSD UFAD exterior zone model
147 : // simulate room airflow using the UCSDUFE model
148 0 : CalcUFADExt(state, ZoneNum);
149 0 : } break;
150 0 : default:
151 0 : break;
152 : }
153 0 : }
154 :
155 0 : void InitUFAD(EnergyPlusData &state,
156 : int const ZoneNum,
157 : RoomAirModel const ZoneModelType // type of zone model; UCSDUFI = 6
158 : )
159 : {
160 :
161 : // SUBROUTINE INFORMATION:
162 : // AUTHOR Fred Buhl
163 : // DATE WRITTEN August 2005
164 :
165 : // PURPOSE OF THIS SUBROUTINE:
166 : // initialize arrays & variables used by the UCSD UFAD zone models
167 :
168 : // METHODOLOGY EMPLOYED:
169 : // Note that much of the initialization is done in RoomAirManager, SharedDVCVUFDataInit
170 :
171 0 : Real64 NumShadesDown(0.0);
172 :
173 : // Do the one time initializations
174 0 : if (state.dataUFADManager->MyOneTimeFlag) {
175 0 : state.dataUFADManager->HeightFloorSubzoneTop = 0.2;
176 0 : state.dataUFADManager->ThickOccupiedSubzoneMin = 0.2;
177 0 : state.dataUFADManager->HeightIntMassDefault = 2.0;
178 0 : state.dataUFADManager->MyOneTimeFlag = false;
179 0 : state.dataUFADManager->MySizeFlag.dimension(state.dataGlobal->NumOfZones, true);
180 : }
181 :
182 0 : if (state.dataUFADManager->MySizeFlag(ZoneNum)) {
183 0 : SizeUFAD(state, ZoneNum, ZoneModelType);
184 0 : state.dataUFADManager->MySizeFlag(ZoneNum) = false;
185 : }
186 :
187 : // initialize these variables every timestep
188 :
189 0 : state.dataUFADManager->HeightIntMass = state.dataUFADManager->HeightIntMassDefault;
190 0 : state.dataRoomAir->ZoneUFADGamma(ZoneNum) = 0.0;
191 0 : state.dataRoomAir->ZoneUFADPowInPlumes(ZoneNum) = 0.0;
192 0 : NumShadesDown = 0.0;
193 0 : for (int Ctd = state.dataRoomAir->PosZ_Window(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Window(ZoneNum).end; ++Ctd) {
194 0 : int SurfNum = state.dataRoomAir->APos_Window(Ctd);
195 0 : if (SurfNum == 0) continue;
196 0 : auto const &surf = state.dataSurface->Surface(SurfNum);
197 0 : if (surf.ExtBoundCond == ExternalEnvironment || surf.ExtBoundCond == OtherSideCoefNoCalcExt ||
198 0 : surf.ExtBoundCond == OtherSideCoefCalcExt || surf.ExtBoundCond == OtherSideCondModeledExt) {
199 0 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
200 0 : ++NumShadesDown;
201 : }
202 : }
203 : }
204 0 : if (ZoneModelType == RoomAirModel::UFADExt) {
205 0 : auto &zoneUE = state.dataRoomAir->ZoneUFAD(state.dataRoomAir->ZoneUFADPtr(ZoneNum));
206 0 : zoneUE.ShadeDown = (zoneUE.NumExtWin > 1.0) && (NumShadesDown / zoneUE.NumExtWin >= 0.5);
207 : }
208 0 : }
209 :
210 0 : void SizeUFAD(EnergyPlusData &state,
211 : int const ZoneNum,
212 : RoomAirModel const model // type of zone model; UCSDUFI = 6
213 : )
214 : {
215 :
216 : // SUBROUTINE INFORMATION:
217 : // AUTHOR Fred Buhl
218 : // DATE WRITTEN August 2005
219 :
220 : // PURPOSE OF THIS SUBROUTINE:
221 : // set some smart defaults for UFAD systems
222 :
223 : // METHODOLOGY EMPLOYED:
224 : // use data from Center for Built Environment
225 :
226 : using DataSizing::AutoSize;
227 :
228 : // This is for both UFADInt and UFADExt
229 0 : auto &zoneU = state.dataRoomAir->ZoneUFAD(state.dataRoomAir->ZoneUFADPtr(ZoneNum));
230 :
231 : std::string_view cCMO = (model == RoomAirModel::UFADExt) ? "RoomAirSettings:UnderFloorAirDistributionExterior"
232 0 : : "RoomAirSettings:UnderFloorAirDistributionInterior";
233 :
234 0 : Real64 NumberOfOccupants = 0.0;
235 0 : for (auto const &people : state.dataHeatBal->People) {
236 0 : if (people.ZonePtr == ZoneNum) NumberOfOccupants += people.NumberOfPeople;
237 : }
238 :
239 0 : if (model == RoomAirModel::UFADExt) {
240 : // calculate total window width in zone
241 0 : for (int Ctd = state.dataRoomAir->PosZ_Window(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Window(ZoneNum).end; ++Ctd) {
242 0 : int SurfNum = state.dataRoomAir->APos_Window(Ctd);
243 0 : if (SurfNum == 0) continue;
244 0 : auto &surf = state.dataSurface->Surface(SurfNum);
245 0 : if (surf.ExtBoundCond == ExternalEnvironment || surf.ExtBoundCond == OtherSideCoefNoCalcExt ||
246 0 : surf.ExtBoundCond == OtherSideCoefCalcExt || surf.ExtBoundCond == OtherSideCondModeledExt) {
247 0 : zoneU.WinWidth += surf.Width;
248 0 : ++zoneU.NumExtWin;
249 : }
250 : }
251 0 : if (zoneU.WinWidth <= 0.0) {
252 0 : ShowWarningError(
253 : state,
254 0 : format("For RoomAirSettings:UnderFloorAirDistributionExterior for Zone {} there are no exterior windows.", zoneU.ZoneName));
255 0 : ShowContinueError(state, " The zone will be treated as a UFAD interior zone");
256 : }
257 : } // if (model == RoomAirModel::UFADExt)
258 :
259 0 : if (zoneU.DiffArea == AutoSize) {
260 0 : constexpr std::array<Real64, (int)Diffuser::Num> diffArea = {0.0075, 0.035, 0.0060, 0.03, 0.0075};
261 0 : zoneU.DiffArea = diffArea[(int)zoneU.DiffuserType];
262 : // 4 ft x 4 inches; 75 cfm per linear foot; area is .025 m2/m
263 :
264 0 : BaseSizer::reportSizerOutput(state, cCMO, zoneU.ZoneName, "Design effective area of diffuser", zoneU.DiffArea);
265 : }
266 0 : if (zoneU.DiffAngle == AutoSize) {
267 0 : constexpr std::array<Real64, (int)Diffuser::Num> diffAngle = {28.0, 45.0, 73.0, 15.0, 28.0};
268 0 : zoneU.DiffAngle = diffAngle[(int)zoneU.DiffuserType];
269 :
270 0 : BaseSizer::reportSizerOutput(state, cCMO, zoneU.ZoneName, "Angle between diffuser slots and the vertical", zoneU.DiffAngle);
271 : }
272 0 : if (zoneU.TransHeight == AutoSize) {
273 0 : zoneU.CalcTransHeight = true;
274 0 : zoneU.TransHeight = 0.0;
275 : } else {
276 0 : zoneU.CalcTransHeight = false;
277 : }
278 :
279 0 : if (zoneU.DiffuserType != Diffuser::Custom &&
280 0 : (zoneU.A_Kc != Constant::AutoCalculate || zoneU.B_Kc != Constant::AutoCalculate || zoneU.C_Kc != Constant::AutoCalculate ||
281 0 : zoneU.D_Kc != Constant::AutoCalculate || zoneU.E_Kc != Constant::AutoCalculate)) {
282 0 : ShowWarningError(state,
283 0 : format("For {} for Zone {}, input for Coefficients A - E will be "
284 : "ignored when Floor Diffuser Type = {}.",
285 : cCMO,
286 0 : zoneU.ZoneName,
287 0 : diffuserNamesUC[(int)zoneU.DiffuserType]));
288 0 : ShowContinueError(state, " To input these Coefficients, use Floor Diffuser Type = Custom.");
289 : }
290 :
291 0 : if (zoneU.DiffuserType == Diffuser::Swirl) {
292 0 : zoneU.A_Kc = 0.0;
293 0 : zoneU.B_Kc = 0.0;
294 0 : zoneU.C_Kc = 0.6531;
295 0 : zoneU.D_Kc = 0.0069;
296 0 : zoneU.E_Kc = -0.00004;
297 0 : } else if (zoneU.DiffuserType == Diffuser::VarArea) {
298 0 : zoneU.A_Kc = 0.0;
299 0 : zoneU.B_Kc = 0.0;
300 0 : zoneU.C_Kc = (model == RoomAirModel::UFADExt) ? 0.83 : 0.88;
301 0 : zoneU.D_Kc = 0.0;
302 0 : zoneU.E_Kc = 0.0;
303 0 : } else if (zoneU.DiffuserType == Diffuser::DisplVent) {
304 0 : zoneU.A_Kc = 0.0;
305 0 : zoneU.B_Kc = 0.0;
306 0 : zoneU.C_Kc = 0.67;
307 0 : zoneU.D_Kc = 0.0;
308 0 : zoneU.E_Kc = 0.0;
309 0 : } else if (zoneU.DiffuserType == Diffuser::LinBarGrille) {
310 0 : zoneU.A_Kc = 0.0;
311 0 : zoneU.B_Kc = 0.0;
312 0 : zoneU.C_Kc = (model == RoomAirModel::UFADExt) ? 0.8214 : 0.8;
313 0 : zoneU.D_Kc = (model == RoomAirModel::UFADExt) ? -0.0263 : 0.0;
314 0 : zoneU.E_Kc = (model == RoomAirModel::UFADExt) ? 0.0014 : 0.0;
315 0 : } else if (zoneU.A_Kc == Constant::AutoCalculate || zoneU.B_Kc == Constant::AutoCalculate || zoneU.C_Kc == Constant::AutoCalculate ||
316 0 : zoneU.D_Kc == Constant::AutoCalculate || zoneU.E_Kc == Constant::AutoCalculate) {
317 0 : ShowFatalError(state,
318 0 : format("For {} for Zone {}, input for Coefficients A - E must be "
319 : "specified when Floor Diffuser Type = Custom.",
320 : cCMO,
321 0 : zoneU.ZoneName));
322 : }
323 :
324 0 : if (zoneU.PowerPerPlume == Constant::AutoCalculate) {
325 :
326 0 : zoneU.PowerPerPlume = sumUFADConvGainPerPlume(state, ZoneNum, NumberOfOccupants);
327 :
328 0 : BaseSizer::reportSizerOutput(state, cCMO, zoneU.ZoneName, "Power per plume [W]", zoneU.PowerPerPlume);
329 :
330 0 : if (zoneU.DiffusersPerZone == AutoSize) {
331 0 : zoneU.DiffusersPerZone = (NumberOfOccupants > 0.0) ? NumberOfOccupants : 1.0;
332 0 : BaseSizer::reportSizerOutput(state, cCMO, zoneU.ZoneName, "Number of diffusers per zone", zoneU.DiffusersPerZone);
333 : }
334 : }
335 :
336 0 : if (zoneU.DiffusersPerZone == AutoSize) {
337 0 : zoneU.DiffusersPerZone = (NumberOfOccupants > 0.0) ? NumberOfOccupants : 1.0;
338 :
339 0 : BaseSizer::reportSizerOutput(state, cCMO, zoneU.ZoneName, "Number of diffusers per zone", zoneU.DiffusersPerZone);
340 : }
341 0 : }
342 :
343 8 : Real64 sumUFADConvGainPerPlume(EnergyPlusData const &state, int const zoneNum, Real64 const numOccupants)
344 : {
345 8 : Real64 zoneElecConv(0.0); // zone elec equip design convective gain [W]
346 48 : for (auto const &zoneElectric : state.dataHeatBal->ZoneElectric) {
347 40 : if (zoneElectric.ZonePtr == zoneNum) {
348 5 : zoneElecConv += zoneElectric.DesignLevel * zoneElectric.FractionConvected;
349 : }
350 : }
351 :
352 8 : Real64 zoneGasConv(0.0); // zone gas equip design convective gain [W]
353 48 : for (auto const &zoneGas : state.dataHeatBal->ZoneGas) {
354 40 : if (zoneGas.ZonePtr == zoneNum) {
355 5 : zoneGasConv += zoneGas.DesignLevel * zoneGas.FractionConvected;
356 : }
357 : }
358 :
359 8 : Real64 zoneOthEqConv(0.0); // zone other equip design convective gain [W]
360 48 : for (auto const &zoneOtherEq : state.dataHeatBal->ZoneOtherEq) {
361 40 : if (zoneOtherEq.ZonePtr == zoneNum) {
362 5 : zoneOthEqConv += zoneOtherEq.DesignLevel * zoneOtherEq.FractionConvected;
363 : }
364 : }
365 :
366 8 : Real64 zoneHWEqConv(0.0); // zone hot water equip design convective gain [W]
367 48 : for (auto const &zoneHWEq : state.dataHeatBal->ZoneHWEq) {
368 40 : if (zoneHWEq.ZonePtr == zoneNum) {
369 5 : zoneHWEqConv += zoneHWEq.DesignLevel * zoneHWEq.FractionConvected;
370 : }
371 : }
372 :
373 8 : Real64 zoneSteamEqConv(0.0); // zone steam equip design convective gain [W]
374 48 : for (auto const &zoneSteamEq : state.dataHeatBal->ZoneSteamEq) {
375 40 : if (zoneSteamEq.ZonePtr == zoneNum) {
376 5 : zoneSteamEqConv += zoneSteamEq.DesignLevel * zoneSteamEq.FractionConvected;
377 : }
378 : }
379 :
380 8 : Real64 numPlumes = (numOccupants > 0.0) ? numOccupants : 1.0;
381 :
382 8 : return (numOccupants * 73.0 + zoneElecConv + zoneGasConv + zoneOthEqConv + zoneHWEqConv + zoneSteamEqConv) / numPlumes;
383 : }
384 :
385 0 : void HcUFAD(EnergyPlusData &state, int const ZoneNum, Real64 const FractionHeight, UFADConvCoef &ufadCC)
386 : {
387 :
388 : // SUBROUTINE INFORMATION:
389 : // AUTHOR G. Carrilho da Graca
390 : // DATE WRITTEN February 2004
391 :
392 : // PURPOSE OF THIS SUBROUTINE:
393 : // Main subroutine for convection calculation in the UCSD Displacement Ventilation model.
394 : // It calls CalcDetailedHcInForDVModel for convection coefficient
395 : // initial calculations and averages the final result comparing the position of the surface with
396 : // the interface subzone height.
397 :
398 : // Using/Aliasing
399 : using namespace DataEnvironment;
400 : using namespace DataHeatBalance;
401 :
402 : // Is the air flow model for this zone set to UCSDDV Displacement Ventilation?
403 0 : if (!state.dataRoomAir->IsZoneUFAD(ZoneNum)) return;
404 :
405 0 : ufadCC.HAT_MX = 0.0; // HAT_MX Convection Coefficient times Area times Temperature for the upper subzone
406 0 : ufadCC.HAT_MXWin = 0.0; // HAT_MX Convection Coefficient times Area times Temperature for the upper subzone (windows only)
407 0 : ufadCC.HA_MX = 0.0; // HA_MX Convection Coefficient times Area for the upper subzone
408 0 : ufadCC.HA_MXWin = 0.0; // HA_MX Convection Coefficient times Area for the upper subzone (windows only)
409 0 : ufadCC.HAT_OC = 0.0; // HAT_OC Convection Coefficient times Area times Temperature for the lower subzone
410 0 : ufadCC.HAT_OCWin = 0.0; // HAT_OC Convection Coefficient times Area times Temperature for the lower subzone (windows only)
411 0 : ufadCC.HA_OC = 0.0; // HA_OC Convection Coefficient times Area for the lower subzone
412 0 : ufadCC.HA_OCWin = 0.0; // HA_OC Convection Coefficient times Area for the lower subzone (windows only)
413 0 : ufadCC.HAT_FLOOR = 0.0; // HAT_FLOOR Convection Coefficient times Area times Temperature for the floor(?) subzone
414 0 : ufadCC.HA_FLOOR = 0.0; // HA_FLOOR Convection Coefficient times Area for the floor(?) subzone
415 :
416 0 : Real64 zoneCeilingHeight1 = state.dataRoomAir->ZoneCeilingHeight1(ZoneNum);
417 0 : Real64 zoneCeilingHeight2 = state.dataRoomAir->ZoneCeilingHeight2(ZoneNum);
418 :
419 0 : Real64 LayH = FractionHeight * (zoneCeilingHeight2 - zoneCeilingHeight1); // Height of the Occupied/Mixed subzone interface
420 :
421 : // WALL Hc, HA and HAT calculation
422 0 : for (int Ctd = state.dataRoomAir->PosZ_Wall(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Wall(ZoneNum).end; ++Ctd) {
423 0 : int SurfNum = state.dataRoomAir->APos_Wall(Ctd);
424 0 : if (SurfNum == 0) continue;
425 :
426 0 : auto &surf = state.dataSurface->Surface(SurfNum);
427 0 : state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
428 0 : state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
429 0 : Real64 ZSupSurf = maxval(surf.Vertex, &Vector::z) - zoneCeilingHeight1; // highest height for this surface
430 0 : Real64 ZInfSurf = minval(surf.Vertex, &Vector::z) - zoneCeilingHeight1; // lowest height for this surface
431 :
432 : // The Wall surface is in the upper subzone
433 0 : if (ZInfSurf > LayH) {
434 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
435 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
436 0 : state.dataRoomAir->HWall(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
437 0 : ufadCC.HAT_MX += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWall(Ctd);
438 0 : ufadCC.HA_MX += surf.Area * state.dataRoomAir->HWall(Ctd);
439 : }
440 :
441 : // The Wall surface is in the lower subzone
442 0 : if (ZSupSurf < LayH) {
443 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
444 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
445 0 : state.dataRoomAir->HWall(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
446 0 : ufadCC.HAT_OC += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWall(Ctd);
447 0 : ufadCC.HA_OC += surf.Area * state.dataRoomAir->HWall(Ctd);
448 : }
449 :
450 0 : if (std::abs(ZInfSurf - ZSupSurf) < 1.e-10) {
451 0 : ShowSevereError(state, "RoomAirModelUFAD:HcUCSDUF: Surface values will cause divide by zero.");
452 0 : ShowContinueError(state, format("Zone=\"{}\", Surface=\"{}\".", state.dataHeatBal->Zone(surf.Zone).Name, surf.Name));
453 0 : ShowContinueError(state, format("ZInfSurf=[{:.4R}], LayH=[{:.4R}].", ZInfSurf, LayH));
454 0 : ShowContinueError(state, format("ZSupSurf=[{:.4R}], LayH=[{:.4R}].", ZSupSurf, LayH));
455 0 : ShowFatalError(state, "...Previous condition causes termination.");
456 : }
457 :
458 : // The Wall surface is partially in upper and partially in lower subzone
459 0 : if (ZInfSurf <= LayH && ZSupSurf >= LayH) {
460 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
461 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
462 0 : Real64 HLU = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the upper area of surface
463 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
464 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
465 0 : Real64 HLD = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the lower area of surface
466 0 : Real64 TmedDV = ((ZSupSurf - LayH) * state.dataRoomAir->ZTMX(ZoneNum) + (LayH - ZInfSurf) * state.dataRoomAir->ZTOC(ZoneNum)) /
467 0 : (ZSupSurf - ZInfSurf); // Average temperature for DV
468 0 : state.dataRoomAir->HWall(Ctd) = ((LayH - ZInfSurf) * HLD + (ZSupSurf - LayH) * HLU) / (ZSupSurf - ZInfSurf);
469 0 : ufadCC.HAT_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLU;
470 0 : ufadCC.HA_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * HLU;
471 0 : ufadCC.HAT_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLD;
472 0 : ufadCC.HA_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * HLD;
473 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = TmedDV;
474 : }
475 :
476 0 : state.dataRoomAir->UFADHcIn(SurfNum) = state.dataRoomAir->HWall(Ctd);
477 :
478 : } // END WALL
479 :
480 : // WINDOW Hc, HA and HAT CALCULATION
481 0 : for (int Ctd = state.dataRoomAir->PosZ_Window(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Window(ZoneNum).end; ++Ctd) {
482 0 : int SurfNum = state.dataRoomAir->APos_Window(Ctd);
483 0 : if (SurfNum == 0) continue;
484 :
485 0 : auto &surf = state.dataSurface->Surface(SurfNum);
486 0 : state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
487 0 : state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
488 :
489 0 : if (surf.Tilt > 10.0 && surf.Tilt < 170.0) { // Window Wall
490 0 : Real64 ZSupSurf = maxval(surf.Vertex, &Vector::z) - zoneCeilingHeight1;
491 0 : Real64 ZInfSurf = minval(surf.Vertex, &Vector::z) - zoneCeilingHeight1;
492 :
493 0 : if (ZInfSurf > LayH) {
494 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
495 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
496 0 : state.dataRoomAir->HWindow(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
497 0 : ufadCC.HAT_MX += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWindow(Ctd);
498 0 : ufadCC.HA_MX += surf.Area * state.dataRoomAir->HWindow(Ctd);
499 0 : ufadCC.HAT_MXWin += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWindow(Ctd);
500 0 : ufadCC.HA_MXWin += surf.Area * state.dataRoomAir->HWindow(Ctd);
501 : }
502 :
503 0 : if (ZSupSurf < LayH) {
504 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
505 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
506 0 : state.dataRoomAir->HWindow(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
507 0 : ufadCC.HAT_OC += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWindow(Ctd);
508 0 : ufadCC.HA_OC += surf.Area * state.dataRoomAir->HWindow(Ctd);
509 0 : ufadCC.HAT_OCWin += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWindow(Ctd);
510 0 : ufadCC.HA_OCWin += surf.Area * state.dataRoomAir->HWindow(Ctd);
511 : }
512 :
513 0 : if (ZInfSurf <= LayH && ZSupSurf >= LayH) {
514 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
515 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
516 0 : Real64 HLU = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the upper area of surface
517 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
518 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
519 0 : Real64 HLD = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the lower area of surface
520 0 : Real64 TmedDV = ((ZSupSurf - LayH) * state.dataRoomAir->ZTMX(ZoneNum) + (LayH - ZInfSurf) * state.dataRoomAir->ZTOC(ZoneNum)) /
521 0 : (ZSupSurf - ZInfSurf); // Average temperature
522 :
523 0 : state.dataRoomAir->HWindow(Ctd) = ((LayH - ZInfSurf) * HLD + (ZSupSurf - LayH) * HLU) / (ZSupSurf - ZInfSurf);
524 0 : ufadCC.HAT_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLU;
525 0 : ufadCC.HA_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * HLU;
526 0 : ufadCC.HAT_MXWin += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLU;
527 0 : ufadCC.HA_MXWin += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * HLU;
528 0 : ufadCC.HAT_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLD;
529 0 : ufadCC.HA_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * HLD;
530 0 : ufadCC.HAT_OCWin += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLD;
531 0 : ufadCC.HA_OCWin += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * HLD;
532 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = TmedDV;
533 : }
534 : }
535 :
536 0 : if (surf.Tilt <= 10.0) { // Window Ceiling
537 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
538 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
539 0 : state.dataRoomAir->HWindow(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
540 0 : ufadCC.HAT_MX += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWindow(Ctd);
541 0 : ufadCC.HA_MX += surf.Area * state.dataRoomAir->HWindow(Ctd);
542 0 : } else if (surf.Tilt >= 170.0) { // Window Floor
543 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
544 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
545 0 : state.dataRoomAir->HWindow(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
546 0 : ufadCC.HAT_OC += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HWindow(Ctd);
547 0 : ufadCC.HA_OC += surf.Area * state.dataRoomAir->HWindow(Ctd);
548 : }
549 :
550 0 : state.dataRoomAir->UFADHcIn(SurfNum) = state.dataRoomAir->HWindow(Ctd);
551 :
552 : } // END WINDOW
553 :
554 : // DOOR Hc, HA and HAT CALCULATION
555 0 : for (int Ctd = state.dataRoomAir->PosZ_Door(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Door(ZoneNum).end; ++Ctd) { // DOOR
556 0 : int SurfNum = state.dataRoomAir->APos_Door(Ctd);
557 0 : if (SurfNum == 0) continue;
558 0 : auto &surf = state.dataSurface->Surface(SurfNum);
559 0 : state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
560 0 : state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
561 :
562 0 : Real64 ZSupSurf = maxval(surf.Vertex, &Vector::z) - zoneCeilingHeight1;
563 0 : Real64 ZInfSurf = minval(surf.Vertex, &Vector::z) - zoneCeilingHeight1;
564 :
565 0 : if (ZInfSurf > LayH) {
566 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
567 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
568 0 : state.dataRoomAir->HDoor(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
569 0 : ufadCC.HAT_MX += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HDoor(Ctd);
570 0 : ufadCC.HA_MX += surf.Area * state.dataRoomAir->HDoor(Ctd);
571 : }
572 :
573 0 : if (ZSupSurf < LayH) {
574 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
575 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
576 0 : state.dataRoomAir->HDoor(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
577 0 : ufadCC.HAT_OC += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HDoor(Ctd);
578 0 : ufadCC.HA_OC += surf.Area * state.dataRoomAir->HDoor(Ctd);
579 : }
580 :
581 0 : if (ZInfSurf <= LayH && ZSupSurf >= LayH) {
582 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
583 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
584 0 : Real64 HLU = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the upper area of surface
585 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
586 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
587 0 : Real64 HLD = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the lower area of surface
588 0 : Real64 TmedDV = ((ZSupSurf - LayH) * state.dataRoomAir->ZTMX(ZoneNum) + (LayH - ZInfSurf) * state.dataRoomAir->ZTOC(ZoneNum)) /
589 0 : (ZSupSurf - ZInfSurf); // Average temperature
590 0 : state.dataRoomAir->HDoor(Ctd) = ((LayH - ZInfSurf) * HLD + (ZSupSurf - LayH) * HLU) / (ZSupSurf - ZInfSurf);
591 0 : ufadCC.HAT_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLU;
592 0 : ufadCC.HA_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * HLU;
593 0 : ufadCC.HAT_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLD;
594 0 : ufadCC.HA_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * HLD;
595 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = TmedDV;
596 : }
597 :
598 0 : state.dataRoomAir->UFADHcIn(SurfNum) = state.dataRoomAir->HDoor(Ctd);
599 :
600 : } // END DOOR
601 :
602 : // INTERNAL Hc, HA and HAT CALCULATION
603 0 : state.dataUFADManager->HeightIntMass = min(state.dataUFADManager->HeightIntMassDefault, (zoneCeilingHeight2 - zoneCeilingHeight1));
604 0 : for (int Ctd = state.dataRoomAir->PosZ_Internal(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Internal(ZoneNum).end; ++Ctd) {
605 0 : int SurfNum = state.dataRoomAir->APos_Internal(Ctd);
606 0 : if (SurfNum == 0) continue;
607 :
608 0 : auto const &surf = state.dataSurface->Surface(SurfNum);
609 0 : state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
610 0 : state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
611 0 : Real64 ZSupSurf = state.dataUFADManager->HeightIntMass;
612 0 : Real64 ZInfSurf = 0.0;
613 :
614 0 : if (ZSupSurf < LayH) {
615 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
616 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
617 0 : state.dataRoomAir->HInternal(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
618 0 : ufadCC.HAT_OC += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HInternal(Ctd);
619 0 : ufadCC.HA_OC += surf.Area * state.dataRoomAir->HInternal(Ctd);
620 : }
621 :
622 0 : if (ZInfSurf <= LayH && ZSupSurf >= LayH) {
623 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
624 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
625 0 : Real64 HLU = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the upper area of surface
626 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTOC(ZoneNum);
627 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
628 0 : Real64 HLD = state.dataRoomAir->UFADHcIn(SurfNum); // Convection coefficient for the lower area of surface
629 0 : Real64 TmedDV = ((ZSupSurf - LayH) * state.dataRoomAir->ZTMX(ZoneNum) + (LayH - ZInfSurf) * state.dataRoomAir->ZTOC(ZoneNum)) /
630 0 : (ZSupSurf - ZInfSurf); // Average temperature
631 0 : state.dataRoomAir->HInternal(Ctd) = ((LayH - ZInfSurf) * HLD + (ZSupSurf - LayH) * HLU) / (ZSupSurf - ZInfSurf);
632 0 : ufadCC.HAT_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLU;
633 0 : ufadCC.HA_MX += surf.Area * (ZSupSurf - LayH) / (ZSupSurf - ZInfSurf) * HLU;
634 0 : ufadCC.HAT_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * state.dataHeatBalSurf->SurfTempIn(SurfNum) * HLD;
635 0 : ufadCC.HA_OC += surf.Area * (LayH - ZInfSurf) / (ZSupSurf - ZInfSurf) * HLD;
636 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = TmedDV;
637 : }
638 :
639 0 : state.dataRoomAir->UFADHcIn(SurfNum) = state.dataRoomAir->HInternal(Ctd);
640 : } // END INTERNAL
641 :
642 : // CEILING Hc, HA and HAT CALCULATION
643 0 : for (int Ctd = state.dataRoomAir->PosZ_Ceiling(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Ceiling(ZoneNum).end; ++Ctd) {
644 0 : int SurfNum = state.dataRoomAir->APos_Ceiling(Ctd);
645 0 : if (SurfNum == 0) continue;
646 0 : auto const &surf = state.dataSurface->Surface(SurfNum);
647 :
648 0 : state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
649 0 : state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
650 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTMX(ZoneNum);
651 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
652 0 : state.dataRoomAir->HCeiling(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
653 0 : ufadCC.HAT_MX += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HCeiling(Ctd);
654 0 : ufadCC.HA_MX += surf.Area * state.dataRoomAir->HCeiling(Ctd);
655 0 : state.dataRoomAir->UFADHcIn(SurfNum) = state.dataRoomAir->HCeiling(Ctd);
656 : } // END CEILING
657 :
658 : // FLOOR Hc, HA and HAT CALCULATION
659 0 : for (int Ctd = state.dataRoomAir->PosZ_Floor(ZoneNum).beg; Ctd <= state.dataRoomAir->PosZ_Floor(ZoneNum).end; ++Ctd) {
660 0 : int SurfNum = state.dataRoomAir->APos_Floor(Ctd);
661 0 : if (SurfNum == 0) continue;
662 0 : auto const &surf = state.dataSurface->Surface(SurfNum);
663 :
664 0 : state.dataSurface->SurfTAirRef(SurfNum) = DataSurfaces::RefAirTemp::AdjacentAirTemp;
665 0 : state.dataSurface->SurfTAirRefRpt(SurfNum) = DataSurfaces::SurfTAirRefReportVals[state.dataSurface->SurfTAirRef(SurfNum)];
666 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTFloor(ZoneNum);
667 0 : CalcDetailedHcInForDVModel(state, SurfNum, state.dataHeatBalSurf->SurfTempIn, state.dataRoomAir->UFADHcIn);
668 0 : state.dataRoomAir->HFloor(Ctd) = state.dataRoomAir->UFADHcIn(SurfNum);
669 0 : ufadCC.HAT_OC += surf.Area * state.dataHeatBalSurf->SurfTempIn(SurfNum) * state.dataRoomAir->HFloor(Ctd);
670 0 : ufadCC.HA_OC += surf.Area * state.dataRoomAir->HFloor(Ctd);
671 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = state.dataRoomAir->ZTFloor(ZoneNum);
672 0 : state.dataRoomAir->UFADHcIn(SurfNum) = state.dataRoomAir->HFloor(Ctd);
673 : } // END FLOOR
674 : }
675 :
676 : static constexpr std::array<DataHeatBalance::IntGainType, 51> IntGainTypesOccupied = {
677 : DataHeatBalance::IntGainType::People,
678 : DataHeatBalance::IntGainType::WaterHeaterMixed,
679 : DataHeatBalance::IntGainType::WaterHeaterStratified,
680 : DataHeatBalance::IntGainType::ThermalStorageChilledWaterMixed,
681 : DataHeatBalance::IntGainType::ThermalStorageChilledWaterStratified,
682 : DataHeatBalance::IntGainType::ElectricEquipment,
683 : DataHeatBalance::IntGainType::ElectricEquipmentITEAirCooled,
684 : DataHeatBalance::IntGainType::GasEquipment,
685 : DataHeatBalance::IntGainType::HotWaterEquipment,
686 : DataHeatBalance::IntGainType::SteamEquipment,
687 : DataHeatBalance::IntGainType::OtherEquipment,
688 : DataHeatBalance::IntGainType::IndoorGreen,
689 : DataHeatBalance::IntGainType::ZoneBaseboardOutdoorTemperatureControlled,
690 : DataHeatBalance::IntGainType::GeneratorFuelCell,
691 : DataHeatBalance::IntGainType::WaterUseEquipment,
692 : DataHeatBalance::IntGainType::GeneratorMicroCHP,
693 : DataHeatBalance::IntGainType::ElectricLoadCenterTransformer,
694 : DataHeatBalance::IntGainType::ElectricLoadCenterInverterSimple,
695 : DataHeatBalance::IntGainType::ElectricLoadCenterInverterFunctionOfPower,
696 : DataHeatBalance::IntGainType::ElectricLoadCenterInverterLookUpTable,
697 : DataHeatBalance::IntGainType::ElectricLoadCenterStorageBattery,
698 : DataHeatBalance::IntGainType::ElectricLoadCenterStorageLiIonNmcBattery,
699 : DataHeatBalance::IntGainType::ElectricLoadCenterStorageSimple,
700 : DataHeatBalance::IntGainType::PipeIndoor,
701 : DataHeatBalance::IntGainType::RefrigerationCase,
702 : DataHeatBalance::IntGainType::RefrigerationCompressorRack,
703 : DataHeatBalance::IntGainType::RefrigerationSystemAirCooledCondenser,
704 : DataHeatBalance::IntGainType::RefrigerationSystemSuctionPipe,
705 : DataHeatBalance::IntGainType::RefrigerationSecondaryReceiver,
706 : DataHeatBalance::IntGainType::RefrigerationSecondaryPipe,
707 : DataHeatBalance::IntGainType::RefrigerationWalkIn,
708 : DataHeatBalance::IntGainType::RefrigerationTransSysAirCooledGasCooler,
709 : DataHeatBalance::IntGainType::RefrigerationTransSysSuctionPipeMT,
710 : DataHeatBalance::IntGainType::RefrigerationTransSysSuctionPipeLT,
711 : DataHeatBalance::IntGainType::Pump_VarSpeed,
712 : DataHeatBalance::IntGainType::Pump_ConSpeed,
713 : DataHeatBalance::IntGainType::Pump_Cond,
714 : DataHeatBalance::IntGainType::PumpBank_VarSpeed,
715 : DataHeatBalance::IntGainType::PumpBank_ConSpeed,
716 : DataHeatBalance::IntGainType::PlantComponentUserDefined,
717 : DataHeatBalance::IntGainType::CoilUserDefined,
718 : DataHeatBalance::IntGainType::ZoneHVACForcedAirUserDefined,
719 : DataHeatBalance::IntGainType::AirTerminalUserDefined,
720 : DataHeatBalance::IntGainType::PackagedTESCoilTank,
721 : DataHeatBalance::IntGainType::SecCoolingDXCoilSingleSpeed,
722 : DataHeatBalance::IntGainType::SecHeatingDXCoilSingleSpeed,
723 : DataHeatBalance::IntGainType::SecCoolingDXCoilTwoSpeed,
724 : DataHeatBalance::IntGainType::SecCoolingDXCoilMultiSpeed,
725 : DataHeatBalance::IntGainType::SecHeatingDXCoilMultiSpeed,
726 : DataHeatBalance::IntGainType::ElectricLoadCenterConverter,
727 : DataHeatBalance::IntGainType::FanSystemModel};
728 :
729 : static constexpr std::array<DataHeatBalance::IntGainType, 2> IntGainTypesUpSubzone = {DataHeatBalance::IntGainType::DaylightingDeviceTubular,
730 : DataHeatBalance::IntGainType::Lights};
731 :
732 : // Explicitly list internal gains not applicable for UFAD
733 : // Explicitly list internal gains not applicable for Displacement Vent
734 : static constexpr std::array<DataHeatBalance::IntGainType, 2> ExcludedIntGainTypes = {
735 : DataHeatBalance::IntGainType::ZoneContaminantSourceAndSinkCarbonDioxide,
736 : DataHeatBalance::IntGainType::ZoneContaminantSourceAndSinkGenericContam};
737 :
738 0 : void CalcUFADInt(EnergyPlusData &state, int const ZoneNum) // index number for the specified zone
739 : {
740 :
741 : // SUBROUTINE INFORMATION:
742 : // AUTHOR Fred Buhl
743 : // DATE WRITTEN August 2005
744 : // MODIFIED Brent Griffith June 2008 for new interpolation and time history
745 : // RE-ENGINEERED na
746 :
747 : // PURPOSE OF THIS SUBROUTINE:
748 : // Using the UCSD UFAD interior zone model, this subroutine calculates the occupied subzone height,
749 : // surface heat transfer coefficients, the occupied subzone temperature, and the upper subzone temperature.
750 :
751 : // METHODOLOGY EMPLOYED:
752 : // The zone is divided into 2 subzones with a variable transition height.
753 :
754 : // REFERENCES:
755 : // The model is described in the EnergyPlus Engineering Reference in Anna Liu's UCSD PhD thesis.
756 :
757 : // Using/Aliasing
758 : using Psychrometrics::PsyCpAirFnW;
759 : using Psychrometrics::PsyRhoAirFnPbTdbW;
760 0 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
761 0 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
762 :
763 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
764 :
765 : Real64 HeightFrac; // Fractional height of transition between occupied and upper subzones
766 : Real64 Gamma; // dimensionless height parameter; higher gamma means interface height will be
767 : // higher, smaller gamma means interface height will be lower.
768 : Real64 ZTAveraged;
769 :
770 : // Exact solution or Euler method
771 0 : if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
772 0 : if (state.dataHVACGlobal->ShortenTimeStepSysRoomAir && TimeStepSys < state.dataGlobal->TimeStepZone) {
773 0 : if (state.dataHVACGlobal->PreviousTimeStep < state.dataGlobal->TimeStepZone) {
774 0 : state.dataRoomAir->Zone1OC(ZoneNum) = state.dataRoomAir->ZoneM2OC(ZoneNum);
775 0 : state.dataRoomAir->Zone1MX(ZoneNum) = state.dataRoomAir->ZoneM2MX(ZoneNum);
776 : } else {
777 0 : state.dataRoomAir->Zone1OC(ZoneNum) = state.dataRoomAir->ZoneMXOC(ZoneNum);
778 0 : state.dataRoomAir->Zone1MX(ZoneNum) = state.dataRoomAir->ZoneMXMX(ZoneNum);
779 : }
780 : } else {
781 0 : state.dataRoomAir->Zone1OC(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
782 0 : state.dataRoomAir->Zone1MX(ZoneNum) = state.dataRoomAir->ZTMX(ZoneNum);
783 : }
784 : }
785 :
786 0 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
787 0 : bool MIXFLAG = false;
788 0 : state.dataRoomAir->UFADHcIn = state.dataHeatBalSurf->SurfHConvInt;
789 0 : Real64 SumSysMCp = 0.0; // Sum of system mass flow rate * specific heat for this zone [W/K]
790 0 : Real64 SumSysMCpT = 0.0; // Sum of system mass flow rate * specific heat * temperature for this zone [W]
791 0 : Real64 TSupK = 0.0; // supply temperature [K]
792 0 : Real64 SumSysM = 0.0; // Sum of systems mass flow rate [kg/s]
793 0 : Real64 TotSysFlow = 0.0; // [m3/s]
794 0 : int ZoneMult = state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier;
795 0 : Real64 CeilingHeight = state.dataRoomAir->ZoneCeilingHeight2(ZoneNum) - state.dataRoomAir->ZoneCeilingHeight1(ZoneNum);
796 :
797 0 : auto &zoneU = state.dataRoomAir->ZoneUFAD(state.dataRoomAir->ZoneUFADPtr(ZoneNum));
798 0 : Real64 HeightThermostat = zoneU.ThermostatHeight; // height of the thermostat above the floor [m]
799 0 : Real64 HeightComfort = zoneU.ComfortHeight; // height at which comfort temperature is calculated
800 0 : Real64 TempDiffCritRep = zoneU.TempTrigger; // Minimum temperature difference between upper and occupied subzones for reporting
801 0 : Real64 DiffArea = zoneU.DiffArea; // diffuser effective area [m2]
802 0 : Real64 ThrowAngle = Constant::DegToRad * zoneU.DiffAngle; // diffuser slot angle relative to vertical [radians]
803 0 : Real64 SourceHeight = 0.0; // height of plume sources above the floor [m]
804 0 : Real64 NumDiffusers = zoneU.DiffusersPerZone;
805 0 : Real64 PowerPerPlume = zoneU.PowerPerPlume;
806 : // gains from occupants, task lighting, elec equip, gas equip, other equip, hot water equip, steam equip,
807 : // baseboards (nonthermostatic), water heater skin loss
808 0 : Real64 ConvGainsOccSubzone = InternalHeatGains::SumInternalConvectionGainsByTypes(state, ZoneNum, IntGainTypesOccupied);
809 :
810 : // Add heat to return air if zonal system (no return air) or cycling system (return air frequently very
811 : // low or zero)
812 0 : if (state.dataHeatBal->Zone(ZoneNum).NoHeatToReturnAir) {
813 0 : ConvGainsOccSubzone += InternalHeatGains::SumReturnAirConvectionGainsByTypes(state, ZoneNum, IntGainTypesOccupied);
814 : }
815 :
816 : // Add convection from pool cover to occupied region
817 0 : ConvGainsOccSubzone += state.dataHeatBalFanSys->SumConvPool(ZoneNum);
818 :
819 : // gains from lights (ceiling), tubular daylighting devices, high temp radiant heaters
820 :
821 0 : Real64 ConvGainsUpSubzone = InternalHeatGains::SumInternalConvectionGainsByTypes(state, ZoneNum, IntGainTypesUpSubzone);
822 0 : ConvGainsUpSubzone += state.dataHeatBalFanSys->SumConvHTRadSys(ZoneNum);
823 0 : if (state.dataHeatBal->Zone(ZoneNum).NoHeatToReturnAir) {
824 0 : ConvGainsUpSubzone += InternalHeatGains::SumReturnAirConvectionGainsByTypes(state, ZoneNum, IntGainTypesUpSubzone);
825 : }
826 :
827 : // Make sure all types of internal gains have been gathered
828 0 : assert((int)(size(IntGainTypesOccupied) + size(IntGainTypesUpSubzone) + size(ExcludedIntGainTypes)) ==
829 : (int)DataHeatBalance::IntGainType::Num);
830 :
831 0 : Real64 ConvGains = ConvGainsOccSubzone + ConvGainsUpSubzone + thisZoneHB.SysDepZoneLoadsLagged;
832 0 : Real64 ZoneEquipConfigNum = zoneU.ZoneEquipPtr;
833 0 : if (ZoneEquipConfigNum > 0) {
834 0 : auto const &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigNum);
835 0 : for (int InNodeIndex = 1; InNodeIndex <= zoneEquipConfig.NumInletNodes; ++InNodeIndex) {
836 0 : Real64 NodeTemp = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(InNodeIndex)).Temp;
837 0 : Real64 MassFlowRate = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(InNodeIndex)).MassFlowRate;
838 0 : Real64 CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
839 0 : SumSysMCp += MassFlowRate * CpAir;
840 0 : SumSysMCpT += MassFlowRate * CpAir * NodeTemp;
841 0 : TotSysFlow += MassFlowRate / PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, NodeTemp, thisZoneHB.airHumRat);
842 0 : TSupK += MassFlowRate * NodeTemp;
843 0 : SumSysM += MassFlowRate;
844 : }
845 0 : if (TotSysFlow > 0.0) {
846 0 : TSupK = TSupK / SumSysM + Constant::Kelvin;
847 : } else {
848 0 : TSupK = 0.0;
849 : }
850 : }
851 : // mass flow rate * specific heat for this zone for infiltration, ventilation, mixing [W/K]
852 0 : Real64 SumMCp = thisZoneHB.MCPI + thisZoneHB.MCPV + thisZoneHB.MCPM + thisZoneHB.MCPE + thisZoneHB.MCPC + thisZoneHB.MDotCPOA;
853 : // mass flow rate * specific heat* temp for this zone for infiltration, ventilation, mixing [W]
854 0 : Real64 SumMCpT = thisZoneHB.MCPTI + thisZoneHB.MCPTV + thisZoneHB.MCPTM + thisZoneHB.MCPTE + thisZoneHB.MCPTC +
855 0 : thisZoneHB.MDotCPOA * state.dataHeatBal->Zone(ZoneNum).OutDryBulbTemp;
856 0 : Real64 MCp_Total = SumMCp + SumSysMCp; // total mass flow rate * specific heat for this zone [W/K]
857 0 : Real64 MCpT_Total = SumMCpT + SumSysMCpT; // total mass flow rate * specific heat* temp for this zone [W]
858 : // For the York MIT diffusers (variable area) the area varies with the flow rate. Assume 400 ft/min velocity
859 : // at the diffuser, and a design flow rate of 150 cfm (.0708 m3/s). Then the design area for each diffuser is
860 : // 150 ft3/min / 400 ft/min = .375 ft2 = .035 m2. This is adjusted each time step by
861 : // (TotSysFlow/(NumDiffusers*.0708))*.035
862 0 : if (zoneU.DiffuserType == Diffuser::VarArea) {
863 0 : DiffArea = 0.035 * TotSysFlow / (0.0708 * NumDiffusers);
864 : }
865 : // initial estimate of convective transfer from surfaces; assume HeightFrac is 0.5.
866 0 : UFADConvCoef ufadCC;
867 0 : HcUFAD(state, ZoneNum, 0.5, ufadCC);
868 0 : Real64 PowerInPlumes = ConvGains + ufadCC.HAT_OC - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum) + ufadCC.HAT_MX -
869 0 : ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum);
870 :
871 0 : Real64 NumberOfPlumes = (PowerPerPlume > 0.0 && PowerInPlumes > 0.0) ? (PowerInPlumes / PowerPerPlume) : 1.0;
872 0 : Real64 NumDiffusersPerPlume = (PowerPerPlume > 0.0 && PowerInPlumes > 0.0) ? (NumDiffusers / NumberOfPlumes) : 1.0;
873 :
874 0 : if ((PowerInPlumes <= 0.0) || (TotSysFlow == 0.0) || (TSupK - Constant::Kelvin) > thisZoneHB.MAT) {
875 : // The system will mix
876 0 : HeightFrac = 0.0;
877 : } else {
878 0 : Gamma = std::pow(TotSysFlow * std::cos(ThrowAngle), 1.5) /
879 0 : (NumberOfPlumes * std::pow(NumDiffusersPerPlume * DiffArea, 1.25) * std::sqrt(0.0281 * 0.001 * PowerInPlumes));
880 0 : if (zoneU.CalcTransHeight) {
881 0 : HeightFrac = (std::sqrt(NumDiffusersPerPlume * DiffArea) * (7.43 * std::log(Gamma) - 1.35) + 0.5 * SourceHeight) / CeilingHeight;
882 : } else {
883 0 : HeightFrac = zoneU.TransHeight / CeilingHeight;
884 : }
885 0 : HeightFrac = max(0.0, min(1.0, HeightFrac));
886 0 : for (int Ctd = 1; Ctd <= 4; ++Ctd) {
887 0 : HcUFAD(state, ZoneNum, HeightFrac, ufadCC);
888 0 : PowerInPlumes = ConvGains + ufadCC.HAT_OC - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum) + ufadCC.HAT_MX -
889 0 : ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum);
890 0 : if (PowerPerPlume > 0.0 && PowerInPlumes > 0.0) {
891 0 : NumberOfPlumes = PowerInPlumes / PowerPerPlume;
892 0 : NumDiffusersPerPlume = NumDiffusers / NumberOfPlumes;
893 : } else {
894 0 : NumberOfPlumes = 1.0;
895 0 : NumDiffusersPerPlume = 1.0;
896 : }
897 0 : if (PowerInPlumes <= 0.0) break;
898 0 : Gamma = std::pow(TotSysFlow * std::cos(ThrowAngle), 1.5) /
899 0 : (NumberOfPlumes * std::pow(NumDiffusersPerPlume * DiffArea, 1.25) * std::sqrt(0.0281 * 0.001 * PowerInPlumes));
900 0 : if (zoneU.CalcTransHeight) {
901 0 : HeightFrac = (std::sqrt(NumDiffusersPerPlume * DiffArea) * (7.43 * std::log(Gamma) - 1.35) + 0.5 * SourceHeight) / CeilingHeight;
902 : } else {
903 0 : HeightFrac = zoneU.TransHeight / CeilingHeight;
904 : }
905 0 : HeightFrac = max(0.0, min(1.0, HeightFrac));
906 0 : state.dataRoomAir->HeightTransition(ZoneNum) = HeightFrac * CeilingHeight;
907 0 : Real64 GainsFrac = zoneU.A_Kc * std::pow(Gamma, zoneU.B_Kc) + zoneU.C_Kc + zoneU.D_Kc * Gamma + zoneU.E_Kc * pow_2(Gamma);
908 0 : GainsFrac = max(0.6, min(GainsFrac, 1.0));
909 0 : state.dataRoomAir->AIRRATOC(ZoneNum) =
910 0 : state.dataHeatBal->Zone(ZoneNum).Volume *
911 0 : (state.dataRoomAir->HeightTransition(ZoneNum) - min(state.dataRoomAir->HeightTransition(ZoneNum), 0.2)) / CeilingHeight *
912 0 : state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpSens *
913 0 : PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, state.dataRoomAir->MATOC(ZoneNum), thisZoneHB.airHumRat) *
914 0 : PsyCpAirFnW(thisZoneHB.airHumRat) / TimeStepSysSec;
915 0 : state.dataRoomAir->AIRRATMX(ZoneNum) =
916 0 : state.dataHeatBal->Zone(ZoneNum).Volume * (CeilingHeight - state.dataRoomAir->HeightTransition(ZoneNum)) / CeilingHeight *
917 0 : state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpSens *
918 0 : PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, state.dataRoomAir->MATMX(ZoneNum), thisZoneHB.airHumRat) *
919 0 : PsyCpAirFnW(thisZoneHB.airHumRat) / TimeStepSysSec;
920 :
921 0 : if (state.dataHVACGlobal->UseZoneTimeStepHistory) {
922 0 : state.dataRoomAir->ZTMOC(ZoneNum)[2] = state.dataRoomAir->XMATOC(ZoneNum)[2];
923 0 : state.dataRoomAir->ZTMOC(ZoneNum)[1] = state.dataRoomAir->XMATOC(ZoneNum)[1];
924 0 : state.dataRoomAir->ZTMOC(ZoneNum)[0] = state.dataRoomAir->XMATOC(ZoneNum)[0];
925 :
926 0 : state.dataRoomAir->ZTMMX(ZoneNum)[2] = state.dataRoomAir->XMATMX(ZoneNum)[2];
927 0 : state.dataRoomAir->ZTMMX(ZoneNum)[1] = state.dataRoomAir->XMATMX(ZoneNum)[1];
928 0 : state.dataRoomAir->ZTMMX(ZoneNum)[0] = state.dataRoomAir->XMATMX(ZoneNum)[0];
929 :
930 : } else {
931 0 : state.dataRoomAir->ZTMOC(ZoneNum)[2] = state.dataRoomAir->DSXMATOC(ZoneNum)[2];
932 0 : state.dataRoomAir->ZTMOC(ZoneNum)[1] = state.dataRoomAir->DSXMATOC(ZoneNum)[1];
933 0 : state.dataRoomAir->ZTMOC(ZoneNum)[0] = state.dataRoomAir->DSXMATOC(ZoneNum)[0];
934 :
935 0 : state.dataRoomAir->ZTMMX(ZoneNum)[2] = state.dataRoomAir->DSXMATMX(ZoneNum)[2];
936 0 : state.dataRoomAir->ZTMMX(ZoneNum)[1] = state.dataRoomAir->DSXMATMX(ZoneNum)[1];
937 0 : state.dataRoomAir->ZTMMX(ZoneNum)[0] = state.dataRoomAir->DSXMATMX(ZoneNum)[0];
938 : }
939 :
940 0 : Real64 AirCap = state.dataRoomAir->AIRRATOC(ZoneNum);
941 0 : Real64 TempHistTerm = AirCap * (3.0 * state.dataRoomAir->ZTMOC(ZoneNum)[0] - (3.0 / 2.0) * state.dataRoomAir->ZTMOC(ZoneNum)[1] +
942 0 : (1.0 / 3.0) * state.dataRoomAir->ZTMOC(ZoneNum)[2]);
943 : // Formerly CoefSumha, coef in zone temp equation with dimensions of h*A
944 0 : Real64 TempDepCoef = GainsFrac * ufadCC.HA_OC + MCp_Total;
945 0 : Real64 TempIndCoef = GainsFrac * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum)) +
946 0 : MCpT_Total + thisZoneHB.NonAirSystemResponse / ZoneMult;
947 0 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
948 0 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
949 0 : state.dataRoomAir->ZTOC(ZoneNum) =
950 0 : (TempHistTerm + GainsFrac * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum)) +
951 0 : MCpT_Total + thisZoneHB.NonAirSystemResponse / ZoneMult) /
952 0 : ((11.0 / 6.0) * AirCap + GainsFrac * ufadCC.HA_OC + MCp_Total);
953 0 : } break;
954 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
955 0 : if (TempDepCoef == 0.0) { // B=0
956 0 : state.dataRoomAir->ZTOC(ZoneNum) = state.dataRoomAir->Zone1OC(ZoneNum) + TempIndCoef / AirCap;
957 : } else {
958 0 : state.dataRoomAir->ZTOC(ZoneNum) =
959 0 : (state.dataRoomAir->Zone1OC(ZoneNum) - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) +
960 0 : TempIndCoef / TempDepCoef;
961 : }
962 0 : } break;
963 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
964 0 : state.dataRoomAir->ZTOC(ZoneNum) = (AirCap * state.dataRoomAir->Zone1OC(ZoneNum) + TempIndCoef) / (AirCap + TempDepCoef);
965 0 : } break;
966 0 : default:
967 0 : break;
968 : }
969 0 : AirCap = state.dataRoomAir->AIRRATMX(ZoneNum);
970 0 : TempHistTerm = AirCap * (3.0 * state.dataRoomAir->ZTMMX(ZoneNum)[0] - (3.0 / 2.0) * state.dataRoomAir->ZTMMX(ZoneNum)[1] +
971 0 : (1.0 / 3.0) * state.dataRoomAir->ZTMMX(ZoneNum)[2]);
972 0 : TempDepCoef = (1.0 - GainsFrac) * ufadCC.HA_MX + MCp_Total;
973 0 : TempIndCoef = (1.0 - GainsFrac) * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum)) +
974 0 : state.dataRoomAir->ZTOC(ZoneNum) * MCp_Total;
975 0 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
976 0 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
977 0 : state.dataRoomAir->ZTMX(ZoneNum) =
978 0 : (TempHistTerm +
979 0 : (1.0 - GainsFrac) * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum)) +
980 0 : state.dataRoomAir->ZTOC(ZoneNum) * MCp_Total) /
981 0 : ((11.0 / 6.0) * AirCap + (1.0 - GainsFrac) * ufadCC.HA_MX + MCp_Total);
982 0 : } break;
983 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
984 0 : if (TempDepCoef == 0.0) { // B=0
985 0 : state.dataRoomAir->ZTMX(ZoneNum) = state.dataRoomAir->Zone1MX(ZoneNum) + TempIndCoef / AirCap;
986 : } else {
987 0 : state.dataRoomAir->ZTMX(ZoneNum) =
988 0 : (state.dataRoomAir->Zone1MX(ZoneNum) - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) +
989 0 : TempIndCoef / TempDepCoef;
990 : }
991 0 : } break;
992 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
993 0 : state.dataRoomAir->ZTMX(ZoneNum) = (AirCap * state.dataRoomAir->Zone1MX(ZoneNum) + TempIndCoef) / (AirCap + TempDepCoef);
994 0 : } break;
995 0 : default:
996 0 : break;
997 : }
998 0 : state.dataRoomAir->ZTFloor(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
999 : }
1000 0 : if (PowerInPlumes <= 0.0) {
1001 0 : HeightFrac = 0.0;
1002 0 : state.dataRoomAir->AirModel(ZoneNum).SimAirModel = false;
1003 0 : state.dataRoomAir->ZoneUFADGamma(ZoneNum) = 0.0;
1004 0 : state.dataRoomAir->ZoneUFADPowInPlumes(ZoneNum) = 0.0;
1005 : } else {
1006 0 : state.dataRoomAir->AirModel(ZoneNum).SimAirModel = true;
1007 0 : state.dataRoomAir->ZoneUFADGamma(ZoneNum) = Gamma;
1008 0 : state.dataRoomAir->ZoneUFADPowInPlumes(ZoneNum) = PowerInPlumes;
1009 : }
1010 : }
1011 :
1012 : //=============================== M I X E D Calculation ==============================================
1013 0 : if (state.dataRoomAir->ZTMX(ZoneNum) < state.dataRoomAir->ZTOC(ZoneNum) || MCp_Total <= 0.0 ||
1014 0 : HeightFrac * CeilingHeight < state.dataUFADManager->ThickOccupiedSubzoneMin) {
1015 0 : MIXFLAG = true;
1016 0 : HeightFrac = 0.0;
1017 0 : state.dataRoomAir->AvgTempGrad(ZoneNum) = 0.0;
1018 0 : state.dataRoomAir->MaxTempGrad(ZoneNum) = 0.0;
1019 0 : state.dataRoomAir->AirModel(ZoneNum).SimAirModel = false;
1020 0 : Real64 AirCap = thisZoneHB.AirPowerCap;
1021 0 : Real64 TempHistTerm = AirCap * (3.0 * thisZoneHB.ZTM[0] - (3.0 / 2.0) * thisZoneHB.ZTM[1] + (1.0 / 3.0) * thisZoneHB.ZTM[2]);
1022 :
1023 0 : for (int Ctd = 1; Ctd <= 3; ++Ctd) {
1024 0 : Real64 TempDepCoef = ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total;
1025 0 : Real64 const thisZoneT1 = thisZoneHB.T1;
1026 : // Formerly CoefSumhat, coef in zone temp equation with dimensions of h*A(T1
1027 0 : Real64 TempIndCoef = ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total;
1028 0 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
1029 0 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
1030 0 : ZTAveraged = (TempHistTerm + ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total) /
1031 0 : ((11.0 / 6.0) * AirCap + ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total);
1032 0 : } break;
1033 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
1034 0 : if (TempDepCoef == 0.0) { // B=0
1035 0 : ZTAveraged = thisZoneT1 + TempIndCoef / AirCap;
1036 : } else {
1037 0 : ZTAveraged =
1038 0 : (thisZoneT1 - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) + TempIndCoef / TempDepCoef;
1039 : }
1040 0 : } break;
1041 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
1042 0 : ZTAveraged = (AirCap * thisZoneT1 + TempIndCoef) / (AirCap + TempDepCoef);
1043 0 : } break;
1044 0 : default:
1045 0 : break;
1046 : }
1047 0 : state.dataRoomAir->ZTOC(ZoneNum) = ZTAveraged;
1048 0 : state.dataRoomAir->ZTMX(ZoneNum) = ZTAveraged;
1049 0 : state.dataRoomAir->ZTFloor(ZoneNum) = ZTAveraged;
1050 0 : HcUFAD(state, ZoneNum, HeightFrac, ufadCC);
1051 0 : TempDepCoef = ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total;
1052 0 : TempIndCoef = ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total;
1053 0 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
1054 0 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
1055 0 : ZTAveraged = (TempHistTerm + ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total) /
1056 0 : ((11.0 / 6.0) * AirCap + ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total);
1057 0 : } break;
1058 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
1059 0 : if (TempDepCoef == 0.0) { // B=0
1060 0 : ZTAveraged = thisZoneT1 + TempIndCoef / AirCap;
1061 : } else {
1062 0 : ZTAveraged =
1063 0 : (thisZoneT1 - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) + TempIndCoef / TempDepCoef;
1064 : }
1065 0 : } break;
1066 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
1067 0 : ZTAveraged = (AirCap * thisZoneT1 + TempIndCoef) / (AirCap + TempDepCoef);
1068 0 : } break;
1069 0 : default:
1070 0 : break;
1071 : }
1072 0 : state.dataRoomAir->ZTOC(ZoneNum) = ZTAveraged;
1073 0 : state.dataRoomAir->ZTMX(ZoneNum) = ZTAveraged;
1074 0 : state.dataRoomAir->ZTFloor(ZoneNum) = ZTAveraged;
1075 : }
1076 : }
1077 : //=========================================================================================
1078 :
1079 : // Comfort temperature and temperature at the thermostat/temperature control sensor
1080 :
1081 0 : state.dataRoomAir->HeightTransition(ZoneNum) = HeightFrac * CeilingHeight;
1082 0 : Real64 HeightUpSubzoneAve = (CeilingHeight + state.dataRoomAir->HeightTransition(ZoneNum)) / 2.0;
1083 0 : Real64 HeightOccupiedSubzoneAve = state.dataRoomAir->HeightTransition(ZoneNum) / 2.0;
1084 : // Comfort temperature
1085 :
1086 0 : if (MIXFLAG) {
1087 0 : state.dataRoomAir->TCMF(ZoneNum) = ZTAveraged;
1088 : } else {
1089 0 : if (HeightComfort < HeightOccupiedSubzoneAve) {
1090 0 : state.dataRoomAir->TCMF(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
1091 0 : } else if (HeightComfort >= HeightOccupiedSubzoneAve && HeightComfort < HeightUpSubzoneAve) {
1092 0 : state.dataRoomAir->TCMF(ZoneNum) = (state.dataRoomAir->ZTOC(ZoneNum) * (HeightUpSubzoneAve - HeightComfort) +
1093 0 : state.dataRoomAir->ZTMX(ZoneNum) * (HeightComfort - HeightOccupiedSubzoneAve)) /
1094 0 : (HeightUpSubzoneAve - HeightOccupiedSubzoneAve);
1095 0 : } else if (HeightComfort >= HeightUpSubzoneAve && HeightComfort <= CeilingHeight) {
1096 0 : state.dataRoomAir->TCMF(ZoneNum) = state.dataRoomAir->ZTMX(ZoneNum);
1097 : } else {
1098 0 : ShowFatalError(state,
1099 0 : format("UFAD comfort height is above ceiling or below floor in Zone: {}", state.dataHeatBal->Zone(ZoneNum).Name));
1100 : }
1101 : }
1102 :
1103 : // Temperature at the thermostat/temperature control sensor
1104 :
1105 0 : if (MIXFLAG) {
1106 0 : state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = ZTAveraged;
1107 : } else {
1108 0 : if (HeightThermostat < HeightOccupiedSubzoneAve) {
1109 0 : state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
1110 0 : } else if (HeightThermostat >= HeightOccupiedSubzoneAve && HeightThermostat < HeightUpSubzoneAve) {
1111 0 : state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = (state.dataRoomAir->ZTOC(ZoneNum) * (HeightUpSubzoneAve - HeightThermostat) +
1112 0 : state.dataRoomAir->ZTMX(ZoneNum) * (HeightThermostat - HeightOccupiedSubzoneAve)) /
1113 0 : (HeightUpSubzoneAve - HeightOccupiedSubzoneAve);
1114 0 : } else if (HeightThermostat >= HeightUpSubzoneAve && HeightThermostat <= CeilingHeight) {
1115 0 : state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = state.dataRoomAir->ZTMX(ZoneNum);
1116 : } else {
1117 0 : ShowFatalError(state,
1118 0 : format("Underfloor air distribution thermostat height is above ceiling or below floor in Zone: {}",
1119 0 : state.dataHeatBal->Zone(ZoneNum).Name));
1120 : }
1121 : }
1122 :
1123 : // Temperature gradients
1124 0 : if ((HeightUpSubzoneAve - HeightOccupiedSubzoneAve) > 0.1) {
1125 0 : state.dataRoomAir->AvgTempGrad(ZoneNum) =
1126 0 : (state.dataRoomAir->ZTMX(ZoneNum) - state.dataRoomAir->ZTOC(ZoneNum)) / (HeightUpSubzoneAve - HeightOccupiedSubzoneAve);
1127 : } else {
1128 0 : state.dataRoomAir->AvgTempGrad(ZoneNum) = 0.0;
1129 : }
1130 :
1131 0 : if (MIXFLAG) {
1132 0 : state.dataRoomAir->ZoneUFADMixedFlag(ZoneNum) = 1;
1133 0 : state.dataRoomAir->AirModel(ZoneNum).SimAirModel = false;
1134 : } else {
1135 0 : state.dataRoomAir->ZoneUFADMixedFlag(ZoneNum) = 0;
1136 0 : state.dataRoomAir->AirModel(ZoneNum).SimAirModel = true;
1137 : }
1138 :
1139 0 : if (ZoneEquipConfigNum > 0) {
1140 0 : int ZoneNodeNum = state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber;
1141 0 : state.dataLoopNodes->Node(ZoneNodeNum).Temp = state.dataRoomAir->ZTMX(ZoneNum);
1142 : }
1143 :
1144 0 : if (MIXFLAG) {
1145 0 : state.dataRoomAir->Phi(ZoneNum) = 1.0;
1146 : } else {
1147 0 : state.dataRoomAir->Phi(ZoneNum) =
1148 0 : (state.dataRoomAir->ZTOC(ZoneNum) - (TSupK - Constant::Kelvin)) / (state.dataRoomAir->ZTMX(ZoneNum) - (TSupK - Constant::Kelvin));
1149 : }
1150 :
1151 : // Mixed for reporting purposes
1152 0 : if ((MIXFLAG) || ((state.dataRoomAir->ZTMX(ZoneNum) - state.dataRoomAir->ZTOC(ZoneNum)) < TempDiffCritRep)) {
1153 0 : state.dataRoomAir->ZoneUFADMixedFlagRep(ZoneNum) = 1.0;
1154 0 : state.dataRoomAir->HeightTransition(ZoneNum) = 0.0;
1155 0 : state.dataRoomAir->AvgTempGrad(ZoneNum) = 0.0;
1156 : } else {
1157 0 : state.dataRoomAir->ZoneUFADMixedFlagRep(ZoneNum) = 0.0;
1158 : }
1159 0 : }
1160 :
1161 0 : void CalcUFADExt(EnergyPlusData &state, int const ZoneNum) // index number for the specified zone
1162 : {
1163 : // SUBROUTINE INFORMATION:
1164 : // AUTHOR Fred Buhl
1165 : // DATE WRITTEN January 2006
1166 : // MODIFIED Brent Griffith June 2008 for new interpolation and time history
1167 : // RE-ENGINEERED na
1168 :
1169 : // PURPOSE OF THIS SUBROUTINE:
1170 : // Using the UCSD UFAD exterior zone model, this subroutine calculates the occupied subzone height,
1171 : // surface heat transfer coefficients, the occupied subzone temperature, and the upper subzone temperature.
1172 :
1173 : // METHODOLOGY EMPLOYED:
1174 : // The zone is divided into 2 subzones with a variable transition height.
1175 :
1176 : // REFERENCES:
1177 : // The model is described in the EnergyPlus Engineering Reference in Anna Liu's UCSD PhD thesis.
1178 :
1179 : // Using/Aliasing
1180 : using Psychrometrics::PsyCpAirFnW;
1181 : using Psychrometrics::PsyRhoAirFnPbTdbW;
1182 0 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
1183 0 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
1184 : using InternalHeatGains::SumInternalConvectionGainsByTypes;
1185 : using InternalHeatGains::SumReturnAirConvectionGainsByTypes;
1186 :
1187 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1188 :
1189 : Real64 PowerInPlumesPerMeter; // Power in Plumes per meter of window length [W/m]
1190 : Real64 ZTAveraged;
1191 :
1192 : // Exact solution or Euler method
1193 0 : if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
1194 0 : if (state.dataHVACGlobal->ShortenTimeStepSysRoomAir && TimeStepSys < state.dataGlobal->TimeStepZone) {
1195 0 : if (state.dataHVACGlobal->PreviousTimeStep < state.dataGlobal->TimeStepZone) {
1196 0 : state.dataRoomAir->Zone1OC(ZoneNum) = state.dataRoomAir->ZoneM2OC(ZoneNum);
1197 0 : state.dataRoomAir->Zone1MX(ZoneNum) = state.dataRoomAir->ZoneM2MX(ZoneNum);
1198 : } else {
1199 0 : state.dataRoomAir->Zone1OC(ZoneNum) = state.dataRoomAir->ZoneMXOC(ZoneNum);
1200 0 : state.dataRoomAir->Zone1MX(ZoneNum) = state.dataRoomAir->ZoneMXMX(ZoneNum);
1201 : }
1202 : } else {
1203 0 : state.dataRoomAir->Zone1OC(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
1204 0 : state.dataRoomAir->Zone1MX(ZoneNum) = state.dataRoomAir->ZTMX(ZoneNum);
1205 : }
1206 : }
1207 :
1208 0 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
1209 0 : Real64 HeightFrac = 0.0; // Fractional height of transition between occupied and upper subzones
1210 0 : bool MIXFLAG = false;
1211 0 : state.dataRoomAir->UFADHcIn = state.dataHeatBalSurf->SurfHConvInt;
1212 0 : Real64 SumSysMCp = 0.0; // Sum of system mass flow rate * specific heat for this zone [W/K]
1213 0 : Real64 SumSysMCpT = 0.0; // Sum of system mass flow rate * specific heat * temperature for this zone [W]
1214 0 : Real64 TotSysFlow = 0.0; // [m3/s]
1215 0 : Real64 TSupK = 0.0; // supply temperature [K]
1216 0 : Real64 SumSysM = 0.0; // Sum of systems mass flow rate [kg/s]
1217 0 : Real64 PowerInPlumes = 0.0; // [W]
1218 0 : Real64 Gamma = 0.0; // dimensionless height parameter; higher gamma means interface height will be
1219 : // higher, smaller gamma means interface height will be lower.
1220 0 : int ZoneMult = state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier;
1221 0 : Real64 CeilingHeight = state.dataRoomAir->ZoneCeilingHeight2(ZoneNum) - state.dataRoomAir->ZoneCeilingHeight1(ZoneNum);
1222 :
1223 0 : auto &zoneU = state.dataRoomAir->ZoneUFAD(state.dataRoomAir->ZoneUFADPtr(ZoneNum));
1224 0 : Real64 HeightThermostat = zoneU.ThermostatHeight; // height of the thermostat above the floor [m]
1225 0 : Real64 HeightComfort = zoneU.ComfortHeight; // height at which comfort temperature is calculated
1226 0 : Real64 TempDiffCritRep = zoneU.TempTrigger; // Minimum temperature difference between upper and occupied subzones for reporting
1227 0 : Real64 DiffArea = zoneU.DiffArea; // diffuser effective area [m2]
1228 0 : Real64 ThrowAngle = Constant::DegToRad * zoneU.DiffAngle; // diffuser slot angle relative to vertical [radians]
1229 0 : Real64 SourceHeight = zoneU.HeatSrcHeight; // height of plume sources above the floor [m]
1230 0 : Real64 NumDiffusers = zoneU.DiffusersPerZone;
1231 0 : Real64 PowerPerPlume = zoneU.PowerPerPlume;
1232 : // gains from occupants, task lighting, elec equip, gas equip, other equip, hot water equip, steam equip,
1233 : // baseboards (nonthermostatic), water heater skin loss
1234 0 : Real64 ConvGainsOccSubzone = SumInternalConvectionGainsByTypes(state, ZoneNum, IntGainTypesOccupied);
1235 :
1236 : // Add heat to return air if zonal system (no return air) or cycling system (return air frequently very
1237 : // low or zero)
1238 0 : if (state.dataHeatBal->Zone(ZoneNum).NoHeatToReturnAir) {
1239 0 : ConvGainsOccSubzone += SumReturnAirConvectionGainsByTypes(state, ZoneNum, IntGainTypesOccupied);
1240 : }
1241 :
1242 : // Add convection from pool cover to occupied region
1243 0 : ConvGainsOccSubzone += state.dataHeatBalFanSys->SumConvPool(ZoneNum);
1244 :
1245 : // gains from lights (ceiling), tubular daylighting devices, high temp radiant heaters
1246 : Real64 ConvGainsUpSubzone =
1247 0 : SumInternalConvectionGainsByTypes(state, ZoneNum, IntGainTypesUpSubzone); // convective heat gains into the upper subzone [W]
1248 0 : ConvGainsUpSubzone += state.dataHeatBalFanSys->SumConvHTRadSys(ZoneNum);
1249 0 : if (state.dataHeatBal->Zone(ZoneNum).NoHeatToReturnAir) {
1250 0 : ConvGainsUpSubzone += SumReturnAirConvectionGainsByTypes(state, ZoneNum, IntGainTypesUpSubzone);
1251 : }
1252 0 : Real64 ConvGains =
1253 0 : ConvGainsOccSubzone + ConvGainsUpSubzone + thisZoneHB.SysDepZoneLoadsLagged; // total zone convective gains (excluding surfaces) [W]
1254 0 : int ZoneEquipConfigNum = zoneU.ZoneEquipPtr;
1255 0 : if (ZoneEquipConfigNum > 0) {
1256 0 : auto const &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigNum);
1257 0 : for (int InNodeIndex = 1; InNodeIndex <= zoneEquipConfig.NumInletNodes; ++InNodeIndex) {
1258 0 : Real64 NodeTemp = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(InNodeIndex)).Temp;
1259 0 : Real64 MassFlowRate = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(InNodeIndex)).MassFlowRate;
1260 0 : Real64 CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
1261 0 : SumSysMCp += MassFlowRate * CpAir;
1262 0 : SumSysMCpT += MassFlowRate * CpAir * NodeTemp;
1263 0 : TotSysFlow += MassFlowRate / PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, NodeTemp, thisZoneHB.airHumRat);
1264 0 : TSupK += MassFlowRate * NodeTemp;
1265 0 : SumSysM += MassFlowRate;
1266 : }
1267 0 : if (TotSysFlow > 0.0) {
1268 0 : TSupK = TSupK / SumSysM + Constant::Kelvin;
1269 : } else {
1270 0 : TSupK = 0.0;
1271 : }
1272 : }
1273 :
1274 : // mass flow rate * specific heat for this zone for infiltration, ventilation, mixing [W/K]
1275 0 : Real64 SumMCp = thisZoneHB.MCPI + thisZoneHB.MCPV + thisZoneHB.MCPM + thisZoneHB.MDotCPOA;
1276 : // mass flow rate * specific heat* temp for this zone for infiltration, ventilation, mixing [W]
1277 : Real64 SumMCpT =
1278 0 : thisZoneHB.MCPTI + thisZoneHB.MCPTV + thisZoneHB.MCPTM + thisZoneHB.MDotCPOA * state.dataHeatBal->Zone(ZoneNum).OutDryBulbTemp;
1279 :
1280 0 : Real64 MCp_Total = SumMCp + SumSysMCp; // total mass flow rate * specific heat for this zone [W/K]
1281 0 : Real64 MCpT_Total = SumMCpT + SumSysMCpT; // total mass flow rate * specific heat* temp for this zone [W]
1282 :
1283 : // For the York MIT diffusers (variable area) the area varies with the flow rate. Assume 400 ft/min velocity
1284 : // at the diffuser, and a design flow rate of 150 cfm (.0708 m3/s). Then the design area for each diffuser is
1285 : // 150 ft3/min / 400 ft/min = .375 ft2 = .035 m2. This is adjusted each time step by
1286 : // (TotSysFlow/(NumDiffusers*.0708))*.035
1287 0 : if (zoneU.DiffuserType == Diffuser::VarArea) {
1288 0 : DiffArea = 0.035 * TotSysFlow / (0.0708 * NumDiffusers);
1289 : }
1290 : // initial estimate of convective transfer from surfaces; assume HeightFrac is 0.5.
1291 0 : UFADConvCoef ufadCC;
1292 0 : HcUFAD(state, ZoneNum, 0.5, ufadCC);
1293 0 : Real64 ConvGainsWindows = ufadCC.HAT_MXWin + ufadCC.HAT_OCWin - // ZoneEquipConfig index for this UFAD zone
1294 0 : ufadCC.HA_MXWin * state.dataRoomAir->ZTMX(ZoneNum) - ufadCC.HA_OCWin * state.dataRoomAir->ZTOC(ZoneNum);
1295 0 : PowerInPlumes = ConvGains + ufadCC.HAT_OC - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum) + ufadCC.HAT_MX -
1296 0 : ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum);
1297 : // NumberOfPlumes = PowerInPlumes / PowerPerPlume
1298 0 : Real64 NumberOfPlumes = (PowerPerPlume > 0.0 && PowerInPlumes > 0.0) ? (PowerInPlumes / PowerPerPlume) : 1.0;
1299 0 : Real64 NumDiffusersPerPlume = (PowerPerPlume > 0.0 && PowerInPlumes > 0.0) ? (NumDiffusers / NumberOfPlumes) : 1.0;
1300 :
1301 0 : if ((PowerInPlumes <= 0.0) || (TotSysFlow == 0.0) || (TSupK - Constant::Kelvin) > thisZoneHB.MAT) {
1302 : // The system will mix
1303 0 : HeightFrac = 0.0;
1304 : } else {
1305 0 : if (PowerInPlumes > 0.0) {
1306 0 : if (zoneU.WinWidth > 0.0) { // exterior zone formula
1307 0 : PowerInPlumesPerMeter = PowerInPlumes / zoneU.WinWidth;
1308 0 : Gamma =
1309 0 : (TotSysFlow * std::cos(ThrowAngle)) / (NumDiffusers * DiffArea * std::pow(0.0281 * 0.001 * PowerInPlumesPerMeter, 0.333333));
1310 : } else { // interior zone formula
1311 0 : Gamma = std::pow(TotSysFlow * std::cos(ThrowAngle), 1.5) /
1312 0 : (NumberOfPlumes * std::pow(NumDiffusersPerPlume * DiffArea, 1.25) * std::sqrt(0.0281 * 0.001 * PowerInPlumes));
1313 : }
1314 : } else {
1315 0 : Gamma = 1000.0;
1316 : }
1317 0 : if (zoneU.CalcTransHeight) {
1318 0 : if (zoneU.WinWidth > 0.0) { // use exterior zone formula
1319 0 : HeightFrac = (std::sqrt(DiffArea) * (11.03 * std::log(Gamma) - 10.73) + 0.5 * SourceHeight) / CeilingHeight;
1320 : } else { // use interior zone formula
1321 0 : HeightFrac = (std::sqrt(NumDiffusersPerPlume * DiffArea) * (7.43 * std::log(Gamma) - 1.35) + 0.5 * SourceHeight) / CeilingHeight;
1322 : }
1323 : } else {
1324 0 : HeightFrac = zoneU.TransHeight / CeilingHeight;
1325 : }
1326 0 : HeightFrac = max(0.0, min(1.0, HeightFrac));
1327 0 : Real64 GainsFrac = zoneU.A_Kc * std::pow(Gamma, zoneU.B_Kc) + zoneU.C_Kc + zoneU.D_Kc * Gamma + zoneU.E_Kc * pow_2(Gamma);
1328 0 : GainsFrac = max(0.7, min(GainsFrac, 1.0));
1329 0 : if (zoneU.ShadeDown) {
1330 0 : GainsFrac -= 0.2;
1331 : }
1332 0 : state.dataRoomAir->ZoneUFADPowInPlumes(ZoneNum) = PowerInPlumes;
1333 0 : for (int Ctd = 1; Ctd <= 4; ++Ctd) {
1334 0 : HcUFAD(state, ZoneNum, HeightFrac, ufadCC);
1335 0 : ConvGainsWindows = ufadCC.HAT_MXWin + ufadCC.HAT_OCWin - ufadCC.HA_MXWin * state.dataRoomAir->ZTMX(ZoneNum) -
1336 0 : ufadCC.HA_OCWin * state.dataRoomAir->ZTOC(ZoneNum);
1337 0 : ConvGainsWindows = max(ConvGainsWindows, 0.0);
1338 0 : PowerInPlumes = ConvGains + ufadCC.HAT_OC - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum) + ufadCC.HAT_MX -
1339 0 : ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum);
1340 : // NumberOfPlumes = PowerInPlumes / PowerPerPlume
1341 0 : NumberOfPlumes = 1.0;
1342 0 : if (PowerInPlumes <= 0.0) break;
1343 0 : if (zoneU.WinWidth > 0.0) { // use exterior zone formula
1344 0 : PowerInPlumesPerMeter = PowerInPlumes / zoneU.WinWidth;
1345 0 : Gamma =
1346 0 : (TotSysFlow * std::cos(ThrowAngle)) / (NumDiffusers * DiffArea * std::pow(0.0281 * 0.001 * PowerInPlumesPerMeter, 0.333333));
1347 : } else { // use interior zone formula
1348 0 : Gamma = std::pow(TotSysFlow * std::cos(ThrowAngle), 1.5) /
1349 0 : (NumberOfPlumes * std::pow(NumDiffusersPerPlume * DiffArea, 1.25) * std::sqrt(0.0281 * 0.001 * PowerInPlumes));
1350 : }
1351 0 : if (zoneU.CalcTransHeight) {
1352 0 : if (zoneU.WinWidth > 0.0) { // exterior zone formula
1353 0 : HeightFrac = (std::sqrt(DiffArea) * (11.03 * std::log(Gamma) - 10.73) + 0.5 * SourceHeight) / CeilingHeight;
1354 : } else { // interior zone formula
1355 0 : HeightFrac =
1356 0 : (std::sqrt(NumDiffusersPerPlume * DiffArea) * (7.43 * std::log(Gamma) - 1.35) + 0.5 * SourceHeight) / CeilingHeight;
1357 : }
1358 : } else {
1359 0 : HeightFrac = zoneU.TransHeight / CeilingHeight;
1360 : }
1361 0 : HeightFrac = min(1.0, HeightFrac);
1362 0 : state.dataRoomAir->HeightTransition(ZoneNum) = HeightFrac * CeilingHeight;
1363 0 : Real64 GainsFrac = zoneU.A_Kc * std::pow(Gamma, zoneU.B_Kc) + zoneU.C_Kc + zoneU.D_Kc * Gamma + zoneU.E_Kc * pow_2(Gamma);
1364 0 : GainsFrac = max(0.7, min(GainsFrac, 1.0));
1365 0 : if (zoneU.ShadeDown) {
1366 0 : GainsFrac -= 0.2;
1367 : }
1368 0 : state.dataRoomAir->AIRRATOC(ZoneNum) =
1369 0 : state.dataHeatBal->Zone(ZoneNum).Volume *
1370 0 : (state.dataRoomAir->HeightTransition(ZoneNum) - min(state.dataRoomAir->HeightTransition(ZoneNum), 0.2)) / CeilingHeight *
1371 0 : state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpSens *
1372 0 : PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, state.dataRoomAir->MATOC(ZoneNum), thisZoneHB.airHumRat) *
1373 0 : PsyCpAirFnW(thisZoneHB.airHumRat) / TimeStepSysSec;
1374 0 : state.dataRoomAir->AIRRATMX(ZoneNum) =
1375 0 : state.dataHeatBal->Zone(ZoneNum).Volume * (CeilingHeight - state.dataRoomAir->HeightTransition(ZoneNum)) / CeilingHeight *
1376 0 : state.dataHeatBal->Zone(ZoneNum).ZoneVolCapMultpSens *
1377 0 : PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, state.dataRoomAir->MATMX(ZoneNum), thisZoneHB.airHumRat) *
1378 0 : PsyCpAirFnW(thisZoneHB.airHumRat) / TimeStepSysSec;
1379 :
1380 0 : if (state.dataHVACGlobal->UseZoneTimeStepHistory) {
1381 0 : state.dataRoomAir->ZTMOC(ZoneNum)[2] = state.dataRoomAir->XMATOC(ZoneNum)[2];
1382 0 : state.dataRoomAir->ZTMOC(ZoneNum)[1] = state.dataRoomAir->XMATOC(ZoneNum)[1];
1383 0 : state.dataRoomAir->ZTMOC(ZoneNum)[0] = state.dataRoomAir->XMATOC(ZoneNum)[0];
1384 :
1385 0 : state.dataRoomAir->ZTMMX(ZoneNum)[2] = state.dataRoomAir->XMATMX(ZoneNum)[2];
1386 0 : state.dataRoomAir->ZTMMX(ZoneNum)[1] = state.dataRoomAir->XMATMX(ZoneNum)[1];
1387 0 : state.dataRoomAir->ZTMMX(ZoneNum)[0] = state.dataRoomAir->XMATMX(ZoneNum)[0];
1388 :
1389 : } else {
1390 0 : state.dataRoomAir->ZTMOC(ZoneNum)[2] = state.dataRoomAir->DSXMATOC(ZoneNum)[2];
1391 0 : state.dataRoomAir->ZTMOC(ZoneNum)[1] = state.dataRoomAir->DSXMATOC(ZoneNum)[1];
1392 0 : state.dataRoomAir->ZTMOC(ZoneNum)[0] = state.dataRoomAir->DSXMATOC(ZoneNum)[0];
1393 :
1394 0 : state.dataRoomAir->ZTMMX(ZoneNum)[2] = state.dataRoomAir->DSXMATMX(ZoneNum)[2];
1395 0 : state.dataRoomAir->ZTMMX(ZoneNum)[1] = state.dataRoomAir->DSXMATMX(ZoneNum)[1];
1396 0 : state.dataRoomAir->ZTMMX(ZoneNum)[0] = state.dataRoomAir->DSXMATMX(ZoneNum)[0];
1397 : }
1398 :
1399 0 : Real64 AirCap = state.dataRoomAir->AIRRATOC(ZoneNum);
1400 0 : Real64 TempHistTerm = AirCap * (3.0 * state.dataRoomAir->ZTMOC(ZoneNum)[0] - (3.0 / 2.0) * state.dataRoomAir->ZTMOC(ZoneNum)[1] +
1401 0 : (1.0 / 3.0) * state.dataRoomAir->ZTMOC(ZoneNum)[2]);
1402 0 : Real64 TempDepCoef = GainsFrac * ufadCC.HA_OC + MCp_Total;
1403 0 : Real64 TempIndCoef = GainsFrac * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum)) +
1404 0 : MCpT_Total + thisZoneHB.NonAirSystemResponse / ZoneMult;
1405 0 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
1406 0 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
1407 0 : state.dataRoomAir->ZTOC(ZoneNum) =
1408 0 : (TempHistTerm + GainsFrac * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_MX * state.dataRoomAir->ZTMX(ZoneNum)) +
1409 0 : MCpT_Total + thisZoneHB.NonAirSystemResponse / ZoneMult) /
1410 0 : ((11.0 / 6.0) * AirCap + GainsFrac * ufadCC.HA_OC + MCp_Total);
1411 0 : } break;
1412 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
1413 0 : if (TempDepCoef == 0.0) { // B=0
1414 0 : state.dataRoomAir->ZTOC(ZoneNum) = state.dataRoomAir->Zone1OC(ZoneNum) + TempIndCoef / AirCap;
1415 : } else {
1416 0 : state.dataRoomAir->ZTOC(ZoneNum) =
1417 0 : (state.dataRoomAir->Zone1OC(ZoneNum) - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) +
1418 0 : TempIndCoef / TempDepCoef;
1419 : }
1420 0 : } break;
1421 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
1422 0 : state.dataRoomAir->ZTOC(ZoneNum) = (AirCap * state.dataRoomAir->Zone1OC(ZoneNum) + TempIndCoef) / (AirCap + TempDepCoef);
1423 0 : } break;
1424 0 : default:
1425 0 : break;
1426 : }
1427 0 : AirCap = state.dataRoomAir->AIRRATMX(ZoneNum);
1428 0 : TempHistTerm = AirCap * (3.0 * state.dataRoomAir->ZTMMX(ZoneNum)[0] - (3.0 / 2.0) * state.dataRoomAir->ZTMMX(ZoneNum)[1] +
1429 0 : (1.0 / 3.0) * state.dataRoomAir->ZTMMX(ZoneNum)[2]);
1430 0 : TempDepCoef = (1.0 - GainsFrac) * ufadCC.HA_MX + MCp_Total;
1431 0 : TempIndCoef = (1.0 - GainsFrac) * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum)) +
1432 0 : state.dataRoomAir->ZTOC(ZoneNum) * MCp_Total;
1433 0 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
1434 0 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
1435 0 : state.dataRoomAir->ZTMX(ZoneNum) =
1436 0 : (TempHistTerm +
1437 0 : (1.0 - GainsFrac) * (ConvGains + ufadCC.HAT_OC + ufadCC.HAT_MX - ufadCC.HA_OC * state.dataRoomAir->ZTOC(ZoneNum)) +
1438 0 : state.dataRoomAir->ZTOC(ZoneNum) * MCp_Total) /
1439 0 : ((11.0 / 6.0) * AirCap + (1.0 - GainsFrac) * ufadCC.HA_MX + MCp_Total);
1440 0 : } break;
1441 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
1442 0 : if (TempDepCoef == 0.0) { // B=0
1443 0 : state.dataRoomAir->ZTMX(ZoneNum) = state.dataRoomAir->Zone1MX(ZoneNum) + TempIndCoef / AirCap;
1444 : } else {
1445 0 : state.dataRoomAir->ZTMX(ZoneNum) =
1446 0 : (state.dataRoomAir->Zone1MX(ZoneNum) - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) +
1447 0 : TempIndCoef / TempDepCoef;
1448 : }
1449 0 : } break;
1450 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
1451 0 : state.dataRoomAir->ZTMX(ZoneNum) = (AirCap * state.dataRoomAir->Zone1MX(ZoneNum) + TempIndCoef) / (AirCap + TempDepCoef);
1452 0 : } break;
1453 0 : default:
1454 0 : break;
1455 : }
1456 0 : state.dataRoomAir->ZTFloor(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
1457 : }
1458 0 : if (PowerInPlumes <= 0.0) {
1459 0 : HeightFrac = 0.0;
1460 0 : state.dataRoomAir->AirModel(ZoneNum).SimAirModel = false;
1461 0 : state.dataRoomAir->ZoneUFADGamma(ZoneNum) = 0.0;
1462 0 : state.dataRoomAir->ZoneUFADPowInPlumes(ZoneNum) = 0.0;
1463 0 : state.dataRoomAir->ZoneUFADPowInPlumesfromWindows(ZoneNum) = 0.0;
1464 : } else {
1465 0 : state.dataRoomAir->AirModel(ZoneNum).SimAirModel = true;
1466 0 : state.dataRoomAir->ZoneUFADGamma(ZoneNum) = Gamma;
1467 0 : state.dataRoomAir->ZoneUFADPowInPlumes(ZoneNum) = PowerInPlumes;
1468 0 : state.dataRoomAir->ZoneUFADPowInPlumesfromWindows(ZoneNum) = ConvGainsWindows;
1469 : }
1470 : }
1471 :
1472 : //=============================== M I X E D Calculation ==============================================
1473 0 : if (state.dataRoomAir->ZTMX(ZoneNum) < state.dataRoomAir->ZTOC(ZoneNum) || MCp_Total <= 0.0 ||
1474 0 : HeightFrac * CeilingHeight < state.dataUFADManager->ThickOccupiedSubzoneMin) {
1475 0 : MIXFLAG = true;
1476 0 : HeightFrac = 0.0;
1477 0 : Real64 const thisZoneT1 = thisZoneHB.T1;
1478 :
1479 0 : state.dataRoomAir->AvgTempGrad(ZoneNum) = 0.0;
1480 0 : state.dataRoomAir->MaxTempGrad(ZoneNum) = 0.0;
1481 0 : state.dataRoomAir->AirModel(ZoneNum).SimAirModel = false;
1482 0 : Real64 AirCap = thisZoneHB.AirPowerCap;
1483 0 : Real64 TempHistTerm = AirCap * (3.0 * thisZoneHB.ZTM[0] - (3.0 / 2.0) * thisZoneHB.ZTM[1] + (1.0 / 3.0) * thisZoneHB.ZTM[2]);
1484 :
1485 0 : for (int Ctd = 1; Ctd <= 3; ++Ctd) {
1486 0 : Real64 TempDepCoef = ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total;
1487 0 : Real64 TempIndCoef = ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total;
1488 0 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
1489 0 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
1490 0 : ZTAveraged = (TempHistTerm + ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total) /
1491 0 : ((11.0 / 6.0) * AirCap + ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total);
1492 0 : } break;
1493 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
1494 0 : if (TempDepCoef == 0.0) { // B=0
1495 0 : ZTAveraged = thisZoneT1 + TempIndCoef / AirCap;
1496 : } else {
1497 0 : ZTAveraged =
1498 0 : (thisZoneT1 - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) + TempIndCoef / TempDepCoef;
1499 : }
1500 0 : } break;
1501 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
1502 0 : ZTAveraged = (AirCap * thisZoneT1 + TempIndCoef) / (AirCap + TempDepCoef);
1503 0 : } break;
1504 0 : default:
1505 0 : break;
1506 : }
1507 0 : state.dataRoomAir->ZTOC(ZoneNum) = ZTAveraged;
1508 0 : state.dataRoomAir->ZTMX(ZoneNum) = ZTAveraged;
1509 0 : state.dataRoomAir->ZTFloor(ZoneNum) = ZTAveraged;
1510 0 : HcUFAD(state, ZoneNum, HeightFrac, ufadCC);
1511 0 : TempDepCoef = ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total;
1512 0 : TempIndCoef = ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total;
1513 0 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
1514 0 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
1515 0 : ZTAveraged = (TempHistTerm + ConvGains + ufadCC.HAT_MX + ufadCC.HAT_OC + MCpT_Total) /
1516 0 : ((11.0 / 6.0) * AirCap + ufadCC.HA_MX + ufadCC.HA_OC + MCp_Total);
1517 0 : } break;
1518 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
1519 0 : if (TempDepCoef == 0.0) { // B=0
1520 0 : ZTAveraged = thisZoneT1 + TempIndCoef / AirCap;
1521 : } else {
1522 0 : ZTAveraged =
1523 0 : (thisZoneT1 - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) + TempIndCoef / TempDepCoef;
1524 : }
1525 0 : } break;
1526 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
1527 0 : ZTAveraged = (AirCap * thisZoneT1 + TempIndCoef) / (AirCap + TempDepCoef);
1528 0 : } break;
1529 0 : default:
1530 0 : break;
1531 : }
1532 0 : state.dataRoomAir->ZTOC(ZoneNum) = ZTAveraged;
1533 0 : state.dataRoomAir->ZTMX(ZoneNum) = ZTAveraged;
1534 0 : state.dataRoomAir->ZTFloor(ZoneNum) = ZTAveraged;
1535 : }
1536 : }
1537 : //=========================================================================================
1538 :
1539 : // Comfort temperature and temperature at the thermostat/temperature control sensor
1540 :
1541 0 : Real64 HeightUpSubzoneAve = (CeilingHeight + state.dataRoomAir->HeightTransition(ZoneNum)) / 2.0;
1542 0 : Real64 HeightOccupiedSubzoneAve = state.dataRoomAir->HeightTransition(ZoneNum) / 2.0;
1543 : // Comfort temperature
1544 :
1545 0 : if (MIXFLAG) {
1546 0 : state.dataRoomAir->TCMF(ZoneNum) = ZTAveraged;
1547 : } else {
1548 0 : if (HeightComfort < HeightOccupiedSubzoneAve) {
1549 0 : state.dataRoomAir->TCMF(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
1550 0 : } else if (HeightComfort >= HeightOccupiedSubzoneAve && HeightComfort < HeightUpSubzoneAve) {
1551 0 : state.dataRoomAir->TCMF(ZoneNum) = (state.dataRoomAir->ZTOC(ZoneNum) * (HeightUpSubzoneAve - HeightComfort) +
1552 0 : state.dataRoomAir->ZTMX(ZoneNum) * (HeightComfort - HeightOccupiedSubzoneAve)) /
1553 0 : (HeightUpSubzoneAve - HeightOccupiedSubzoneAve);
1554 0 : } else if (HeightComfort >= HeightUpSubzoneAve && HeightComfort <= CeilingHeight) {
1555 0 : state.dataRoomAir->TCMF(ZoneNum) = state.dataRoomAir->ZTMX(ZoneNum);
1556 : } else {
1557 0 : ShowFatalError(state,
1558 0 : format("UFAD comfort height is above ceiling or below floor in Zone: {}", state.dataHeatBal->Zone(ZoneNum).Name));
1559 : }
1560 : }
1561 :
1562 : // Temperature at the thermostat/temperature control sensor
1563 :
1564 0 : if (MIXFLAG) {
1565 0 : state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = ZTAveraged;
1566 : } else {
1567 0 : if (HeightThermostat < HeightOccupiedSubzoneAve) {
1568 0 : state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = state.dataRoomAir->ZTOC(ZoneNum);
1569 0 : } else if (HeightThermostat >= HeightOccupiedSubzoneAve && HeightThermostat < HeightUpSubzoneAve) {
1570 0 : state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = (state.dataRoomAir->ZTOC(ZoneNum) * (HeightUpSubzoneAve - HeightThermostat) +
1571 0 : state.dataRoomAir->ZTMX(ZoneNum) * (HeightThermostat - HeightOccupiedSubzoneAve)) /
1572 0 : (HeightUpSubzoneAve - HeightOccupiedSubzoneAve);
1573 0 : } else if (HeightThermostat >= HeightUpSubzoneAve && HeightThermostat <= CeilingHeight) {
1574 0 : state.dataHeatBalFanSys->TempTstatAir(ZoneNum) = state.dataRoomAir->ZTMX(ZoneNum);
1575 : } else {
1576 0 : ShowFatalError(state,
1577 0 : format("Underfloor air distribution thermostat height is above ceiling or below floor in Zone: {}",
1578 0 : state.dataHeatBal->Zone(ZoneNum).Name));
1579 : }
1580 : }
1581 :
1582 : // Temperature gradients
1583 0 : if ((HeightUpSubzoneAve - HeightOccupiedSubzoneAve) > 0.1) {
1584 0 : state.dataRoomAir->AvgTempGrad(ZoneNum) =
1585 0 : (state.dataRoomAir->ZTMX(ZoneNum) - state.dataRoomAir->ZTOC(ZoneNum)) / (HeightUpSubzoneAve - HeightOccupiedSubzoneAve);
1586 : } else {
1587 0 : state.dataRoomAir->AvgTempGrad(ZoneNum) = 0.0;
1588 : }
1589 :
1590 0 : if (MIXFLAG) {
1591 0 : state.dataRoomAir->ZoneUFADMixedFlag(ZoneNum) = 1;
1592 0 : state.dataRoomAir->AirModel(ZoneNum).SimAirModel = false;
1593 : } else {
1594 0 : state.dataRoomAir->ZoneUFADMixedFlag(ZoneNum) = 0;
1595 0 : state.dataRoomAir->AirModel(ZoneNum).SimAirModel = true;
1596 : }
1597 :
1598 0 : if (ZoneEquipConfigNum > 0) {
1599 0 : int ZoneNodeNum = state.dataHeatBal->Zone(ZoneNum).SystemZoneNodeNumber;
1600 0 : state.dataLoopNodes->Node(ZoneNodeNum).Temp = state.dataRoomAir->ZTMX(ZoneNum);
1601 : }
1602 :
1603 0 : if (MIXFLAG) {
1604 0 : state.dataRoomAir->Phi(ZoneNum) = 1.0;
1605 : } else {
1606 0 : state.dataRoomAir->Phi(ZoneNum) =
1607 0 : (state.dataRoomAir->ZTOC(ZoneNum) - (TSupK - Constant::Kelvin)) / (state.dataRoomAir->ZTMX(ZoneNum) - (TSupK - Constant::Kelvin));
1608 : }
1609 :
1610 : // Mixed for reporting purposes
1611 0 : if ((MIXFLAG) || ((state.dataRoomAir->ZTMX(ZoneNum) - state.dataRoomAir->ZTOC(ZoneNum)) < TempDiffCritRep)) {
1612 0 : state.dataRoomAir->ZoneUFADMixedFlagRep(ZoneNum) = 1.0;
1613 0 : state.dataRoomAir->HeightTransition(ZoneNum) = 0.0;
1614 0 : state.dataRoomAir->AvgTempGrad(ZoneNum) = 0.0;
1615 : } else {
1616 0 : state.dataRoomAir->ZoneUFADMixedFlagRep(ZoneNum) = 0.0;
1617 : }
1618 0 : }
1619 :
1620 : } // namespace RoomAir
1621 : } // namespace EnergyPlus
|