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