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