Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // ObjexxFCL Headers
49 : #include <ObjexxFCL/Array.functions.hh>
50 : #include <ObjexxFCL/Array1D.hh>
51 : #include <ObjexxFCL/Fmath.hh>
52 :
53 : // EnergyPlus Headers
54 : #include <AirflowNetwork/Solver.hpp>
55 : #include <EnergyPlus/BaseboardElectric.hh>
56 : #include <EnergyPlus/BaseboardRadiator.hh>
57 : #include <EnergyPlus/Data/EnergyPlusData.hh>
58 : #include <EnergyPlus/DataDefineEquip.hh>
59 : #include <EnergyPlus/DataEnvironment.hh>
60 : #include <EnergyPlus/DataHVACGlobals.hh>
61 : #include <EnergyPlus/DataHeatBalSurface.hh>
62 : #include <EnergyPlus/DataHeatBalance.hh>
63 : #include <EnergyPlus/DataLoopNode.hh>
64 : #include <EnergyPlus/DataMoistureBalance.hh>
65 : #include <EnergyPlus/DataMoistureBalanceEMPD.hh>
66 : #include <EnergyPlus/DataRoomAirModel.hh>
67 : #include <EnergyPlus/DataSurfaceLists.hh>
68 : #include <EnergyPlus/DataSurfaces.hh>
69 : #include <EnergyPlus/DataZoneEquipment.hh>
70 : #include <EnergyPlus/ElectricBaseboardRadiator.hh>
71 : #include <EnergyPlus/FluidProperties.hh>
72 : #include <EnergyPlus/General.hh>
73 : #include <EnergyPlus/GlobalNames.hh>
74 : #include <EnergyPlus/HWBaseboardRadiator.hh>
75 : #include <EnergyPlus/HeatBalFiniteDiffManager.hh>
76 : #include <EnergyPlus/HeatBalanceHAMTManager.hh>
77 : #include <EnergyPlus/HighTempRadiantSystem.hh>
78 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
79 : #include <EnergyPlus/InternalHeatGains.hh>
80 : #include <EnergyPlus/MoistureBalanceEMPDManager.hh>
81 : #include <EnergyPlus/OutputProcessor.hh>
82 : #include <EnergyPlus/Psychrometrics.hh>
83 : #include <EnergyPlus/RefrigeratedCase.hh>
84 : #include <EnergyPlus/RoomAirModelAirflowNetwork.hh>
85 : #include <EnergyPlus/SteamBaseboardRadiator.hh>
86 : #include <EnergyPlus/UtilityRoutines.hh>
87 : #include <EnergyPlus/ZoneAirLoopEquipmentManager.hh>
88 : #include <EnergyPlus/ZoneDehumidifier.hh>
89 : #include <EnergyPlus/ZonePlenum.hh>
90 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
91 :
92 : namespace EnergyPlus {
93 :
94 : namespace RoomAir {
95 :
96 : // MODULE INFORMATION:
97 : // AUTHOR Brent Griffith
98 : // DATE WRITTEN November 2009
99 : // MODIFIED Lixing Gu, Aug. 2015 for v8.4 replease
100 :
101 : // PURPOSE OF THIS MODULE:
102 : // contains the RoomAir model portions of RoomAirflowNetwork modeling
103 :
104 : // METHODOLOGY EMPLOYED:
105 : // Interact with Surface HB, internal gain, HVAC system and Airflow Network Domains
106 : // Do heat and moisture balance calculations on roomair nodes.
107 :
108 : // Using/Aliasing
109 : using namespace DataHeatBalSurface;
110 : using namespace DataSurfaces;
111 : using namespace DataHeatBalance;
112 :
113 7413 : void SimRoomAirModelAFN(EnergyPlusData &state, int const zoneNum) // index number for the specified zone
114 : {
115 :
116 : // SUBROUTINE INFORMATION:
117 : // AUTHOR Brent Griffith
118 : // DATE WRITTEN January 2004/Aug 2005
119 : // MODIFIED Lixing Gu, Aug. 2015 for v8.4 replease
120 :
121 : // PURPOSE OF THIS SUBROUTINE:
122 : // This subroutine manages RoomAirflowNetwork model simulation
123 :
124 : // METHODOLOGY EMPLOYED:
125 : // calls subroutines (LOL)
126 :
127 7413 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
128 :
129 : // model control volume for each roomAir:node in the zone.
130 51891 : for (int roomAirNodeNum = 1; roomAirNodeNum <= afnZoneInfo.NumOfAirNodes; ++roomAirNodeNum) {
131 44478 : InitRoomAirModelAFN(state, zoneNum, roomAirNodeNum);
132 44478 : CalcRoomAirModelAFN(state, zoneNum, roomAirNodeNum);
133 : }
134 :
135 7413 : UpdateRoomAirModelAFN(state, zoneNum);
136 :
137 7413 : } // SimRoomAirModelAirflowNetwork
138 :
139 : //****************************************************
140 :
141 7413 : void LoadPredictionRoomAirModelAFN(EnergyPlusData &state,
142 : int const zoneNum,
143 : int const roomAirNodeNum) // index number for the specified zone and node
144 : {
145 :
146 : // SUBROUTINE INFORMATION:
147 : // AUTHOR Lixing Gu
148 : // DATE WRITTEN June, 2015
149 :
150 : // PURPOSE OF THIS SUBROUTINE:
151 : // Predict zone loads at a controlled node
152 :
153 7413 : InitRoomAirModelAFN(state, zoneNum, roomAirNodeNum);
154 :
155 7413 : } // LoadPredictionRoomAirModelAirflowNetwork
156 :
157 : //****************************************************
158 :
159 51891 : void InitRoomAirModelAFN(EnergyPlusData &state, int const zoneNum,
160 : int const roomAirNodeNum) // index number for the specified zone
161 : {
162 :
163 : // SUBROUTINE INFORMATION:
164 : // AUTHOR B. Griffith
165 : // DATE WRITTEN November 2009
166 : // MODIFIED Lixing Gu, Aug. 2015 for v8.4 release
167 :
168 : // PURPOSE OF THIS SUBROUTINE:
169 : // Perform one-time checking and term calculations
170 :
171 : using InternalHeatGains::SumInternalLatentGainsByTypes;
172 : using Psychrometrics::PsyCpAirFnW;
173 : using Psychrometrics::PsyRhoAirFnPbTdbW;
174 :
175 51891 : Array1D_bool NodeFound; // True if a node is found.
176 51891 : Array1D_bool EquipFound;
177 51891 : bool ErrorsFound = false;
178 51891 : Array1D<Real64> SupplyFrac;
179 51891 : Array1D<Real64> ReturnFrac;
180 :
181 51891 : if (state.dataRoomAirflowNetModel->OneTimeFlag) { // then do one - time setup inits
182 :
183 : // loop over all zones with RoomAirflowNetwork model
184 6 : for (int iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
185 5 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(iZone);
186 5 : if (!afnZoneInfo.IsUsed) continue;
187 1 : int NumSurfs = 0;
188 2 : for (int spaceNum : state.dataHeatBal->Zone(iZone).spaceIndexes) {
189 1 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
190 1 : NumSurfs += thisSpace.HTSurfaceLast - thisSpace.HTSurfaceFirst + 1;
191 1 : }
192 :
193 7 : for (auto &afnNode : afnZoneInfo.Node) {
194 : // calculate volume of air in node's control volume
195 6 : afnNode.AirVolume = state.dataHeatBal->Zone(iZone).Volume * afnNode.ZoneVolumeFraction;
196 :
197 12 : SetupOutputVariable(state,
198 : "RoomAirflowNetwork Node NonAirSystemResponse",
199 : Constant::Units::W,
200 6 : afnNode.NonAirSystemResponse,
201 : OutputProcessor::TimeStepType::System,
202 : OutputProcessor::StoreType::Average,
203 6 : afnNode.Name);
204 12 : SetupOutputVariable(state,
205 : "RoomAirflowNetwork Node SysDepZoneLoadsLagged",
206 : Constant::Units::W,
207 6 : afnNode.SysDepZoneLoadsLagged,
208 : OutputProcessor::TimeStepType::System,
209 : OutputProcessor::StoreType::Average,
210 6 : afnNode.Name);
211 12 : SetupOutputVariable(state,
212 : "RoomAirflowNetwork Node SumIntSensibleGain",
213 : Constant::Units::W,
214 6 : afnNode.SumIntSensibleGain,
215 : OutputProcessor::TimeStepType::System,
216 : OutputProcessor::StoreType::Average,
217 6 : afnNode.Name);
218 12 : SetupOutputVariable(state,
219 : "RoomAirflowNetwork Node SumIntLatentGain",
220 : Constant::Units::W,
221 6 : afnNode.SumIntLatentGain,
222 : OutputProcessor::TimeStepType::System,
223 : OutputProcessor::StoreType::Average,
224 6 : afnNode.Name);
225 : }
226 : }
227 1 : state.dataRoomAirflowNetModel->OneTimeFlag = false;
228 : }
229 :
230 51891 : if (state.dataRoomAirflowNetModel->OneTimeFlagConf) { // then do one - time setup inits
231 1 : if (allocated(state.dataZoneEquip->ZoneEquipConfig) && allocated(state.dataZoneEquip->ZoneEquipList)) {
232 1 : int MaxNodeNum = 0;
233 1 : int MaxEquipNum = 0;
234 1 : ErrorsFound = false;
235 6 : for (int iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
236 5 : if (!state.dataHeatBal->Zone(iZone).IsControlled) continue;
237 1 : MaxEquipNum = max(MaxEquipNum, state.dataZoneEquip->ZoneEquipList(iZone).NumOfEquipTypes);
238 1 : MaxNodeNum = max(MaxNodeNum, state.dataZoneEquip->ZoneEquipConfig(iZone).NumInletNodes);
239 : }
240 1 : if (MaxNodeNum > 0) {
241 1 : NodeFound.allocate(MaxNodeNum);
242 1 : NodeFound = false;
243 : }
244 1 : if (MaxEquipNum > 0) {
245 1 : EquipFound.allocate(MaxEquipNum);
246 1 : SupplyFrac.allocate(MaxEquipNum);
247 1 : ReturnFrac.allocate(MaxEquipNum);
248 1 : EquipFound = false;
249 1 : SupplyFrac = 0.0;
250 1 : ReturnFrac = 0.0;
251 : }
252 :
253 : // loop over all zones with RoomAirflowNetwork model
254 6 : for (int iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
255 5 : auto const &zone = state.dataHeatBal->Zone(iZone);
256 5 : if (!zone.IsControlled) continue;
257 :
258 1 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(iZone);
259 1 : if (!afnZoneInfo.IsUsed) continue;
260 1 : afnZoneInfo.ActualZoneID = iZone;
261 1 : SupplyFrac = 0.0;
262 1 : ReturnFrac = 0.0;
263 1 : NodeFound = false;
264 1 : int numAirDistUnits = 0;
265 :
266 1 : auto const &zoneEquipList = state.dataZoneEquip->ZoneEquipList(iZone);
267 1 : auto const &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(iZone);
268 :
269 : // find supply air node number
270 7 : for (auto &afnNode : afnZoneInfo.Node) {
271 12 : for (auto &afnHVAC : afnNode.HVAC) {
272 12 : for (int I = 1; I <= zoneEquipList.NumOfEquipTypes; ++I) { // loop over all equip types
273 6 : if (zoneEquipList.EquipType(I) == DataZoneEquipment::ZoneEquipType::AirDistributionUnit) {
274 0 : if (numAirDistUnits == 0)
275 : numAirDistUnits =
276 0 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneHVAC:AirDistributionUnit");
277 0 : if (state.dataZoneAirLoopEquipmentManager->GetAirDistUnitsFlag) {
278 0 : ZoneAirLoopEquipmentManager::GetZoneAirLoopEquipment(state);
279 0 : state.dataZoneAirLoopEquipmentManager->GetAirDistUnitsFlag = false;
280 : }
281 :
282 0 : for (int AirDistUnitNum = 1; AirDistUnitNum <= numAirDistUnits; ++AirDistUnitNum) {
283 0 : if (zoneEquipList.EquipName(I) == state.dataDefineEquipment->AirDistUnit(AirDistUnitNum).Name) {
284 0 : if (afnHVAC.Name == state.dataDefineEquipment->AirDistUnit(AirDistUnitNum).EquipName(1)) {
285 0 : if (afnHVAC.EquipConfigIndex == 0) {
286 0 : afnHVAC.EquipConfigIndex = I;
287 : }
288 0 : EquipFound(I) = true;
289 0 : SupplyFrac(I) += afnHVAC.SupplyFraction;
290 0 : ReturnFrac(I) += afnHVAC.ReturnFraction;
291 : }
292 : }
293 : }
294 6 : } else if (Util::SameString(zoneEquipList.EquipName(I), afnHVAC.Name)) {
295 6 : if (afnHVAC.EquipConfigIndex == 0) {
296 6 : afnHVAC.EquipConfigIndex = I;
297 : }
298 6 : EquipFound(I) = true;
299 6 : SupplyFrac(I) += afnHVAC.SupplyFraction;
300 6 : ReturnFrac(I) += afnHVAC.ReturnFraction;
301 : }
302 : }
303 18 : for (int iNode = 1; iNode <= state.dataLoopNodes->NumOfNodes; ++iNode) { // loop over all nodes to find supply node ID
304 18 : if (Util::SameString(state.dataLoopNodes->NodeID(iNode), afnHVAC.SupplyNodeName)) {
305 6 : afnHVAC.SupNodeNum = iNode;
306 6 : break;
307 : }
308 : }
309 : // Verify inlet nodes
310 6 : int inletNodeIndex = 0;
311 6 : for (int iNode = 1; iNode <= zoneEquipConfig.NumInletNodes;
312 : ++iNode) { // loop over all supply inlet nodes in a single zone
313 : // !Get node conditions
314 6 : if (zoneEquipConfig.InletNode(iNode) == afnHVAC.SupNodeNum) {
315 6 : NodeFound(iNode) = true;
316 6 : inletNodeIndex = iNode;
317 6 : break;
318 : }
319 : }
320 :
321 6 : if (afnHVAC.SupNodeNum > 0 && afnHVAC.ReturnNodeName.empty()) {
322 : // Find matching return node
323 0 : for (int retNode = 1; retNode <= zoneEquipConfig.NumReturnNodes; ++retNode) {
324 0 : if ((zoneEquipConfig.ReturnNodeInletNum(retNode) == inletNodeIndex) &&
325 0 : (zoneEquipConfig.ReturnNode(retNode) > 0)) {
326 0 : afnHVAC.RetNodeNum = zoneEquipConfig.ReturnNode(retNode); // Zone return node
327 0 : break;
328 : }
329 : }
330 : }
331 :
332 6 : if (afnHVAC.RetNodeNum == 0) {
333 12 : for (int iNode = 1; iNode <= state.dataLoopNodes->NumOfNodes; ++iNode) { // loop over all nodes to find return node ID
334 12 : if (Util::SameString(state.dataLoopNodes->NodeID(iNode), afnHVAC.ReturnNodeName)) {
335 6 : afnHVAC.RetNodeNum = iNode;
336 6 : break;
337 : }
338 : }
339 : }
340 12 : SetupOutputVariable(state,
341 : "RoomAirflowNetwork Node HVAC Supply Fraction",
342 : Constant::Units::None,
343 6 : afnHVAC.SupplyFraction,
344 : OutputProcessor::TimeStepType::System,
345 : OutputProcessor::StoreType::Average,
346 6 : afnHVAC.Name);
347 12 : SetupOutputVariable(state,
348 : "RoomAirflowNetwork Node HVAC Return Fraction",
349 : Constant::Units::None,
350 6 : afnHVAC.ReturnFraction,
351 : OutputProcessor::TimeStepType::System,
352 : OutputProcessor::StoreType::Average,
353 6 : afnHVAC.Name);
354 : }
355 : }
356 : // Count node with.TRUE.
357 1 : int ISum = 0;
358 2 : for (int iNode = 1; iNode <= MaxNodeNum; ++iNode) { // loop over all supply inlet nodes in a single zone
359 1 : if (NodeFound(iNode)) ++ISum;
360 : }
361 : // Provide error messages with incorrect supplu node inputs
362 1 : if (ISum != zoneEquipConfig.NumInletNodes) {
363 0 : if (ISum > zoneEquipConfig.NumInletNodes) {
364 0 : ShowSevereError(
365 : state, "GetRoomAirflowNetworkData: The number of equipment listed in RoomAirflowNetwork:Node:HVACEquipment objects");
366 0 : ShowContinueError(state, format("is greater than the number of zone configuration inlet nodes in {}", zone.Name));
367 0 : ShowContinueError(state, "Please check inputs of both objects.");
368 0 : ErrorsFound = true;
369 : } else {
370 0 : ShowSevereError(
371 : state, "GetRoomAirflowNetworkData: The number of equipment listed in RoomAirflowNetwork:Node:HVACEquipment objects");
372 0 : ShowContinueError(state, format("is less than the number of zone configuration inlet nodes in {}", zone.Name));
373 0 : ShowContinueError(state, "Please check inputs of both objects.");
374 0 : ErrorsFound = true;
375 : }
376 : }
377 :
378 : // Check equipment names to ensure they are used in RoomAirflowNetwork : Node : HVACEquipment objects
379 2 : for (int I = 1; I <= zoneEquipList.NumOfEquipTypes; ++I) { // loop over all equip types
380 1 : if (!EquipFound(I)) {
381 0 : ShowSevereError(state,
382 : "GetRoomAirflowNetworkData: The equipment listed in ZoneEquipList is not found in the lsit of "
383 : "RoomAir:Node:AirflowNetwork:HVACEquipment objects =");
384 0 : ShowContinueError(state, format("{}. Please check inputs of both objects.", zoneEquipList.EquipName(I)));
385 0 : ErrorsFound = true;
386 : }
387 : }
388 :
389 : // Check fraction to ensure sum = 1.0 for every equipment
390 2 : for (int I = 1; I <= zoneEquipList.NumOfEquipTypes; ++I) { // loop over all equip types
391 1 : if (std::abs(SupplyFrac(I) - 1.0) > 0.001) {
392 0 : ShowSevereError(state, "GetRoomAirflowNetworkData: Invalid, zone supply fractions do not sum to 1.0");
393 0 : ShowContinueError(
394 0 : state, format("Entered in {} defined in RoomAir:Node:AirflowNetwork:HVACEquipment", zoneEquipList.EquipName(I)));
395 0 : ShowContinueError(state,
396 : "The Fraction of supply fraction values across all the roomair nodes in a zone needs to sum to 1.0.");
397 0 : ShowContinueError(state, format("The sum of fractions entered = {:.3R}", SupplyFrac(I)));
398 0 : ErrorsFound = true;
399 : }
400 1 : if (std::abs(ReturnFrac(I) - 1.0) > 0.001) {
401 0 : ShowSevereError(state, "GetRoomAirflowNetworkData: Invalid, zone return fractions do not sum to 1.0");
402 0 : ShowContinueError(
403 0 : state, format("Entered in {} defined in RoomAir:Node:AirflowNetwork:HVACEquipment", zoneEquipList.EquipName(I)));
404 0 : ShowContinueError(state,
405 : "The Fraction of return fraction values across all the roomair nodes in a zone needs to sum to 1.0.");
406 0 : ShowContinueError(state, format("The sum of fractions entered = {:.3R}", ReturnFrac(I)));
407 0 : ErrorsFound = true;
408 : }
409 : }
410 : }
411 1 : state.dataRoomAirflowNetModel->OneTimeFlagConf = false;
412 1 : if (allocated(NodeFound)) NodeFound.deallocate();
413 1 : if (ErrorsFound) {
414 0 : ShowFatalError(state, "GetRoomAirflowNetworkData: Errors found getting air model input. Program terminates.");
415 : }
416 : } // if (allocated)
417 : } // if (OneTimeFlagConf)
418 :
419 51891 : if (state.dataGlobal->BeginEnvrnFlag && state.dataRoomAirflowNetModel->EnvrnFlag) {
420 54 : for (int iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
421 45 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(iZone);
422 45 : if (!afnZoneInfo.IsUsed) continue;
423 63 : for (auto &afnNode : afnZoneInfo.Node) {
424 54 : afnNode.AirTemp = 23.0;
425 54 : afnNode.AirTempX = {23.0, 23.0, 23.0, 23.0};
426 54 : afnNode.AirTempDSX = {23.0, 23.0, 23.0, 23.0};
427 54 : afnNode.AirTempT1 = 23.0;
428 54 : afnNode.AirTempTX = 23.0;
429 54 : afnNode.AirTempT2 = 23.0;
430 :
431 54 : afnNode.HumRat = 0.0;
432 54 : afnNode.HumRatX = {0.0, 0.0, 0.0, 0.0};
433 54 : afnNode.HumRatDSX = {0.0, 0.0, 0.0, 0.0};
434 54 : afnNode.HumRatT1 = 0.0;
435 54 : afnNode.HumRatTX = 0.0;
436 54 : afnNode.HumRatT2 = 0.0;
437 :
438 54 : afnNode.SysDepZoneLoadsLagged = 0.0;
439 54 : afnNode.SysDepZoneLoadsLaggedOld = 0.0;
440 : }
441 : }
442 9 : state.dataRoomAirflowNetModel->EnvrnFlag = false;
443 : }
444 51891 : if (!state.dataGlobal->BeginEnvrnFlag) {
445 51625 : state.dataRoomAirflowNetModel->EnvrnFlag = true;
446 : }
447 :
448 : // reuse code in ZoneTempPredictorCorrector for sensible components.
449 51891 : CalcNodeSums(state, zoneNum, roomAirNodeNum);
450 :
451 51891 : SumNonAirSystemResponseForNode(state, zoneNum, roomAirNodeNum);
452 :
453 : // latent gains.
454 51891 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
455 51891 : auto &afnNode = afnZoneInfo.Node(roomAirNodeNum);
456 :
457 51891 : if (allocated(afnNode.SurfMask)) {
458 51891 : CalcSurfaceMoistureSums(state, zoneNum, roomAirNodeNum, afnNode.SumHmAW, afnNode.SumHmARa, afnNode.SumHmARaW, afnNode.SurfMask);
459 : }
460 :
461 : // prepare AirflowNetwor flow rates and temperatures
462 51891 : Real64 SumLinkMCp = 0.0;
463 51891 : Real64 SumLinkMCpT = 0.0;
464 51891 : Real64 SumLinkM = 0.0;
465 51891 : Real64 SumLinkMW = 0.0;
466 :
467 51891 : if (afnNode.AFNNodeID > 0) {
468 370650 : for (int iLink = 1; iLink <= afnNode.NumOfAirflowLinks; ++iLink) {
469 318759 : auto &afnLink = afnNode.Link(iLink);
470 318759 : int linkNum = afnLink.AFNSimuID;
471 318759 : if (state.afn->AirflowNetworkLinkageData(linkNum).NodeNums[0] == afnNode.AFNNodeID) { // incoming flow
472 170499 : int nodeInNum = state.afn->AirflowNetworkLinkageData(linkNum).NodeNums[1];
473 170499 : afnLink.TempIn = state.afn->AirflowNetworkNodeSimu(nodeInNum).TZ;
474 170499 : afnLink.HumRatIn = state.afn->AirflowNetworkNodeSimu(nodeInNum).WZ;
475 170499 : afnLink.MdotIn = state.afn->AirflowNetworkLinkSimu(linkNum).FLOW2;
476 : }
477 318759 : if (state.afn->AirflowNetworkLinkageData(linkNum).NodeNums[1] == afnNode.AFNNodeID) { // outgoing flow
478 148260 : int nodeInNum = state.afn->AirflowNetworkLinkageData(linkNum).NodeNums[0];
479 148260 : afnLink.TempIn = state.afn->AirflowNetworkNodeSimu(nodeInNum).TZ;
480 148260 : afnLink.HumRatIn = state.afn->AirflowNetworkNodeSimu(nodeInNum).WZ;
481 148260 : afnLink.MdotIn = state.afn->AirflowNetworkLinkSimu(linkNum).FLOW;
482 : }
483 : }
484 :
485 370650 : for (int iLink = 1; iLink <= afnNode.NumOfAirflowLinks; ++iLink) {
486 318759 : auto &afnLink = afnNode.Link(iLink);
487 318759 : Real64 CpAir = PsyCpAirFnW(afnLink.HumRatIn);
488 318759 : SumLinkMCp += CpAir * afnLink.MdotIn;
489 318759 : SumLinkMCpT += CpAir * afnLink.MdotIn * afnLink.TempIn;
490 318759 : SumLinkM += afnLink.MdotIn;
491 318759 : SumLinkMW += afnLink.MdotIn * afnLink.HumRatIn;
492 : }
493 : }
494 :
495 51891 : afnNode.SumLinkMCp = SumLinkMCp;
496 51891 : afnNode.SumLinkMCpT = SumLinkMCpT;
497 51891 : afnNode.SumLinkM = SumLinkM;
498 51891 : afnNode.SumLinkMW = SumLinkMW;
499 51891 : afnNode.SysDepZoneLoadsLagged = afnNode.SysDepZoneLoadsLaggedOld;
500 :
501 51891 : afnNode.RhoAir = PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, afnNode.AirTemp, afnNode.HumRat, "InitRoomAirModelAirflowNetwork");
502 :
503 51891 : afnNode.CpAir = PsyCpAirFnW(afnNode.HumRat);
504 :
505 51891 : } // InitRoomAirModelAirflowNetwork
506 :
507 : //*****************************************************************************************
508 :
509 44478 : void CalcRoomAirModelAFN(EnergyPlusData &state, int const zoneNum,
510 : int const roomAirNodeNum) // index number for the specified zone and node
511 : {
512 :
513 : // SUBROUTINE INFORMATION:
514 : // AUTHOR Brent Griffith
515 : // DATE WRITTEN November 2009
516 : // MODIFIED Lixing Gu, Aug. 2015 for v8.4 replease
517 :
518 : // PURPOSE OF THIS SUBROUTINE:
519 : // calculate new values for temperature and humidity ratio for room air node
520 :
521 : // METHODOLOGY EMPLOYED:
522 : // take terms(updated in init routine) and use classic air balance equations
523 : // solved for state variables. Store results in structure.
524 :
525 : // Using/Aliasing
526 44478 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
527 : using Psychrometrics::PsyHgAirFnWTdb;
528 : using Psychrometrics::PsyRhFnTdbWPb;
529 :
530 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
531 : std::array<Real64, 3> NodeTempX;
532 : std::array<Real64, 3> NodeHumRatX;
533 : Real64 AirTempT1;
534 : Real64 HumRatT1;
535 :
536 44478 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
537 44478 : auto &afnNode = afnZoneInfo.Node(roomAirNodeNum);
538 :
539 44478 : if (state.dataHVACGlobal->UseZoneTimeStepHistory) {
540 34650 : NodeTempX[0] = afnNode.AirTempX[0];
541 34650 : NodeTempX[1] = afnNode.AirTempX[1];
542 34650 : NodeTempX[2] = afnNode.AirTempX[2];
543 :
544 34650 : NodeHumRatX[0] = afnNode.HumRatX[0];
545 34650 : NodeHumRatX[1] = afnNode.HumRatX[1];
546 34650 : NodeHumRatX[2] = afnNode.HumRatX[2];
547 : } else { // use down - stepped history
548 9828 : NodeTempX[0] = afnNode.AirTempDSX[0];
549 9828 : NodeTempX[1] = afnNode.AirTempDSX[1];
550 9828 : NodeTempX[2] = afnNode.AirTempDSX[2];
551 :
552 9828 : NodeHumRatX[0] = afnNode.HumRatDSX[0];
553 9828 : NodeHumRatX[1] = afnNode.HumRatDSX[1];
554 9828 : NodeHumRatX[2] = afnNode.HumRatDSX[2];
555 : }
556 :
557 44478 : if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
558 0 : AirTempT1 = afnNode.AirTempT1;
559 0 : HumRatT1 = afnNode.HumRatT1;
560 : }
561 : // solve for node drybulb temperature
562 44478 : Real64 TempDepCoef = afnNode.SumHA + afnNode.SumLinkMCp + afnNode.SumSysMCp;
563 44478 : Real64 TempIndCoef = afnNode.SumIntSensibleGain + afnNode.SumHATsurf - afnNode.SumHATref + afnNode.SumLinkMCpT + afnNode.SumSysMCpT +
564 44478 : afnNode.NonAirSystemResponse + afnNode.SysDepZoneLoadsLagged;
565 44478 : Real64 AirCap = afnNode.AirVolume * state.dataHeatBal->Zone(zoneNum).ZoneVolCapMultpSens * afnNode.RhoAir * afnNode.CpAir / TimeStepSysSec;
566 :
567 44478 : if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::AnalyticalSolution) {
568 0 : if (TempDepCoef == 0.0) { // B=0
569 0 : afnNode.AirTemp = AirTempT1 + TempIndCoef / AirCap;
570 : } else {
571 0 : afnNode.AirTemp = (AirTempT1 - TempIndCoef / TempDepCoef) * std::exp(min(700.0, -TempDepCoef / AirCap)) + TempIndCoef / TempDepCoef;
572 : }
573 44478 : } else if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::EulerMethod) {
574 0 : afnNode.AirTemp = (AirCap * AirTempT1 + TempIndCoef) / (AirCap + TempDepCoef);
575 : } else {
576 44478 : afnNode.AirTemp = (TempIndCoef + AirCap * (3.0 * NodeTempX[0] - (3.0 / 2.0) * NodeTempX[1] + (1.0 / 3.0) * NodeTempX[2])) /
577 44478 : ((11.0 / 6.0) * AirCap + TempDepCoef);
578 : }
579 :
580 : // solve for node humidity ratio using 3 algorithms
581 44478 : Real64 H2OHtOfVap = PsyHgAirFnWTdb(afnNode.HumRat, afnNode.AirTemp);
582 44478 : Real64 A = afnNode.SumLinkM + afnNode.SumHmARa + afnNode.SumSysM;
583 44478 : Real64 B = (afnNode.SumIntLatentGain / H2OHtOfVap) + afnNode.SumSysMW + afnNode.SumLinkMW + afnNode.SumHmARaW;
584 44478 : Real64 C = afnNode.RhoAir * afnNode.AirVolume * state.dataHeatBal->Zone(zoneNum).ZoneVolCapMultpMoist / TimeStepSysSec;
585 :
586 : // Exact solution
587 44478 : if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::AnalyticalSolution) {
588 0 : if (A == 0.0) { // B=0
589 0 : afnNode.HumRat = HumRatT1 + B / C;
590 : } else {
591 0 : afnNode.HumRat = (HumRatT1 - B / A) * std::exp(min(700., -A / C)) + B / A;
592 : }
593 44478 : } else if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::EulerMethod) {
594 0 : afnNode.HumRat = (C * HumRatT1 + B) / (C + A);
595 : } else {
596 44478 : afnNode.HumRat = (B + C * (3.0 * NodeHumRatX[0] - (3.0 / 2.0) * NodeHumRatX[1] + (1.0 / 3.0) * NodeHumRatX[2])) / ((11.0 / 6.0) * C + A);
597 : }
598 :
599 44478 : afnNode.AirCap = AirCap;
600 44478 : afnNode.AirHumRat = C;
601 :
602 44478 : afnNode.RelHumidity =
603 44478 : PsyRhFnTdbWPb(state, afnNode.AirTemp, afnNode.HumRat, state.dataEnvrn->OutBaroPress, "CalcRoomAirModelAirflowNetwork") * 100.0;
604 :
605 44478 : } // CalcRoomAirModelAirflowNetwork
606 :
607 7413 : void UpdateRoomAirModelAFN(EnergyPlusData &state, int const zoneNum)
608 : {
609 :
610 : // SUBROUTINE INFORMATION:
611 : // AUTHOR B Griffith
612 : // DATE WRITTEN November 2009
613 : // MODIFIED Lixing Gu, Aug. 2015 for v8.4 replease
614 :
615 : // PURPOSE OF THIS SUBROUTINE:
616 : // update variables
617 7413 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
618 :
619 7413 : if (!afnZoneInfo.IsUsed) return;
620 :
621 7413 : if (!state.dataGlobal->ZoneSizingCalc) SumSystemDepResponseForNode(state, zoneNum);
622 :
623 : // Update return node conditions
624 14826 : for (int I = 1; I <= state.dataZoneEquip->ZoneEquipList(zoneNum).NumOfEquipTypes; ++I) { // loop over all equip types
625 7413 : Real64 SumMass = 0.0;
626 7413 : Real64 SumMassT = 0.0;
627 7413 : Real64 SumMassW = 0.0;
628 7413 : int RetNodeNum = 0;
629 51891 : for (auto const &afnNode : afnZoneInfo.Node) {
630 88956 : for (auto const &afnHVAC : afnNode.HVAC) {
631 44478 : if (afnHVAC.EquipConfigIndex == I && afnHVAC.SupNodeNum > 0 && afnHVAC.RetNodeNum > 0) {
632 44478 : Real64 NodeMass = state.dataLoopNodes->Node(afnHVAC.SupNodeNum).MassFlowRate * afnHVAC.ReturnFraction;
633 44478 : SumMass += NodeMass;
634 44478 : SumMassT += NodeMass * afnNode.AirTemp;
635 44478 : SumMassW += NodeMass * afnNode.HumRat;
636 44478 : RetNodeNum = afnHVAC.RetNodeNum;
637 : }
638 : }
639 : }
640 7413 : if (SumMass > 0.0) {
641 7296 : state.dataLoopNodes->Node(RetNodeNum).Temp = SumMassT / SumMass;
642 7296 : state.dataLoopNodes->Node(RetNodeNum).HumRat = SumMassW / SumMass;
643 : }
644 : }
645 : } // UpdateRoomAirModelAirflowNetwork
646 :
647 51891 : void CalcNodeSums(EnergyPlusData &state, int const zoneNum, int const roomAirNodeNum)
648 : {
649 :
650 : // SUBROUTINE INFORMATION:
651 : // AUTHOR B Griffith
652 : // DATE WRITTEN August 2009
653 : // MODIFIED Lixing Gu, Aug. 2015 for v8.4 replease
654 : // RE - ENGINEERED na
655 :
656 : // PURPOSE OF THIS SUBROUTINE :
657 : // This subroutine calculates the various sums that go into the zone heat balance
658 : // equation.This replaces the SUMC, SUMHA, and SUMHAT calculations that were
659 : // previously done in various places throughout the program.
660 : // The SumHAT portion of the code is reproduced in RadiantSystemHighTemp and
661 : // RadiantSystemLowTemp and should be updated accordingly.
662 : //
663 : // A reference temperature(Tref) is specified for use with the ceiling diffuser
664 : // convection correlation.A bogus value of Tref = -999.9 defaults to using
665 : // the zone air(i.e.outlet) temperature for the reference temperature.
666 : // If Tref is applied to all surfaces, SumHA = 0, and SumHATref /= 0.
667 : // If Tref is not used at all, SumHATref = 0, and SumHA /= 0.
668 : //
669 :
670 : // USE STATEMENTS:
671 : using InternalHeatGains::SumInternalConvectionGainsByIndices;
672 : using InternalHeatGains::SumInternalLatentGainsByIndices;
673 : using InternalHeatGains::SumReturnAirConvectionGainsByIndices;
674 : using InternalHeatGains::SumReturnAirConvectionGainsByTypes;
675 : using Psychrometrics::PsyCpAirFnW;
676 : using Psychrometrics::PsyRhoAirFnPbTdbW;
677 :
678 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
679 : Real64 HA; // !Hc*Area
680 : Real64 Area; // !Effective surface area
681 : Real64 RefAirTemp; // !Reference air temperature for surface convection calculations
682 : bool Found; //
683 :
684 51891 : Real64 SumIntGain = 0.0; // node sum of convective internal gains
685 51891 : Real64 SumHA = 0.0; // Zone sum of Hc*Area
686 51891 : Real64 SumHATsurf = 0.0; // Zone sum of Hc*Area*Tsurf
687 51891 : Real64 SumHATref = 0.0; // Zone sum of Hc*Area*Tref, for ceiling diffuser convection correlation
688 51891 : Real64 SumSysMCp = 0.0; // Zone sum of air system MassFlowRate*Cp
689 51891 : Real64 SumSysMCpT = 0.0; // Zone sum of air system MassFlowRate*Cp*T
690 51891 : Real64 SumSysM = 0.0; // Zone sum of air system MassFlowRate
691 51891 : Real64 SumSysMW = 0.0; // Zone sum of air system MassFlowRate*W
692 :
693 51891 : auto const &zone = state.dataHeatBal->Zone(zoneNum);
694 51891 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
695 51891 : auto &afnNode = afnZoneInfo.Node(roomAirNodeNum);
696 : // Sum all convective internal gains: SumIntGain
697 103782 : afnNode.SumIntSensibleGain = SumInternalConvectionGainsByIndices(
698 51891 : state, afnNode.NumIntGains, afnNode.intGainsDeviceSpaces, afnNode.IntGainsDeviceIndices, afnNode.IntGainsFractions);
699 :
700 103782 : afnNode.SumIntLatentGain = SumInternalLatentGainsByIndices(
701 51891 : state, afnNode.NumIntGains, afnNode.intGainsDeviceSpaces, afnNode.IntGainsDeviceIndices, afnNode.IntGainsFractions);
702 : // Add heat to return air if zonal system(no return air) or cycling system(return air frequently very low or zero)
703 51891 : if (state.dataHeatBal->Zone(zoneNum).NoHeatToReturnAir) {
704 : // *******************************************
705 51436 : SumIntGain = SumReturnAirConvectionGainsByIndices(
706 25718 : state, afnNode.NumIntGains, afnNode.intGainsDeviceSpaces, afnNode.IntGainsDeviceIndices, afnNode.IntGainsFractions);
707 25718 : afnNode.SumIntSensibleGain += SumIntGain;
708 : }
709 :
710 : // Check to see if this is a controlled zone
711 : // Check to see if this is a plenum zone
712 51891 : int zoneRetPlenumNum = 0;
713 51891 : for (int iPlenum = 1; iPlenum <= state.dataZonePlenum->NumZoneReturnPlenums; ++iPlenum) {
714 0 : if (state.dataZonePlenum->ZoneRetPlenCond(iPlenum).ActualZoneNum != zoneNum) continue;
715 0 : zoneRetPlenumNum = iPlenum;
716 0 : break;
717 : }
718 51891 : bool zoneSupPlenumNum = false;
719 51891 : for (int iPlenum = 1; iPlenum <= state.dataZonePlenum->NumZoneSupplyPlenums; ++iPlenum) {
720 0 : if (state.dataZonePlenum->ZoneSupPlenCond(iPlenum).ActualZoneNum != zoneNum) continue;
721 0 : zoneSupPlenumNum = iPlenum;
722 0 : break;
723 : }
724 :
725 : // Plenum and controlled zones have a different set of inlet nodes which must be calculated.
726 51891 : auto &zoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum);
727 51891 : if (zone.IsControlled) {
728 51891 : auto &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(zoneNum);
729 103782 : for (int iNode = 1; iNode <= zoneEquipConfig.NumInletNodes; ++iNode) {
730 : // Get node conditions
731 : // this next block is of interest to irratic system loads... maybe nodes are not accurate at time of call ?
732 : // how can we tell ? predict step must be lagged ? correct step, systems have run.
733 51891 : auto const &inletNode = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(iNode));
734 103782 : for (auto const &afnHVAC : afnNode.HVAC) {
735 51891 : if (afnHVAC.SupNodeNum == zoneEquipConfig.InletNode(iNode)) {
736 51891 : Real64 MassFlowRate = inletNode.MassFlowRate * afnHVAC.SupplyFraction;
737 51891 : Real64 CpAir = PsyCpAirFnW(zoneHB.airHumRat);
738 51891 : SumSysMCp += MassFlowRate * CpAir;
739 51891 : SumSysMCpT += MassFlowRate * CpAir * inletNode.Temp;
740 51891 : SumSysM += MassFlowRate;
741 51891 : SumSysMW += MassFlowRate * inletNode.HumRat;
742 : }
743 : } // EquipLoop
744 : } // NodeNum
745 0 : } else if (zoneRetPlenumNum != 0) {
746 0 : auto const &zoneRetPlenum = state.dataZonePlenum->ZoneRetPlenCond(zoneRetPlenumNum);
747 0 : for (int iNode = 1; iNode <= zoneRetPlenum.NumInletNodes; ++iNode) {
748 : // Get node conditions
749 0 : auto const &zoneRetPlenumNode = state.dataLoopNodes->Node(zoneRetPlenum.InletNode(iNode));
750 0 : Real64 CpAir = PsyCpAirFnW(zoneHB.airHumRat);
751 0 : SumSysMCp += zoneRetPlenumNode.MassFlowRate * CpAir;
752 0 : SumSysMCpT += zoneRetPlenumNode.MassFlowRate * CpAir * zoneRetPlenumNode.Temp;
753 : } // NodeNum
754 : // add in the leaks
755 0 : for (int iADU = 1; iADU <= zoneRetPlenum.NumADUs; ++iADU) {
756 0 : int ADUNum = zoneRetPlenum.ADUIndex(iADU);
757 0 : auto const &adu = state.dataDefineEquipment->AirDistUnit(ADUNum);
758 0 : if (adu.UpStreamLeak) {
759 0 : Real64 CpAir = PsyCpAirFnW(zoneHB.airHumRat);
760 0 : SumSysMCp += adu.MassFlowRateUpStrLk * CpAir;
761 0 : SumSysMCpT += adu.MassFlowRateUpStrLk * CpAir * state.dataLoopNodes->Node(adu.InletNodeNum).Temp;
762 : }
763 0 : if (adu.DownStreamLeak) {
764 0 : Real64 CpAir = PsyCpAirFnW(zoneHB.airHumRat);
765 0 : SumSysMCp += adu.MassFlowRateDnStrLk * CpAir;
766 0 : SumSysMCpT += adu.MassFlowRateDnStrLk * CpAir * state.dataLoopNodes->Node(adu.OutletNodeNum).Temp;
767 : }
768 : } // ADUListIndex
769 0 : } else if (zoneSupPlenumNum != 0) {
770 : // Get node conditions
771 0 : auto const &zoneSupPlenum = state.dataZonePlenum->ZoneSupPlenCond(zoneSupPlenumNum);
772 0 : auto const &inletNode = state.dataLoopNodes->Node(zoneSupPlenum.InletNode);
773 0 : Real64 CpAir = PsyCpAirFnW(zoneHB.airHumRat);
774 0 : SumSysMCp += inletNode.MassFlowRate * CpAir;
775 0 : SumSysMCpT += inletNode.MassFlowRate * CpAir * inletNode.Temp;
776 : }
777 :
778 51891 : int ZoneMult = zone.Multiplier * zone.ListMultiplier;
779 :
780 51891 : SumSysMCp /= ZoneMult;
781 51891 : SumSysMCpT /= ZoneMult;
782 51891 : SumSysM /= ZoneMult;
783 51891 : SumSysMW /= ZoneMult;
784 :
785 : // Sum all surface convection : SumHA, SumHATsurf, SumHATref(and additional contributions to SumIntGain)
786 : // Modified by Gu to include assigned surfaces only shown in the surface lsit
787 51891 : if (!afnNode.HasSurfacesAssigned) return;
788 :
789 51891 : int surfCount = 0;
790 103782 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
791 51891 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
792 882147 : for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
793 830256 : ++surfCount;
794 830256 : if (afnZoneInfo.ControlAirNodeID == roomAirNodeNum) {
795 237216 : Found = false;
796 1408470 : for (int Loop = 1; Loop <= afnZoneInfo.NumOfAirNodes; ++Loop) {
797 1245384 : if (Loop != roomAirNodeNum) {
798 1037820 : if (afnZoneInfo.Node(Loop).SurfMask(surfCount)) {
799 74130 : Found = true;
800 74130 : break;
801 : }
802 : }
803 : }
804 237216 : if (Found) continue;
805 : } else {
806 593040 : if (!afnNode.SurfMask(surfCount)) continue;
807 : }
808 :
809 200151 : HA = 0.0;
810 200151 : Area = state.dataSurface->Surface(SurfNum).Area; // For windows, this is the glazing area
811 :
812 200151 : if (state.dataSurface->Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window) {
813 :
814 : // Add to the convective internal gains
815 29652 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
816 : // The shade area covers the area of the glazing plus the area of the dividers.
817 0 : Area += state.dataSurface->SurfWinDividerArea(SurfNum);
818 0 : SumIntGain += state.dataSurface->SurfWinDividerHeatGain(SurfNum);
819 : }
820 :
821 : // Convective heat gain from natural convection in gap between glass and interior shade or blind
822 29652 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum)))
823 0 : SumIntGain += state.dataSurface->SurfWinConvHeatFlowNatural(SurfNum);
824 :
825 : // Convective heat gain from airflow window
826 29652 : if (state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
827 0 : SumIntGain += state.dataSurface->SurfWinConvHeatGainToZoneAir(SurfNum);
828 0 : if (zone.NoHeatToReturnAir) {
829 0 : SumIntGain += state.dataSurface->SurfWinRetHeatGainToZoneAir(SurfNum);
830 0 : state.dataSurface->SurfWinHeatGain(SurfNum) += state.dataSurface->SurfWinRetHeatGainToZoneAir(SurfNum);
831 0 : if (state.dataSurface->SurfWinHeatGain(SurfNum) >= 0.0) {
832 0 : state.dataSurface->SurfWinHeatGainRep(SurfNum) = state.dataSurface->SurfWinHeatGain(SurfNum);
833 0 : state.dataSurface->SurfWinHeatGainRepEnergy(SurfNum) =
834 0 : state.dataSurface->SurfWinHeatGainRep(SurfNum) * state.dataGlobal->TimeStepZone * Constant::SecInHour;
835 : } else {
836 0 : state.dataSurface->SurfWinHeatLossRep(SurfNum) = -state.dataSurface->SurfWinHeatGain(SurfNum);
837 0 : state.dataSurface->SurfWinHeatLossRepEnergy(SurfNum) =
838 0 : state.dataSurface->SurfWinHeatLossRep(SurfNum) * state.dataGlobal->TimeStepZone * Constant::SecInHour;
839 : }
840 0 : state.dataSurface->SurfWinHeatTransferRepEnergy(SurfNum) =
841 0 : state.dataSurface->SurfWinHeatGain(SurfNum) * state.dataGlobal->TimeStepZone * Constant::SecInHour;
842 : }
843 : }
844 :
845 : // Add to the surface convection sums
846 29652 : if (state.dataSurface->SurfWinFrameArea(SurfNum) > 0.0) {
847 : // Window frame contribution
848 0 : SumHATsurf += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataSurface->SurfWinFrameArea(SurfNum) *
849 0 : (1.0 + state.dataSurface->SurfWinProjCorrFrIn(SurfNum)) * state.dataSurface->SurfWinFrameTempIn(SurfNum);
850 0 : HA += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataSurface->SurfWinFrameArea(SurfNum) *
851 0 : (1.0 + state.dataSurface->SurfWinProjCorrFrIn(SurfNum));
852 : }
853 :
854 29652 : if (state.dataSurface->SurfWinDividerArea(SurfNum) > 0.0 &&
855 0 : !ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
856 : // Window divider contribution(only from shade or blind for window with divider and interior shade or blind)
857 0 : SumHATsurf += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataSurface->SurfWinDividerArea(SurfNum) *
858 0 : (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum)) *
859 0 : state.dataSurface->SurfWinDividerTempIn(SurfNum);
860 0 : HA += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataSurface->SurfWinDividerArea(SurfNum) *
861 0 : (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum));
862 : }
863 :
864 : } // End of check if window
865 :
866 200151 : HA += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * Area;
867 200151 : SumHATsurf += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * Area * state.dataHeatBalSurf->SurfTempInTmp(SurfNum);
868 :
869 200151 : if (state.dataSurface->SurfTAirRef(SurfNum) == DataSurfaces::RefAirTemp::ZoneMeanAirTemp) {
870 : // The zone air is the reference temperature(which is to be solved for in CorrectZoneAirTemp).
871 0 : RefAirTemp = zoneHB.MAT;
872 0 : SumHA += HA;
873 200151 : } else if (state.dataSurface->SurfTAirRef(SurfNum) == DataSurfaces::RefAirTemp::AdjacentAirTemp) {
874 0 : RefAirTemp = state.dataHeatBal->SurfTempEffBulkAir(SurfNum);
875 0 : SumHATref += HA * RefAirTemp;
876 200151 : } else if (state.dataSurface->SurfTAirRef(SurfNum) == DataSurfaces::RefAirTemp::ZoneSupplyAirTemp) {
877 : // check whether this zone is a controlled zone or not
878 0 : if (!zone.IsControlled) {
879 0 : ShowFatalError(state,
880 0 : format("Zones must be controlled for Ceiling-Diffuser Convection model. No system serves zone {}", zone.Name));
881 0 : return;
882 : }
883 : // determine supply air temperature as a weighted average of the inlet temperatures.
884 0 : RefAirTemp = SumSysMCpT / SumSysMCp;
885 0 : SumHATref += HA * RefAirTemp;
886 : } else {
887 200151 : RefAirTemp = zoneHB.MAT;
888 200151 : SumHA += HA;
889 : }
890 :
891 : } // SurfNum
892 51891 : }
893 : // Assemble values
894 51891 : afnNode.SumHA = SumHA;
895 51891 : afnNode.SumHATsurf = SumHATsurf;
896 51891 : afnNode.SumHATref = SumHATref;
897 51891 : afnNode.SumSysMCp = SumSysMCp;
898 51891 : afnNode.SumSysMCpT = SumSysMCpT;
899 51891 : afnNode.SumSysM = SumSysM;
900 51891 : afnNode.SumSysMW = SumSysMW;
901 :
902 : } // CalcNodeSums
903 :
904 51891 : void CalcSurfaceMoistureSums(EnergyPlusData &state,
905 : int const zoneNum,
906 : int const roomAirNodeNum,
907 : Real64 &SumHmAW,
908 : Real64 &SumHmARa,
909 : Real64 &SumHmARaW,
910 : [[maybe_unused]] Array1D<bool> const &SurfMask)
911 : {
912 :
913 : // SUBROUTINE INFORMATION:
914 : // AUTHOR B Griffith
915 : // derived from P. Biddulph-- HAMT, L. Gu -- EPMD,
916 : // DATE WRITTEN November 2009
917 : // MODIFIED Lixing Gu, Aug. 2015 for v8.4 replease
918 :
919 : // PURPOSE OF THIS SUBROUTINE:
920 : // Breakout summation of surface moisture interaction terms
921 :
922 : // Using/Aliasing
923 :
924 : using HeatBalanceHAMTManager::UpdateHeatBalHAMT;
925 : using MoistureBalanceEMPDManager::UpdateMoistureBalanceEMPD;
926 : using Psychrometrics::PsyRhFnTdbRhov;
927 : using Psychrometrics::PsyRhFnTdbRhovLBnd0C;
928 : using Psychrometrics::PsyRhoAirFnPbTdbW;
929 : using Psychrometrics::PsyWFnTdbRhPb;
930 :
931 51891 : SumHmAW = 0.0;
932 51891 : SumHmARa = 0.0;
933 51891 : SumHmARaW = 0.0;
934 :
935 51891 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
936 :
937 51891 : int surfCount = 1;
938 103782 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
939 51891 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
940 882147 : for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum, ++surfCount) {
941 830256 : auto const &surf = state.dataSurface->Surface(SurfNum);
942 830256 : if (surf.Class == SurfaceClass::Window) continue;
943 :
944 726474 : if (afnZoneInfo.ControlAirNodeID == roomAirNodeNum) {
945 207564 : bool Found = false;
946 1275036 : for (int Loop = 1; Loop <= afnZoneInfo.NumOfAirNodes && !Found; ++Loop) {
947 : // None - assigned surfaces belong to the zone node
948 1067472 : Found = (Loop != roomAirNodeNum) && afnZoneInfo.Node(Loop).SurfMask(surfCount);
949 : }
950 207564 : if (Found) continue;
951 : } else {
952 518910 : if (!afnZoneInfo.Node(roomAirNodeNum).SurfMask(surfCount)) continue;
953 : }
954 :
955 170499 : auto &HMassConvInFD = state.dataMstBal->HMassConvInFD;
956 170499 : auto &RhoVaporSurfIn = state.dataMstBal->RhoVaporSurfIn;
957 170499 : auto &RhoVaporAirIn = state.dataMstBal->RhoVaporAirIn;
958 170499 : if (surf.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::HAMT) {
959 0 : UpdateHeatBalHAMT(state, SurfNum);
960 :
961 0 : SumHmAW += HMassConvInFD(SurfNum) * surf.Area * (RhoVaporSurfIn(SurfNum) - RhoVaporAirIn(SurfNum));
962 :
963 0 : Real64 RhoAirZone = PsyRhoAirFnPbTdbW(
964 : state,
965 0 : state.dataEnvrn->OutBaroPress,
966 0 : state.dataZoneTempPredictorCorrector->zoneHeatBalance(surf.Zone).MAT,
967 0 : PsyRhFnTdbRhov(state,
968 0 : state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataSurface->Surface(SurfNum).Zone).MAT,
969 0 : RhoVaporAirIn(SurfNum),
970 : "RhoAirZone"));
971 :
972 : Real64 Wsurf =
973 0 : PsyWFnTdbRhPb(state,
974 0 : state.dataHeatBalSurf->SurfTempInTmp(SurfNum),
975 0 : PsyRhFnTdbRhov(state, state.dataHeatBalSurf->SurfTempInTmp(SurfNum), RhoVaporSurfIn(SurfNum), "Wsurf"),
976 0 : state.dataEnvrn->OutBaroPress);
977 :
978 0 : SumHmARa += HMassConvInFD(SurfNum) * surf.Area * RhoAirZone;
979 0 : SumHmARaW += HMassConvInFD(SurfNum) * surf.Area * RhoAirZone * Wsurf;
980 : }
981 :
982 170499 : else if (surf.HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::EMPD) {
983 :
984 0 : UpdateMoistureBalanceEMPD(state, SurfNum);
985 0 : RhoVaporSurfIn(SurfNum) = state.dataMstBalEMPD->RVSurface(SurfNum);
986 :
987 0 : SumHmAW += HMassConvInFD(SurfNum) * surf.Area * (RhoVaporSurfIn(SurfNum) - RhoVaporAirIn(SurfNum));
988 0 : SumHmARa += HMassConvInFD(SurfNum) * surf.Area *
989 0 : PsyRhoAirFnPbTdbW(
990 : state,
991 0 : state.dataEnvrn->OutBaroPress,
992 0 : state.dataHeatBalSurf->SurfTempInTmp(SurfNum),
993 0 : PsyWFnTdbRhPb(state,
994 0 : state.dataHeatBalSurf->SurfTempInTmp(SurfNum),
995 0 : PsyRhFnTdbRhovLBnd0C(state, state.dataHeatBalSurf->SurfTempInTmp(SurfNum), RhoVaporAirIn(SurfNum)),
996 0 : state.dataEnvrn->OutBaroPress));
997 0 : SumHmARaW += HMassConvInFD(SurfNum) * surf.Area * RhoVaporSurfIn(SurfNum);
998 : }
999 : } // for (SurfNum)
1000 51891 : } // for (spaceNum)
1001 :
1002 51891 : } // CalcSurfaceMoistureSums
1003 :
1004 51891 : void SumNonAirSystemResponseForNode(EnergyPlusData &state, int const zoneNum, int const roomAirNodeNum)
1005 : {
1006 :
1007 : // SUBROUTINE INFORMATION:
1008 : // AUTHOR B. Griffith
1009 : // DATE WRITTEN June 2012
1010 : // MODIFIED Lixing Gu, Aug. 2015 for v8.4 replease
1011 :
1012 : // PURPOSE OF THIS SUBROUTINE:
1013 : // Sum system response from none air systems
1014 :
1015 : // USE STATEMENTS:
1016 : using BaseboardElectric::SimElectricBaseboard;
1017 : using BaseboardRadiator::SimBaseboard;
1018 : using ElectricBaseboardRadiator::SimElecBaseboard;
1019 : using HighTempRadiantSystem::SimHighTempRadiantSystem;
1020 : using HWBaseboardRadiator::SimHWBaseboard;
1021 : using RefrigeratedCase::SimAirChillerSet;
1022 : using SteamBaseboardRadiator::SimSteamBaseboard;
1023 :
1024 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1025 : Real64 SysOutputProvided;
1026 : Real64 LatOutputProvided;
1027 :
1028 : // TODO
1029 51891 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
1030 51891 : auto &afnNode = afnZoneInfo.Node(roomAirNodeNum);
1031 :
1032 51891 : afnNode.NonAirSystemResponse = 0.0;
1033 :
1034 51891 : if (!allocated(state.dataZoneEquip->ZoneEquipConfig)) return;
1035 :
1036 103782 : for (auto &afnHVAC : afnNode.HVAC) {
1037 51891 : switch (afnHVAC.zoneEquipType) {
1038 :
1039 0 : case DataZoneEquipment::ZoneEquipType::BaseboardWater: {
1040 : //'ZoneHVAC:Baseboard:RadiantConvective:Water' 13
1041 0 : SimHWBaseboard(state, afnHVAC.Name, zoneNum, false, SysOutputProvided, afnHVAC.CompIndex);
1042 0 : afnNode.NonAirSystemResponse += afnHVAC.SupplyFraction * SysOutputProvided;
1043 : // LatOutputProvided = 0.0d0 !This baseboard does not add / remove any latent heat
1044 0 : } break;
1045 :
1046 0 : case DataZoneEquipment::ZoneEquipType::BaseboardSteam: {
1047 : // CASE(BBSteam_Num) !'ZoneHVAC:Baseboard:RadiantConvective:Steam' 14
1048 0 : SimSteamBaseboard(state, afnHVAC.Name, zoneNum, false, SysOutputProvided, afnHVAC.CompIndex);
1049 :
1050 0 : afnNode.NonAirSystemResponse += afnHVAC.SupplyFraction * SysOutputProvided;
1051 : // LatOutputProvided = 0.0d0 !This baseboard does not add / remove any latent heat
1052 0 : } break;
1053 :
1054 0 : case DataZoneEquipment::ZoneEquipType::BaseboardConvectiveWater: {
1055 : // CASE(BBWaterConvective_Num) !'ZoneHVAC:Baseboard:Convective:Water' 16
1056 0 : SimBaseboard(state, afnHVAC.Name, zoneNum, false, SysOutputProvided, afnHVAC.CompIndex);
1057 0 : afnNode.NonAirSystemResponse += afnHVAC.SupplyFraction * SysOutputProvided;
1058 : // LatOutputProvided = 0.0d0 !This baseboard does not add / remove any latent heat
1059 0 : } break;
1060 :
1061 0 : case DataZoneEquipment::ZoneEquipType::BaseboardConvectiveElectric: {
1062 : // CASE(BBElectricConvective_Num) !'ZoneHVAC:Baseboard:Convective:Electric' 15
1063 0 : SimElectricBaseboard(state, afnHVAC.Name, zoneNum, SysOutputProvided, afnHVAC.CompIndex);
1064 0 : afnNode.NonAirSystemResponse += afnHVAC.SupplyFraction * SysOutputProvided;
1065 : // LatOutputProvided = 0.0d0 !This baseboard does not add / remove any latent heat
1066 0 : } break;
1067 :
1068 0 : case DataZoneEquipment::ZoneEquipType::RefrigerationChillerSet: {
1069 : // CASE(RefrigerationAirChillerSet_Num) !'ZoneHVAC:RefrigerationChillerSet' 20
1070 0 : SimAirChillerSet(state, afnHVAC.Name, zoneNum, false, SysOutputProvided, LatOutputProvided, afnHVAC.CompIndex);
1071 0 : afnNode.NonAirSystemResponse += afnHVAC.SupplyFraction * SysOutputProvided;
1072 0 : } break;
1073 :
1074 0 : case DataZoneEquipment::ZoneEquipType::BaseboardElectric: {
1075 : // CASE(BBElectric_Num) !'ZoneHVAC:Baseboard:RadiantConvective:Electric' 12
1076 0 : SimElecBaseboard(state, afnHVAC.Name, zoneNum, false, SysOutputProvided, afnHVAC.CompIndex);
1077 0 : afnNode.NonAirSystemResponse += afnHVAC.SupplyFraction * SysOutputProvided;
1078 : // LatOutputProvided = 0.0d0 !This baseboard does not add / remove any latent heat
1079 0 : } break;
1080 :
1081 0 : case DataZoneEquipment::ZoneEquipType::HighTemperatureRadiant: {
1082 : // CASE(BBElectric_Num) !'ZoneHVAC:HighTemperatureRadiant' 17
1083 0 : SimHighTempRadiantSystem(state, afnHVAC.Name, false, SysOutputProvided, afnHVAC.CompIndex);
1084 0 : afnNode.NonAirSystemResponse += afnHVAC.SupplyFraction * SysOutputProvided;
1085 : // LatOutputProvided = 0.0d0 !This baseboard does not add / remove any latent heat
1086 0 : } break;
1087 :
1088 51891 : default: {
1089 51891 : } break;
1090 : } // switch
1091 :
1092 : // Zone sum of system convective gains, collected via NonAirSystemResponse
1093 : }
1094 :
1095 : } // SumNonAirSystemResponseForNode
1096 :
1097 : //*****************************************************************************************
1098 :
1099 3689 : void SumSystemDepResponseForNode(EnergyPlusData &state, int const zoneNum)
1100 : {
1101 : // SUBROUTINE INFORMATION:
1102 : // AUTHOR B.Griffith
1103 : // DATE WRITTEN aug 2005, Jan2004
1104 : // MODIFIED Lixing Gu, Aug. 2015 for v8.4 replease
1105 :
1106 : // PURPOSE OF THIS SUBROUTINE:
1107 : // Sum system sensible loads used at the next time step
1108 :
1109 : // USE STATEMENTS:
1110 : using ZoneDehumidifier::SimZoneDehumidifier;
1111 :
1112 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1113 : Real64 LatOutputProvided;
1114 :
1115 : // TODO
1116 :
1117 3689 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
1118 :
1119 : // SysDepZoneLoads saved to be added to zone heat balance next
1120 3689 : Real64 SysOutputProvided = 0.0;
1121 25823 : for (auto &afnNode : afnZoneInfo.Node) {
1122 22134 : afnNode.SysDepZoneLoadsLaggedOld = 0.0;
1123 44268 : for (auto &afnHVAC : afnNode.HVAC) {
1124 22134 : if (afnHVAC.zoneEquipType == DataZoneEquipment::ZoneEquipType::DehumidifierDX) {
1125 0 : if (SysOutputProvided == 0.0)
1126 0 : SimZoneDehumidifier(state, afnHVAC.Name, zoneNum, false, SysOutputProvided, LatOutputProvided, afnHVAC.CompIndex);
1127 0 : if (SysOutputProvided > 0.0) break;
1128 : }
1129 : }
1130 : }
1131 :
1132 3689 : if (SysOutputProvided > 0.0) {
1133 0 : for (auto &afnNode : afnZoneInfo.Node) {
1134 0 : for (auto const &afnHVAC : afnNode.HVAC) {
1135 0 : if (afnHVAC.zoneEquipType == DataZoneEquipment::ZoneEquipType::DehumidifierDX) {
1136 0 : afnNode.SysDepZoneLoadsLaggedOld += afnHVAC.SupplyFraction * SysOutputProvided;
1137 : }
1138 : }
1139 : }
1140 : }
1141 :
1142 3689 : } // SumSystemDepResponseForNode
1143 :
1144 : //*****************************************************************************************
1145 :
1146 : } // namespace RoomAir
1147 :
1148 : } // namespace EnergyPlus
|