Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <algorithm>
50 :
51 : #include <string>
52 :
53 : // ObjexxFCL Headers
54 : #include <ObjexxFCL/Array.functions.hh>
55 : #include <ObjexxFCL/Fmath.hh>
56 :
57 : // EnergyPlus Headers
58 : #include <AirflowNetwork/Solver.hpp>
59 : #include <EnergyPlus/Coils/CoilCoolingDX.hh>
60 : #include <EnergyPlus/Data/EnergyPlusData.hh>
61 : #include <EnergyPlus/DataAirLoop.hh>
62 : #include <EnergyPlus/DataAirSystems.hh>
63 : #include <EnergyPlus/DataConvergParams.hh>
64 : #include <EnergyPlus/DataHVACGlobals.hh>
65 : #include <EnergyPlus/DataHeatBalFanSys.hh>
66 : #include <EnergyPlus/DataHeatBalance.hh>
67 : #include <EnergyPlus/DataLoopNode.hh>
68 : #include <EnergyPlus/DataReportingFlags.hh>
69 : #include <EnergyPlus/DataSurfaces.hh>
70 : #include <EnergyPlus/DataSystemVariables.hh>
71 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
72 : #include <EnergyPlus/DemandManager.hh>
73 : #include <EnergyPlus/DisplayRoutines.hh>
74 : #include <EnergyPlus/EMSManager.hh>
75 : #include <EnergyPlus/ElectricPowerServiceManager.hh>
76 : #include <EnergyPlus/Fans.hh>
77 : #include <EnergyPlus/General.hh>
78 : #include <EnergyPlus/HVACManager.hh>
79 : #include <EnergyPlus/HVACSizingSimulationManager.hh>
80 : #include <EnergyPlus/IceThermalStorage.hh>
81 : #include <EnergyPlus/IndoorGreen.hh>
82 : #include <EnergyPlus/InternalHeatGains.hh>
83 : #include <EnergyPlus/NodeInputManager.hh>
84 : #include <EnergyPlus/NonZoneEquipmentManager.hh>
85 : #include <EnergyPlus/OutAirNodeManager.hh>
86 : #include <EnergyPlus/OutputProcessor.hh>
87 : #include <EnergyPlus/OutputReportTabular.hh>
88 : #include <EnergyPlus/Plant/DataPlant.hh>
89 : #include <EnergyPlus/Plant/PlantManager.hh>
90 : #include <EnergyPlus/PlantCondLoopOperation.hh>
91 : #include <EnergyPlus/PlantLoopHeatPumpEIR.hh>
92 : #include <EnergyPlus/PlantUtilities.hh>
93 : #include <EnergyPlus/PollutionModule.hh>
94 : #include <EnergyPlus/Psychrometrics.hh>
95 : #include <EnergyPlus/RefrigeratedCase.hh>
96 : #include <EnergyPlus/ScheduleManager.hh>
97 : #include <EnergyPlus/SetPointManager.hh>
98 : #include <EnergyPlus/SimAirServingZones.hh>
99 : #include <EnergyPlus/SizingManager.hh>
100 : #include <EnergyPlus/SystemAvailabilityManager.hh>
101 : #include <EnergyPlus/SystemReports.hh>
102 : #include <EnergyPlus/UtilityRoutines.hh>
103 : #include <EnergyPlus/WaterManager.hh>
104 : #include <EnergyPlus/ZoneContaminantPredictorCorrector.hh>
105 : #include <EnergyPlus/ZoneEquipmentManager.hh>
106 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
107 :
108 : namespace EnergyPlus::HVACManager {
109 :
110 : // PURPOSE OF THIS MODULE:
111 : // This module contains the high level HVAC control
112 : // subroutines. Subroutine ManageHVAC, which is called from the heat balance,
113 : // calls the HVAC simulation and is the most probable insertion point for
114 : // connections to other HVAC engines. ManageHVAC also controls the system
115 : // timestep, automatically shortening the timestep to meet convergence criteria.
116 :
117 : // METHODOLOGY EMPLOYED:
118 : // The basic solution technique is iteration with lagging.
119 : // The timestep is shortened using a bisection method.
120 :
121 : static constexpr std::array<Real64, DataPlant::NumConvergenceHistoryTerms> ConvergenceHistoryARR = {0.0, -1.0, -2.0, -3.0, -4.0};
122 : static constexpr std::array<std::string_view, static_cast<int>(ConvErrorCallType::Num)> ConvErrorCallString = {
123 : "mass flow rate", "humidity ratio", "temperature", "energy", "CO2", "generic contaminant"};
124 : constexpr Real64 sum_ConvergenceHistoryARR(-10.0);
125 : constexpr Real64 square_sum_ConvergenceHistoryARR(100.0);
126 : constexpr Real64 sum_square_ConvergenceHistoryARR(30.0);
127 :
128 248593 : void ManageHVAC(EnergyPlusData &state)
129 : {
130 :
131 : // SUBROUTINE INFORMATION:
132 : // AUTHORS: Russ Taylor, Dan Fisher
133 : // DATE WRITTEN: Jan. 1998
134 : // MODIFIED Jul 2003 (CC) added a subroutine call for air models
135 : // RE-ENGINEERED May 2008, Brent Griffith, revised variable time step method and zone conditions history
136 :
137 : // PURPOSE OF THIS SUBROUTINE:
138 : // This routine effectively replaces the IBLAST
139 : // "SystemDriver" routine. The main function of the routine
140 : // is to set the system timestep, "TimeStepSys", call the models related to zone
141 : // air temperatures, and .
142 :
143 : // METHODOLOGY EMPLOYED:
144 : // manage calls to Predictor and Corrector and other updates in ZoneTempPredictorCorrector
145 : // manage variable time step and when zone air histories are updated.
146 :
147 : // SUBROUTINE PARAMETER DEFINITIONS:
148 : static constexpr std::string_view EndOfHeaderString("End of Data Dictionary"); // End of data dictionary marker
149 : static constexpr std::string_view EnvironmentStampFormatStr("{},{},{:7.2F},{:7.2F},{:7.2F},{:7.2F}\n"); // Format descriptor for environ stamp
150 :
151 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
152 : Real64 PriorTimeStep; // magnitude of time step for previous history terms
153 248593 : Real64 ZoneTempChange(0.0); // change in zone air temperature from timestep t-1 to t
154 :
155 248593 : auto &s_hbfs = state.dataHeatBalFanSys;
156 :
157 : // SYSTEM INITIALIZATION
158 248593 : if (state.dataHVACMgr->TriggerGetAFN) {
159 102 : state.dataHVACMgr->TriggerGetAFN = false;
160 102 : DisplayString(state, "Initializing HVAC");
161 102 : state.afn->manage_balance(); // first call only gets input and returns.
162 : }
163 :
164 583880 : for (auto &thisZoneHB : state.dataZoneTempPredictorCorrector->zoneHeatBalance) {
165 335287 : thisZoneHB.ZT = thisZoneHB.MAT;
166 : // save for use with thermal comfort control models (Fang, Pierce, and KSU)
167 335287 : thisZoneHB.ZTAV = 0.0;
168 335287 : thisZoneHB.airHumRatAvg = 0.0;
169 : }
170 620183 : for (auto &thisSpaceHB : state.dataZoneTempPredictorCorrector->spaceHeatBalance) {
171 371590 : thisSpaceHB.ZT = thisSpaceHB.MAT;
172 : // save for use with thermal comfort control models (Fang, Pierce, and KSU)
173 371590 : thisSpaceHB.ZTAV = 0.0;
174 371590 : thisSpaceHB.airHumRatAvg = 0.0;
175 : }
176 :
177 583758 : for (auto &zoneTstatSetpt : s_hbfs->zoneTstatSetpts) {
178 335165 : zoneTstatSetpt.setptHiAver = zoneTstatSetpt.setptLoAver = 0.0;
179 : }
180 :
181 248593 : state.dataHVACMgr->PrintedWarmup = false;
182 248593 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
183 0 : state.dataContaminantBalance->OutdoorCO2 = state.dataContaminantBalance->Contaminant.CO2OutdoorSched->getCurrentVal();
184 0 : state.dataContaminantBalance->ZoneAirCO2Avg = 0.0;
185 : }
186 248593 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
187 0 : state.dataContaminantBalance->OutdoorGC = state.dataContaminantBalance->Contaminant.genericOutdoorSched->getCurrentVal();
188 0 : if (allocated(state.dataContaminantBalance->ZoneAirGCAvg)) state.dataContaminantBalance->ZoneAirGCAvg = 0.0;
189 : }
190 :
191 248593 : if (state.dataGlobal->BeginEnvrnFlag && state.dataHVACMgr->MyEnvrnFlag) {
192 478 : state.dataHVACGlobal->AirLoopsSimOnce = false;
193 478 : state.dataHVACMgr->MyEnvrnFlag = false;
194 478 : state.dataHVACGlobal->NumOfSysTimeStepsLastZoneTimeStep = 1;
195 478 : state.dataHVACGlobal->PreviousTimeStep = state.dataGlobal->TimeStepZone;
196 : }
197 248593 : if (!state.dataGlobal->BeginEnvrnFlag) {
198 248115 : state.dataHVACMgr->MyEnvrnFlag = true;
199 : }
200 :
201 248593 : state.dataHeatBalFanSys->QRadSurfAFNDuct = 0.0;
202 :
203 248593 : state.dataHVACGlobal->SysTimeElapsed = 0.0;
204 248593 : state.dataHVACGlobal->TimeStepSys = state.dataGlobal->TimeStepZone;
205 248593 : state.dataHVACGlobal->TimeStepSysSec = state.dataHVACGlobal->TimeStepSys * Constant::rSecsInHour;
206 248593 : state.dataHVACGlobal->FirstTimeStepSysFlag = true;
207 248593 : state.dataHVACGlobal->ShortenTimeStepSys = false;
208 248593 : state.dataHVACGlobal->UseZoneTimeStepHistory = true;
209 248593 : PriorTimeStep = state.dataGlobal->TimeStepZone;
210 248593 : state.dataHVACGlobal->NumOfSysTimeSteps = 1;
211 248593 : state.dataHVACGlobal->FracTimeStepZone = state.dataHVACGlobal->TimeStepSys / state.dataGlobal->TimeStepZone;
212 :
213 : bool anyEMSRan;
214 248593 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyEMSRan, ObjexxFCL::Optional_int_const()); // calling point
215 :
216 248593 : OutAirNodeManager::SetOutAirNodes(state);
217 :
218 248593 : RefrigeratedCase::ManageRefrigeratedCaseRacks(state);
219 :
220 : // ZONE INITIALIZATION 'Get Zone Setpoints'
221 497186 : ZoneTempPredictorCorrector::ManageZoneAirUpdates(state,
222 : DataHeatBalFanSys::PredictorCorrectorCtrl::GetZoneSetPoints,
223 : ZoneTempChange,
224 248593 : state.dataHVACGlobal->ShortenTimeStepSys,
225 248593 : state.dataHVACGlobal->UseZoneTimeStepHistory,
226 : PriorTimeStep);
227 248593 : if (state.dataContaminantBalance->Contaminant.SimulateContaminants)
228 0 : ZoneContaminantPredictorCorrector::ManageZoneContaminanUpdates(state,
229 : DataHeatBalFanSys::PredictorCorrectorCtrl::GetZoneSetPoints,
230 0 : state.dataHVACGlobal->ShortenTimeStepSys,
231 0 : state.dataHVACGlobal->UseZoneTimeStepHistory,
232 : PriorTimeStep);
233 :
234 248593 : Avail::ManageHybridVentilation(state);
235 :
236 248593 : ZoneEquipmentManager::CalcAirFlowSimple(state);
237 248593 : if (state.afn->simulation_control.type != AirflowNetwork::ControlType::NoMultizoneOrDistribution) {
238 4044 : state.afn->RollBackFlag = false;
239 4044 : state.afn->manage_balance(false);
240 : }
241 :
242 248593 : SetHeatToReturnAirFlag(state);
243 :
244 583880 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
245 335287 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum);
246 335287 : thisZoneHB.SysDepZoneLoadsLagged = thisZoneHB.SysDepZoneLoads;
247 335287 : if (state.dataHeatBal->doSpaceHeatBalance) {
248 56616 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
249 : // SpaceHB ToDo: For now allocate by space volume frac
250 42462 : state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum).SysDepZoneLoadsLagged =
251 42462 : thisZoneHB.SysDepZoneLoads * state.dataHeatBal->space(spaceNum).fracZoneVolume;
252 : }
253 : }
254 : }
255 248593 : IndoorGreen::SimIndoorGreen(state);
256 248593 : InternalHeatGains::UpdateInternalGainValues(state, true, true);
257 :
258 497186 : ZoneTempPredictorCorrector::ManageZoneAirUpdates(state,
259 : DataHeatBalFanSys::PredictorCorrectorCtrl::PredictStep,
260 : ZoneTempChange,
261 248593 : state.dataHVACGlobal->ShortenTimeStepSys,
262 248593 : state.dataHVACGlobal->UseZoneTimeStepHistory,
263 : PriorTimeStep);
264 :
265 248593 : if (state.dataContaminantBalance->Contaminant.SimulateContaminants)
266 0 : ZoneContaminantPredictorCorrector::ManageZoneContaminanUpdates(state,
267 : DataHeatBalFanSys::PredictorCorrectorCtrl::PredictStep,
268 0 : state.dataHVACGlobal->ShortenTimeStepSys,
269 0 : state.dataHVACGlobal->UseZoneTimeStepHistory,
270 : PriorTimeStep);
271 :
272 248593 : SimHVAC(state);
273 248592 : if (state.dataGlobal->AnyIdealCondEntSetPointInModel && state.dataGlobal->MetersHaveBeenInitialized && !state.dataGlobal->WarmupFlag) {
274 0 : state.dataGlobal->RunOptCondEntTemp = true;
275 0 : while (state.dataGlobal->RunOptCondEntTemp) {
276 0 : SimHVAC(state);
277 : }
278 : }
279 :
280 248592 : WaterManager::ManageWaterInits(state);
281 :
282 : // Only simulate once per zone timestep; must be after SimHVAC
283 248592 : if (state.dataHVACGlobal->FirstTimeStepSysFlag && state.dataGlobal->MetersHaveBeenInitialized) {
284 164434 : DemandManager::ManageDemand(state);
285 : }
286 :
287 248592 : state.dataGlobal->BeginTimeStepFlag = false; // At this point, we have been through the first pass through SimHVAC so this needs to be set
288 :
289 497184 : ZoneTempPredictorCorrector::ManageZoneAirUpdates(state,
290 : DataHeatBalFanSys::PredictorCorrectorCtrl::CorrectStep,
291 : ZoneTempChange,
292 248592 : state.dataHVACGlobal->ShortenTimeStepSys,
293 248592 : state.dataHVACGlobal->UseZoneTimeStepHistory,
294 : PriorTimeStep);
295 248592 : if (state.dataContaminantBalance->Contaminant.SimulateContaminants)
296 0 : ZoneContaminantPredictorCorrector::ManageZoneContaminanUpdates(state,
297 : DataHeatBalFanSys::PredictorCorrectorCtrl::CorrectStep,
298 0 : state.dataHVACGlobal->ShortenTimeStepSys,
299 0 : state.dataHVACGlobal->UseZoneTimeStepHistory,
300 : PriorTimeStep);
301 :
302 248592 : if (ZoneTempChange > state.dataConvergeParams->MaxZoneTempDiff && !state.dataGlobal->KickOffSimulation) {
303 : // determine value of adaptive system time step
304 : // model how many system timesteps we want in zone timestep
305 9992 : int ZTempTrendsNumSysSteps = int(ZoneTempChange / state.dataConvergeParams->MaxZoneTempDiff + 1.0); // add 1 for truncation
306 9992 : state.dataHVACGlobal->NumOfSysTimeSteps = min(ZTempTrendsNumSysSteps, state.dataHVACGlobal->LimitNumSysSteps);
307 : // then determine timestep length for even distribution, protect div by zero
308 9992 : if (state.dataHVACGlobal->NumOfSysTimeSteps > 0) {
309 9992 : state.dataHVACGlobal->TimeStepSys = state.dataGlobal->TimeStepZone / state.dataHVACGlobal->NumOfSysTimeSteps;
310 : }
311 9992 : state.dataHVACGlobal->TimeStepSys = max(state.dataHVACGlobal->TimeStepSys, state.dataConvergeParams->MinTimeStepSys);
312 9992 : state.dataHVACGlobal->TimeStepSysSec = state.dataHVACGlobal->TimeStepSys * Constant::rSecsInHour;
313 9992 : state.dataHVACGlobal->UseZoneTimeStepHistory = false;
314 9992 : state.dataHVACGlobal->ShortenTimeStepSys = true;
315 :
316 : } else {
317 238600 : state.dataHVACGlobal->NumOfSysTimeSteps = 1;
318 238600 : state.dataHVACGlobal->UseZoneTimeStepHistory = true;
319 : }
320 :
321 248592 : if (state.dataHVACGlobal->UseZoneTimeStepHistory) state.dataHVACGlobal->PreviousTimeStep = state.dataGlobal->TimeStepZone;
322 535854 : for (int SysTimestepLoop = 1; SysTimestepLoop <= state.dataHVACGlobal->NumOfSysTimeSteps; ++SysTimestepLoop) {
323 287263 : if (state.dataGlobal->stopSimulation) break;
324 :
325 287262 : if (state.dataHVACGlobal->TimeStepSys < state.dataGlobal->TimeStepZone) {
326 :
327 48663 : Avail::ManageHybridVentilation(state);
328 48663 : ZoneEquipmentManager::CalcAirFlowSimple(state, SysTimestepLoop);
329 48663 : if (state.afn->simulation_control.type != AirflowNetwork::ControlType::NoMultizoneOrDistribution) {
330 1640 : state.afn->RollBackFlag = false;
331 1640 : state.afn->manage_balance(false);
332 : }
333 :
334 48663 : InternalHeatGains::UpdateInternalGainValues(state, true, true);
335 :
336 97326 : ZoneTempPredictorCorrector::ManageZoneAirUpdates(state,
337 : DataHeatBalFanSys::PredictorCorrectorCtrl::PredictStep,
338 : ZoneTempChange,
339 48663 : state.dataHVACGlobal->ShortenTimeStepSys,
340 48663 : state.dataHVACGlobal->UseZoneTimeStepHistory,
341 : PriorTimeStep);
342 :
343 48663 : if (state.dataContaminantBalance->Contaminant.SimulateContaminants)
344 0 : ZoneContaminantPredictorCorrector::ManageZoneContaminanUpdates(state,
345 : DataHeatBalFanSys::PredictorCorrectorCtrl::PredictStep,
346 0 : state.dataHVACGlobal->ShortenTimeStepSys,
347 0 : state.dataHVACGlobal->UseZoneTimeStepHistory,
348 : PriorTimeStep);
349 48663 : SimHVAC(state);
350 :
351 48663 : if (state.dataGlobal->AnyIdealCondEntSetPointInModel && state.dataGlobal->MetersHaveBeenInitialized && !state.dataGlobal->WarmupFlag) {
352 0 : state.dataGlobal->RunOptCondEntTemp = true;
353 0 : while (state.dataGlobal->RunOptCondEntTemp) {
354 0 : SimHVAC(state);
355 : }
356 : }
357 :
358 48663 : WaterManager::ManageWaterInits(state);
359 :
360 : // Need to set the flag back since we do not need to shift the temps back again in the correct step.
361 48663 : state.dataHVACGlobal->ShortenTimeStepSys = false;
362 :
363 97326 : ZoneTempPredictorCorrector::ManageZoneAirUpdates(state,
364 : DataHeatBalFanSys::PredictorCorrectorCtrl::CorrectStep,
365 : ZoneTempChange,
366 48663 : state.dataHVACGlobal->ShortenTimeStepSys,
367 48663 : state.dataHVACGlobal->UseZoneTimeStepHistory,
368 : PriorTimeStep);
369 48663 : if (state.dataContaminantBalance->Contaminant.SimulateContaminants)
370 0 : ZoneContaminantPredictorCorrector::ManageZoneContaminanUpdates(state,
371 : DataHeatBalFanSys::PredictorCorrectorCtrl::CorrectStep,
372 0 : state.dataHVACGlobal->ShortenTimeStepSys,
373 0 : state.dataHVACGlobal->UseZoneTimeStepHistory,
374 : PriorTimeStep);
375 :
376 97326 : ZoneTempPredictorCorrector::ManageZoneAirUpdates(state,
377 : DataHeatBalFanSys::PredictorCorrectorCtrl::PushSystemTimestepHistories,
378 : ZoneTempChange,
379 48663 : state.dataHVACGlobal->ShortenTimeStepSys,
380 48663 : state.dataHVACGlobal->UseZoneTimeStepHistory,
381 : PriorTimeStep);
382 48663 : if (state.dataContaminantBalance->Contaminant.SimulateContaminants)
383 0 : ZoneContaminantPredictorCorrector::ManageZoneContaminanUpdates(state,
384 : DataHeatBalFanSys::PredictorCorrectorCtrl::PushSystemTimestepHistories,
385 0 : state.dataHVACGlobal->ShortenTimeStepSys,
386 0 : state.dataHVACGlobal->UseZoneTimeStepHistory,
387 : PriorTimeStep);
388 48663 : state.dataHVACGlobal->PreviousTimeStep = state.dataHVACGlobal->TimeStepSys;
389 : }
390 :
391 287262 : state.dataHVACGlobal->FracTimeStepZone = state.dataHVACGlobal->TimeStepSys / state.dataGlobal->TimeStepZone;
392 :
393 687557 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
394 400295 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
395 400295 : thisZoneHB.ZTAV += thisZoneHB.ZT * state.dataHVACGlobal->FracTimeStepZone;
396 400295 : thisZoneHB.airHumRatAvg += thisZoneHB.airHumRat * state.dataHVACGlobal->FracTimeStepZone;
397 : // Space temps are always used, regardless of doSpaceHeatBalance setting
398 854219 : for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
399 453924 : auto &thisSpaceHB = state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum);
400 453924 : thisSpaceHB.ZTAV += thisSpaceHB.ZT * state.dataHVACGlobal->FracTimeStepZone;
401 453924 : thisSpaceHB.airHumRatAvg += thisSpaceHB.airHumRat * state.dataHVACGlobal->FracTimeStepZone;
402 : }
403 400295 : if (state.dataContaminantBalance->Contaminant.CO2Simulation)
404 0 : state.dataContaminantBalance->ZoneAirCO2Avg(ZoneNum) +=
405 0 : state.dataContaminantBalance->ZoneAirCO2(ZoneNum) * state.dataHVACGlobal->FracTimeStepZone;
406 400295 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation)
407 0 : state.dataContaminantBalance->ZoneAirGCAvg(ZoneNum) +=
408 0 : state.dataContaminantBalance->ZoneAirGC(ZoneNum) * state.dataHVACGlobal->FracTimeStepZone;
409 400295 : if (state.dataZoneTempPredictorCorrector->NumOnOffCtrZone > 0) {
410 0 : auto &zoneTstatSetpt = s_hbfs->zoneTstatSetpts(ZoneNum);
411 0 : zoneTstatSetpt.setptHiAver += zoneTstatSetpt.setptHi * state.dataHVACGlobal->FracTimeStepZone;
412 0 : zoneTstatSetpt.setptLoAver += zoneTstatSetpt.setptLo * state.dataHVACGlobal->FracTimeStepZone;
413 : }
414 : }
415 :
416 287262 : ZoneTempPredictorCorrector::DetectOscillatingZoneTemp(state);
417 287262 : UpdateZoneListAndGroupLoads(state); // Must be called before UpdateDataandReport(OutputProcessor::TimeStepType::TimeStepSystem)
418 287262 : IceThermalStorage::UpdateIceFractions(state); // Update fraction of ice stored in TES
419 287262 : WaterManager::ManageWater(state);
420 : // update electricity data for net, purchased, sold etc.
421 287262 : bool DummyLogical = false;
422 287262 : state.dataElectPwrSvcMgr->facilityElectricServiceObj->manageElectricPowerService(state, false, DummyLogical, true);
423 :
424 : // Update the plant and condenser loop capacitance model temperature history.
425 287262 : PlantManager::UpdateNodeThermalHistory(state);
426 :
427 287262 : if (state.dataOutRptTab->displayHeatEmissionsSummary) {
428 71332 : OutputReportTabular::CalcHeatEmissionReport(state);
429 : }
430 :
431 287262 : EMSManager::ManageEMS(
432 574524 : state, EMSManager::EMSCallFrom::EndSystemTimestepBeforeHVACReporting, anyEMSRan, ObjexxFCL::Optional_int_const()); // EMS calling point
433 :
434 : // This is where output processor data is updated for System Timestep reporting
435 287262 : if (!state.dataGlobal->WarmupFlag) {
436 32524 : if (state.dataGlobal->DoOutputReporting && !state.dataGlobal->ZoneSizingCalc) {
437 19866 : NodeInputManager::CalcMoreNodeInfo(state);
438 19866 : Pollution::CalculatePollution(state);
439 19866 : SystemReports::InitEnergyReports(state);
440 19866 : SystemReports::ReportSystemEnergyUse(state);
441 : }
442 32524 : if (state.dataGlobal->DoOutputReporting || (state.dataGlobal->ZoneSizingCalc && state.dataGlobal->CompLoadReportIsReq)) {
443 24426 : ReportAirHeatBalance(state);
444 24426 : if (state.dataGlobal->ZoneSizingCalc) OutputReportTabular::GatherComponentLoadsHVAC(state);
445 : }
446 32524 : if (state.dataGlobal->DoOutputReporting) {
447 22362 : SystemReports::ReportVentilationLoads(state);
448 22362 : UpdateDataandReport(state, OutputProcessor::TimeStepType::System);
449 44724 : if (state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeDesignDay ||
450 22362 : state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeRunPeriodDesign) {
451 0 : if (state.dataHVACSizingSimMgr->hvacSizingSimulationManager)
452 0 : state.dataHVACSizingSimMgr->hvacSizingSimulationManager->UpdateSizingLogsSystemStep(state);
453 : }
454 22362 : OutputReportTabular::UpdateTabularReports(state, OutputProcessor::TimeStepType::System);
455 : }
456 32524 : if (state.dataGlobal->ZoneSizingCalc) {
457 12316 : ZoneEquipmentManager::UpdateZoneSizing(state, Constant::CallIndicator::DuringDay);
458 12316 : SizingManager::UpdateFacilitySizing(state, Constant::CallIndicator::DuringDay);
459 : }
460 32524 : EIRPlantLoopHeatPumps::EIRPlantLoopHeatPump::checkConcurrentOperation(state);
461 254738 : } else if (!state.dataGlobal->KickOffSimulation && state.dataGlobal->DoOutputReporting && state.dataSysVars->ReportDuringWarmup) {
462 0 : if (state.dataGlobal->BeginDayFlag && !state.dataEnvrn->PrintEnvrnStampWarmupPrinted) {
463 0 : state.dataEnvrn->PrintEnvrnStampWarmup = true;
464 0 : state.dataEnvrn->PrintEnvrnStampWarmupPrinted = true;
465 : }
466 0 : if (!state.dataGlobal->BeginDayFlag) state.dataEnvrn->PrintEnvrnStampWarmupPrinted = false;
467 0 : if (state.dataEnvrn->PrintEnvrnStampWarmup) {
468 0 : if (state.dataReportFlag->PrintEndDataDictionary && state.dataGlobal->DoOutputReporting && !state.dataHVACMgr->PrintedWarmup) {
469 0 : print(state.files.eso, "{}\n", EndOfHeaderString);
470 0 : print(state.files.mtr, "{}\n", EndOfHeaderString);
471 0 : state.dataReportFlag->PrintEndDataDictionary = false;
472 : }
473 0 : if (state.dataGlobal->DoOutputReporting && !state.dataHVACMgr->PrintedWarmup) {
474 :
475 0 : print(state.files.eso,
476 : EnvironmentStampFormatStr,
477 : "1",
478 0 : "Warmup {" + state.dataReportFlag->cWarmupDay + "} " + state.dataEnvrn->EnvironmentName,
479 0 : state.dataEnvrn->Latitude,
480 0 : state.dataEnvrn->Longitude,
481 0 : state.dataEnvrn->TimeZoneNumber,
482 0 : state.dataEnvrn->Elevation);
483 0 : print(state.files.mtr,
484 : EnvironmentStampFormatStr,
485 : "1",
486 0 : "Warmup {" + state.dataReportFlag->cWarmupDay + "} " + state.dataEnvrn->EnvironmentName,
487 0 : state.dataEnvrn->Latitude,
488 0 : state.dataEnvrn->Longitude,
489 0 : state.dataEnvrn->TimeZoneNumber,
490 0 : state.dataEnvrn->Elevation);
491 0 : state.dataEnvrn->PrintEnvrnStampWarmup = false;
492 : }
493 0 : state.dataHVACMgr->PrintedWarmup = true;
494 : }
495 0 : if (!state.dataGlobal->DoingSizing) {
496 0 : NodeInputManager::CalcMoreNodeInfo(state);
497 : }
498 0 : UpdateDataandReport(state, OutputProcessor::TimeStepType::System);
499 0 : if (state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeDesignDay ||
500 0 : state.dataGlobal->KindOfSim == Constant::KindOfSim::HVACSizeRunPeriodDesign) {
501 0 : if (state.dataHVACSizingSimMgr->hvacSizingSimulationManager)
502 0 : state.dataHVACSizingSimMgr->hvacSizingSimulationManager->UpdateSizingLogsSystemStep(state);
503 : }
504 254738 : } else if (state.dataSysVars->UpdateDataDuringWarmupExternalInterface) { // added for FMI
505 0 : if (state.dataGlobal->BeginDayFlag && !state.dataEnvrn->PrintEnvrnStampWarmupPrinted) {
506 0 : state.dataEnvrn->PrintEnvrnStampWarmup = true;
507 0 : state.dataEnvrn->PrintEnvrnStampWarmupPrinted = true;
508 : }
509 0 : if (!state.dataGlobal->BeginDayFlag) state.dataEnvrn->PrintEnvrnStampWarmupPrinted = false;
510 0 : if (state.dataEnvrn->PrintEnvrnStampWarmup) {
511 0 : if (state.dataReportFlag->PrintEndDataDictionary && state.dataGlobal->DoOutputReporting && !state.dataHVACMgr->PrintedWarmup) {
512 0 : print(state.files.eso, "{}\n", EndOfHeaderString);
513 0 : print(state.files.mtr, "{}\n", EndOfHeaderString);
514 0 : state.dataReportFlag->PrintEndDataDictionary = false;
515 : }
516 0 : if (state.dataGlobal->DoOutputReporting && !state.dataHVACMgr->PrintedWarmup) {
517 0 : print(state.files.eso,
518 : EnvironmentStampFormatStr,
519 : "1",
520 0 : "Warmup {" + state.dataReportFlag->cWarmupDay + "} " + state.dataEnvrn->EnvironmentName,
521 0 : state.dataEnvrn->Latitude,
522 0 : state.dataEnvrn->Longitude,
523 0 : state.dataEnvrn->TimeZoneNumber,
524 0 : state.dataEnvrn->Elevation);
525 0 : print(state.files.mtr,
526 : EnvironmentStampFormatStr,
527 : "1",
528 0 : "Warmup {" + state.dataReportFlag->cWarmupDay + "} " + state.dataEnvrn->EnvironmentName,
529 0 : state.dataEnvrn->Latitude,
530 0 : state.dataEnvrn->Longitude,
531 0 : state.dataEnvrn->TimeZoneNumber,
532 0 : state.dataEnvrn->Elevation);
533 0 : state.dataEnvrn->PrintEnvrnStampWarmup = false;
534 : }
535 0 : state.dataHVACMgr->PrintedWarmup = true;
536 : }
537 0 : UpdateDataandReport(state, OutputProcessor::TimeStepType::System);
538 : }
539 287262 : EMSManager::ManageEMS(
540 574524 : state, EMSManager::EMSCallFrom::EndSystemTimestepAfterHVACReporting, anyEMSRan, ObjexxFCL::Optional_int_const()); // EMS calling point
541 : // UPDATE SYSTEM CLOCKS
542 287262 : state.dataHVACGlobal->SysTimeElapsed += state.dataHVACGlobal->TimeStepSys;
543 :
544 287262 : state.dataHVACGlobal->FirstTimeStepSysFlag = false;
545 : } // system time step loop (loops once if no downstepping)
546 :
547 583878 : for (auto &thisZoneHB : state.dataZoneTempPredictorCorrector->zoneHeatBalance) {
548 335286 : thisZoneHB.ZTAVComf = thisZoneHB.ZTAV;
549 335286 : thisZoneHB.airHumRatAvgComf = thisZoneHB.airHumRatAvg;
550 : }
551 620181 : for (auto &thisSpaceHB : state.dataZoneTempPredictorCorrector->spaceHeatBalance) {
552 371589 : thisSpaceHB.ZTAVComf = thisSpaceHB.ZTAV;
553 371589 : thisSpaceHB.airHumRatAvgComf = thisSpaceHB.airHumRatAvg;
554 : }
555 :
556 497184 : ZoneTempPredictorCorrector::ManageZoneAirUpdates(state,
557 : DataHeatBalFanSys::PredictorCorrectorCtrl::PushZoneTimestepHistories,
558 : ZoneTempChange,
559 248592 : state.dataHVACGlobal->ShortenTimeStepSys,
560 248592 : state.dataHVACGlobal->UseZoneTimeStepHistory,
561 : PriorTimeStep);
562 248592 : if (state.dataContaminantBalance->Contaminant.SimulateContaminants)
563 0 : ZoneContaminantPredictorCorrector::ManageZoneContaminanUpdates(state,
564 : DataHeatBalFanSys::PredictorCorrectorCtrl::PushZoneTimestepHistories,
565 0 : state.dataHVACGlobal->ShortenTimeStepSys,
566 0 : state.dataHVACGlobal->UseZoneTimeStepHistory,
567 : PriorTimeStep);
568 :
569 248592 : state.dataHVACGlobal->NumOfSysTimeStepsLastZoneTimeStep = state.dataHVACGlobal->NumOfSysTimeSteps;
570 :
571 248592 : DemandManager::UpdateDemandManagers(state);
572 :
573 : // DO FINAL UPDATE OF RECORD KEEPING VARIABLES
574 : // Report the Node Data to Aid in Debugging
575 248592 : if (state.dataReportFlag->DebugOutput) {
576 : bool ReportDebug;
577 0 : if (state.dataReportFlag->EvenDuringWarmup) {
578 0 : ReportDebug = true;
579 : } else {
580 0 : ReportDebug = !state.dataGlobal->WarmupFlag;
581 : }
582 0 : if ((ReportDebug) && (state.dataGlobal->DayOfSim > 0)) { // Report the node data
583 : // report node name list and column header each time number of nodes changes
584 : static int numNodes = 0;
585 0 : if (isize(state.dataLoopNodes->Node) > numNodes) state.dataHVACMgr->DebugNamesReported = false;
586 0 : if (size(state.dataLoopNodes->Node) > 0 && !state.dataHVACMgr->DebugNamesReported) {
587 0 : numNodes = isize(state.dataLoopNodes->Node);
588 0 : print(state.files.debug, "{}\n", "node # Node Type Name");
589 0 : for (int NodeNum = 1; NodeNum <= isize(state.dataLoopNodes->Node); ++NodeNum) {
590 0 : print(state.files.debug,
591 : " {:3} {} {}\n",
592 : NodeNum,
593 0 : DataLoopNode::NodeFluidTypeNames[static_cast<int>(state.dataLoopNodes->Node(NodeNum).FluidType)],
594 0 : state.dataLoopNodes->NodeID(NodeNum));
595 : }
596 0 : print(state.files.debug, "Day of Sim, Hour of Day, TimeStep,");
597 0 : for (int NodeNum = 1; NodeNum <= isize(state.dataLoopNodes->Node); ++NodeNum) {
598 0 : print(state.files.debug, "{}: Temp,", state.dataLoopNodes->NodeID(NodeNum));
599 0 : print(state.files.debug, "{}: MassMinAv,", state.dataLoopNodes->NodeID(NodeNum));
600 0 : print(state.files.debug, "{}: MassMaxAv,", state.dataLoopNodes->NodeID(NodeNum));
601 0 : print(state.files.debug, "{}: TempSP,", state.dataLoopNodes->NodeID(NodeNum));
602 0 : print(state.files.debug, "{}: MassFlow,", state.dataLoopNodes->NodeID(NodeNum));
603 0 : print(state.files.debug, "{}: MassMin,", state.dataLoopNodes->NodeID(NodeNum));
604 0 : print(state.files.debug, "{}: MassMax,", state.dataLoopNodes->NodeID(NodeNum));
605 0 : print(state.files.debug, "{}: MassSP,", state.dataLoopNodes->NodeID(NodeNum));
606 0 : print(state.files.debug, "{}: Press,", state.dataLoopNodes->NodeID(NodeNum));
607 0 : print(state.files.debug, "{}: Enth,", state.dataLoopNodes->NodeID(NodeNum));
608 0 : print(state.files.debug, "{}: HumRat,", state.dataLoopNodes->NodeID(NodeNum));
609 0 : print(state.files.debug, "{}: Fluid Type,", state.dataLoopNodes->NodeID(NodeNum));
610 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation)
611 0 : print(state.files.debug, "{}: CO2Conc,", state.dataLoopNodes->NodeID(NodeNum));
612 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation)
613 0 : print(state.files.debug, "{}: GenericContamConc,", state.dataLoopNodes->NodeID(NodeNum));
614 0 : if (NodeNum == isize(state.dataLoopNodes->Node)) print(state.files.debug, "\n");
615 : }
616 0 : state.dataHVACMgr->DebugNamesReported = true;
617 : }
618 0 : if (size(state.dataLoopNodes->Node) > 0) {
619 0 : print(state.files.debug,
620 : "{:12},{:12}, {:22.15N},",
621 0 : state.dataGlobal->DayOfSim,
622 0 : state.dataGlobal->HourOfDay,
623 0 : state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone);
624 : }
625 : static constexpr std::string_view Format_20{
626 : " {:8.2F}, {:8.3F}, {:8.3F}, {:8.2F}, {:13.2F}, {:13.2F}, {:13.2F}, {:13.2F}, {:#7.0F}, {:11.2F}, {:9.5F}, {},"};
627 : static constexpr std::string_view Format_21{" {:8.2F},"};
628 0 : for (int NodeNum = 1; NodeNum <= isize(state.dataLoopNodes->Node); ++NodeNum) {
629 :
630 0 : print(state.files.debug,
631 : Format_20,
632 0 : state.dataLoopNodes->Node(NodeNum).Temp,
633 0 : state.dataLoopNodes->Node(NodeNum).MassFlowRateMinAvail,
634 0 : state.dataLoopNodes->Node(NodeNum).MassFlowRateMaxAvail,
635 0 : state.dataLoopNodes->Node(NodeNum).TempSetPoint,
636 0 : state.dataLoopNodes->Node(NodeNum).MassFlowRate,
637 0 : state.dataLoopNodes->Node(NodeNum).MassFlowRateMin,
638 0 : state.dataLoopNodes->Node(NodeNum).MassFlowRateMax,
639 0 : state.dataLoopNodes->Node(NodeNum).MassFlowRateSetPoint,
640 0 : state.dataLoopNodes->Node(NodeNum).Press,
641 0 : state.dataLoopNodes->Node(NodeNum).Enthalpy,
642 0 : state.dataLoopNodes->Node(NodeNum).HumRat,
643 0 : DataLoopNode::NodeFluidTypeNames[static_cast<int>(state.dataLoopNodes->Node(NodeNum).FluidType)]);
644 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation)
645 0 : print(state.files.debug, Format_21, state.dataLoopNodes->Node(NodeNum).CO2);
646 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation)
647 0 : print(state.files.debug, Format_21, state.dataLoopNodes->Node(NodeNum).GenContam);
648 0 : if (NodeNum == isize(state.dataLoopNodes->Node)) print(state.files.debug, "\n");
649 : }
650 : }
651 : }
652 248592 : }
653 :
654 297256 : void SimHVAC(EnergyPlusData &state)
655 : {
656 :
657 : // SUBROUTINE INFORMATION:
658 : // AUTHOR: Dan Fisher
659 : // DATE WRITTEN: April 1997
660 : // DATE MODIFIED: May 1998 (RKS,RDT)
661 :
662 : // PURPOSE OF THIS SUBROUTINE: Selects and calls the HVAC loop managers
663 :
664 : // METHODOLOGY EMPLOYED: Each loop manager is called or passed over
665 : // in succession based on the logical flags associated with the manager.
666 : // The logical flags are set in the manager routines and passed
667 : // as parameters to this routine. Each loop manager potentially
668 : // affects a different set of other loop managers.
669 :
670 : // Future development could involve specifying any number of user
671 : // selectable control schemes based on the logical flags used in
672 : // this default control algorithm.
673 :
674 : // SUBROUTINE PARAMETER DEFINITIONS:
675 297256 : bool constexpr SimWithPlantFlowUnlocked(false);
676 297256 : bool constexpr SimWithPlantFlowLocked(true);
677 :
678 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
679 : bool FirstHVACIteration; // True when solution technique on first iteration
680 : Real64 SlopeHumRat;
681 : Real64 SlopeMdot;
682 : Real64 SlopeTemps;
683 : Real64 AvgValue;
684 :
685 : static constexpr std::array<Real64, DataConvergParams::ConvergLogStackDepth> ConvergLogStackARR = {
686 : 0.0, -1.0, -2.0, -3.0, -4.0, -5.0, -6.0, -7.0, -8.0, -9.0};
687 297256 : Real64 constexpr sum_ConvergLogStackARR(-45);
688 297256 : Real64 constexpr square_sum_ConvergLogStackARR(2025);
689 297256 : Real64 constexpr sum_square_ConvergLogStackARR(285);
690 :
691 297256 : int NumPrimaryAirSys = state.dataHVACGlobal->NumPrimaryAirSys;
692 :
693 : // Initialize all of the simulation flags to true for the first iteration
694 297256 : state.dataHVACGlobal->SimZoneEquipmentFlag = true;
695 297256 : state.dataHVACGlobal->SimNonZoneEquipmentFlag = true;
696 297256 : state.dataHVACGlobal->SimAirLoopsFlag = true;
697 297256 : state.dataHVACGlobal->SimPlantLoopsFlag = true;
698 297256 : state.dataHVACGlobal->SimElecCircuitsFlag = true;
699 297256 : FirstHVACIteration = true;
700 :
701 297256 : if (state.dataAirLoop->AirLoopInputsFilled) {
702 242596 : for (auto &e : state.dataAirLoop->AirLoopControlInfo) {
703 : // Reset air loop control info for cooling coil active flag (used in TU's for reheat air flow control)
704 34234 : e.CoolingActiveFlag = false;
705 : // Reset air loop control info for heating coil active flag (used in OA controller for HX control)
706 34234 : e.HeatingActiveFlag = false;
707 : // reset outside air system HX to off first time through
708 34234 : e.HeatRecoveryBypass = true;
709 : // set HX check status flag to check for custom control in MixedAir.cc
710 34234 : e.CheckHeatRecoveryBypassStatus = true;
711 : // set OA comp simulated flag to false
712 34234 : e.OASysComponentsSimulated = false;
713 : // set economizer flow locked flag to false, will reset if custom HX control is used
714 34234 : e.EconomizerFlowLocked = false;
715 : // set air loop resim flags for when heat recovery is used and air loop needs another iteration
716 34234 : e.HeatRecoveryResimFlag = true;
717 34234 : e.HeatRecoveryResimFlag2 = false;
718 34234 : e.ResimAirLoopFlag = false;
719 : }
720 : }
721 :
722 : // This setups the reports for the Iteration variable that limits how many times
723 : // it goes through all of the HVAC managers before moving on.
724 : // The plant loop 'get inputs' and initialization are also done here in order to allow plant loop connected components
725 : // simulated by managers other than the plant manager to run correctly.
726 297256 : state.dataHVACMgr->HVACManageIteration = 0;
727 297256 : state.dataPlnt->PlantManageSubIterations = 0;
728 297256 : state.dataPlnt->PlantManageHalfLoopCalls = 0;
729 297256 : PlantUtilities::SetAllPlantSimFlagsToValue(state, true);
730 297256 : if (!state.dataHVACMgr->SimHVACIterSetup) {
731 306 : SetupOutputVariable(state,
732 : "HVAC System Solver Iteration Count",
733 : Constant::Units::None,
734 102 : state.dataHVACMgr->HVACManageIteration,
735 : OutputProcessor::TimeStepType::System,
736 : OutputProcessor::StoreType::Sum,
737 : "SimHVAC");
738 204 : SetupOutputVariable(state,
739 : "Air System Solver Iteration Count",
740 : Constant::Units::None,
741 102 : state.dataHVACMgr->RepIterAir,
742 : OutputProcessor::TimeStepType::System,
743 : OutputProcessor::StoreType::Sum,
744 : "SimHVAC");
745 408 : SetupOutputVariable(state,
746 : "Air System Relief Air Total Heat Loss Energy",
747 : Constant::Units::J,
748 102 : state.dataHeatBal->SysTotalHVACReliefHeatLoss,
749 : OutputProcessor::TimeStepType::System,
750 : OutputProcessor::StoreType::Sum,
751 : "SimHVAC");
752 408 : SetupOutputVariable(state,
753 : "HVAC System Total Heat Rejection Energy",
754 : Constant::Units::J,
755 102 : state.dataHeatBal->SysTotalHVACRejectHeatLoss,
756 : OutputProcessor::TimeStepType::System,
757 : OutputProcessor::StoreType::Sum,
758 : "SimHVAC");
759 102 : SetPointManager::ManageSetPoints(state); // need to call this before getting plant loop data so setpoint checks can complete okay
760 102 : PlantManager::GetPlantLoopData(state);
761 102 : PlantManager::GetPlantInput(state);
762 102 : PlantManager::SetupInitialPlantCallingOrder(state);
763 102 : PlantManager::SetupBranchControlTypes(state); // new routine to do away with input for branch control type
764 102 : PlantManager::SetupReports(state);
765 102 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
766 23 : PlantCondLoopOperation::SetupPlantEMSActuators(state);
767 : }
768 :
769 102 : if (state.dataPlnt->TotNumLoops > 0) {
770 72 : SetupOutputVariable(state,
771 : "Plant Solver Sub Iteration Count",
772 : Constant::Units::None,
773 24 : state.dataPlnt->PlantManageSubIterations,
774 : OutputProcessor::TimeStepType::System,
775 : OutputProcessor::StoreType::Sum,
776 : "SimHVAC");
777 48 : SetupOutputVariable(state,
778 : "Plant Solver Half Loop Calls Count",
779 : Constant::Units::None,
780 24 : state.dataPlnt->PlantManageHalfLoopCalls,
781 : OutputProcessor::TimeStepType::System,
782 : OutputProcessor::StoreType::Sum,
783 : "SimHVAC");
784 63 : for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
785 : // init plant sizing numbers in main plant data structure
786 39 : PlantManager::InitOneTimePlantSizingInfo(state, LoopNum);
787 : }
788 : }
789 102 : state.dataHVACMgr->SimHVACIterSetup = true;
790 : }
791 :
792 297256 : if (state.dataGlobal->ZoneSizingCalc) {
793 88803 : ZoneEquipmentManager::ManageZoneEquipment(
794 88803 : state, FirstHVACIteration, state.dataHVACGlobal->SimZoneEquipmentFlag, state.dataHVACGlobal->SimAirLoopsFlag);
795 : // need to call non zone equipment so water use zone gains can be included in sizing calcs
796 88803 : NonZoneEquipmentManager::ManageNonZoneEquipment(state, FirstHVACIteration, state.dataHVACGlobal->SimNonZoneEquipmentFlag);
797 88803 : state.dataElectPwrSvcMgr->facilityElectricServiceObj->manageElectricPowerService(
798 88803 : state, FirstHVACIteration, state.dataHVACGlobal->SimElecCircuitsFlag, false);
799 88803 : return;
800 : }
801 :
802 : // Before the HVAC simulation, reset control flags and specified flow
803 : // rates that might have been set by the set point and availability
804 : // managers.
805 :
806 208453 : ResetHVACControl(state);
807 :
808 : // Before the HVAC simulation, call ManageSetPoints to set all the HVAC node setpoints
809 208453 : bool anyEMSRan = false;
810 208453 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::BeforeHVACManagers, anyEMSRan, ObjexxFCL::Optional_int_const()); // calling point
811 :
812 208453 : SetPointManager::ManageSetPoints(state);
813 :
814 : // re-initialize plant loop and nodes.
815 208453 : PlantManager::ReInitPlantLoopsAtFirstHVACIteration(state);
816 :
817 : // Before the HVAC simulation, call ManageSystemAvailability to set the system on/off flags
818 208453 : Avail::ManageSystemAvailability(state);
819 :
820 208453 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::AfterHVACManagers, anyEMSRan, ObjexxFCL::Optional_int_const()); // calling point
821 208453 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::HVACIterationLoop, anyEMSRan, ObjexxFCL::Optional_int_const()); // calling point id
822 :
823 : // first explicitly call each system type with FirstHVACIteration,
824 :
825 : // Manages the various component simulations
826 208453 : SimSelectedEquipment(state,
827 208453 : state.dataHVACGlobal->SimAirLoopsFlag,
828 208453 : state.dataHVACGlobal->SimZoneEquipmentFlag,
829 208453 : state.dataHVACGlobal->SimNonZoneEquipmentFlag,
830 208453 : state.dataHVACGlobal->SimPlantLoopsFlag,
831 208453 : state.dataHVACGlobal->SimElecCircuitsFlag,
832 : FirstHVACIteration,
833 : SimWithPlantFlowUnlocked);
834 :
835 : // Eventually, when all of the flags are set to false, the
836 : // simulation has converged for this system time step.
837 :
838 208452 : state.dataHVACGlobal->SimPlantLoopsFlag = true;
839 208452 : PlantUtilities::SetAllPlantSimFlagsToValue(state, true); // set so loop to simulate at least once on non-first hvac
840 :
841 208452 : FirstHVACIteration = false;
842 :
843 : // then iterate among all systems after first HVAC iteration is over
844 :
845 : // Main iteration loop for HVAC. If any of the simulation flags are
846 : // true, then specific components must be resimulated.
847 841679 : while ((state.dataHVACGlobal->SimAirLoopsFlag || state.dataHVACGlobal->SimZoneEquipmentFlag || state.dataHVACGlobal->SimNonZoneEquipmentFlag ||
848 849552 : state.dataHVACGlobal->SimPlantLoopsFlag || state.dataHVACGlobal->SimElecCircuitsFlag) &&
849 216325 : (state.dataHVACMgr->HVACManageIteration <= state.dataConvergeParams->MaxIter)) {
850 :
851 216325 : if (state.dataGlobal->stopSimulation) break;
852 :
853 216324 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::HVACIterationLoop, anyEMSRan, ObjexxFCL::Optional_int_const()); // calling point id
854 :
855 : // Manages the various component simulations
856 216324 : SimSelectedEquipment(state,
857 216324 : state.dataHVACGlobal->SimAirLoopsFlag,
858 216324 : state.dataHVACGlobal->SimZoneEquipmentFlag,
859 216324 : state.dataHVACGlobal->SimNonZoneEquipmentFlag,
860 216324 : state.dataHVACGlobal->SimPlantLoopsFlag,
861 216324 : state.dataHVACGlobal->SimElecCircuitsFlag,
862 : FirstHVACIteration,
863 : SimWithPlantFlowUnlocked);
864 :
865 : // Eventually, when all of the flags are set to false, the
866 : // simulation has converged for this system time step.
867 :
868 216324 : UpdateZoneInletConvergenceLog(state);
869 :
870 216324 : ++state.dataHVACMgr->HVACManageIteration; // Increment the iteration counter
871 :
872 216324 : if (anyEMSRan && state.dataHVACMgr->HVACManageIteration <= 2) {
873 : // the calling point emsCallFromHVACIterationLoop is only effective for air loops if this while loop runs at least twice
874 7710 : state.dataHVACGlobal->SimAirLoopsFlag = true;
875 : }
876 216324 : if (state.dataHVACMgr->HVACManageIteration < state.dataHVACGlobal->MinAirLoopIterationsAfterFirst) {
877 : // sequenced zone loads for airloops may require extra iterations depending upon zone equipment order and load distribution type
878 0 : state.dataHVACGlobal->SimAirLoopsFlag = true;
879 0 : state.dataHVACGlobal->SimZoneEquipmentFlag = true;
880 : }
881 : }
882 208452 : if (state.dataGlobal->AnyPlantInModel) {
883 12433 : if (PlantUtilities::AnyPlantSplitterMixerLacksContinuity(state)) {
884 : // rerun systems in a "Final flow lock/last iteration" mode
885 : // now call for one second to last plant simulation
886 0 : state.dataHVACGlobal->SimAirLoopsFlag = false;
887 0 : state.dataHVACGlobal->SimZoneEquipmentFlag = false;
888 0 : state.dataHVACGlobal->SimNonZoneEquipmentFlag = false;
889 0 : state.dataHVACGlobal->SimPlantLoopsFlag = true;
890 0 : state.dataHVACGlobal->SimElecCircuitsFlag = false;
891 0 : SimSelectedEquipment(state,
892 0 : state.dataHVACGlobal->SimAirLoopsFlag,
893 0 : state.dataHVACGlobal->SimZoneEquipmentFlag,
894 0 : state.dataHVACGlobal->SimNonZoneEquipmentFlag,
895 0 : state.dataHVACGlobal->SimPlantLoopsFlag,
896 0 : state.dataHVACGlobal->SimElecCircuitsFlag,
897 : FirstHVACIteration,
898 : SimWithPlantFlowUnlocked);
899 : // now call for all non-plant simulation, but with plant flow lock on
900 0 : state.dataHVACGlobal->SimAirLoopsFlag = true;
901 0 : state.dataHVACGlobal->SimZoneEquipmentFlag = true;
902 0 : state.dataHVACGlobal->SimNonZoneEquipmentFlag = true;
903 0 : state.dataHVACGlobal->SimPlantLoopsFlag = false;
904 0 : state.dataHVACGlobal->SimElecCircuitsFlag = true;
905 0 : SimSelectedEquipment(state,
906 0 : state.dataHVACGlobal->SimAirLoopsFlag,
907 0 : state.dataHVACGlobal->SimZoneEquipmentFlag,
908 0 : state.dataHVACGlobal->SimNonZoneEquipmentFlag,
909 0 : state.dataHVACGlobal->SimPlantLoopsFlag,
910 0 : state.dataHVACGlobal->SimElecCircuitsFlag,
911 : FirstHVACIteration,
912 : SimWithPlantFlowLocked);
913 0 : UpdateZoneInletConvergenceLog(state);
914 : // now call for a last plant simulation
915 0 : state.dataHVACGlobal->SimAirLoopsFlag = false;
916 0 : state.dataHVACGlobal->SimZoneEquipmentFlag = false;
917 0 : state.dataHVACGlobal->SimNonZoneEquipmentFlag = false;
918 0 : state.dataHVACGlobal->SimPlantLoopsFlag = true;
919 0 : state.dataHVACGlobal->SimElecCircuitsFlag = false;
920 0 : SimSelectedEquipment(state,
921 0 : state.dataHVACGlobal->SimAirLoopsFlag,
922 0 : state.dataHVACGlobal->SimZoneEquipmentFlag,
923 0 : state.dataHVACGlobal->SimNonZoneEquipmentFlag,
924 0 : state.dataHVACGlobal->SimPlantLoopsFlag,
925 0 : state.dataHVACGlobal->SimElecCircuitsFlag,
926 : FirstHVACIteration,
927 : SimWithPlantFlowUnlocked);
928 : // now call for a last all non-plant simulation, but with plant flow lock on
929 0 : state.dataHVACGlobal->SimAirLoopsFlag = true;
930 0 : state.dataHVACGlobal->SimZoneEquipmentFlag = true;
931 0 : state.dataHVACGlobal->SimNonZoneEquipmentFlag = true;
932 0 : state.dataHVACGlobal->SimPlantLoopsFlag = false;
933 0 : state.dataHVACGlobal->SimElecCircuitsFlag = true;
934 0 : SimSelectedEquipment(state,
935 0 : state.dataHVACGlobal->SimAirLoopsFlag,
936 0 : state.dataHVACGlobal->SimZoneEquipmentFlag,
937 0 : state.dataHVACGlobal->SimNonZoneEquipmentFlag,
938 0 : state.dataHVACGlobal->SimPlantLoopsFlag,
939 0 : state.dataHVACGlobal->SimElecCircuitsFlag,
940 : FirstHVACIteration,
941 : SimWithPlantFlowLocked);
942 0 : UpdateZoneInletConvergenceLog(state);
943 : }
944 : }
945 :
946 : // Test plant loop for errors
947 229926 : for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
948 64422 : for (DataPlant::LoopSideLocation LoopSide : DataPlant::LoopSideKeys) {
949 42948 : PlantUtilities::CheckPlantMixerSplitterConsistency(state, LoopNum, LoopSide, FirstHVACIteration);
950 42948 : PlantUtilities::CheckForRunawayPlantTemps(state, LoopNum, LoopSide);
951 : }
952 : }
953 :
954 208452 : if ((state.dataHVACMgr->HVACManageIteration > state.dataConvergeParams->MaxIter) && (!state.dataGlobal->WarmupFlag)) {
955 0 : ++state.dataHVACMgr->ErrCount;
956 0 : if (state.dataHVACMgr->ErrCount < 15) {
957 0 : state.dataHVACMgr->ErrEnvironmentName = state.dataEnvrn->EnvironmentName;
958 0 : ShowWarningError(state,
959 0 : format("SimHVAC: Maximum iterations ({}) exceeded for all HVAC loops, at {}, {} {}",
960 0 : state.dataConvergeParams->MaxIter,
961 0 : state.dataEnvrn->EnvironmentName,
962 0 : state.dataEnvrn->CurMnDy,
963 0 : General::CreateSysTimeIntervalString(state)));
964 0 : if (state.dataHVACGlobal->SimAirLoopsFlag) {
965 0 : ShowContinueError(state, "The solution for one or more of the Air Loop HVAC systems did not appear to converge");
966 : }
967 0 : if (state.dataHVACGlobal->SimZoneEquipmentFlag) {
968 0 : ShowContinueError(state, "The solution for zone HVAC equipment did not appear to converge");
969 : }
970 0 : if (state.dataHVACGlobal->SimNonZoneEquipmentFlag) {
971 0 : ShowContinueError(state, "The solution for non-zone equipment did not appear to converge");
972 : }
973 0 : if (state.dataHVACGlobal->SimPlantLoopsFlag) {
974 0 : ShowContinueError(state, "The solution for one or more plant systems did not appear to converge");
975 : }
976 0 : if (state.dataHVACGlobal->SimElecCircuitsFlag) {
977 0 : ShowContinueError(state, "The solution for on-site electric generators did not appear to converge");
978 : }
979 0 : if (state.dataHVACMgr->ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
980 0 : ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on each max iteration exceeded.");
981 : }
982 0 : if (state.dataGlobal->DisplayExtraWarnings) {
983 :
984 0 : for (int AirSysNum = 1; AirSysNum <= NumPrimaryAirSys; ++AirSysNum) {
985 0 : auto &conv = state.dataConvergeParams->AirLoopConvergence(AirSysNum);
986 : // mass flow rate
987 0 : ConvergenceErrors(state,
988 0 : conv.HVACMassFlowNotConverged,
989 0 : conv.HVACFlowDemandToSupplyTolValue,
990 0 : conv.HVACFlowSupplyDeck1ToDemandTolValue,
991 0 : conv.HVACFlowSupplyDeck2ToDemandTolValue,
992 : AirSysNum,
993 : ConvErrorCallType::MassFlow);
994 : // humidity ratio
995 0 : ConvergenceErrors(state,
996 0 : conv.HVACHumRatNotConverged,
997 0 : conv.HVACHumDemandToSupplyTolValue,
998 0 : conv.HVACHumSupplyDeck1ToDemandTolValue,
999 0 : conv.HVACHumSupplyDeck2ToDemandTolValue,
1000 : AirSysNum,
1001 : ConvErrorCallType::HumidityRatio);
1002 : // temperature
1003 0 : ConvergenceErrors(state,
1004 0 : conv.HVACTempNotConverged,
1005 0 : conv.HVACTempDemandToSupplyTolValue,
1006 0 : conv.HVACTempSupplyDeck1ToDemandTolValue,
1007 0 : conv.HVACTempSupplyDeck2ToDemandTolValue,
1008 : AirSysNum,
1009 : ConvErrorCallType::Temperature);
1010 : // energy
1011 0 : ConvergenceErrors(state,
1012 0 : conv.HVACEnergyNotConverged,
1013 0 : conv.HVACEnergyDemandToSupplyTolValue,
1014 0 : conv.HVACEnergySupplyDeck1ToDemandTolValue,
1015 0 : conv.HVACEnergySupplyDeck2ToDemandTolValue,
1016 : AirSysNum,
1017 : ConvErrorCallType::Energy);
1018 : // CO2
1019 0 : ConvergenceErrors(state,
1020 0 : conv.HVACCO2NotConverged,
1021 0 : conv.HVACCO2DemandToSupplyTolValue,
1022 0 : conv.HVACCO2SupplyDeck1ToDemandTolValue,
1023 0 : conv.HVACCO2SupplyDeck2ToDemandTolValue,
1024 : AirSysNum,
1025 : ConvErrorCallType::CO2);
1026 : // generic contaminant
1027 0 : ConvergenceErrors(state,
1028 0 : conv.HVACGenContamNotConverged,
1029 0 : conv.HVACGenContamDemandToSupplyTolValue,
1030 0 : conv.HVACGenContamSupplyDeck1ToDemandTolValue,
1031 0 : conv.HVACGenContamSupplyDeck2ToDemandTolValue,
1032 : AirSysNum,
1033 : ConvErrorCallType::Generic);
1034 : } // loop over air loop systems
1035 :
1036 : // loop over zones and check for issues with zone inlet nodes
1037 0 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1038 :
1039 0 : for (int NodeIndex = 1; NodeIndex <= state.dataConvergeParams->ZoneInletConvergence(ZoneNum).NumInletNodes; ++NodeIndex) {
1040 :
1041 0 : auto &humRatInletNode = state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).HumidityRatio;
1042 0 : auto &mdotInletNode = state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).MassFlowRate;
1043 0 : auto &inletTemp = state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).Temperature;
1044 :
1045 : // Check humidity ratio
1046 0 : bool FoundOscillationByDuplicate = false;
1047 0 : bool MonotonicDecreaseFound = false;
1048 0 : bool MonotonicIncreaseFound = false;
1049 : // check for evidence of oscillation by identifying duplicates when latest value not equal to average
1050 0 : Real64 summation = 0.0;
1051 0 : summation = std::accumulate(humRatInletNode.begin(), humRatInletNode.end(), 0.0);
1052 0 : AvgValue = summation / double(DataConvergParams::ConvergLogStackDepth);
1053 0 : if (std::abs(humRatInletNode[0] - AvgValue) >
1054 : DataConvergParams::HVACHumRatOscillationToler) { // last iterate differs from average
1055 0 : FoundOscillationByDuplicate = false;
1056 0 : for (int StackDepth = 1; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1057 0 : if (std::abs(humRatInletNode[0] - humRatInletNode[StackDepth]) < DataConvergParams::HVACHumRatOscillationToler) {
1058 0 : FoundOscillationByDuplicate = true;
1059 0 : ShowContinueError(
1060 : state,
1061 0 : format("Node named {} shows oscillating humidity ratio across iterations with a repeated value of {:.6R}",
1062 0 : state.dataLoopNodes->NodeID(
1063 0 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum),
1064 0 : humRatInletNode[0]));
1065 0 : break;
1066 : }
1067 : }
1068 0 : if (!FoundOscillationByDuplicate) {
1069 :
1070 0 : Real64 humRatInletNodDotProd = std::inner_product(
1071 : std::begin(ConvergLogStackARR), std::end(ConvergLogStackARR), std::begin(humRatInletNode), 0.0);
1072 0 : Real64 summation2 = 0.0;
1073 0 : summation2 = std::accumulate(humRatInletNode.begin(), humRatInletNode.end(), 0.0);
1074 0 : SlopeHumRat =
1075 0 : (sum_ConvergLogStackARR * summation2 - double(DataConvergParams::ConvergLogStackDepth) * humRatInletNodDotProd) /
1076 : (square_sum_ConvergLogStackARR - double(DataConvergParams::ConvergLogStackDepth) * sum_square_ConvergLogStackARR);
1077 0 : if (std::abs(SlopeHumRat) > DataConvergParams::HVACHumRatSlopeToler) {
1078 :
1079 0 : if (SlopeHumRat < 0.0) { // check for monotonic decrease
1080 0 : MonotonicDecreaseFound = true;
1081 0 : for (int StackDepth = 1; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1082 0 : if (humRatInletNode[StackDepth - 1] > humRatInletNode[StackDepth]) {
1083 0 : MonotonicDecreaseFound = false;
1084 0 : break;
1085 : }
1086 : }
1087 0 : if (MonotonicDecreaseFound) {
1088 0 : ShowContinueError(
1089 : state,
1090 0 : format("Node named {} shows monotonically decreasing humidity ratio with a trend "
1091 : "rate across iterations of {:.6R} [ kg-water/kg-dryair/iteration]",
1092 0 : state.dataLoopNodes->NodeID(
1093 0 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum),
1094 : SlopeHumRat));
1095 : }
1096 : } else { // check for monotonic increase
1097 0 : MonotonicIncreaseFound = true;
1098 0 : for (int StackDepth = 1; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1099 0 : if (humRatInletNode[StackDepth - 1] < humRatInletNode[StackDepth]) {
1100 0 : MonotonicIncreaseFound = false;
1101 0 : break;
1102 : }
1103 : }
1104 0 : if (MonotonicIncreaseFound) {
1105 0 : ShowContinueError(
1106 : state,
1107 0 : format("Node named {} shows monotonically increasing humidity ratio with a trend "
1108 : "rate across iterations of {:.6R} [ kg-water/kg-dryair/iteration]",
1109 0 : state.dataLoopNodes->NodeID(
1110 0 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum),
1111 : SlopeHumRat));
1112 : }
1113 : }
1114 : } // significant slope in iterates
1115 : } // no osciallation
1116 : } // last value does not equal average of stack.
1117 :
1118 0 : if (MonotonicDecreaseFound || MonotonicIncreaseFound || FoundOscillationByDuplicate) {
1119 0 : std::string HistoryTrace;
1120 0 : for (int StackDepth = 0; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1121 0 : HistoryTrace += format("{:.6R},", humRatInletNode[StackDepth]);
1122 : }
1123 0 : ShowContinueError(
1124 : state,
1125 0 : format(
1126 : "Node named {} humidity ratio [kg-water/kg-dryair] iteration history trace (most recent first): {}",
1127 0 : state.dataLoopNodes->NodeID(state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum),
1128 : HistoryTrace));
1129 0 : } // need to report trace
1130 : // end humidity ratio
1131 :
1132 : // Check Mass flow rate
1133 0 : FoundOscillationByDuplicate = false;
1134 0 : MonotonicDecreaseFound = false;
1135 0 : MonotonicIncreaseFound = false;
1136 : // check for evidence of oscillation by identify duplicates when latest value not equal to average
1137 0 : Real64 summation2 = 0.0;
1138 0 : summation2 = std::accumulate(mdotInletNode.begin(), mdotInletNode.end(), 0.0);
1139 0 : AvgValue = summation2 / double(DataConvergParams::ConvergLogStackDepth);
1140 0 : if (std::abs(mdotInletNode[0] - AvgValue) >
1141 : DataConvergParams::HVACFlowRateOscillationToler) { // last iterate differs from average
1142 0 : FoundOscillationByDuplicate = false;
1143 0 : for (int StackDepth = 1; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1144 0 : if (std::abs(mdotInletNode[0] - mdotInletNode[StackDepth]) < DataConvergParams::HVACFlowRateOscillationToler) {
1145 0 : FoundOscillationByDuplicate = true;
1146 0 : ShowContinueError(
1147 : state,
1148 0 : format("Node named {} shows oscillating mass flow rate across iterations with a repeated value of {:.6R}",
1149 0 : state.dataLoopNodes->NodeID(
1150 0 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum),
1151 0 : mdotInletNode[0]));
1152 0 : break;
1153 : }
1154 : }
1155 0 : if (!FoundOscillationByDuplicate) {
1156 :
1157 : Real64 humRatInletNodDotProd =
1158 0 : std::inner_product(std::begin(ConvergLogStackARR), std::end(ConvergLogStackARR), std::begin(mdotInletNode), 0.0);
1159 0 : Real64 summation3 = 0.0;
1160 0 : summation3 = std::accumulate(mdotInletNode.begin(), mdotInletNode.end(), 0.0);
1161 0 : SlopeMdot =
1162 0 : (sum_ConvergLogStackARR * summation3 - double(DataConvergParams::ConvergLogStackDepth) * humRatInletNodDotProd) /
1163 : (square_sum_ConvergLogStackARR - double(DataConvergParams::ConvergLogStackDepth) * sum_square_ConvergLogStackARR);
1164 0 : if (std::abs(SlopeMdot) > DataConvergParams::HVACFlowRateSlopeToler) {
1165 0 : if (SlopeMdot < 0.0) { // check for monotonic decrease
1166 0 : MonotonicDecreaseFound = true;
1167 0 : for (int StackDepth = 1; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1168 0 : if (mdotInletNode[StackDepth - 1] > mdotInletNode[StackDepth]) {
1169 0 : MonotonicDecreaseFound = false;
1170 0 : break;
1171 : }
1172 : }
1173 0 : if (MonotonicDecreaseFound) {
1174 0 : ShowContinueError(
1175 : state,
1176 0 : format("Node named {} shows monotonically decreasing mass flow rate with a trend "
1177 : "rate across iterations of {:.6R} [kg/s/iteration]",
1178 0 : state.dataLoopNodes->NodeID(
1179 0 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum),
1180 : SlopeMdot));
1181 : }
1182 : } else { // check for monotonic increase
1183 0 : MonotonicIncreaseFound = true;
1184 0 : for (int StackDepth = 1; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1185 0 : if (mdotInletNode[StackDepth - 1] < mdotInletNode[StackDepth]) {
1186 0 : MonotonicIncreaseFound = false;
1187 0 : break;
1188 : }
1189 : }
1190 0 : if (MonotonicIncreaseFound) {
1191 0 : ShowContinueError(
1192 : state,
1193 0 : format("Node named {} shows monotonically increasing mass flow rate with a trend "
1194 : "rate across iterations of {:.6R} [kg/s/iteration]",
1195 0 : state.dataLoopNodes->NodeID(
1196 0 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum),
1197 : SlopeMdot));
1198 : }
1199 : }
1200 : } // significant slope in iterates
1201 : } // no oscillation
1202 : } // last value does not equal average of stack.
1203 :
1204 0 : if (MonotonicDecreaseFound || MonotonicIncreaseFound || FoundOscillationByDuplicate) {
1205 0 : std::string HistoryTrace;
1206 0 : for (int StackDepth = 0; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1207 0 : HistoryTrace += format("{:.6R},", mdotInletNode[StackDepth]);
1208 : }
1209 0 : ShowContinueError(state,
1210 0 : format("Node named {} mass flow rate [kg/s] iteration history trace (most recent first): {}",
1211 0 : state.dataLoopNodes->NodeID(
1212 0 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum),
1213 : HistoryTrace));
1214 0 : } // need to report trace
1215 : // end mass flow rate
1216 :
1217 : // Check Temperatures
1218 0 : FoundOscillationByDuplicate = false;
1219 0 : MonotonicDecreaseFound = false;
1220 0 : MonotonicIncreaseFound = false;
1221 : // check for evidence of oscillation by identify duplicates when latest value not equal to average
1222 0 : Real64 summation3 = 0.0;
1223 0 : summation3 = std::accumulate(inletTemp.begin(), inletTemp.end(), 0.0);
1224 0 : AvgValue = summation3 / double(DataConvergParams::ConvergLogStackDepth);
1225 0 : if (std::abs(inletTemp[0] - AvgValue) >
1226 : DataConvergParams::HVACTemperatureOscillationToler) { // last iterate differs from average
1227 0 : FoundOscillationByDuplicate = false;
1228 0 : for (int StackDepth = 1; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1229 0 : if (std::abs(inletTemp[0] - inletTemp[StackDepth]) < DataConvergParams::HVACTemperatureOscillationToler) {
1230 0 : FoundOscillationByDuplicate = true;
1231 0 : ShowContinueError(
1232 : state,
1233 0 : format("Node named {} shows oscillating temperatures across iterations with a repeated value of {:.6R}",
1234 0 : state.dataLoopNodes->NodeID(
1235 0 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum),
1236 0 : inletTemp[0]));
1237 0 : break;
1238 : }
1239 : }
1240 0 : if (!FoundOscillationByDuplicate) {
1241 :
1242 : Real64 inletTempDotProd =
1243 0 : std::inner_product(std::begin(ConvergLogStackARR), std::end(ConvergLogStackARR), std::begin(inletTemp), 0.0);
1244 :
1245 0 : Real64 summation4 = 0.0;
1246 0 : summation4 = std::accumulate(inletTemp.begin(), inletTemp.end(), 0.0);
1247 0 : SlopeTemps =
1248 0 : (sum_ConvergLogStackARR * summation4 - double(DataConvergParams::ConvergLogStackDepth) * inletTempDotProd) /
1249 : (square_sum_ConvergLogStackARR - double(DataConvergParams::ConvergLogStackDepth) * sum_square_ConvergLogStackARR);
1250 0 : if (std::abs(SlopeTemps) > DataConvergParams::HVACTemperatureSlopeToler) {
1251 0 : if (SlopeTemps < 0.0) { // check for monotonic decrease
1252 0 : MonotonicDecreaseFound = true;
1253 0 : for (int StackDepth = 1; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1254 0 : if (inletTemp[StackDepth - 1] > inletTemp[StackDepth]) {
1255 0 : MonotonicDecreaseFound = false;
1256 0 : break;
1257 : }
1258 : }
1259 0 : if (MonotonicDecreaseFound) {
1260 0 : ShowContinueError(
1261 : state,
1262 0 : format("Node named {} shows monotonically decreasing temperature with a trend rate "
1263 : "across iterations of {:.4R} [C/iteration]",
1264 0 : state.dataLoopNodes->NodeID(
1265 0 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum),
1266 : SlopeTemps));
1267 : }
1268 : } else { // check for monotonic increase
1269 0 : MonotonicIncreaseFound = true;
1270 0 : for (int StackDepth = 1; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1271 0 : if (inletTemp[StackDepth - 1] < inletTemp[StackDepth]) {
1272 0 : MonotonicIncreaseFound = false;
1273 0 : break;
1274 : }
1275 : }
1276 0 : if (MonotonicIncreaseFound) {
1277 0 : ShowContinueError(
1278 : state,
1279 0 : format("Node named {} shows monotonically increasing temperatures with a trend "
1280 : "rate across iterations of {:.4R} [C/iteration]",
1281 0 : state.dataLoopNodes->NodeID(
1282 0 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum),
1283 : SlopeTemps));
1284 : }
1285 : }
1286 : } // significant slope in iterates
1287 : } // no osciallation
1288 : } // last value does not equal average of stack.
1289 :
1290 0 : if (MonotonicDecreaseFound || MonotonicIncreaseFound || FoundOscillationByDuplicate) {
1291 0 : std::string HistoryTrace;
1292 0 : for (int StackDepth = 0; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1293 0 : HistoryTrace += format("{:.6R},", inletTemp[StackDepth]);
1294 : }
1295 0 : ShowContinueError(state,
1296 0 : format("Node named {} temperature [C] iteration history trace (most recent first): {}",
1297 0 : state.dataLoopNodes->NodeID(
1298 0 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum),
1299 : HistoryTrace));
1300 0 : } // need to report trace
1301 : // end Temperature checks
1302 :
1303 : } // loop over zone inlet nodes
1304 : } // loop over zones
1305 :
1306 0 : for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
1307 : bool FoundOscillationByDuplicate;
1308 : bool MonotonicIncreaseFound;
1309 : bool MonotonicDecreaseFound;
1310 :
1311 0 : if (state.dataConvergeParams->PlantConvergence(LoopNum).PlantMassFlowNotConverged) {
1312 0 : ShowContinueError(
1313 0 : state, format("Plant System Named = {} did not converge for mass flow rate", state.dataPlnt->PlantLoop(LoopNum).Name));
1314 0 : ShowContinueError(state, "Check values should be zero. Most Recent values listed first.");
1315 0 : std::string HistoryTrace;
1316 0 : for (int StackDepth = 0; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1317 : HistoryTrace +=
1318 0 : format("{:.6R},", state.dataConvergeParams->PlantConvergence(LoopNum).PlantFlowDemandToSupplyTolValue[StackDepth]);
1319 : }
1320 0 : ShowContinueError(state,
1321 0 : format("Demand-to-Supply interface mass flow rate check value iteration history trace: {}", HistoryTrace));
1322 0 : HistoryTrace = "";
1323 0 : for (int StackDepth = 0; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1324 : HistoryTrace +=
1325 0 : format("{:.6R},", state.dataConvergeParams->PlantConvergence(LoopNum).PlantFlowSupplyToDemandTolValue[StackDepth]);
1326 : }
1327 0 : ShowContinueError(state,
1328 0 : format("Supply-to-Demand interface mass flow rate check value iteration history trace: {}", HistoryTrace));
1329 :
1330 : // now work with history logs for mass flow to detect issues
1331 0 : for (DataPlant::LoopSideLocation ThisLoopSide : DataPlant::LoopSideKeys) {
1332 :
1333 0 : auto &mdotHistInletNode = state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).InletNode.MassFlowRateHistory;
1334 0 : auto &mdotHistOutletNode = state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).OutletNode.MassFlowRateHistory;
1335 :
1336 : // loop side inlet node
1337 0 : FoundOscillationByDuplicate = false;
1338 0 : MonotonicDecreaseFound = false;
1339 0 : MonotonicIncreaseFound = false;
1340 0 : AvgValue = sum(mdotHistInletNode) / double(DataPlant::NumConvergenceHistoryTerms);
1341 0 : if (std::abs(mdotHistInletNode(1) - AvgValue) > DataConvergParams::PlantFlowRateOscillationToler) {
1342 0 : FoundOscillationByDuplicate = false;
1343 0 : for (int StackDepth = 2; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1344 0 : if (std::abs(mdotHistInletNode(1) - mdotHistInletNode(StackDepth)) <
1345 : DataConvergParams::PlantFlowRateOscillationToler) {
1346 0 : FoundOscillationByDuplicate = true;
1347 0 : ShowContinueError(
1348 : state,
1349 0 : format("Node named {} shows oscillating flow rates across iterations with a repeated value of {:.7R}",
1350 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameIn,
1351 : mdotHistInletNode(1)));
1352 0 : break;
1353 : }
1354 : }
1355 : }
1356 0 : if (!FoundOscillationByDuplicate) {
1357 :
1358 0 : Real64 mdotHistInletNodeDotProd = std::inner_product(
1359 : std::begin(ConvergenceHistoryARR), std::end(ConvergenceHistoryARR), std::begin(mdotHistInletNode), 0.0);
1360 :
1361 0 : SlopeMdot = (sum_ConvergenceHistoryARR * sum(mdotHistInletNode) -
1362 0 : double(DataPlant::NumConvergenceHistoryTerms) * mdotHistInletNodeDotProd) /
1363 : (square_sum_ConvergenceHistoryARR -
1364 : double(DataPlant::NumConvergenceHistoryTerms) * sum_square_ConvergenceHistoryARR);
1365 0 : if (std::abs(SlopeMdot) > DataConvergParams::PlantFlowRateSlopeToler) {
1366 0 : if (SlopeMdot < 0.0) { // check for monotonic decrease
1367 0 : MonotonicDecreaseFound = true;
1368 0 : for (int StackDepth = 2; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1369 0 : if (mdotHistInletNode(StackDepth - 1) > mdotHistInletNode(StackDepth)) {
1370 0 : MonotonicDecreaseFound = false;
1371 0 : break;
1372 : }
1373 : }
1374 0 : if (MonotonicDecreaseFound) {
1375 0 : ShowContinueError(state,
1376 0 : format("Node named {} shows monotonically decreasing mass flow rate with a trend "
1377 : "rate across iterations of {:.7R} [kg/s/iteration]",
1378 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameIn,
1379 : SlopeMdot));
1380 : }
1381 : } else { // check for monotonic increase
1382 0 : MonotonicIncreaseFound = true;
1383 0 : for (int StackDepth = 2; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1384 0 : if (mdotHistInletNode(StackDepth - 1) < mdotHistInletNode(StackDepth)) {
1385 0 : MonotonicIncreaseFound = false;
1386 0 : break;
1387 : }
1388 : }
1389 0 : if (MonotonicIncreaseFound) {
1390 0 : ShowContinueError(state,
1391 0 : format("Node named {} shows monotonically increasing mass flow rate with a trend "
1392 : "rate across iterations of {:.7R} [kg/s/iteration]",
1393 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameIn,
1394 : SlopeMdot));
1395 : }
1396 : }
1397 : } // significant slope found
1398 : } // no oscillation found
1399 :
1400 0 : if (MonotonicDecreaseFound || MonotonicIncreaseFound || FoundOscillationByDuplicate) {
1401 0 : HistoryTrace = "";
1402 0 : for (int StackDepth = 1; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1403 0 : HistoryTrace += format("{:.7R},", mdotHistInletNode(StackDepth));
1404 : }
1405 0 : ShowContinueError(state,
1406 0 : format("Node named {} mass flow rate [kg/s] iteration history trace (most recent first): {}",
1407 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameIn,
1408 : HistoryTrace));
1409 : } // need to report trace
1410 : // end of inlet node
1411 :
1412 : // loop side outlet node
1413 0 : FoundOscillationByDuplicate = false;
1414 0 : MonotonicDecreaseFound = false;
1415 0 : MonotonicIncreaseFound = false;
1416 0 : AvgValue = sum(mdotHistOutletNode) / double(DataPlant::NumConvergenceHistoryTerms);
1417 0 : if (std::abs(mdotHistOutletNode(1) - AvgValue) > DataConvergParams::PlantFlowRateOscillationToler) {
1418 0 : FoundOscillationByDuplicate = false;
1419 0 : for (int StackDepth = 2; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1420 0 : if (std::abs(mdotHistOutletNode(1) - mdotHistOutletNode(StackDepth)) <
1421 : DataConvergParams::PlantFlowRateOscillationToler) {
1422 0 : FoundOscillationByDuplicate = true;
1423 0 : ShowContinueError(
1424 : state,
1425 0 : format("Node named {} shows oscillating flow rates across iterations with a repeated value of {:.7R}",
1426 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameOut,
1427 : mdotHistOutletNode(1)));
1428 0 : break;
1429 : }
1430 : }
1431 : }
1432 0 : if (!FoundOscillationByDuplicate) {
1433 :
1434 0 : Real64 mdotHistOutletNodeDotProd = std::inner_product(
1435 : std::begin(ConvergenceHistoryARR), std::end(ConvergenceHistoryARR), std::begin(mdotHistOutletNode), 0.0);
1436 :
1437 0 : SlopeMdot = (sum_ConvergenceHistoryARR * sum(mdotHistOutletNode) -
1438 0 : double(DataPlant::NumConvergenceHistoryTerms) * mdotHistOutletNodeDotProd) /
1439 : (square_sum_ConvergenceHistoryARR -
1440 : double(DataPlant::NumConvergenceHistoryTerms) * sum_square_ConvergenceHistoryARR);
1441 0 : if (std::abs(SlopeMdot) > DataConvergParams::PlantFlowRateSlopeToler) {
1442 0 : if (SlopeMdot < 0.0) { // check for monotonic decrease
1443 0 : MonotonicDecreaseFound = true;
1444 0 : for (int StackDepth = 2; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1445 0 : if (mdotHistOutletNode(StackDepth - 1) > mdotHistOutletNode(StackDepth)) {
1446 0 : MonotonicDecreaseFound = false;
1447 0 : break;
1448 : }
1449 : }
1450 0 : if (MonotonicDecreaseFound) {
1451 0 : ShowContinueError(state,
1452 0 : format("Node named {} shows monotonically decreasing mass flow rate with a trend "
1453 : "rate across iterations of {:.7R} [kg/s/iteration]",
1454 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameOut,
1455 : SlopeMdot));
1456 : }
1457 : } else { // check for monotonic increase
1458 0 : MonotonicIncreaseFound = true;
1459 0 : for (int StackDepth = 2; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1460 0 : if (mdotHistOutletNode(StackDepth - 1) < mdotHistOutletNode(StackDepth)) {
1461 0 : MonotonicIncreaseFound = false;
1462 0 : break;
1463 : }
1464 : }
1465 0 : if (MonotonicIncreaseFound) {
1466 0 : ShowContinueError(state,
1467 0 : format("Node named {} shows monotonically increasing mass flow rate with a trend "
1468 : "rate across iterations of {:.7R} [kg/s/iteration]",
1469 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameOut,
1470 : SlopeMdot));
1471 : }
1472 : }
1473 : } // significant slope found
1474 : } // no oscillation found
1475 :
1476 0 : if (MonotonicDecreaseFound || MonotonicIncreaseFound || FoundOscillationByDuplicate) {
1477 0 : HistoryTrace = "";
1478 0 : for (int StackDepth = 1; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1479 0 : HistoryTrace += format("{:.7R},", mdotHistOutletNode(StackDepth));
1480 : }
1481 0 : ShowContinueError(state,
1482 0 : format("Node named {} mass flow rate [kg/s] iteration history trace (most recent first): {}",
1483 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameOut,
1484 : HistoryTrace));
1485 : } // need to report trace
1486 : // end of Outlet node
1487 :
1488 : } // plant loop sides
1489 :
1490 0 : } // mass flow not converged
1491 :
1492 0 : if (state.dataConvergeParams->PlantConvergence(LoopNum).PlantTempNotConverged) {
1493 0 : ShowContinueError(
1494 0 : state, format("Plant System Named = {} did not converge for temperature", state.dataPlnt->PlantLoop(LoopNum).Name));
1495 0 : ShowContinueError(state, "Check values should be zero. Most Recent values listed first.");
1496 0 : std::string HistoryTrace;
1497 0 : for (int StackDepth = 0; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1498 : HistoryTrace +=
1499 0 : format("{:.6R},", state.dataConvergeParams->PlantConvergence(LoopNum).PlantTempDemandToSupplyTolValue[StackDepth]);
1500 : }
1501 0 : ShowContinueError(state,
1502 0 : format("Demand-to-Supply interface temperature check value iteration history trace: {}", HistoryTrace));
1503 0 : HistoryTrace = "";
1504 0 : for (int StackDepth = 0; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
1505 : HistoryTrace +=
1506 0 : format("{:.6R},", state.dataConvergeParams->PlantConvergence(LoopNum).PlantTempSupplyToDemandTolValue[StackDepth]);
1507 : }
1508 0 : ShowContinueError(state,
1509 0 : format("Supply-to-Demand interface temperature check value iteration history trace: {}", HistoryTrace));
1510 :
1511 : // now work with history logs for mass flow to detect issues
1512 0 : for (DataPlant::LoopSideLocation ThisLoopSide : DataPlant::LoopSideKeys) {
1513 :
1514 0 : auto &tempHistInletNode = state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).InletNode.TemperatureHistory;
1515 0 : auto &tempHistOutletNode = state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).OutletNode.TemperatureHistory;
1516 :
1517 : // loop side inlet node
1518 0 : FoundOscillationByDuplicate = false;
1519 0 : MonotonicDecreaseFound = false;
1520 0 : MonotonicIncreaseFound = false;
1521 0 : AvgValue = sum(tempHistInletNode) / double(DataPlant::NumConvergenceHistoryTerms);
1522 0 : if (std::abs(tempHistInletNode(1) - AvgValue) > DataConvergParams::PlantTemperatureOscillationToler) {
1523 0 : FoundOscillationByDuplicate = false;
1524 0 : for (int StackDepth = 2; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1525 0 : if (std::abs(tempHistInletNode(1) - tempHistInletNode(StackDepth)) <
1526 : DataConvergParams::PlantTemperatureOscillationToler) {
1527 0 : FoundOscillationByDuplicate = true;
1528 0 : ShowContinueError(
1529 : state,
1530 0 : format("Node named {} shows oscillating temperatures across iterations with a repeated value of {:.5R}",
1531 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameIn,
1532 : tempHistInletNode(1)));
1533 0 : break;
1534 : }
1535 : }
1536 : }
1537 0 : if (!FoundOscillationByDuplicate) {
1538 :
1539 0 : Real64 tempHistInletNodeDotProd = std::inner_product(
1540 : std::begin(ConvergenceHistoryARR), std::end(ConvergenceHistoryARR), std::begin(tempHistInletNode), 0.0);
1541 :
1542 0 : SlopeTemps = (sum_ConvergenceHistoryARR * sum(tempHistInletNode) -
1543 0 : double(DataPlant::NumConvergenceHistoryTerms) * tempHistInletNodeDotProd) /
1544 : (square_sum_ConvergenceHistoryARR -
1545 : double(DataPlant::NumConvergenceHistoryTerms) * sum_square_ConvergenceHistoryARR);
1546 0 : if (std::abs(SlopeTemps) > DataConvergParams::PlantTemperatureSlopeToler) {
1547 0 : if (SlopeTemps < 0.0) { // check for monotonic decrease
1548 0 : MonotonicDecreaseFound = true;
1549 0 : for (int StackDepth = 2; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1550 0 : if (tempHistInletNode(StackDepth - 1) > tempHistInletNode(StackDepth)) {
1551 0 : MonotonicDecreaseFound = false;
1552 0 : break;
1553 : }
1554 : }
1555 0 : if (MonotonicDecreaseFound) {
1556 0 : ShowContinueError(state,
1557 0 : format("Node named {} shows monotonically decreasing temperatures with a trend "
1558 : "rate across iterations of {:.5R} [C/iteration]",
1559 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameIn,
1560 : SlopeTemps));
1561 : }
1562 : } else { // check for monotonic increase
1563 0 : MonotonicIncreaseFound = true;
1564 0 : for (int StackDepth = 2; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1565 0 : if (tempHistInletNode(StackDepth - 1) < tempHistInletNode(StackDepth)) {
1566 0 : MonotonicIncreaseFound = false;
1567 0 : break;
1568 : }
1569 : }
1570 0 : if (MonotonicIncreaseFound) {
1571 0 : ShowContinueError(state,
1572 0 : format("Node named {} shows monotonically increasing temperatures with a trend "
1573 : "rate across iterations of {:.5R} [C/iteration]",
1574 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameIn,
1575 : SlopeTemps));
1576 : }
1577 : }
1578 : } // significant slope found
1579 : } // no oscillation found
1580 :
1581 0 : if (MonotonicDecreaseFound || MonotonicIncreaseFound || FoundOscillationByDuplicate) {
1582 0 : HistoryTrace = "";
1583 0 : for (int StackDepth = 1; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1584 0 : HistoryTrace += format("{:.5R},", tempHistInletNode(StackDepth));
1585 : }
1586 0 : ShowContinueError(state,
1587 0 : format("Node named {} temperature [C] iteration history trace (most recent first): {}",
1588 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameIn,
1589 : HistoryTrace));
1590 : } // need to report trace
1591 : // end of inlet node
1592 :
1593 : // loop side outlet node
1594 0 : FoundOscillationByDuplicate = false;
1595 0 : MonotonicDecreaseFound = false;
1596 0 : MonotonicIncreaseFound = false;
1597 0 : AvgValue = sum(tempHistOutletNode) / double(DataPlant::NumConvergenceHistoryTerms);
1598 0 : if (std::abs(tempHistOutletNode(1) - AvgValue) > DataConvergParams::PlantTemperatureOscillationToler) {
1599 0 : FoundOscillationByDuplicate = false;
1600 0 : for (int StackDepth = 2; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1601 0 : if (std::abs(tempHistOutletNode(1) - tempHistOutletNode(StackDepth)) <
1602 : DataConvergParams::PlantTemperatureOscillationToler) {
1603 0 : FoundOscillationByDuplicate = true;
1604 0 : ShowContinueError(
1605 : state,
1606 0 : format("Node named {} shows oscillating temperatures across iterations with a repeated value of {:.5R}",
1607 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameOut,
1608 : tempHistOutletNode(1)));
1609 0 : break;
1610 : }
1611 : }
1612 : }
1613 0 : if (!FoundOscillationByDuplicate) {
1614 :
1615 0 : Real64 tempHistOutletNodeDotProd = std::inner_product(
1616 : std::begin(ConvergenceHistoryARR), std::end(ConvergenceHistoryARR), std::begin(tempHistOutletNode), 0.0);
1617 :
1618 0 : SlopeTemps = (sum_ConvergenceHistoryARR * sum(tempHistOutletNode) -
1619 0 : double(DataPlant::NumConvergenceHistoryTerms) * tempHistOutletNodeDotProd) /
1620 : (square_sum_ConvergenceHistoryARR -
1621 : double(DataPlant::NumConvergenceHistoryTerms) * sum_square_ConvergenceHistoryARR);
1622 0 : if (std::abs(SlopeTemps) > DataConvergParams::PlantFlowRateSlopeToler) {
1623 0 : if (SlopeTemps < 0.0) { // check for monotonic decrease
1624 0 : MonotonicDecreaseFound = true;
1625 0 : for (int StackDepth = 2; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1626 0 : if (state.dataPlnt->PlantLoop(LoopNum)
1627 0 : .LoopSide(ThisLoopSide)
1628 0 : .OutletNode.TemperatureHistory(StackDepth - 1) > tempHistOutletNode(StackDepth)) {
1629 0 : MonotonicDecreaseFound = false;
1630 0 : break;
1631 : }
1632 : }
1633 0 : if (MonotonicDecreaseFound) {
1634 0 : ShowContinueError(state,
1635 0 : format("Node named {} shows monotonically decreasing temperatures with a trend "
1636 : "rate across iterations of {:.5R} [C/iteration]",
1637 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameOut,
1638 : SlopeTemps));
1639 : }
1640 : } else { // check for monotonic increase
1641 0 : MonotonicIncreaseFound = true;
1642 0 : for (int StackDepth = 2; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1643 0 : if (state.dataPlnt->PlantLoop(LoopNum)
1644 0 : .LoopSide(ThisLoopSide)
1645 0 : .OutletNode.TemperatureHistory(StackDepth - 1) < tempHistOutletNode(StackDepth)) {
1646 0 : MonotonicIncreaseFound = false;
1647 0 : break;
1648 : }
1649 : }
1650 0 : if (MonotonicIncreaseFound) {
1651 0 : ShowContinueError(state,
1652 0 : format("Node named {} shows monotonically increasing temperatures with a trend "
1653 : "rate across iterations of {:.5R} [C/iteration]",
1654 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameOut,
1655 : SlopeTemps));
1656 : }
1657 : }
1658 : } // significant slope found
1659 : } // no oscillation found
1660 :
1661 0 : if (MonotonicDecreaseFound || MonotonicIncreaseFound || FoundOscillationByDuplicate) {
1662 0 : HistoryTrace = "";
1663 0 : for (int StackDepth = 1; StackDepth <= DataPlant::NumConvergenceHistoryTerms; ++StackDepth) {
1664 0 : HistoryTrace += format("{:.5R},", tempHistOutletNode(StackDepth));
1665 : }
1666 0 : ShowContinueError(state,
1667 0 : format("Node named {} temperature [C] iteration history trace (most recent first): {}",
1668 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(ThisLoopSide).NodeNameOut,
1669 : HistoryTrace));
1670 : } // need to report trace
1671 : // end of Outlet node
1672 :
1673 : } // plant loop sides
1674 :
1675 0 : } // temperature not converged
1676 : } // loop over plant loop systems
1677 : }
1678 : } else {
1679 0 : if (state.dataEnvrn->EnvironmentName == state.dataHVACMgr->ErrEnvironmentName) {
1680 0 : ShowRecurringWarningErrorAtEnd(
1681 : state,
1682 0 : format("SimHVAC: Exceeding Maximum iterations for all HVAC loops, during {} continues", state.dataEnvrn->EnvironmentName),
1683 0 : state.dataHVACMgr->MaxErrCount);
1684 : } else {
1685 0 : state.dataHVACMgr->MaxErrCount = 0;
1686 0 : state.dataHVACMgr->ErrEnvironmentName = state.dataEnvrn->EnvironmentName;
1687 0 : ShowRecurringWarningErrorAtEnd(
1688 : state,
1689 0 : format("SimHVAC: Exceeding Maximum iterations for all HVAC loops, during {} continues", state.dataEnvrn->EnvironmentName),
1690 0 : state.dataHVACMgr->MaxErrCount);
1691 : }
1692 : }
1693 : }
1694 :
1695 208452 : CheckAirLoopFlowBalance(state);
1696 :
1697 : // Set node setpoints to a flag value so that controllers can check whether their sensed nodes
1698 : // have a setpoint
1699 208452 : if (!state.dataGlobal->ZoneSizingCalc && !state.dataGlobal->SysSizingCalc) {
1700 208452 : if (state.dataHVACMgr->MySetPointInit) {
1701 90 : if (state.dataLoopNodes->NumOfNodes > 0) {
1702 1216 : for (auto &e : state.dataLoopNodes->Node) {
1703 1165 : e.TempSetPoint = DataLoopNode::SensedNodeFlagValue;
1704 1165 : e.HumRatSetPoint = DataLoopNode::SensedNodeFlagValue;
1705 1165 : e.HumRatMin = DataLoopNode::SensedNodeFlagValue;
1706 1165 : e.HumRatMax = DataLoopNode::SensedNodeFlagValue;
1707 1165 : e.MassFlowRateSetPoint = DataLoopNode::SensedNodeFlagValue; // BG 5-26-2009 (being checked in HVACControllers.cc)
1708 : }
1709 51 : state.dataLoopNodes->DefaultNodeValues.TempSetPoint = DataLoopNode::SensedNodeFlagValue;
1710 51 : state.dataLoopNodes->DefaultNodeValues.HumRatSetPoint = DataLoopNode::SensedNodeFlagValue;
1711 51 : state.dataLoopNodes->DefaultNodeValues.HumRatMin = DataLoopNode::SensedNodeFlagValue;
1712 51 : state.dataLoopNodes->DefaultNodeValues.HumRatMax = DataLoopNode::SensedNodeFlagValue;
1713 51 : state.dataLoopNodes->DefaultNodeValues.MassFlowRateSetPoint =
1714 : DataLoopNode::SensedNodeFlagValue; // BG 5-26-2009 (being checked in HVACControllers.cc)
1715 : }
1716 90 : state.dataHVACMgr->MySetPointInit = false;
1717 90 : state.dataHVACGlobal->DoSetPointTest = true;
1718 : } else {
1719 208362 : state.dataHVACGlobal->DoSetPointTest = false;
1720 : }
1721 :
1722 208452 : if (state.dataCoilCoolingDX->stillNeedToReportStandardRatings) {
1723 124191 : if (!state.dataGlobal->WarmupFlag) {
1724 68 : CoilCoolingDX::reportAllStandardRatings(state);
1725 : }
1726 : }
1727 : }
1728 208452 : if (state.dataHVACGlobal->SetPointErrorFlag) {
1729 0 : ShowFatalError(state, "Previous severe set point errors cause program termination");
1730 : }
1731 : }
1732 :
1733 424777 : void SimSelectedEquipment(EnergyPlusData &state,
1734 : bool &SimAirLoops, // True when the air loops need to be (re)simulated
1735 : bool &SimZoneEquipment, // True when zone equipment components need to be (re)simulated
1736 : bool &SimNonZoneEquipment, // True when non-zone equipment components need to be (re)simulated
1737 : bool &SimPlantLoops, // True when the main plant loops need to be (re)simulated
1738 : bool &SimElecCircuits, // True when electric circuits need to be (re)simulated
1739 : bool &FirstHVACIteration, // True when solution technique on first iteration
1740 : bool const LockPlantFlows)
1741 : {
1742 :
1743 : // SUBROUTINE INFORMATION:
1744 : // AUTHOR Russ Taylor, Rick Strand
1745 : // DATE WRITTEN May 1998
1746 :
1747 : // PURPOSE OF THIS SUBROUTINE:
1748 : // This subroutine receives the flags from SimHVAC which determines
1749 : // which middle-level managers must be called.
1750 :
1751 : // METHODOLOGY EMPLOYED:
1752 : // Each flag is checked and the appropriate manager is then called.
1753 :
1754 : // SUBROUTINE PARAMETER DEFINITIONS:
1755 424777 : int constexpr MaxAir(5); // Iteration Max for Air Simulation Iterations
1756 :
1757 : // Set all plant flow locks to UNLOCKED to allow air side components to operate properly
1758 : // This requires that the plant flow resolver carefully set the min/max avail limits on
1759 : // air side components to ensure they request within bounds.
1760 424777 : if (LockPlantFlows) {
1761 0 : PlantUtilities::SetAllFlowLocks(state, DataPlant::FlowLock::Locked);
1762 : } else {
1763 424777 : PlantUtilities::SetAllFlowLocks(state, DataPlant::FlowLock::Unlocked);
1764 : }
1765 424777 : PlantUtilities::ResetAllPlantInterConnectFlags(state);
1766 :
1767 424777 : if (state.dataGlobal->BeginEnvrnFlag && state.dataHVACMgr->MyEnvrnFlag2) {
1768 : // Following comment is incorrect! (LKL) Even the first time through this does more than read in data.
1769 : // Zone equipment data needs to be read in before air loop data to allow the
1770 : // determination of which zones are connected to which air loops.
1771 : // This call of ManageZoneEquipment does nothing except force the
1772 : // zone equipment data to be read in.
1773 286 : ZoneEquipmentManager::ManageZoneEquipment(state, FirstHVACIteration, SimZoneEquipment, SimAirLoops);
1774 285 : state.dataHVACMgr->MyEnvrnFlag2 = false;
1775 : }
1776 424776 : if (!state.dataGlobal->BeginEnvrnFlag) {
1777 423502 : state.dataHVACMgr->MyEnvrnFlag2 = true;
1778 : }
1779 :
1780 424776 : if (FirstHVACIteration) {
1781 208452 : state.dataHVACMgr->RepIterAir = 0;
1782 : // Call AirflowNetwork simulation to calculate air flows and pressures
1783 208452 : if (state.afn->simulation_control.type != AirflowNetwork::ControlType::NoMultizoneOrDistribution) {
1784 2820 : state.afn->manage_balance(FirstHVACIteration);
1785 : }
1786 208452 : SimAirServingZones::ManageAirLoops(state, FirstHVACIteration, SimAirLoops, SimZoneEquipment);
1787 208452 : state.dataAirLoop->AirLoopInputsFilled = true; // all air loop inputs have been read in
1788 208452 : SimAirLoops = true; // Need to make sure that SimAirLoop is simulated at min twice to calculate PLR in some air loop equipment
1789 208452 : state.dataHVACGlobal->AirLoopsSimOnce = true; // air loops simulated once for this environment
1790 208452 : ResetTerminalUnitFlowLimits(state);
1791 208452 : state.dataHVACMgr->FlowMaxAvailAlreadyReset = true;
1792 208452 : ZoneEquipmentManager::ManageZoneEquipment(state, FirstHVACIteration, SimZoneEquipment, SimAirLoops);
1793 208452 : SimZoneEquipment = true; // needs to be simulated at least twice for flow resolution to propagate to this routine
1794 208452 : NonZoneEquipmentManager::ManageNonZoneEquipment(state, FirstHVACIteration, SimNonZoneEquipment);
1795 208452 : state.dataElectPwrSvcMgr->facilityElectricServiceObj->manageElectricPowerService(
1796 208452 : state, FirstHVACIteration, state.dataHVACGlobal->SimElecCircuitsFlag, false);
1797 :
1798 208452 : PlantManager::ManagePlantLoops(state, FirstHVACIteration, SimAirLoops, SimZoneEquipment, SimNonZoneEquipment, SimPlantLoops, SimElecCircuits);
1799 :
1800 208452 : state.dataErrTracking->AskForPlantCheckOnAbort = true; // need to make a first pass through plant calcs before this check make sense
1801 208452 : state.dataElectPwrSvcMgr->facilityElectricServiceObj->manageElectricPowerService(
1802 208452 : state, FirstHVACIteration, state.dataHVACGlobal->SimElecCircuitsFlag, false);
1803 : } else {
1804 216324 : state.dataHVACMgr->FlowResolutionNeeded = false;
1805 216324 : int IterAir = 0;
1806 440873 : while ((SimAirLoops || SimZoneEquipment) && (IterAir <= MaxAir)) {
1807 224549 : ++IterAir; // Increment the iteration counter
1808 : // Call AirflowNetwork simulation to calculate air flows and pressures
1809 224549 : bool ResimulateAirZone = false;
1810 224549 : if (state.afn->simulation_control.type != AirflowNetwork::ControlType::NoMultizoneOrDistribution) {
1811 8348 : state.afn->manage_balance(FirstHVACIteration, IterAir, ResimulateAirZone);
1812 : }
1813 224549 : if (SimAirLoops) {
1814 224549 : SimAirServingZones::ManageAirLoops(state, FirstHVACIteration, SimAirLoops, SimZoneEquipment);
1815 224549 : SimElecCircuits = true; // If this was simulated there are possible electric changes that need to be simulated
1816 : }
1817 :
1818 : // make sure flow resolution gets done
1819 224549 : if (state.dataHVACMgr->FlowResolutionNeeded) {
1820 155 : SimZoneEquipment = true;
1821 : }
1822 224549 : if (SimZoneEquipment) {
1823 215647 : if ((IterAir == 1) && (!state.dataHVACMgr->FlowMaxAvailAlreadyReset)) { // don't do reset if already done in FirstHVACIteration
1824 : // ResetTerminalUnitFlowLimits(); // don't do reset at all - interferes with convergence and terminal unit flow controls
1825 162 : state.dataHVACMgr->FlowResolutionNeeded = true;
1826 : } else {
1827 215485 : ResolveAirLoopFlowLimits(state);
1828 215485 : state.dataHVACMgr->FlowResolutionNeeded = false;
1829 : }
1830 215647 : ZoneEquipmentManager::ManageZoneEquipment(state, FirstHVACIteration, SimZoneEquipment, SimAirLoops);
1831 215647 : SimElecCircuits = true; // If this was simulated there are possible electric changes that need to be simulated
1832 : }
1833 224549 : state.dataHVACMgr->FlowMaxAvailAlreadyReset = false;
1834 :
1835 : // IterAir = IterAir + 1 ! Increment the iteration counter
1836 224549 : if (state.afn->simulation_control.type != AirflowNetwork::ControlType::NoMultizoneOrDistribution) {
1837 8348 : if (ResimulateAirZone) { // Need to make sure that SimAirLoop and SimZoneEquipment are simulated
1838 5528 : SimAirLoops = true; // at min three times using ONOFF fan with the AirflowNetwork model
1839 5528 : SimZoneEquipment = true;
1840 : }
1841 : }
1842 : }
1843 :
1844 216324 : state.dataHVACMgr->RepIterAir += IterAir;
1845 : // Check to see if any components have been locked out. If so, SimAirLoops will be reset to TRUE.
1846 216324 : ResolveLockoutFlags(state, SimAirLoops);
1847 :
1848 216324 : if (SimNonZoneEquipment) {
1849 208451 : NonZoneEquipmentManager::ManageNonZoneEquipment(state, FirstHVACIteration, SimNonZoneEquipment);
1850 208451 : SimElecCircuits = true; // If this was simulated there are possible electric changes that need to be simulated
1851 : }
1852 :
1853 216324 : if (SimElecCircuits) {
1854 216324 : state.dataElectPwrSvcMgr->facilityElectricServiceObj->manageElectricPowerService(
1855 216324 : state, FirstHVACIteration, state.dataHVACGlobal->SimElecCircuitsFlag, false);
1856 : }
1857 :
1858 216324 : if (!SimPlantLoops) {
1859 : // check to see if any air side component may have requested plant resim
1860 7873 : if (PlantUtilities::AnyPlantLoopSidesNeedSim(state)) {
1861 0 : SimPlantLoops = true;
1862 : }
1863 : }
1864 :
1865 216324 : if (SimPlantLoops) {
1866 208451 : PlantManager::ManagePlantLoops(
1867 208451 : state, FirstHVACIteration, SimAirLoops, SimZoneEquipment, SimNonZoneEquipment, SimPlantLoops, SimElecCircuits);
1868 : }
1869 :
1870 216324 : if (SimElecCircuits) {
1871 0 : state.dataElectPwrSvcMgr->facilityElectricServiceObj->manageElectricPowerService(
1872 0 : state, FirstHVACIteration, state.dataHVACGlobal->SimElecCircuitsFlag, false);
1873 : }
1874 : }
1875 424776 : }
1876 :
1877 208452 : void ResetTerminalUnitFlowLimits(EnergyPlusData &state)
1878 : {
1879 :
1880 : // SUBROUTINE INFORMATION:
1881 : // AUTHOR Fred Buhl
1882 : // DATE WRITTEN Feb 2010
1883 :
1884 : // PURPOSE OF THIS SUBROUTINE:
1885 : // Reset the max flow available limits at the inlet nodes of terminal units
1886 :
1887 : // METHODOLOGY EMPLOYED:
1888 : // Loops through all air loops, finds the inlet nodes of the terminal units
1889 : // served by each air loop, and resets the node MassFlowRateMaxAvail (and MinAvail) to
1890 : // the hard max and mins.
1891 :
1892 242710 : for (int AirLoopIndex = 1; AirLoopIndex <= state.dataHVACGlobal->NumPrimaryAirSys; ++AirLoopIndex) { // loop over the primary air loops
1893 90102 : for (int ZonesCooledIndex = 1; ZonesCooledIndex <= state.dataAirLoop->AirToZoneNodeInfo(AirLoopIndex).NumZonesCooled;
1894 : ++ZonesCooledIndex) { // loop over the zones cooled by this air loop
1895 55844 : int TermInletNode = state.dataAirLoop->AirToZoneNodeInfo(AirLoopIndex).TermUnitCoolInletNodes(ZonesCooledIndex);
1896 : // reset the max avail flow rate at the terminal unit cold air inlet to the max
1897 55844 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMaxAvail = state.dataLoopNodes->Node(TermInletNode).MassFlowRateMax;
1898 55844 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMinAvail = state.dataLoopNodes->Node(TermInletNode).MassFlowRateMin;
1899 : }
1900 34258 : for (int ZonesHeatedIndex = 1; ZonesHeatedIndex <= state.dataAirLoop->AirToZoneNodeInfo(AirLoopIndex).NumZonesHeated;
1901 : ++ZonesHeatedIndex) { // loop over the zones heated by this air loop
1902 0 : int TermInletNode = state.dataAirLoop->AirToZoneNodeInfo(AirLoopIndex).TermUnitHeatInletNodes(ZonesHeatedIndex);
1903 : // reset the max avail flow rate at the terminal unit hot air inlet to the max
1904 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMaxAvail = state.dataLoopNodes->Node(TermInletNode).MassFlowRateMax;
1905 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMinAvail = state.dataLoopNodes->Node(TermInletNode).MassFlowRateMin;
1906 : }
1907 : }
1908 208452 : }
1909 :
1910 215485 : void ResolveAirLoopFlowLimits(EnergyPlusData &state)
1911 : {
1912 :
1913 : // SUBROUTINE INFORMATION:
1914 : // AUTHOR Fred Buhl
1915 : // DATE WRITTEN August 2003
1916 : // RE-ENGINEERED na
1917 :
1918 : // PURPOSE OF THIS SUBROUTINE:
1919 : // This subroutine is for resolving hard flow mismatches between zone equipment and
1920 : // the primary air loop. Such a mismatch can occur when the air terminal units are
1921 : // requesting more air than the central air system can supply.
1922 :
1923 : // METHODOLOGY EMPLOYED:
1924 : // Sets the MassFlowRateMaxAvail on the terminal unit inlet nodes to match the
1925 : // maximum available from the primary air loop.
1926 :
1927 256777 : for (int AirLoopIndex = 1; AirLoopIndex <= state.dataHVACGlobal->NumPrimaryAirSys; ++AirLoopIndex) { // loop over the primary air loops
1928 :
1929 41292 : auto &AirToZoneNodeInfo = state.dataAirLoop->AirToZoneNodeInfo(AirLoopIndex);
1930 :
1931 82584 : for (int SupplyIndex = 1; SupplyIndex <= AirToZoneNodeInfo.NumSupplyNodes; ++SupplyIndex) { // loop over the air loop supply outlets
1932 41292 : if (AirToZoneNodeInfo.SupplyDuctType(SupplyIndex) == HVAC::AirDuctType::Cooling) { // check for cooling duct
1933 : // check if terminal units requesting more air than air loop can supply; if so, set terminal unit inlet
1934 : // node mass flow max avail to what air loop can supply
1935 41292 : int SupplyNode = AirToZoneNodeInfo.AirLoopSupplyNodeNum(SupplyIndex);
1936 41292 : if (state.dataLoopNodes->Node(SupplyNode).MassFlowRate > 0.0) {
1937 : // must include bypass flow for ChangeoverBypass system so that terminal units are not restricted (e.g., MaxAvail is lowered)
1938 35864 : if ((state.dataLoopNodes->Node(SupplyNode).MassFlowRateSetPoint - state.dataLoopNodes->Node(SupplyNode).MassFlowRate -
1939 35864 : state.dataAirLoop->AirLoopFlow(AirLoopIndex).BypassMassFlow) > DataConvergParams::HVACFlowRateToler * 0.01) {
1940 : Real64 FlowRatio =
1941 1824 : state.dataLoopNodes->Node(SupplyNode).MassFlowRate / state.dataLoopNodes->Node(SupplyNode).MassFlowRateSetPoint;
1942 3648 : for (int ZonesCooledIndex = 1; ZonesCooledIndex <= AirToZoneNodeInfo.NumZonesCooled; ++ZonesCooledIndex) {
1943 1824 : int TermInletNode = AirToZoneNodeInfo.TermUnitCoolInletNodes(ZonesCooledIndex);
1944 1824 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMaxAvail =
1945 1824 : state.dataLoopNodes->Node(TermInletNode).MassFlowRate * FlowRatio;
1946 1824 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMinAvail =
1947 1824 : min(state.dataLoopNodes->Node(TermInletNode).MassFlowRateMaxAvail,
1948 1824 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMinAvail);
1949 : }
1950 : }
1951 35864 : if ((state.dataLoopNodes->Node(SupplyNode).MassFlowRateSetPoint - state.dataLoopNodes->Node(SupplyNode).MassFlowRate -
1952 35864 : state.dataAirLoop->AirLoopFlow(AirLoopIndex).BypassMassFlow) < -DataConvergParams::HVACFlowRateToler * 0.01) {
1953 220 : if (state.dataLoopNodes->Node(SupplyNode).MassFlowRateSetPoint == 0.0) {
1954 : // CALL ShowFatalError('ResolveAirLoopFlowLimits: Node MassFlowRateSetPoint = 0.0, Node='// &
1955 : // TRIM(state.dataLoopNodes->NodeID(SupplyNode))// &
1956 : // ', check for Node Connection Errors in the following messages.')
1957 0 : for (int ZonesCooledIndex = 1; ZonesCooledIndex <= AirToZoneNodeInfo.NumZonesCooled; ++ZonesCooledIndex) {
1958 0 : int TermInletNode = AirToZoneNodeInfo.TermUnitCoolInletNodes(ZonesCooledIndex);
1959 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMaxAvail =
1960 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMax;
1961 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMinAvail =
1962 0 : state.dataLoopNodes->Node(SupplyNode).MassFlowRate / double(AirToZoneNodeInfo.NumZonesCooled);
1963 : }
1964 : } else {
1965 : Real64 FlowRatio =
1966 220 : state.dataLoopNodes->Node(SupplyNode).MassFlowRate / state.dataLoopNodes->Node(SupplyNode).MassFlowRateSetPoint;
1967 440 : for (int ZonesCooledIndex = 1; ZonesCooledIndex <= AirToZoneNodeInfo.NumZonesCooled; ++ZonesCooledIndex) {
1968 220 : int TermInletNode = AirToZoneNodeInfo.TermUnitCoolInletNodes(ZonesCooledIndex);
1969 220 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMinAvail =
1970 220 : state.dataLoopNodes->Node(TermInletNode).MassFlowRate * FlowRatio;
1971 220 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMaxAvail =
1972 220 : max(state.dataLoopNodes->Node(TermInletNode).MassFlowRateMaxAvail,
1973 220 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMinAvail);
1974 : }
1975 : }
1976 : }
1977 : }
1978 : }
1979 : }
1980 82584 : for (int SupplyIndex = 1; SupplyIndex <= AirToZoneNodeInfo.NumSupplyNodes; ++SupplyIndex) { // loop over the air loop supply outlets
1981 41292 : if (AirToZoneNodeInfo.SupplyDuctType(SupplyIndex) == HVAC::AirDuctType::Heating) { // check for heating duct
1982 : // check if terminal units requesting more air than air loop can supply; if so, set terminal unit inlet
1983 : // node mass flow max avail to what air loop can supply
1984 0 : int SupplyNode = AirToZoneNodeInfo.AirLoopSupplyNodeNum(SupplyIndex);
1985 0 : if (state.dataLoopNodes->Node(SupplyNode).MassFlowRate > 0.0) {
1986 : // must include bypass flow for ChangeoverBypass system so that terminal units are not restricted (e.g., MaxAvail is lowered)
1987 0 : if ((state.dataLoopNodes->Node(SupplyNode).MassFlowRateSetPoint - state.dataLoopNodes->Node(SupplyNode).MassFlowRate -
1988 0 : state.dataAirLoop->AirLoopFlow(AirLoopIndex).BypassMassFlow) > DataConvergParams::HVACFlowRateToler * 0.01) {
1989 : Real64 FlowRatio =
1990 0 : state.dataLoopNodes->Node(SupplyNode).MassFlowRate / state.dataLoopNodes->Node(SupplyNode).MassFlowRateSetPoint;
1991 0 : for (int ZonesHeatedIndex = 1; ZonesHeatedIndex <= AirToZoneNodeInfo.NumZonesHeated; ++ZonesHeatedIndex) {
1992 0 : int TermInletNode = AirToZoneNodeInfo.TermUnitHeatInletNodes(ZonesHeatedIndex);
1993 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMaxAvail =
1994 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRate * FlowRatio;
1995 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMinAvail =
1996 0 : min(state.dataLoopNodes->Node(TermInletNode).MassFlowRateMaxAvail,
1997 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMinAvail);
1998 : }
1999 : }
2000 0 : if ((state.dataLoopNodes->Node(SupplyNode).MassFlowRateSetPoint - state.dataLoopNodes->Node(SupplyNode).MassFlowRate -
2001 0 : state.dataAirLoop->AirLoopFlow(AirLoopIndex).BypassMassFlow) < -DataConvergParams::HVACFlowRateToler * 0.01) {
2002 0 : if (state.dataLoopNodes->Node(SupplyNode).MassFlowRateSetPoint == 0.0) {
2003 : // ', check for Node Connection Errors in the following messages.')
2004 0 : for (int ZonesHeatedIndex = 1; ZonesHeatedIndex <= AirToZoneNodeInfo.NumZonesHeated; ++ZonesHeatedIndex) {
2005 0 : int TermInletNode = AirToZoneNodeInfo.TermUnitHeatInletNodes(ZonesHeatedIndex);
2006 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMaxAvail =
2007 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMax;
2008 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMinAvail =
2009 0 : state.dataLoopNodes->Node(SupplyNode).MassFlowRate / double(AirToZoneNodeInfo.NumZonesCooled);
2010 : }
2011 : } else {
2012 : Real64 FlowRatio =
2013 0 : state.dataLoopNodes->Node(SupplyNode).MassFlowRate / state.dataLoopNodes->Node(SupplyNode).MassFlowRateSetPoint;
2014 0 : for (int ZonesHeatedIndex = 1; ZonesHeatedIndex <= AirToZoneNodeInfo.NumZonesHeated; ++ZonesHeatedIndex) {
2015 0 : int TermInletNode = AirToZoneNodeInfo.TermUnitHeatInletNodes(ZonesHeatedIndex);
2016 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMinAvail =
2017 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRate * FlowRatio;
2018 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMaxAvail =
2019 0 : max(state.dataLoopNodes->Node(TermInletNode).MassFlowRateMaxAvail,
2020 0 : state.dataLoopNodes->Node(TermInletNode).MassFlowRateMinAvail);
2021 : }
2022 : }
2023 : }
2024 : }
2025 : }
2026 : }
2027 : }
2028 215485 : }
2029 :
2030 216324 : void ResolveLockoutFlags(EnergyPlusData &state, bool &SimAir) // TRUE means air loops must be (re)simulated
2031 : {
2032 :
2033 : // SUBROUTINE INFORMATION:
2034 : // AUTHOR Fred Buhl
2035 : // DATE WRITTEN December 2003
2036 :
2037 : // PURPOSE OF THIS SUBROUTINE:
2038 : // This subroutine checks for components lockout flags and asks for air loop resimulation
2039 : // if any components have been locked out
2040 :
2041 : // METHODOLOGY EMPLOYED:
2042 : // Checks if loop lockout flags are .TRUE.; if so, sets SimAirLoops to .TRUE.
2043 :
2044 250745 : for (int AirLoopIndex = 1; AirLoopIndex <= state.dataHVACGlobal->NumPrimaryAirSys; ++AirLoopIndex) { // loop over the primary air loops
2045 34421 : auto &airLoopControlInfo = state.dataAirLoop->AirLoopControlInfo(AirLoopIndex);
2046 :
2047 : // check if economizer ia active and if there is a request that it be locked out
2048 34421 : if (airLoopControlInfo.EconoActive &&
2049 693 : (airLoopControlInfo.ReqstEconoLockoutWithCompressor || airLoopControlInfo.ReqstEconoLockoutWithHeating)) {
2050 0 : airLoopControlInfo.EconoLockout = true;
2051 0 : SimAir = true;
2052 : }
2053 : }
2054 216324 : }
2055 :
2056 208453 : void ResetHVACControl(EnergyPlusData const &state)
2057 : {
2058 :
2059 : // SUBROUTINE INFORMATION:
2060 : // AUTHOR Fred Buhl
2061 : // DATE WRITTEN December 2004
2062 :
2063 : // PURPOSE OF THIS SUBROUTINE:
2064 : // This subroutine resets loop control flags and specified flow rates that may
2065 : // have been set by the set point and availability managers in the previous
2066 : // time step
2067 :
2068 208453 : if (state.dataHVACGlobal->NumPrimaryAirSys == 0) return;
2069 68510 : for (auto &e : state.dataAirLoop->AirLoopControlInfo) {
2070 34255 : e.NightVent = false;
2071 34255 : e.LoopFlowRateSet = false;
2072 : }
2073 68510 : for (auto &e : state.dataAirLoop->AirLoopFlow)
2074 34255 : e.ReqSupplyFrac = 1.0;
2075 : }
2076 :
2077 113 : void ResetNodeData(EnergyPlusData &state)
2078 : {
2079 :
2080 : // SUBROUTINE INFORMATION:
2081 : // AUTHOR Linda Lawrie
2082 : // DATE WRITTEN March 2005
2083 :
2084 : // PURPOSE OF THIS SUBROUTINE:
2085 : // This routine resets all node data to "initial" conditions.
2086 :
2087 113 : if (state.dataLoopNodes->NumOfNodes <= 0) return;
2088 :
2089 1421 : for (auto &e : state.dataLoopNodes->Node) {
2090 1368 : e.Temp = state.dataLoopNodes->DefaultNodeValues.Temp;
2091 1368 : e.TempMin = state.dataLoopNodes->DefaultNodeValues.TempMin;
2092 1368 : e.TempMax = state.dataLoopNodes->DefaultNodeValues.TempMax;
2093 1368 : e.TempSetPoint = state.dataLoopNodes->DefaultNodeValues.TempSetPoint;
2094 1368 : e.MassFlowRate = state.dataLoopNodes->DefaultNodeValues.MassFlowRate;
2095 1368 : e.MassFlowRateMin = state.dataLoopNodes->DefaultNodeValues.MassFlowRateMin;
2096 1368 : e.MassFlowRateMax = state.dataLoopNodes->DefaultNodeValues.MassFlowRateMax;
2097 1368 : e.MassFlowRateMinAvail = state.dataLoopNodes->DefaultNodeValues.MassFlowRateMinAvail;
2098 1368 : e.MassFlowRateMaxAvail = state.dataLoopNodes->DefaultNodeValues.MassFlowRateMaxAvail;
2099 1368 : e.MassFlowRateSetPoint = state.dataLoopNodes->DefaultNodeValues.MassFlowRateSetPoint;
2100 1368 : e.Quality = state.dataLoopNodes->DefaultNodeValues.Quality;
2101 1368 : e.Press = state.dataLoopNodes->DefaultNodeValues.Press;
2102 1368 : e.Enthalpy = state.dataLoopNodes->DefaultNodeValues.Enthalpy;
2103 1368 : e.HumRat = state.dataLoopNodes->DefaultNodeValues.HumRat;
2104 1368 : e.HumRatMin = state.dataLoopNodes->DefaultNodeValues.HumRatMin;
2105 1368 : e.HumRatMax = state.dataLoopNodes->DefaultNodeValues.HumRatMax;
2106 1368 : e.HumRatSetPoint = state.dataLoopNodes->DefaultNodeValues.HumRatSetPoint;
2107 1368 : e.TempSetPointHi = state.dataLoopNodes->DefaultNodeValues.TempSetPointHi;
2108 1368 : e.TempSetPointLo = state.dataLoopNodes->DefaultNodeValues.TempSetPointLo;
2109 : }
2110 :
2111 53 : if (allocated(state.dataLoopNodes->MoreNodeInfo)) {
2112 1419 : for (auto &e : state.dataLoopNodes->MoreNodeInfo) {
2113 1367 : e.WetBulbTemp = state.dataLoopNodes->DefaultNodeValues.Temp;
2114 1367 : e.RelHumidity = 0.0;
2115 1367 : e.ReportEnthalpy = state.dataLoopNodes->DefaultNodeValues.Enthalpy;
2116 1367 : e.VolFlowRateStdRho = 0.0;
2117 1367 : e.VolFlowRateCrntRho = 0.0;
2118 1367 : e.Density = 0.0;
2119 : }
2120 : }
2121 : }
2122 :
2123 287262 : void UpdateZoneListAndGroupLoads(EnergyPlusData &state)
2124 : {
2125 :
2126 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2127 : int ZoneNum;
2128 : int ListNum;
2129 : int GroupNum;
2130 : int Mult;
2131 :
2132 : // Sum ZONE LIST and ZONE GROUP report variables
2133 336545 : for (ListNum = 1; ListNum <= state.dataHeatBal->NumOfZoneLists; ++ListNum) {
2134 49283 : state.dataHeatBal->ZoneListSNLoadHeatEnergy(ListNum) = 0.0;
2135 49283 : state.dataHeatBal->ZoneListSNLoadCoolEnergy(ListNum) = 0.0;
2136 49283 : state.dataHeatBal->ZoneListSNLoadHeatRate(ListNum) = 0.0;
2137 49283 : state.dataHeatBal->ZoneListSNLoadCoolRate(ListNum) = 0.0;
2138 : }
2139 :
2140 336545 : for (ListNum = 1; ListNum <= state.dataHeatBal->NumOfZoneLists; ++ListNum) {
2141 49283 : auto &zoneList = state.dataHeatBal->ZoneList(ListNum);
2142 115849 : for (ZoneNum = 1; ZoneNum <= zoneList.NumOfZones; ++ZoneNum) {
2143 66566 : auto const &zoneSysEnergyDemand = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneList.Zone(ZoneNum));
2144 66566 : Mult = state.dataHeatBal->Zone(ZoneNum).Multiplier;
2145 66566 : state.dataHeatBal->ZoneListSNLoadHeatEnergy(ListNum) += zoneSysEnergyDemand.airSysHeatEnergy * Mult;
2146 66566 : state.dataHeatBal->ZoneListSNLoadCoolEnergy(ListNum) += zoneSysEnergyDemand.airSysCoolEnergy * Mult;
2147 66566 : state.dataHeatBal->ZoneListSNLoadHeatRate(ListNum) += zoneSysEnergyDemand.airSysHeatRate * Mult;
2148 66566 : state.dataHeatBal->ZoneListSNLoadCoolRate(ListNum) += zoneSysEnergyDemand.airSysCoolRate * Mult;
2149 : } // ZoneNum
2150 : } // ListNum
2151 :
2152 316963 : for (GroupNum = 1; GroupNum <= state.dataHeatBal->NumOfZoneGroups; ++GroupNum) {
2153 29701 : auto &zoneGroup = state.dataHeatBal->ZoneGroup(GroupNum);
2154 29701 : Mult = zoneGroup.Multiplier;
2155 29701 : state.dataHeatBal->ZoneGroupSNLoadHeatEnergy(GroupNum) = state.dataHeatBal->ZoneListSNLoadHeatEnergy(zoneGroup.ZoneList) * Mult;
2156 29701 : state.dataHeatBal->ZoneGroupSNLoadCoolEnergy(GroupNum) = state.dataHeatBal->ZoneListSNLoadCoolEnergy(zoneGroup.ZoneList) * Mult;
2157 29701 : state.dataHeatBal->ZoneGroupSNLoadHeatRate(GroupNum) = state.dataHeatBal->ZoneListSNLoadHeatRate(zoneGroup.ZoneList) * Mult;
2158 29701 : state.dataHeatBal->ZoneGroupSNLoadCoolRate(GroupNum) = state.dataHeatBal->ZoneListSNLoadCoolRate(zoneGroup.ZoneList) * Mult;
2159 : } // GroupNum
2160 287262 : }
2161 :
2162 24091 : void ReportInfiltrations(EnergyPlusData &state)
2163 : {
2164 : // SUBROUTINE INFORMATION:
2165 : // AUTHOR Yueyue Zhou
2166 : // DATE WRITTEN July 2021
2167 :
2168 : // PURPOSE OF THIS SUBROUTINE:
2169 : // This subroutine currently creates the values for standard Infiltration object level reporting
2170 :
2171 : // SUBROUTINE PARAMETER DEFINITIONS:
2172 : static constexpr std::string_view RoutineName = "ReportInfiltrations";
2173 :
2174 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2175 : Real64 AirDensity; // Density of air (kg/m^3)
2176 : Real64 CpAir; // Heat capacity of air (J/kg-C)
2177 : Real64 TotalLoad; // Total loss or gain
2178 : Real64 H2OHtOfVap; // Heat of vaporization of air
2179 : Real64 ADSCorrectionFactor; // Correction factor of air flow model values when ADS is simulated
2180 24091 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
2181 24091 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
2182 :
2183 28054 : for (auto &thisInfiltration : state.dataHeatBal->Infiltration) {
2184 :
2185 3963 : int spaceNum = thisInfiltration.spaceIndex;
2186 3963 : auto &thisSpaceHB = state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum);
2187 3963 : int NZ = thisInfiltration.ZonePtr;
2188 3963 : auto const &thisZone = state.dataHeatBal->Zone(NZ);
2189 3963 : ADSCorrectionFactor = 1.0;
2190 3963 : if (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation) {
2191 : // CR7608 IF (TurnFansOn .AND. AirflowNetworkZoneFlag(NZ)) ADSCorrectionFactor=0
2192 0 : if ((state.dataZoneEquip->ZoneEquipAvail(NZ) == Avail::Status::CycleOn ||
2193 0 : state.dataZoneEquip->ZoneEquipAvail(NZ) == Avail::Status::CycleOnZoneFansOnly) &&
2194 0 : state.afn->AirflowNetworkZoneFlag(NZ))
2195 0 : ADSCorrectionFactor = 0.0;
2196 : }
2197 :
2198 3963 : CpAir = Psychrometrics::PsyCpAirFnW(state.dataEnvrn->OutHumRat);
2199 3963 : thisInfiltration.InfilMdot = thisInfiltration.MCpI_temp / CpAir * ADSCorrectionFactor;
2200 3963 : thisInfiltration.InfilMass = thisInfiltration.InfilMdot * TimeStepSysSec;
2201 :
2202 3963 : if (thisSpaceHB.MAT > thisZone.OutDryBulbTemp) {
2203 :
2204 2239 : thisInfiltration.InfilHeatLoss =
2205 2239 : thisInfiltration.MCpI_temp * (thisSpaceHB.MAT - thisZone.OutDryBulbTemp) * TimeStepSysSec * ADSCorrectionFactor;
2206 2239 : thisInfiltration.InfilHeatGain = 0.0;
2207 :
2208 : } else {
2209 :
2210 1724 : thisInfiltration.InfilHeatGain =
2211 1724 : thisInfiltration.MCpI_temp * (thisZone.OutDryBulbTemp - thisSpaceHB.MAT) * TimeStepSysSec * ADSCorrectionFactor;
2212 1724 : thisInfiltration.InfilHeatLoss = 0.0;
2213 : }
2214 :
2215 : // Report infiltration latent gains and losses
2216 3963 : H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(thisSpaceHB.airHumRat, thisSpaceHB.MAT);
2217 3963 : if (thisSpaceHB.airHumRat > state.dataEnvrn->OutHumRat) {
2218 :
2219 664 : thisInfiltration.InfilLatentLoss =
2220 664 : thisInfiltration.InfilMdot * (thisSpaceHB.airHumRat - state.dataEnvrn->OutHumRat) * H2OHtOfVap * TimeStepSysSec;
2221 664 : thisInfiltration.InfilLatentGain = 0.0;
2222 :
2223 : } else {
2224 :
2225 3299 : thisInfiltration.InfilLatentGain =
2226 3299 : thisInfiltration.InfilMdot * (state.dataEnvrn->OutHumRat - thisSpaceHB.airHumRat) * H2OHtOfVap * TimeStepSysSec;
2227 3299 : thisInfiltration.InfilLatentLoss = 0.0;
2228 : }
2229 : // Total infiltration losses and gains
2230 3963 : TotalLoad =
2231 3963 : thisInfiltration.InfilHeatGain + thisInfiltration.InfilLatentGain - thisInfiltration.InfilHeatLoss - thisInfiltration.InfilLatentLoss;
2232 3963 : if (TotalLoad > 0) {
2233 1306 : thisInfiltration.InfilTotalGain = TotalLoad;
2234 1306 : thisInfiltration.InfilTotalLoss = 0.0;
2235 : } else {
2236 2657 : thisInfiltration.InfilTotalGain = 0.0;
2237 2657 : thisInfiltration.InfilTotalLoss = -TotalLoad;
2238 : }
2239 : // CR7751 second, calculate using indoor conditions for density property
2240 : Real64 const spAirDensity =
2241 3963 : Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisSpaceHB.MAT, thisSpaceHB.airHumRatAvg, RoutineName);
2242 3963 : thisInfiltration.InfilVdotCurDensity = thisInfiltration.InfilMdot / spAirDensity;
2243 3963 : thisInfiltration.InfilVolumeCurDensity = thisInfiltration.InfilVdotCurDensity * TimeStepSysSec;
2244 :
2245 : // CR7751 third, calculate using standard dry air at nominal elevation
2246 3963 : thisInfiltration.InfilVdotStdDensity = thisInfiltration.InfilMdot / state.dataEnvrn->StdRhoAir;
2247 3963 : thisInfiltration.InfilVolumeStdDensity = thisInfiltration.InfilVdotStdDensity * TimeStepSysSec;
2248 :
2249 : // calculate using outdoor density
2250 : Real64 const outAirDensity =
2251 3963 : Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisZone.OutDryBulbTemp, state.dataEnvrn->OutHumRat, RoutineName);
2252 3963 : thisInfiltration.InfilVdotOutDensity = thisInfiltration.InfilMdot / outAirDensity;
2253 :
2254 : // Air change rates
2255 3963 : Real64 const vol = state.dataHeatBal->space(spaceNum).Volume;
2256 3963 : if (vol > 0.0) {
2257 3963 : Real64 secInHrOverVol = Constant::rSecsInHour / vol;
2258 3963 : thisInfiltration.InfilAirChangeRateCurDensity = thisInfiltration.InfilVdotCurDensity * secInHrOverVol;
2259 3963 : thisInfiltration.InfilAirChangeRateStdDensity = thisInfiltration.InfilVdotStdDensity * secInHrOverVol;
2260 3963 : thisInfiltration.InfilAirChangeRateOutDensity = thisInfiltration.InfilVdotOutDensity * secInHrOverVol;
2261 : //} else {
2262 : // shouldn't need this, should be initialized to zero and remain zero
2263 : // thisInfiltration.InfilAirChangeRateCurDensity = 0.0;
2264 : // thisInfiltration.InfilAirChangeRateStdDensity = 0.0;
2265 : // thisInfiltration.InfilAirChangeRateOutDensity = 0.0;
2266 : }
2267 : }
2268 24091 : }
2269 :
2270 24430 : void ReportAirHeatBalance(EnergyPlusData &state)
2271 : {
2272 :
2273 : // SUBROUTINE INFORMATION:
2274 : // AUTHOR Linda Lawrie
2275 : // DATE WRITTEN July 2000
2276 : // MODIFIED Shirey, Jan 2008 (MIXING/CROSS MIXING outputs)
2277 :
2278 : // PURPOSE OF THIS SUBROUTINE:
2279 : // This subroutine updates the report variables for the AirHeatBalance.
2280 :
2281 : static constexpr std::string_view RoutineName3("ReportAirHeatBalance:3");
2282 :
2283 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2284 :
2285 24430 : state.dataHeatBal->ZoneTotalExfiltrationHeatLoss = 0.0;
2286 24430 : state.dataHeatBal->ZoneTotalExhaustHeatLoss = 0.0;
2287 :
2288 24430 : if (state.afn->simulation_control.type != AirflowNetwork::ControlType::NoMultizoneOrDistribution) {
2289 339 : state.afn->report();
2290 : }
2291 :
2292 : // Reports zone exhaust loss by exhaust fans
2293 57099 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) { // Start of zone loads report variable update loop ...
2294 32669 : auto &zone = state.dataHeatBal->Zone(zoneNum);
2295 32669 : auto &znAirRpt = state.dataHeatBal->ZnAirRpt(zoneNum);
2296 32669 : auto &znEquipConfig = state.dataZoneEquip->ZoneEquipConfig(zoneNum);
2297 32669 : reportAirHeatBal1(state, znAirRpt, znEquipConfig, zoneNum);
2298 : }
2299 24430 : if (state.dataHeatBal->doSpaceHeatBalance) {
2300 8064 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
2301 6048 : auto &spAirRpt = state.dataHeatBal->spaceAirRpt(spaceNum);
2302 6048 : auto &spEquipConfig = state.dataZoneEquip->spaceEquipConfig(spaceNum);
2303 6048 : int zoneNum = state.dataHeatBal->space(spaceNum).zoneNum;
2304 6048 : reportAirHeatBal1(state, spAirRpt, spEquipConfig, zoneNum, spaceNum);
2305 : }
2306 : }
2307 :
2308 : // Report results for SIMPLE option only
2309 24769 : if (!(state.afn->simulation_control.type == AirflowNetwork::ControlType::NoMultizoneOrDistribution ||
2310 339 : state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation)) {
2311 339 : return;
2312 : }
2313 :
2314 24091 : ReportInfiltrations(state);
2315 :
2316 55743 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
2317 31652 : auto &znAirRpt = state.dataHeatBal->ZnAirRpt(zoneNum);
2318 31652 : auto &znEquipConfig = state.dataZoneEquip->ZoneEquipConfig(zoneNum);
2319 31652 : auto &znHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(zoneNum);
2320 31652 : reportAirHeatBal2(state, znAirRpt, znEquipConfig, znHB, zoneNum);
2321 : }
2322 24091 : if (state.dataHeatBal->doSpaceHeatBalance) {
2323 8064 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
2324 6048 : auto &spAirRpt = state.dataHeatBal->spaceAirRpt(spaceNum);
2325 6048 : auto &spEquipConfig = state.dataZoneEquip->spaceEquipConfig(spaceNum);
2326 6048 : auto &spHB = state.dataZoneTempPredictorCorrector->spaceHeatBalance(spaceNum);
2327 6048 : int zoneNum = state.dataHeatBal->space(spaceNum).zoneNum;
2328 6048 : reportAirHeatBal2(state, spAirRpt, spEquipConfig, spHB, zoneNum, spaceNum);
2329 : }
2330 : }
2331 : }
2332 :
2333 38717 : void reportAirHeatBal1(EnergyPlusData &state,
2334 : DataHeatBalance::AirReportVars &szAirRpt,
2335 : DataZoneEquipment::EquipConfiguration const &szEquipConfig,
2336 : int const zoneNum,
2337 : int const spaceNum)
2338 : {
2339 38717 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(state.dataEnvrn->OutHumRat); // Heat capacity of air (J/kg-C)
2340 38717 : Real64 outDB = state.dataHeatBal->Zone(zoneNum).OutDryBulbTemp;
2341 38717 : Real64 H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(state.dataEnvrn->OutHumRat, outDB); // Heat of vaporization of air
2342 38717 : Real64 ADSCorrectionFactor = 1.0;
2343 38717 : if (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation) {
2344 0 : if ((state.dataZoneEquip->ZoneEquipAvail(zoneNum) == Avail::Status::CycleOn ||
2345 0 : state.dataZoneEquip->ZoneEquipAvail(zoneNum) == Avail::Status::CycleOnZoneFansOnly) &&
2346 0 : state.afn->AirflowNetworkZoneFlag(zoneNum)) {
2347 0 : ADSCorrectionFactor = 0.0;
2348 : }
2349 : }
2350 :
2351 38717 : szAirRpt.ExhTotalLoss = 0;
2352 38717 : szAirRpt.ExhSensiLoss = 0;
2353 :
2354 61139 : for (int FanNum = 1; FanNum <= (int)state.dataFans->fans.size(); ++FanNum) {
2355 22422 : auto const *thisFan = state.dataFans->fans(FanNum);
2356 : // Add reportable vars
2357 22422 : if (thisFan->type == HVAC::FanType::Exhaust) {
2358 1358 : for (int ExhNum = 1; ExhNum <= szEquipConfig.NumExhaustNodes; ExhNum++) {
2359 679 : if (thisFan->inletNodeNum == szEquipConfig.ExhaustNode(ExhNum)) {
2360 340 : szAirRpt.ExhTotalLoss +=
2361 340 : thisFan->outletAirMassFlowRate * (thisFan->outletAirEnthalpy - state.dataEnvrn->OutEnthalpy) * ADSCorrectionFactor;
2362 340 : szAirRpt.ExhSensiLoss += thisFan->outletAirMassFlowRate * CpAir * (thisFan->outletAirTemp - outDB) * ADSCorrectionFactor;
2363 340 : break;
2364 : }
2365 : }
2366 : }
2367 : }
2368 :
2369 38717 : szAirRpt.ExhLatentLoss = szAirRpt.ExhTotalLoss - szAirRpt.ExhSensiLoss;
2370 38717 : }
2371 37700 : void reportAirHeatBal2(EnergyPlusData &state,
2372 : DataHeatBalance::AirReportVars &szAirRpt,
2373 : DataZoneEquipment::EquipConfiguration const &szEquipConfig,
2374 : ZoneTempPredictorCorrector::ZoneSpaceHeatBalanceData const &szHeatBal,
2375 : int const zoneNum,
2376 : int const spaceNum)
2377 : {
2378 : static constexpr std::string_view RoutineName = "reportAirHeatBal2";
2379 :
2380 : // Break the infiltration load into heat gain and loss components
2381 37700 : Real64 ADSCorrectionFactor = 1.0;
2382 :
2383 37700 : if (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation) {
2384 : // CR7608 IF (TurnFansOn .AND. AirflowNetworkZoneFlag(zoneNum)) ADSCorrectionFactor=0
2385 0 : if ((state.dataZoneEquip->ZoneEquipAvail(zoneNum) == Avail::Status::CycleOn ||
2386 0 : state.dataZoneEquip->ZoneEquipAvail(zoneNum) == Avail::Status::CycleOnZoneFansOnly) &&
2387 0 : state.afn->AirflowNetworkZoneFlag(zoneNum))
2388 0 : ADSCorrectionFactor = 0.0;
2389 : }
2390 :
2391 37700 : Real64 const outDryBulb = state.dataHeatBal->Zone(zoneNum).OutDryBulbTemp;
2392 37700 : if (szHeatBal.MAT > outDryBulb) {
2393 :
2394 19896 : szAirRpt.InfilHeatLoss = szHeatBal.MCPI * (szHeatBal.MAT - outDryBulb) * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2395 19896 : szAirRpt.InfilHeatGain = 0.0;
2396 :
2397 : } else {
2398 :
2399 17804 : szAirRpt.InfilHeatGain = szHeatBal.MCPI * (outDryBulb - szHeatBal.MAT) * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2400 17804 : szAirRpt.InfilHeatLoss = 0.0;
2401 : }
2402 : // Report infiltration latent gains and losses
2403 37700 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(state.dataEnvrn->OutHumRat); // Heat capacity of air (J/kg-C)
2404 37700 : Real64 H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(szHeatBal.airHumRat, szHeatBal.MAT); // Heat of vaporization of air
2405 37700 : if (szHeatBal.airHumRat > state.dataEnvrn->OutHumRat) {
2406 :
2407 12930 : szAirRpt.InfilLatentLoss = szHeatBal.MCPI / CpAir * (szHeatBal.airHumRat - state.dataEnvrn->OutHumRat) * H2OHtOfVap *
2408 12930 : state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2409 12930 : szAirRpt.InfilLatentGain = 0.0;
2410 :
2411 : } else {
2412 :
2413 24770 : szAirRpt.InfilLatentGain = szHeatBal.MCPI / CpAir * (state.dataEnvrn->OutHumRat - szHeatBal.airHumRat) * H2OHtOfVap *
2414 24770 : state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2415 24770 : szAirRpt.InfilLatentLoss = 0.0;
2416 : }
2417 : // Total infiltration losses and gains
2418 37700 : Real64 TotalLoad = szAirRpt.InfilHeatGain + szAirRpt.InfilLatentGain - szAirRpt.InfilHeatLoss - szAirRpt.InfilLatentLoss;
2419 37700 : if (TotalLoad > 0) {
2420 1306 : szAirRpt.InfilTotalGain = TotalLoad * ADSCorrectionFactor;
2421 1306 : szAirRpt.InfilTotalLoss = 0.0;
2422 : } else {
2423 36394 : szAirRpt.InfilTotalGain = 0.0;
2424 36394 : szAirRpt.InfilTotalLoss = -TotalLoad * ADSCorrectionFactor;
2425 : }
2426 :
2427 : // first calculate mass flows using outside air heat capacity for consistency with input to heat balance
2428 37700 : szAirRpt.InfilMdot = (szHeatBal.MCPI / CpAir) * ADSCorrectionFactor;
2429 37700 : szAirRpt.InfilMass = szAirRpt.InfilMdot * state.dataHVACGlobal->TimeStepSysSec;
2430 37700 : szAirRpt.VentilMdot = (szHeatBal.MCPV / CpAir) * ADSCorrectionFactor;
2431 37700 : szAirRpt.VentilMass = szAirRpt.VentilMdot * state.dataHVACGlobal->TimeStepSysSec;
2432 :
2433 : // CR7751 second, calculate using indoor conditions for density property
2434 : Real64 const szAirDensity =
2435 37700 : Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, szHeatBal.MAT, szHeatBal.airHumRatAvg, RoutineName);
2436 37700 : szAirRpt.InfilVdotCurDensity = szAirRpt.InfilMdot / szAirDensity;
2437 37700 : szAirRpt.InfilVolumeCurDensity = szAirRpt.InfilVdotCurDensity * state.dataHVACGlobal->TimeStepSysSec;
2438 37700 : szAirRpt.VentilVdotCurDensity = szAirRpt.VentilMdot / szAirDensity;
2439 37700 : szAirRpt.VentilVolumeCurDensity = szAirRpt.VentilVdotCurDensity * state.dataHVACGlobal->TimeStepSysSec;
2440 :
2441 : // CR7751 third, calculate using standard dry air at nominal elevation
2442 37700 : szAirRpt.InfilVdotStdDensity = szAirRpt.InfilMdot / state.dataEnvrn->StdRhoAir;
2443 37700 : szAirRpt.InfilVolumeStdDensity = szAirRpt.InfilVdotStdDensity * state.dataHVACGlobal->TimeStepSysSec;
2444 37700 : szAirRpt.VentilVdotStdDensity = szAirRpt.VentilMdot / state.dataEnvrn->StdRhoAir;
2445 37700 : szAirRpt.VentilVolumeStdDensity = szAirRpt.VentilVdotStdDensity * state.dataHVACGlobal->TimeStepSysSec;
2446 :
2447 : // Calculate using outdoor air density
2448 : Real64 const outAirDensity =
2449 37700 : Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, outDryBulb, state.dataEnvrn->OutHumRat, RoutineName);
2450 37700 : szAirRpt.InfilVdotOutDensity = szAirRpt.InfilMdot / outAirDensity;
2451 37700 : szAirRpt.VentilVdotOutDensity = szAirRpt.VentilMdot / outAirDensity;
2452 :
2453 : // calculate air change rates
2454 37700 : Real64 const szVolume = (spaceNum == 0) ? state.dataHeatBal->Zone(zoneNum).Volume : state.dataHeatBal->space(spaceNum).Volume;
2455 37700 : if (szVolume > 0.0) {
2456 37694 : Real64 secInHrOverVol = Constant::rSecsInHour / szVolume;
2457 37694 : szAirRpt.InfilAirChangeRateCurDensity = szAirRpt.InfilVdotCurDensity * secInHrOverVol;
2458 37694 : szAirRpt.InfilAirChangeRateStdDensity = szAirRpt.InfilVdotStdDensity * secInHrOverVol;
2459 37694 : szAirRpt.InfilAirChangeRateOutDensity = szAirRpt.InfilVdotOutDensity * secInHrOverVol;
2460 37694 : szAirRpt.VentilAirChangeRateCurDensity = szAirRpt.VentilVdotCurDensity * secInHrOverVol;
2461 37694 : szAirRpt.VentilAirChangeRateStdDensity = szAirRpt.VentilVdotStdDensity * secInHrOverVol;
2462 37694 : szAirRpt.VentilAirChangeRateOutDensity = szAirRpt.VentilVdotOutDensity * secInHrOverVol;
2463 : //} else {
2464 : // shouldn't need this, should be initialized to zero and remain zero
2465 : // szAirRpt.InfilAirChangeRateCurDensity = 0.0;
2466 : // szAirRpt.InfilAirChangeRateStdDensity = 0.0;
2467 : // szAirRpt.InfilAirChangeRateOutDensity = 0.0;
2468 : // szAirRpt.VentilAirChangeRateCurDensity = 0.0;
2469 : // szAirRpt.VentilAirChangeRateStdDensity = 0.0;
2470 : // szAirRpt.VentilAirChangeRateOutDensity = 0.0;
2471 : }
2472 :
2473 : // szAirRpt%VentilFanElec = 0.0
2474 37700 : szAirRpt.VentilAirTemp = 0.0;
2475 37700 : szAirRpt.VentilHeatLoss = 0.0;
2476 37700 : szAirRpt.VentilHeatGain = 0.0;
2477 37700 : int ventCount = 0; // Number of ventilation object per zone or space
2478 37700 : Real64 VentZoneMassflow = 0.0; // Total mass flow rate per zone
2479 37700 : Real64 VentZoneAirTemp = 0.0; // Average Zone inlet temperature
2480 :
2481 37702 : for (int VentNum = 1; VentNum <= state.dataHeatBal->TotVentilation; ++VentNum) {
2482 2 : auto const &ventilation = state.dataHeatBal->Ventilation(VentNum);
2483 2 : if (((spaceNum == 0) && (ventilation.ZonePtr == zoneNum)) || ((spaceNum > 0) && (spaceNum == ventilation.spaceIndex))) {
2484 1 : if (ADSCorrectionFactor > 0) {
2485 1 : szAirRpt.VentilAirTemp += ventilation.AirTemp * ventilation.MCP;
2486 1 : VentZoneMassflow += ventilation.MCP;
2487 1 : VentZoneAirTemp += ventilation.AirTemp;
2488 : } else {
2489 0 : szAirRpt.VentilAirTemp = outDryBulb;
2490 : }
2491 : // Break the ventilation load into heat gain and loss components
2492 1 : if (szHeatBal.MAT > ventilation.AirTemp) {
2493 1 : szAirRpt.VentilHeatLoss +=
2494 1 : ventilation.MCP * (szHeatBal.MAT - ventilation.AirTemp) * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2495 : } else {
2496 0 : szAirRpt.VentilHeatGain +=
2497 0 : ventilation.MCP * (ventilation.AirTemp - szHeatBal.MAT) * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2498 : }
2499 :
2500 1 : ++ventCount;
2501 1 : if (ventCount > 1) continue;
2502 :
2503 : // Report ventilation latent gains and losses
2504 1 : H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(szHeatBal.airHumRat, szHeatBal.MAT);
2505 1 : if (szHeatBal.airHumRat > state.dataEnvrn->OutHumRat) {
2506 1 : szAirRpt.VentilLatentLoss =
2507 1 : szAirRpt.VentilMdot * (szHeatBal.airHumRat - state.dataEnvrn->OutHumRat) * H2OHtOfVap * state.dataHVACGlobal->TimeStepSysSec;
2508 1 : szAirRpt.VentilLatentGain = 0.0;
2509 : } else {
2510 0 : szAirRpt.VentilLatentGain =
2511 0 : szAirRpt.VentilMdot * (state.dataEnvrn->OutHumRat - szHeatBal.airHumRat) * H2OHtOfVap * state.dataHVACGlobal->TimeStepSysSec;
2512 0 : szAirRpt.VentilLatentLoss = 0.0;
2513 : }
2514 : // Total ventilation losses and gains
2515 1 : TotalLoad = szAirRpt.VentilHeatGain + szAirRpt.VentilLatentGain - szAirRpt.VentilHeatLoss - szAirRpt.VentilLatentLoss;
2516 1 : if (TotalLoad > 0) {
2517 0 : szAirRpt.VentilTotalGain = TotalLoad * ADSCorrectionFactor;
2518 0 : szAirRpt.VentilTotalLoss = 0.0;
2519 : } else {
2520 1 : szAirRpt.VentilTotalGain = 0.0;
2521 1 : szAirRpt.VentilTotalLoss = -TotalLoad * ADSCorrectionFactor;
2522 : }
2523 : }
2524 : }
2525 :
2526 37700 : if (ADSCorrectionFactor > 0 && ventCount > 1 && VentZoneMassflow > 0.0) {
2527 0 : szAirRpt.VentilAirTemp /= VentZoneMassflow;
2528 37700 : } else if (ADSCorrectionFactor > 0 && ventCount == 1) {
2529 1 : szAirRpt.VentilAirTemp = VentZoneAirTemp;
2530 : } else { // Just in case
2531 37699 : szAirRpt.VentilAirTemp = outDryBulb;
2532 : }
2533 :
2534 : // Report mixing sensible and latent loads
2535 37700 : szAirRpt.MixSenLoad = 0.0; // Initialize arrays to zero before starting to sum
2536 37700 : szAirRpt.MixLatLoad = 0.0;
2537 37700 : szAirRpt.MixVolume = 0.0; // zero reported volume prior to summations below
2538 37700 : szAirRpt.MixVdotCurDensity = 0.0; // zero reported volume flow rate prior to summations below
2539 37700 : szAirRpt.MixVdotStdDensity = 0.0; // zero reported volume flow rate prior to summations below
2540 37700 : szAirRpt.MixMass = 0.0; // ! zero reported mass prior to summations below
2541 37700 : szAirRpt.MixMdot = 0.0; // ! zero reported mass flow rate prior to summations below
2542 : // MixingLoad = 0.0d0
2543 :
2544 52100 : for (int MixNum = 1; MixNum <= state.dataHeatBal->TotMixing; ++MixNum) {
2545 14400 : auto &mixing = state.dataHeatBal->Mixing(MixNum);
2546 14400 : if (mixing.ReportFlag && (((spaceNum == 0) && (mixing.ZonePtr == zoneNum)) || ((spaceNum > 0) && (spaceNum == mixing.spaceIndex)))) {
2547 7200 : Real64 const fromMAT = (mixing.fromSpaceIndex == 0) ? state.dataZoneTempPredictorCorrector->zoneHeatBalance(mixing.FromZone).MAT
2548 5760 : : state.dataZoneTempPredictorCorrector->spaceHeatBalance(mixing.fromSpaceIndex).MAT;
2549 7200 : Real64 const fromHumRat = (mixing.fromSpaceIndex == 0)
2550 7200 : ? state.dataZoneTempPredictorCorrector->zoneHeatBalance(mixing.FromZone).airHumRat
2551 5760 : : state.dataZoneTempPredictorCorrector->spaceHeatBalance(mixing.fromSpaceIndex).airHumRat;
2552 : // szAirRpt.MixSenLoad(zoneNum) = szAirRpt.MixSenLoad(zoneNum)+MCPM(zoneNum)*MAT(mixing%FromZone)
2553 : // H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(ZoneAirHumRat(zoneNum), MAT(zoneNum))
2554 : // Per Jan 17, 2008 conference call, agreed to use average conditions for Rho, Cp and Hfg
2555 : // and to recalculate the report variable using end of time step temps and humrats
2556 14400 : Real64 const AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(
2557 21600 : state, state.dataEnvrn->OutBaroPress, (szHeatBal.MAT + fromMAT) / 2.0, (szHeatBal.airHumRat + fromHumRat) / 2.0, std::string());
2558 7200 : CpAir = Psychrometrics::PsyCpAirFnW((szHeatBal.airHumRat + fromHumRat) / 2.0);
2559 7200 : szAirRpt.MixVolume += mixing.DesiredAirFlowRate * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2560 7200 : szAirRpt.MixVdotCurDensity += mixing.DesiredAirFlowRate * ADSCorrectionFactor;
2561 7200 : szAirRpt.MixMass += mixing.DesiredAirFlowRate * AirDensity * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2562 7200 : szAirRpt.MixMdot += mixing.DesiredAirFlowRate * AirDensity * ADSCorrectionFactor;
2563 7200 : szAirRpt.MixVdotStdDensity += mixing.DesiredAirFlowRate * (AirDensity / state.dataEnvrn->StdRhoAir) * ADSCorrectionFactor;
2564 7200 : szAirRpt.MixSenLoad += mixing.DesiredAirFlowRate * AirDensity * CpAir * (szHeatBal.MAT - fromMAT);
2565 7200 : H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb((szHeatBal.airHumRat + fromHumRat) / 2.0, (szHeatBal.MAT + fromMAT) / 2.0);
2566 : // szAirRpt.MixLatLoad(zoneNum) = szAirRpt.MixLatLoad(zoneNum)+MixingMassFlowzone*(ZoneAirHumRat(zoneNum)- &
2567 : // ZoneAirHumRat(mixing%FromZone))*H2OHtOfVap
2568 7200 : szAirRpt.MixLatLoad += mixing.DesiredAirFlowRate * AirDensity * (szHeatBal.airHumRat - fromHumRat) * H2OHtOfVap;
2569 : }
2570 : }
2571 :
2572 52102 : for (int MixNum = 1; MixNum <= state.dataHeatBal->TotCrossMixing; ++MixNum) {
2573 14402 : auto &crossMixing = state.dataHeatBal->CrossMixing(MixNum);
2574 14402 : if (crossMixing.ReportFlag &&
2575 14402 : ((((spaceNum == 0) && (crossMixing.ZonePtr == zoneNum)) || (spaceNum > 0) && (spaceNum == crossMixing.spaceIndex)))) {
2576 7201 : Real64 const fromMAT = (crossMixing.fromSpaceIndex == 0)
2577 7201 : ? state.dataZoneTempPredictorCorrector->zoneHeatBalance(crossMixing.FromZone).MAT
2578 5760 : : state.dataZoneTempPredictorCorrector->spaceHeatBalance(crossMixing.fromSpaceIndex).MAT;
2579 7201 : Real64 const fromHumRat = (crossMixing.fromSpaceIndex == 0)
2580 7201 : ? state.dataZoneTempPredictorCorrector->zoneHeatBalance(crossMixing.FromZone).airHumRat
2581 5760 : : state.dataZoneTempPredictorCorrector->spaceHeatBalance(crossMixing.fromSpaceIndex).airHumRat;
2582 : // szAirRpt.MixSenLoad(zoneNum) = szAirRpt.MixSenLoad(zoneNum)+MCPM(zoneNum)*MAT(crossMixing%FromZone)
2583 : // Per Jan 17, 2008 conference call, agreed to use average conditions for Rho, Cp and Hfg
2584 : // and to recalculate the report variable using end of time step temps and humrats
2585 14402 : Real64 const AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(
2586 21603 : state, state.dataEnvrn->OutBaroPress, (szHeatBal.MAT + fromMAT) / 2.0, (szHeatBal.airHumRat + fromHumRat) / 2.0, std::string());
2587 7201 : CpAir = Psychrometrics::PsyCpAirFnW((szHeatBal.airHumRat + fromHumRat) / 2.0);
2588 7201 : szAirRpt.MixVolume += crossMixing.DesiredAirFlowRate * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2589 7201 : szAirRpt.MixVdotCurDensity += crossMixing.DesiredAirFlowRate * ADSCorrectionFactor;
2590 7201 : szAirRpt.MixMass += crossMixing.DesiredAirFlowRate * AirDensity * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2591 7201 : szAirRpt.MixMdot += crossMixing.DesiredAirFlowRate * AirDensity * ADSCorrectionFactor;
2592 7201 : szAirRpt.MixVdotStdDensity += crossMixing.DesiredAirFlowRate * (AirDensity / state.dataEnvrn->StdRhoAir) * ADSCorrectionFactor;
2593 7201 : szAirRpt.MixSenLoad += crossMixing.DesiredAirFlowRate * AirDensity * CpAir * (szHeatBal.MAT - fromMAT);
2594 7201 : H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb((szHeatBal.airHumRat + fromHumRat) / 2.0, (szHeatBal.MAT + fromMAT) / 2.0);
2595 : // szAirRpt.MixLatLoad(zoneNum) = szAirRpt.MixLatLoad(zoneNum)+MixingMassFlowzone*(ZoneAirHumRat(zoneNum)- &
2596 : // ZoneAirHumRat(crossMixing%FromZone))*H2OHtOfVap
2597 7201 : szAirRpt.MixLatLoad += crossMixing.DesiredAirFlowRate * AirDensity * (szHeatBal.airHumRat - fromHumRat) * H2OHtOfVap;
2598 : }
2599 14402 : if (crossMixing.ReportFlag &&
2600 14402 : (((spaceNum == 0) && (crossMixing.FromZone == zoneNum)) || ((spaceNum > 0) && (spaceNum == crossMixing.fromSpaceIndex)))) {
2601 7201 : Real64 const mixingMAT = (crossMixing.spaceIndex == 0)
2602 7201 : ? state.dataZoneTempPredictorCorrector->zoneHeatBalance(crossMixing.ZonePtr).MAT
2603 7200 : : state.dataZoneTempPredictorCorrector->spaceHeatBalance(crossMixing.spaceIndex).MAT;
2604 7201 : Real64 const mixingHumRat = (crossMixing.fromSpaceIndex == 0)
2605 7201 : ? state.dataZoneTempPredictorCorrector->zoneHeatBalance(crossMixing.ZonePtr).airHumRat
2606 5760 : : state.dataZoneTempPredictorCorrector->spaceHeatBalance(crossMixing.spaceIndex).airHumRat;
2607 14402 : Real64 const AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(
2608 21603 : state, state.dataEnvrn->OutBaroPress, (szHeatBal.MAT + mixingMAT) / 2.0, (szHeatBal.airHumRat + mixingHumRat) / 2.0, std::string());
2609 7201 : CpAir = Psychrometrics::PsyCpAirFnW((szHeatBal.airHumRat + mixingHumRat) / 2.0);
2610 7201 : szAirRpt.MixVolume += crossMixing.DesiredAirFlowRate * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2611 7201 : szAirRpt.MixVdotCurDensity += crossMixing.DesiredAirFlowRate * ADSCorrectionFactor;
2612 7201 : szAirRpt.MixMass += crossMixing.DesiredAirFlowRate * AirDensity * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2613 7201 : szAirRpt.MixMdot += crossMixing.DesiredAirFlowRate * AirDensity * ADSCorrectionFactor;
2614 7201 : szAirRpt.MixVdotStdDensity += crossMixing.DesiredAirFlowRate * (AirDensity / state.dataEnvrn->StdRhoAir) * ADSCorrectionFactor;
2615 7201 : szAirRpt.MixSenLoad += crossMixing.DesiredAirFlowRate * AirDensity * CpAir * (szHeatBal.MAT - mixingMAT);
2616 7201 : H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb((szHeatBal.airHumRat + mixingHumRat) / 2.0, (szHeatBal.MAT + mixingMAT) / 2.0);
2617 7201 : szAirRpt.MixLatLoad += crossMixing.DesiredAirFlowRate * AirDensity * (szHeatBal.airHumRat - mixingHumRat) * H2OHtOfVap;
2618 : }
2619 : }
2620 :
2621 37700 : if (state.dataHeatBal->TotRefDoorMixing > 0) {
2622 : // IF(zoneNum .NE. NumOfZones)THEN !Refrigeration Door Mixing
2623 : // Note - do each Pair a Single time, so must do increment reports for both zones
2624 : // Can't have a pair that has ZoneA zone number = NumOfZones because organized
2625 : // in input with lowest zone # first no matter how input in idf
2626 0 : auto &refDoorMixing = state.dataHeatBal->RefDoorMixing(zoneNum);
2627 0 : if (refDoorMixing.RefDoorMixFlag) { // .TRUE. for both zoneA and zoneB
2628 0 : if (((spaceNum == 0) && (refDoorMixing.ZonePtr == zoneNum)) || ((spaceNum > 0) && (spaceNum == refDoorMixing.spaceIndex))) {
2629 0 : for (int j = 1; j <= refDoorMixing.NumRefDoorConnections; ++j) {
2630 : // Capture impact when zoneNum is the 'primary zone'
2631 : // that is, the zone of a pair with the lower zone number
2632 0 : if (refDoorMixing.VolRefDoorFlowRate(j) > 0.0) {
2633 : // int ZoneB = refDoorMixing.MateZonePtr(j);
2634 : // auto const &zoneBHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneB);
2635 0 : Real64 const szBMAT = (refDoorMixing.fromSpaceIndex == 0)
2636 0 : ? state.dataZoneTempPredictorCorrector->zoneHeatBalance(refDoorMixing.MateZonePtr(j)).MAT
2637 0 : : state.dataZoneTempPredictorCorrector->spaceHeatBalance(refDoorMixing.fromSpaceIndex).MAT;
2638 0 : Real64 const szBHumRat = (refDoorMixing.fromSpaceIndex == 0)
2639 0 : ? state.dataZoneTempPredictorCorrector->zoneHeatBalance(refDoorMixing.MateZonePtr(j)).airHumRat
2640 0 : : state.dataZoneTempPredictorCorrector->spaceHeatBalance(refDoorMixing.fromSpaceIndex).airHumRat;
2641 0 : Real64 const AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state,
2642 0 : state.dataEnvrn->OutBaroPress,
2643 0 : (szHeatBal.MAT + szBMAT) / 2.0,
2644 0 : (szHeatBal.airHumRat + szBHumRat) / 2.0,
2645 0 : std::string());
2646 0 : CpAir = Psychrometrics::PsyCpAirFnW((szHeatBal.airHumRat + szBHumRat) / 2.0);
2647 0 : H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb((szHeatBal.airHumRat + szBHumRat) / 2.0, (szHeatBal.MAT + szBMAT) / 2.0);
2648 0 : szAirRpt.MixVolume += refDoorMixing.VolRefDoorFlowRate(j) * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2649 0 : szAirRpt.MixVdotCurDensity += refDoorMixing.VolRefDoorFlowRate(j) * ADSCorrectionFactor;
2650 0 : szAirRpt.MixMass +=
2651 0 : refDoorMixing.VolRefDoorFlowRate(j) * AirDensity * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2652 0 : szAirRpt.MixMdot += refDoorMixing.VolRefDoorFlowRate(j) * AirDensity * ADSCorrectionFactor;
2653 0 : szAirRpt.MixVdotStdDensity +=
2654 0 : refDoorMixing.VolRefDoorFlowRate(j) * (AirDensity / state.dataEnvrn->StdRhoAir) * ADSCorrectionFactor;
2655 0 : szAirRpt.MixSenLoad += refDoorMixing.VolRefDoorFlowRate(j) * AirDensity * CpAir * (szHeatBal.MAT - szBMAT);
2656 0 : szAirRpt.MixLatLoad += refDoorMixing.VolRefDoorFlowRate(j) * AirDensity * (szHeatBal.airHumRat - szBHumRat) * H2OHtOfVap;
2657 : } // flow > 0
2658 : } // J-1, numref connections
2659 : } // zone A (zoneptr = zoneNum)
2660 0 : for (int ZoneA = 1; ZoneA <= (zoneNum - 1); ++ZoneA) {
2661 0 : auto &refDoorMixingA = state.dataHeatBal->RefDoorMixing(ZoneA);
2662 : // Capture impact when zoneNum is the 'mating zone'
2663 : // that is, the zone of a pair with the higher zone number(matezoneptr = zoneNum)
2664 0 : if (refDoorMixingA.RefDoorMixFlag) {
2665 0 : for (int j = 1; j <= refDoorMixingA.NumRefDoorConnections; ++j) {
2666 0 : if (((spaceNum == 0) && (refDoorMixingA.MateZonePtr(j) == zoneNum)) ||
2667 0 : ((spaceNum == 0) && (refDoorMixingA.fromSpaceIndex == spaceNum))) {
2668 0 : if (refDoorMixingA.VolRefDoorFlowRate(j) > 0.0) {
2669 : // auto const &zoneAHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneA);
2670 0 : Real64 const szAMAT = (refDoorMixingA.spaceIndex == 0)
2671 0 : ? state.dataZoneTempPredictorCorrector->zoneHeatBalance(refDoorMixingA.ZonePtr).MAT
2672 0 : : state.dataZoneTempPredictorCorrector->spaceHeatBalance(refDoorMixingA.spaceIndex).MAT;
2673 : Real64 const szAHumRat =
2674 0 : (refDoorMixingA.spaceIndex == 0)
2675 0 : ? state.dataZoneTempPredictorCorrector->zoneHeatBalance(refDoorMixingA.ZonePtr).airHumRat
2676 0 : : state.dataZoneTempPredictorCorrector->spaceHeatBalance(refDoorMixingA.spaceIndex).airHumRat;
2677 0 : Real64 const AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state,
2678 0 : state.dataEnvrn->OutBaroPress,
2679 0 : (szHeatBal.MAT + szAMAT) / 2.0,
2680 0 : (szHeatBal.airHumRat + szAHumRat) / 2.0,
2681 0 : std::string());
2682 0 : CpAir = Psychrometrics::PsyCpAirFnW((szHeatBal.airHumRat + szAHumRat) / 2.0);
2683 0 : H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb((szHeatBal.airHumRat + szAHumRat) / 2.0, (szHeatBal.MAT + szAMAT) / 2.0);
2684 0 : szAirRpt.MixVolume +=
2685 0 : refDoorMixingA.VolRefDoorFlowRate(j) * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2686 0 : szAirRpt.MixVdotCurDensity += refDoorMixingA.VolRefDoorFlowRate(j) * ADSCorrectionFactor;
2687 0 : szAirRpt.MixMass +=
2688 0 : refDoorMixingA.VolRefDoorFlowRate(j) * AirDensity * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2689 0 : szAirRpt.MixMdot += refDoorMixingA.VolRefDoorFlowRate(j) * AirDensity * ADSCorrectionFactor;
2690 0 : szAirRpt.MixVdotStdDensity +=
2691 0 : refDoorMixingA.VolRefDoorFlowRate(j) * (AirDensity / state.dataEnvrn->StdRhoAir) * ADSCorrectionFactor;
2692 0 : szAirRpt.MixSenLoad += refDoorMixingA.VolRefDoorFlowRate(j) * AirDensity * CpAir * (szHeatBal.MAT - szAMAT);
2693 0 : szAirRpt.MixLatLoad +=
2694 0 : refDoorMixingA.VolRefDoorFlowRate(j) * AirDensity * (szHeatBal.airHumRat - szAHumRat) * H2OHtOfVap;
2695 : } // volflowrate > 0
2696 : } // matezoneptr (zoneB) = Zonelooop
2697 : } // NumRefDoorConnections
2698 : } // Refdoormix flag on ZoneA
2699 : } // zone A from 1 to (zoneNum - 1)
2700 : } // Refdoormix flag on zoneNum
2701 : } //(TotRefDoorMixing .GT. 0)
2702 : // end refrigeration door mixing reports
2703 :
2704 : // MixingLoad(zoneNum) = MCPM(zoneNum)*MAT(zoneNum) - szAirRpt.MixSenLoad(zoneNum)
2705 37700 : if (szAirRpt.MixSenLoad > 0.0) {
2706 2881 : szAirRpt.MixHeatLoss = szAirRpt.MixSenLoad * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2707 2881 : szAirRpt.MixHeatGain = 0.0;
2708 : } else {
2709 34819 : szAirRpt.MixHeatLoss = 0.0;
2710 34819 : szAirRpt.MixHeatGain = -szAirRpt.MixSenLoad * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2711 : }
2712 : // Report mixing latent loads
2713 : // MixingLoad(zoneNum) = szAirRpt.MixLatLoad(zoneNum)
2714 37700 : if (szAirRpt.MixLatLoad > 0.0) {
2715 2881 : szAirRpt.MixLatentLoss = szAirRpt.MixLatLoad * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2716 2881 : szAirRpt.MixLatentGain = 0.0;
2717 : } else {
2718 34819 : szAirRpt.MixLatentLoss = 0.0;
2719 34819 : szAirRpt.MixLatentGain = -szAirRpt.MixLatLoad * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2720 : }
2721 : // Total Mixing losses and gains
2722 37700 : TotalLoad = szAirRpt.MixHeatGain + szAirRpt.MixLatentGain - szAirRpt.MixHeatLoss - szAirRpt.MixLatentLoss;
2723 37700 : if (TotalLoad > 0) {
2724 1 : szAirRpt.MixTotalGain = TotalLoad * ADSCorrectionFactor;
2725 1 : szAirRpt.MixTotalLoss = 0.0;
2726 : } else {
2727 37699 : szAirRpt.MixTotalGain = 0.0;
2728 37699 : szAirRpt.MixTotalLoss = -TotalLoad * ADSCorrectionFactor;
2729 : }
2730 :
2731 : // Reporting combined outdoor air flows
2732 37700 : for (int j = 1; j <= state.dataHeatBal->TotZoneAirBalance; ++j) {
2733 0 : if (state.dataHeatBal->ZoneAirBalance(j).BalanceMethod == DataHeatBalance::AirBalance::Quadrature &&
2734 0 : zoneNum == state.dataHeatBal->ZoneAirBalance(j).ZonePtr) {
2735 0 : if (szHeatBal.MAT > outDryBulb) {
2736 0 : szAirRpt.OABalanceHeatLoss =
2737 0 : szHeatBal.MDotCPOA * (szHeatBal.MAT - outDryBulb) * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2738 0 : szAirRpt.OABalanceHeatGain = 0.0;
2739 : } else {
2740 0 : szAirRpt.OABalanceHeatLoss = 0.0;
2741 0 : szAirRpt.OABalanceHeatGain =
2742 0 : -szHeatBal.MDotCPOA * (szHeatBal.MAT - outDryBulb) * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2743 : }
2744 0 : H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(state.dataEnvrn->OutHumRat, outDryBulb);
2745 0 : if (szHeatBal.airHumRat > state.dataEnvrn->OutHumRat) {
2746 0 : szAirRpt.OABalanceLatentLoss = szHeatBal.MDotOA * (szHeatBal.airHumRat - state.dataEnvrn->OutHumRat) * H2OHtOfVap *
2747 0 : state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2748 0 : szAirRpt.OABalanceLatentGain = 0.0;
2749 : } else {
2750 0 : szAirRpt.OABalanceLatentGain = szHeatBal.MDotOA * (state.dataEnvrn->OutHumRat - szHeatBal.airHumRat) * H2OHtOfVap *
2751 0 : state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2752 0 : szAirRpt.OABalanceLatentLoss = 0.0;
2753 : }
2754 : // Total ventilation losses and gains
2755 0 : TotalLoad = szAirRpt.OABalanceHeatGain + szAirRpt.OABalanceLatentGain - szAirRpt.OABalanceHeatLoss - szAirRpt.OABalanceLatentLoss;
2756 0 : if (TotalLoad > 0) {
2757 0 : szAirRpt.OABalanceTotalGain = TotalLoad * ADSCorrectionFactor;
2758 0 : szAirRpt.OABalanceTotalLoss = 0.0;
2759 : } else {
2760 0 : szAirRpt.OABalanceTotalGain = 0.0;
2761 0 : szAirRpt.OABalanceTotalLoss = -TotalLoad * ADSCorrectionFactor;
2762 : }
2763 0 : szAirRpt.OABalanceMass = (szHeatBal.MDotOA) * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2764 0 : szAirRpt.OABalanceMdot = (szHeatBal.MDotOA) * ADSCorrectionFactor;
2765 : Real64 const AirDensity =
2766 0 : Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, szHeatBal.MAT, szHeatBal.airHumRatAvg, std::string());
2767 0 : szAirRpt.OABalanceVolumeCurDensity = (szHeatBal.MDotOA / AirDensity) * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2768 0 : szAirRpt.OABalanceAirChangeRate = szAirRpt.OABalanceVolumeCurDensity / (state.dataHVACGlobal->TimeStepSys * szVolume);
2769 0 : szAirRpt.OABalanceVdotCurDensity = (szHeatBal.MDotOA / AirDensity) * ADSCorrectionFactor;
2770 0 : szAirRpt.OABalanceVolumeStdDensity =
2771 0 : (szHeatBal.MDotOA / state.dataEnvrn->StdRhoAir) * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2772 0 : szAirRpt.OABalanceVdotStdDensity = (szHeatBal.MDotOA / state.dataEnvrn->StdRhoAir) * ADSCorrectionFactor;
2773 0 : szAirRpt.OABalanceFanElec = szAirRpt.VentilFanElec;
2774 : }
2775 : }
2776 : // Reports exfiltration loss
2777 37700 : H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(state.dataEnvrn->OutHumRat, outDryBulb);
2778 37700 : szAirRpt.SysInletMass = 0;
2779 37700 : szAirRpt.SysOutletMass = 0;
2780 37700 : if (!szEquipConfig.IsControlled) {
2781 22642 : for (int k = 1; k <= szEquipConfig.NumInletNodes; ++k) {
2782 0 : szAirRpt.SysInletMass +=
2783 0 : state.dataLoopNodes->Node(szEquipConfig.InletNode(k)).MassFlowRate * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2784 : }
2785 22643 : for (int k = 1; k <= szEquipConfig.NumExhaustNodes; ++k) {
2786 1 : szAirRpt.SysOutletMass +=
2787 1 : state.dataLoopNodes->Node(szEquipConfig.ExhaustNode(k)).MassFlowRate * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2788 : }
2789 22642 : for (int k = 1; k <= szEquipConfig.NumReturnNodes; ++k) {
2790 0 : szAirRpt.SysOutletMass +=
2791 0 : state.dataLoopNodes->Node(szEquipConfig.ReturnNode(k)).MassFlowRate * state.dataHVACGlobal->TimeStepSysSec * ADSCorrectionFactor;
2792 : }
2793 : }
2794 :
2795 37700 : szAirRpt.ExfilMass =
2796 37700 : szAirRpt.InfilMass + szAirRpt.VentilMass + szAirRpt.MixMass + szAirRpt.OABalanceMass + szAirRpt.SysInletMass - szAirRpt.SysOutletMass; // kg
2797 : // I am not happy with these un-parenthesized divisions and multiplications. Someone clean this up.
2798 37700 : szAirRpt.ExfilSensiLoss = szAirRpt.ExfilMass / state.dataHVACGlobal->TimeStepSysSec * (szHeatBal.MAT - outDryBulb) * CpAir; // W
2799 37700 : szAirRpt.ExfilLatentLoss =
2800 37700 : szAirRpt.ExfilMass / state.dataHVACGlobal->TimeStepSysSec * (szHeatBal.airHumRat - state.dataEnvrn->OutHumRat) * H2OHtOfVap;
2801 37700 : szAirRpt.ExfilTotalLoss = szAirRpt.ExfilLatentLoss + szAirRpt.ExfilSensiLoss;
2802 :
2803 : // Accumulate only for zones
2804 37700 : if (spaceNum == 0) {
2805 31652 : state.dataHeatBal->ZoneTotalExfiltrationHeatLoss += szAirRpt.ExfilTotalLoss * state.dataHVACGlobal->TimeStepSysSec;
2806 31652 : state.dataHeatBal->ZoneTotalExhaustHeatLoss += szAirRpt.ExhTotalLoss * state.dataHVACGlobal->TimeStepSysSec;
2807 : }
2808 37700 : }
2809 :
2810 248593 : void SetHeatToReturnAirFlag(EnergyPlusData &state)
2811 : {
2812 :
2813 : // SUBROUTINE INFORMATION:
2814 : // AUTHOR Fred Buhl
2815 : // DATE WRITTEN February 2008
2816 :
2817 : // PURPOSE OF THIS SUBROUTINE:
2818 : // This sets some flags at the air loop and zone level: these flags indicate
2819 : // whether an air loop represents a "unitary" system, and whether the system is operating
2820 : // in a on/off (cycling fan) mode. At the zone level flags are set to indicate whether
2821 : // the zone is served by a zonal system only, and whether the air loop serving the zone (idf any)
2822 : // is in cycling fan mode. Using this information, the subroutine sets a flag at the zone level
2823 : // to tell ManageZoneAirUpdates (predict and correct) what to do with the heat to return air.
2824 :
2825 : // METHODOLOGY EMPLOYED:
2826 : // Uses program data structures AirLoopControlInfo and ZoneEquipInfo
2827 :
2828 248593 : if (!state.dataHVACGlobal->AirLoopsSimOnce) return;
2829 :
2830 165285 : int NumPrimaryAirSys = state.dataHVACGlobal->NumPrimaryAirSys;
2831 :
2832 165285 : if (state.dataHVACMgr->MyOneTimeFlag) {
2833 : // set the air loop Any Continuous Fan flag
2834 112 : for (int AirLoopNum = 1; AirLoopNum <= NumPrimaryAirSys; ++AirLoopNum) {
2835 24 : auto &airLoopControlInfo = state.dataAirLoop->AirLoopControlInfo(AirLoopNum);
2836 :
2837 24 : if (!airLoopControlInfo.UnitarySys) { // for nonunitary (central) all systems are continuous fan
2838 22 : airLoopControlInfo.AnyContFan = true;
2839 2 : } else if (airLoopControlInfo.cycFanSched != nullptr) { // for unitary systems check the cycling fan schedule
2840 2 : airLoopControlInfo.AnyContFan = (airLoopControlInfo.cycFanSched->getMaxVal(state) > 0.0);
2841 : } else { // no schedule means always cycling fan
2842 0 : airLoopControlInfo.AnyContFan = false;
2843 : }
2844 : }
2845 : // check to see if a controlled zone is served exclusively by a zonal system
2846 185 : for (int ControlledZoneNum = 1; ControlledZoneNum <= state.dataGlobal->NumOfZones; ++ControlledZoneNum) {
2847 97 : auto &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum);
2848 97 : bool airLoopFound = false;
2849 156 : for (int zoneInNode = 1; zoneInNode <= zoneEquipConfig.NumInletNodes; ++zoneInNode) {
2850 59 : if (zoneEquipConfig.InletNodeAirLoopNum(zoneInNode) > 0) {
2851 37 : airLoopFound = true;
2852 : }
2853 : }
2854 97 : if (!airLoopFound && zoneEquipConfig.NumInletNodes == zoneEquipConfig.NumExhaustNodes) {
2855 55 : zoneEquipConfig.ZonalSystemOnly = true;
2856 : }
2857 : }
2858 : // issue warning messages if zone is served by a zonal system or a cycling system and the input calls for
2859 : // heat gain to return air
2860 185 : for (int ControlledZoneNum = 1; ControlledZoneNum <= state.dataGlobal->NumOfZones; ++ControlledZoneNum) {
2861 97 : auto &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum);
2862 97 : if (!zoneEquipConfig.IsControlled) continue;
2863 56 : bool CyclingFan = false; // TRUE means air loop operates in cycling fan mode at some point
2864 115 : for (int zoneInNode = 1; zoneInNode <= zoneEquipConfig.NumInletNodes; ++zoneInNode) {
2865 59 : int AirLoopNum = zoneEquipConfig.InletNodeAirLoopNum(zoneInNode);
2866 59 : if (AirLoopNum > 0) {
2867 37 : if (state.dataAirLoop->AirLoopControlInfo(AirLoopNum).cycFanSched != nullptr) {
2868 2 : CyclingFan = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).cycFanSched->hasVal(state, 0.0);
2869 : }
2870 : }
2871 : }
2872 56 : if (zoneEquipConfig.ZonalSystemOnly || CyclingFan) {
2873 16 : auto const &thisZone = state.dataHeatBal->Zone(ControlledZoneNum);
2874 16 : if (thisZone.RefrigCaseRA) {
2875 0 : ShowWarningError(state,
2876 0 : format("For zone={} return air cooling by refrigerated cases will be applied to the zone air.", thisZone.Name));
2877 0 : ShowContinueError(state, " This zone has no return air or is served by an on/off HVAC system.");
2878 : }
2879 24 : for (int LightNum = 1; LightNum <= state.dataHeatBal->TotLights; ++LightNum) {
2880 10 : if (state.dataHeatBal->Lights(LightNum).ZonePtr != ControlledZoneNum) continue;
2881 5 : if (state.dataHeatBal->Lights(LightNum).FractionReturnAir > 0.0) {
2882 4 : ShowWarningError(state,
2883 4 : format("For zone={} return air heat gain from lights will be applied to the zone air.", thisZone.Name));
2884 4 : ShowContinueError(state, " This zone has no return air or is served by an on/off HVAC system.");
2885 2 : break;
2886 : }
2887 : }
2888 40 : for (int spaceNum : thisZone.spaceIndexes) {
2889 24 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
2890 120 : for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
2891 96 : if (state.dataSurface->SurfWinAirflowDestination(SurfNum) == DataSurfaces::WindowAirFlowDestination::Return) {
2892 0 : ShowWarningError(
2893 : state,
2894 0 : format("For zone={} return air heat gain from air flow windows will be applied to the zone air.", thisZone.Name));
2895 0 : ShowContinueError(state, " This zone has no return air or is served by an on/off HVAC system.");
2896 : }
2897 : }
2898 : }
2899 : }
2900 : }
2901 88 : state.dataHVACMgr->MyOneTimeFlag = false;
2902 : }
2903 :
2904 : // set the air loop fan operation mode
2905 192860 : for (int AirLoopNum = 1; AirLoopNum <= NumPrimaryAirSys; ++AirLoopNum) {
2906 27575 : auto &airLoopControlInfo = state.dataAirLoop->AirLoopControlInfo(AirLoopNum);
2907 27575 : if (airLoopControlInfo.cycFanSched != nullptr) {
2908 3027 : airLoopControlInfo.fanOp = (airLoopControlInfo.cycFanSched->getCurrentVal() == 0.0) ? HVAC::FanOp::Cycling : HVAC::FanOp::Continuous;
2909 : }
2910 : }
2911 : // set the zone level NoHeatToReturnAir flag
2912 : // if any air loop in the zone is continuous fan, then set NoHeatToReturnAir = false and sort it out node-by-node
2913 361823 : for (int ControlledZoneNum = 1; ControlledZoneNum <= state.dataGlobal->NumOfZones; ++ControlledZoneNum) {
2914 196538 : auto &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum);
2915 196538 : auto &thisZone = state.dataHeatBal->Zone(ControlledZoneNum);
2916 196538 : if (!zoneEquipConfig.IsControlled) continue;
2917 57655 : thisZone.NoHeatToReturnAir = true;
2918 57655 : if (!zoneEquipConfig.ZonalSystemOnly) {
2919 57556 : for (int zoneInNode = 1; zoneInNode <= zoneEquipConfig.NumInletNodes; ++zoneInNode) {
2920 54175 : int AirLoopNum = zoneEquipConfig.InletNodeAirLoopNum(zoneInNode);
2921 54175 : if (AirLoopNum > 0) {
2922 45073 : if (state.dataAirLoop->AirLoopControlInfo(AirLoopNum).fanOp == HVAC::FanOp::Continuous) {
2923 42046 : thisZone.NoHeatToReturnAir = false;
2924 42046 : break;
2925 : }
2926 : }
2927 : }
2928 : }
2929 : }
2930 : }
2931 :
2932 216324 : void UpdateZoneInletConvergenceLog(EnergyPlusData &state)
2933 : {
2934 :
2935 216324 : std::array<Real64, DataConvergParams::ConvergLogStackDepth> tmpRealARR = {};
2936 :
2937 488215 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
2938 :
2939 353993 : for (int NodeIndex = 1; NodeIndex <= state.dataConvergeParams->ZoneInletConvergence(ZoneNum).NumInletNodes; ++NodeIndex) {
2940 82102 : int NodeNum = state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).NodeNum;
2941 :
2942 82102 : tmpRealARR = state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).HumidityRatio;
2943 82102 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).HumidityRatio[0] = state.dataLoopNodes->Node(NodeNum).HumRat;
2944 821020 : for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
2945 738918 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).HumidityRatio[logIndex] = tmpRealARR[logIndex - 1];
2946 : }
2947 :
2948 82102 : tmpRealARR = state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).MassFlowRate;
2949 82102 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).MassFlowRate[0] =
2950 82102 : state.dataLoopNodes->Node(NodeNum).MassFlowRate;
2951 821020 : for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
2952 738918 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).MassFlowRate[logIndex] = tmpRealARR[logIndex - 1];
2953 : }
2954 :
2955 82102 : tmpRealARR = state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).Temperature;
2956 82102 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).Temperature[0] = state.dataLoopNodes->Node(NodeNum).Temp;
2957 821020 : for (int logIndex = 1; logIndex < DataConvergParams::ConvergLogStackDepth; logIndex++) {
2958 738918 : state.dataConvergeParams->ZoneInletConvergence(ZoneNum).InletNode(NodeIndex).Temperature[logIndex] = tmpRealARR[logIndex - 1];
2959 : }
2960 : }
2961 : }
2962 216324 : }
2963 :
2964 208456 : void CheckAirLoopFlowBalance(EnergyPlusData &state)
2965 : {
2966 : // Check for unbalanced airloop
2967 208456 : if (!state.dataGlobal->WarmupFlag && state.dataHVACGlobal->AirLoopsSimOnce) {
2968 26117 : for (int AirLoopNum = 1; AirLoopNum <= state.dataHVACGlobal->NumPrimaryAirSys; ++AirLoopNum) {
2969 4993 : auto &thisAirLoopFlow = state.dataAirLoop->AirLoopFlow(AirLoopNum);
2970 4993 : if (!thisAirLoopFlow.FlowError) {
2971 4992 : Real64 unbalancedExhaustDelta = thisAirLoopFlow.SupFlow - thisAirLoopFlow.OAFlow - thisAirLoopFlow.SysRetFlow;
2972 4992 : if (unbalancedExhaustDelta > HVAC::SmallMassFlow) {
2973 4 : ShowSevereError(state,
2974 4 : format("CheckAirLoopFlowBalance: AirLoopHVAC {} is unbalanced. Supply is > return plus outdoor air.",
2975 2 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNum).Name));
2976 4 : ShowContinueErrorTimeStamp(state, "");
2977 4 : ShowContinueError(state,
2978 4 : format(" Flows [m3/s at standard density]: Supply={:.6R} Return={:.6R} Outdoor Air={:.6R}",
2979 2 : thisAirLoopFlow.SupFlow / state.dataEnvrn->StdRhoAir,
2980 2 : thisAirLoopFlow.SysRetFlow / state.dataEnvrn->StdRhoAir,
2981 2 : thisAirLoopFlow.OAFlow / state.dataEnvrn->StdRhoAir));
2982 2 : ShowContinueError(state, format(" Imbalance={:.6R}", unbalancedExhaustDelta / state.dataEnvrn->StdRhoAir));
2983 4 : ShowContinueError(state, " This error will only be reported once per system.");
2984 2 : thisAirLoopFlow.FlowError = true;
2985 : }
2986 : }
2987 : }
2988 : }
2989 208456 : }
2990 :
2991 6 : void ConvergenceErrors(EnergyPlusData &state,
2992 : std::array<bool, 3> &HVACNotConverged,
2993 : std::array<Real64, 10> &DemandToSupply,
2994 : std::array<Real64, 10> &SupplyDeck1ToDemand,
2995 : std::array<Real64, 10> &SupplyDeck2ToDemand,
2996 : int const AirSysNum,
2997 : ConvErrorCallType const callType)
2998 : {
2999 :
3000 6 : std::string_view const CaseName = ConvErrorCallString[(int)callType];
3001 :
3002 6 : auto &arrayRef = HVACNotConverged;
3003 18 : if (std::any_of(std::begin(arrayRef), std::end(arrayRef), [](bool i) { return i; })) {
3004 :
3005 12 : ShowContinueError(
3006 12 : state, format("Air System Named = {} did not converge for {}", state.dataAirLoop->AirToZoneNodeInfo(AirSysNum).AirLoopName, CaseName));
3007 12 : ShowContinueError(state, "Check values should be zero. Most Recent values listed first.");
3008 6 : std::string HistoryTrace;
3009 66 : for (int StackDepth = 0; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
3010 60 : HistoryTrace += format("{:.6R},", DemandToSupply[StackDepth]);
3011 : }
3012 6 : ShowContinueError(state, format("Demand-to-Supply interface {} check value iteration history trace: {}", CaseName, HistoryTrace));
3013 6 : HistoryTrace = "";
3014 66 : for (int StackDepth = 0; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
3015 60 : HistoryTrace += format("{:.6R},", SupplyDeck1ToDemand[StackDepth]);
3016 : }
3017 6 : ShowContinueError(state, format("Supply-to-demand interface deck 1 {} check value iteration history trace: {}", CaseName, HistoryTrace));
3018 :
3019 6 : if (state.dataAirLoop->AirToZoneNodeInfo(AirSysNum).NumSupplyNodes >= 2) {
3020 1 : HistoryTrace = "";
3021 11 : for (int StackDepth = 0; StackDepth < DataConvergParams::ConvergLogStackDepth; ++StackDepth) {
3022 10 : HistoryTrace += format("{:.6R},", SupplyDeck2ToDemand[StackDepth]);
3023 : }
3024 1 : ShowContinueError(state, format("Supply-to-demand interface deck 2 {} check value iteration history trace: {}", CaseName, HistoryTrace));
3025 : }
3026 6 : } // energy not converged
3027 6 : }
3028 : } // namespace EnergyPlus::HVACManager
|