Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 : #include <numeric>
51 : #include <string>
52 :
53 : // ObjexxFCL Headers
54 : #include <ObjexxFCL/Array.functions.hh>
55 :
56 : // EnergyPlus Headers
57 : #include <AirflowNetwork/Elements.hpp>
58 : #include <AirflowNetwork/Solver.hpp>
59 : #include <EnergyPlus/Construction.hh>
60 : #include <EnergyPlus/Data/EnergyPlusData.hh>
61 : #include <EnergyPlus/DataDefineEquip.hh>
62 : #include <EnergyPlus/DataEnvironment.hh>
63 : #include <EnergyPlus/DataHVACGlobals.hh>
64 : #include <EnergyPlus/DataHeatBalFanSys.hh>
65 : #include <EnergyPlus/DataHeatBalSurface.hh>
66 : #include <EnergyPlus/DataHeatBalance.hh>
67 : #include <EnergyPlus/DataIPShortCuts.hh>
68 : #include <EnergyPlus/DataLoopNode.hh>
69 : #include <EnergyPlus/DataPrecisionGlobals.hh>
70 : #include <EnergyPlus/DataRoomAirModel.hh>
71 : #include <EnergyPlus/DataSizing.hh>
72 : #include <EnergyPlus/DataStringGlobals.hh>
73 : #include <EnergyPlus/DataSurfaces.hh>
74 : #include <EnergyPlus/DataZoneControls.hh>
75 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
76 : #include <EnergyPlus/DataZoneEquipment.hh>
77 : #include <EnergyPlus/FaultsManager.hh>
78 : #include <EnergyPlus/FileSystem.hh>
79 : #include <EnergyPlus/General.hh>
80 : #include <EnergyPlus/GeneralRoutines.hh>
81 : #include <EnergyPlus/GlobalNames.hh>
82 : #include <EnergyPlus/HeatBalFiniteDiffManager.hh>
83 : #include <EnergyPlus/HeatBalanceSurfaceManager.hh>
84 : #include <EnergyPlus/HybridModel.hh>
85 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
86 : #include <EnergyPlus/InternalHeatGains.hh>
87 : #include <EnergyPlus/OutputProcessor.hh>
88 : #include <EnergyPlus/OutputReportPredefined.hh>
89 : #include <EnergyPlus/OutputReportTabular.hh>
90 : #include <EnergyPlus/Psychrometrics.hh>
91 : #include <EnergyPlus/RoomAirModelAirflowNetwork.hh>
92 : #include <EnergyPlus/RoomAirModelManager.hh>
93 : #include <EnergyPlus/ScheduleManager.hh>
94 : #include <EnergyPlus/ThermalComfort.hh>
95 : #include <EnergyPlus/UtilityRoutines.hh>
96 : #include <EnergyPlus/WeatherManager.hh>
97 : #include <EnergyPlus/ZonePlenum.hh>
98 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
99 :
100 : namespace EnergyPlus::ZoneTempPredictorCorrector {
101 :
102 : // MODULE INFORMATION:
103 : // AUTHOR Russell D. Taylor
104 : // DATE WRITTEN 1997
105 : // MODIFIED Aug 2001(FW): make SNLoadHeatRate public
106 : // Nov 2010 BN(FSEC) added TemperatureAndHumidity Control
107 : // RE-ENGINEERED July 2003 (Peter Graham Ellis)
108 : // July 2006 (BG) added operative temp control
109 : // February 2008 (BG) reworked zone air temp histories
110 :
111 : // PURPOSE OF THIS MODULE:
112 : // This module contains routines to predict and correct zone temperatures.
113 : // also includes zone thermostatic controlling
114 : // Model the "Air Heat Balance" part of the the "Zone Heat Balance Method."
115 :
116 : // METHODOLOGY EMPLOYED:
117 : // apply model equations for air heat balance solved for zone air temp.
118 : // sum up values for the terms (e.g SUMHAT, SUMHA etc. )
119 : // "Predict" step is used to get zone loads for HVAC equipment
120 : // "correct" step determines zone air temp with available HVAC
121 :
122 : enum class ZoneControlTypes
123 : {
124 : Invalid = -1,
125 : TStat = 1,
126 : TCTStat = 2,
127 : OTTStat = 3,
128 : HStat = 4,
129 : TandHStat = 5,
130 : StagedDual = 6,
131 : Num
132 : };
133 :
134 : enum class AdaptiveComfortModel
135 : {
136 : Invalid = -1,
137 : ADAP_NONE = 1,
138 : ASH55_CENTRAL = 2,
139 : ASH55_UPPER_90 = 3,
140 : ASH55_UPPER_80 = 4,
141 : CEN15251_CENTRAL = 5,
142 : CEN15251_UPPER_I = 6,
143 : CEN15251_UPPER_II = 7,
144 : CEN15251_UPPER_III = 8,
145 : Num
146 : };
147 :
148 : static constexpr std::array<std::string_view, (int)HVAC::SetptType::Num> setptTypeNames = {"Uncontrolled",
149 : "ThermostatSetpoint:SingleHeating",
150 : "ThermostatSetpoint:SingleCooling",
151 : "ThermostatSetpoint:SingleHeatingOrCooling",
152 : "ThermostatSetpoint:DualSetpoint"};
153 :
154 : static constexpr std::array<std::string_view, (int)HVAC::SetptType::Num> setptTypeNamesUC = {"UNCONTROLLED",
155 : "THERMOSTATSETPOINT:SINGLEHEATING",
156 : "THERMOSTATSETPOINT:SINGLECOOLING",
157 : "THERMOSTATSETPOINT:SINGLEHEATINGORCOOLING",
158 : "THERMOSTATSETPOINT:DUALSETPOINT"};
159 :
160 : static constexpr std::array<std::string_view, (int)HVAC::SetptType::Num> comfortSetptTypeNames = {
161 : "Uncontrolled",
162 : "ThermostatSetpoint:ThermalComfort:Fanger:SingleHeating",
163 : "ThermostatSetpoint:ThermalComfort:Fanger:SingleCooling",
164 : "ThermostatSetpoint:ThermalComfort:Fanger:SingleHeatingOrCooling",
165 : "ThermostatSetpoint:ThermalComfort:Fanger:DualSetpoint"};
166 :
167 : static constexpr std::array<std::string_view, (int)HVAC::SetptType::Num> comfortSetptTypeNamesUC = {
168 : "UNCONTROLLED",
169 : "THERMOSTATSETPOINT:THERMALCOMFORT:FANGER:SINGLEHEATING",
170 : "THERMOSTATSETPOINT:THERMALCOMFORT:FANGER:SINGLECOOLING",
171 : "THERMOSTATSETPOINT:THERMALCOMFORT:FANGER:SINGLEHEATINGORCOOLING",
172 : "THERMOSTATSETPOINT:THERMALCOMFORT:FANGER:DUALSETPOINT"};
173 :
174 : Array1D_string const cZControlTypes(6,
175 : {"ZoneControl:Thermostat",
176 : "ZoneControl:Thermostat:ThermalComfort",
177 : "ZoneControl:Thermostat:OperativeTemperature",
178 : "ZoneControl:Humidistat",
179 : "ZoneControl:Thermostat:TemperatureAndHumidity",
180 : "ZoneControl:Thermostat:StagedDualSetpoint"});
181 :
182 : Array1D_string const AdaptiveComfortModelTypes(8,
183 : {"None",
184 : "AdaptiveASH55CentralLine",
185 : "AdaptiveASH5590PercentUpperLine",
186 : "AdaptiveASH5580PercentUpperLine",
187 : "AdaptiveCEN15251CentralLine",
188 : "AdaptiveCEN15251CategoryIUpperLine",
189 : "AdaptiveCEN15251CategoryIIUpperLine",
190 : "AdaptiveCEN15251CategoryIIIUpperLine"});
191 :
192 : // Functions
193 14518428 : void ManageZoneAirUpdates(EnergyPlusData &state,
194 : DataHeatBalFanSys::PredictorCorrectorCtrl const UpdateType, // Can be iGetZoneSetPoints, iPredictStep, iCorrectStep
195 : Real64 &ZoneTempChange, // Temp change in zone air btw previous and current timestep
196 : bool const ShortenTimeStepSys,
197 : bool const UseZoneTimeStepHistory, // if true then use zone timestep history, if false use system time step
198 : Real64 const PriorTimeStep // the old value for timestep length is passed for possible use in interpolating
199 : )
200 : {
201 :
202 : // SUBROUTINE INFORMATION
203 : // AUTHOR Russ Taylor
204 : // DATE WRITTEN September 1998
205 : // MODIFIED na
206 : // RE-ENGINEERED Brent Griffith Feb. 2008, added arguments
207 :
208 : // PURPOSE OF THIS SUBROUTINE:
209 : // This subroutine predicts or corrects the zone air temperature
210 : // depending on the simulation status and determines the correct
211 : // temperature setpoint for each zone from the schedule manager.
212 :
213 14518428 : if (state.dataZoneCtrls->GetZoneAirStatsInputFlag) {
214 791 : GetZoneAirSetPoints(state);
215 791 : state.dataZoneCtrls->GetZoneAirStatsInputFlag = false;
216 : }
217 :
218 14518428 : InitZoneAirSetPoints(state);
219 :
220 14518428 : switch (UpdateType) {
221 2828450 : case DataHeatBalFanSys::PredictorCorrectorCtrl::GetZoneSetPoints: {
222 2828450 : CalcZoneAirTempSetPoints(state);
223 2828450 : } break;
224 3896818 : case DataHeatBalFanSys::PredictorCorrectorCtrl::PredictStep: {
225 3896818 : PredictSystemLoads(state, ShortenTimeStepSys, UseZoneTimeStepHistory, PriorTimeStep);
226 3896818 : } break;
227 3896580 : case DataHeatBalFanSys::PredictorCorrectorCtrl::CorrectStep: {
228 3896580 : ZoneTempChange = correctZoneAirTemps(state, UseZoneTimeStepHistory);
229 3896580 : } break;
230 0 : case DataHeatBalFanSys::PredictorCorrectorCtrl::RevertZoneTimestepHistories: {
231 0 : RevertZoneTimestepHistories(state);
232 0 : } break;
233 2828212 : case DataHeatBalFanSys::PredictorCorrectorCtrl::PushZoneTimestepHistories: {
234 2828212 : PushZoneTimestepHistories(state);
235 2828212 : } break;
236 1068368 : case DataHeatBalFanSys::PredictorCorrectorCtrl::PushSystemTimestepHistories: {
237 1068368 : PushSystemTimestepHistories(state);
238 1068368 : } break;
239 0 : default:
240 0 : break;
241 : }
242 14518428 : }
243 :
244 801 : void GetZoneAirSetPoints(EnergyPlusData &state)
245 : {
246 :
247 : // SUBROUTINE INFORMATION:
248 : // AUTHOR Russell Taylor
249 : // DATE WRITTEN September 1998
250 : // MODIFIED L.Gu, May 2006, B. Griffith June 2006
251 : // RE-ENGINEERED na
252 :
253 : // PURPOSE OF THIS SUBROUTINE:
254 : // This subroutine gets the inputs related to thermostatic control.
255 :
256 : // METHODOLOGY EMPLOYED:
257 : // Uses the status flags to trigger events.
258 :
259 : // Using/Aliasing
260 : using General::CheckCreatedZoneItemName;
261 : using General::FindNumberInList;
262 :
263 : // SUBROUTINE PARAMETER DEFINITIONS:
264 : static constexpr std::string_view RoutineName("GetZoneAirSetpoints: ");
265 : static constexpr std::string_view routineName = "GetZoneAirSetpoints";
266 :
267 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
268 : int TempControlledZoneNum; // The Splitter that you are currently loading input into
269 : int NumAlphas;
270 : int NumNums;
271 : int IOStat;
272 801 : bool ErrorsFound(false);
273 : bool errFlag;
274 : int HumidControlledZoneNum; // The Humidity Controller that information is being loaded into
275 : int ActualZoneNum;
276 :
277 : int ComfortControlledZoneNum; // The Splitter that you are currently loading input into
278 : int i;
279 : int found;
280 : int NumStageControlledZones; // Number of staged controlled objects
281 :
282 801 : Array1D_int CTSchedMapToControlledZone;
283 801 : Array1D_int CCmSchedMapToControlledZone;
284 : int Item;
285 : int Item1;
286 : int ZLItem;
287 :
288 : struct NeededControlTypes
289 : {
290 : // Members 4= the four control types + uncontrolled
291 : std::array<bool, static_cast<int>(HVAC::SetptType::Num)> MustHave = {false, false, false, false, false};
292 : std::array<bool, static_cast<int>(HVAC::SetptType::Num)> DidHave = {false, false, false, false, false};
293 : };
294 :
295 : struct NeededComfortControlTypes
296 : {
297 : // Members 4= the four control types + uncontrolled
298 : std::array<bool, static_cast<int>(HVAC::SetptType::Num)> MustHave = {false, false, false, false, false};
299 : std::array<bool, static_cast<int>(HVAC::SetptType::Num)> DidHave = {false, false, false, false, false};
300 : };
301 :
302 : // Object Data
303 801 : Array1D<NeededControlTypes> TStatControlTypes;
304 801 : Array1D<NeededComfortControlTypes> TComfortControlTypes;
305 :
306 : // Formats
307 : static constexpr std::string_view Header(
308 : "! <Zone Volume Capacitance Multiplier>, Sensible Heat Capacity Multiplier, Moisture Capacity Multiplier, Carbon "
309 : "Dioxide Capacity Multiplier, Generic Contaminant Capacity Multiplier\n");
310 : static constexpr std::string_view Format_701("Zone Volume Capacitance Multiplier,{:8.3F} ,{:8.3F},{:8.3F},{:8.3F}\n");
311 :
312 801 : auto &s_ipsc = state.dataIPShortCut;
313 801 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
314 :
315 801 : auto &TStatObjects = state.dataZoneCtrls->TStatObjects;
316 801 : auto &Zone = state.dataHeatBal->Zone;
317 801 : auto &ZoneList = state.dataHeatBal->ZoneList;
318 801 : auto &ComfortTStatObjects = state.dataZoneCtrls->ComfortTStatObjects;
319 801 : int NumOfZones = state.dataGlobal->NumOfZones;
320 801 : auto &s_ip = state.dataInputProcessing->inputProcessor;
321 :
322 801 : s_ipsc->cCurrentModuleObject = cZControlTypes(static_cast<int>(ZoneControlTypes::TStat));
323 : // Update Num in state and make local convenience copy
324 801 : int NumTStatStatements = state.dataZoneCtrls->NumTStatStatements = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
325 801 : TStatObjects.allocate(NumTStatStatements);
326 :
327 : // Pre-scan for use of Zone lists in TStat statements (i.e. Global application of TStat)
328 801 : state.dataZoneCtrls->NumTempControlledZones = 0;
329 5100 : for (Item = 1; Item <= NumTStatStatements; ++Item) {
330 8598 : s_ip->getObjectItem(state,
331 4299 : s_ipsc->cCurrentModuleObject,
332 : Item,
333 4299 : s_ipsc->cAlphaArgs,
334 : NumAlphas,
335 4299 : s_ipsc->rNumericArgs,
336 : NumNums,
337 : IOStat,
338 4299 : s_ipsc->lNumericFieldBlanks,
339 4299 : s_ipsc->lAlphaFieldBlanks,
340 4299 : s_ipsc->cAlphaFieldNames,
341 4299 : s_ipsc->cNumericFieldNames);
342 :
343 4299 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
344 4299 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
345 :
346 4299 : TStatObjects(Item).Name = s_ipsc->cAlphaArgs(1);
347 4299 : Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(2), Zone);
348 4299 : ZLItem = 0;
349 4299 : if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) {
350 9 : ZLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(2), ZoneList);
351 : }
352 4299 : if (Item1 > 0) {
353 4290 : TStatObjects(Item).TempControlledZoneStartPtr = state.dataZoneCtrls->NumTempControlledZones + 1;
354 4290 : ++state.dataZoneCtrls->NumTempControlledZones;
355 4290 : TStatObjects(Item).NumOfZones = 1;
356 4290 : TStatObjects(Item).ZoneListActive = false;
357 4290 : TStatObjects(Item).ZoneOrZoneListPtr = Item1;
358 9 : } else if (ZLItem > 0) {
359 9 : auto const &ZoneList = state.dataHeatBal->ZoneList(ZLItem);
360 9 : TStatObjects(Item).TempControlledZoneStartPtr = state.dataZoneCtrls->NumTempControlledZones + 1;
361 9 : state.dataZoneCtrls->NumTempControlledZones += ZoneList.NumOfZones;
362 9 : TStatObjects(Item).NumOfZones = ZoneList.NumOfZones;
363 9 : TStatObjects(Item).ZoneListActive = true;
364 9 : TStatObjects(Item).ZoneOrZoneListPtr = ZLItem;
365 : } else {
366 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
367 0 : ErrorsFound = true;
368 : }
369 : }
370 :
371 801 : if (ErrorsFound) {
372 0 : ShowSevereError(state, format("GetZoneAirSetpoints: Errors with invalid names in {} objects.", s_ipsc->cCurrentModuleObject));
373 0 : ShowContinueError(state, "...These will not be read in. Other errors may occur.");
374 0 : state.dataZoneCtrls->NumTempControlledZones = 0;
375 : }
376 :
377 801 : if (state.dataZoneCtrls->NumTempControlledZones > 0) {
378 690 : state.dataZoneCtrls->TempControlledZone.allocate(state.dataZoneCtrls->NumTempControlledZones);
379 690 : TStatControlTypes.allocate(state.dataZoneCtrls->NumTempControlledZones); // Number of set point types
380 690 : CTSchedMapToControlledZone.dimension(state.dataZoneCtrls->NumTempControlledZones, 0);
381 :
382 690 : TempControlledZoneNum = 0;
383 690 : s_ztpc->NumOnOffCtrZone = 0;
384 4989 : for (Item = 1; Item <= NumTStatStatements; ++Item) {
385 8598 : s_ip->getObjectItem(state,
386 4299 : s_ipsc->cCurrentModuleObject,
387 : Item,
388 4299 : s_ipsc->cAlphaArgs,
389 : NumAlphas,
390 4299 : s_ipsc->rNumericArgs,
391 : NumNums,
392 : IOStat,
393 4299 : s_ipsc->lNumericFieldBlanks,
394 4299 : s_ipsc->lAlphaFieldBlanks,
395 4299 : s_ipsc->cAlphaFieldNames,
396 4299 : s_ipsc->cNumericFieldNames);
397 :
398 4299 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
399 :
400 8632 : for (Item1 = 1; Item1 <= TStatObjects(Item).NumOfZones; ++Item1) {
401 4333 : ++TempControlledZoneNum;
402 4333 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum);
403 :
404 4333 : if (TStatObjects(Item).ZoneListActive) {
405 43 : s_ipsc->cAlphaArgs(2) = Zone(ZoneList(TStatObjects(Item).ZoneOrZoneListPtr).Zone(Item1)).Name;
406 : }
407 4333 : int ZoneAssigned = Util::FindItemInList(s_ipsc->cAlphaArgs(2),
408 4333 : state.dataZoneCtrls->TempControlledZone,
409 : &DataZoneControls::ZoneTempControls::ZoneName,
410 : TempControlledZoneNum - 1);
411 4333 : if (ZoneAssigned == 0) {
412 4333 : tempZone.ZoneName = s_ipsc->cAlphaArgs(2);
413 4333 : tempZone.ActualZoneNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), Zone);
414 4333 : if (tempZone.ActualZoneNum == 0) {
415 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
416 0 : ErrorsFound = true;
417 : } else {
418 4333 : Zone(tempZone.ActualZoneNum).TempControlledZoneIndex = TempControlledZoneNum;
419 : }
420 : } else {
421 0 : tempZone.ZoneName = s_ipsc->cAlphaArgs(2); // for continuity
422 0 : ShowSevereDuplicateAssignment(
423 0 : state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), state.dataZoneCtrls->TempControlledZone(ZoneAssigned).Name);
424 0 : ErrorsFound = true;
425 0 : continue;
426 : }
427 :
428 4333 : if (!TStatObjects(Item).ZoneListActive) {
429 4290 : tempZone.Name = s_ipsc->cAlphaArgs(1);
430 : } else {
431 43 : auto &ZoneList = state.dataHeatBal->ZoneList(TStatObjects(Item).ZoneOrZoneListPtr);
432 129 : CheckCreatedZoneItemName(state,
433 : RoutineName,
434 43 : s_ipsc->cCurrentModuleObject,
435 43 : Zone(ZoneList.Zone(Item1)).Name,
436 : ZoneList.MaxZoneNameLength,
437 43 : TStatObjects(Item).Name,
438 43 : state.dataZoneCtrls->TempControlledZone,
439 : TempControlledZoneNum - 1,
440 43 : tempZone.Name,
441 : errFlag);
442 43 : if (errFlag) {
443 0 : ErrorsFound = true;
444 : }
445 : }
446 :
447 4333 : tempZone.setptTypeSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3));
448 4333 : if (Item1 == 1) { // only show error on first of several if zone list
449 4299 : if (tempZone.setptTypeSched == nullptr) {
450 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
451 0 : ErrorsFound = true;
452 4299 : } else if (!tempZone.setptTypeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 4.0)) {
453 0 : Sched::ShowSevereBadMinMax(
454 0 : state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), Clusive::In, 0.0, Clusive::In, 4.0);
455 0 : ErrorsFound = true;
456 : }
457 : }
458 :
459 4333 : if (s_ipsc->lAlphaFieldBlanks(7)) {
460 3192 : NumAlphas = 5;
461 1141 : } else if (s_ipsc->lAlphaFieldBlanks(9)) {
462 474 : NumAlphas = 7;
463 667 : } else if (s_ipsc->lAlphaFieldBlanks(11)) {
464 667 : NumAlphas = 9;
465 : }
466 :
467 4333 : int NumSetptTypes = nint((NumAlphas - 3.0) / 2.0);
468 :
469 10474 : for (int iSetpt = 1; iSetpt <= NumSetptTypes; ++iSetpt) {
470 :
471 6141 : HVAC::SetptType setptType = HVAC::SetptType::Invalid;
472 6141 : int spIdx = 2 * iSetpt - 1 + 3;
473 :
474 6141 : if (s_ipsc->lAlphaFieldBlanks(spIdx)) {
475 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(spIdx));
476 0 : ErrorsFound = true;
477 0 : continue;
478 6141 : } else if ((setptType = static_cast<HVAC::SetptType>(getEnumValue(setptTypeNamesUC, s_ipsc->cAlphaArgs(spIdx)))) ==
479 : HVAC::SetptType::Invalid) {
480 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(spIdx), s_ipsc->cAlphaArgs(spIdx));
481 0 : ErrorsFound = true;
482 0 : continue;
483 : }
484 :
485 6141 : tempZone.setpts[(int)setptType].Name = s_ipsc->cAlphaArgs(2 * iSetpt + 3);
486 6141 : tempZone.setpts[(int)setptType].isUsed = true;
487 : }
488 :
489 4333 : if (NumNums > 0) {
490 11 : if (s_ipsc->rNumericArgs(1) >= 0.0) {
491 11 : tempZone.DeltaTCutSet = s_ipsc->rNumericArgs(1);
492 11 : if (s_ipsc->rNumericArgs(1) > 0.0) {
493 7 : s_ztpc->NumOnOffCtrZone++;
494 : }
495 : } else {
496 0 : ShowSevereError(state,
497 0 : format("{}=\"{} invalid {}=[{:.0T}].",
498 0 : s_ipsc->cCurrentModuleObject,
499 0 : s_ipsc->cAlphaArgs(1),
500 0 : s_ipsc->cNumericFieldNames(1),
501 0 : s_ipsc->rNumericArgs(1)));
502 0 : ShowContinueError(state, "..Allowable values must be greater or equal to 0");
503 0 : ErrorsFound = true;
504 : }
505 : }
506 :
507 4333 : if (tempZone.DeltaTCutSet > 0.0 && tempZone.setpts[(int)HVAC::SetptType::SingleHeatCool].Name != "") {
508 0 : ShowWarningError(state,
509 0 : format("{}=\"{}: The choice of Temperature Difference Between Cutout And Setpoint will not be applied "
510 : "to ThermostatSetpoint:SingleHeatingOrCooling.",
511 0 : s_ipsc->cCurrentModuleObject,
512 0 : s_ipsc->cAlphaArgs(1)));
513 : }
514 : }
515 : } // NumTStatStatements
516 : } // Check on number of TempControlledZones
517 :
518 801 : s_ipsc->cCurrentModuleObject = setptTypeNamesUC[(int)HVAC::SetptType::SingleHeat];
519 801 : s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeat] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
520 :
521 801 : if (s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeat] > 0) {
522 326 : s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleHeat].allocate(s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeat]);
523 : }
524 :
525 1255 : for (int idx = 1; idx <= s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeat]; ++idx) {
526 908 : s_ip->getObjectItem(state,
527 454 : s_ipsc->cCurrentModuleObject,
528 : idx,
529 454 : s_ipsc->cAlphaArgs,
530 : NumAlphas,
531 454 : s_ipsc->rNumericArgs,
532 : NumNums,
533 : IOStat,
534 454 : s_ipsc->lNumericFieldBlanks,
535 454 : s_ipsc->lAlphaFieldBlanks,
536 454 : s_ipsc->cAlphaFieldNames,
537 454 : s_ipsc->cNumericFieldNames);
538 :
539 454 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
540 :
541 454 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
542 454 : auto &setpt = s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleHeat](idx);
543 454 : setpt.Name = s_ipsc->cAlphaArgs(1);
544 :
545 454 : if (s_ipsc->lAlphaFieldBlanks(2)) {
546 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
547 0 : ErrorsFound = true;
548 454 : } else if ((setpt.heatSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
549 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
550 0 : ErrorsFound = true;
551 : }
552 :
553 : } // SingleTempHeatingControlNum
554 :
555 801 : s_ipsc->cCurrentModuleObject = setptTypeNamesUC[(int)HVAC::SetptType::SingleCool];
556 801 : s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleCool] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
557 :
558 801 : if (s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleCool] > 0) {
559 320 : s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleCool].allocate(s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleCool]);
560 : }
561 :
562 1249 : for (int idx = 1; idx <= s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleCool]; ++idx) {
563 896 : s_ip->getObjectItem(state,
564 448 : s_ipsc->cCurrentModuleObject,
565 : idx,
566 448 : s_ipsc->cAlphaArgs,
567 : NumAlphas,
568 448 : s_ipsc->rNumericArgs,
569 : NumNums,
570 : IOStat,
571 448 : s_ipsc->lNumericFieldBlanks,
572 448 : s_ipsc->lAlphaFieldBlanks,
573 448 : s_ipsc->cAlphaFieldNames,
574 448 : s_ipsc->cNumericFieldNames);
575 :
576 448 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
577 :
578 448 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
579 448 : auto &setpt = s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleCool](idx);
580 448 : setpt.Name = s_ipsc->cAlphaArgs(1);
581 :
582 448 : if (s_ipsc->lAlphaFieldBlanks(2)) {
583 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
584 0 : ErrorsFound = true;
585 448 : } else if ((setpt.coolSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
586 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
587 0 : ErrorsFound = true;
588 : }
589 :
590 : } // SingleTempCoolingControlNum
591 :
592 801 : s_ipsc->cCurrentModuleObject = setptTypeNames[(int)HVAC::SetptType::SingleHeatCool];
593 801 : s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeatCool] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
594 :
595 801 : if (s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeatCool] > 0) {
596 11 : s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleHeatCool].allocate(s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeatCool]);
597 : }
598 :
599 812 : for (int idx = 1; idx <= s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeatCool]; ++idx) {
600 22 : s_ip->getObjectItem(state,
601 11 : s_ipsc->cCurrentModuleObject,
602 : idx,
603 11 : s_ipsc->cAlphaArgs,
604 : NumAlphas,
605 11 : s_ipsc->rNumericArgs,
606 : NumNums,
607 : IOStat,
608 11 : s_ipsc->lNumericFieldBlanks,
609 11 : s_ipsc->lAlphaFieldBlanks,
610 11 : s_ipsc->cAlphaFieldNames,
611 11 : s_ipsc->cNumericFieldNames);
612 :
613 11 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
614 :
615 11 : auto &setpt = s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleHeatCool](idx);
616 11 : setpt.Name = s_ipsc->cAlphaArgs(1);
617 :
618 11 : if (s_ipsc->lAlphaFieldBlanks(2)) {
619 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
620 0 : ErrorsFound = true;
621 11 : } else if ((setpt.heatSched = setpt.coolSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
622 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
623 0 : ErrorsFound = true;
624 : }
625 :
626 : } // SingleTempHeatCoolControlNum
627 :
628 801 : s_ipsc->cCurrentModuleObject = setptTypeNames[(int)HVAC::SetptType::DualHeatCool];
629 801 : s_ztpc->NumTempControls[(int)HVAC::SetptType::DualHeatCool] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
630 :
631 801 : if (s_ztpc->NumTempControls[(int)HVAC::SetptType::DualHeatCool] > 0) {
632 499 : s_ztpc->tempSetptScheds[(int)HVAC::SetptType::DualHeatCool].allocate(s_ztpc->NumTempControls[(int)HVAC::SetptType::DualHeatCool]);
633 : }
634 :
635 3402 : for (int idx = 1; idx <= s_ztpc->NumTempControls[(int)HVAC::SetptType::DualHeatCool]; ++idx) {
636 5202 : s_ip->getObjectItem(state,
637 2601 : s_ipsc->cCurrentModuleObject,
638 : idx,
639 2601 : s_ipsc->cAlphaArgs,
640 : NumAlphas,
641 2601 : s_ipsc->rNumericArgs,
642 : NumNums,
643 : IOStat,
644 2601 : s_ipsc->lNumericFieldBlanks,
645 2601 : s_ipsc->lAlphaFieldBlanks,
646 2601 : s_ipsc->cAlphaFieldNames,
647 2601 : s_ipsc->cNumericFieldNames);
648 :
649 2601 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
650 2601 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
651 2601 : auto &setpt = s_ztpc->tempSetptScheds[(int)HVAC::SetptType::DualHeatCool](idx);
652 2601 : setpt.Name = s_ipsc->cAlphaArgs(1);
653 :
654 2601 : if (s_ipsc->lAlphaFieldBlanks(2)) {
655 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
656 0 : ErrorsFound = true;
657 2601 : } else if ((setpt.heatSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
658 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
659 0 : ErrorsFound = true;
660 : }
661 :
662 2601 : if (s_ipsc->lAlphaFieldBlanks(3)) {
663 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
664 0 : ErrorsFound = true;
665 2601 : } else if ((setpt.coolSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
666 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
667 0 : ErrorsFound = true;
668 : }
669 :
670 : } // DualTempHeatCoolControlNum
671 :
672 : // Finish filling in Schedule pointing indexes
673 5134 : for (TempControlledZoneNum = 1; TempControlledZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TempControlledZoneNum) {
674 4333 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum);
675 :
676 21665 : for (HVAC::SetptType setptType : HVAC::controlledSetptTypes) {
677 17332 : auto &setpt = tempZone.setpts[(int)setptType];
678 17332 : if (!setpt.isUsed) {
679 11191 : continue;
680 : }
681 :
682 6141 : int setptIdx = Util::FindItem(setpt.Name, s_ztpc->tempSetptScheds[(int)setptType]);
683 :
684 6141 : if (setptType == HVAC::SetptType::SingleHeat || setptType == HVAC::SetptType::SingleHeatCool ||
685 : setptType == HVAC::SetptType::DualHeatCool) {
686 4997 : setpt.heatSetptSched = s_ztpc->tempSetptScheds[(int)setptType](setptIdx).heatSched;
687 : }
688 :
689 6141 : if (setptType == HVAC::SetptType::SingleCool || setptType == HVAC::SetptType::SingleHeatCool ||
690 : setptType == HVAC::SetptType::DualHeatCool) {
691 4983 : setpt.coolSetptSched = s_ztpc->tempSetptScheds[(int)setptType](setptIdx).coolSched;
692 : }
693 : }
694 : }
695 :
696 : // Now, Check the schedule values/indices for validity
697 :
698 5134 : for (int TempControlledZoneNum = 1; TempControlledZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TempControlledZoneNum) {
699 4333 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum);
700 :
701 4333 : if (tempZone.setptTypeSched == nullptr) {
702 0 : continue; // error will be caught elsewhere
703 : }
704 :
705 4333 : int SchedMin = tempZone.setptTypeSched->getMinVal(state);
706 4333 : int SchedMax = tempZone.setptTypeSched->getMaxVal(state);
707 :
708 4333 : if (SchedMin == (int)HVAC::SetptType::Uncontrolled && SchedMax == (int)HVAC::SetptType::Uncontrolled) {
709 0 : if (FindNumberInList(tempZone.setptTypeSched->Num, CTSchedMapToControlledZone, state.dataZoneCtrls->NumTempControlledZones) == 0) {
710 0 : ShowSevereError(state, format("Control Type Schedule={}", tempZone.setptTypeSched->Name));
711 0 : ShowContinueError(state, "..specifies control type 0 for all entries.");
712 0 : ShowContinueError(state, "All zones using this Control Type Schedule have no heating or cooling available.");
713 : }
714 0 : CTSchedMapToControlledZone(TempControlledZoneNum) = tempZone.setptTypeSched->Num;
715 : }
716 :
717 21665 : for (HVAC::SetptType setptType : HVAC::controlledSetptTypes) {
718 17332 : auto const &setpt = tempZone.setpts[(int)setptType];
719 :
720 17332 : if (!setpt.isUsed) {
721 : // Catch early issues
722 11191 : if (tempZone.setptTypeSched->hasVal(state, (int)setptType)) {
723 0 : ShowSevereError(state, format("Control Type Schedule={}", tempZone.setptTypeSched->Name));
724 0 : ShowContinueError(
725 : state,
726 0 : format("..specifies {} ({}) as the control type. Not valid for this zone.", (int)setptType, setptTypeNames[(int)setptType]));
727 0 : ShowContinueError(state, format("..reference {}={}", cZControlTypes((int)ZoneControlTypes::TStat), tempZone.Name));
728 0 : ShowContinueError(state, format("..reference ZONE={}", tempZone.ZoneName));
729 0 : ErrorsFound = true;
730 : }
731 11191 : continue;
732 : }
733 :
734 1144 : if (setpt.heatSetptSched == nullptr &&
735 1144 : (setptType == HVAC::SetptType::SingleHeat || setptType == HVAC::SetptType::SingleHeatCool ||
736 7285 : setptType == HVAC::SetptType::DualHeatCool) &&
737 0 : tempZone.setptTypeSched->hasVal(state, (int)setptType)) {
738 0 : ShowSevereError(state, format("Control Type Schedule={}", tempZone.setptTypeSched->Name));
739 0 : ShowContinueError(
740 : state,
741 0 : format("..specifies {} ({}) as the control type. Not valid for this zone.", (int)setptType, setptTypeNames[(int)setptType]));
742 0 : ShowContinueError(state, format("..reference {}={}", cZControlTypes((int)ZoneControlTypes::TStat), tempZone.Name));
743 0 : ShowContinueError(state, format("..reference ZONE={}", tempZone.ZoneName));
744 0 : ErrorsFound = true;
745 : }
746 :
747 1158 : if (setpt.coolSetptSched == nullptr &&
748 1158 : (setptType == HVAC::SetptType::SingleCool || setptType == HVAC::SetptType::SingleHeatCool ||
749 7299 : setptType == HVAC::SetptType::DualHeatCool) &&
750 0 : tempZone.setptTypeSched->hasVal(state, (int)setptType)) {
751 0 : ShowSevereError(state, format("Control Type Schedule={}", tempZone.setptTypeSched->Name));
752 0 : ShowContinueError(
753 : state,
754 0 : format("..specifies {} ({}) as the control type. Not valid for this zone.", (int)setptType, setptTypeNames[(int)setptType]));
755 0 : ShowContinueError(state, format("..reference {}={}", cZControlTypes((int)ZoneControlTypes::TStat), tempZone.Name));
756 0 : ShowContinueError(state, format("..reference ZONE={}", tempZone.ZoneName));
757 0 : ErrorsFound = true;
758 : }
759 : } // for (setptType)
760 : }
761 :
762 5134 : for (TempControlledZoneNum = 1; TempControlledZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TempControlledZoneNum) {
763 4333 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum);
764 4333 : ActualZoneNum = tempZone.ActualZoneNum;
765 :
766 4333 : if (tempZone.setptTypeSched == nullptr) {
767 0 : continue; // error caught elsewhere -- would just be confusing here
768 : }
769 :
770 21665 : for (HVAC::SetptType setptType : HVAC::controlledSetptTypes) {
771 17332 : if (TStatControlTypes(TempControlledZoneNum).MustHave[(int)setptType] &&
772 0 : TStatControlTypes(TempControlledZoneNum).DidHave[(int)setptType]) {
773 0 : continue;
774 : }
775 :
776 17332 : if (!TStatControlTypes(TempControlledZoneNum).MustHave[(int)setptType]) {
777 17332 : continue;
778 : }
779 0 : ShowWarningError(state, format("Schedule={}", tempZone.setptTypeSched->Name));
780 0 : ShowContinueError(state, format("...should include control type {} ({}) but does not.", (int)setptType, setptTypeNames[(int)setptType]));
781 0 : ShowContinueError(state, format("..reference {}={}", cZControlTypes((int)ZoneControlTypes::TStat), tempZone.Name));
782 0 : ShowContinueError(state, format("..reference ZONE={}", tempZone.ZoneName));
783 : }
784 : }
785 :
786 801 : if (allocated(TStatControlTypes)) {
787 690 : TStatControlTypes.deallocate();
788 : }
789 : // This starts the Humidity Control Get Input section
790 801 : s_ipsc->cCurrentModuleObject = cZControlTypes(static_cast<int>(ZoneControlTypes::HStat));
791 801 : state.dataZoneCtrls->NumHumidityControlZones = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
792 :
793 801 : if (state.dataZoneCtrls->NumHumidityControlZones > 0) {
794 92 : state.dataZoneCtrls->HumidityControlZone.allocate(state.dataZoneCtrls->NumHumidityControlZones);
795 92 : s_ztpc->HumidityControlZoneUniqueNames.reserve(static_cast<unsigned>(state.dataZoneCtrls->NumHumidityControlZones));
796 : }
797 :
798 987 : for (HumidControlledZoneNum = 1; HumidControlledZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HumidControlledZoneNum) {
799 372 : s_ip->getObjectItem(state,
800 186 : s_ipsc->cCurrentModuleObject,
801 : HumidControlledZoneNum,
802 186 : s_ipsc->cAlphaArgs,
803 : NumAlphas,
804 186 : s_ipsc->rNumericArgs,
805 : NumNums,
806 : IOStat,
807 186 : s_ipsc->lNumericFieldBlanks,
808 186 : s_ipsc->lAlphaFieldBlanks,
809 186 : s_ipsc->cAlphaFieldNames,
810 186 : s_ipsc->cNumericFieldNames);
811 :
812 186 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
813 :
814 186 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
815 :
816 186 : auto &humidControlledZone = state.dataZoneCtrls->HumidityControlZone(HumidControlledZoneNum);
817 186 : humidControlledZone.ControlName = s_ipsc->cAlphaArgs(1);
818 186 : GlobalNames::IntraObjUniquenessCheck(state,
819 186 : s_ipsc->cAlphaArgs(2),
820 186 : s_ipsc->cCurrentModuleObject,
821 186 : s_ipsc->cAlphaFieldNames(2),
822 186 : s_ztpc->HumidityControlZoneUniqueNames,
823 : ErrorsFound);
824 :
825 186 : humidControlledZone.ZoneName = s_ipsc->cAlphaArgs(2);
826 186 : humidControlledZone.ActualZoneNum = Util::FindItem(s_ipsc->cAlphaArgs(2), Zone);
827 186 : if (humidControlledZone.ActualZoneNum == 0) {
828 0 : ShowSevereError(state,
829 0 : format("{}=\"{} invalid {}=\"{}\" not found.",
830 0 : s_ipsc->cCurrentModuleObject,
831 0 : s_ipsc->cAlphaArgs(1),
832 0 : s_ipsc->cAlphaFieldNames(2),
833 0 : s_ipsc->cAlphaArgs(2)));
834 0 : ErrorsFound = true;
835 : } else {
836 186 : state.dataHeatBal->Zone(humidControlledZone.ActualZoneNum).humidityControlZoneIndex = HumidControlledZoneNum;
837 : }
838 :
839 186 : if (s_ipsc->lAlphaFieldBlanks(3)) {
840 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
841 0 : ErrorsFound = true;
842 186 : } else if ((humidControlledZone.humidifyingSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
843 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
844 0 : ErrorsFound = true;
845 : }
846 :
847 186 : if (NumAlphas < 4 || s_ipsc->lAlphaFieldBlanks(4)) {
848 70 : humidControlledZone.dehumidifyingSched = humidControlledZone.humidifyingSched;
849 116 : } else if ((humidControlledZone.dehumidifyingSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(4))) == nullptr) {
850 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
851 0 : ErrorsFound = true;
852 : }
853 :
854 : } // HumidControlledZoneNum
855 :
856 : // Start to read Thermal comfort control objects
857 801 : s_ipsc->cCurrentModuleObject = cZControlTypes(static_cast<int>(ZoneControlTypes::TCTStat));
858 801 : state.dataZoneCtrls->NumComfortTStatStatements = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
859 801 : ComfortTStatObjects.allocate(state.dataZoneCtrls->NumComfortTStatStatements);
860 :
861 : // Pre-scan for use of Zone lists in TStat statements (i.e. Global application of TStat)
862 801 : state.dataZoneCtrls->NumComfortControlledZones = 0;
863 801 : errFlag = false;
864 802 : for (Item = 1; Item <= state.dataZoneCtrls->NumComfortTStatStatements; ++Item) {
865 2 : s_ip->getObjectItem(state,
866 1 : s_ipsc->cCurrentModuleObject,
867 : Item,
868 1 : s_ipsc->cAlphaArgs,
869 : NumAlphas,
870 1 : s_ipsc->rNumericArgs,
871 : NumNums,
872 : IOStat,
873 1 : s_ipsc->lNumericFieldBlanks,
874 1 : s_ipsc->lAlphaFieldBlanks,
875 1 : s_ipsc->cAlphaFieldNames,
876 1 : s_ipsc->cNumericFieldNames);
877 1 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
878 :
879 1 : Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(2), Zone);
880 1 : ZLItem = 0;
881 1 : if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) {
882 0 : ZLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(2), ZoneList);
883 : }
884 1 : ComfortTStatObjects(Item).Name = s_ipsc->cAlphaArgs(1);
885 1 : if (Item1 > 0) {
886 1 : ComfortTStatObjects(Item).ComfortControlledZoneStartPtr = state.dataZoneCtrls->NumComfortControlledZones + 1;
887 1 : ++state.dataZoneCtrls->NumComfortControlledZones;
888 1 : ComfortTStatObjects(Item).NumOfZones = 1;
889 1 : ComfortTStatObjects(Item).ZoneListActive = false;
890 1 : ComfortTStatObjects(Item).ZoneOrZoneListPtr = Item1;
891 0 : } else if (ZLItem > 0) {
892 0 : auto const &ZoneList = state.dataHeatBal->ZoneList(ZLItem);
893 0 : ComfortTStatObjects(Item).ComfortControlledZoneStartPtr = state.dataZoneCtrls->NumComfortControlledZones + 1;
894 0 : state.dataZoneCtrls->NumComfortControlledZones += ZoneList.NumOfZones;
895 0 : ComfortTStatObjects(Item).NumOfZones = ZoneList.NumOfZones;
896 0 : ComfortTStatObjects(Item).ZoneListActive = true;
897 0 : ComfortTStatObjects(Item).ZoneOrZoneListPtr = ZLItem;
898 : } else {
899 0 : ShowSevereError(state,
900 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
901 0 : s_ipsc->cCurrentModuleObject,
902 0 : s_ipsc->cAlphaArgs(1),
903 0 : s_ipsc->cAlphaFieldNames(2),
904 0 : s_ipsc->cAlphaArgs(2)));
905 0 : errFlag = true;
906 0 : ErrorsFound = true;
907 : }
908 : }
909 :
910 801 : if (errFlag) {
911 0 : ShowSevereError(state, format("GetZoneAirSetpoints: Errors with invalid names in {} objects.", s_ipsc->cCurrentModuleObject));
912 0 : ShowContinueError(state, "...These will not be read in. Other errors may occur.");
913 0 : state.dataZoneCtrls->NumComfortControlledZones = 0;
914 : }
915 :
916 801 : if (state.dataZoneCtrls->NumComfortControlledZones > 0) {
917 1 : state.dataZoneCtrls->ComfortControlledZone.allocate(state.dataZoneCtrls->NumComfortControlledZones);
918 1 : TComfortControlTypes.allocate(state.dataZoneCtrls->NumComfortControlledZones); // Number of set point types
919 1 : CCmSchedMapToControlledZone.dimension(state.dataZoneCtrls->NumComfortControlledZones, 0);
920 :
921 1 : ComfortControlledZoneNum = 0;
922 2 : for (Item = 1; Item <= state.dataZoneCtrls->NumComfortTStatStatements; ++Item) {
923 2 : s_ip->getObjectItem(state,
924 1 : s_ipsc->cCurrentModuleObject,
925 : Item,
926 1 : s_ipsc->cAlphaArgs,
927 : NumAlphas,
928 1 : s_ipsc->rNumericArgs,
929 : NumNums,
930 : IOStat,
931 1 : s_ipsc->lNumericFieldBlanks,
932 1 : s_ipsc->lAlphaFieldBlanks,
933 1 : s_ipsc->cAlphaFieldNames,
934 1 : s_ipsc->cNumericFieldNames);
935 :
936 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
937 :
938 2 : for (Item1 = 1; Item1 <= ComfortTStatObjects(Item).NumOfZones; ++Item1) {
939 1 : ++ComfortControlledZoneNum;
940 :
941 1 : auto &comfortZone = state.dataZoneCtrls->ComfortControlledZone(ComfortControlledZoneNum);
942 :
943 1 : if (ComfortTStatObjects(Item).ZoneListActive) {
944 0 : s_ipsc->cAlphaArgs(2) = state.dataHeatBal->Zone(ZoneList(ComfortTStatObjects(Item).ZoneOrZoneListPtr).Zone(Item1)).Name;
945 : }
946 1 : int ZoneAssigned = Util::FindItemInList(s_ipsc->cAlphaArgs(2),
947 1 : state.dataZoneCtrls->ComfortControlledZone,
948 : &DataZoneControls::ZoneComfortControls::ZoneName,
949 : ComfortControlledZoneNum - 1);
950 1 : if (ZoneAssigned == 0) {
951 1 : comfortZone.ZoneName = s_ipsc->cAlphaArgs(2);
952 1 : comfortZone.ActualZoneNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), Zone);
953 1 : if (comfortZone.ActualZoneNum == 0) {
954 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
955 0 : ErrorsFound = true;
956 : }
957 : } else {
958 0 : comfortZone.ZoneName = s_ipsc->cAlphaArgs(2); // for continuity
959 0 : ShowSevereDuplicateAssignment(state,
960 : eoh,
961 0 : s_ipsc->cAlphaFieldNames(2),
962 0 : s_ipsc->cAlphaArgs(2),
963 0 : state.dataZoneCtrls->ComfortControlledZone(ZoneAssigned).Name);
964 0 : ErrorsFound = true;
965 0 : continue;
966 : }
967 :
968 1 : if (!ComfortTStatObjects(Item).ZoneListActive) {
969 1 : comfortZone.Name = s_ipsc->cAlphaArgs(1);
970 : } else {
971 0 : comfortZone.Name = state.dataHeatBal->Zone(ZoneList(ComfortTStatObjects(Item).ZoneOrZoneListPtr).Zone(Item1)).Name + ' ' +
972 0 : ComfortTStatObjects(Item).Name;
973 : }
974 :
975 : // Read Fields A3 and A4 for averaging method
976 1 : int IZoneCount = 0;
977 4 : for (i = 1; i <= state.dataHeatBal->TotPeople; ++i) {
978 3 : if (comfortZone.ActualZoneNum == state.dataHeatBal->People(i).ZonePtr) {
979 1 : ++IZoneCount;
980 : }
981 : }
982 : // Could not find a people object for this particular zone
983 1 : if (IZoneCount == 0 && comfortZone.ActualZoneNum > 0) {
984 0 : ShowSevereError(state,
985 0 : format("{}=\"{} no PEOPLE in {}=\"{}\" - cannot use Comfort Control.",
986 0 : s_ipsc->cCurrentModuleObject,
987 0 : s_ipsc->cAlphaArgs(1),
988 0 : s_ipsc->cAlphaFieldNames(2),
989 0 : s_ipsc->cAlphaArgs(2)));
990 0 : ErrorsFound = true;
991 : }
992 :
993 1 : comfortZone.averageMethod = DataZoneControls::AverageMethod::NO;
994 1 : if (IZoneCount > 1) {
995 0 : comfortZone.averageMethod =
996 0 : static_cast<DataZoneControls::AverageMethod>(getEnumValue(DataZoneControls::averageMethodNamesUC, s_ipsc->cAlphaArgs(3)));
997 0 : if (comfortZone.averageMethod == DataZoneControls::AverageMethod::Invalid) {
998 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
999 0 : ErrorsFound = true;
1000 0 : } else if (comfortZone.averageMethod == DataZoneControls::AverageMethod::SPE) {
1001 0 : comfortZone.AverageObjectName = s_ipsc->cAlphaArgs(4);
1002 0 : if (Util::FindItem(s_ipsc->cAlphaArgs(4), state.dataHeatBal->People) == 0) {
1003 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
1004 0 : ErrorsFound = true;
1005 : } else {
1006 0 : comfortZone.SpecificObjectNum = Util::FindItem(s_ipsc->cAlphaArgs(4), state.dataHeatBal->People);
1007 : }
1008 : }
1009 : } else {
1010 2 : for (i = 1; i <= state.dataHeatBal->TotPeople; ++i) {
1011 2 : if (comfortZone.ActualZoneNum == state.dataHeatBal->People(i).ZonePtr) {
1012 1 : break;
1013 : }
1014 : }
1015 1 : comfortZone.SpecificObjectNum = i;
1016 : }
1017 : // Check values used for thermal comfort calculation
1018 4 : for (i = 1; i <= state.dataHeatBal->TotPeople; ++i) {
1019 3 : auto &people = state.dataHeatBal->People(i);
1020 :
1021 3 : if (comfortZone.ActualZoneNum != people.ZonePtr) {
1022 2 : continue;
1023 : }
1024 :
1025 : // Check activity level
1026 1 : if (people.activityLevelSched == nullptr) {
1027 0 : ShowSevereError(state, format("GetPeople Activity Level: Activity level schedule is not found={}", people.Name));
1028 0 : ShowContinueError(state, "Required when the zone has Thermal Comfort Controls.");
1029 0 : ErrorsFound = true;
1030 1 : } else if (!people.activityLevelSched->checkMinMaxVals(state, Clusive::In, 72.0, Clusive::In, 909.0)) {
1031 0 : ShowSevereError(state, "GetPeople Activity Level: Invalid activity level values entered for thermal comfort calculation");
1032 0 : ShowContinueError(state, format("Outside of range values [72,909], Reference object={}", people.Name));
1033 : }
1034 :
1035 : // Check Work Efficiency
1036 1 : if (people.workEffSched == nullptr) {
1037 0 : ShowSevereError(state, format("GetPeople work efficiency: Work efficiency schedule is not found={}", people.Name));
1038 0 : ShowContinueError(state, "Required when the zone has Thermal Comfort Controls.");
1039 0 : ErrorsFound = true;
1040 1 : } else if (!people.workEffSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
1041 0 : ShowSevereError(state, "GetPeople work efficiency: Invalid work efficiency values entered for thermal comfort calculation");
1042 0 : ShowContinueError(state, format("Outside of range values [0,1], Reference object={}", people.Name));
1043 0 : ErrorsFound = true;
1044 : }
1045 :
1046 : // Check Clothing Insulation
1047 1 : if (people.clothingSched == nullptr) {
1048 0 : ShowSevereError(state, format("GetPeople Clothing Insulation: Clothing Insulation schedule is not found={}", people.Name));
1049 0 : ShowContinueError(state, "Required when the zone has Thermal Comfort Controls.");
1050 0 : ErrorsFound = true;
1051 1 : } else if (!people.clothingSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 2.0)) {
1052 0 : ShowSevereError(state,
1053 : "GetPeople Clothing Insulation: Invalid Clothing Insulation values entered for thermal comfort calculation");
1054 0 : ShowContinueError(state, format("Outside of range values [0.0,2.0], Reference object={}", people.Name));
1055 0 : ErrorsFound = true;
1056 : }
1057 :
1058 : // Check Air velocity
1059 1 : if (people.airVelocitySched == nullptr) {
1060 0 : ShowSevereError(state, format("GetPeople Air Velocity: Air velocity schedule is not found={}", people.Name));
1061 0 : ShowContinueError(state, "Required when the zone has Thermal Comfort Controls.");
1062 0 : ErrorsFound = true;
1063 : }
1064 : }
1065 :
1066 : // Read Max and Min temperature setpoint
1067 1 : if (NumNums > 0) {
1068 1 : comfortZone.TdbMinSetPoint = s_ipsc->rNumericArgs(1);
1069 1 : if (s_ipsc->rNumericArgs(1) > 50 || s_ipsc->rNumericArgs(1) < 0) {
1070 0 : ShowSevereError(state,
1071 0 : format("{}=\"{} invalid {}=[{:.0T}].",
1072 0 : s_ipsc->cCurrentModuleObject,
1073 0 : s_ipsc->cAlphaArgs(1),
1074 0 : s_ipsc->cNumericFieldNames(1),
1075 0 : s_ipsc->rNumericArgs(1)));
1076 0 : ShowContinueError(state, "..Allowable values must be between 0 C and 50 C");
1077 0 : ErrorsFound = true;
1078 : }
1079 : }
1080 1 : if (NumNums > 1) {
1081 1 : comfortZone.TdbMaxSetPoint = s_ipsc->rNumericArgs(2);
1082 1 : if (s_ipsc->rNumericArgs(2) > 50 || s_ipsc->rNumericArgs(2) < 0) {
1083 0 : ShowSevereError(state,
1084 0 : format("{}=\"{} invalid {}=[{:.0T}].",
1085 0 : s_ipsc->cCurrentModuleObject,
1086 0 : s_ipsc->cAlphaArgs(1),
1087 0 : s_ipsc->cNumericFieldNames(2),
1088 0 : s_ipsc->rNumericArgs(2)));
1089 0 : ShowContinueError(state, "..Allowable values must be between 0 C and 50 C");
1090 0 : ErrorsFound = true;
1091 : }
1092 : }
1093 : // Ensure MaxTemp >= MinTemp
1094 1 : if (comfortZone.TdbMinSetPoint > comfortZone.TdbMaxSetPoint) {
1095 0 : ShowSevereError(state, format("{}=\"{}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1096 0 : ShowContinueError(state, format("..{} > {}", s_ipsc->cNumericFieldNames(1), s_ipsc->cNumericFieldNames(2)));
1097 0 : ShowContinueError(state, format("..[{:.0T}] > [{:.0T}].", s_ipsc->rNumericArgs(1), s_ipsc->rNumericArgs(2)));
1098 0 : ErrorsFound = true;
1099 : }
1100 : // If MaxTemp = MinTemp, no thermal comfort control
1101 1 : if (comfortZone.TdbMinSetPoint == comfortZone.TdbMaxSetPoint) {
1102 0 : ShowSevereError(state, format("{}=\"{}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1103 0 : ShowContinueError(state, format("..{} = {}", s_ipsc->cNumericFieldNames(1), s_ipsc->cNumericFieldNames(2)));
1104 0 : ShowContinueError(state, "The zone will be controlled using this dry-bulb temperature setpoint.");
1105 : }
1106 :
1107 : // read Thermal comfort type schedule name
1108 1 : if (s_ipsc->lAlphaFieldBlanks(5)) {
1109 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(5));
1110 0 : ErrorsFound = true;
1111 1 : } else if ((comfortZone.setptTypeSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(5))) == nullptr) {
1112 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5));
1113 0 : ErrorsFound = true;
1114 1 : } else if (!comfortZone.setptTypeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 4.0)) {
1115 0 : Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5), Clusive::In, 0.0, Clusive::In, 4.0);
1116 0 : ErrorsFound = true;
1117 : }
1118 :
1119 1 : int NumSetptTypes = nint((NumAlphas - 5.0) / 2.0);
1120 :
1121 5 : for (int iSetptType = 1; iSetptType <= NumSetptTypes; ++iSetptType) {
1122 :
1123 4 : int ctIdx = 2 * iSetptType - 1 + 5;
1124 :
1125 4 : HVAC::SetptType setptType = HVAC::SetptType::Invalid;
1126 4 : if (s_ipsc->lAlphaFieldBlanks(ctIdx)) {
1127 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(ctIdx));
1128 0 : ErrorsFound = true;
1129 0 : continue;
1130 4 : } else if ((setptType = static_cast<HVAC::SetptType>(getEnumValue(comfortSetptTypeNamesUC, s_ipsc->cAlphaArgs(ctIdx)))) ==
1131 : HVAC::SetptType::Invalid) {
1132 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(ctIdx), s_ipsc->cAlphaFieldNames(ctIdx));
1133 0 : ErrorsFound = true;
1134 0 : continue;
1135 : }
1136 :
1137 4 : auto &setpt = comfortZone.setpts[(int)setptType];
1138 4 : setpt.Name = s_ipsc->cAlphaArgs(nint(2.0 * iSetptType + 5));
1139 4 : setpt.isUsed = true;
1140 : }
1141 : }
1142 : } // NumComfortTStatStatements
1143 : }
1144 : // End of Thermal comfort control reading and checking
1145 :
1146 801 : s_ipsc->cCurrentModuleObject = comfortSetptTypeNames[(int)HVAC::SetptType::SingleHeat];
1147 801 : s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeat] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1148 :
1149 801 : if (s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeat] > 0) {
1150 1 : s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::SingleHeat].allocate(s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeat]);
1151 : }
1152 :
1153 802 : for (int idx = 1; idx <= s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeat]; ++idx) {
1154 2 : s_ip->getObjectItem(state,
1155 1 : s_ipsc->cCurrentModuleObject,
1156 : idx,
1157 1 : s_ipsc->cAlphaArgs,
1158 : NumAlphas,
1159 1 : s_ipsc->rNumericArgs,
1160 : NumNums,
1161 : IOStat,
1162 1 : s_ipsc->lNumericFieldBlanks,
1163 1 : s_ipsc->lAlphaFieldBlanks,
1164 1 : s_ipsc->cAlphaFieldNames,
1165 1 : s_ipsc->cNumericFieldNames);
1166 :
1167 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1168 :
1169 1 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
1170 1 : auto &setpt = s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::SingleHeat](idx);
1171 1 : setpt.Name = s_ipsc->cAlphaArgs(1);
1172 :
1173 1 : if (s_ipsc->lAlphaFieldBlanks(2)) {
1174 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
1175 0 : ErrorsFound = true;
1176 1 : } else if ((setpt.heatSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
1177 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
1178 0 : ErrorsFound = true;
1179 1 : } else if (!setpt.heatSched->checkMinMaxVals(state, Clusive::In, -3.0, Clusive::In, 3.0)) {
1180 0 : Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), Clusive::In, -3.0, Clusive::In, 3.0);
1181 0 : ErrorsFound = true;
1182 : }
1183 : } // SingleFangerHeatingControlNum
1184 :
1185 801 : s_ipsc->cCurrentModuleObject = comfortSetptTypeNames[(int)HVAC::SetptType::SingleCool];
1186 801 : s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleCool] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1187 :
1188 801 : if (s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleCool] > 0) {
1189 1 : s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::SingleCool].allocate(s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleCool]);
1190 : }
1191 :
1192 802 : for (int idx = 1; idx <= s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleCool]; ++idx) {
1193 2 : s_ip->getObjectItem(state,
1194 1 : s_ipsc->cCurrentModuleObject,
1195 : idx,
1196 1 : s_ipsc->cAlphaArgs,
1197 : NumAlphas,
1198 1 : s_ipsc->rNumericArgs,
1199 : NumNums,
1200 : IOStat,
1201 1 : s_ipsc->lNumericFieldBlanks,
1202 1 : s_ipsc->lAlphaFieldBlanks,
1203 1 : s_ipsc->cAlphaFieldNames,
1204 1 : s_ipsc->cNumericFieldNames);
1205 :
1206 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1207 :
1208 1 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
1209 1 : auto &setpt = s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::SingleCool](idx);
1210 1 : setpt.Name = s_ipsc->cAlphaArgs(1);
1211 :
1212 1 : if (s_ipsc->lAlphaFieldBlanks(2)) {
1213 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
1214 0 : ErrorsFound = true;
1215 1 : } else if ((setpt.coolSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
1216 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
1217 0 : ErrorsFound = true;
1218 1 : } else if (!setpt.coolSched->checkMinMaxVals(state, Clusive::In, -3.0, Clusive::In, 3.0)) {
1219 0 : Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), Clusive::In, -3.0, Clusive::In, 3.0);
1220 0 : ErrorsFound = true;
1221 : }
1222 :
1223 : } // SingleFangerCoolingControlNum
1224 :
1225 801 : s_ipsc->cCurrentModuleObject = comfortSetptTypeNames[(int)HVAC::SetptType::SingleHeatCool];
1226 801 : s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeatCool] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1227 :
1228 801 : if (s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeatCool] > 0) {
1229 1 : s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::SingleHeatCool].allocate(s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeatCool]);
1230 : }
1231 :
1232 802 : for (int idx = 1; idx <= s_ztpc->NumComfortControls[(int)HVAC::SetptType::SingleHeatCool]; ++idx) {
1233 2 : s_ip->getObjectItem(state,
1234 1 : s_ipsc->cCurrentModuleObject,
1235 : idx,
1236 1 : s_ipsc->cAlphaArgs,
1237 : NumAlphas,
1238 1 : s_ipsc->rNumericArgs,
1239 : NumNums,
1240 : IOStat,
1241 1 : s_ipsc->lNumericFieldBlanks,
1242 1 : s_ipsc->lAlphaFieldBlanks,
1243 1 : s_ipsc->cAlphaFieldNames,
1244 1 : s_ipsc->cNumericFieldNames);
1245 :
1246 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1247 :
1248 1 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
1249 1 : auto &setpt = s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::SingleHeatCool](idx);
1250 1 : setpt.Name = s_ipsc->cAlphaArgs(1);
1251 :
1252 1 : if (s_ipsc->lAlphaFieldBlanks(2)) {
1253 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
1254 0 : ErrorsFound = true;
1255 1 : } else if ((setpt.heatSched = setpt.coolSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
1256 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
1257 0 : ErrorsFound = true;
1258 1 : } else if (!setpt.heatSched->checkMinMaxVals(state, Clusive::In, -3.0, Clusive::In, 3.0)) {
1259 0 : Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), Clusive::In, -3.0, Clusive::In, 3.0);
1260 0 : ErrorsFound = true;
1261 : }
1262 :
1263 : } // SingleFangerHeatCoolControlNum
1264 :
1265 801 : s_ipsc->cCurrentModuleObject = comfortSetptTypeNames[(int)HVAC::SetptType::DualHeatCool];
1266 801 : s_ztpc->NumComfortControls[(int)HVAC::SetptType::DualHeatCool] = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1267 :
1268 801 : if (s_ztpc->NumComfortControls[(int)HVAC::SetptType::DualHeatCool] > 0) {
1269 1 : s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::DualHeatCool].allocate(s_ztpc->NumComfortControls[(int)HVAC::SetptType::DualHeatCool]);
1270 : }
1271 :
1272 802 : for (int idx = 1; idx <= s_ztpc->NumComfortControls[(int)HVAC::SetptType::DualHeatCool]; ++idx) {
1273 2 : s_ip->getObjectItem(state,
1274 1 : s_ipsc->cCurrentModuleObject,
1275 : idx,
1276 1 : s_ipsc->cAlphaArgs,
1277 : NumAlphas,
1278 1 : s_ipsc->rNumericArgs,
1279 : NumNums,
1280 : IOStat,
1281 1 : s_ipsc->lNumericFieldBlanks,
1282 1 : s_ipsc->lAlphaFieldBlanks,
1283 1 : s_ipsc->cAlphaFieldNames,
1284 1 : s_ipsc->cNumericFieldNames);
1285 :
1286 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1287 :
1288 1 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
1289 1 : auto &setpt = s_ztpc->comfortSetptScheds[(int)HVAC::SetptType::DualHeatCool](idx);
1290 1 : setpt.Name = s_ipsc->cAlphaArgs(1);
1291 :
1292 1 : if (s_ipsc->lAlphaFieldBlanks(2)) {
1293 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
1294 0 : ErrorsFound = true;
1295 1 : } else if ((setpt.heatSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
1296 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
1297 0 : ErrorsFound = true;
1298 1 : } else if (!setpt.heatSched->checkMinMaxVals(state, Clusive::In, -3.0, Clusive::In, 3.0)) {
1299 0 : Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2), Clusive::In, -3.0, Clusive::In, 3.0);
1300 0 : ErrorsFound = true;
1301 : }
1302 :
1303 1 : if (s_ipsc->lAlphaFieldBlanks(3)) {
1304 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
1305 0 : ErrorsFound = true;
1306 1 : } else if ((setpt.coolSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
1307 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
1308 0 : ErrorsFound = true;
1309 1 : } else if (!setpt.coolSched->checkMinMaxVals(state, Clusive::In, -3.0, Clusive::In, 3.0)) {
1310 0 : Sched::ShowSevereBadMinMax(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), Clusive::In, -3.0, Clusive::In, 3.0);
1311 0 : ErrorsFound = true;
1312 : }
1313 :
1314 : } // DualFangerHeatCoolControlNum
1315 :
1316 : // Finish filling in Schedule pointing indexes for Thermal Comfort Control
1317 802 : for (ComfortControlledZoneNum = 1; ComfortControlledZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++ComfortControlledZoneNum) {
1318 :
1319 1 : auto &comfortZone = state.dataZoneCtrls->ComfortControlledZone(ComfortControlledZoneNum);
1320 :
1321 5 : for (HVAC::SetptType setptType : HVAC::controlledSetptTypes) {
1322 4 : auto &setpt = comfortZone.setpts[(int)setptType];
1323 4 : if (!setpt.isUsed) {
1324 0 : continue;
1325 : }
1326 :
1327 4 : int setptIdx = Util::FindItem(setpt.Name, s_ztpc->comfortSetptScheds[(int)setptType]);
1328 :
1329 4 : if (setptType == HVAC::SetptType::SingleHeat || setptType == HVAC::SetptType::SingleHeatCool ||
1330 : setptType == HVAC::SetptType::DualHeatCool) {
1331 3 : setpt.heatSetptSched = s_ztpc->comfortSetptScheds[(int)setptType](setptIdx).heatSched;
1332 : }
1333 :
1334 4 : if (setptType == HVAC::SetptType::SingleCool || setptType == HVAC::SetptType::SingleHeatCool ||
1335 : setptType == HVAC::SetptType::DualHeatCool) {
1336 3 : setpt.coolSetptSched = s_ztpc->comfortSetptScheds[(int)setptType](setptIdx).coolSched;
1337 : }
1338 :
1339 4 : TComfortControlTypes(ComfortControlledZoneNum).MustHave[(int)setptType] = true;
1340 : }
1341 : }
1342 :
1343 : // Now, Check the schedule values/indices for validity for Thermal Comfort Control
1344 :
1345 802 : for (ComfortControlledZoneNum = 1; ComfortControlledZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++ComfortControlledZoneNum) {
1346 1 : auto &comfortZone = state.dataZoneCtrls->ComfortControlledZone(ComfortControlledZoneNum);
1347 1 : ActualZoneNum = comfortZone.ActualZoneNum;
1348 1 : if (comfortZone.setptTypeSched == nullptr) {
1349 0 : continue;
1350 : }
1351 :
1352 1 : int SchedMin = comfortZone.setptTypeSched->getMinVal(state);
1353 1 : int SchedMax = comfortZone.setptTypeSched->getMaxVal(state);
1354 :
1355 1 : if (SchedMin == (int)HVAC::SetptType::Uncontrolled && SchedMax == (int)HVAC::SetptType::Uncontrolled) {
1356 0 : if (FindNumberInList(comfortZone.setptTypeSched->Num, CCmSchedMapToControlledZone, state.dataZoneCtrls->NumComfortControlledZones) == 0) {
1357 0 : ShowWarningError(state, format("Control Type Schedule={}", comfortZone.setptTypeSched->Name));
1358 0 : ShowContinueError(state, "..specifies control type 0 for all entries.");
1359 0 : ShowContinueError(state, "All zones using this Control Type Schedule have no thermal comfort control.");
1360 : }
1361 0 : CCmSchedMapToControlledZone(ComfortControlledZoneNum) = comfortZone.setptTypeSched->Num;
1362 : }
1363 :
1364 5 : for (HVAC::SetptType setptType : HVAC::controlledSetptTypes) {
1365 4 : auto const &setpt = comfortZone.setpts[(int)setptType];
1366 4 : if (!setpt.isUsed) {
1367 0 : continue;
1368 : }
1369 :
1370 4 : TComfortControlTypes(ComfortControlledZoneNum).DidHave[(int)setptType] = true;
1371 :
1372 1 : if (setpt.heatSetptSched == nullptr &&
1373 1 : (setptType == HVAC::SetptType::SingleHeat || setptType == HVAC::SetptType::SingleHeatCool ||
1374 5 : setptType == HVAC::SetptType::DualHeatCool) &&
1375 0 : comfortZone.setptTypeSched->hasVal(state, (int)setptType)) {
1376 0 : ShowSevereError(state, format("Control Type Schedule={}", comfortZone.setptTypeSched->Name));
1377 0 : ShowContinueError(
1378 : state,
1379 0 : format("..specifies {} ({}) as the control type. Not valid for this zone.", (int)setptType, setptTypeNames[(int)setptType]));
1380 0 : ShowContinueError(state, format("..reference {}={}", cZControlTypes((int)ZoneControlTypes::TStat), comfortZone.Name));
1381 0 : ShowContinueError(state, format("..reference ZONE={}", comfortZone.ZoneName));
1382 0 : ErrorsFound = true;
1383 : }
1384 :
1385 1 : if (setpt.coolSetptSched == nullptr &&
1386 1 : (setptType == HVAC::SetptType::SingleCool || setptType == HVAC::SetptType::SingleHeatCool ||
1387 5 : setptType == HVAC::SetptType::DualHeatCool) &&
1388 0 : comfortZone.setptTypeSched->hasVal(state, (int)setptType)) {
1389 0 : ShowSevereError(state, format("Control Type Schedule={}", comfortZone.setptTypeSched->Name));
1390 0 : ShowContinueError(
1391 : state,
1392 0 : format("..specifies {} ({}) as the control type. Not valid for this zone.", (int)setptType, setptTypeNames[(int)setptType]));
1393 0 : ShowContinueError(state, format("..reference {}={}", cZControlTypes((int)ZoneControlTypes::TStat), comfortZone.Name));
1394 0 : ShowContinueError(state, format("..reference ZONE={}", comfortZone.ZoneName));
1395 0 : ErrorsFound = true;
1396 : }
1397 : } // for (setptType)
1398 : } // for (ComfortControlledZoneNum)
1399 :
1400 802 : for (int ComfortControlledZoneNum = 1; ComfortControlledZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++ComfortControlledZoneNum) {
1401 :
1402 1 : auto &comfortZone = state.dataZoneCtrls->ComfortControlledZone(ComfortControlledZoneNum);
1403 1 : ActualZoneNum = comfortZone.ActualZoneNum;
1404 1 : if (comfortZone.setptTypeSched == nullptr) {
1405 0 : continue;
1406 : }
1407 :
1408 5 : for (HVAC::SetptType setptType : HVAC::controlledSetptTypes) {
1409 8 : if (TComfortControlTypes(ComfortControlledZoneNum).MustHave[(int)setptType] &&
1410 4 : TComfortControlTypes(ComfortControlledZoneNum).DidHave[(int)setptType]) {
1411 4 : continue;
1412 : }
1413 :
1414 0 : if (!TComfortControlTypes(ComfortControlledZoneNum).MustHave[(int)setptType]) {
1415 0 : continue;
1416 : }
1417 :
1418 0 : ShowWarningError(state, format("Schedule={}", comfortZone.setptTypeSched->Name));
1419 0 : ShowContinueError(state,
1420 0 : format("...should include control type {} ({}) but does not.", (int)setptType, comfortSetptTypeNames[(int)setptType]));
1421 0 : ShowContinueError(state, format("..reference {}={}", cZControlTypes((int)ZoneControlTypes::TCTStat), comfortZone.Name));
1422 0 : ShowContinueError(state, format("...reference ZONE={}", comfortZone.ZoneName));
1423 : }
1424 : }
1425 :
1426 801 : if (allocated(TComfortControlTypes)) {
1427 1 : TComfortControlTypes.deallocate();
1428 : }
1429 :
1430 : // Get the Hybrid Model setting inputs
1431 801 : HybridModel::GetHybridModelZone(state);
1432 :
1433 : // Default multiplier values
1434 801 : Real64 ZoneVolCapMultpSens = 1.0;
1435 801 : Real64 ZoneVolCapMultpMoist = 1.0;
1436 801 : Real64 ZoneVolCapMultpCO2 = 1.0;
1437 801 : Real64 ZoneVolCapMultpGenContam = 1.0;
1438 :
1439 : // Get the Zone Air Capacitance Multiplier for use in the Predictor-Corrector Procedure
1440 801 : s_ipsc->cCurrentModuleObject = "ZoneCapacitanceMultiplier:ResearchSpecial";
1441 801 : int NumZoneCapaMultiplier = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject); // Number of ZonesCapacityMultiplier object
1442 801 : if (NumZoneCapaMultiplier == 0) {
1443 : // Assign default multiplier values to all zones
1444 5834 : for (int ZoneNum = 1; ZoneNum <= NumOfZones; ZoneNum++) {
1445 5071 : auto &Zone = state.dataHeatBal->Zone(ZoneNum);
1446 5071 : Zone.ZoneVolCapMultpSens = ZoneVolCapMultpSens;
1447 5071 : Zone.ZoneVolCapMultpMoist = ZoneVolCapMultpMoist;
1448 5071 : Zone.ZoneVolCapMultpCO2 = ZoneVolCapMultpCO2;
1449 5071 : Zone.ZoneVolCapMultpGenContam = ZoneVolCapMultpGenContam;
1450 : }
1451 :
1452 : } else {
1453 :
1454 : // Allow user to specify ZoneCapacitanceMultiplier:ResearchSpecial at zone level
1455 : // Added by S. Lee and R. Zhang in Oct. 2016.
1456 : // Assign the user inputted multipliers to specified zones
1457 85 : for (int ZoneCapNum = 1; ZoneCapNum <= NumZoneCapaMultiplier; ZoneCapNum++) {
1458 94 : s_ip->getObjectItem(state,
1459 47 : s_ipsc->cCurrentModuleObject,
1460 : ZoneCapNum,
1461 47 : s_ipsc->cAlphaArgs,
1462 : NumAlphas,
1463 47 : s_ipsc->rNumericArgs,
1464 : NumNums,
1465 : IOStat,
1466 47 : s_ipsc->lNumericFieldBlanks,
1467 47 : s_ipsc->lAlphaFieldBlanks,
1468 47 : s_ipsc->cAlphaFieldNames,
1469 47 : s_ipsc->cNumericFieldNames);
1470 :
1471 47 : if (s_ipsc->lAlphaFieldBlanks(2)) {
1472 : // default multiplier values for all the zones not specified (zone or zonelist name field is empty)
1473 35 : ZoneVolCapMultpSens = s_ipsc->rNumericArgs(1);
1474 35 : ZoneVolCapMultpMoist = s_ipsc->rNumericArgs(2);
1475 35 : ZoneVolCapMultpCO2 = s_ipsc->rNumericArgs(3);
1476 35 : ZoneVolCapMultpGenContam = s_ipsc->rNumericArgs(4);
1477 : } else {
1478 : // multiplier values for the specified zone(s)
1479 12 : ZLItem = 0;
1480 :
1481 12 : Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(2), Zone);
1482 12 : if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) {
1483 0 : ZLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(2), ZoneList);
1484 : }
1485 12 : if (Item1 > 0) {
1486 12 : int ZoneNum = Item1;
1487 12 : Zone(ZoneNum).FlagCustomizedZoneCap = true;
1488 12 : Zone(ZoneNum).ZoneVolCapMultpSens = s_ipsc->rNumericArgs(1);
1489 12 : Zone(ZoneNum).ZoneVolCapMultpMoist = s_ipsc->rNumericArgs(2);
1490 12 : Zone(ZoneNum).ZoneVolCapMultpCO2 = s_ipsc->rNumericArgs(3);
1491 12 : Zone(ZoneNum).ZoneVolCapMultpGenContam = s_ipsc->rNumericArgs(4);
1492 0 : } else if (ZLItem > 0) {
1493 0 : for (int ZonePtrNum = 1; ZonePtrNum < ZoneList(ZLItem).NumOfZones; ZonePtrNum++) {
1494 0 : int ZoneNum = ZoneList(ZLItem).Zone(ZonePtrNum);
1495 0 : Zone(ZoneNum).FlagCustomizedZoneCap = true;
1496 0 : Zone(ZoneNum).ZoneVolCapMultpSens = s_ipsc->rNumericArgs(1);
1497 0 : Zone(ZoneNum).ZoneVolCapMultpMoist = s_ipsc->rNumericArgs(2);
1498 0 : Zone(ZoneNum).ZoneVolCapMultpCO2 = s_ipsc->rNumericArgs(3);
1499 0 : Zone(ZoneNum).ZoneVolCapMultpGenContam = s_ipsc->rNumericArgs(4);
1500 : }
1501 :
1502 : } else {
1503 0 : ShowSevereError(state,
1504 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
1505 0 : s_ipsc->cCurrentModuleObject,
1506 0 : s_ipsc->cAlphaArgs(1),
1507 0 : s_ipsc->cAlphaFieldNames(2),
1508 0 : s_ipsc->cAlphaArgs(2)));
1509 0 : ErrorsFound = true;
1510 : }
1511 : }
1512 : }
1513 :
1514 : // Assign default multiplier values to all the other zones
1515 168 : for (int ZoneNum = 1; ZoneNum <= NumOfZones; ZoneNum++) {
1516 130 : auto &Zone = state.dataHeatBal->Zone(ZoneNum);
1517 130 : if (!Zone.FlagCustomizedZoneCap) {
1518 118 : Zone.ZoneVolCapMultpSens = ZoneVolCapMultpSens;
1519 118 : Zone.ZoneVolCapMultpMoist = ZoneVolCapMultpMoist;
1520 118 : Zone.ZoneVolCapMultpCO2 = ZoneVolCapMultpCO2;
1521 118 : Zone.ZoneVolCapMultpGenContam = ZoneVolCapMultpGenContam;
1522 : }
1523 : }
1524 :
1525 : // Calculate the average multiplier value from all zones
1526 : {
1527 38 : Real64 ZoneVolCapMultpSens_temp = 0.0;
1528 38 : Real64 ZoneVolCapMultpMoist_temp = 0.0;
1529 38 : Real64 ZoneVolCapMultpCO2_temp = 0.0;
1530 38 : Real64 ZoneVolCapMultpGenContam_temp = 0.0;
1531 :
1532 168 : for (int ZoneNum = 1; ZoneNum <= NumOfZones; ZoneNum++) {
1533 130 : auto const &Zone = state.dataHeatBal->Zone(ZoneNum);
1534 130 : ZoneVolCapMultpSens_temp += Zone.ZoneVolCapMultpSens;
1535 130 : ZoneVolCapMultpMoist_temp += Zone.ZoneVolCapMultpMoist;
1536 130 : ZoneVolCapMultpCO2_temp += Zone.ZoneVolCapMultpCO2;
1537 130 : ZoneVolCapMultpGenContam_temp += Zone.ZoneVolCapMultpGenContam;
1538 : }
1539 :
1540 38 : if (NumOfZones > 0) {
1541 38 : ZoneVolCapMultpSens = ZoneVolCapMultpSens_temp / NumOfZones;
1542 38 : ZoneVolCapMultpMoist = ZoneVolCapMultpMoist_temp / NumOfZones;
1543 38 : ZoneVolCapMultpCO2 = ZoneVolCapMultpCO2_temp / NumOfZones;
1544 38 : ZoneVolCapMultpGenContam = ZoneVolCapMultpGenContam_temp / NumOfZones;
1545 : }
1546 : }
1547 : }
1548 :
1549 801 : print(state.files.eio, Header);
1550 801 : print(state.files.eio, Format_701, ZoneVolCapMultpSens, ZoneVolCapMultpMoist, ZoneVolCapMultpCO2, ZoneVolCapMultpGenContam);
1551 :
1552 801 : s_ipsc->cCurrentModuleObject = cZControlTypes((int)ZoneControlTypes::OTTStat);
1553 801 : state.dataZoneCtrls->NumOpTempControlledZones = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1554 :
1555 801 : if (state.dataZoneCtrls->NumOpTempControlledZones > 0) {
1556 3 : state.dataZoneCtrls->AnyOpTempControl = true;
1557 :
1558 6 : for (int idx = 1; idx <= state.dataZoneCtrls->NumOpTempControlledZones; ++idx) {
1559 6 : s_ip->getObjectItem(state,
1560 3 : s_ipsc->cCurrentModuleObject,
1561 : idx,
1562 3 : s_ipsc->cAlphaArgs,
1563 : NumAlphas,
1564 3 : s_ipsc->rNumericArgs,
1565 : NumNums,
1566 : IOStat,
1567 3 : s_ipsc->lNumericFieldBlanks,
1568 3 : s_ipsc->lAlphaFieldBlanks,
1569 3 : s_ipsc->cAlphaFieldNames,
1570 3 : s_ipsc->cNumericFieldNames);
1571 :
1572 3 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1573 :
1574 : // find matching name of ZONECONTROL:THERMOSTAT object
1575 3 : if ((found = Util::FindItem(s_ipsc->cAlphaArgs(1), TStatObjects)) != 0) {
1576 2 : auto const &TStatObjects = state.dataZoneCtrls->TStatObjects(found);
1577 8 : for (Item = 1; Item <= TStatObjects.NumOfZones; ++Item) {
1578 6 : TempControlledZoneNum = TStatObjects.TempControlledZoneStartPtr + Item - 1;
1579 6 : auto &TempControlledZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum);
1580 6 : if (state.dataZoneCtrls->NumTempControlledZones == 0) {
1581 0 : continue;
1582 : }
1583 6 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum);
1584 6 : tempZone.OpTempCtrl =
1585 6 : static_cast<DataZoneControls::TempCtrl>(getEnumValue(DataZoneControls::tempCtrlNamesUC, s_ipsc->cAlphaArgs(2)));
1586 :
1587 6 : if (Item == 1) {
1588 2 : if (tempZone.OpTempCtrl != DataZoneControls::TempCtrl::Constant &&
1589 0 : tempZone.OpTempCtrl != DataZoneControls::TempCtrl::Scheduled) {
1590 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
1591 0 : ErrorsFound = true;
1592 : }
1593 : }
1594 :
1595 6 : tempZone.FixedRadiativeFraction = s_ipsc->rNumericArgs(1);
1596 :
1597 6 : if (tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Scheduled) {
1598 0 : if (s_ipsc->lAlphaFieldBlanks(3)) {
1599 0 : if (Item == 1) {
1600 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
1601 0 : ErrorsFound = true;
1602 : }
1603 0 : } else if ((tempZone.opTempRadiativeFractionSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
1604 0 : if (Item == 1) {
1605 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
1606 0 : ErrorsFound = true;
1607 : }
1608 0 : } else if (!tempZone.opTempRadiativeFractionSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::Ex, 0.9)) {
1609 0 : if (Item == 1) {
1610 0 : Sched::ShowSevereBadMinMax(
1611 0 : state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), Clusive::In, 0.0, Clusive::Ex, 0.9);
1612 0 : ErrorsFound = true;
1613 : }
1614 : }
1615 :
1616 : } else { // !tempZone.OpTempCntrlModeScheduled
1617 :
1618 : // check validity of fixed radiative fraction
1619 6 : if (Item == 1) {
1620 2 : if (tempZone.FixedRadiativeFraction < 0.0) {
1621 0 : ShowSevereBadMin(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::In, 0.0);
1622 0 : ErrorsFound = true;
1623 2 : } else if (tempZone.FixedRadiativeFraction >= 0.9) {
1624 0 : ShowSevereBadMax(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::Ex, 0.9);
1625 0 : ErrorsFound = true;
1626 : }
1627 : }
1628 : }
1629 :
1630 : // added Jan, 2017 - Xuan Luo
1631 : // read adaptive comfort model and calculate adaptive thermal comfort setpoint
1632 6 : if (tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Constant || tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Scheduled) {
1633 6 : if (NumAlphas >= 4 && !s_ipsc->lAlphaFieldBlanks(4)) {
1634 : int adaptiveComfortModelTypeIndex =
1635 5 : Util::FindItem(s_ipsc->cAlphaArgs(4), AdaptiveComfortModelTypes, AdaptiveComfortModelTypes.isize());
1636 5 : if (!adaptiveComfortModelTypeIndex) {
1637 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
1638 0 : ErrorsFound = true;
1639 5 : } else if (adaptiveComfortModelTypeIndex != static_cast<int>(AdaptiveComfortModel::ADAP_NONE)) {
1640 5 : tempZone.AdaptiveComfortTempControl = true;
1641 5 : tempZone.AdaptiveComfortModelTypeIndex =
1642 5 : Util::FindItem(s_ipsc->cAlphaArgs(4), AdaptiveComfortModelTypes, AdaptiveComfortModelTypes.isize());
1643 5 : if (!s_ztpc->AdapComfortDailySetPointSchedule.initialized) {
1644 1 : Array1D<Real64> runningAverageASH(state.dataWeather->NumDaysInYear, 0.0);
1645 1 : Array1D<Real64> runningAverageCEN(state.dataWeather->NumDaysInYear, 0.0);
1646 1 : CalculateMonthlyRunningAverageDryBulb(state, runningAverageASH, runningAverageCEN);
1647 1 : CalculateAdaptiveComfortSetPointSchl(state, runningAverageASH, runningAverageCEN);
1648 1 : }
1649 : }
1650 : }
1651 : }
1652 :
1653 : // CurrentModuleObject='ZoneControl:Thermostat:OperativeTemperature'
1654 12 : SetupOutputVariable(state,
1655 : "Zone Thermostat Operative Temperature",
1656 : Constant::Units::C,
1657 6 : state.dataHeatBal->ZnAirRpt(tempZone.ActualZoneNum).ThermOperativeTemp,
1658 : OutputProcessor::TimeStepType::Zone,
1659 : OutputProcessor::StoreType::Average,
1660 6 : Zone(tempZone.ActualZoneNum).Name);
1661 : } // TStat Objects Loop
1662 :
1663 : // It might be in the TempControlledZones
1664 1 : } else if ((found = Util::FindItem(s_ipsc->cAlphaArgs(1), state.dataZoneCtrls->TempControlledZone)) != 0) {
1665 :
1666 1 : TempControlledZoneNum = found;
1667 1 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum);
1668 1 : tempZone.OpTempCtrl = static_cast<DataZoneControls::TempCtrl>(getEnumValue(DataZoneControls::tempCtrlNamesUC, s_ipsc->cAlphaArgs(2)));
1669 1 : if (tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Invalid || tempZone.OpTempCtrl == DataZoneControls::TempCtrl::None) {
1670 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
1671 0 : ErrorsFound = true;
1672 : }
1673 :
1674 1 : tempZone.FixedRadiativeFraction = s_ipsc->rNumericArgs(1);
1675 :
1676 1 : if (tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Scheduled) {
1677 0 : if (s_ipsc->lAlphaFieldBlanks(3)) {
1678 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
1679 0 : ErrorsFound = true;
1680 0 : } else if ((tempZone.opTempRadiativeFractionSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
1681 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
1682 0 : ErrorsFound = true;
1683 0 : } else if (!tempZone.opTempRadiativeFractionSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::Ex, 0.9)) {
1684 0 : Sched::ShowSevereBadMinMax(
1685 0 : state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), Clusive::In, 0.0, Clusive::Ex, 0.9);
1686 0 : ErrorsFound = true;
1687 : }
1688 :
1689 : } else { // !tempZone.OpTempCntrlModeScheduled
1690 :
1691 1 : if (tempZone.FixedRadiativeFraction < 0.0) {
1692 0 : ShowSevereBadMin(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::In, 0.0);
1693 0 : ErrorsFound = true;
1694 1 : } else if (tempZone.FixedRadiativeFraction >= 0.9) {
1695 0 : ShowSevereBadMax(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::Ex, 0.9);
1696 0 : ErrorsFound = true;
1697 : }
1698 : }
1699 :
1700 : // added Jan, 2017 - Xuan Luo
1701 : // read adaptive comfort model and calculate adaptive thermal comfort setpoint
1702 1 : if (tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Constant || tempZone.OpTempCtrl == DataZoneControls::TempCtrl::Scheduled) {
1703 1 : if (NumAlphas >= 4 && !s_ipsc->lAlphaFieldBlanks(4)) {
1704 : int adaptiveComfortModelTypeIndex =
1705 0 : Util::FindItem(s_ipsc->cAlphaArgs(4), AdaptiveComfortModelTypes, AdaptiveComfortModelTypes.isize());
1706 0 : if (!adaptiveComfortModelTypeIndex) {
1707 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
1708 0 : ErrorsFound = true;
1709 0 : } else if (adaptiveComfortModelTypeIndex != static_cast<int>(AdaptiveComfortModel::ADAP_NONE)) {
1710 0 : tempZone.AdaptiveComfortTempControl = true;
1711 0 : tempZone.AdaptiveComfortModelTypeIndex = adaptiveComfortModelTypeIndex;
1712 0 : if (!s_ztpc->AdapComfortDailySetPointSchedule.initialized) {
1713 0 : Array1D<Real64> runningAverageASH(state.dataWeather->NumDaysInYear, 0.0);
1714 0 : Array1D<Real64> runningAverageCEN(state.dataWeather->NumDaysInYear, 0.0);
1715 : // What does this accomplish?
1716 0 : CalculateMonthlyRunningAverageDryBulb(state, runningAverageASH, runningAverageCEN);
1717 0 : CalculateAdaptiveComfortSetPointSchl(state, runningAverageASH, runningAverageCEN);
1718 0 : }
1719 : }
1720 : }
1721 :
1722 : // CurrentModuleObject='ZoneControl:Thermostat:OperativeTemperature'
1723 2 : SetupOutputVariable(state,
1724 : "Zone Thermostat Operative Temperature",
1725 : Constant::Units::C,
1726 1 : state.dataHeatBal->ZnAirRpt(tempZone.ActualZoneNum).ThermOperativeTemp,
1727 : OutputProcessor::TimeStepType::Zone,
1728 : OutputProcessor::StoreType::Average,
1729 1 : Zone(tempZone.ActualZoneNum).Name);
1730 : }
1731 : // throw error
1732 : } else {
1733 0 : ShowSevereError(state,
1734 0 : format("{}={} invalid {} reference not found.",
1735 0 : s_ipsc->cCurrentModuleObject,
1736 0 : s_ipsc->cAlphaArgs(1),
1737 : cZControlTypes(static_cast<int>(ZoneControlTypes::TStat))));
1738 0 : ErrorsFound = true;
1739 : }
1740 : } // loop over NumOpTempControlledZones
1741 : } // NumOpTempControlledZones > 0
1742 :
1743 : // Overcool dehumidificaton GetInput starts here
1744 801 : s_ipsc->cCurrentModuleObject = cZControlTypes((int)ZoneControlTypes::TandHStat);
1745 801 : state.dataZoneCtrls->NumTempAndHumidityControlledZones = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1746 801 : if (state.dataZoneCtrls->NumTempAndHumidityControlledZones > 0) {
1747 1 : state.dataZoneCtrls->AnyZoneTempAndHumidityControl = true;
1748 :
1749 2 : for (int idx = 1; idx <= state.dataZoneCtrls->NumTempAndHumidityControlledZones; ++idx) {
1750 2 : s_ip->getObjectItem(state,
1751 1 : s_ipsc->cCurrentModuleObject,
1752 : idx,
1753 1 : s_ipsc->cAlphaArgs,
1754 : NumAlphas,
1755 1 : s_ipsc->rNumericArgs,
1756 : NumNums,
1757 : IOStat,
1758 1 : s_ipsc->lNumericFieldBlanks,
1759 1 : s_ipsc->lAlphaFieldBlanks,
1760 1 : s_ipsc->cAlphaFieldNames,
1761 1 : s_ipsc->cNumericFieldNames);
1762 :
1763 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1764 :
1765 : // find matching name of ZONECONTROL:THERMOSTAT object
1766 1 : found = Util::FindItem(s_ipsc->cAlphaArgs(1), TStatObjects);
1767 1 : if (found == 0) {
1768 : // It might be in the TempControlledZones
1769 0 : found = Util::FindItem(s_ipsc->cAlphaArgs(1), state.dataZoneCtrls->TempControlledZone);
1770 0 : if (found == 0) { // throw error
1771 0 : ShowSevereError(state,
1772 0 : format("{}={} invalid {} reference not found.",
1773 0 : s_ipsc->cCurrentModuleObject,
1774 0 : s_ipsc->cAlphaArgs(1),
1775 : cZControlTypes(static_cast<int>(ZoneControlTypes::TStat))));
1776 0 : ErrorsFound = true;
1777 : } else {
1778 0 : TempControlledZoneNum = found;
1779 0 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum);
1780 :
1781 0 : if (s_ipsc->lAlphaFieldBlanks(2)) {
1782 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
1783 0 : ErrorsFound = true;
1784 0 : } else if ((tempZone.dehumidifyingSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
1785 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
1786 0 : ErrorsFound = true;
1787 : }
1788 :
1789 0 : tempZone.OvercoolCtrl =
1790 0 : static_cast<DataZoneControls::TempCtrl>(getEnumValue(DataZoneControls::tempCtrlNamesUC, s_ipsc->cAlphaArgs(3)));
1791 0 : if (tempZone.OvercoolCtrl == DataZoneControls::TempCtrl::Invalid) {
1792 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
1793 0 : ErrorsFound = true;
1794 : }
1795 :
1796 0 : tempZone.ZoneOvercoolConstRange = s_ipsc->rNumericArgs(1);
1797 :
1798 0 : if (tempZone.OvercoolCtrl == DataZoneControls::TempCtrl::Scheduled) {
1799 0 : if (s_ipsc->lAlphaFieldBlanks(5)) {
1800 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(5));
1801 0 : ErrorsFound = true;
1802 0 : } else if ((tempZone.zoneOvercoolRangeSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(5))) == nullptr) {
1803 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5));
1804 0 : ErrorsFound = true;
1805 0 : } else if (!tempZone.zoneOvercoolRangeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 3.0)) {
1806 0 : Sched::ShowSevereBadMinMax(
1807 0 : state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5), Clusive::In, 0.0, Clusive::In, 3.0);
1808 0 : ErrorsFound = true;
1809 : }
1810 : } else { // !tempZone.OvercoolCntrlModeScheduled
1811 :
1812 0 : if (tempZone.ZoneOvercoolConstRange < 0.0) {
1813 0 : ShowSevereBadMin(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::In, 0.0);
1814 0 : ErrorsFound = true;
1815 0 : } else if (tempZone.ZoneOvercoolConstRange > 3.0) {
1816 0 : ShowSevereBadMax(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::In, 3.0);
1817 0 : ErrorsFound = true;
1818 : }
1819 :
1820 : // check Overcool Control Ratio limits
1821 0 : tempZone.ZoneOvercoolControlRatio = s_ipsc->rNumericArgs(2);
1822 0 : if (tempZone.ZoneOvercoolControlRatio < 0.0) {
1823 0 : ShowSevereBadMin(state, eoh, s_ipsc->cNumericFieldNames(2), s_ipsc->rNumericArgs(2), Clusive::In, 0.0);
1824 0 : ErrorsFound = true;
1825 : }
1826 : }
1827 : }
1828 :
1829 : } else {
1830 2 : for (int Item = 1; Item <= TStatObjects(found).NumOfZones; ++Item) {
1831 1 : TempControlledZoneNum = TStatObjects(found).TempControlledZoneStartPtr + Item - 1;
1832 :
1833 1 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneNum);
1834 :
1835 1 : if (s_ipsc->lAlphaFieldBlanks(2)) {
1836 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
1837 0 : ErrorsFound = true;
1838 1 : } else if ((tempZone.dehumidifyingSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(2))) == nullptr) {
1839 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
1840 0 : ErrorsFound = true;
1841 : }
1842 :
1843 : // This (i.e., using two booleans to represent three options) is a bad idiom
1844 1 : if (s_ipsc->cAlphaArgs(3) == "NONE") {
1845 0 : tempZone.OvercoolCtrl = DataZoneControls::TempCtrl::None;
1846 1 : } else if (s_ipsc->cAlphaArgs(3) != "OVERCOOL") {
1847 0 : if (Item == 1) {
1848 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
1849 0 : ErrorsFound = true;
1850 : }
1851 1 : } else if ((tempZone.OvercoolCtrl = static_cast<DataZoneControls::TempCtrl>(
1852 1 : getEnumValue(DataZoneControls::tempCtrlNamesUC, s_ipsc->cAlphaArgs(4)))) == DataZoneControls::TempCtrl::Invalid) {
1853 0 : if (Item == 1) {
1854 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
1855 0 : ErrorsFound = true;
1856 : }
1857 : }
1858 :
1859 1 : tempZone.ZoneOvercoolConstRange = s_ipsc->rNumericArgs(1);
1860 :
1861 1 : if (tempZone.OvercoolCtrl == DataZoneControls::TempCtrl::Scheduled) {
1862 0 : if (s_ipsc->lAlphaFieldBlanks(6)) {
1863 0 : if (Item == 1) {
1864 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(6));
1865 0 : ErrorsFound = true;
1866 : }
1867 0 : } else if ((tempZone.zoneOvercoolRangeSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
1868 0 : if (Item == 1) {
1869 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
1870 0 : ErrorsFound = true;
1871 : }
1872 0 : } else if (!tempZone.zoneOvercoolRangeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 3.0)) {
1873 0 : if (Item == 1) {
1874 0 : Sched::ShowSevereBadMinMax(
1875 0 : state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6), Clusive::In, 0.0, Clusive::In, 3.0);
1876 0 : ErrorsFound = true;
1877 : }
1878 : }
1879 : } else { // tempZone.OvercoolCntrlModeScheduled
1880 1 : if (Item == 1) {
1881 1 : if (tempZone.ZoneOvercoolConstRange < 0.0) {
1882 0 : ShowSevereBadMin(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::In, 0.0);
1883 0 : ErrorsFound = true;
1884 1 : } else if (tempZone.ZoneOvercoolConstRange > 3.0) {
1885 0 : ShowSevereBadMax(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::In, 3.0);
1886 0 : ErrorsFound = true;
1887 : }
1888 : }
1889 : }
1890 :
1891 1 : tempZone.ZoneOvercoolControlRatio = s_ipsc->rNumericArgs(2);
1892 : // check Overcool Control Ratio limits
1893 1 : if (tempZone.ZoneOvercoolControlRatio < 0.0) {
1894 0 : if (Item == 1) {
1895 0 : ShowSevereBadMin(state, eoh, s_ipsc->cNumericFieldNames(2), s_ipsc->rNumericArgs(2), Clusive::In, 0.0);
1896 0 : ErrorsFound = true;
1897 : }
1898 : }
1899 : } // TStat Objects Loop
1900 : } // found thermostat reference
1901 : } // loop over NumTempAndHumidityControlledZones
1902 : } // NumTempAndHumidityControlledZones > 0
1903 :
1904 : // Staged thermostat control inputs start
1905 801 : s_ipsc->cCurrentModuleObject = cZControlTypes((int)ZoneControlTypes::StagedDual);
1906 801 : NumStageControlledZones = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1907 801 : if (NumStageControlledZones > 0) {
1908 2 : state.dataZoneCtrls->StagedTStatObjects.allocate(NumStageControlledZones);
1909 : }
1910 :
1911 : // Pre-scan for use of Zone lists in TStat statements (i.e. Global application of TStat)
1912 801 : s_ztpc->NumStageCtrZone = 0;
1913 806 : for (Item = 1; Item <= NumStageControlledZones; ++Item) {
1914 10 : s_ip->getObjectItem(state,
1915 5 : s_ipsc->cCurrentModuleObject,
1916 : Item,
1917 5 : s_ipsc->cAlphaArgs,
1918 : NumAlphas,
1919 5 : s_ipsc->rNumericArgs,
1920 : NumNums,
1921 : IOStat,
1922 5 : s_ipsc->lNumericFieldBlanks,
1923 5 : s_ipsc->lAlphaFieldBlanks,
1924 5 : s_ipsc->cAlphaFieldNames,
1925 5 : s_ipsc->cNumericFieldNames);
1926 5 : Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
1927 :
1928 5 : state.dataZoneCtrls->StagedTStatObjects(Item).Name = s_ipsc->cAlphaArgs(1);
1929 5 : Item1 = Util::FindItemInList(s_ipsc->cAlphaArgs(2), Zone);
1930 5 : ZLItem = 0;
1931 5 : if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) {
1932 1 : ZLItem = Util::FindItemInList(s_ipsc->cAlphaArgs(2), ZoneList);
1933 : }
1934 5 : if (Item1 > 0) {
1935 4 : state.dataZoneCtrls->StagedTStatObjects(Item).StageControlledZoneStartPtr = s_ztpc->NumStageCtrZone + 1;
1936 4 : ++s_ztpc->NumStageCtrZone;
1937 4 : state.dataZoneCtrls->StagedTStatObjects(Item).NumOfZones = 1;
1938 4 : state.dataZoneCtrls->StagedTStatObjects(Item).ZoneListActive = false;
1939 4 : state.dataZoneCtrls->StagedTStatObjects(Item).ZoneOrZoneListPtr = Item1;
1940 1 : } else if (ZLItem > 0) {
1941 1 : state.dataZoneCtrls->StagedTStatObjects(Item).TempControlledZoneStartPtr = s_ztpc->NumStageCtrZone + 1;
1942 1 : s_ztpc->NumStageCtrZone += ZoneList(ZLItem).NumOfZones;
1943 1 : state.dataZoneCtrls->StagedTStatObjects(Item).NumOfZones = ZoneList(ZLItem).NumOfZones;
1944 1 : state.dataZoneCtrls->StagedTStatObjects(Item).ZoneListActive = true;
1945 1 : state.dataZoneCtrls->StagedTStatObjects(Item).ZoneOrZoneListPtr = ZLItem;
1946 : } else {
1947 0 : ShowSevereError(state,
1948 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.",
1949 0 : s_ipsc->cCurrentModuleObject,
1950 0 : s_ipsc->cAlphaArgs(1),
1951 0 : s_ipsc->cAlphaFieldNames(2),
1952 0 : s_ipsc->cAlphaArgs(2)));
1953 0 : ErrorsFound = true;
1954 : }
1955 : }
1956 :
1957 801 : if (ErrorsFound) {
1958 0 : ShowSevereError(state, format("GetStagedDualSetpoint: Errors with invalid names in {} objects.", s_ipsc->cCurrentModuleObject));
1959 0 : ShowContinueError(state, "...These will not be read in. Other errors may occur.");
1960 0 : s_ztpc->NumStageCtrZone = 0;
1961 : }
1962 :
1963 801 : if (s_ztpc->NumStageCtrZone > 0) {
1964 2 : state.dataZoneCtrls->StageControlledZone.allocate(s_ztpc->NumStageCtrZone);
1965 2 : state.dataZoneCtrls->StageZoneLogic.dimension(NumOfZones, false);
1966 :
1967 2 : int StageControlledZoneNum = 0;
1968 7 : for (Item = 1; Item <= NumStageControlledZones; ++Item) {
1969 10 : s_ip->getObjectItem(state,
1970 5 : s_ipsc->cCurrentModuleObject,
1971 : Item,
1972 5 : s_ipsc->cAlphaArgs,
1973 : NumAlphas,
1974 5 : s_ipsc->rNumericArgs,
1975 : NumNums,
1976 : IOStat,
1977 5 : s_ipsc->lNumericFieldBlanks,
1978 5 : s_ipsc->lAlphaFieldBlanks,
1979 5 : s_ipsc->cAlphaFieldNames,
1980 5 : s_ipsc->cNumericFieldNames);
1981 :
1982 5 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1983 :
1984 12 : for (Item1 = 1; Item1 <= state.dataZoneCtrls->StagedTStatObjects(Item).NumOfZones; ++Item1) {
1985 7 : ++StageControlledZoneNum;
1986 :
1987 7 : auto &stageZone = state.dataZoneCtrls->StageControlledZone(StageControlledZoneNum);
1988 :
1989 7 : if (state.dataZoneCtrls->StagedTStatObjects(Item).ZoneListActive) {
1990 3 : s_ipsc->cAlphaArgs(2) =
1991 6 : state.dataHeatBal->Zone(ZoneList(state.dataZoneCtrls->StagedTStatObjects(Item).ZoneOrZoneListPtr).Zone(Item1)).Name;
1992 : }
1993 7 : int ZoneAssigned = Util::FindItemInList(s_ipsc->cAlphaArgs(2),
1994 7 : state.dataZoneCtrls->StageControlledZone,
1995 : &DataZoneControls::ZoneStagedControls::ZoneName,
1996 : StageControlledZoneNum - 1);
1997 7 : if (ZoneAssigned == 0) {
1998 7 : stageZone.ZoneName = s_ipsc->cAlphaArgs(2);
1999 7 : if ((stageZone.ActualZoneNum = Util::FindItemInList(s_ipsc->cAlphaArgs(2), Zone)) == 0) {
2000 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
2001 0 : ErrorsFound = true;
2002 : } else {
2003 : // Zone(stageControlledZone%ActualZoneNum)%StageControlledZoneIndex =
2004 : // StageControlledZoneNum
2005 : }
2006 7 : state.dataZoneCtrls->StageZoneLogic(stageZone.ActualZoneNum) = true;
2007 : } else {
2008 0 : stageZone.ZoneName = s_ipsc->cAlphaArgs(2); // for continuity
2009 0 : ShowSevereError(state,
2010 0 : format("{}=\"{}\" invalid {}=\"{}\" zone previously assigned.",
2011 0 : s_ipsc->cCurrentModuleObject,
2012 0 : s_ipsc->cAlphaArgs(1),
2013 0 : s_ipsc->cAlphaFieldNames(2),
2014 0 : s_ipsc->cAlphaArgs(2)));
2015 0 : ShowContinueError(
2016 : state,
2017 0 : format("...Zone was previously assigned to Setpt=\"{}\".", state.dataZoneCtrls->StageControlledZone(ZoneAssigned).Name));
2018 0 : ErrorsFound = true;
2019 0 : continue;
2020 : }
2021 :
2022 7 : if (!state.dataZoneCtrls->StagedTStatObjects(Item).ZoneListActive) {
2023 4 : stageZone.Name = s_ipsc->cAlphaArgs(1);
2024 : } else {
2025 9 : CheckCreatedZoneItemName(
2026 : state,
2027 : RoutineName,
2028 3 : s_ipsc->cCurrentModuleObject,
2029 3 : state.dataHeatBal->Zone(ZoneList(state.dataZoneCtrls->StagedTStatObjects(Item).ZoneOrZoneListPtr).Zone(Item1)).Name,
2030 3 : ZoneList(state.dataZoneCtrls->StagedTStatObjects(Item).ZoneOrZoneListPtr).MaxZoneNameLength,
2031 3 : state.dataZoneCtrls->StagedTStatObjects(Item).Name,
2032 3 : state.dataZoneCtrls->StageControlledZone,
2033 : StageControlledZoneNum - 1,
2034 3 : stageZone.Name,
2035 : errFlag);
2036 3 : if (errFlag) {
2037 0 : ErrorsFound = true;
2038 : }
2039 : }
2040 :
2041 7 : stageZone.NumOfHeatStages = s_ipsc->rNumericArgs(1);
2042 7 : if (s_ipsc->rNumericArgs(1) < 1 || s_ipsc->rNumericArgs(1) > 4) {
2043 0 : ShowSevereBadMinMax(state, eoh, s_ipsc->cNumericFieldNames(1), s_ipsc->rNumericArgs(1), Clusive::In, 1, Clusive::In, 4);
2044 0 : ErrorsFound = true;
2045 : }
2046 :
2047 7 : if (s_ipsc->lAlphaFieldBlanks(3)) {
2048 0 : if (Item1 == 1) {
2049 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
2050 0 : ErrorsFound = true;
2051 : }
2052 7 : } else if ((stageZone.heatSetptBaseSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
2053 0 : if (Item1 == 1) {
2054 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
2055 0 : ErrorsFound = true;
2056 : }
2057 : }
2058 :
2059 7 : stageZone.HeatThroRange = s_ipsc->rNumericArgs(2);
2060 7 : if (s_ipsc->rNumericArgs(1) < 0.0) {
2061 0 : ShowSevereBadMin(state, eoh, s_ipsc->cNumericFieldNames(2), s_ipsc->rNumericArgs(2), Clusive::In, 0.0);
2062 0 : ErrorsFound = true;
2063 : }
2064 :
2065 7 : if (stageZone.NumOfHeatStages > 0) {
2066 7 : stageZone.HeatTOffset.allocate(stageZone.NumOfHeatStages);
2067 18 : for (i = 1; i <= stageZone.NumOfHeatStages; ++i) {
2068 11 : stageZone.HeatTOffset(i) = s_ipsc->rNumericArgs(2 + i);
2069 11 : if (s_ipsc->lNumericFieldBlanks(2 + i)) {
2070 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cNumericFieldNames(2 + i));
2071 0 : ErrorsFound = true;
2072 11 : } else if (s_ipsc->rNumericArgs(2 + i) > 0.0) {
2073 0 : ShowSevereBadMax(state, eoh, s_ipsc->cNumericFieldNames(2 + i), s_ipsc->rNumericArgs(2 + i), Clusive::In, 0.0);
2074 0 : ErrorsFound = true;
2075 : }
2076 :
2077 11 : if (i > 1) {
2078 4 : if (s_ipsc->rNumericArgs(2 + i) >= s_ipsc->rNumericArgs(1 + i)) {
2079 0 : ShowSevereCustom(state,
2080 : eoh,
2081 0 : format("{} = {:.1R} must be less than than {}={:.1R}",
2082 0 : s_ipsc->cNumericFieldNames(2 + i),
2083 0 : s_ipsc->rNumericArgs(2 + i),
2084 0 : s_ipsc->cNumericFieldNames(1 + i),
2085 0 : s_ipsc->rNumericArgs(1 + i)));
2086 0 : ErrorsFound = true;
2087 : }
2088 : }
2089 : }
2090 : }
2091 :
2092 7 : stageZone.NumOfCoolStages = s_ipsc->rNumericArgs(7);
2093 7 : if (s_ipsc->rNumericArgs(7) < 1 || s_ipsc->rNumericArgs(7) > 4) {
2094 0 : ShowSevereBadMinMax(state, eoh, s_ipsc->cNumericFieldNames(7), s_ipsc->rNumericArgs(7), Clusive::In, 1, Clusive::In, 4);
2095 0 : ErrorsFound = true;
2096 : }
2097 :
2098 7 : if (s_ipsc->lAlphaFieldBlanks(4)) {
2099 0 : if (Item1 == 1) {
2100 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(4));
2101 0 : ErrorsFound = true;
2102 : }
2103 7 : } else if ((stageZone.coolSetptBaseSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(4))) == nullptr) {
2104 0 : if (Item1 == 1) { // only show error on first of several if zone list
2105 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
2106 0 : ErrorsFound = true;
2107 : }
2108 : }
2109 :
2110 7 : stageZone.CoolThroRange = s_ipsc->rNumericArgs(8);
2111 7 : if (s_ipsc->rNumericArgs(8) < 0.0) {
2112 0 : ShowSevereBadMin(state, eoh, s_ipsc->cNumericFieldNames(8), s_ipsc->rNumericArgs(8), Clusive::In, 0.0);
2113 0 : ErrorsFound = true;
2114 : }
2115 :
2116 7 : if (stageZone.NumOfCoolStages > 0) {
2117 7 : stageZone.CoolTOffset.allocate(stageZone.NumOfCoolStages);
2118 26 : for (i = 1; i <= stageZone.NumOfCoolStages; ++i) {
2119 19 : stageZone.CoolTOffset(i) = s_ipsc->rNumericArgs(8 + i);
2120 19 : if (s_ipsc->lNumericFieldBlanks(8 + i)) {
2121 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cNumericFieldNames(8 + i));
2122 0 : ErrorsFound = true;
2123 19 : } else if (s_ipsc->rNumericArgs(8 + i) < 0.0) {
2124 0 : ShowSevereBadMin(state, eoh, s_ipsc->cNumericFieldNames(8 + i), s_ipsc->rNumericArgs(8 + i), Clusive::In, 0.0);
2125 0 : ErrorsFound = true;
2126 : }
2127 :
2128 19 : if (i > 1 && s_ipsc->rNumericArgs(8 + i) <= s_ipsc->rNumericArgs(7 + i)) {
2129 0 : ShowSevereCustom(state,
2130 : eoh,
2131 0 : format("{} = {:.1R} must be greater than {} = {:.1R}",
2132 0 : s_ipsc->cNumericFieldNames(8 + i),
2133 0 : s_ipsc->rNumericArgs(8 + i),
2134 0 : s_ipsc->cNumericFieldNames(7 + i),
2135 0 : s_ipsc->rNumericArgs(7 + i)));
2136 0 : ErrorsFound = true;
2137 : }
2138 : }
2139 : }
2140 : }
2141 : } // loop over NumStageControlledZones
2142 :
2143 2 : if ((s_ip->getNumObjectsFound(state, "AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed") == 0) &&
2144 1 : (s_ip->getNumObjectsFound(state, "AirLoopHVAC:UnitarySystem") == 0) &&
2145 3 : (s_ip->getNumObjectsFound(state, "SetpointManager:SingleZone:OneStageCooling") == 0) &&
2146 2 : (s_ip->getNumObjectsFound(state, "SetpointManager:SingleZone:OneStageHeating") == 0)) {
2147 0 : ShowWarningError(state,
2148 0 : format("{} is applicable to only selected HVAC objects which are missing from input.", s_ipsc->cCurrentModuleObject));
2149 0 : ShowContinueError(state, "Model should include one or more of the following objects: ");
2150 0 : ShowContinueError(state, "AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed, AirLoopHVAC:UnitarySystem, ");
2151 0 : ShowContinueError(
2152 : state, "SetpointManager:SingleZone:OneStageCooling, and/or SetpointManager:SingleZone:OneStageHeating. The simulation continues...");
2153 : }
2154 : } // NumStageControlledZones > 0
2155 :
2156 801 : if (ErrorsFound) {
2157 0 : ShowFatalError(state, "Errors getting Zone Control input data. Preceding condition(s) cause termination.");
2158 : }
2159 801 : }
2160 :
2161 1 : void CalculateMonthlyRunningAverageDryBulb(EnergyPlusData &state, Array1D<Real64> &runningAverageASH, Array1D<Real64> &runningAverageCEN)
2162 : {
2163 : // SUBROUTINE INFORMATION:
2164 : // AUTHOR Xuan Luo
2165 : // DATE WRITTEN January 2017
2166 : // RE-ENGINEERED na
2167 :
2168 : // PURPOSE OF THIS SUBROUTINE:
2169 : // This subroutine calculate the monthly running average dry bulb temperature;
2170 :
2171 : // Using/Aliasing
2172 :
2173 : using OutputReportTabular::GetColumnUsingTabs;
2174 : using OutputReportTabular::StrToReal;
2175 :
2176 : // SUBROUTINE PARAMETER DEFINITIONS:
2177 :
2178 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2179 : Real64 dryBulb;
2180 : Real64 avgDryBulb;
2181 :
2182 : std::string::size_type pos;
2183 :
2184 1 : Array1D<Real64> adaptiveTemp(state.dataWeather->NumDaysInYear, 0.0);
2185 1 : Array1D<Real64> dailyDryTemp(state.dataWeather->NumDaysInYear, 0.0);
2186 :
2187 1 : if (FileSystem::fileExists(state.files.inputWeatherFilePath.filePath)) {
2188 : // Read hourly dry bulb temperature first
2189 2 : auto epwFile = state.files.inputWeatherFilePath.open(state, "CalcThermalComfortAdaptive");
2190 10 : for (int i = 1; i <= 9; ++i) { // Headers
2191 9 : epwFile.readLine();
2192 : }
2193 366 : for (int i = 1; i <= state.dataWeather->NumDaysInYear; ++i) {
2194 365 : avgDryBulb = 0.0;
2195 9125 : for (int j = 1; j <= 24; ++j) {
2196 8760 : std::string epwLine = epwFile.readLine().data;
2197 61320 : for (int ind = 1; ind <= 6; ++ind) {
2198 52560 : pos = index(epwLine, ',');
2199 52560 : epwLine.erase(0, pos + 1);
2200 : }
2201 8760 : pos = index(epwLine, ',');
2202 8760 : dryBulb = StrToReal(epwLine.substr(0, pos));
2203 8760 : avgDryBulb += (dryBulb / 24.0);
2204 8760 : }
2205 365 : dailyDryTemp(i) = avgDryBulb;
2206 : }
2207 1 : epwFile.close();
2208 :
2209 : // Calculate monthly running average dry bulb temperature.
2210 1 : int dayOfYear = 0;
2211 366 : while (dayOfYear < state.dataWeather->NumDaysInYear) {
2212 365 : dayOfYear++;
2213 365 : int calcEndDay = dayOfYear - 1;
2214 365 : int calcStartDayASH = calcEndDay - 30;
2215 365 : int calcStartDayCEN = calcEndDay - 7;
2216 :
2217 365 : if (calcStartDayASH > 0) {
2218 10688 : for (int i = calcStartDayASH; i <= calcStartDayASH + 30; i++) {
2219 10354 : avgDryBulb = dailyDryTemp(i);
2220 10354 : runningAverageASH(dayOfYear) = runningAverageASH(dayOfYear) + avgDryBulb;
2221 : }
2222 334 : runningAverageASH(dayOfYear) /= 30;
2223 : } else { // Do special things for wrapping the epw
2224 31 : calcStartDayASH += state.dataWeather->NumDaysInYear;
2225 496 : for (int i = 1; i <= calcEndDay; i++) {
2226 465 : avgDryBulb = dailyDryTemp(i);
2227 465 : runningAverageASH(dayOfYear) = runningAverageASH(dayOfYear) + avgDryBulb;
2228 : }
2229 496 : for (int i = calcStartDayASH; i < state.dataWeather->NumDaysInYear; i++) {
2230 465 : avgDryBulb = dailyDryTemp(i);
2231 465 : runningAverageASH(dayOfYear) = runningAverageASH(dayOfYear) + avgDryBulb;
2232 : }
2233 31 : runningAverageASH(dayOfYear) /= 30;
2234 : }
2235 :
2236 365 : if (calcStartDayCEN > 0) {
2237 3213 : for (int i = calcStartDayCEN; i <= calcStartDayCEN + 7; i++) {
2238 2856 : avgDryBulb = dailyDryTemp(i);
2239 2856 : runningAverageCEN(dayOfYear) = runningAverageCEN(dayOfYear) + avgDryBulb;
2240 : }
2241 357 : runningAverageCEN(dayOfYear) /= 7;
2242 : } else { // Do special things for wrapping the epw
2243 8 : calcStartDayCEN += state.dataWeather->NumDaysInYear;
2244 36 : for (int i = 1; i <= calcEndDay; i++) {
2245 28 : avgDryBulb = dailyDryTemp(i);
2246 28 : runningAverageCEN(dayOfYear) = runningAverageCEN(dayOfYear) + avgDryBulb;
2247 : }
2248 36 : for (int i = calcStartDayCEN; i < state.dataWeather->NumDaysInYear; i++) {
2249 28 : avgDryBulb = dailyDryTemp(i);
2250 28 : runningAverageCEN(dayOfYear) = runningAverageCEN(dayOfYear) + avgDryBulb;
2251 : }
2252 8 : runningAverageCEN(dayOfYear) /= 7;
2253 : }
2254 : }
2255 1 : } else {
2256 0 : ShowFatalError(state,
2257 0 : format("CalcThermalComfortAdaptive: Could not open file {} for input (read). (File does not exist)",
2258 0 : state.files.inputWeatherFilePath.filePath));
2259 : }
2260 1 : }
2261 :
2262 1 : void CalculateAdaptiveComfortSetPointSchl(EnergyPlusData &state, Array1D<Real64> const &runningAverageASH, Array1D<Real64> const &runningAverageCEN)
2263 : {
2264 : // SUBROUTINE INFORMATION:
2265 : // AUTHOR Xuan Luo
2266 : // DATE WRITTEN January 2017
2267 : // RE-ENGINEERED na
2268 :
2269 : // PURPOSE OF THIS SUBROUTINE:
2270 : // This subroutine calculates the zone operative temperature setpoint using adaptive comfort model.
2271 :
2272 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2273 1 : int constexpr summerDesignDayTypeIndex(9);
2274 1 : Real64 GrossApproxAvgDryBulbDesignDay(0.0);
2275 :
2276 1 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
2277 :
2278 3 : for (size_t i = 1; i <= state.dataWeather->DesDayInput.size(); i++) {
2279 : // Summer design day
2280 2 : if (state.dataWeather->DesDayInput(i).DayType == summerDesignDayTypeIndex) {
2281 1 : GrossApproxAvgDryBulbDesignDay = (state.dataWeather->DesDayInput(i).MaxDryBulb +
2282 1 : (state.dataWeather->DesDayInput(i).MaxDryBulb - state.dataWeather->DesDayInput(i).DailyDBRange)) /
2283 : 2.0;
2284 1 : if (GrossApproxAvgDryBulbDesignDay > 10 && GrossApproxAvgDryBulbDesignDay < 33.5) {
2285 1 : s_ztpc->AdapComfortSetPointSummerDesDay[0] = 0.31 * GrossApproxAvgDryBulbDesignDay + 17.8;
2286 1 : s_ztpc->AdapComfortSetPointSummerDesDay[1] = 0.31 * GrossApproxAvgDryBulbDesignDay + 20.3;
2287 1 : s_ztpc->AdapComfortSetPointSummerDesDay[2] = 0.31 * GrossApproxAvgDryBulbDesignDay + 21.3;
2288 : }
2289 1 : if (GrossApproxAvgDryBulbDesignDay > 10 && GrossApproxAvgDryBulbDesignDay < 30) {
2290 1 : s_ztpc->AdapComfortSetPointSummerDesDay[3] = 0.33 * GrossApproxAvgDryBulbDesignDay + 18.8;
2291 1 : s_ztpc->AdapComfortSetPointSummerDesDay[4] = 0.33 * GrossApproxAvgDryBulbDesignDay + 20.8;
2292 : ; // What is this?
2293 1 : s_ztpc->AdapComfortSetPointSummerDesDay[5] = 0.33 * GrossApproxAvgDryBulbDesignDay + 21.8;
2294 : ;
2295 1 : s_ztpc->AdapComfortSetPointSummerDesDay[6] = 0.33 * GrossApproxAvgDryBulbDesignDay + 22.8;
2296 : ;
2297 : }
2298 : }
2299 : }
2300 :
2301 1 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Central.allocate(state.dataWeather->NumDaysInYear);
2302 1 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_90.allocate(state.dataWeather->NumDaysInYear);
2303 1 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_80.allocate(state.dataWeather->NumDaysInYear);
2304 1 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Central.allocate(state.dataWeather->NumDaysInYear);
2305 1 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_I.allocate(state.dataWeather->NumDaysInYear);
2306 1 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_II.allocate(state.dataWeather->NumDaysInYear);
2307 1 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_III.allocate(state.dataWeather->NumDaysInYear);
2308 :
2309 : // Calculate the set points based on different models, set flag as -1 when running average temperature is not in the range.
2310 366 : for (int day = 1; day <= state.dataWeather->NumDaysInYear; day++) {
2311 365 : if (runningAverageASH(day) > 10 && runningAverageASH(day) < 33.5) {
2312 365 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Central(day) = 0.31 * runningAverageASH(day) + 17.8;
2313 365 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_90(day) = 0.31 * runningAverageASH(day) + 20.3;
2314 365 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_80(day) = 0.31 * runningAverageASH(day) + 21.3;
2315 : } else {
2316 0 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Central(day) = -1;
2317 0 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_90(day) = -1;
2318 0 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_80(day) = -1;
2319 : }
2320 365 : if (runningAverageCEN(day) > 10 && runningAverageCEN(day) < 30) {
2321 216 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Central(day) = 0.33 * runningAverageCEN(day) + 18.8;
2322 216 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_I(day) = 0.33 * runningAverageCEN(day) + 20.8;
2323 216 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_II(day) = 0.33 * runningAverageCEN(day) + 21.8;
2324 216 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_III(day) = 0.33 * runningAverageCEN(day) + 22.8;
2325 : } else {
2326 149 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Central(day) = -1;
2327 149 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_I(day) = -1;
2328 149 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_II(day) = -1;
2329 149 : s_ztpc->AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_III(day) = -1;
2330 : }
2331 : }
2332 1 : s_ztpc->AdapComfortDailySetPointSchedule.initialized = true;
2333 1 : }
2334 :
2335 14518428 : void InitZoneAirSetPoints(EnergyPlusData &state)
2336 : {
2337 :
2338 : // SUBROUTINE INFORMATION:
2339 : // AUTHOR Russell Taylor
2340 : // DATE WRITTEN September 1998
2341 : // MODIFIED November 2004, M. J. Witte additional report variables
2342 : // MODIFIED L.Gu, May 2006
2343 : // RE-ENGINEERED na
2344 :
2345 : // PURPOSE OF THIS SUBROUTINE:
2346 : // This subroutine initializes the data for the zone air setpoints.
2347 :
2348 : // METHODOLOGY EMPLOYED:
2349 : // Uses the status flags to trigger events.
2350 :
2351 : // SUBROUTINE PARAMETER DEFINITIONS:
2352 : static constexpr std::string_view RoutineName("InitZoneAirSetpoints: ");
2353 :
2354 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2355 : bool FirstSurfFlag;
2356 : int TRefFlag; // Flag for Reference Temperature process in Zones
2357 :
2358 14518428 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
2359 14518428 : auto &s_hbfs = state.dataHeatBalFanSys;
2360 :
2361 14518428 : auto &ZoneList = state.dataHeatBal->ZoneList;
2362 14518428 : auto &TempControlType = state.dataHeatBalFanSys->TempControlType;
2363 14518428 : auto &TempControlTypeRpt = state.dataHeatBalFanSys->TempControlTypeRpt;
2364 14518428 : int NumOfZones = state.dataGlobal->NumOfZones;
2365 :
2366 14518428 : if (s_ztpc->InitZoneAirSetPointsOneTimeFlag) {
2367 801 : s_hbfs->zoneTstatSetpts.allocate(NumOfZones);
2368 :
2369 801 : state.dataHeatBalFanSys->LoadCorrectionFactor.dimension(NumOfZones, 0.0);
2370 801 : TempControlType.dimension(NumOfZones, HVAC::SetptType::Uncontrolled);
2371 801 : TempControlTypeRpt.dimension(NumOfZones, 0);
2372 801 : if (state.dataZoneCtrls->NumComfortControlledZones > 0) {
2373 1 : state.dataHeatBalFanSys->ComfortControlType.dimension(NumOfZones, HVAC::SetptType::Uncontrolled);
2374 1 : state.dataHeatBalFanSys->ComfortControlTypeRpt.dimension(NumOfZones, 0);
2375 1 : state.dataHeatBalFanSys->ZoneComfortControlsFanger.allocate(NumOfZones);
2376 : }
2377 801 : state.dataZoneEnergyDemand->Setback.dimension(NumOfZones, false);
2378 801 : state.dataZoneEnergyDemand->DeadBandOrSetback.dimension(NumOfZones, false);
2379 801 : state.dataZoneEnergyDemand->CurDeadBandOrSetback.dimension(NumOfZones, false);
2380 :
2381 801 : state.dataHeatBal->ZoneListSNLoadHeatEnergy.dimension(state.dataHeatBal->NumOfZoneLists, 0.0);
2382 801 : state.dataHeatBal->ZoneListSNLoadCoolEnergy.dimension(state.dataHeatBal->NumOfZoneLists, 0.0);
2383 801 : state.dataHeatBal->ZoneListSNLoadHeatRate.dimension(state.dataHeatBal->NumOfZoneLists, 0.0);
2384 801 : state.dataHeatBal->ZoneListSNLoadCoolRate.dimension(state.dataHeatBal->NumOfZoneLists, 0.0);
2385 :
2386 801 : state.dataHeatBal->ZoneGroupSNLoadHeatEnergy.dimension(state.dataHeatBal->NumOfZoneGroups, 0.0);
2387 801 : state.dataHeatBal->ZoneGroupSNLoadCoolEnergy.dimension(state.dataHeatBal->NumOfZoneGroups, 0.0);
2388 801 : state.dataHeatBal->ZoneGroupSNLoadHeatRate.dimension(state.dataHeatBal->NumOfZoneGroups, 0.0);
2389 801 : state.dataHeatBal->ZoneGroupSNLoadCoolRate.dimension(state.dataHeatBal->NumOfZoneGroups, 0.0);
2390 :
2391 : // Hybrid modeling
2392 801 : state.dataHeatBalFanSys->PreviousMeasuredZT1.dimension(NumOfZones, 0.0);
2393 801 : state.dataHeatBalFanSys->PreviousMeasuredZT2.dimension(NumOfZones, 0.0);
2394 801 : state.dataHeatBalFanSys->PreviousMeasuredZT3.dimension(NumOfZones, 0.0);
2395 801 : state.dataHeatBalFanSys->PreviousMeasuredHumRat1.dimension(NumOfZones, 0.0);
2396 801 : state.dataHeatBalFanSys->PreviousMeasuredHumRat2.dimension(NumOfZones, 0.0);
2397 801 : state.dataHeatBalFanSys->PreviousMeasuredHumRat3.dimension(NumOfZones, 0.0);
2398 :
2399 : // Allocate Derived Types
2400 801 : state.dataZoneEnergyDemand->ZoneSysEnergyDemand.allocate(NumOfZones);
2401 801 : state.dataZoneEnergyDemand->ZoneSysMoistureDemand.allocate(NumOfZones);
2402 801 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
2403 2 : state.dataZoneEnergyDemand->spaceSysEnergyDemand.allocate(state.dataGlobal->numSpaces);
2404 2 : state.dataZoneEnergyDemand->spaceSysMoistureDemand.allocate(state.dataGlobal->numSpaces);
2405 : }
2406 :
2407 6002 : for (int zoneNum = 1; zoneNum <= NumOfZones; ++zoneNum) {
2408 5201 : bool FirstSurfFlag = true;
2409 10414 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
2410 5213 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
2411 50795 : for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
2412 45582 : if (FirstSurfFlag) {
2413 5201 : TRefFlag = state.dataSurface->SurfTAirRef(SurfNum);
2414 5201 : FirstSurfFlag = false;
2415 : }
2416 : // for each particular zone, the reference air temperature(s) should be the same
2417 : // (either mean air, bulk air, or supply air temp).
2418 45582 : if (state.dataSurface->SurfTAirRef(SurfNum) != TRefFlag) {
2419 0 : ShowWarningError(state,
2420 0 : format("Different reference air temperatures for difference surfaces encountered in zone {}",
2421 0 : state.dataHeatBal->Zone(zoneNum).Name));
2422 : }
2423 : }
2424 5201 : }
2425 : }
2426 :
2427 : // CurrentModuleObject='Zone'
2428 6002 : for (int zoneNum = 1; zoneNum <= NumOfZones; ++zoneNum) {
2429 5201 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
2430 5201 : s_ztpc->zoneHeatBalance(zoneNum).setUpOutputVars(state, DataStringGlobals::zonePrefix, thisZone.Name);
2431 5201 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation) {
2432 28 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
2433 16 : s_ztpc->spaceHeatBalance(spaceNum).setUpOutputVars(
2434 16 : state, DataStringGlobals::spacePrefix, state.dataHeatBal->space(spaceNum).Name);
2435 12 : }
2436 : }
2437 5201 : bool staged = false;
2438 5201 : if (allocated(state.dataZoneCtrls->StageZoneLogic)) {
2439 8 : staged = state.dataZoneCtrls->StageZoneLogic(zoneNum);
2440 : }
2441 : // If not doSpaceHeatBalanceSimulation then meter zones, not spaces
2442 5201 : bool attachMeters = !state.dataHeatBal->doSpaceHeatBalanceSimulation;
2443 5201 : state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).setUpOutputVars(
2444 5201 : state, DataStringGlobals::zonePrefix, thisZone.Name, staged, attachMeters, thisZone.Multiplier, thisZone.ListMultiplier);
2445 5201 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation) {
2446 : // If doSpaceHeatBalanceSimulation then meter spaces, not zones
2447 12 : attachMeters = state.dataHeatBal->doSpaceHeatBalanceSimulation;
2448 28 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
2449 16 : state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).setUpOutputVars(state,
2450 : DataStringGlobals::spacePrefix,
2451 16 : state.dataHeatBal->space(spaceNum).Name,
2452 : staged,
2453 : attachMeters,
2454 : thisZone.Multiplier,
2455 : thisZone.ListMultiplier);
2456 12 : }
2457 : }
2458 5201 : state.dataZoneEnergyDemand->ZoneSysMoistureDemand(zoneNum).setUpOutputVars(state, DataStringGlobals::zonePrefix, thisZone.Name);
2459 5201 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation) {
2460 28 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
2461 16 : state.dataZoneEnergyDemand->spaceSysMoistureDemand(spaceNum).setUpOutputVars(
2462 16 : state, DataStringGlobals::spacePrefix, state.dataHeatBal->space(spaceNum).Name);
2463 12 : }
2464 : }
2465 10402 : SetupOutputVariable(state,
2466 : "Zone Thermostat Air Temperature",
2467 : Constant::Units::C,
2468 5201 : state.dataHeatBalFanSys->TempTstatAir(zoneNum),
2469 : OutputProcessor::TimeStepType::System,
2470 : OutputProcessor::StoreType::Average,
2471 5201 : thisZone.Name);
2472 5201 : SetupOutputVariable(state,
2473 : "Zone Thermostat Control Type",
2474 : Constant::Units::None,
2475 5201 : state.dataHeatBalFanSys->TempControlTypeRpt(zoneNum),
2476 : OutputProcessor::TimeStepType::Zone,
2477 : OutputProcessor::StoreType::Average,
2478 5201 : thisZone.Name);
2479 10402 : SetupOutputVariable(state,
2480 : "Zone Thermostat Heating Setpoint Temperature",
2481 : Constant::Units::C,
2482 5201 : s_hbfs->zoneTstatSetpts(zoneNum).setptLo,
2483 : OutputProcessor::TimeStepType::System,
2484 : OutputProcessor::StoreType::Average,
2485 5201 : thisZone.Name);
2486 10402 : SetupOutputVariable(state,
2487 : "Zone Thermostat Cooling Setpoint Temperature",
2488 : Constant::Units::C,
2489 5201 : s_hbfs->zoneTstatSetpts(zoneNum).setptHi,
2490 : OutputProcessor::TimeStepType::System,
2491 : OutputProcessor::StoreType::Average,
2492 5201 : thisZone.Name);
2493 10402 : SetupOutputVariable(state,
2494 : "Zone Adaptive Comfort Operative Temperature Set Point",
2495 : Constant::Units::C,
2496 5201 : s_hbfs->zoneTstatSetpts(zoneNum).setptAdapComfortCool,
2497 : OutputProcessor::TimeStepType::Zone,
2498 : OutputProcessor::StoreType::Average,
2499 5201 : thisZone.Name);
2500 10402 : SetupOutputVariable(state,
2501 : "Zone Predicted Sensible Load Room Air Correction Factor",
2502 : Constant::Units::None,
2503 5201 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum),
2504 : OutputProcessor::TimeStepType::System,
2505 : OutputProcessor::StoreType::Average,
2506 5201 : thisZone.Name);
2507 : } // zoneNum
2508 :
2509 : // Thermal comfort control output
2510 801 : if (state.dataZoneCtrls->NumComfortControlledZones > 0) {
2511 : // CurrentModuleObject='ZoneControl:Thermostat:ThermalComfort'
2512 2 : for (int Loop = 1; Loop <= state.dataZoneCtrls->NumComfortControlledZones; ++Loop) {
2513 1 : int zoneNum = state.dataZoneCtrls->ComfortControlledZone(Loop).ActualZoneNum;
2514 1 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
2515 1 : SetupOutputVariable(state,
2516 : "Zone Thermal Comfort Control Type",
2517 : Constant::Units::None,
2518 1 : state.dataHeatBalFanSys->ComfortControlTypeRpt(zoneNum),
2519 : OutputProcessor::TimeStepType::Zone,
2520 : OutputProcessor::StoreType::Average,
2521 1 : thisZone.Name);
2522 2 : SetupOutputVariable(state,
2523 : "Zone Thermal Comfort Control Fanger Low Setpoint PMV",
2524 : Constant::Units::None,
2525 1 : state.dataHeatBalFanSys->ZoneComfortControlsFanger(zoneNum).LowPMV,
2526 : OutputProcessor::TimeStepType::Zone,
2527 : OutputProcessor::StoreType::Average,
2528 1 : thisZone.Name);
2529 2 : SetupOutputVariable(state,
2530 : "Zone Thermal Comfort Control Fanger High Setpoint PMV",
2531 : Constant::Units::None,
2532 1 : state.dataHeatBalFanSys->ZoneComfortControlsFanger(zoneNum).HighPMV,
2533 : OutputProcessor::TimeStepType::Zone,
2534 : OutputProcessor::StoreType::Average,
2535 1 : thisZone.Name);
2536 : }
2537 : }
2538 :
2539 : // CurrentModuleObject='ZoneList'
2540 849 : for (int Loop = 1; Loop <= state.dataHeatBal->NumOfZoneLists; ++Loop) {
2541 48 : auto &zoneList = state.dataHeatBal->ZoneList(Loop);
2542 96 : SetupOutputVariable(state,
2543 : "Zone List Sensible Heating Energy",
2544 : Constant::Units::J,
2545 48 : state.dataHeatBal->ZoneListSNLoadHeatEnergy(Loop),
2546 : OutputProcessor::TimeStepType::System,
2547 : OutputProcessor::StoreType::Sum,
2548 48 : zoneList.Name);
2549 96 : SetupOutputVariable(state,
2550 : "Zone List Sensible Cooling Energy",
2551 : Constant::Units::J,
2552 48 : state.dataHeatBal->ZoneListSNLoadCoolEnergy(Loop),
2553 : OutputProcessor::TimeStepType::System,
2554 : OutputProcessor::StoreType::Sum,
2555 48 : zoneList.Name);
2556 96 : SetupOutputVariable(state,
2557 : "Zone List Sensible Heating Rate",
2558 : Constant::Units::W,
2559 48 : state.dataHeatBal->ZoneListSNLoadHeatRate(Loop),
2560 : OutputProcessor::TimeStepType::System,
2561 : OutputProcessor::StoreType::Average,
2562 48 : zoneList.Name);
2563 96 : SetupOutputVariable(state,
2564 : "Zone List Sensible Cooling Rate",
2565 : Constant::Units::W,
2566 48 : state.dataHeatBal->ZoneListSNLoadCoolRate(Loop),
2567 : OutputProcessor::TimeStepType::System,
2568 : OutputProcessor::StoreType::Average,
2569 48 : zoneList.Name);
2570 : } // Loop
2571 :
2572 : // CurrentModuleObject='ZoneGroup'
2573 805 : for (int Loop = 1; Loop <= state.dataHeatBal->NumOfZoneGroups; ++Loop) {
2574 4 : auto &zoneGroup = state.dataHeatBal->ZoneGroup(Loop);
2575 8 : SetupOutputVariable(state,
2576 : "Zone Group Sensible Heating Energy",
2577 : Constant::Units::J,
2578 4 : state.dataHeatBal->ZoneGroupSNLoadHeatEnergy(Loop),
2579 : OutputProcessor::TimeStepType::System,
2580 : OutputProcessor::StoreType::Sum,
2581 4 : zoneGroup.Name);
2582 8 : SetupOutputVariable(state,
2583 : "Zone Group Sensible Cooling Energy",
2584 : Constant::Units::J,
2585 4 : state.dataHeatBal->ZoneGroupSNLoadCoolEnergy(Loop),
2586 : OutputProcessor::TimeStepType::System,
2587 : OutputProcessor::StoreType::Sum,
2588 4 : zoneGroup.Name);
2589 8 : SetupOutputVariable(state,
2590 : "Zone Group Sensible Heating Rate",
2591 : Constant::Units::W,
2592 4 : state.dataHeatBal->ZoneGroupSNLoadHeatRate(Loop),
2593 : OutputProcessor::TimeStepType::System,
2594 : OutputProcessor::StoreType::Average,
2595 4 : zoneGroup.Name);
2596 8 : SetupOutputVariable(state,
2597 : "Zone Group Sensible Cooling Rate",
2598 : Constant::Units::W,
2599 4 : state.dataHeatBal->ZoneGroupSNLoadCoolRate(Loop),
2600 : OutputProcessor::TimeStepType::System,
2601 : OutputProcessor::StoreType::Average,
2602 4 : zoneGroup.Name);
2603 : } // Loop
2604 :
2605 801 : s_ztpc->InitZoneAirSetPointsOneTimeFlag = false;
2606 : }
2607 :
2608 : // Do the Begin Environment initializations
2609 14518428 : if (s_ztpc->MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
2610 57005 : for (auto &thisZoneHB : s_ztpc->zoneHeatBalance) {
2611 50509 : thisZoneHB.beginEnvironmentInit(state);
2612 6496 : }
2613 6496 : if (state.dataHeatBal->doSpaceHeatBalance) {
2614 209 : for (auto &thisSpaceHB : s_ztpc->spaceHeatBalance) {
2615 186 : thisSpaceHB.beginEnvironmentInit(state);
2616 23 : }
2617 : }
2618 :
2619 57005 : for (auto &zoneTstatSetpt : s_hbfs->zoneTstatSetpts) {
2620 50509 : zoneTstatSetpt.setpt = zoneTstatSetpt.setptAdapComfortCool = zoneTstatSetpt.setptLo = zoneTstatSetpt.setptHi = 0.0;
2621 : }
2622 :
2623 6496 : state.dataHeatBalFanSys->LoadCorrectionFactor = 1.0;
2624 6496 : TempControlType = HVAC::SetptType::Uncontrolled;
2625 57005 : for (auto &e : state.dataZoneEnergyDemand->ZoneSysEnergyDemand) {
2626 50509 : e.beginEnvironmentInit();
2627 6496 : }
2628 57005 : for (auto &e : state.dataZoneEnergyDemand->ZoneSysMoistureDemand) {
2629 50509 : e.beginEnvironmentInit();
2630 6496 : }
2631 6496 : if (state.dataHeatBal->doSpaceHeatBalance) {
2632 209 : for (auto &e : state.dataZoneEnergyDemand->spaceSysEnergyDemand) {
2633 186 : e.beginEnvironmentInit();
2634 23 : }
2635 209 : for (auto &e : state.dataZoneEnergyDemand->spaceSysMoistureDemand) {
2636 186 : e.beginEnvironmentInit();
2637 23 : }
2638 : }
2639 :
2640 6496 : state.dataZoneEnergyDemand->DeadBandOrSetback = false;
2641 :
2642 57005 : for (auto &e : state.dataHeatBal->Zone) {
2643 50509 : e.NoHeatToReturnAir = false;
2644 6496 : }
2645 6496 : state.dataHeatBalFanSys->PreviousMeasuredZT1 = 0.0; // Hybrid modeling
2646 6496 : state.dataHeatBalFanSys->PreviousMeasuredZT2 = 0.0; // Hybrid modeling
2647 6496 : state.dataHeatBalFanSys->PreviousMeasuredZT3 = 0.0; // Hybrid modeling
2648 6496 : state.dataHeatBalFanSys->PreviousMeasuredHumRat1 = 0.0; // Hybrid modeling
2649 6496 : state.dataHeatBalFanSys->PreviousMeasuredHumRat2 = 0.0; // Hybrid modeling
2650 6496 : state.dataHeatBalFanSys->PreviousMeasuredHumRat3 = 0.0; // Hybrid modeling
2651 :
2652 6496 : s_ztpc->MyEnvrnFlag = false;
2653 : }
2654 :
2655 14518428 : if (!state.dataGlobal->BeginEnvrnFlag) {
2656 14460215 : s_ztpc->MyEnvrnFlag = true;
2657 : }
2658 :
2659 : // Do the Begin Day initializations
2660 14518428 : if (s_ztpc->MyDayFlag && state.dataGlobal->BeginDayFlag) {
2661 25938 : s_ztpc->MyDayFlag = false;
2662 : }
2663 :
2664 14518428 : if (!state.dataGlobal->BeginDayFlag) {
2665 14361828 : s_ztpc->MyDayFlag = true;
2666 : }
2667 :
2668 111976506 : for (int Loop = 1; Loop <= state.dataZoneCtrls->NumTempControlledZones; ++Loop) {
2669 97458078 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(Loop);
2670 97458078 : if (state.dataZoneEquip->ZoneEquipInputsFilled && !s_ztpc->ControlledZonesChecked) {
2671 4333 : if (!VerifyControlledZoneForThermostat(state, tempZone.ZoneName)) {
2672 0 : ShowSevereError(
2673 : state,
2674 0 : format("{}Zone=\"{}\" has specified a Thermostatic control but is not a controlled zone.", RoutineName, tempZone.ZoneName));
2675 0 : ShowContinueError(state, "...must have a ZoneHVAC:EquipmentConnections specification for this zone.");
2676 0 : s_ztpc->ErrorsFound = true;
2677 : }
2678 : }
2679 :
2680 97458078 : if (tempZone.ManageDemand) {
2681 0 : int ZoneNum = tempZone.ActualZoneNum;
2682 :
2683 0 : auto &zoneTstatSetpt = s_hbfs->zoneTstatSetpts(ZoneNum);
2684 :
2685 0 : switch (TempControlType(ZoneNum)) {
2686 0 : case HVAC::SetptType::SingleHeat: {
2687 0 : if (zoneTstatSetpt.setpt > tempZone.HeatingResetLimit) {
2688 0 : zoneTstatSetpt.setptLo = zoneTstatSetpt.setpt = tempZone.HeatingResetLimit;
2689 : }
2690 0 : } break;
2691 :
2692 0 : case HVAC::SetptType::SingleCool: {
2693 0 : if (zoneTstatSetpt.setpt < tempZone.CoolingResetLimit) {
2694 0 : zoneTstatSetpt.setptHi = zoneTstatSetpt.setpt = tempZone.CoolingResetLimit;
2695 : }
2696 0 : } break;
2697 :
2698 0 : case HVAC::SetptType::SingleHeatCool: {
2699 0 : if ((zoneTstatSetpt.setpt > tempZone.HeatingResetLimit) || (zoneTstatSetpt.setpt < tempZone.CoolingResetLimit)) {
2700 :
2701 0 : TempControlType(ZoneNum) = HVAC::SetptType::DualHeatCool;
2702 0 : TempControlTypeRpt(ZoneNum) = static_cast<int>(TempControlType(ZoneNum));
2703 0 : zoneTstatSetpt.setptHi = zoneTstatSetpt.setptLo = zoneTstatSetpt.setpt;
2704 :
2705 0 : if (zoneTstatSetpt.setptLo > tempZone.HeatingResetLimit) {
2706 0 : zoneTstatSetpt.setptLo = tempZone.HeatingResetLimit;
2707 : }
2708 0 : if (zoneTstatSetpt.setptHi < tempZone.CoolingResetLimit) {
2709 0 : zoneTstatSetpt.setptHi = tempZone.CoolingResetLimit;
2710 : }
2711 : }
2712 0 : } break;
2713 :
2714 0 : case HVAC::SetptType::DualHeatCool: {
2715 0 : if (zoneTstatSetpt.setptLo > tempZone.HeatingResetLimit) {
2716 0 : zoneTstatSetpt.setptLo = tempZone.HeatingResetLimit;
2717 : }
2718 0 : if (zoneTstatSetpt.setptHi < tempZone.CoolingResetLimit) {
2719 0 : zoneTstatSetpt.setptHi = tempZone.CoolingResetLimit;
2720 : }
2721 0 : } break;
2722 :
2723 0 : default: {
2724 0 : } break;
2725 : } // switch (setptType)
2726 : }
2727 : }
2728 :
2729 14528700 : for (int Loop = 1; Loop <= state.dataZoneCtrls->NumComfortControlledZones; ++Loop) {
2730 10272 : auto const &comfortZone = state.dataZoneCtrls->ComfortControlledZone(Loop);
2731 10272 : if (state.dataZoneEquip->ZoneEquipInputsFilled && !s_ztpc->ControlledZonesChecked) {
2732 1 : if (!VerifyControlledZoneForThermostat(state, comfortZone.ZoneName)) {
2733 0 : ShowSevereError(
2734 0 : state, format("{}Zone=\"{}\" has specified a Comfort control but is not a controlled zone.", RoutineName, comfortZone.ZoneName));
2735 0 : ShowContinueError(state, "...must have a ZoneHVAC:EquipmentConnections specification for this zone.");
2736 0 : s_ztpc->ErrorsFound = true;
2737 : }
2738 : }
2739 :
2740 10272 : if (comfortZone.ManageDemand) {
2741 0 : int ZoneNum = comfortZone.ActualZoneNum;
2742 0 : auto &zoneTstatSetpt = s_hbfs->zoneTstatSetpts(ZoneNum);
2743 0 : switch (s_hbfs->ComfortControlType(ZoneNum)) {
2744 0 : case HVAC::SetptType::SingleHeat: {
2745 0 : if (zoneTstatSetpt.setpt >= comfortZone.HeatingResetLimit) {
2746 0 : zoneTstatSetpt.setptLo = zoneTstatSetpt.setpt = comfortZone.HeatingResetLimit;
2747 0 : TempControlType(ZoneNum) = HVAC::SetptType::SingleHeat;
2748 0 : TempControlTypeRpt(ZoneNum) = static_cast<int>(TempControlType(ZoneNum));
2749 : }
2750 0 : } break;
2751 :
2752 0 : case HVAC::SetptType::SingleCool: {
2753 0 : if (zoneTstatSetpt.setpt <= comfortZone.CoolingResetLimit) {
2754 0 : zoneTstatSetpt.setptHi = zoneTstatSetpt.setpt = comfortZone.CoolingResetLimit;
2755 0 : TempControlType(ZoneNum) = HVAC::SetptType::SingleCool;
2756 0 : TempControlTypeRpt(ZoneNum) = static_cast<int>(TempControlType(ZoneNum));
2757 : }
2758 0 : } break;
2759 :
2760 0 : case HVAC::SetptType::SingleHeatCool: {
2761 0 : if ((zoneTstatSetpt.setpt >= comfortZone.HeatingResetLimit) || (zoneTstatSetpt.setpt <= comfortZone.CoolingResetLimit)) {
2762 :
2763 0 : TempControlType(ZoneNum) = HVAC::SetptType::DualHeatCool;
2764 0 : TempControlTypeRpt(ZoneNum) = static_cast<int>(TempControlType(ZoneNum));
2765 0 : zoneTstatSetpt.setptLo = zoneTstatSetpt.setptHi = zoneTstatSetpt.setpt;
2766 :
2767 0 : if (zoneTstatSetpt.setptLo >= comfortZone.HeatingResetLimit) {
2768 0 : zoneTstatSetpt.setptLo = comfortZone.HeatingResetLimit;
2769 : }
2770 0 : if (zoneTstatSetpt.setptHi <= comfortZone.CoolingResetLimit) {
2771 0 : zoneTstatSetpt.setptHi = comfortZone.CoolingResetLimit;
2772 : }
2773 : }
2774 0 : } break;
2775 :
2776 0 : case HVAC::SetptType::DualHeatCool: {
2777 0 : TempControlType(ZoneNum) = HVAC::SetptType::DualHeatCool;
2778 0 : TempControlTypeRpt(ZoneNum) = static_cast<int>(TempControlType(ZoneNum));
2779 0 : if (zoneTstatSetpt.setptLo >= comfortZone.HeatingResetLimit) {
2780 0 : zoneTstatSetpt.setptLo = comfortZone.HeatingResetLimit;
2781 : }
2782 0 : if (zoneTstatSetpt.setptHi <= comfortZone.CoolingResetLimit) {
2783 0 : zoneTstatSetpt.setptHi = comfortZone.CoolingResetLimit;
2784 : }
2785 0 : } break;
2786 :
2787 0 : default: {
2788 0 : } break;
2789 : } // switch
2790 : } // Demand manager
2791 : }
2792 :
2793 14518428 : if (s_ztpc->ErrorsFound) {
2794 0 : ShowFatalError(state, "InitZoneAirSetpoints - program terminates due to previous condition.");
2795 : }
2796 :
2797 14518428 : if (state.dataZoneEquip->ZoneEquipInputsFilled) {
2798 14518428 : s_ztpc->ControlledZonesChecked = true;
2799 : }
2800 14518428 : }
2801 :
2802 50695 : void ZoneSpaceHeatBalanceData::beginEnvironmentInit(EnergyPlusData &state)
2803 : {
2804 253475 : for (int i = 0; i <= 3; ++i) {
2805 202780 : this->ZTM[i] = 0.0;
2806 202780 : this->WPrevZoneTS[i] = state.dataEnvrn->OutHumRat;
2807 202780 : this->DSWPrevZoneTS[i] = state.dataEnvrn->OutHumRat;
2808 202780 : this->WPrevZoneTSTemp[i] = 0.0;
2809 : }
2810 50695 : this->WTimeMinusP = state.dataEnvrn->OutHumRat;
2811 50695 : this->W1 = state.dataEnvrn->OutHumRat;
2812 50695 : this->WMX = state.dataEnvrn->OutHumRat;
2813 50695 : this->WM2 = state.dataEnvrn->OutHumRat;
2814 50695 : this->airHumRatTemp = 0.0;
2815 50695 : this->tempIndLoad = 0.0;
2816 50695 : this->tempDepLoad = 0.0;
2817 50695 : this->airRelHum = 0.0;
2818 50695 : this->AirPowerCap = 0.0;
2819 50695 : this->T1 = 0.0;
2820 50695 : }
2821 :
2822 5217 : void ZoneSpaceHeatBalanceData::setUpOutputVars(EnergyPlusData &state, std::string_view prefix, std::string const &name)
2823 : {
2824 15651 : SetupOutputVariable(state,
2825 10434 : format("{} Air Temperature", prefix),
2826 : Constant::Units::C,
2827 5217 : this->ZT,
2828 : OutputProcessor::TimeStepType::System,
2829 : OutputProcessor::StoreType::Average,
2830 : name);
2831 15651 : SetupOutputVariable(state,
2832 10434 : format("{} Air Humidity Ratio", prefix),
2833 : Constant::Units::None,
2834 5217 : this->airHumRat,
2835 : OutputProcessor::TimeStepType::System,
2836 : OutputProcessor::StoreType::Average,
2837 : name);
2838 15651 : SetupOutputVariable(state,
2839 10434 : format("{} Air Relative Humidity", prefix),
2840 : Constant::Units::Perc,
2841 5217 : this->airRelHum,
2842 : OutputProcessor::TimeStepType::System,
2843 : OutputProcessor::StoreType::Average,
2844 : name);
2845 15651 : SetupOutputVariable(state,
2846 10434 : format("{} Mean Radiant Temperature", prefix),
2847 : Constant::Units::C,
2848 5217 : this->MRT,
2849 : OutputProcessor::TimeStepType::Zone,
2850 : OutputProcessor::StoreType::Average,
2851 : name);
2852 5217 : }
2853 :
2854 3896818 : void PredictSystemLoads(EnergyPlusData &state,
2855 : bool const ShortenTimeStepSys,
2856 : bool const UseZoneTimeStepHistory, // if true then use zone timestep history, if false use system time step
2857 : Real64 const PriorTimeStep // the old value for timestep length is passed for possible use in interpolating
2858 : )
2859 : {
2860 :
2861 : // SUBROUTINE INFORMATION:
2862 : // AUTHOR Russ Taylor
2863 : // DATE WRITTEN May 1997
2864 : // MODIFIED na
2865 : // RE-ENGINEERED July 2003 (Peter Graham Ellis)
2866 :
2867 : // PURPOSE OF THIS SUBROUTINE:
2868 : // This subroutine is responsible for determining
2869 : // how much of each type of energy every zone requires.
2870 : // In effect, this subroutine defines and simulates all
2871 : // the system types and in the case of hybrid systems
2872 : // which use more than one type of energy must determine
2873 : // how to apportion the load. An example of a hybrid system
2874 : // is a water loop heat pump with supplemental air. In
2875 : // this case, a zone will require water from the loop and
2876 : // cooled or heated air from the air system. A simpler
2877 : // example would be a VAV system with baseboard heaters.
2878 :
2879 : // Basic Air System Types
2880 : // 1) Constant Volume Single Duct
2881 : // 2) Variable Volume Single Duct
2882 : // 3) Constant Volume Dual Duct
2883 : // 4) Variable Volume Dual Duct
2884 :
2885 : // METHODOLOGY EMPLOYED:
2886 : // 0. Determine if simulation has downstepped and readjust history and revert node results
2887 : // 1. Determine zone load - this is zone temperature dependent
2888 : // 2. Determine balance point - the temperature at which the
2889 : // zone load is balanced by the system output. The way the
2890 : // balance point is determined will be different depending on
2891 : // the type of system being simulated.
2892 : // 3. Calculate zone energy requirements
2893 :
2894 3896818 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
2895 3896818 : auto const &s_hbfs = state.dataHeatBalFanSys;
2896 :
2897 : // Staged thermostat setpoint
2898 3896818 : if (s_ztpc->NumStageCtrZone > 0) {
2899 127321 : for (int RelativeZoneNum = 1; RelativeZoneNum <= s_ztpc->NumStageCtrZone; ++RelativeZoneNum) {
2900 100893 : auto &thisStageControlZone = state.dataZoneCtrls->StageControlledZone(RelativeZoneNum);
2901 100893 : int ActualZoneNum = thisStageControlZone.ActualZoneNum;
2902 :
2903 100893 : auto &thisZoneHB = s_ztpc->zoneHeatBalance(ActualZoneNum);
2904 100893 : auto &zoneTstatSetpt = s_hbfs->zoneTstatSetpts(ActualZoneNum);
2905 100893 : Real64 ZoneT = thisZoneHB.MAT; // Zone temperature at previous time step
2906 100893 : if (ShortenTimeStepSys) {
2907 1893 : ZoneT = thisZoneHB.XMPT;
2908 : }
2909 100893 : thisStageControlZone.HeatSetPoint = thisStageControlZone.heatSetptBaseSched->getCurrentVal();
2910 100893 : thisStageControlZone.CoolSetPoint = thisStageControlZone.coolSetptBaseSched->getCurrentVal();
2911 :
2912 100893 : if (thisStageControlZone.HeatSetPoint >= thisStageControlZone.CoolSetPoint) {
2913 0 : ++thisStageControlZone.StageErrCount;
2914 0 : if (thisStageControlZone.StageErrCount < 2) {
2915 0 : ShowWarningError(
2916 : state,
2917 0 : format("ZoneControl:Thermostat:StagedDualSetpoint: The heating setpoint is equal to or above the cooling setpoint in {}",
2918 0 : thisStageControlZone.Name));
2919 0 : ShowContinueError(state, "The zone heating setpoint is set to the cooling setpoint - 0.1C.");
2920 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
2921 : } else {
2922 0 : ShowRecurringWarningErrorAtEnd(state,
2923 : "The heating setpoint is still above the cooling setpoint",
2924 0 : thisStageControlZone.StageErrIndex,
2925 0 : thisStageControlZone.HeatSetPoint,
2926 0 : thisStageControlZone.HeatSetPoint);
2927 : }
2928 0 : thisStageControlZone.HeatSetPoint = thisStageControlZone.CoolSetPoint - 0.1; //???????????
2929 : }
2930 : // Determine either cooling or heating
2931 100893 : if (thisStageControlZone.CoolSetPoint < ZoneT) { // Cooling
2932 19407 : Real64 SetpointOffset = ZoneT - thisStageControlZone.CoolSetPoint;
2933 19407 : int Itemp = 0;
2934 69285 : for (int I = 1; I <= thisStageControlZone.NumOfCoolStages; ++I) {
2935 49878 : if (SetpointOffset >= thisStageControlZone.CoolTOffset(I)) {
2936 30440 : Itemp = -I;
2937 : }
2938 : }
2939 19407 : state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ActualZoneNum).StageNum = Itemp;
2940 19407 : if (SetpointOffset >= 0.5 * thisStageControlZone.CoolThroRange) {
2941 7226 : zoneTstatSetpt.setptHi = thisStageControlZone.CoolSetPoint - 0.5 * thisStageControlZone.CoolThroRange;
2942 : } else {
2943 12181 : zoneTstatSetpt.setptHi = thisStageControlZone.CoolSetPoint + 0.5 * thisStageControlZone.CoolThroRange;
2944 : }
2945 19407 : zoneTstatSetpt.setptLo = zoneTstatSetpt.setptHi;
2946 :
2947 81486 : } else if (thisStageControlZone.HeatSetPoint > ZoneT) { // heating
2948 37113 : Real64 SetpointOffset = ZoneT - thisStageControlZone.HeatSetPoint;
2949 37113 : int Itemp = 0;
2950 86506 : for (int I = 1; I <= thisStageControlZone.NumOfHeatStages; ++I) {
2951 49393 : if (std::abs(SetpointOffset) >= std::abs(thisStageControlZone.HeatTOffset(I))) {
2952 46615 : Itemp = I;
2953 : }
2954 : }
2955 37113 : state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ActualZoneNum).StageNum = Itemp;
2956 37113 : if (std::abs(SetpointOffset) >= 0.5 * thisStageControlZone.CoolThroRange) {
2957 25332 : zoneTstatSetpt.setptLo = thisStageControlZone.HeatSetPoint + 0.5 * thisStageControlZone.HeatThroRange;
2958 : } else {
2959 11781 : zoneTstatSetpt.setptLo = thisStageControlZone.HeatSetPoint - 0.5 * thisStageControlZone.HeatThroRange;
2960 : }
2961 37113 : zoneTstatSetpt.setptHi = zoneTstatSetpt.setptLo;
2962 :
2963 : } else {
2964 44373 : zoneTstatSetpt.setptHi = thisStageControlZone.CoolSetPoint + 0.5 * thisStageControlZone.CoolThroRange;
2965 44373 : zoneTstatSetpt.setptLo = thisStageControlZone.HeatSetPoint - 0.5 * thisStageControlZone.HeatThroRange;
2966 44373 : state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ActualZoneNum).StageNum = 0;
2967 : }
2968 : // SpaceHB TODO: For now, set space stagenum to zone stagenum - later need to see what space the thermostat is in
2969 100893 : if (state.dataHeatBal->doSpaceHeatBalance) {
2970 0 : for (int spaceNum : state.dataHeatBal->Zone(ActualZoneNum).spaceIndexes) {
2971 0 : state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).StageNum =
2972 0 : state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ActualZoneNum).StageNum;
2973 0 : }
2974 : }
2975 : }
2976 : }
2977 :
2978 : // Setpoint revision for onoff thermostat
2979 3896818 : if (s_ztpc->NumOnOffCtrZone > 0) {
2980 93112 : Real64 TempTole = 0.02;
2981 : Real64 Tprev;
2982 186224 : for (int RelativeZoneNum = 1; RelativeZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++RelativeZoneNum) {
2983 93112 : auto &thisTempControlledZone = state.dataZoneCtrls->TempControlledZone(RelativeZoneNum);
2984 93112 : if (thisTempControlledZone.DeltaTCutSet > 0.0) {
2985 93112 : if (ShortenTimeStepSys) {
2986 16254 : thisTempControlledZone.HeatModeLast = thisTempControlledZone.HeatModeLastSave;
2987 16254 : thisTempControlledZone.CoolModeLast = thisTempControlledZone.CoolModeLastSave;
2988 : } else {
2989 76858 : thisTempControlledZone.HeatModeLastSave = thisTempControlledZone.HeatModeLast;
2990 76858 : thisTempControlledZone.CoolModeLastSave = thisTempControlledZone.CoolModeLast;
2991 : }
2992 :
2993 93112 : auto &zoneTstatSetpt = s_hbfs->zoneTstatSetpts(thisTempControlledZone.ActualZoneNum);
2994 93112 : auto &thisZoneHB = s_ztpc->zoneHeatBalance(thisTempControlledZone.ActualZoneNum);
2995 93112 : thisTempControlledZone.CoolOffFlag = false;
2996 93112 : thisTempControlledZone.HeatOffFlag = false;
2997 93112 : if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::ThirdOrder) {
2998 93112 : Tprev = thisZoneHB.MAT;
2999 93112 : if (ShortenTimeStepSys) {
3000 16254 : Tprev = thisZoneHB.XMPT;
3001 : }
3002 : } else {
3003 0 : Tprev = thisZoneHB.T1;
3004 : }
3005 :
3006 93112 : switch (state.dataHeatBalFanSys->TempControlType(thisTempControlledZone.ActualZoneNum)) {
3007 :
3008 0 : case HVAC::SetptType::SingleHeat: {
3009 0 : zoneTstatSetpt.setpt = thisTempControlledZone.ZoneThermostatSetPointLo;
3010 0 : zoneTstatSetpt.setptLo = thisTempControlledZone.ZoneThermostatSetPointLo;
3011 0 : if (Tprev < thisTempControlledZone.ZoneThermostatSetPointLo + TempTole) {
3012 0 : zoneTstatSetpt.setpt = thisTempControlledZone.ZoneThermostatSetPointLo + thisTempControlledZone.DeltaTCutSet;
3013 0 : zoneTstatSetpt.setptLo = zoneTstatSetpt.setpt;
3014 0 : } else if (Tprev > thisTempControlledZone.ZoneThermostatSetPointLo &&
3015 0 : (Tprev < thisTempControlledZone.ZoneThermostatSetPointLo + thisTempControlledZone.DeltaTCutSet - TempTole)) {
3016 0 : zoneTstatSetpt.setpt = thisTempControlledZone.ZoneThermostatSetPointLo + thisTempControlledZone.DeltaTCutSet;
3017 0 : zoneTstatSetpt.setptLo = zoneTstatSetpt.setpt;
3018 : } else {
3019 0 : thisTempControlledZone.HeatOffFlag = true;
3020 : }
3021 0 : if (thisTempControlledZone.HeatModeLast && Tprev > thisTempControlledZone.ZoneThermostatSetPointLo) {
3022 0 : zoneTstatSetpt.setpt = thisTempControlledZone.ZoneThermostatSetPointLo;
3023 0 : zoneTstatSetpt.setptLo = thisTempControlledZone.ZoneThermostatSetPointLo;
3024 0 : thisTempControlledZone.HeatOffFlag = true;
3025 : }
3026 0 : } break;
3027 :
3028 0 : case HVAC::SetptType::SingleCool: {
3029 0 : zoneTstatSetpt.setpt = thisTempControlledZone.ZoneThermostatSetPointHi;
3030 0 : zoneTstatSetpt.setptHi = thisTempControlledZone.ZoneThermostatSetPointHi;
3031 0 : if (Tprev > thisTempControlledZone.ZoneThermostatSetPointHi - TempTole) {
3032 0 : zoneTstatSetpt.setpt = thisTempControlledZone.ZoneThermostatSetPointHi - thisTempControlledZone.DeltaTCutSet;
3033 0 : zoneTstatSetpt.setptHi = zoneTstatSetpt.setpt;
3034 0 : } else if (Tprev < thisTempControlledZone.ZoneThermostatSetPointHi &&
3035 0 : Tprev > thisTempControlledZone.ZoneThermostatSetPointHi - thisTempControlledZone.DeltaTCutSet + TempTole) {
3036 0 : zoneTstatSetpt.setpt = thisTempControlledZone.ZoneThermostatSetPointHi - thisTempControlledZone.DeltaTCutSet;
3037 0 : zoneTstatSetpt.setptHi = zoneTstatSetpt.setpt;
3038 : } else {
3039 0 : thisTempControlledZone.CoolOffFlag = true;
3040 : }
3041 0 : if (thisTempControlledZone.CoolModeLast && Tprev < thisTempControlledZone.ZoneThermostatSetPointHi) {
3042 0 : zoneTstatSetpt.setpt = thisTempControlledZone.ZoneThermostatSetPointHi;
3043 0 : zoneTstatSetpt.setptHi = thisTempControlledZone.ZoneThermostatSetPointHi;
3044 0 : thisTempControlledZone.CoolOffFlag = true;
3045 : }
3046 0 : } break;
3047 :
3048 93112 : case HVAC::SetptType::DualHeatCool: {
3049 93112 : zoneTstatSetpt.setptHi = thisTempControlledZone.ZoneThermostatSetPointHi;
3050 93112 : zoneTstatSetpt.setptLo = thisTempControlledZone.ZoneThermostatSetPointLo;
3051 93112 : if (Tprev > thisTempControlledZone.ZoneThermostatSetPointHi - TempTole) {
3052 6917 : zoneTstatSetpt.setptHi = thisTempControlledZone.ZoneThermostatSetPointHi - thisTempControlledZone.DeltaTCutSet;
3053 86195 : } else if (Tprev < thisTempControlledZone.ZoneThermostatSetPointHi &&
3054 86195 : Tprev > thisTempControlledZone.ZoneThermostatSetPointHi - thisTempControlledZone.DeltaTCutSet + TempTole) {
3055 31484 : zoneTstatSetpt.setptHi = thisTempControlledZone.ZoneThermostatSetPointHi - thisTempControlledZone.DeltaTCutSet;
3056 : } else {
3057 54711 : thisTempControlledZone.CoolOffFlag = true;
3058 : }
3059 93112 : if (thisTempControlledZone.CoolModeLast && Tprev < thisTempControlledZone.ZoneThermostatSetPointHi) {
3060 66971 : zoneTstatSetpt.setptHi = thisTempControlledZone.ZoneThermostatSetPointHi;
3061 66971 : thisTempControlledZone.CoolOffFlag = true;
3062 : }
3063 :
3064 93112 : if (Tprev < thisTempControlledZone.ZoneThermostatSetPointLo + TempTole) {
3065 14898 : zoneTstatSetpt.setptLo = thisTempControlledZone.ZoneThermostatSetPointLo + thisTempControlledZone.DeltaTCutSet;
3066 78214 : } else if (Tprev > thisTempControlledZone.ZoneThermostatSetPointLo &&
3067 78214 : (Tprev < thisTempControlledZone.ZoneThermostatSetPointLo + thisTempControlledZone.DeltaTCutSet - TempTole)) {
3068 23406 : zoneTstatSetpt.setptLo = thisTempControlledZone.ZoneThermostatSetPointLo + thisTempControlledZone.DeltaTCutSet;
3069 : } else {
3070 54808 : thisTempControlledZone.HeatOffFlag = true;
3071 : }
3072 93112 : if (thisTempControlledZone.HeatModeLast && Tprev > thisTempControlledZone.ZoneThermostatSetPointLo) {
3073 46868 : zoneTstatSetpt.setptLo = thisTempControlledZone.ZoneThermostatSetPointLo;
3074 46868 : thisTempControlledZone.HeatOffFlag = true;
3075 : }
3076 :
3077 : // check setpoint for both and provde an error message
3078 93112 : if (zoneTstatSetpt.setptLo >= zoneTstatSetpt.setptHi) {
3079 0 : ShowSevereError(state,
3080 : "DualSetPointWithDeadBand: When Temperature Difference Between Cutout And Setpoint is applied, the heating "
3081 : "setpoint is greater than the cooling setpoint. ");
3082 0 : ShowContinueErrorTimeStamp(state,
3083 0 : format("occurs in Zone={}", state.dataHeatBal->Zone(thisTempControlledZone.ActualZoneNum).Name));
3084 0 : ShowContinueError(state, format("Zone Heating ThermostatSetPoint={:.2R}", zoneTstatSetpt.setptLo));
3085 0 : ShowContinueError(state, format("Zone Cooling ThermostatSetPoint={:.2R}", zoneTstatSetpt.setptHi));
3086 0 : ShowFatalError(state, "Program terminates due to above conditions.");
3087 : }
3088 93112 : } break;
3089 :
3090 0 : default: {
3091 0 : } break;
3092 : } // switch (setptType)
3093 : }
3094 : }
3095 : }
3096 :
3097 35243058 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
3098 31346240 : auto &thisZoneHB = s_ztpc->zoneHeatBalance(zoneNum);
3099 31346240 : thisZoneHB.predictSystemLoad(state, ShortenTimeStepSys, UseZoneTimeStepHistory, PriorTimeStep, zoneNum);
3100 62756344 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
3101 31410104 : if (state.dataHeatBal->doSpaceHeatBalance) {
3102 86394 : s_ztpc->spaceHeatBalance(spaceNum).predictSystemLoad(
3103 : state, ShortenTimeStepSys, UseZoneTimeStepHistory, PriorTimeStep, zoneNum, spaceNum);
3104 31323710 : } else if (ShortenTimeStepSys) {
3105 3162218 : s_ztpc->spaceHeatBalance(spaceNum).MAT = thisZoneHB.MAT;
3106 3162218 : s_ztpc->spaceHeatBalance(spaceNum).airHumRat = thisZoneHB.airHumRat;
3107 : }
3108 31346240 : }
3109 : }
3110 3896818 : if (s_ztpc->NumOnOffCtrZone > 0) {
3111 186224 : for (int RelativeZoneNum = 1; RelativeZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++RelativeZoneNum) {
3112 93112 : auto &thisTempControlledZone = state.dataZoneCtrls->TempControlledZone(RelativeZoneNum);
3113 93112 : if (thisTempControlledZone.DeltaTCutSet > 0.0) {
3114 93112 : int ZoneNum = thisTempControlledZone.ActualZoneNum;
3115 93112 : if (thisTempControlledZone.CoolOffFlag && state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).TotalOutputRequired >= 0.0) {
3116 66033 : thisTempControlledZone.CoolModeLast = true;
3117 : } else {
3118 27079 : thisTempControlledZone.CoolModeLast = false;
3119 : }
3120 93112 : if (thisTempControlledZone.HeatOffFlag && state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).TotalOutputRequired <= 0.0) {
3121 46851 : thisTempControlledZone.HeatModeLast = true;
3122 : } else {
3123 46261 : thisTempControlledZone.HeatModeLast = false;
3124 : }
3125 : }
3126 : }
3127 : }
3128 3896818 : }
3129 31432634 : void ZoneSpaceHeatBalanceData::predictSystemLoad(
3130 : EnergyPlusData &state,
3131 : bool const shortenTimeStepSys,
3132 : bool const useZoneTimeStepHistory, // if true then use zone timestep history, if false use system time step
3133 : Real64 const priorTimeStep, // the old value for timestep length is passed for possible use in interpolating
3134 : int zoneNum,
3135 : int spaceNum)
3136 : {
3137 31432634 : assert(zoneNum > 0);
3138 31432634 : this->updateTemperatures(state, shortenTimeStepSys, useZoneTimeStepHistory, priorTimeStep, zoneNum, spaceNum);
3139 :
3140 31432634 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
3141 31432634 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
3142 :
3143 31432634 : Real64 volume = 0.0;
3144 31432634 : if (spaceNum > 0) {
3145 86394 : volume = state.dataHeatBal->space(spaceNum).Volume;
3146 : } else {
3147 31346240 : volume = state.dataHeatBal->Zone(zoneNum).Volume;
3148 : }
3149 :
3150 31432634 : this->AirPowerCap = volume * state.dataHeatBal->Zone(zoneNum).ZoneVolCapMultpSens *
3151 31432634 : Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->MAT, this->airHumRat) *
3152 31432634 : Psychrometrics::PsyCpAirFnW(this->airHumRat) / TimeStepSysSec;
3153 31432634 : Real64 RAFNFrac = 0.0;
3154 :
3155 : // Calculate the various heat balance sums
3156 :
3157 : // NOTE: SumSysMCp and SumSysMCpT are not used in the predict step
3158 31432634 : this->calcZoneOrSpaceSums(state, false, zoneNum, spaceNum);
3159 :
3160 : // Sum all convective internal gains except for people: SumIntGainExceptPeople
3161 31432634 : if (spaceNum == 0 && state.dataHybridModel->FlagHybridModel_PC) {
3162 8212 : this->SumIntGainExceptPeople = 0.0;
3163 8212 : this->SumIntGainExceptPeople = InternalHeatGains::SumAllInternalConvectionGainsExceptPeople(state, zoneNum);
3164 : }
3165 :
3166 31432634 : this->TempDepCoef = this->SumHA + this->SumMCp;
3167 31432634 : this->TempIndCoef = this->SumIntGain + this->SumHATsurf - this->SumHATref + this->SumMCpT + this->SysDepZoneLoadsLagged;
3168 31432634 : this->TempHistoryTerm = this->AirPowerCap * (3.0 * this->ZTM[0] - (3.0 / 2.0) * this->ZTM[1] + (1.0 / 3.0) * this->ZTM[2]);
3169 31432634 : this->tempDepLoad = (11.0 / 6.0) * this->AirPowerCap + this->TempDepCoef;
3170 31432634 : this->tempIndLoad = this->TempHistoryTerm + this->TempIndCoef;
3171 31432634 : if (state.dataRoomAir->anyNonMixingRoomAirModel) {
3172 160955 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
3173 : // RoomAirflowNetworkModel - make dynamic term independent of TimeStepSys
3174 7413 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
3175 7413 : if (afnZoneInfo.IsUsed) {
3176 7413 : int RoomAirNode = afnZoneInfo.ControlAirNodeID;
3177 7413 : RoomAir::LoadPredictionRoomAirModelAFN(state, zoneNum, RoomAirNode);
3178 7413 : this->TempDepCoef = afnZoneInfo.Node(RoomAirNode).SumHA + afnZoneInfo.Node(RoomAirNode).SumLinkMCp;
3179 7413 : this->TempIndCoef = afnZoneInfo.Node(RoomAirNode).SumIntSensibleGain + afnZoneInfo.Node(RoomAirNode).SumHATsurf -
3180 7413 : afnZoneInfo.Node(RoomAirNode).SumHATref + afnZoneInfo.Node(RoomAirNode).SumLinkMCpT +
3181 7413 : afnZoneInfo.Node(RoomAirNode).SysDepZoneLoadsLagged;
3182 7413 : this->AirPowerCap = afnZoneInfo.Node(RoomAirNode).AirVolume * state.dataHeatBal->Zone(zoneNum).ZoneVolCapMultpSens *
3183 7413 : afnZoneInfo.Node(RoomAirNode).RhoAir * afnZoneInfo.Node(RoomAirNode).CpAir / TimeStepSysSec;
3184 7413 : this->TempHistoryTerm = this->AirPowerCap * (3.0 * this->ZTM[0] - (3.0 / 2.0) * this->ZTM[1] + (1.0 / 3.0) * this->ZTM[2]);
3185 7413 : this->tempDepLoad = (11.0 / 6.0) * this->AirPowerCap + this->TempDepCoef;
3186 7413 : this->tempIndLoad = this->TempHistoryTerm + this->TempIndCoef;
3187 7413 : if (afnZoneInfo.Node(RoomAirNode).HasHVACAssigned) {
3188 7413 : RAFNFrac = afnZoneInfo.Node(RoomAirNode).HVAC(1).SupplyFraction;
3189 : }
3190 : }
3191 : }
3192 : }
3193 :
3194 : // Exact solution or Euler method
3195 31432634 : state.dataHVACGlobal->ShortenTimeStepSysRoomAir = false;
3196 31432634 : if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
3197 14341335 : if (shortenTimeStepSys && TimeStepSys < state.dataGlobal->TimeStepZone) {
3198 1866675 : if (state.dataHVACGlobal->PreviousTimeStep < state.dataGlobal->TimeStepZone) {
3199 1554480 : this->T1 = this->TM2;
3200 1554480 : this->W1 = this->WM2;
3201 1554480 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
3202 0 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
3203 0 : for (auto &afnNode : afnZoneInfo.Node) {
3204 0 : afnNode.AirTempT1 = afnNode.AirTempT2;
3205 0 : afnNode.HumRatT1 = afnNode.HumRatT2;
3206 : }
3207 : }
3208 : } else {
3209 312195 : this->T1 = this->TMX;
3210 312195 : this->W1 = this->WMX;
3211 312195 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
3212 0 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
3213 0 : for (auto &afnNode : afnZoneInfo.Node) {
3214 0 : afnNode.AirTempT1 = afnNode.AirTempTX;
3215 0 : afnNode.HumRatT1 = afnNode.HumRatTX;
3216 : }
3217 : }
3218 : }
3219 1866675 : state.dataHVACGlobal->ShortenTimeStepSysRoomAir = true;
3220 : } else {
3221 12474660 : this->T1 = this->ZT;
3222 12474660 : this->W1 = this->airHumRat;
3223 12474660 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
3224 0 : auto &afnZoneInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
3225 0 : for (auto &afnNode : afnZoneInfo.Node) {
3226 0 : afnNode.AirTempT1 = afnNode.AirTemp;
3227 0 : afnNode.HumRatT1 = afnNode.HumRat;
3228 : }
3229 : }
3230 : }
3231 14341335 : this->tempDepLoad = this->TempDepCoef;
3232 14341335 : this->tempIndLoad = this->TempIndCoef;
3233 : }
3234 :
3235 : // Calculate the predicted zone load to be provided by the system with the given desired zone air temperature
3236 31432634 : this->calcPredictedSystemLoad(state, RAFNFrac, zoneNum, spaceNum);
3237 :
3238 : // Calculate the predicted zone load to be provided by the system with the given desired humidity ratio
3239 31432634 : this->calcPredictedHumidityRatio(state, RAFNFrac, zoneNum, spaceNum);
3240 31432634 : }
3241 :
3242 2828450 : void CalcZoneAirTempSetPoints(EnergyPlusData &state)
3243 : {
3244 :
3245 : // SUBROUTINE INFORMATION:
3246 : // AUTHOR Russ Taylor
3247 : // DATE WRITTEN Nov 1997
3248 : // MODIFIED Aug 2013, Xiufeng Pang (XP) - Added code for updating set points during
3249 : // optimum start period
3250 : // RE-ENGINEERED na
3251 :
3252 : // PURPOSE OF THIS SUBROUTINE:
3253 : // This routine sets what the setpoints for each controlled zone should be based on schedules.
3254 : // This is called each time step.
3255 :
3256 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3257 : int RelativeZoneNum;
3258 : int ActualZoneNum;
3259 : int OccStartTime; // Occupancy start time - for optimum start
3260 : Real64 DeltaT; // Temperature difference between cutout and setpoint
3261 :
3262 2828450 : auto &s_hbfs = state.dataHeatBalFanSys;
3263 :
3264 2828450 : auto &Zone = state.dataHeatBal->Zone;
3265 2828450 : auto &TempControlledZone = state.dataZoneCtrls->TempControlledZone;
3266 2828450 : auto &TempControlType = state.dataHeatBalFanSys->TempControlType;
3267 2828450 : auto &TempControlTypeRpt = state.dataHeatBalFanSys->TempControlTypeRpt;
3268 2828450 : int NumOfZones = state.dataGlobal->NumOfZones;
3269 :
3270 2828450 : TempControlType = HVAC::SetptType::Uncontrolled; // Default
3271 :
3272 : // Place holder for occupied heating and cooling set points - for optimum start
3273 2828450 : if (!allocated(state.dataZoneCtrls->OccRoomTSetPointHeat)) {
3274 801 : state.dataZoneCtrls->OccRoomTSetPointHeat.allocate(NumOfZones);
3275 : }
3276 2828450 : if (!allocated(state.dataZoneCtrls->OccRoomTSetPointCool)) {
3277 801 : state.dataZoneCtrls->OccRoomTSetPointCool.allocate(NumOfZones);
3278 : }
3279 2828450 : state.dataZoneCtrls->OccRoomTSetPointHeat = 0.0;
3280 2828450 : state.dataZoneCtrls->OccRoomTSetPointCool = 100.0;
3281 2828450 : DeltaT = 0.0;
3282 :
3283 20391270 : for (RelativeZoneNum = 1; RelativeZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++RelativeZoneNum) {
3284 17562820 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(RelativeZoneNum);
3285 : // What if this zone not controlled???
3286 :
3287 17562820 : int ActualZoneNum = tempZone.ActualZoneNum;
3288 17562820 : TempControlType(ActualZoneNum) = static_cast<HVAC::SetptType>(tempZone.setptTypeSched->getCurrentVal());
3289 17562820 : TempControlTypeRpt(ActualZoneNum) = static_cast<int>(TempControlType(ActualZoneNum));
3290 : // Error detection for these values is done in the Get routine
3291 :
3292 17562820 : auto &zoneTstatSetpt = s_hbfs->zoneTstatSetpts(tempZone.ActualZoneNum);
3293 :
3294 17562820 : switch (TempControlType(ActualZoneNum)) {
3295 2034 : case HVAC::SetptType::Uncontrolled: {
3296 2034 : } break;
3297 :
3298 1911933 : case HVAC::SetptType::SingleHeat: {
3299 1911933 : if (tempZone.setpts[(int)HVAC::SetptType::SingleHeat].isUsed) {
3300 1911933 : zoneTstatSetpt.setpt = tempZone.setpts[(int)HVAC::SetptType::SingleHeat].heatSetptSched->getCurrentVal();
3301 1911933 : tempZone.ZoneThermostatSetPointLo = zoneTstatSetpt.setpt;
3302 :
3303 1911933 : AdjustAirSetPointsforOpTempCntrl(state, RelativeZoneNum, ActualZoneNum, zoneTstatSetpt.setpt);
3304 1911933 : zoneTstatSetpt.setptLo = zoneTstatSetpt.setpt;
3305 : }
3306 1911933 : } break;
3307 :
3308 1926233 : case HVAC::SetptType::SingleCool: {
3309 1926233 : zoneTstatSetpt.setpt = tempZone.setpts[(int)HVAC::SetptType::SingleCool].coolSetptSched->getCurrentVal();
3310 1926233 : tempZone.ZoneThermostatSetPointHi = zoneTstatSetpt.setpt;
3311 :
3312 : // Added Jan 17 (X. Luo)
3313 : // Adjust operative temperature based on adaptive comfort model
3314 1926233 : if (tempZone.AdaptiveComfortTempControl) {
3315 6750 : AdjustOperativeSetPointsforAdapComfort(state, RelativeZoneNum, zoneTstatSetpt.setpt);
3316 6750 : zoneTstatSetpt.setptAdapComfortCool = zoneTstatSetpt.setpt;
3317 : }
3318 :
3319 1926233 : AdjustAirSetPointsforOpTempCntrl(state, RelativeZoneNum, ActualZoneNum, zoneTstatSetpt.setpt);
3320 1926233 : zoneTstatSetpt.setptHi = zoneTstatSetpt.setpt;
3321 :
3322 1926233 : AdjustCoolingSetPointforTempAndHumidityControl(state, RelativeZoneNum, ActualZoneNum);
3323 1926233 : } break;
3324 :
3325 79254 : case HVAC::SetptType::SingleHeatCool: {
3326 79254 : zoneTstatSetpt.setpt = tempZone.setpts[(int)HVAC::SetptType::SingleHeatCool].heatSetptSched->getCurrentVal();
3327 :
3328 : // Added Jan 17 (X. Luo)
3329 : // Adjust operative temperature based on adaptive comfort model
3330 79254 : if (tempZone.AdaptiveComfortTempControl) {
3331 0 : AdjustOperativeSetPointsforAdapComfort(state, RelativeZoneNum, zoneTstatSetpt.setpt);
3332 0 : zoneTstatSetpt.setptAdapComfortCool = zoneTstatSetpt.setpt;
3333 : }
3334 :
3335 79254 : AdjustAirSetPointsforOpTempCntrl(state, RelativeZoneNum, ActualZoneNum, zoneTstatSetpt.setpt);
3336 :
3337 79254 : zoneTstatSetpt.setptLo = zoneTstatSetpt.setptHi = zoneTstatSetpt.setpt;
3338 :
3339 : // Change the room set point to occupied set point during optimum start period--------------
3340 :
3341 79254 : if (allocated(state.dataAvail->OptStart)) {
3342 0 : if (state.dataAvail->OptStart(ActualZoneNum).ActualZoneNum == ActualZoneNum) {
3343 :
3344 0 : OccStartTime = CEILING(state.dataAvail->OptStart(ActualZoneNum).OccStartTime) + 1;
3345 0 : zoneTstatSetpt.setpt = tempZone.setpts[(int)HVAC::SetptType::SingleHeat].heatSetptSched->getDayVals(
3346 0 : state)[OccStartTime * state.dataGlobal->TimeStepsInHour];
3347 : }
3348 :
3349 0 : if (state.dataAvail->OptStart(ActualZoneNum).OptStartFlag) {
3350 0 : zoneTstatSetpt.setptLo = zoneTstatSetpt.setptHi = zoneTstatSetpt.setpt;
3351 : }
3352 : }
3353 : //--------------------------------------------------------------------------------------------
3354 79254 : } break;
3355 :
3356 13643366 : case HVAC::SetptType::DualHeatCool: {
3357 13643366 : zoneTstatSetpt.setptHi = tempZone.setpts[(int)HVAC::SetptType::DualHeatCool].coolSetptSched->getCurrentVal();
3358 13643366 : TempControlledZone(RelativeZoneNum).ZoneThermostatSetPointHi = zoneTstatSetpt.setptHi;
3359 :
3360 : // Added Jan 17 (X. Luo)
3361 : // Adjust operative temperature based on adaptive comfort model
3362 13643366 : if ((TempControlledZone(RelativeZoneNum).AdaptiveComfortTempControl)) {
3363 15 : AdjustOperativeSetPointsforAdapComfort(state, RelativeZoneNum, zoneTstatSetpt.setptHi);
3364 15 : zoneTstatSetpt.setptAdapComfortCool = zoneTstatSetpt.setptHi;
3365 : }
3366 :
3367 13643366 : AdjustAirSetPointsforOpTempCntrl(state, RelativeZoneNum, ActualZoneNum, zoneTstatSetpt.setptHi);
3368 :
3369 13643366 : zoneTstatSetpt.setptLo = tempZone.setpts[(int)HVAC::SetptType::DualHeatCool].heatSetptSched->getCurrentVal();
3370 13643366 : TempControlledZone(RelativeZoneNum).ZoneThermostatSetPointLo = zoneTstatSetpt.setptLo;
3371 13643366 : AdjustAirSetPointsforOpTempCntrl(state, RelativeZoneNum, ActualZoneNum, zoneTstatSetpt.setptLo);
3372 :
3373 : // Change the room set point to occupied set point during optimum start period--------------
3374 :
3375 13643366 : if (allocated(state.dataAvail->OptStart)) {
3376 36848 : if (state.dataAvail->OptStart(ActualZoneNum).ActualZoneNum == ActualZoneNum) {
3377 : // TODO: Why are we getting all day values if all we want is the value at (1, OccStartTime);
3378 11515 : OccStartTime = CEILING(state.dataAvail->OptStart(ActualZoneNum).OccStartTime) + 1;
3379 11515 : state.dataZoneCtrls->OccRoomTSetPointCool(ActualZoneNum) =
3380 11515 : tempZone.setpts[(int)HVAC::SetptType::DualHeatCool].coolSetptSched->getDayVals(
3381 11515 : state)[OccStartTime * state.dataGlobal->TimeStepsInHour];
3382 11515 : state.dataZoneCtrls->OccRoomTSetPointHeat(ActualZoneNum) =
3383 11515 : tempZone.setpts[(int)HVAC::SetptType::DualHeatCool].heatSetptSched->getDayVals(
3384 11515 : state)[OccStartTime * state.dataGlobal->TimeStepsInHour];
3385 : }
3386 :
3387 36848 : if (state.dataAvail->OptStart(ActualZoneNum).OptStartFlag) {
3388 1740 : zoneTstatSetpt.setptHi = state.dataZoneCtrls->OccRoomTSetPointCool(ActualZoneNum);
3389 1740 : zoneTstatSetpt.setptLo = state.dataZoneCtrls->OccRoomTSetPointHeat(ActualZoneNum);
3390 : }
3391 : }
3392 : //--------------------------------------------------------------------------------------------
3393 :
3394 13643366 : AdjustCoolingSetPointforTempAndHumidityControl(state, RelativeZoneNum, ActualZoneNum);
3395 13643366 : } break;
3396 :
3397 0 : default: {
3398 0 : ShowSevereError(state,
3399 0 : format("CalcZoneAirTempSetpoints: Illegal control type for Zone={}, Found value={}, in Schedule={}",
3400 0 : Zone(ActualZoneNum).Name,
3401 : TempControlType(ActualZoneNum),
3402 0 : tempZone.setptTypeSched->Name));
3403 :
3404 0 : } break;
3405 : } // switch
3406 :
3407 : // Apply offset for faulty thermostats
3408 17567428 : if ((state.dataFaultsMgr->NumFaultyThermostat > 0) && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
3409 4608 : (!state.dataGlobal->KickOffSimulation)) {
3410 : // loop through the FaultsThermostatOffset objects to find the one for the zone
3411 34848 : for (int iFault = 1; iFault <= state.dataFaultsMgr->NumFaultyThermostat; ++iFault) {
3412 : // Why are we doing this here?
3413 34848 : if (Util::SameString(TempControlledZone(RelativeZoneNum).Name,
3414 34848 : state.dataFaultsMgr->FaultsThermostatOffset(iFault).FaultyThermostatName)) {
3415 :
3416 : // Check fault availability schedules
3417 4608 : if (state.dataFaultsMgr->FaultsThermostatOffset(iFault).availSched->getCurrentVal() > 0.0) {
3418 :
3419 : // Check fault severity schedules to update the reference thermostat offset
3420 4608 : Real64 rSchVal = 1.0;
3421 : Real64 offsetUpdated;
3422 4608 : if (state.dataFaultsMgr->FaultsThermostatOffset(iFault).severitySched != nullptr) {
3423 4608 : rSchVal = state.dataFaultsMgr->FaultsThermostatOffset(iFault).severitySched->getCurrentVal();
3424 : }
3425 4608 : offsetUpdated = rSchVal * state.dataFaultsMgr->FaultsThermostatOffset(iFault).Offset;
3426 :
3427 : // Positive offset means the sensor reading is higher than the actual value
3428 4608 : zoneTstatSetpt.setpt -= offsetUpdated;
3429 4608 : zoneTstatSetpt.setptLo -= offsetUpdated;
3430 4608 : zoneTstatSetpt.setptHi -= offsetUpdated;
3431 : }
3432 :
3433 : // Stop searching the FaultsThermostatOffset object for the zone
3434 4608 : break;
3435 : }
3436 : }
3437 : }
3438 : }
3439 :
3440 2828450 : if (state.dataZoneCtrls->NumComfortControlledZones > 0) {
3441 2025 : CalcZoneAirComfortSetPoints(state);
3442 : }
3443 2828450 : OverrideAirSetPointsforEMSCntrl(state);
3444 2828450 : }
3445 :
3446 31432634 : void ZoneSpaceHeatBalanceData::calcPredictedHumidityRatio(EnergyPlusData &state, Real64 const RAFNFrac, int const zoneNum, int const spaceNum)
3447 : {
3448 :
3449 : // SUBROUTINE INFORMATION:
3450 : // AUTHOR Richard J. Liesen
3451 : // DATE WRITTEN May 2001
3452 :
3453 : // PURPOSE OF THIS SUBROUTINE:
3454 : // This subroutine does the prediction step for humidity control
3455 :
3456 : // METHODOLOGY EMPLOYED:
3457 : // This solves for the required system moisture required to try and achieve the desired
3458 : // Humidity Ratio in the Zone
3459 :
3460 : // REFERENCES:
3461 : // Routine FinalZnCalcs - FINAL ZONE CALCULATIONS, authored by Dale Herron
3462 : // for BLAST.
3463 :
3464 : static constexpr std::string_view RoutineName("calcPredictedHumidityRatio");
3465 :
3466 31432634 : Real64 ZoneRHHumidifyingSetPoint = 0.0; // Zone humidifying set point (%)
3467 31432634 : Real64 ZoneRHDehumidifyingSetPoint = 0.0; // Zone dehumidifying set point (%)
3468 :
3469 31432634 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
3470 31432634 : bool SingleSetPoint = false; // This determines whether both setpoint are equal or not
3471 :
3472 : // Check to see if this is a "humidity controlled zone"
3473 31432634 : bool ControlledHumidZoneFlag = false;
3474 : // Check all the controlled zones to see if it matches the zone simulated
3475 31432634 : if (thisZone.humidityControlZoneIndex > 0) {
3476 1184325 : auto &humidityControlZone = state.dataZoneCtrls->HumidityControlZone(thisZone.humidityControlZoneIndex);
3477 1184325 : assert(humidityControlZone.ActualZoneNum == zoneNum);
3478 1184325 : ZoneRHHumidifyingSetPoint = humidityControlZone.humidifyingSched->getCurrentVal();
3479 1184325 : ZoneRHDehumidifyingSetPoint = humidityControlZone.dehumidifyingSched->getCurrentVal();
3480 :
3481 : // Apply EMS values to overwrite the humidistat values
3482 1184325 : if (humidityControlZone.EMSOverrideHumidifySetPointOn) {
3483 0 : ZoneRHHumidifyingSetPoint = humidityControlZone.EMSOverrideHumidifySetPointValue;
3484 : }
3485 1184325 : if (humidityControlZone.EMSOverrideDehumidifySetPointOn) {
3486 0 : ZoneRHDehumidifyingSetPoint = humidityControlZone.EMSOverrideDehumidifySetPointValue;
3487 : }
3488 :
3489 : // Apply offsets for faulty humidistats
3490 1184947 : if ((state.dataFaultsMgr->NumFaultyHumidistat > 0) && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
3491 622 : (!state.dataGlobal->KickOffSimulation)) {
3492 :
3493 : // loop through the FaultsHumidistatOffset objects to find the one for the zone
3494 622 : for (int iFault = 1; iFault <= state.dataFaultsMgr->NumFaultyHumidistat; ++iFault) {
3495 :
3496 622 : if (Util::SameString(humidityControlZone.ControlName, state.dataFaultsMgr->FaultsHumidistatOffset(iFault).FaultyHumidistatName)) {
3497 :
3498 622 : if (Util::SameString(state.dataFaultsMgr->FaultsHumidistatOffset(iFault).FaultyHumidistatType, "ThermostatOffsetDependent")) {
3499 : // For Humidistat Offset Type I: ThermostatOffsetDependent
3500 :
3501 304 : bool IsThermostatFound = false;
3502 304 : Real64 offsetThermostat = 0.0;
3503 :
3504 : // Get the offset value of the corresponding thermostat fault object
3505 304 : if (state.dataFaultsMgr->NumFaultyThermostat > 0) {
3506 :
3507 : // loop through the FaultsThermostatOffset objects to find the one causes the Humidistat Offset
3508 304 : for (int iFaultThermo = 1; iFaultThermo <= state.dataFaultsMgr->NumFaultyThermostat; ++iFaultThermo) {
3509 :
3510 304 : if (Util::SameString(state.dataFaultsMgr->FaultsHumidistatOffset(iFault).FaultyThermostatName,
3511 304 : state.dataFaultsMgr->FaultsThermostatOffset(iFaultThermo).Name)) {
3512 304 : IsThermostatFound = true;
3513 :
3514 : // Check fault availability schedules
3515 304 : if (state.dataFaultsMgr->FaultsThermostatOffset(iFaultThermo).availSched->getCurrentVal() > 0.0) {
3516 :
3517 : // Check fault severity schedules to update the reference thermostat offset
3518 304 : Real64 rSchVal = 1.0;
3519 304 : if (state.dataFaultsMgr->FaultsThermostatOffset(iFaultThermo).severitySched != nullptr) {
3520 304 : rSchVal = state.dataFaultsMgr->FaultsThermostatOffset(iFaultThermo).severitySched->getCurrentVal();
3521 : }
3522 304 : offsetThermostat = rSchVal * state.dataFaultsMgr->FaultsThermostatOffset(iFaultThermo).Offset;
3523 : }
3524 :
3525 : // Stop searching the FaultsThermostatOffset object for the Humidistat Offset
3526 304 : break;
3527 : }
3528 : }
3529 : }
3530 :
3531 : // The FaultsThermostatOffset specified in the FaultHumidistatOffset is not found
3532 304 : if (!IsThermostatFound) {
3533 0 : ShowSevereError(
3534 : state,
3535 0 : format("FaultModel:HumidistatOffset = \"{}\" invalid Reference Humidistat Offset Name = \"{}\" not found.",
3536 0 : state.dataFaultsMgr->FaultsHumidistatOffset(iFault).Name,
3537 0 : state.dataFaultsMgr->FaultsHumidistatOffset(iFault).FaultyThermostatName));
3538 0 : ShowFatalError(state, "Errors getting FaultModel input data. Preceding condition(s) cause termination.");
3539 : }
3540 :
3541 304 : if (offsetThermostat != 0.0) {
3542 : // Calculate the humidistat offset value from the thermostat offset value
3543 304 : Real64 faultZoneWHumidifyingSetPoint = Psychrometrics::PsyWFnTdbRhPb(
3544 304 : state, (this->MAT + offsetThermostat), (ZoneRHHumidifyingSetPoint / 100.0), state.dataEnvrn->OutBaroPress);
3545 304 : Real64 faultZoneWDehumidifyingSetPoint = Psychrometrics::PsyWFnTdbRhPb(
3546 304 : state, (this->MAT + offsetThermostat), (ZoneRHDehumidifyingSetPoint / 100.0), state.dataEnvrn->OutBaroPress);
3547 : Real64 offsetZoneRHHumidifyingSetPoint =
3548 304 : ZoneRHHumidifyingSetPoint -
3549 304 : Psychrometrics::PsyRhFnTdbWPb(state, this->MAT, faultZoneWHumidifyingSetPoint, state.dataEnvrn->OutBaroPress) * 100.0;
3550 : Real64 offsetZoneRHDehumidifyingSetPoint =
3551 304 : ZoneRHDehumidifyingSetPoint -
3552 304 : Psychrometrics::PsyRhFnTdbWPb(state, this->MAT, faultZoneWDehumidifyingSetPoint, state.dataEnvrn->OutBaroPress) *
3553 304 : 100.0;
3554 :
3555 : // Apply the calculated humidistat offset value
3556 : // Positive offset means the sensor reading is higher than the actual value
3557 304 : ZoneRHHumidifyingSetPoint -= offsetZoneRHHumidifyingSetPoint;
3558 304 : ZoneRHDehumidifyingSetPoint -= offsetZoneRHDehumidifyingSetPoint;
3559 :
3560 : // constrain value to something reasonable
3561 304 : ZoneRHHumidifyingSetPoint = min(100.0, max(0.0, ZoneRHHumidifyingSetPoint));
3562 304 : ZoneRHDehumidifyingSetPoint = min(100.0, max(0.0, ZoneRHDehumidifyingSetPoint));
3563 : }
3564 :
3565 : } else {
3566 : // For Humidistat Offset Type II: ThermostatOffsetIndependent
3567 :
3568 : // Check fault availability schedules
3569 318 : if (state.dataFaultsMgr->FaultsHumidistatOffset(iFault).availSched->getCurrentVal() > 0.0) {
3570 :
3571 : // Check fault severity schedules to update the reference humidistat offset
3572 318 : Real64 rSchVal = 1.0;
3573 : Real64 offsetUpdated;
3574 318 : if (state.dataFaultsMgr->FaultsHumidistatOffset(iFault).severitySched != nullptr) {
3575 318 : rSchVal = state.dataFaultsMgr->FaultsHumidistatOffset(iFault).severitySched->getCurrentVal();
3576 : }
3577 318 : offsetUpdated = rSchVal * state.dataFaultsMgr->FaultsHumidistatOffset(iFault).Offset;
3578 :
3579 : // Positive offset means the sensor reading is higher than the actual value
3580 318 : ZoneRHHumidifyingSetPoint -= offsetUpdated;
3581 318 : ZoneRHDehumidifyingSetPoint -= offsetUpdated;
3582 :
3583 : // constrain value to something reasonable
3584 318 : ZoneRHHumidifyingSetPoint = min(100.0, max(0.0, ZoneRHHumidifyingSetPoint));
3585 318 : ZoneRHDehumidifyingSetPoint = min(100.0, max(0.0, ZoneRHDehumidifyingSetPoint));
3586 : }
3587 : }
3588 622 : break;
3589 : }
3590 : }
3591 : }
3592 :
3593 : // Run-time error check
3594 1184325 : if (ZoneRHHumidifyingSetPoint > ZoneRHDehumidifyingSetPoint) {
3595 0 : if (humidityControlZone.ErrorIndex == 0) {
3596 0 : ShowWarningMessage(
3597 0 : state, format("HUMIDISTAT: The humidifying setpoint is above the dehumidifying setpoint in {}", humidityControlZone.ControlName));
3598 0 : ShowContinueError(state, "The zone humidifying setpoint is set to the dehumidifying setpoint.");
3599 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
3600 : }
3601 0 : ShowRecurringWarningErrorAtEnd(state,
3602 : "The humidifying setpoint is still above the dehumidifying setpoint",
3603 0 : humidityControlZone.ErrorIndex,
3604 : ZoneRHHumidifyingSetPoint,
3605 : ZoneRHHumidifyingSetPoint);
3606 0 : ZoneRHHumidifyingSetPoint = ZoneRHDehumidifyingSetPoint;
3607 : }
3608 1184325 : if (ZoneRHHumidifyingSetPoint == ZoneRHDehumidifyingSetPoint) {
3609 605618 : SingleSetPoint = true;
3610 : }
3611 1184325 : ControlledHumidZoneFlag = true;
3612 :
3613 : } // HumidControlledZoneNum
3614 :
3615 : // if zone latent sizing is requested but no humidistat exists
3616 31432634 : if (state.dataGlobal->DoingSizing && !ControlledHumidZoneFlag && state.dataHeatBal->DoLatentSizing) {
3617 43500 : for (size_t zoneEqConfigNum = 1; zoneEqConfigNum <= state.dataZoneEquip->ZoneEquipConfig.size(); ++zoneEqConfigNum) {
3618 43500 : auto &zoneEqConfig = state.dataZoneEquip->ZoneEquipConfig(zoneEqConfigNum);
3619 43500 : if (!zoneEqConfig.IsControlled) {
3620 19686 : continue;
3621 : }
3622 23814 : int ZoneSizNum = Util::FindItemInList(zoneEqConfig.ZoneName, state.dataSize->ZoneSizingInput, &DataSizing::ZoneSizingInputData::ZoneName);
3623 : // should use the first Sizing:Zone object if not found
3624 23814 : if (ZoneSizNum == 0 && !state.dataSize->ZoneSizingInput.empty()) {
3625 0 : ZoneSizNum = 1;
3626 : }
3627 23814 : if (ZoneSizNum > 0) {
3628 23814 : auto &zoneSizingInput = state.dataSize->ZoneSizingInput(ZoneSizNum);
3629 23814 : if (zoneSizingInput.zoneLatentSizing) {
3630 47628 : ZoneRHDehumidifyingSetPoint = (zoneSizingInput.zoneRHDehumidifySched != nullptr)
3631 23814 : ? zoneSizingInput.zoneRHDehumidifySched->getCurrentVal()
3632 : : zoneSizingInput.zoneRHDehumidifySetPoint;
3633 47628 : ZoneRHHumidifyingSetPoint = (zoneSizingInput.zoneRHHumidifySched != nullptr)
3634 23814 : ? zoneSizingInput.zoneRHHumidifySched->getCurrentVal()
3635 : : zoneSizingInput.zoneRHHumidifySetPoint;
3636 23814 : if (ZoneRHHumidifyingSetPoint > ZoneRHDehumidifyingSetPoint) {
3637 0 : ZoneRHHumidifyingSetPoint = ZoneRHDehumidifyingSetPoint;
3638 : }
3639 23814 : if (ZoneRHHumidifyingSetPoint == ZoneRHDehumidifyingSetPoint) {
3640 19686 : SingleSetPoint = true;
3641 : }
3642 23814 : ControlledHumidZoneFlag = true;
3643 : }
3644 : }
3645 23814 : break;
3646 : }
3647 : }
3648 :
3649 31432634 : Real64 LoadToHumidifySetPoint = 0.0; // Moisture load at humidifying set point
3650 31432634 : Real64 LoadToDehumidifySetPoint = 0.0; // Moisture load at dehumidifying set point
3651 31432634 : Real64 totalOutputRequired = 0.0;
3652 31432634 : if (ControlledHumidZoneFlag) {
3653 :
3654 : // Calculate hourly humidity ratio from infiltration + humidity added from latent load
3655 : // to determine system added/subtracted moisture.
3656 1208139 : Real64 LatentGain = this->latentGain + state.dataHeatBalFanSys->SumLatentHTRadSys(zoneNum) + state.dataHeatBalFanSys->SumLatentPool(zoneNum);
3657 :
3658 1208139 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
3659 :
3660 : // Calculate the coefficients for the 3rd Order derivative for final
3661 : // zone humidity ratio. The A, B, C coefficients are analogous to the heat balance.
3662 : // SumHmARaW and SumHmARa will be used with the Moisture Balance on the building elements and
3663 : // are currently set to zero when the CTF only version is used.
3664 :
3665 : // The density of air and latent heat of vaporization are calculated as functions.
3666 1208139 : Real64 RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->ZT, this->airHumRat, RoutineName);
3667 1208139 : Real64 H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(this->airHumRat, this->ZT);
3668 :
3669 : // Assume that the system will have flow
3670 1208139 : Real64 A = 0.0;
3671 1208139 : Real64 B = 0.0;
3672 1208139 : Real64 C = 0.0;
3673 2375201 : if (state.afn->multizone_always_simulated ||
3674 1167062 : (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
3675 0 : state.afn->AirflowNetworkFanActivated)) {
3676 : // Multizone airflow calculated in AirflowNetwork
3677 41077 : B = (LatentGain / H2OHtOfVap) + state.afn->exchangeData(zoneNum).SumMHrW + state.afn->exchangeData(zoneNum).SumMMHrW + this->SumHmARaW;
3678 41077 : A = state.afn->exchangeData(zoneNum).SumMHr + state.afn->exchangeData(zoneNum).SumMMHr + this->SumHmARa;
3679 : } else {
3680 1167062 : B = (LatentGain / H2OHtOfVap) + ((this->OAMFL + this->VAMFL + this->CTMFL) * state.dataEnvrn->OutHumRat) + this->EAMFLxHumRat +
3681 1167062 : this->SumHmARaW + this->MixingMassFlowXHumRat + this->MDotOA * state.dataEnvrn->OutHumRat;
3682 1167062 : A = this->OAMFL + this->VAMFL + this->EAMFL + this->CTMFL + this->SumHmARa + this->MixingMassFlowZone + this->MDotOA;
3683 : }
3684 1208139 : Real64 volume = 0.0;
3685 1208139 : if (spaceNum > 0) {
3686 0 : volume = state.dataHeatBal->space(spaceNum).Volume;
3687 : } else {
3688 1208139 : volume = thisZone.Volume;
3689 : }
3690 1208139 : C = RhoAir * volume * thisZone.ZoneVolCapMultpMoist / TimeStepSysSec;
3691 :
3692 1208139 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
3693 0 : auto &roomAFNInfo = state.dataRoomAir->AFNZoneInfo(zoneNum);
3694 0 : int RoomAirNode = roomAFNInfo.ControlAirNodeID;
3695 0 : H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(roomAFNInfo.Node(RoomAirNode).HumRat, roomAFNInfo.Node(RoomAirNode).AirTemp);
3696 0 : A = roomAFNInfo.Node(RoomAirNode).SumLinkM + roomAFNInfo.Node(RoomAirNode).SumHmARa;
3697 0 : B = (roomAFNInfo.Node(RoomAirNode).SumIntLatentGain / H2OHtOfVap) + roomAFNInfo.Node(RoomAirNode).SumLinkMW +
3698 0 : roomAFNInfo.Node(RoomAirNode).SumHmARaW;
3699 0 : C = roomAFNInfo.Node(RoomAirNode).RhoAir * roomAFNInfo.Node(RoomAirNode).AirVolume * thisZone.ZoneVolCapMultpMoist / TimeStepSysSec;
3700 : }
3701 :
3702 : // Use a 3rd Order derivative to predict zone moisture addition or removal and
3703 : // smooth the changes using the zone air capacitance. Positive values of Moist Load means that
3704 : // this amount of moisture must be added to the zone to reach the setpoint. Negative values represent
3705 : // the amount of moisture that must be removed by the system.
3706 : // MoistLoadHumidSetPoint = massflow * HumRat = kgDryAir/s * kgWater/kgDryAir = kgWater/s
3707 : Real64 WZoneSetPoint =
3708 1208139 : Psychrometrics::PsyWFnTdbRhPb(state, this->ZT, (ZoneRHHumidifyingSetPoint / 100.0), state.dataEnvrn->OutBaroPress, RoutineName);
3709 1208139 : Real64 exp_700_A_C(0.0);
3710 1208139 : if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::ThirdOrder) {
3711 902292 : LoadToHumidifySetPoint =
3712 1804584 : ((11.0 / 6.0) * C + A) * WZoneSetPoint -
3713 902292 : (B + C * (3.0 * this->WPrevZoneTSTemp[0] - (3.0 / 2.0) * this->WPrevZoneTSTemp[1] + (1.0 / 3.0) * this->WPrevZoneTSTemp[2]));
3714 : // Exact solution
3715 305847 : } else if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::AnalyticalSolution) {
3716 305847 : if (A == 0.0) { // B=0
3717 49711 : LoadToHumidifySetPoint = C * (WZoneSetPoint - this->W1) - B;
3718 : } else {
3719 256136 : exp_700_A_C = std::exp(min(700.0, -A / C)); // Tuned Save expensive value
3720 256136 : LoadToHumidifySetPoint = A * (WZoneSetPoint - this->W1 * exp_700_A_C) / (1.0 - exp_700_A_C) - B;
3721 : }
3722 0 : } else if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::EulerMethod) {
3723 0 : LoadToHumidifySetPoint = C * (WZoneSetPoint - this->W1) + A * WZoneSetPoint - B;
3724 : }
3725 1208139 : if (RAFNFrac > 0.0) {
3726 0 : LoadToHumidifySetPoint = LoadToHumidifySetPoint / RAFNFrac;
3727 : }
3728 : WZoneSetPoint =
3729 1208139 : Psychrometrics::PsyWFnTdbRhPb(state, this->ZT, (ZoneRHDehumidifyingSetPoint / 100.0), state.dataEnvrn->OutBaroPress, RoutineName);
3730 1208139 : if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::ThirdOrder) {
3731 902292 : LoadToDehumidifySetPoint =
3732 1804584 : ((11.0 / 6.0) * C + A) * WZoneSetPoint -
3733 902292 : (B + C * (3.0 * this->WPrevZoneTSTemp[0] - (3.0 / 2.0) * this->WPrevZoneTSTemp[1] + (1.0 / 3.0) * this->WPrevZoneTSTemp[2]));
3734 : // Exact solution
3735 305847 : } else if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::AnalyticalSolution) {
3736 305847 : if (A == 0.0) { // B=0
3737 49711 : LoadToDehumidifySetPoint = C * (WZoneSetPoint - this->W1) - B;
3738 : } else {
3739 256136 : LoadToDehumidifySetPoint = A * (WZoneSetPoint - this->W1 * exp_700_A_C) / (1.0 - exp_700_A_C) - B; // exp_700_A_C set above
3740 : }
3741 0 : } else if (state.dataHeatBal->ZoneAirSolutionAlgo == DataHeatBalance::SolutionAlgo::EulerMethod) {
3742 0 : LoadToDehumidifySetPoint = C * (WZoneSetPoint - this->W1) + A * WZoneSetPoint - B;
3743 : }
3744 1208139 : if (RAFNFrac > 0.0) {
3745 0 : LoadToDehumidifySetPoint = LoadToDehumidifySetPoint / RAFNFrac;
3746 : }
3747 :
3748 : // The load is added to the TotalOutputRequired as in the Temperature Predictor. There is also the remaining
3749 : // output variable for those who will use this for humidity control and stored in DataZoneEnergyDemands with the
3750 : // analogous temperature terms.
3751 :
3752 1208139 : if (SingleSetPoint) {
3753 625304 : totalOutputRequired = LoadToHumidifySetPoint;
3754 : } else {
3755 582835 : if (LoadToHumidifySetPoint > 0.0 && LoadToDehumidifySetPoint > 0.0) {
3756 142560 : totalOutputRequired = LoadToHumidifySetPoint;
3757 440275 : } else if (LoadToHumidifySetPoint < 0.0 && LoadToDehumidifySetPoint < 0.0) {
3758 131052 : totalOutputRequired = LoadToDehumidifySetPoint;
3759 309223 : } else if (LoadToHumidifySetPoint <= 0.0 && LoadToDehumidifySetPoint >= 0.0) { // deadband includes zero loads
3760 309223 : totalOutputRequired = 0.0;
3761 : } else { // this should never occur!
3762 0 : ShowSevereError(
3763 : state, "Humidistat: Unanticipated combination of humidifying and dehumidifying loads - report to EnergyPlus Development Team");
3764 0 : ShowContinueErrorTimeStamp(state, format("occurs in Zone = {}", thisZone.Name));
3765 0 : ShowContinueError(
3766 : state,
3767 0 : format("LoadToHumidifySetPoint={:.5R}, LoadToDehumidifySetPoint={:.5R}", LoadToHumidifySetPoint, LoadToDehumidifySetPoint));
3768 0 : ShowContinueError(state, format("Zone RH Humidifying Set-point={:.1R}", ZoneRHHumidifyingSetPoint));
3769 0 : ShowContinueError(state, format("Zone RH Dehumidifying Set-point={:.2R}", ZoneRHDehumidifyingSetPoint));
3770 0 : ShowFatalError(state, "Program terminates due to above conditions.");
3771 : }
3772 : }
3773 : }
3774 :
3775 : // Apply zone multipliers as needed or set to zero
3776 31432634 : if (spaceNum > 0) {
3777 86394 : auto &thisspaceSysMoistureDemand = state.dataZoneEnergyDemand->spaceSysMoistureDemand(spaceNum);
3778 86394 : if (ControlledHumidZoneFlag) {
3779 0 : thisspaceSysMoistureDemand.reportMoistLoadsZoneMultiplier(
3780 : state, zoneNum, totalOutputRequired, LoadToHumidifySetPoint, LoadToDehumidifySetPoint);
3781 : } else {
3782 86394 : thisspaceSysMoistureDemand.TotalOutputRequired = 0.0;
3783 86394 : thisspaceSysMoistureDemand.OutputRequiredToDehumidifyingSP = 0.0;
3784 86394 : thisspaceSysMoistureDemand.OutputRequiredToHumidifyingSP = 0.0;
3785 : }
3786 : } else {
3787 31346240 : auto &thisZoneSysMoistureDemand = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(zoneNum);
3788 31346240 : if (ControlledHumidZoneFlag) {
3789 1208139 : thisZoneSysMoistureDemand.reportMoistLoadsZoneMultiplier(
3790 : state, zoneNum, totalOutputRequired, LoadToHumidifySetPoint, LoadToDehumidifySetPoint);
3791 : } else {
3792 30138101 : thisZoneSysMoistureDemand.TotalOutputRequired = 0.0;
3793 30138101 : thisZoneSysMoistureDemand.OutputRequiredToDehumidifyingSP = 0.0;
3794 30138101 : thisZoneSysMoistureDemand.OutputRequiredToHumidifyingSP = 0.0;
3795 : }
3796 : }
3797 31432634 : }
3798 :
3799 3896580 : Real64 correctZoneAirTemps(EnergyPlusData &state,
3800 : bool useZoneTimeStepHistory // if true then use zone timestep history, if false use system time step history
3801 : )
3802 : {
3803 3896580 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
3804 3896580 : Real64 maxTempChange = DataPrecisionGlobals::constant_zero; // Max absolute air temperature change between previous and current timestep
3805 35241392 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
3806 31344812 : auto &thisZoneHB = s_ztpc->zoneHeatBalance(zoneNum);
3807 31344812 : Real64 zoneTempChange = thisZoneHB.correctAirTemp(state, useZoneTimeStepHistory, zoneNum);
3808 31344812 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
3809 62753488 : for (int spaceNum : thisZone.spaceIndexes) {
3810 31408676 : auto &thisSpaceHB = s_ztpc->spaceHeatBalance(spaceNum);
3811 31495070 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation &&
3812 86394 : !state.dataGlobal->DoingSizing) { // Need space air temps to match zone temps for sizing
3813 29170 : Real64 spaceTempChange = thisSpaceHB.correctAirTemp(state, useZoneTimeStepHistory, zoneNum, spaceNum);
3814 29170 : maxTempChange = max(maxTempChange, spaceTempChange);
3815 : } else {
3816 : // If doing sizing and zone is controlled, then set space node to match zone node
3817 31379506 : if (state.dataHeatBal->doSpaceHeatBalanceSizing && thisZone.IsControlled) {
3818 50212 : auto const &thisZoneNode = state.dataLoopNodes->Node(thisZone.SystemZoneNodeNumber);
3819 50212 : auto &thisSpaceNode = state.dataLoopNodes->Node(state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber);
3820 50212 : thisSpaceNode.Temp = thisZoneNode.Temp;
3821 50212 : thisSpaceNode.HumRat = thisZoneNode.HumRat;
3822 50212 : thisSpaceNode.Enthalpy = thisZoneNode.Enthalpy;
3823 : }
3824 : // If no SpaceHB or doing sizing, then set space temps and humrat to match zone
3825 31379506 : thisSpaceHB.ZT = thisZoneHB.ZT;
3826 31379506 : thisSpaceHB.ZTM = thisZoneHB.ZTM;
3827 31379506 : thisSpaceHB.MAT = thisZoneHB.MAT;
3828 31379506 : thisSpaceHB.airHumRat = thisZoneHB.airHumRat;
3829 31379506 : thisSpaceHB.airRelHum = thisZoneHB.airRelHum;
3830 : // thisSpaceHB.ZTAVComf = thisZoneHB.ZTAVComf;
3831 : }
3832 31344812 : }
3833 31344812 : maxTempChange = max(maxTempChange, zoneTempChange);
3834 :
3835 31344812 : CalcZoneComponentLoadSums(state, zoneNum, &s_ztpc->zoneHeatBalance(zoneNum), state.dataHeatBal->ZnAirRpt(zoneNum));
3836 31344812 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation) {
3837 150192 : for (int spaceNum : thisZone.spaceIndexes) {
3838 86394 : CalcZoneComponentLoadSums(state, zoneNum, &s_ztpc->spaceHeatBalance(spaceNum), state.dataHeatBal->spaceAirRpt(spaceNum));
3839 63798 : }
3840 : }
3841 : }
3842 3896580 : return maxTempChange;
3843 : }
3844 :
3845 31373982 : Real64 ZoneSpaceHeatBalanceData::correctAirTemp(
3846 : EnergyPlusData &state,
3847 : bool const useZoneTimeStepHistory, // if true then use zone timestep history, if false use system time step history
3848 : int const zoneNum,
3849 : int const spaceNum)
3850 : {
3851 :
3852 : // SUBROUTINE INFORMATION:
3853 : // AUTHOR Russell Taylor
3854 : // MODIFIED November 1999, LKL; November 2016 Sang Hoon Lee, Tianzhen Hong, Rongpeng Zhang;
3855 : // RE-ENGINEERED July 2003 (Peter Graham Ellis)
3856 : // February 2008 (Brent Griffith reworked history )
3857 :
3858 : // PURPOSE OF THIS SUBROUTINE:
3859 : // This subroutine updates the zone air temperature and modifies the system
3860 : // time step.
3861 :
3862 : static constexpr std::string_view RoutineName("correctAirTemp");
3863 :
3864 31373982 : Real64 tempChange = DataPrecisionGlobals::constant_zero; // Zone or space air temperature change between previous and current timestep
3865 :
3866 31373982 : assert(zoneNum > 0);
3867 31373982 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
3868 :
3869 : // Update zone temperatures
3870 :
3871 31373982 : Real64 ZoneMult = thisZone.Multiplier * thisZone.ListMultiplier;
3872 :
3873 31373982 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
3874 :
3875 : // update the variables actually used in the balance equations.
3876 31373982 : if (!useZoneTimeStepHistory) {
3877 10818069 : this->ZTM = this->DSXMAT;
3878 10818069 : this->WPrevZoneTSTemp = this->DSWPrevZoneTS;
3879 : } else {
3880 20555913 : this->ZTM = this->XMAT;
3881 20555913 : this->WPrevZoneTSTemp = this->WPrevZoneTS;
3882 : }
3883 :
3884 31373982 : Real64 volume = 0.0;
3885 31373982 : if (spaceNum > 0) {
3886 29170 : volume = state.dataHeatBal->space(spaceNum).Volume;
3887 : } else {
3888 31344812 : volume = thisZone.Volume;
3889 : }
3890 94121946 : this->AirPowerCap = volume * thisZone.ZoneVolCapMultpSens *
3891 31373982 : Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->MAT, this->airHumRat, RoutineName) *
3892 31373982 : Psychrometrics::PsyCpAirFnW(this->airHumRat) / TimeStepSysSec;
3893 :
3894 : // SpaceHB TODO: For now, room air model is only for zones
3895 31373982 : if (spaceNum == 0) {
3896 31344812 : RoomAir::ManageAirModel(state, zoneNum);
3897 : }
3898 :
3899 : // Calculate the various heat balance sums
3900 31373982 : this->calcZoneOrSpaceSums(state, true, zoneNum, spaceNum);
3901 :
3902 : // Sum all convective internal gains except for people: SumIntGainExceptPeople
3903 31373982 : if (state.dataHybridModel->FlagHybridModel_PC) {
3904 : // TODO: For now, don't do space heat balance with hybrid model
3905 8212 : this->SumIntGainExceptPeople = InternalHeatGains::SumAllInternalConvectionGainsExceptPeople(state, zoneNum);
3906 : }
3907 :
3908 : // ZoneTempHistoryTerm = (3.0D0 * ZTM1(zoneNum) - (3.0D0/2.0D0) * ZTM2(zoneNum) + (1.0D0/3.0D0) * ZTM3(zoneNum))
3909 31373982 : int ZoneNodeNum = thisZone.SystemZoneNodeNumber;
3910 31373982 : if (spaceNum > 0) {
3911 29170 : ZoneNodeNum = state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber;
3912 : }
3913 :
3914 31373982 : Real64 SNLoad = 0.0;
3915 :
3916 31373982 : if (ZoneNodeNum > 0) { // This zone is controlled by a zone equipment configuration or zone plenum
3917 28233887 : auto &thisSystemNode = state.dataLoopNodes->Node(ZoneNodeNum);
3918 :
3919 : // Heat balance coefficients for controlled zone, i.e. with system air flow
3920 28233887 : this->TempDepCoef = this->SumHA + this->SumMCp + this->SumSysMCp;
3921 28233887 : this->TempIndCoef = this->SumIntGain + this->SumHATsurf - this->SumHATref + this->SumMCpT + this->SumSysMCpT +
3922 28233887 : (this->NonAirSystemResponse / ZoneMult + this->SysDepZoneLoadsLagged);
3923 :
3924 28233887 : if (state.afn->distribution_simulated) {
3925 233502 : this->TempIndCoef += state.afn->exchangeData(zoneNum).TotalSen;
3926 : }
3927 :
3928 : // Solve for zone air temperature
3929 28233887 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
3930 14825878 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
3931 14825878 : this->ZT = (this->TempIndCoef + this->AirPowerCap * (3.0 * this->ZTM[0] - (3.0 / 2.0) * this->ZTM[1] + (1.0 / 3.0) * this->ZTM[2])) /
3932 14825878 : ((11.0 / 6.0) * this->AirPowerCap + this->TempDepCoef);
3933 14825878 : } break;
3934 13376407 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
3935 13376407 : if (this->TempDepCoef == 0.0) { // B=0
3936 0 : this->ZT = this->T1 + this->TempIndCoef / this->AirPowerCap;
3937 : } else {
3938 13376407 : this->ZT = (this->T1 - this->TempIndCoef / this->TempDepCoef) * std::exp(min(700.0, -this->TempDepCoef / this->AirPowerCap)) +
3939 13376407 : this->TempIndCoef / this->TempDepCoef;
3940 : }
3941 13376407 : } break;
3942 31602 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
3943 31602 : this->ZT = (this->AirPowerCap * this->T1 + this->TempIndCoef) / (this->AirPowerCap + this->TempDepCoef);
3944 31602 : } break;
3945 0 : default:
3946 0 : break;
3947 : }
3948 : // Update zone node temperature and thermostat temperature unless already updated in Room Air Model,
3949 : // calculate load correction factor
3950 28233887 : if (!state.dataRoomAir->anyNonMixingRoomAirModel) {
3951 : // Fully mixed
3952 28124920 : thisSystemNode.Temp = this->ZT;
3953 : // SpaceHB TODO: What to do here if this is for space
3954 28124920 : if (spaceNum == 0) {
3955 28095750 : state.dataHeatBalFanSys->TempTstatAir(zoneNum) = this->ZT;
3956 : }
3957 28124920 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0;
3958 : } else {
3959 108967 : auto const &thisAirModel = state.dataRoomAir->AirModel(zoneNum);
3960 108967 : if ((thisAirModel.AirModel == RoomAir::RoomAirModel::Mixing) || (!thisAirModel.SimAirModel)) {
3961 : // Fully mixed
3962 41760 : thisSystemNode.Temp = this->ZT;
3963 : // SpaceHB TODO: What to do here if this is for space
3964 41760 : if (spaceNum == 0) {
3965 41760 : state.dataHeatBalFanSys->TempTstatAir(zoneNum) = this->ZT;
3966 : }
3967 41760 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0;
3968 67207 : } else if (state.dataRoomAir->IsZoneDispVent3Node(zoneNum) || state.dataRoomAir->IsZoneUFAD(zoneNum)) {
3969 : // UCSDDV: Not fully mixed - calculate factor to correct load for fully mixed assumption
3970 : // Space HB TODO: Space HB doesn't mix with DV etc.
3971 13152 : if (this->SumSysMCp > HVAC::SmallMassFlow) {
3972 12303 : Real64 TempSupplyAir = this->SumSysMCpT / this->SumSysMCp; // Non-negligible flow, calculate supply air temperature
3973 12303 : if (std::abs(TempSupplyAir - this->ZT) > state.dataHeatBal->TempConvergTol) {
3974 12035 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = (TempSupplyAir - thisSystemNode.Temp) / (TempSupplyAir - this->ZT);
3975 : // constrain value to something reasonable
3976 12035 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = max(-3.0, state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum));
3977 12035 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = min(3.0, state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum));
3978 :
3979 : } else {
3980 268 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0; // Indeterminate
3981 : }
3982 : } else {
3983 : // Negligible flow, assume mixed - reasonable lagged starting value for first step time with significant flow
3984 849 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0;
3985 : }
3986 54055 : } else if (thisAirModel.SimAirModel && ((thisAirModel.AirModel == RoomAir::RoomAirModel::UserDefined) ||
3987 16039 : (thisAirModel.AirModel == RoomAir::RoomAirModel::DispVent1Node))) {
3988 46642 : if (this->SumSysMCp > HVAC::SmallMassFlow) {
3989 46282 : Real64 TempSupplyAir = this->SumSysMCpT / this->SumSysMCp; // Non-negligible flow, calculate supply air temperature
3990 46282 : if (std::abs(TempSupplyAir - this->ZT) > state.dataHeatBal->TempConvergTol) {
3991 46278 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = (TempSupplyAir - thisSystemNode.Temp) / (TempSupplyAir - this->ZT);
3992 : // constrain value
3993 46278 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = max(-3.0, state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum));
3994 46278 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = min(3.0, state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum));
3995 :
3996 : } else {
3997 4 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0; // Indeterminate
3998 : }
3999 : } else {
4000 : // Negligible flow, assume mixed - reasonable lagged starting value for first step time with significant flow
4001 360 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0;
4002 : }
4003 54055 : } else if (thisAirModel.AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
4004 : // Zone node used in the RoomAirflowNetwork model
4005 7413 : this->ZT = state.dataRoomAir->AFNZoneInfo(zoneNum).Node(state.dataRoomAir->AFNZoneInfo(zoneNum).ControlAirNodeID).AirTemp;
4006 7413 : thisSystemNode.Temp = this->ZT;
4007 : // SpaceHB TODO: What to do here if this is for space
4008 7413 : if (spaceNum == 0) {
4009 7413 : state.dataHeatBalFanSys->TempTstatAir(zoneNum) = this->ZT;
4010 : }
4011 7413 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0;
4012 : } else {
4013 0 : thisSystemNode.Temp = this->ZT;
4014 : // SpaceHB TODO: What to do here if this is for space
4015 0 : if (spaceNum == 0) {
4016 0 : state.dataHeatBalFanSys->TempTstatAir(zoneNum) = this->ZT;
4017 : }
4018 0 : state.dataHeatBalFanSys->LoadCorrectionFactor(zoneNum) = 1.0;
4019 : }
4020 : }
4021 :
4022 : // Sensible load is the enthalpy into the zone minus the enthalpy that leaves the zone.
4023 28233887 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(this->airHumRat);
4024 28233887 : Real64 ZoneEnthalpyIn = this->SumSysMCpT;
4025 :
4026 : // SNLOAD is the single zone load, without Zone Multiplier or Zone List Multiplier
4027 28233887 : SNLoad = ZoneEnthalpyIn - (thisSystemNode.MassFlowRate / ZoneMult) * CpAir * thisSystemNode.Temp + this->NonAirSystemResponse / ZoneMult +
4028 28233887 : this->SysDepZoneLoadsLagged;
4029 :
4030 : } else {
4031 :
4032 : // Heat balance coefficients for uncontrolled zone, i.e. without system air flow
4033 3140095 : this->TempDepCoef = this->SumHA + this->SumMCp;
4034 3140095 : this->TempIndCoef = this->SumIntGain + this->SumHATsurf - this->SumHATref + this->SumMCpT;
4035 :
4036 3140095 : if (state.afn->distribution_simulated) {
4037 146998 : this->TempIndCoef += state.afn->exchangeData(zoneNum).TotalSen;
4038 : }
4039 :
4040 : // Solve for zone air temperature
4041 3140095 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
4042 2206769 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
4043 2206769 : this->ZT = (this->TempIndCoef + this->AirPowerCap * (3.0 * this->ZTM[0] - (3.0 / 2.0) * this->ZTM[1] + (1.0 / 3.0) * this->ZTM[2])) /
4044 2206769 : ((11.0 / 6.0) * this->AirPowerCap + this->TempDepCoef);
4045 : // Exact solution
4046 2206769 : } break;
4047 926718 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
4048 926718 : if (this->TempDepCoef == 0.0) { // B=0
4049 0 : this->ZT = this->T1 + this->TempIndCoef / this->AirPowerCap;
4050 : } else {
4051 926718 : this->ZT = (this->T1 - this->TempIndCoef / this->TempDepCoef) * std::exp(min(700.0, -this->TempDepCoef / this->AirPowerCap)) +
4052 926718 : this->TempIndCoef / this->TempDepCoef;
4053 : }
4054 926718 : } break;
4055 6608 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
4056 6608 : this->ZT = (this->AirPowerCap * this->T1 + this->TempIndCoef) / (this->AirPowerCap + this->TempDepCoef);
4057 6608 : } break;
4058 0 : default:
4059 0 : break;
4060 : }
4061 :
4062 : // SpaceHB TODO: For now, room air model is only for zones
4063 3140095 : if (spaceNum == 0 && state.dataRoomAir->anyNonMixingRoomAirModel) {
4064 51988 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
4065 0 : this->ZT = state.dataRoomAir->AFNZoneInfo(zoneNum).Node(state.dataRoomAir->AFNZoneInfo(zoneNum).ControlAirNodeID).AirTemp;
4066 : }
4067 : }
4068 :
4069 : // No sensible load
4070 3140095 : SNLoad = 0.0;
4071 : }
4072 :
4073 : // Hybrid modeling start
4074 : // SpaceHB TODO: For now, hybrid model is only for zones
4075 31373982 : if (spaceNum == 0 && state.dataHybridModel->FlagHybridModel) {
4076 30204 : auto &hmZone = state.dataHybridModel->hybridModelZones(zoneNum);
4077 32004 : if ((hmZone.InfiltrationCalc_T || hmZone.InternalThermalMassCalc_T || hmZone.PeopleCountCalc_T) && (!state.dataGlobal->WarmupFlag) &&
4078 1800 : (!state.dataGlobal->DoingSizing)) {
4079 1800 : InverseModelTemperature(state,
4080 : zoneNum,
4081 : this->SumIntGain,
4082 : this->SumIntGainExceptPeople,
4083 : this->SumHA,
4084 : this->SumHATsurf,
4085 : this->SumHATref,
4086 : this->SumMCp,
4087 : this->SumMCpT,
4088 : this->SumSysMCp,
4089 : this->SumSysMCpT,
4090 : this->AirPowerCap);
4091 : }
4092 : }
4093 :
4094 31373982 : this->MAT = this->ZT;
4095 :
4096 : // Determine sensible load heating/cooling rate and energy
4097 31373982 : if (spaceNum > 0) {
4098 29170 : state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).reportZoneAirSystemSensibleLoads(state, SNLoad);
4099 : } else {
4100 31344812 : state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).reportZoneAirSystemSensibleLoads(state, SNLoad);
4101 : }
4102 :
4103 : // Final humidity calcs
4104 31373982 : this->correctHumRat(state, zoneNum, spaceNum);
4105 :
4106 31373982 : this->airHumRat = this->airHumRatTemp;
4107 31373982 : this->airRelHum = 100.0 * Psychrometrics::PsyRhFnTdbWPb(state, this->ZT, this->airHumRat, state.dataEnvrn->OutBaroPress, RoutineName);
4108 :
4109 : // tempChange is used by HVACManager to determine if the timestep needs to be shortened.
4110 31373982 : bool isMixed = true;
4111 : // SpaceHB TODO: For now, room air model is only for zones
4112 31373982 : if (spaceNum == 0 && state.dataRoomAir->anyNonMixingRoomAirModel) {
4113 315590 : isMixed = !((state.dataRoomAir->IsZoneDispVent3Node(zoneNum) && !state.dataRoomAir->ZoneDispVent3NodeMixedFlag(zoneNum)) ||
4114 154635 : (state.dataRoomAir->IsZoneUFAD(zoneNum) && !state.dataRoomAir->ZoneUFADMixedFlag(zoneNum)));
4115 : }
4116 31373982 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
4117 17032647 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
4118 17032647 : if (isMixed) {
4119 17019495 : tempChange = max(tempChange, std::abs(this->ZT - this->ZTM[0]));
4120 : } else {
4121 26304 : tempChange = max(tempChange,
4122 13152 : max(std::abs(state.dataRoomAir->ZTOC(zoneNum) - state.dataRoomAir->ZTMOC(zoneNum)[0]),
4123 13152 : std::abs(state.dataRoomAir->ZTMX(zoneNum) - state.dataRoomAir->ZTMMX(zoneNum)[0])));
4124 : }
4125 17032647 : } break;
4126 14341335 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution:
4127 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
4128 14341335 : if (isMixed) {
4129 14339906 : tempChange = max(tempChange, std::abs(this->ZT - this->T1));
4130 : } else {
4131 1429 : tempChange = max(tempChange,
4132 1429 : max(std::abs(state.dataRoomAir->ZTOC(zoneNum) - state.dataRoomAir->Zone1OC(zoneNum)),
4133 1429 : std::abs(state.dataRoomAir->ZTMX(zoneNum) - state.dataRoomAir->Zone1MX(zoneNum))));
4134 : }
4135 14341335 : } break;
4136 0 : default:
4137 0 : break;
4138 : }
4139 :
4140 31373982 : return tempChange;
4141 : }
4142 :
4143 2828212 : void PushZoneTimestepHistories(EnergyPlusData &state)
4144 : {
4145 :
4146 : // SUBROUTINE INFORMATION:
4147 : // AUTHOR Brent Griffith
4148 : // DATE WRITTEN February 2008
4149 :
4150 : // PURPOSE OF THIS SUBROUTINE:
4151 : // push histories for timestep advancing
4152 2828212 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
4153 23362447 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
4154 20534235 : s_ztpc->zoneHeatBalance(zoneNum).pushZoneTimestepHistory(state, zoneNum);
4155 20534235 : if (state.dataHeatBal->doSpaceHeatBalance) {
4156 113364 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
4157 64782 : s_ztpc->spaceHeatBalance(spaceNum).pushZoneTimestepHistory(state, zoneNum, spaceNum);
4158 48582 : }
4159 : }
4160 : }
4161 2828212 : }
4162 :
4163 20599017 : void ZoneSpaceHeatBalanceData::pushZoneTimestepHistory(EnergyPlusData &state, int const zoneNum, int const spaceNum)
4164 : {
4165 :
4166 20599017 : constexpr std::string_view routineName("pushTimestepHistories");
4167 20599017 : assert(zoneNum > 0);
4168 :
4169 20599017 : auto &thisAirModel = state.dataRoomAir->AirModel(zoneNum);
4170 :
4171 : // Push the temperature and humidity ratio histories
4172 :
4173 82396068 : for (int iHistory = 3; iHistory >= 1; --iHistory) {
4174 61797051 : this->XMAT[iHistory] = this->XMAT[iHistory - 1];
4175 61797051 : this->WPrevZoneTS[iHistory] = this->WPrevZoneTS[iHistory - 1];
4176 : }
4177 20599017 : this->XMAT[0] = this->ZTAV; // using average for whole zone time step.
4178 20599017 : this->XMPT = this->ZT;
4179 20599017 : this->WPrevZoneTS[0] = this->airHumRatAvg; // using average for whole zone time step.
4180 20599017 : this->airHumRat = this->airHumRatTemp;
4181 20599017 : this->WTimeMinusP = this->airHumRatTemp;
4182 20599017 : this->airRelHum = 100.0 * Psychrometrics::PsyRhFnTdbWPb(state, this->ZT, this->airHumRat, state.dataEnvrn->OutBaroPress, routineName);
4183 :
4184 : // SpaceHB TODO: For now, room air model is only for zones
4185 20599017 : if (spaceNum == 0) {
4186 20534235 : if (thisAirModel.AirModel == RoomAir::RoomAirModel::DispVent3Node || thisAirModel.AirModel == RoomAir::RoomAirModel::UFADInt ||
4187 20518617 : thisAirModel.AirModel == RoomAir::RoomAirModel::UFADExt) {
4188 26442 : state.dataRoomAir->XMATFloor(zoneNum)[3] = state.dataRoomAir->XMATFloor(zoneNum)[2];
4189 26442 : state.dataRoomAir->XMATFloor(zoneNum)[2] = state.dataRoomAir->XMATFloor(zoneNum)[1];
4190 26442 : state.dataRoomAir->XMATFloor(zoneNum)[1] = state.dataRoomAir->XMATFloor(zoneNum)[0];
4191 26442 : state.dataRoomAir->XMATFloor(zoneNum)[0] = state.dataRoomAir->ZTFloor(zoneNum);
4192 26442 : state.dataRoomAir->MATFloor(zoneNum) = state.dataRoomAir->ZTFloor(zoneNum);
4193 :
4194 26442 : state.dataRoomAir->XMATOC(zoneNum)[3] = state.dataRoomAir->XMATOC(zoneNum)[2];
4195 26442 : state.dataRoomAir->XMATOC(zoneNum)[2] = state.dataRoomAir->XMATOC(zoneNum)[1];
4196 26442 : state.dataRoomAir->XMATOC(zoneNum)[1] = state.dataRoomAir->XMATOC(zoneNum)[0];
4197 26442 : state.dataRoomAir->XMATOC(zoneNum)[0] = state.dataRoomAir->ZTOC(zoneNum);
4198 26442 : state.dataRoomAir->MATOC(zoneNum) = state.dataRoomAir->ZTOC(zoneNum);
4199 :
4200 26442 : state.dataRoomAir->XMATMX(zoneNum)[3] = state.dataRoomAir->XMATMX(zoneNum)[2];
4201 26442 : state.dataRoomAir->XMATMX(zoneNum)[2] = state.dataRoomAir->XMATMX(zoneNum)[1];
4202 26442 : state.dataRoomAir->XMATMX(zoneNum)[1] = state.dataRoomAir->XMATMX(zoneNum)[0];
4203 26442 : state.dataRoomAir->XMATMX(zoneNum)[0] = state.dataRoomAir->ZTMX(zoneNum);
4204 26442 : state.dataRoomAir->MATMX(zoneNum) = state.dataRoomAir->ZTMX(zoneNum);
4205 : }
4206 :
4207 : // for RoomAirflowNetwork model
4208 20534235 : if (thisAirModel.AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
4209 40425 : for (auto &afnNode : state.dataRoomAir->AFNZoneInfo(zoneNum).Node) {
4210 34650 : afnNode.AirTempX[3] = afnNode.AirTempX[2];
4211 34650 : afnNode.AirTempX[2] = afnNode.AirTempX[1];
4212 34650 : afnNode.AirTempX[1] = afnNode.AirTempX[0];
4213 34650 : afnNode.AirTempX[0] = afnNode.AirTemp;
4214 :
4215 34650 : afnNode.HumRatX[3] = afnNode.HumRatX[2];
4216 34650 : afnNode.HumRatX[2] = afnNode.HumRatX[1];
4217 34650 : afnNode.HumRatX[1] = afnNode.HumRatX[0];
4218 34650 : afnNode.HumRatX[0] = afnNode.HumRat;
4219 : }
4220 : }
4221 : }
4222 :
4223 20599017 : if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
4224 7787097 : this->TM2 = this->TMX;
4225 7787097 : this->TMX = this->ZTAV; // using average for whole zone time step.
4226 7787097 : this->WM2 = this->WMX;
4227 7787097 : this->WMX = this->airHumRatAvg; // using average for whole zone time step.
4228 : // SpaceHB TODO: For now, room air model is only for zones
4229 7787097 : if (spaceNum == 0) {
4230 7787097 : if (thisAirModel.AirModel == RoomAir::RoomAirModel::DispVent3Node || thisAirModel.AirModel == RoomAir::RoomAirModel::UFADInt ||
4231 7781319 : thisAirModel.AirModel == RoomAir::RoomAirModel::UFADExt) {
4232 5778 : state.dataRoomAir->ZoneM2Floor(zoneNum) = state.dataRoomAir->ZoneMXFloor(zoneNum);
4233 5778 : state.dataRoomAir->ZoneMXFloor(zoneNum) = state.dataRoomAir->ZTFloor(zoneNum); // using average for whole zone time step.
4234 5778 : state.dataRoomAir->ZoneM2OC(zoneNum) = state.dataRoomAir->ZoneMXOC(zoneNum);
4235 5778 : state.dataRoomAir->ZoneMXOC(zoneNum) = state.dataRoomAir->ZTOC(zoneNum); // using average for whole zone time step.
4236 5778 : state.dataRoomAir->ZoneM2MX(zoneNum) = state.dataRoomAir->ZoneMXMX(zoneNum);
4237 5778 : state.dataRoomAir->ZoneMXMX(zoneNum) = state.dataRoomAir->ZTMX(zoneNum); // using average for whole zone time step.
4238 : }
4239 :
4240 7787097 : if (thisAirModel.AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
4241 0 : for (auto &afnNode : state.dataRoomAir->AFNZoneInfo(zoneNum).Node) {
4242 0 : afnNode.AirTempT2 = afnNode.AirTempTX;
4243 0 : afnNode.AirTempTX = afnNode.AirTemp;
4244 :
4245 0 : afnNode.HumRatT2 = afnNode.HumRatTX;
4246 0 : afnNode.HumRatTX = afnNode.HumRat;
4247 : }
4248 : }
4249 : }
4250 : }
4251 20599017 : }
4252 :
4253 1068368 : void PushSystemTimestepHistories(EnergyPlusData &state)
4254 : {
4255 :
4256 : // SUBROUTINE INFORMATION:
4257 : // AUTHOR Brent Griffith
4258 : // DATE WRITTEN April 2008
4259 :
4260 : // PURPOSE OF THIS SUBROUTINE:
4261 : // Push the temperature and humidity ratio histories back in time
4262 1068368 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
4263 11878945 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
4264 10810577 : s_ztpc->zoneHeatBalance(zoneNum).pushSystemTimestepHistory(state, zoneNum);
4265 10810577 : if (state.dataHeatBal->doSpaceHeatBalance) {
4266 36828 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
4267 21612 : s_ztpc->spaceHeatBalance(spaceNum).pushSystemTimestepHistory(state, zoneNum, spaceNum);
4268 15216 : }
4269 : }
4270 : }
4271 1068368 : }
4272 :
4273 10832189 : void ZoneSpaceHeatBalanceData::pushSystemTimestepHistory(EnergyPlusData &state, int const zoneNum, int const spaceNum)
4274 : {
4275 10832189 : assert(zoneNum > 0);
4276 43328756 : for (int iHistory = 3; iHistory >= 1; --iHistory) {
4277 32496567 : this->DSXMAT[iHistory] = this->DSXMAT[iHistory - 1];
4278 32496567 : this->DSWPrevZoneTS[iHistory] = this->DSWPrevZoneTS[iHistory - 1];
4279 : }
4280 10832189 : this->DSXMAT[0] = this->MAT;
4281 10832189 : this->DSWPrevZoneTS[0] = this->airHumRat;
4282 :
4283 : // SpaceHB TODO: For now, room air model is only for zones
4284 10832189 : if (spaceNum == 0 && state.dataRoomAir->anyNonMixingRoomAirModel) {
4285 34733 : if (state.dataRoomAir->IsZoneDispVent3Node(zoneNum) || state.dataRoomAir->IsZoneUFAD(zoneNum)) {
4286 5868 : state.dataRoomAir->DSXMATFloor(zoneNum)[3] = state.dataRoomAir->DSXMATFloor(zoneNum)[2];
4287 5868 : state.dataRoomAir->DSXMATFloor(zoneNum)[2] = state.dataRoomAir->DSXMATFloor(zoneNum)[1];
4288 5868 : state.dataRoomAir->DSXMATFloor(zoneNum)[1] = state.dataRoomAir->DSXMATFloor(zoneNum)[0];
4289 5868 : state.dataRoomAir->DSXMATFloor(zoneNum)[0] = state.dataRoomAir->MATFloor(zoneNum);
4290 :
4291 5868 : state.dataRoomAir->DSXMATOC(zoneNum)[3] = state.dataRoomAir->DSXMATOC(zoneNum)[2];
4292 5868 : state.dataRoomAir->DSXMATOC(zoneNum)[2] = state.dataRoomAir->DSXMATOC(zoneNum)[1];
4293 5868 : state.dataRoomAir->DSXMATOC(zoneNum)[1] = state.dataRoomAir->DSXMATOC(zoneNum)[0];
4294 5868 : state.dataRoomAir->DSXMATOC(zoneNum)[0] = state.dataRoomAir->MATOC(zoneNum);
4295 :
4296 5868 : state.dataRoomAir->DSXMATMX(zoneNum)[3] = state.dataRoomAir->DSXMATMX(zoneNum)[2];
4297 5868 : state.dataRoomAir->DSXMATMX(zoneNum)[2] = state.dataRoomAir->DSXMATMX(zoneNum)[1];
4298 5868 : state.dataRoomAir->DSXMATMX(zoneNum)[1] = state.dataRoomAir->DSXMATMX(zoneNum)[0];
4299 5868 : state.dataRoomAir->DSXMATMX(zoneNum)[0] = state.dataRoomAir->MATMX(zoneNum);
4300 : }
4301 34733 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
4302 11466 : for (auto &afnNode : state.dataRoomAir->AFNZoneInfo(zoneNum).Node) {
4303 9828 : afnNode.AirTempDSX[3] = afnNode.AirTempDSX[2];
4304 9828 : afnNode.AirTempDSX[2] = afnNode.AirTempDSX[1];
4305 9828 : afnNode.AirTempDSX[1] = afnNode.AirTempDSX[0];
4306 9828 : afnNode.AirTempDSX[0] = afnNode.AirTemp;
4307 :
4308 9828 : afnNode.HumRatDSX[3] = afnNode.HumRatDSX[2];
4309 9828 : afnNode.HumRatDSX[2] = afnNode.HumRatDSX[1];
4310 9828 : afnNode.HumRatDSX[1] = afnNode.HumRatDSX[0];
4311 9828 : afnNode.HumRatDSX[0] = afnNode.HumRat;
4312 : }
4313 : }
4314 : }
4315 :
4316 10832189 : if (state.dataHeatBal->ZoneAirSolutionAlgo != DataHeatBalance::SolutionAlgo::ThirdOrder) {
4317 6554238 : this->TM2 = this->TMX;
4318 6554238 : this->TMX = this->MAT; // using average for whole zone time step.
4319 6554238 : this->WM2 = this->WMX;
4320 6554238 : this->WMX = this->airHumRatTemp; // using average for whole zone time step.
4321 :
4322 : // SpaceHB TODO: For now, room air model is only for zones
4323 6554238 : if (spaceNum == 0) {
4324 6554238 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::DispVent3Node ||
4325 13107646 : state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::UFADInt ||
4326 6553408 : state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::UFADExt) {
4327 830 : state.dataRoomAir->ZoneM2Floor(zoneNum) = state.dataRoomAir->ZoneMXFloor(zoneNum);
4328 830 : state.dataRoomAir->ZoneMXFloor(zoneNum) = state.dataRoomAir->ZTFloor(zoneNum); // using average for whole zone time step.
4329 830 : state.dataRoomAir->ZoneM2OC(zoneNum) = state.dataRoomAir->ZoneMXOC(zoneNum);
4330 830 : state.dataRoomAir->ZoneMXOC(zoneNum) = state.dataRoomAir->ZTOC(zoneNum); // using average for whole zone time step.
4331 830 : state.dataRoomAir->ZoneM2MX(zoneNum) = state.dataRoomAir->ZoneMXMX(zoneNum);
4332 830 : state.dataRoomAir->ZoneMXMX(zoneNum) = state.dataRoomAir->ZTMX(zoneNum); // using average for whole zone time step.
4333 : }
4334 6554238 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
4335 0 : for (int LoopNode = 1; LoopNode <= state.dataRoomAir->AFNZoneInfo(zoneNum).NumOfAirNodes; ++LoopNode) {
4336 0 : auto &afnNode = state.dataRoomAir->AFNZoneInfo(zoneNum).Node(LoopNode);
4337 0 : afnNode.AirTempT2 = afnNode.AirTempTX;
4338 0 : afnNode.AirTempTX = afnNode.AirTemp;
4339 :
4340 0 : afnNode.HumRatT2 = afnNode.HumRatTX;
4341 0 : afnNode.HumRatTX = afnNode.HumRat;
4342 : }
4343 : }
4344 : }
4345 : }
4346 10832189 : }
4347 :
4348 0 : void RevertZoneTimestepHistories(EnergyPlusData &state)
4349 : {
4350 : // SUBROUTINE INFORMATION:
4351 : // AUTHOR Brent Griffith
4352 : // DATE WRITTEN February 2008
4353 :
4354 : // PURPOSE OF THIS SUBROUTINE:
4355 : // Revert the temperature and humidity ratio histories
4356 0 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
4357 0 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
4358 0 : s_ztpc->zoneHeatBalance(zoneNum).revertZoneTimestepHistory(state, zoneNum);
4359 0 : if (state.dataHeatBal->doSpaceHeatBalance) {
4360 0 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
4361 0 : s_ztpc->spaceHeatBalance(spaceNum).revertZoneTimestepHistory(state, zoneNum, spaceNum);
4362 0 : }
4363 : }
4364 : }
4365 0 : }
4366 :
4367 0 : void ZoneSpaceHeatBalanceData::revertZoneTimestepHistory(EnergyPlusData &state, int const zoneNum, int const spaceNum)
4368 : {
4369 0 : assert(zoneNum > 0);
4370 :
4371 0 : for (int iHistory = 0; iHistory <= 2; ++iHistory) {
4372 0 : this->XMAT[iHistory] = this->XMAT[iHistory + 1];
4373 0 : this->WPrevZoneTS[iHistory] = this->WPrevZoneTS[iHistory + 1];
4374 : }
4375 :
4376 : // SpaceHB TODO: For now, room air model is only for zones
4377 0 : if (spaceNum == 0) {
4378 0 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::DispVent3Node ||
4379 0 : state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::UFADInt ||
4380 0 : state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::UFADExt) {
4381 :
4382 0 : state.dataRoomAir->XMATFloor(zoneNum)[0] = state.dataRoomAir->XMATFloor(zoneNum)[1];
4383 0 : state.dataRoomAir->XMATFloor(zoneNum)[1] = state.dataRoomAir->XMATFloor(zoneNum)[2];
4384 0 : state.dataRoomAir->XMATFloor(zoneNum)[2] = state.dataRoomAir->XMATFloor(zoneNum)[3];
4385 :
4386 0 : state.dataRoomAir->XMATOC(zoneNum)[0] = state.dataRoomAir->XMATOC(zoneNum)[1];
4387 0 : state.dataRoomAir->XMATOC(zoneNum)[1] = state.dataRoomAir->XMATOC(zoneNum)[2];
4388 0 : state.dataRoomAir->XMATOC(zoneNum)[2] = state.dataRoomAir->XMATOC(zoneNum)[3];
4389 :
4390 0 : state.dataRoomAir->XMATMX(zoneNum)[0] = state.dataRoomAir->XMATMX(zoneNum)[1];
4391 0 : state.dataRoomAir->XMATMX(zoneNum)[1] = state.dataRoomAir->XMATMX(zoneNum)[2];
4392 0 : state.dataRoomAir->XMATMX(zoneNum)[3] = state.dataRoomAir->XMATMX(zoneNum)[3];
4393 : }
4394 :
4395 0 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
4396 0 : for (auto &afnNode : state.dataRoomAir->AFNZoneInfo(zoneNum).Node) {
4397 0 : afnNode.AirTempX[0] = afnNode.AirTempX[1];
4398 0 : afnNode.AirTempX[1] = afnNode.AirTempX[2];
4399 0 : afnNode.AirTempX[2] = afnNode.AirTempX[3];
4400 :
4401 0 : afnNode.HumRatX[0] = afnNode.HumRatX[1];
4402 0 : afnNode.HumRatX[1] = afnNode.HumRatX[2];
4403 0 : afnNode.HumRatX[2] = afnNode.HumRatX[3];
4404 : }
4405 : }
4406 : }
4407 0 : }
4408 :
4409 31373982 : void ZoneSpaceHeatBalanceData::correctHumRat(EnergyPlusData &state, int const zoneNum, int const spaceNum)
4410 : {
4411 :
4412 : // SUBROUTINE INFORMATION:
4413 : // AUTHOR Richard Liesen
4414 : // DATE WRITTEN 2000
4415 : // REFERENCES: Routine FinalZnCalcs - FINAL ZONE CALCULATIONS, authored by Dale Herron for BLAST.
4416 :
4417 31373982 : assert(zoneNum > 0);
4418 : static constexpr std::string_view RoutineName("correctHumRat");
4419 :
4420 31373982 : Real64 MoistureMassFlowRate = 0.0;
4421 31373982 : Real64 ZoneMassFlowRate = 0.0;
4422 31373982 : auto &zone = state.dataHeatBal->Zone(zoneNum);
4423 31373982 : int ZoneMult = zone.Multiplier * zone.ListMultiplier;
4424 31373982 : bool ControlledZoneAirFlag = zone.IsControlled;
4425 31373982 : bool ZoneRetPlenumAirFlag = zone.IsReturnPlenum;
4426 31373982 : bool ZoneSupPlenumAirFlag = zone.IsSupplyPlenum;
4427 :
4428 31373982 : if (ControlledZoneAirFlag) { // If there is system flow then calculate the flow rates
4429 27124722 : auto &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(zoneNum);
4430 : // Calculate moisture flow rate into each zone
4431 56010835 : for (int NodeNum = 1; NodeNum <= zoneEquipConfig.NumInletNodes; ++NodeNum) {
4432 28886113 : auto const &inletNode = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(NodeNum));
4433 28886113 : MoistureMassFlowRate += (inletNode.MassFlowRate * inletNode.HumRat) / ZoneMult;
4434 28886113 : ZoneMassFlowRate += inletNode.MassFlowRate / ZoneMult;
4435 : }
4436 :
4437 : // Do the calculations for the plenum zone
4438 4249260 : } else if (ZoneRetPlenumAirFlag) {
4439 1089639 : int ZoneRetPlenumNum = zone.PlenumCondNum;
4440 1089639 : auto &zoneRetPlenCond = state.dataZonePlenum->ZoneRetPlenCond(ZoneRetPlenumNum);
4441 6283299 : for (int NodeNum = 1; NodeNum <= zoneRetPlenCond.NumInletNodes; ++NodeNum) {
4442 5193660 : auto const &inletNode = state.dataLoopNodes->Node(zoneRetPlenCond.InletNode(NodeNum));
4443 5193660 : MoistureMassFlowRate += (inletNode.MassFlowRate * inletNode.HumRat) / ZoneMult;
4444 5193660 : ZoneMassFlowRate += inletNode.MassFlowRate / ZoneMult;
4445 : }
4446 : // add in the leak flow
4447 6301939 : for (int ADUListIndex = 1; ADUListIndex <= zoneRetPlenCond.NumADUs; ++ADUListIndex) {
4448 5212300 : int ADUNum = zoneRetPlenCond.ADUIndex(ADUListIndex);
4449 5212300 : auto const &airDistUnit = state.dataDefineEquipment->AirDistUnit(ADUNum);
4450 5212300 : if (airDistUnit.UpStreamLeak) {
4451 106595 : int ADUInNode = airDistUnit.InletNodeNum;
4452 106595 : MoistureMassFlowRate += (airDistUnit.MassFlowRateUpStrLk * state.dataLoopNodes->Node(ADUInNode).HumRat) / ZoneMult;
4453 106595 : ZoneMassFlowRate += airDistUnit.MassFlowRateUpStrLk / ZoneMult;
4454 : }
4455 5212300 : if (airDistUnit.DownStreamLeak) {
4456 106595 : int ADUOutNode = airDistUnit.OutletNodeNum;
4457 106595 : MoistureMassFlowRate += (airDistUnit.MassFlowRateDnStrLk * state.dataLoopNodes->Node(ADUOutNode).HumRat) / ZoneMult;
4458 106595 : ZoneMassFlowRate += airDistUnit.MassFlowRateDnStrLk / ZoneMult;
4459 : }
4460 : }
4461 :
4462 3159621 : } else if (ZoneSupPlenumAirFlag) {
4463 19526 : int ZoneSupPlenumNum = zone.PlenumCondNum;
4464 19526 : auto const &inletNode = state.dataLoopNodes->Node(state.dataZonePlenum->ZoneSupPlenCond(ZoneSupPlenumNum).InletNode);
4465 19526 : MoistureMassFlowRate += (inletNode.MassFlowRate * inletNode.HumRat) / ZoneMult;
4466 19526 : ZoneMassFlowRate += inletNode.MassFlowRate / ZoneMult;
4467 : }
4468 :
4469 : // Calculate hourly humidity ratio from infiltration + humidity added from latent load + system added moisture
4470 31373982 : Real64 LatentGain = this->latentGain + state.dataHeatBalFanSys->SumLatentHTRadSys(zoneNum) + state.dataHeatBalFanSys->SumLatentPool(zoneNum);
4471 :
4472 31373982 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
4473 :
4474 : // Calculate the coefficients for the 3rd order derivative for final
4475 : // zone humidity ratio. The A, B, C coefficients are analogous to the
4476 : // heat balance. There are 2 cases that should be considered, system
4477 : // operating and system shutdown.
4478 :
4479 31373982 : Real64 const RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->ZT, this->airHumRat, RoutineName);
4480 31373982 : Real64 const H2OHtOfVap = Psychrometrics::PsyHgAirFnWTdb(this->airHumRat, this->ZT);
4481 :
4482 31373982 : Real64 B = (LatentGain / H2OHtOfVap) + ((this->OAMFL + this->VAMFL + this->CTMFL) * state.dataEnvrn->OutHumRat) + this->EAMFLxHumRat +
4483 31373982 : (MoistureMassFlowRate) + this->SumHmARaW + this->MixingMassFlowXHumRat + this->MDotOA * state.dataEnvrn->OutHumRat;
4484 31373982 : Real64 A = ZoneMassFlowRate + this->OAMFL + this->VAMFL + this->EAMFL + this->CTMFL + this->SumHmARa + this->MixingMassFlowZone + this->MDotOA;
4485 :
4486 62254337 : if (state.afn->multizone_always_simulated ||
4487 30880355 : (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
4488 23258 : state.afn->AirflowNetworkFanActivated)) {
4489 511861 : auto const &exchangeData = state.afn->exchangeData(zoneNum);
4490 : // Multizone airflow calculated in AirflowNetwork
4491 511861 : B = (LatentGain / H2OHtOfVap) + (exchangeData.SumMHrW + exchangeData.SumMMHrW) + (MoistureMassFlowRate) + this->SumHmARaW;
4492 511861 : A = ZoneMassFlowRate + exchangeData.SumMHr + exchangeData.SumMMHr + this->SumHmARa;
4493 : }
4494 31373982 : Real64 C = RhoAir * zone.Volume * zone.ZoneVolCapMultpMoist / TimeStepSysSec;
4495 :
4496 31373982 : if (state.afn->distribution_simulated) {
4497 380500 : B += state.afn->exchangeData(zoneNum).TotalLat;
4498 : }
4499 :
4500 : // Use a 3rd order derivative to predict final zone humidity ratio and
4501 : // smooth the changes using the zone air capacitance.
4502 : // auto &zoneAirHumRatTemp = this->ZoneAirHumRatTemp;
4503 : // auto &zoneW1 = s_ztpc->zoneHeatBalance(ZoneNum).ZoneW1;
4504 31373982 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
4505 17032647 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
4506 17032647 : this->airHumRatTemp =
4507 17032647 : (B + C * (3.0 * this->WPrevZoneTSTemp[0] - (3.0 / 2.0) * this->WPrevZoneTSTemp[1] + (1.0 / 3.0) * this->WPrevZoneTSTemp[2])) /
4508 17032647 : ((11.0 / 6.0) * C + A);
4509 : // Exact solution
4510 17032647 : } break;
4511 14303125 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
4512 14303125 : if (A == 0.0) { // B=0
4513 532784 : this->airHumRatTemp = this->W1 + B / C;
4514 : } else {
4515 13770341 : this->airHumRatTemp = (this->W1 - B / A) * std::exp(min(700.0, -A / C)) + B / A;
4516 : }
4517 14303125 : } break;
4518 38210 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
4519 38210 : this->airHumRatTemp = (C * this->W1 + B) / (C + A);
4520 38210 : } break;
4521 0 : default:
4522 0 : break;
4523 : }
4524 :
4525 : // Set the humidity ratio to zero if the zone has been dried out
4526 31373982 : if (this->airHumRatTemp < 0.0) {
4527 577 : this->airHumRatTemp = 0.0;
4528 : }
4529 :
4530 : // Check to make sure that is saturated there is condensation in the zone
4531 : // by resetting to saturation conditions.
4532 31373982 : Real64 const WZSat = Psychrometrics::PsyWFnTdbRhPb(state, this->ZT, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
4533 :
4534 31373982 : if (this->airHumRatTemp > WZSat) {
4535 839709 : this->airHumRatTemp = WZSat;
4536 : }
4537 :
4538 31373982 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
4539 7413 : this->airHumRatTemp = state.dataRoomAir->AFNZoneInfo(zoneNum).Node(state.dataRoomAir->AFNZoneInfo(zoneNum).ControlAirNodeID).HumRat;
4540 : }
4541 :
4542 : // HybridModel with measured humidity ratio begins
4543 : // SpaceHB TODO: For now, hybrid model is only for zones
4544 31373982 : if (spaceNum == 0 && state.dataHybridModel->FlagHybridModel) {
4545 30204 : auto &hmZone = state.dataHybridModel->hybridModelZones(zoneNum);
4546 30204 : if ((hmZone.InfiltrationCalc_H || hmZone.PeopleCountCalc_H) && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing)) {
4547 600 : Real64 LatentGainExceptPeople = 0.0;
4548 600 : if (hmZone.PeopleCountCalc_H) {
4549 298 : LatentGainExceptPeople = this->latentGainExceptPeople + state.dataHeatBalFanSys->SumLatentHTRadSys(zoneNum) +
4550 298 : state.dataHeatBalFanSys->SumLatentPool(zoneNum);
4551 : }
4552 :
4553 600 : InverseModelHumidity(state, zoneNum, LatentGain, LatentGainExceptPeople, ZoneMassFlowRate, MoistureMassFlowRate, H2OHtOfVap, RhoAir);
4554 : }
4555 : }
4556 :
4557 : // Now put the calculated info into the actual zone nodes; ONLY if there is zone air flow, i.e. controlled zone or plenum zone
4558 31373982 : int ZoneNodeNum = zone.SystemZoneNodeNumber;
4559 31373982 : if (spaceNum > 0) {
4560 29170 : ZoneNodeNum = state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber;
4561 : }
4562 31373982 : if (ZoneNodeNum > 0) {
4563 28233887 : state.dataLoopNodes->Node(ZoneNodeNum).HumRat = this->airHumRatTemp;
4564 28233887 : state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy = Psychrometrics::PsyHFnTdbW(this->ZT, this->airHumRatTemp);
4565 : }
4566 31373982 : if (state.dataHeatBal->DoLatentSizing) {
4567 38334 : Real64 sensibleLoad = 0.0;
4568 38334 : Real64 pSat = Psychrometrics::PsyPsatFnTemp(state, this->ZT, RoutineName);
4569 38334 : Real64 Tdp = Psychrometrics::PsyTdpFnWPb(state, this->airHumRatTemp, state.dataEnvrn->StdBaroPress);
4570 38334 : Real64 vaporPressureDiff = pSat - Psychrometrics::PsyPsatFnTemp(state, Tdp, RoutineName);
4571 38334 : if (spaceNum > 0) {
4572 0 : sensibleLoad = state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).airSysHeatRate +
4573 0 : state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).airSysCoolRate;
4574 0 : state.dataZoneEnergyDemand->spaceSysMoistureDemand(spaceNum).reportZoneAirSystemMoistureLoads(
4575 : state, LatentGain, sensibleLoad, vaporPressureDiff);
4576 : } else {
4577 38334 : sensibleLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).airSysHeatRate +
4578 38334 : state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).airSysCoolRate;
4579 38334 : state.dataZoneEnergyDemand->ZoneSysMoistureDemand(zoneNum).reportZoneAirSystemMoistureLoads(
4580 : state, LatentGain, sensibleLoad, vaporPressureDiff);
4581 : }
4582 : }
4583 31373982 : }
4584 :
4585 60400 : void DownInterpolate4HistoryValues(Real64 const OldTimeStep,
4586 : Real64 const NewTimeStep,
4587 : Real64 const oldVal0,
4588 : Real64 const oldVal1,
4589 : Real64 const oldVal2,
4590 : Real64 &newVal0,
4591 : Real64 &newVal1,
4592 : Real64 &newVal2,
4593 : Real64 &newVal3,
4594 : Real64 &newVal4)
4595 : {
4596 : // SUBROUTINE INFORMATION:
4597 : // AUTHOR Brent Griffith
4598 : // DATE WRITTEN Feb 2008
4599 :
4600 : // PURPOSE OF THIS SUBROUTINE:
4601 : // provide a reusable routine for the various places that need to
4602 : // interpolate a new set of history values on a different time scale
4603 : // Once the systemtimestep has shortened, the new history terms need to be interpolated
4604 :
4605 : // METHODOLOGY EMPLOYED:
4606 : // This routine assumes that the direction is to a shorter timestep.
4607 : // The down step ratio, DSRatio = OldTimeStep/ NewTimeStep
4608 : // is expected to be roughly integer-valued and near 2.0 or 3.0 or 4.0 or more.
4609 :
4610 : // old math variables
4611 : // Real64 const oldTime0 = 0.0;
4612 : // Real64 const oldTime1 = oldTime0 - OldTimeStep;
4613 : // Real64 const newTime0 = 0.0;
4614 : // Real64 const newTime1 = newTime0 - NewTimeStep;
4615 : // Real64 const newTime2 = newTime1 - NewTimeStep;
4616 : // Real64 const newTime3 = newTime2 - NewTimeStep;
4617 : // Real64 const newTime4 = newTime3 - NewTimeStep;
4618 :
4619 60400 : Real64 constexpr realTWO = 2.0;
4620 60400 : Real64 constexpr realTHREE = 3.0;
4621 : // first determine the ratio of system time step to zone time step
4622 60400 : Real64 const DSRatio = OldTimeStep / NewTimeStep; // should pretty much be an integer value 2, 3, 4, etc.
4623 :
4624 60400 : newVal0 = oldVal0;
4625 :
4626 60400 : if (std::abs(DSRatio - realTWO) < 0.01) { // DSRatio = 2
4627 : // when DSRatio = 2 the 1st point lies exactly between old points, and 2nd point is old 1st point
4628 : // first two points lie between oldVal0 and oldVal1
4629 : // old math example
4630 : // newVal1 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime1) / (OldTimeStep));
4631 : // newVal2 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime2) / (OldTimeStep));
4632 11800 : newVal1 = (oldVal0 + oldVal1) / realTWO;
4633 11800 : newVal2 = oldVal1;
4634 : // when DSRatio = 2 the 3rd point lies exactly between old points, and 4th point is old 2nd point
4635 : // last two points lie between oldVal1 and oldVal2
4636 : // newVal3 = oldVal1 + (oldVal2 - oldVal1) * ((oldTime1 - newTime3) / (OldTimeStep));
4637 : // newVal4 = oldVal1 + (oldVal2 - oldVal1) * ((oldTime1 - newTime4) / (OldTimeStep));
4638 11800 : newVal3 = (oldVal1 + oldVal2) / realTWO;
4639 11800 : newVal4 = oldVal2;
4640 48600 : } else if (std::abs(DSRatio - realTHREE) < 0.01) { // DSRatio = 3
4641 : // when DSRatio = 3 the 1st point lies 1/3 way between old points, and 2nd and 3rd points are 2/3 and 3/3 the way
4642 : // first three points lie between oldVal0 and oldVal1
4643 : // newVal1 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime1) / (OldTimeStep));
4644 : // newVal2 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime2) / (OldTimeStep));
4645 : // newVal3 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime3) / (OldTimeStep));
4646 7751 : Real64 delta10 = (oldVal1 - oldVal0) / realTHREE;
4647 7751 : newVal1 = oldVal0 + delta10;
4648 7751 : newVal2 = newVal1 + delta10;
4649 7751 : newVal3 = oldVal1;
4650 : // last point lies 1/3 way between oldVal1 and oldVal2
4651 : // newVal4 = oldVal1 + (oldVal2 - oldVal1) * ((oldTime1 - newTime4) / (OldTimeStep));
4652 7751 : newVal4 = oldVal1 + (oldVal2 - oldVal1) / realTHREE;
4653 :
4654 : } else { // DSRatio = 4 or more
4655 : // all new points lie between oldVal0 and oldVal1 (if DSRatio = 4, newVal4 = oldVal1)
4656 : // newVal1 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime1) / (OldTimeStep));
4657 : // newVal2 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime2) / (OldTimeStep));
4658 : // newVal3 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime3) / (OldTimeStep));
4659 : // newVal4 = oldVal0 + (oldVal1 - oldVal0) * ((oldTime0 - newTime4) / (OldTimeStep));
4660 40849 : Real64 delta10 = (oldVal1 - oldVal0) / DSRatio;
4661 40849 : newVal1 = oldVal0 + delta10;
4662 40849 : newVal2 = newVal1 + delta10;
4663 40849 : newVal3 = newVal2 + delta10;
4664 40849 : newVal4 = newVal3 + delta10;
4665 : }
4666 60400 : }
4667 :
4668 2880660 : Real64 DownInterpolate4HistoryValues(Real64 OldTimeStep, Real64 NewTimeStep, std::array<Real64, 4> const &oldVals, std::array<Real64, 4> &newVals)
4669 : {
4670 2880660 : Real64 constexpr realTWO = 2.0;
4671 2880660 : Real64 constexpr realTHREE = 3.0;
4672 : // first determine the ratio of system time step to zone time step
4673 2880660 : Real64 const DSRatio = OldTimeStep / NewTimeStep; // should pretty much be an integer value 2, 3, 4, etc.
4674 :
4675 2880660 : newVals[0] = oldVals[0];
4676 :
4677 2880660 : if (std::abs(DSRatio - realTWO) < 0.01) { // DSRatio = 2
4678 : // first point lies exactly between (oldVals[0] and oldVals[1])
4679 964012 : newVals[1] = (oldVals[0] + oldVals[1]) / realTWO;
4680 : // 2nd point is oldVal[1] and last point lies exactly between (oldVals[1] and oldVals[2])
4681 964012 : newVals[2] = oldVals[1];
4682 964012 : newVals[3] = (oldVals[1] + oldVals[2]) / realTWO;
4683 :
4684 1916648 : } else if (std::abs(DSRatio - realTHREE) < 0.01) { // DSRatio = 3
4685 : // first two points lie between (oldVals[0] and oldVals[1])
4686 488137 : Real64 delta10 = (oldVals[1] - oldVals[0]) / realTHREE;
4687 488137 : newVals[1] = oldVals[0] + delta10;
4688 488137 : newVals[2] = newVals[1] + delta10;
4689 : // last point is oldVals[1]
4690 488137 : newVals[3] = oldVals[1];
4691 :
4692 : } else { // DSRatio = 4 or more
4693 : // all new points lie between (oldVals[0] and oldVals[1])
4694 1428511 : Real64 delta10 = (oldVals[1] - oldVals[0]) / DSRatio;
4695 1428511 : newVals[1] = oldVals[0] + delta10;
4696 1428511 : newVals[2] = newVals[1] + delta10;
4697 1428511 : newVals[3] = newVals[2] + delta10;
4698 : }
4699 2880660 : return oldVals[0];
4700 : }
4701 1800 : void InverseModelTemperature(EnergyPlusData &state,
4702 : int const ZoneNum, // Zone number
4703 : Real64 const SumIntGain, // Zone sum of convective internal gains
4704 : Real64 const SumIntGainExceptPeople, // Zone sum of convective internal gains except for people
4705 : Real64 const SumHA, // Zone sum of Hc*Area
4706 : Real64 const SumHATsurf, // Zone sum of Hc*Area*Tsurf
4707 : Real64 const SumHATref, // Zone sum of Hc*Area*Tref, for ceiling diffuser convection correlation
4708 : Real64 const SumMCp, // Zone sum of MassFlowRate*Cp
4709 : Real64 const SumMCpT, // Zone sum of MassFlowRate*Cp*T
4710 : Real64 const SumSysMCp, // Zone sum of air system MassFlowRate*Cp
4711 : Real64 const SumSysMCpT, // Zone sum of air system MassFlowRate*Cp*T
4712 : Real64 const AirCap // Formerly CoefAirrat, coef in zone temp eqn with dim of "air power capacity"rd
4713 : )
4714 : {
4715 : // SUBROUTINE INFORMATION:
4716 : // AUTHOR Han Li
4717 : // DATE WRITTEN February 2019
4718 :
4719 : // PURPOSE OF THIS SUBROUTINE:
4720 : // This subroutine inversely solve infiltration airflow rate or people count with zone air temperatures measurements.
4721 :
4722 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4723 1800 : Real64 AirCapHM(0.0); // Air power capacity for hybrid modeling
4724 1800 : Real64 AA(0.0);
4725 1800 : Real64 BB(0.0);
4726 1800 : Real64 FractionConvection(0.0); // Default convection portion of the sensible heat from people
4727 :
4728 1800 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
4729 1800 : auto &zone = state.dataHeatBal->Zone(ZoneNum);
4730 1800 : auto &hmZone = state.dataHybridModel->hybridModelZones(ZoneNum);
4731 1800 : auto &thisZoneHB = s_ztpc->zoneHeatBalance(ZoneNum);
4732 :
4733 1800 : int ZoneMult = zone.Multiplier * zone.ListMultiplier;
4734 1800 : zone.ZoneMeasuredTemperature = (hmZone.measuredTempSched != nullptr) ? hmZone.measuredTempSched->getCurrentVal() : 0.0;
4735 1800 : zone.ZoneVolCapMultpSensHM = 1.0; // Initialize to 1.0 in case hybrid not active
4736 :
4737 : // HM calculation only HM calculation period start
4738 1800 : if (state.dataEnvrn->DayOfYear >= hmZone.HybridStartDayOfYear && state.dataEnvrn->DayOfYear <= hmZone.HybridEndDayOfYear) {
4739 1800 : Real64 MultpHM(1.0);
4740 :
4741 1800 : thisZoneHB.ZT = zone.ZoneMeasuredTemperature; // Array1D<Real64> ZT -- Zone
4742 : // Air Temperature Averaged over
4743 : // the System Time Increment
4744 1800 : if (hmZone.InfiltrationCalc_T && state.dataHVACGlobal->UseZoneTimeStepHistory) {
4745 : static constexpr std::string_view RoutineNameInfiltration("CalcAirFlowSimple:Infiltration");
4746 :
4747 576 : if (hmZone.IncludeSystemSupplyParameters) {
4748 0 : zone.ZoneMeasuredSupplyAirTemperature = hmZone.supplyAirTempSched->getCurrentVal();
4749 0 : zone.ZoneMeasuredSupplyAirFlowRate = hmZone.supplyAirMassFlowRateSched ? hmZone.supplyAirMassFlowRateSched->getCurrentVal() : 0.0;
4750 0 : zone.ZoneMeasuredSupplyAirHumidityRatio = hmZone.supplyAirHumRatSched ? hmZone.supplyAirHumRatSched->getCurrentVal() : 0.0;
4751 : // Calculate the air humidity ratio at supply air inlet.
4752 0 : Real64 CpAirInlet(0.0);
4753 0 : CpAirInlet = Psychrometrics::PsyCpAirFnW(zone.ZoneMeasuredSupplyAirHumidityRatio);
4754 :
4755 0 : Real64 SumSysMCp_HM = zone.ZoneMeasuredSupplyAirFlowRate * CpAirInlet;
4756 0 : Real64 SumSysMCpT_HM = zone.ZoneMeasuredSupplyAirFlowRate * CpAirInlet * zone.ZoneMeasuredSupplyAirTemperature;
4757 :
4758 0 : AA = SumSysMCp_HM + SumHA + thisZoneHB.MCPV + thisZoneHB.MCPM + thisZoneHB.MCPE + thisZoneHB.MCPC + thisZoneHB.MDotCPOA;
4759 0 : BB = SumSysMCpT_HM + SumIntGain + SumHATsurf - SumHATref + thisZoneHB.MCPTV + thisZoneHB.MCPTM + thisZoneHB.MCPTE + thisZoneHB.MCPTC +
4760 0 : thisZoneHB.MDotCPOA * zone.OutDryBulbTemp + (thisZoneHB.NonAirSystemResponse / ZoneMult + thisZoneHB.SysDepZoneLoadsLagged);
4761 : } else {
4762 576 : AA = SumHA + thisZoneHB.MCPV + thisZoneHB.MCPM + thisZoneHB.MCPE + thisZoneHB.MCPC + thisZoneHB.MDotCPOA;
4763 576 : BB = SumIntGain + SumHATsurf - SumHATref + thisZoneHB.MCPTV + thisZoneHB.MCPTM + thisZoneHB.MCPTE + thisZoneHB.MCPTC +
4764 576 : thisZoneHB.MDotCPOA * zone.OutDryBulbTemp;
4765 : }
4766 576 : Real64 CC = AirCap;
4767 : Real64 DD =
4768 576 : (3.0 * state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum) - (3.0 / 2.0) * state.dataHeatBalFanSys->PreviousMeasuredZT2(ZoneNum) +
4769 576 : (1.0 / 3.0) * state.dataHeatBalFanSys->PreviousMeasuredZT3(ZoneNum));
4770 :
4771 576 : Real64 delta_T = (zone.ZoneMeasuredTemperature - zone.OutDryBulbTemp);
4772 576 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(state.dataEnvrn->OutHumRat);
4773 576 : Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(
4774 576 : state, state.dataEnvrn->OutBaroPress, zone.OutDryBulbTemp, state.dataEnvrn->OutHumRat, RoutineNameInfiltration);
4775 576 : zone.delta_T = delta_T;
4776 :
4777 : // s4 - Set ACH to 0 when delta_T <= 0.5, add max and min limits to ach
4778 576 : Real64 M_inf = 0.0;
4779 576 : if (std::abs(delta_T) > 0.5) {
4780 558 : M_inf = (BB + CC * DD - ((11.0 / 6.0) * CC + AA) * zone.ZoneMeasuredTemperature) / (CpAir * delta_T);
4781 : }
4782 576 : Real64 ACH_inf = max(0.0, min(10.0, (M_inf / AirDensity) / zone.Volume * Constant::rSecsInHour));
4783 576 : M_inf = (ACH_inf / Constant::rSecsInHour) * zone.Volume * AirDensity;
4784 :
4785 : // Overwrite variable with inverse solution
4786 576 : zone.MCPIHM = M_inf;
4787 576 : zone.InfilOAAirChangeRateHM = ACH_inf;
4788 :
4789 : } // Hybrid model infiltration calculation end
4790 :
4791 : // Hybrid modeling internal thermal mass calculation start
4792 2664 : if (hmZone.InternalThermalMassCalc_T && SumSysMCpT == 0 && thisZoneHB.ZT != state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum) &&
4793 864 : state.dataHVACGlobal->UseZoneTimeStepHistory) { // HM calculation only when SumSysMCpT =0,
4794 : // TimeStepZone (not @ TimeStepSys)
4795 864 : Real64 TempDepCoef = SumHA + SumMCp + SumSysMCp;
4796 864 : Real64 TempIndCoef = SumIntGain + SumHATsurf - SumHATref + SumMCpT + SumSysMCpT +
4797 864 : (thisZoneHB.NonAirSystemResponse / ZoneMult + thisZoneHB.SysDepZoneLoadsLagged);
4798 : // TempHistoryTerm = AirCap * (3.0 * ZTM1(ZoneNum) - (3.0/2.0) * ZTM2(ZoneNum) + (1.0/3.0) * ZTM3(ZoneNum)) !debug only
4799 :
4800 864 : if (state.afn->distribution_simulated) {
4801 0 : TempIndCoef += state.afn->exchangeData(ZoneNum).TotalSen;
4802 : }
4803 : // Calculate air capacity using DataHeatBalance::SolutionAlgo::AnalyticalSolution
4804 864 : if (TempDepCoef == 0.0) {
4805 : // Is this correct? Shouldn't we use log?? What if thisZT ==
4806 : // PreviousMeasuredZT1(ZoneNum)??
4807 0 : AirCapHM = TempIndCoef / (thisZoneHB.ZT - state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum)); // Inverse equation
4808 : } else {
4809 864 : Real64 AirCapHM_temp = 0.0;
4810 864 : if (TempIndCoef == TempDepCoef * thisZoneHB.ZT) {
4811 0 : AirCapHM_temp = 0.0; // This is the denominator.
4812 : } else {
4813 864 : AirCapHM_temp = (TempIndCoef - TempDepCoef * state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum)) /
4814 864 : (TempIndCoef - TempDepCoef * thisZoneHB.ZT);
4815 : }
4816 :
4817 864 : if ((AirCapHM_temp > 0) && (AirCapHM_temp != 1)) { // Avoid IND
4818 857 : AirCapHM = TempDepCoef / std::log(AirCapHM_temp); // Inverse equation
4819 : } else {
4820 7 : AirCapHM = TempIndCoef / (thisZoneHB.ZT - state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum));
4821 : }
4822 : }
4823 :
4824 : // Calculate multiplier
4825 864 : if (std::abs(thisZoneHB.ZT - state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum)) > 0.05) { // Filter
4826 288 : MultpHM = AirCapHM /
4827 288 : (zone.Volume *
4828 288 : Psychrometrics::PsyRhoAirFnPbTdbW(state,
4829 144 : state.dataEnvrn->OutBaroPress,
4830 : thisZoneHB.ZT,
4831 144 : thisZoneHB.airHumRat) *
4832 144 : Psychrometrics::PsyCpAirFnW(thisZoneHB.airHumRat)) *
4833 144 : (state.dataGlobal->TimeStepZone * Constant::rSecsInHour); // Inverse equation
4834 : } else {
4835 720 : MultpHM = 1.0; // Default value 1.0
4836 : }
4837 :
4838 864 : processInverseModelMultpHM(
4839 864 : state, MultpHM, zone.ZoneVolCapMultpSensHMSum, zone.ZoneVolCapMultpSensHMCountSum, zone.ZoneVolCapMultpSensHMAverage, ZoneNum);
4840 864 : zone.ZoneVolCapMultpSensHM = MultpHM;
4841 :
4842 : } // Hybrid model internal thermal mass calculation end
4843 :
4844 : // Hybrid model people count calculation
4845 1800 : if (hmZone.PeopleCountCalc_T && state.dataHVACGlobal->UseZoneTimeStepHistory) {
4846 288 : zone.ZoneMeasuredTemperature = hmZone.measuredTempSched->getCurrentVal();
4847 288 : zone.ZonePeopleActivityLevel = hmZone.peopleActivityLevelSched ? hmZone.peopleActivityLevelSched->getCurrentVal() : 0.0;
4848 288 : zone.ZonePeopleSensibleHeatFraction = hmZone.peopleSensibleFracSched ? hmZone.peopleSensibleFracSched->getCurrentVal() : 0.0;
4849 288 : zone.ZonePeopleRadiantHeatFraction = hmZone.peopleRadiantFracSched ? hmZone.peopleRadiantFracSched->getCurrentVal() : 0.0;
4850 :
4851 288 : Real64 FractionSensible = zone.ZonePeopleSensibleHeatFraction;
4852 288 : Real64 FractionRadiation = zone.ZonePeopleRadiantHeatFraction;
4853 288 : Real64 ActivityLevel = hmZone.peopleActivityLevelSched ? hmZone.peopleActivityLevelSched->getCurrentVal() : 0.0;
4854 :
4855 288 : if (FractionSensible <= 0.0) {
4856 0 : FractionSensible = 0.6;
4857 : }
4858 :
4859 288 : if (FractionRadiation <= 0.0) {
4860 0 : FractionConvection = 0.7;
4861 : } else {
4862 288 : FractionConvection = 1.0 - FractionRadiation;
4863 : }
4864 :
4865 288 : if (ActivityLevel <= 0.0) {
4866 0 : ActivityLevel = 130.0;
4867 : }
4868 :
4869 288 : if (hmZone.IncludeSystemSupplyParameters) {
4870 0 : zone.ZoneMeasuredSupplyAirTemperature = hmZone.supplyAirTempSched->getCurrentVal();
4871 0 : zone.ZoneMeasuredSupplyAirFlowRate = hmZone.supplyAirMassFlowRateSched ? hmZone.supplyAirMassFlowRateSched->getCurrentVal() : 0.0;
4872 0 : zone.ZoneMeasuredSupplyAirHumidityRatio = hmZone.supplyAirHumRatSched ? hmZone.supplyAirHumRatSched->getCurrentVal() : 0.0;
4873 :
4874 : // Calculate the air humidity ratio at supply air inlet.
4875 0 : Real64 CpAirInlet = Psychrometrics::PsyCpAirFnW(zone.ZoneMeasuredSupplyAirHumidityRatio);
4876 :
4877 0 : Real64 SumSysMCp_HM = zone.ZoneMeasuredSupplyAirFlowRate * CpAirInlet;
4878 0 : Real64 SumSysMCpT_HM = zone.ZoneMeasuredSupplyAirFlowRate * CpAirInlet * zone.ZoneMeasuredSupplyAirTemperature;
4879 :
4880 0 : AA = SumSysMCp_HM + SumHA + SumMCp;
4881 0 : BB = SumSysMCpT_HM + SumIntGainExceptPeople + SumHATsurf - SumHATref + SumMCpT +
4882 0 : (thisZoneHB.NonAirSystemResponse / ZoneMult + thisZoneHB.SysDepZoneLoadsLagged);
4883 : } else {
4884 288 : AA = SumHA + SumMCp;
4885 288 : BB = SumIntGainExceptPeople + SumHATsurf - SumHATref + SumMCpT;
4886 : }
4887 :
4888 288 : Real64 CC = AirCap;
4889 : Real64 DD =
4890 288 : (3.0 * state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum) - (3.0 / 2.0) * state.dataHeatBalFanSys->PreviousMeasuredZT2(ZoneNum) +
4891 288 : (1.0 / 3.0) * state.dataHeatBalFanSys->PreviousMeasuredZT3(ZoneNum));
4892 :
4893 288 : Real64 SumIntGainPeople = ((11.0 / 6.0) * CC + AA) * zone.ZoneMeasuredTemperature - BB - CC * DD;
4894 288 : Real64 UpperBound = max(0.0, SumIntGain / (ActivityLevel * FractionSensible * FractionConvection));
4895 288 : Real64 NumPeople = min(UpperBound, max(0.0, SumIntGainPeople / (ActivityLevel * FractionSensible * FractionConvection)));
4896 :
4897 288 : if (NumPeople < 0.05) {
4898 286 : NumPeople = 0;
4899 : }
4900 288 : zone.NumOccHM = NumPeople;
4901 : }
4902 : }
4903 :
4904 : // Update zone temperatures in the previous steps
4905 1800 : state.dataHeatBalFanSys->PreviousMeasuredZT3(ZoneNum) = state.dataHeatBalFanSys->PreviousMeasuredZT2(ZoneNum);
4906 1800 : state.dataHeatBalFanSys->PreviousMeasuredZT2(ZoneNum) = state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum);
4907 1800 : state.dataHeatBalFanSys->PreviousMeasuredZT1(ZoneNum) = thisZoneHB.ZT;
4908 1800 : }
4909 :
4910 864 : void processInverseModelMultpHM(EnergyPlusData &state,
4911 : Real64 &multiplierHM, // Hybrid model thermal mass multiplier
4912 : Real64 &multSumHM, // Sum of Hybrid model thermal mass multipliers
4913 : Real64 &countSumHM, // Count of number of points in sum
4914 : Real64 &multAvgHM, // Average of hybrid model mass multiplier
4915 : int zoneNum // Zone number for the hybrid model
4916 : )
4917 : {
4918 864 : Real64 constexpr minHMMultValue = 1.0;
4919 864 : Real64 constexpr maxHMMultValue = 30.0;
4920 :
4921 864 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
4922 864 : auto &zone = state.dataHeatBal->Zone(zoneNum);
4923 864 : auto &thisZoneHB = s_ztpc->zoneHeatBalance(zoneNum);
4924 :
4925 : // Apply limits and generate warnings as needed
4926 864 : if (multiplierHM < minHMMultValue) { // don't allow this to be less than minimum (potential for instability)
4927 70 : multiplierHM = minHMMultValue;
4928 794 : } else if (multiplierHM > maxHMMultValue) { // as per suggestions in Defect #10508, only warn if greater than the max
4929 4 : if (thisZoneHB.hmThermalMassMultErrIndex == 0) {
4930 2 : ShowWarningMessage(state, format("Hybrid model thermal mass multiplier higher than the limit for {}", zone.Name));
4931 4 : ShowContinueError(state, "This means that the ratio of the zone air heat capacity for the current time step to the");
4932 2 : ShowContinueError(state, format("zone air heat storage is higher than the maximum limit of {:.1R}.", maxHMMultValue));
4933 : }
4934 32 : ShowRecurringWarningErrorAtEnd(
4935 8 : state, "Hybrid model thermal mass multiplier limit exceeded in zone " + zone.Name, thisZoneHB.hmThermalMassMultErrIndex);
4936 : }
4937 :
4938 : // Update running totals (but only when there is a valid multiplier, i.e. multiplier is greater than min but not higher than the max)
4939 864 : if (multiplierHM > minHMMultValue) {
4940 74 : multSumHM += multiplierHM;
4941 74 : countSumHM++;
4942 : }
4943 :
4944 : // Calculate average (always so that it does get calculated)
4945 864 : if (countSumHM >= 1) {
4946 468 : multAvgHM = multSumHM / countSumHM;
4947 : }
4948 864 : }
4949 :
4950 600 : void InverseModelHumidity(EnergyPlusData &state,
4951 : int const ZoneNum, // Zone number
4952 : Real64 const LatentGain, // Zone sum of latent gain
4953 : Real64 const LatentGainExceptPeople, // Zone sum of latent gain except for people
4954 : Real64 const ZoneMassFlowRate, // Zone air mass flow rate
4955 : Real64 const MoistureMassFlowRate, // Zone moisture mass flow rate
4956 : Real64 const H2OHtOfVap, // Heat of vaporization of air
4957 : Real64 const RhoAir // Air density
4958 : )
4959 : {
4960 : // SUBROUTINE INFORMATION:
4961 : // AUTHOR Han Li
4962 : // DATE WRITTEN February 2019
4963 :
4964 : // PURPOSE OF THIS SUBROUTINE:
4965 : // This subroutine inversely solve infiltration airflow rate or people count with zone air humidity measurements.
4966 :
4967 : // SUBROUTINE PARAMETER DEFINITIONS:
4968 : static constexpr std::string_view RoutineName("InverseModelHumidity");
4969 :
4970 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4971 600 : Real64 AA(0.0);
4972 600 : Real64 BB(0.0);
4973 600 : Real64 ActivityLevel(0.0);
4974 600 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
4975 :
4976 600 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
4977 600 : auto &zone = state.dataHeatBal->Zone(ZoneNum);
4978 600 : auto &hmZone = state.dataHybridModel->hybridModelZones(ZoneNum);
4979 600 : auto &thisZoneHB = s_ztpc->zoneHeatBalance(ZoneNum);
4980 :
4981 : // Get measured zone humidity ratio
4982 600 : zone.ZoneMeasuredHumidityRatio = hmZone.measuredHumRatSched->getCurrentVal();
4983 :
4984 600 : if (state.dataEnvrn->DayOfYear >= hmZone.HybridStartDayOfYear && state.dataEnvrn->DayOfYear <= hmZone.HybridEndDayOfYear) {
4985 600 : thisZoneHB.airHumRat = zone.ZoneMeasuredHumidityRatio;
4986 :
4987 : // Hybrid Model calculate air infiltration rate
4988 600 : if (hmZone.InfiltrationCalc_H && state.dataHVACGlobal->UseZoneTimeStepHistory) {
4989 : // Conditionally calculate the time dependent and time independent terms
4990 288 : if (hmZone.IncludeSystemSupplyParameters) {
4991 0 : zone.ZoneMeasuredSupplyAirFlowRate = hmZone.supplyAirMassFlowRateSched->getCurrentVal();
4992 0 : zone.ZoneMeasuredSupplyAirHumidityRatio = hmZone.supplyAirHumRatSched->getCurrentVal();
4993 :
4994 0 : Real64 SumSysM_HM = zone.ZoneMeasuredSupplyAirFlowRate;
4995 0 : Real64 SumSysMHumRat_HM = zone.ZoneMeasuredSupplyAirFlowRate * zone.ZoneMeasuredSupplyAirHumidityRatio;
4996 :
4997 0 : AA = SumSysM_HM + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.SumHmARa + thisZoneHB.MixingMassFlowZone +
4998 0 : thisZoneHB.MDotOA;
4999 0 : BB = SumSysMHumRat_HM + (LatentGain / H2OHtOfVap) + ((thisZoneHB.VAMFL + thisZoneHB.CTMFL) * state.dataEnvrn->OutHumRat) +
5000 0 : thisZoneHB.EAMFLxHumRat + thisZoneHB.SumHmARaW + thisZoneHB.MixingMassFlowXHumRat +
5001 0 : thisZoneHB.MDotOA * state.dataEnvrn->OutHumRat;
5002 : } else {
5003 288 : AA = thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.SumHmARa + thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
5004 288 : BB = (LatentGain / H2OHtOfVap) + ((thisZoneHB.VAMFL + thisZoneHB.CTMFL) * state.dataEnvrn->OutHumRat) + thisZoneHB.EAMFLxHumRat +
5005 288 : thisZoneHB.SumHmARaW + thisZoneHB.MixingMassFlowXHumRat + thisZoneHB.MDotOA * state.dataEnvrn->OutHumRat;
5006 : }
5007 :
5008 288 : Real64 CC = RhoAir * zone.Volume * zone.ZoneVolCapMultpMoist / TimeStepSysSec;
5009 288 : Real64 DD = (3.0 * state.dataHeatBalFanSys->PreviousMeasuredHumRat1(ZoneNum) -
5010 288 : (3.0 / 2.0) * state.dataHeatBalFanSys->PreviousMeasuredHumRat2(ZoneNum) +
5011 288 : (1.0 / 3.0) * state.dataHeatBalFanSys->PreviousMeasuredHumRat3(ZoneNum));
5012 :
5013 288 : Real64 delta_HR = (zone.ZoneMeasuredHumidityRatio - state.dataEnvrn->OutHumRat);
5014 :
5015 : Real64 AirDensity =
5016 288 : Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, zone.OutDryBulbTemp, state.dataEnvrn->OutHumRat, RoutineName);
5017 :
5018 288 : Real64 M_inf = 0.0;
5019 288 : if (std::abs(zone.ZoneMeasuredHumidityRatio - state.dataEnvrn->OutHumRat) > 0.0000001) {
5020 288 : M_inf = (CC * DD + BB - ((11.0 / 6.0) * CC + AA) * zone.ZoneMeasuredHumidityRatio) / delta_HR;
5021 : }
5022 :
5023 : // Add threshold for air change rate
5024 288 : Real64 ACH_inf = max(0.0, min(10.0, (M_inf / AirDensity) / zone.Volume * Constant::rSecsInHour));
5025 288 : M_inf = (ACH_inf / Constant::rSecsInHour) * zone.Volume * AirDensity;
5026 288 : zone.MCPIHM = M_inf;
5027 288 : zone.InfilOAAirChangeRateHM = ACH_inf;
5028 : }
5029 :
5030 : // Hybrid Model calculate people count
5031 600 : if (hmZone.PeopleCountCalc_H && state.dataHVACGlobal->UseZoneTimeStepHistory) {
5032 288 : zone.ZonePeopleActivityLevel = hmZone.peopleActivityLevelSched ? hmZone.peopleActivityLevelSched->getCurrentVal() : 0.0;
5033 288 : zone.ZonePeopleSensibleHeatFraction = hmZone.peopleSensibleFracSched ? hmZone.peopleSensibleFracSched->getCurrentVal() : 0.0;
5034 288 : zone.ZonePeopleRadiantHeatFraction = hmZone.peopleRadiantFracSched ? hmZone.peopleRadiantFracSched->getCurrentVal() : 0.0;
5035 :
5036 288 : Real64 FractionSensible = zone.ZonePeopleSensibleHeatFraction;
5037 :
5038 288 : if (FractionSensible <= 0.0) {
5039 0 : FractionSensible = 0.6;
5040 : }
5041 :
5042 288 : if (ActivityLevel <= 0.0) {
5043 288 : ActivityLevel = 130.0;
5044 : }
5045 :
5046 : // Conditionally calculate the humidity-dependent and humidity-independent
5047 : // terms.
5048 288 : if (hmZone.IncludeSystemSupplyParameters) {
5049 288 : zone.ZoneMeasuredSupplyAirFlowRate = hmZone.supplyAirMassFlowRateSched->getCurrentVal();
5050 288 : zone.ZoneMeasuredSupplyAirHumidityRatio = hmZone.supplyAirHumRatSched->getCurrentVal();
5051 :
5052 288 : Real64 SumSysM_HM = zone.ZoneMeasuredSupplyAirFlowRate;
5053 288 : Real64 SumSysMHumRat_HM = zone.ZoneMeasuredSupplyAirFlowRate * zone.ZoneMeasuredSupplyAirHumidityRatio;
5054 :
5055 288 : AA = SumSysM_HM + thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.SumHmARa +
5056 288 : thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
5057 864 : BB = SumSysMHumRat_HM + (LatentGainExceptPeople / H2OHtOfVap) +
5058 288 : ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.CTMFL) * state.dataEnvrn->OutHumRat) + thisZoneHB.EAMFLxHumRat +
5059 288 : thisZoneHB.SumHmARaW + thisZoneHB.MixingMassFlowXHumRat + thisZoneHB.MDotOA * state.dataEnvrn->OutHumRat;
5060 : } else {
5061 0 : AA = ZoneMassFlowRate + thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.EAMFL + thisZoneHB.CTMFL + thisZoneHB.SumHmARa +
5062 0 : thisZoneHB.MixingMassFlowZone + thisZoneHB.MDotOA;
5063 0 : BB = (LatentGainExceptPeople / H2OHtOfVap) + ((thisZoneHB.OAMFL + thisZoneHB.VAMFL + thisZoneHB.CTMFL) * state.dataEnvrn->OutHumRat) +
5064 0 : thisZoneHB.EAMFLxHumRat + (MoistureMassFlowRate) + thisZoneHB.SumHmARaW + thisZoneHB.MixingMassFlowXHumRat +
5065 0 : thisZoneHB.MDotOA * state.dataEnvrn->OutHumRat;
5066 : }
5067 :
5068 288 : Real64 CC = RhoAir * zone.Volume * zone.ZoneVolCapMultpMoist / TimeStepSysSec;
5069 288 : Real64 DD = (3.0 * state.dataHeatBalFanSys->PreviousMeasuredHumRat1(ZoneNum) -
5070 288 : (3.0 / 2.0) * state.dataHeatBalFanSys->PreviousMeasuredHumRat2(ZoneNum) +
5071 288 : (1.0 / 3.0) * state.dataHeatBalFanSys->PreviousMeasuredHumRat3(ZoneNum));
5072 :
5073 288 : Real64 LatentGainPeople = (((11.0 / 6.0) * CC + AA) * zone.ZoneMeasuredHumidityRatio - BB - CC * DD) * H2OHtOfVap;
5074 288 : Real64 UpperBound = max(0.0, LatentGain / (ActivityLevel * (1.0 - FractionSensible)));
5075 288 : Real64 NumPeople = min(UpperBound, max(0.0, LatentGainPeople / (ActivityLevel * (1.0 - FractionSensible))));
5076 288 : NumPeople = floor(NumPeople * 100.00 + 0.5) / 100.00;
5077 288 : if (NumPeople < 0.05) {
5078 235 : NumPeople = 0;
5079 : }
5080 288 : zone.NumOccHM = NumPeople;
5081 : }
5082 : }
5083 :
5084 : // Update zone humidity ratio in the previous steps
5085 600 : state.dataHeatBalFanSys->PreviousMeasuredHumRat3(ZoneNum) = state.dataHeatBalFanSys->PreviousMeasuredHumRat2(ZoneNum);
5086 600 : state.dataHeatBalFanSys->PreviousMeasuredHumRat2(ZoneNum) = state.dataHeatBalFanSys->PreviousMeasuredHumRat1(ZoneNum);
5087 600 : state.dataHeatBalFanSys->PreviousMeasuredHumRat1(ZoneNum) = zone.ZoneMeasuredHumidityRatio;
5088 600 : }
5089 :
5090 62806616 : void ZoneSpaceHeatBalanceData::calcZoneOrSpaceSums(EnergyPlusData &state,
5091 : bool const CorrectorFlag, // Corrector call flag
5092 : int const zoneNum,
5093 : int const spaceNum)
5094 : {
5095 :
5096 : // SUBROUTINE INFORMATION:
5097 : // AUTHOR Peter Graham Ellis
5098 : // DATE WRITTEN July 2003
5099 : // MODIFIED Aug 2003, FCW: add this->SumHA contributions from window frame and divider
5100 : // Aug 2003, CC: change how the reference temperatures are used
5101 :
5102 : // PURPOSE OF THIS SUBROUTINE:
5103 : // This subroutine calculates the various sums that go into the zone heat balance
5104 : // equation. This replaces the SUMC, SumHA, and SumHAT calculations that were
5105 : // previously done in various places throughout the program.
5106 : // The SumHAT portion of the code is reproduced in RadiantSystemHighTemp and
5107 : // RadiantSystemLowTemp and should be updated accordingly.
5108 : // A reference temperature (Tref) is specified for use with the ceiling diffuser
5109 : // convection correlation. A bogus value of Tref = -999.9 defaults to using
5110 : // the zone air (i.e. outlet) temperature for the reference temperature.
5111 : // If Tref is applied to all surfaces, SumHA = 0, and SumHATref /= 0.
5112 : // If Tref is not used at all, SumHATref = 0, and SumHA /= 0.
5113 : // For future implementations, Tref can be easily converted into an array to
5114 : // allow a different reference temperature to be specified for each surface.
5115 62806616 : assert(zoneNum > 0);
5116 :
5117 62806616 : this->SumHA = 0.0;
5118 62806616 : this->SumHATsurf = 0.0;
5119 62806616 : this->SumHATref = 0.0;
5120 62806616 : this->SumSysMCp = 0.0;
5121 62806616 : this->SumSysMCpT = 0.0;
5122 : // Sum all convective internal gains: this->SumIntGain
5123 62806616 : if (spaceNum == 0) {
5124 62691052 : this->SumIntGain = InternalHeatGains::zoneSumAllInternalConvectionGains(state, zoneNum);
5125 : } else {
5126 115564 : this->SumIntGain = InternalHeatGains::spaceSumAllInternalConvectionGains(state, spaceNum);
5127 : }
5128 62806616 : this->SumIntGain += state.dataHeatBalFanSys->SumConvHTRadSys(zoneNum) + state.dataHeatBalFanSys->SumConvPool(zoneNum);
5129 :
5130 : // Add heat to return air if zonal system (no return air) or cycling system (return air frequently very low or zero)
5131 62806616 : assert(zoneNum > 0);
5132 62806616 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
5133 62806616 : if (thisZone.NoHeatToReturnAir) {
5134 7216260 : if (spaceNum == 0) {
5135 7216260 : this->SumIntGain += InternalHeatGains::zoneSumAllReturnAirConvectionGains(state, zoneNum, 0);
5136 : } else {
5137 0 : this->SumIntGain += InternalHeatGains::spaceSumAllReturnAirConvectionGains(state, spaceNum, 0);
5138 : }
5139 : }
5140 :
5141 : // Sum all non-system air flow, i.e. infiltration, simple ventilation, mixing, earth tube: this->SumMCp, this->SumMCpT
5142 62806616 : this->SumMCp = this->MCPI + this->MCPV + this->MCPM + this->MCPE + this->MCPC + this->MDotCPOA;
5143 62806616 : this->SumMCpT = this->MCPTI + this->MCPTV + this->MCPTM + this->MCPTE + this->MCPTC + this->MDotCPOA * thisZone.OutDryBulbTemp;
5144 :
5145 : // Sum all multizone air flow calculated from AirflowNetwork by assuming no simple air infiltration model
5146 124625978 : if (state.afn->multizone_always_simulated ||
5147 61819362 : (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
5148 46516 : state.afn->AirflowNetworkFanActivated)) {
5149 1023709 : auto const &exchangeData = state.afn->exchangeData(zoneNum);
5150 1023709 : this->SumMCp = exchangeData.SumMCp + exchangeData.SumMVCp + exchangeData.SumMMCp;
5151 1023709 : this->SumMCpT = exchangeData.SumMCpT + exchangeData.SumMVCpT + exchangeData.SumMMCpT;
5152 : }
5153 :
5154 : // Sum all system air flow: this->SumSysMCp, this->SumSysMCpT and check to see if this is a controlled zone
5155 : // If the space is controlled, use space supply nodes, otherwise use zone supply nodes and allocate later
5156 62806616 : bool isSpaceControlled = (spaceNum > 0 && state.dataZoneEquip->spaceEquipConfig(spaceNum).IsControlled);
5157 62806616 : if (CorrectorFlag) {
5158 : // Plenum and controlled zones have a different set of inlet nodes which must be calculated.
5159 31373982 : if (thisZone.IsControlled) {
5160 27124722 : auto const &zsec = (isSpaceControlled ? state.dataZoneEquip->spaceEquipConfig(spaceNum) : state.dataZoneEquip->ZoneEquipConfig(zoneNum));
5161 56010835 : for (int NodeNum = 1, NodeNum_end = zsec.NumInletNodes; NodeNum <= NodeNum_end; ++NodeNum) {
5162 : // Get node conditions, this next block is of interest to irratic system loads... maybe nodes are not accurate at time of call?
5163 : // how can we tell? predict step must be lagged ? correct step, systems have run.
5164 28886113 : auto const &node(state.dataLoopNodes->Node(zsec.InletNode(NodeNum)));
5165 28886113 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(this->airHumRat);
5166 28886113 : Real64 const MassFlowRate_CpAir(node.MassFlowRate * CpAir);
5167 28886113 : this->SumSysMCp += MassFlowRate_CpAir;
5168 28886113 : this->SumSysMCpT += MassFlowRate_CpAir * node.Temp;
5169 : }
5170 :
5171 4249260 : } else if (thisZone.IsReturnPlenum) {
5172 1089639 : auto const &zrpc(state.dataZonePlenum->ZoneRetPlenCond(thisZone.PlenumCondNum));
5173 1089639 : Real64 const air_hum_rat(this->airHumRat);
5174 6283299 : for (int NodeNum = 1, NodeNum_end = zrpc.NumInletNodes; NodeNum <= NodeNum_end; ++NodeNum) {
5175 5193660 : auto const &node(state.dataLoopNodes->Node(zrpc.InletNode(NodeNum)));
5176 5193660 : Real64 const MassFlowRate_CpAir(node.MassFlowRate * Psychrometrics::PsyCpAirFnW(air_hum_rat));
5177 5193660 : this->SumSysMCp += MassFlowRate_CpAir;
5178 5193660 : this->SumSysMCpT += MassFlowRate_CpAir * node.Temp;
5179 : }
5180 : // add in the leaks
5181 6301939 : for (int ADUListIndex = 1, ADUListIndex_end = zrpc.NumADUs; ADUListIndex <= ADUListIndex_end; ++ADUListIndex) {
5182 5212300 : auto &airDistUnit = state.dataDefineEquipment->AirDistUnit(zrpc.ADUIndex(ADUListIndex));
5183 5212300 : if (airDistUnit.UpStreamLeak) {
5184 106595 : Real64 const MassFlowRate_CpAir(airDistUnit.MassFlowRateUpStrLk * Psychrometrics::PsyCpAirFnW(air_hum_rat));
5185 106595 : this->SumSysMCp += MassFlowRate_CpAir;
5186 106595 : this->SumSysMCpT += MassFlowRate_CpAir * state.dataLoopNodes->Node(airDistUnit.InletNodeNum).Temp;
5187 : }
5188 5212300 : if (airDistUnit.DownStreamLeak) {
5189 106595 : Real64 const MassFlowRate_CpAir(airDistUnit.MassFlowRateDnStrLk * Psychrometrics::PsyCpAirFnW(air_hum_rat));
5190 106595 : this->SumSysMCp += MassFlowRate_CpAir;
5191 106595 : this->SumSysMCpT += MassFlowRate_CpAir * state.dataLoopNodes->Node(airDistUnit.OutletNodeNum).Temp;
5192 : }
5193 : }
5194 :
5195 3159621 : } else if (thisZone.IsSupplyPlenum) {
5196 19526 : Real64 MassFlowRate = state.dataLoopNodes->Node(state.dataZonePlenum->ZoneSupPlenCond(thisZone.PlenumCondNum).InletNode).MassFlowRate;
5197 19526 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(this->airHumRat);
5198 19526 : this->SumSysMCp += MassFlowRate * CpAir;
5199 19526 : this->SumSysMCpT +=
5200 19526 : MassFlowRate * CpAir * state.dataLoopNodes->Node(state.dataZonePlenum->ZoneSupPlenCond(thisZone.PlenumCondNum).InletNode).Temp;
5201 : }
5202 :
5203 31373982 : int ZoneMult = thisZone.Multiplier * thisZone.ListMultiplier;
5204 :
5205 31373982 : this->SumSysMCp /= ZoneMult;
5206 31373982 : this->SumSysMCpT /= ZoneMult;
5207 : }
5208 :
5209 62806616 : if (spaceNum > 0 && !isSpaceControlled) {
5210 : // If space is not controlled, allocate zone-level airflow by volume
5211 93034 : Real64 spaceFrac = state.dataHeatBal->space(spaceNum).fracZoneVolume;
5212 93034 : this->SumSysMCp *= spaceFrac;
5213 93034 : this->SumSysMCpT *= spaceFrac;
5214 : }
5215 :
5216 : // Sum all surface convection: this->SumHA, this->SumHATsurf, this->SumHATref (and additional contributions to this->SumIntGain)
5217 62806616 : SumHATOutput sumHATResults; // space or zone return values
5218 62806616 : sumHATResults = this->calcSumHAT(state, zoneNum, spaceNum);
5219 62806616 : this->SumIntGain += sumHATResults.sumIntGain;
5220 62806616 : this->SumHA = sumHATResults.sumHA;
5221 62806616 : this->SumHATsurf = sumHATResults.sumHATsurf;
5222 62806616 : this->SumHATref = sumHATResults.sumHATref;
5223 62806616 : }
5224 :
5225 62691052 : SumHATOutput ZoneHeatBalanceData::calcSumHAT(EnergyPlusData &state, int const zoneNum, [[maybe_unused]] int const spaceNum)
5226 : {
5227 62691052 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
5228 62691052 : assert(zoneNum > 0);
5229 62691052 : assert(spaceNum == 0);
5230 62691052 : SumHATOutput zoneResults; // zone-level return values
5231 125509832 : for (int zoneSpaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
5232 62818780 : SumHATOutput spaceResults; // temporary return value from space-level calcSumHAT
5233 62818780 : spaceResults = s_ztpc->spaceHeatBalance(zoneSpaceNum).calcSumHAT(state, zoneNum, zoneSpaceNum);
5234 62818780 : zoneResults.sumIntGain += spaceResults.sumIntGain;
5235 62818780 : zoneResults.sumHA += spaceResults.sumHA;
5236 62818780 : zoneResults.sumHATsurf += spaceResults.sumHATsurf;
5237 62818780 : zoneResults.sumHATref += spaceResults.sumHATref;
5238 62691052 : }
5239 62691052 : return zoneResults;
5240 : }
5241 :
5242 62934344 : SumHATOutput SpaceHeatBalanceData::calcSumHAT(EnergyPlusData &state, int const zoneNum, int const spaceNum)
5243 : {
5244 62934344 : assert(zoneNum > 0);
5245 62934344 : assert(spaceNum > 0);
5246 62934344 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
5247 62934344 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
5248 62934344 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
5249 62934344 : SumHATOutput results; // space-level return values
5250 :
5251 609545632 : for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
5252 546611288 : Real64 HA = 0.0;
5253 546611288 : Real64 Area = state.dataSurface->Surface(SurfNum).Area; // For windows, this is the glazing area
5254 :
5255 546611288 : if (state.dataSurface->Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window) {
5256 74769762 : DataSurfaces::WinShadingType const shading_flag = state.dataSurface->SurfWinShadingFlag(SurfNum);
5257 :
5258 : // Add to the convective internal gains
5259 74769762 : if (ANY_INTERIOR_SHADE_BLIND(shading_flag)) {
5260 : // The shade area covers the area of the glazing plus the area of the dividers.
5261 555262 : Area += state.dataSurface->SurfWinDividerArea(SurfNum);
5262 : // If interior shade or blind is present it is assumed that both the convective and IR radiative gain
5263 : // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative
5264 : // interaction between divider and shade or blind is ignored due to the difficulty of calculating this interaction
5265 : // at the same time that the interaction between glass and shade is calculated.
5266 555262 : results.sumIntGain += state.dataSurface->SurfWinDividerHeatGain(SurfNum);
5267 : }
5268 :
5269 : // Other convection term is applicable to equivalent layer window (ASHWAT) model
5270 74769762 : if (state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).WindowTypeEQL) {
5271 16326 : results.sumIntGain += state.dataSurface->SurfWinOtherConvHeatGain(SurfNum);
5272 : }
5273 :
5274 : // Convective heat gain from natural convection in gap between glass and interior shade or blind
5275 74769762 : if (ANY_INTERIOR_SHADE_BLIND(shading_flag)) {
5276 555262 : results.sumIntGain += state.dataSurface->SurfWinConvHeatFlowNatural(SurfNum);
5277 : }
5278 :
5279 : // Convective heat gain from airflow window
5280 74769762 : if (state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
5281 40144 : results.sumIntGain += state.dataSurface->SurfWinConvHeatGainToZoneAir(SurfNum);
5282 40144 : if (thisZone.NoHeatToReturnAir) {
5283 40048 : results.sumIntGain += state.dataSurface->SurfWinRetHeatGainToZoneAir(SurfNum);
5284 40048 : state.dataSurface->SurfWinHeatGain(SurfNum) += state.dataSurface->SurfWinRetHeatGainToZoneAir(SurfNum);
5285 40048 : if (state.dataSurface->SurfWinHeatGain(SurfNum) >= 0.0) {
5286 11000 : state.dataSurface->SurfWinHeatGainRep(SurfNum) = state.dataSurface->SurfWinHeatGain(SurfNum);
5287 11000 : state.dataSurface->SurfWinHeatGainRepEnergy(SurfNum) =
5288 11000 : state.dataSurface->SurfWinHeatGainRep(SurfNum) * state.dataGlobal->TimeStepZoneSec;
5289 : } else {
5290 29048 : state.dataSurface->SurfWinHeatLossRep(SurfNum) = -state.dataSurface->SurfWinHeatGain(SurfNum);
5291 29048 : state.dataSurface->SurfWinHeatLossRepEnergy(SurfNum) =
5292 29048 : state.dataSurface->SurfWinHeatLossRep(SurfNum) * state.dataGlobal->TimeStepZoneSec;
5293 : }
5294 40048 : state.dataSurface->SurfWinHeatTransferRepEnergy(SurfNum) =
5295 40048 : state.dataSurface->SurfWinHeatGain(SurfNum) * state.dataGlobal->TimeStepZoneSec;
5296 : }
5297 : }
5298 :
5299 : // Add to the surface convection sums
5300 74769762 : if (state.dataSurface->SurfWinFrameArea(SurfNum) > 0.0) {
5301 : // Window frame contribution
5302 2874560 : Real64 const HA_surf(state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataSurface->SurfWinFrameArea(SurfNum) *
5303 2874560 : (1.0 + state.dataSurface->SurfWinProjCorrFrIn(SurfNum)));
5304 2874560 : results.sumHATsurf += HA_surf * state.dataSurface->SurfWinFrameTempIn(SurfNum);
5305 2874560 : HA += HA_surf;
5306 : }
5307 :
5308 74769762 : if (state.dataSurface->SurfWinDividerArea(SurfNum) > 0.0 && !ANY_INTERIOR_SHADE_BLIND(shading_flag)) {
5309 : // Window divider contribution (only from shade or blind for window with divider and interior shade or blind)
5310 992870 : Real64 const HA_surf(state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataSurface->SurfWinDividerArea(SurfNum) *
5311 992870 : (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum)));
5312 992870 : results.sumHATsurf += HA_surf * state.dataSurface->SurfWinDividerTempIn(SurfNum);
5313 992870 : HA += HA_surf;
5314 : }
5315 :
5316 : } // End of check if window
5317 :
5318 546611288 : HA += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * Area;
5319 546611288 : results.sumHATsurf += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * Area * state.dataHeatBalSurf->SurfTempInTmp(SurfNum);
5320 :
5321 : // determine reference air temperature for this surface
5322 546611288 : switch (state.dataSurface->SurfTAirRef(SurfNum)) {
5323 3134082 : case DataSurfaces::RefAirTemp::ZoneMeanAirTemp:
5324 : // The zone air is the reference temperature (which is to be solved for in CorrectZoneAirTemp).
5325 3134082 : results.sumHA += HA;
5326 3134082 : break;
5327 4502853 : case DataSurfaces::RefAirTemp::AdjacentAirTemp:
5328 4502853 : results.sumHATref += HA * state.dataHeatBal->SurfTempEffBulkAir(SurfNum);
5329 4502853 : break;
5330 0 : case DataSurfaces::RefAirTemp::ZoneSupplyAirTemp:
5331 : // check whether this zone is a controlled zone or not
5332 0 : if (!thisZone.IsControlled) {
5333 0 : ShowFatalError(state,
5334 0 : format("Zones must be controlled for Ceiling-Diffuser Convection model. No system serves zone {}", thisZone.Name));
5335 0 : return results;
5336 : }
5337 : // determine supply air temperature as a weighted average of the inlet temperatures.
5338 : // TODO: For now, use zone-level values for system flow
5339 0 : if (s_ztpc->zoneHeatBalance(zoneNum).SumSysMCp > 0.0) {
5340 0 : results.sumHATref += HA * s_ztpc->zoneHeatBalance(zoneNum).SumSysMCpT / s_ztpc->zoneHeatBalance(zoneNum).SumSysMCp;
5341 : } else {
5342 : // no system flow (yet) so just use zone air temperature #5906
5343 0 : results.sumHA += HA;
5344 : }
5345 0 : break;
5346 538974353 : default:
5347 : // currently set to mean air temp but should add error warning here
5348 538974353 : results.sumHA += HA;
5349 538974353 : break;
5350 : }
5351 :
5352 : } // SurfNum
5353 62934344 : return results;
5354 : }
5355 31431206 : void CalcZoneComponentLoadSums(EnergyPlusData &state,
5356 : int ZoneNum, // Zone number
5357 : ZoneTempPredictorCorrector::ZoneSpaceHeatBalanceData *thisHB,
5358 : DataHeatBalance::AirReportVars &thisAirRpt)
5359 : {
5360 :
5361 : // SUBROUTINE INFORMATION:
5362 : // AUTHOR Brent Griffith
5363 : // DATE WRITTEN Feb 2008
5364 :
5365 : // PURPOSE OF THIS SUBROUTINE:
5366 : // This subroutine calculates the various sums that go into the zone heat balance
5367 : // equation for reporting (and diagnostic) purposes only.
5368 : // It was derived from CalcZonethisAirRpt.Sums but differs in that that routine
5369 : // breaks up the component's dependence on zone air temp in order to *solve* for zone air temp,
5370 : // but here we *use* the result for zone air temp and calculate the terms of the heat balance
5371 : // Go back and calculate each of the 6 terms in Equation 5 and fill report variables.
5372 : // notes on these raw terms for zone air heat balance model :
5373 : // these are state variables at the end of the last system timestep.
5374 : // they are not necessarily proper averages for what happened over entire zone time step
5375 : // these are not multiplied by zone multipliers.
5376 : // The values are all Watts.
5377 :
5378 : // REFERENCES:
5379 : // Equation 5 in Engineering Reference.
5380 :
5381 31431206 : thisAirRpt.SumIntGains = 0.0; // Zone sum of convective internal gains
5382 31431206 : thisAirRpt.SumHADTsurfs = 0.0; // Zone sum of Hc*Area*(Tsurf - Tz)
5383 31431206 : thisAirRpt.SumMCpDTzones = 0.0; // zone sum of MassFlowRate*cp*(TremotZone - Tz) transfer air from other zone, Mixing
5384 31431206 : thisAirRpt.SumMCpDtInfil = 0.0; // Zone sum of MassFlowRate*Cp*(Tout - Tz)
5385 31431206 : thisAirRpt.SumMCpDTsystem = 0.0; // Zone sum of air system MassFlowRate*Cp*(Tsup - Tz)
5386 31431206 : thisAirRpt.SumNonAirSystem = 0.0;
5387 31431206 : thisAirRpt.CzdTdt = 0.0;
5388 31431206 : thisAirRpt.imBalance = 0.0;
5389 31431206 : thisAirRpt.SumEnthalpyM = 0.0;
5390 31431206 : thisAirRpt.SumEnthalpyH = 0.0;
5391 :
5392 31431206 : auto &thisZone = state.dataHeatBal->Zone(ZoneNum);
5393 :
5394 31431206 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
5395 :
5396 : // Sum all convective internal gains: SumIntGain
5397 31431206 : thisAirRpt.SumIntGains = InternalHeatGains::zoneSumAllInternalConvectionGains(state, ZoneNum);
5398 :
5399 : // Add heat to return air if zonal system (no return air) or cycling system (return air frequently very
5400 : // low or zero)
5401 31431206 : if (thisZone.NoHeatToReturnAir) {
5402 3608130 : thisAirRpt.SumIntGains += InternalHeatGains::zoneSumAllReturnAirConvectionGains(state, ZoneNum, 0);
5403 : }
5404 :
5405 : // sum non-system air flow transfers between zones
5406 31431206 : thisAirRpt.SumMCpDTzones = thisHB->MCPTM - thisHB->MCPM * thisHB->MAT; // but maybe it should be ZTAV(ZoneNum)
5407 :
5408 : // Sum non-system air flow, i.e. infiltration, simple ventilation, earth tube
5409 : // reuse SumMCp, SumMCpT from CalcZoneSum but use MAT (or maybe ZTAV?) to complete
5410 31431206 : thisAirRpt.SumMCpDtInfil = (thisHB->MCPTI - thisHB->MCPI * thisHB->MAT) + (thisHB->MCPTV - thisHB->MCPV * thisHB->MAT) +
5411 31431206 : (thisHB->MCPTE - thisHB->MCPE * thisHB->MAT) + (thisHB->MCPTC - thisHB->MCPC * thisHB->MAT) +
5412 31431206 : (thisHB->MDotCPOA * thisZone.OutDryBulbTemp -
5413 31431206 : thisHB->MDotCPOA * thisHB->MAT); // infiltration | Ventilation (simple) | Earth tube. | Cooltower | combined OA flow
5414 :
5415 : // Sum all multizone air flow calculated from AirflowNetwork by assuming no simple air infiltration model (if used)
5416 62368785 : if (state.afn->multizone_always_simulated ||
5417 30937579 : (state.afn->simulation_control.type == AirflowNetwork::ControlType::MultizoneWithDistributionOnlyDuringFanOperation &&
5418 23258 : state.afn->AirflowNetworkFanActivated)) {
5419 : // Multizone airflow calculated in AirflowNetwork
5420 511861 : thisAirRpt.SumMCpDtInfil = state.afn->exchangeData(ZoneNum).SumMCpT + state.afn->exchangeData(ZoneNum).SumMVCpT -
5421 511861 : (state.afn->exchangeData(ZoneNum).SumMCp + state.afn->exchangeData(ZoneNum).SumMVCp) * thisHB->MAT;
5422 511861 : thisAirRpt.SumMCpDTzones = state.afn->exchangeData(ZoneNum).SumMMCpT - state.afn->exchangeData(ZoneNum).SumMMCp * thisHB->MAT;
5423 : }
5424 :
5425 : // Sum all system air flow: reusing how SumSysMCp, SumSysMCpT are calculated in CalcZoneSums
5426 : // Plenum and controlled zones have a different set of inlet nodes which must be calculated.
5427 31431206 : Real64 QSensRate = 0.0;
5428 31431206 : if (thisZone.IsControlled) {
5429 27174934 : auto &zoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(ZoneNum);
5430 56111259 : for (int NodeNum = 1; NodeNum <= zoneEquipConfig.NumInletNodes; ++NodeNum) {
5431 : // Get node conditions
5432 28936325 : Real64 const NodeTemp = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(NodeNum)).Temp;
5433 28936325 : Real64 const MassFlowRate = state.dataLoopNodes->Node(zoneEquipConfig.InletNode(NodeNum)).MassFlowRate;
5434 28936325 : QSensRate = calcZoneSensibleOutput(MassFlowRate, NodeTemp, thisHB->MAT, thisHB->airHumRat);
5435 28936325 : thisAirRpt.SumMCpDTsystem += QSensRate;
5436 :
5437 28936325 : if (zoneEquipConfig.InletNodeADUNum(NodeNum) > 0) {
5438 14854137 : auto &airDistUnit = state.dataDefineEquipment->AirDistUnit(zoneEquipConfig.InletNodeADUNum(NodeNum));
5439 14854137 : Real64 ADUHeatAddRate = calcZoneSensibleOutput(state.dataLoopNodes->Node(airDistUnit.OutletNodeNum).MassFlowRate,
5440 14854137 : state.dataLoopNodes->Node(airDistUnit.OutletNodeNum).Temp,
5441 : thisHB->MAT,
5442 : thisHB->airHumRat);
5443 14854137 : airDistUnit.HeatRate = max(0.0, ADUHeatAddRate);
5444 14854137 : airDistUnit.CoolRate = std::abs(min(0.0, ADUHeatAddRate));
5445 14854137 : airDistUnit.HeatGain = airDistUnit.HeatRate * TimeStepSysSec;
5446 14854137 : airDistUnit.CoolGain = airDistUnit.CoolRate * TimeStepSysSec;
5447 : }
5448 : }
5449 :
5450 4256272 : } else if (thisZone.IsReturnPlenum) {
5451 1089639 : auto &zoneRetPlenCond = state.dataZonePlenum->ZoneRetPlenCond(thisZone.PlenumCondNum);
5452 6283299 : for (int NodeNum = 1; NodeNum <= zoneRetPlenCond.NumInletNodes; ++NodeNum) {
5453 5193660 : QSensRate = calcZoneSensibleOutput(state.dataLoopNodes->Node(zoneRetPlenCond.InletNode(NodeNum)).MassFlowRate,
5454 5193660 : state.dataLoopNodes->Node(zoneRetPlenCond.InletNode(NodeNum)).Temp,
5455 : thisHB->MAT,
5456 : thisHB->airHumRat);
5457 5193660 : thisAirRpt.SumMCpDTsystem += QSensRate;
5458 : }
5459 : // add in the leaks
5460 6301939 : for (int ADUListIndex = 1; ADUListIndex <= zoneRetPlenCond.NumADUs; ++ADUListIndex) {
5461 5212300 : auto &airDistUnit = state.dataDefineEquipment->AirDistUnit(zoneRetPlenCond.ADUIndex(ADUListIndex));
5462 5212300 : if (airDistUnit.UpStreamLeak) {
5463 319785 : QSensRate = calcZoneSensibleOutput(
5464 106595 : airDistUnit.MassFlowRateUpStrLk, state.dataLoopNodes->Node(airDistUnit.InletNodeNum).Temp, thisHB->MAT, thisHB->airHumRat);
5465 106595 : thisAirRpt.SumMCpDTsystem += QSensRate;
5466 : }
5467 5212300 : if (airDistUnit.DownStreamLeak) {
5468 319785 : QSensRate = calcZoneSensibleOutput(
5469 106595 : airDistUnit.MassFlowRateDnStrLk, state.dataLoopNodes->Node(airDistUnit.OutletNodeNum).Temp, thisHB->MAT, thisHB->airHumRat);
5470 106595 : thisAirRpt.SumMCpDTsystem += QSensRate;
5471 : }
5472 : }
5473 :
5474 3166633 : } else if (thisZone.IsSupplyPlenum) {
5475 19526 : auto &zoneSupPlenCond = state.dataZonePlenum->ZoneSupPlenCond(thisZone.PlenumCondNum);
5476 19526 : QSensRate = calcZoneSensibleOutput(state.dataLoopNodes->Node(zoneSupPlenCond.InletNode).MassFlowRate,
5477 19526 : state.dataLoopNodes->Node(zoneSupPlenCond.InletNode).Temp,
5478 : thisHB->MAT,
5479 : thisHB->airHumRat);
5480 19526 : thisAirRpt.SumMCpDTsystem += QSensRate;
5481 : }
5482 :
5483 : // non air system response.
5484 31431206 : thisAirRpt.SumNonAirSystem =
5485 31431206 : thisHB->NonAirSystemResponse + state.dataHeatBalFanSys->SumConvHTRadSys(ZoneNum) + state.dataHeatBalFanSys->SumConvPool(ZoneNum);
5486 :
5487 : // Sum all surface convection: SumHA, SumHATsurf, SumHATref (and additional contributions to SumIntGain)
5488 62994064 : for (int spaceNum : state.dataHeatBal->Zone(ZoneNum).spaceIndexes) {
5489 31562858 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
5490 305331376 : for (int SurfNum = thisSpace.HTSurfaceFirst; SurfNum <= thisSpace.HTSurfaceLast; ++SurfNum) {
5491 :
5492 273768518 : Real64 Area = state.dataSurface->Surface(SurfNum).Area; // For windows, this is the glazing area
5493 273768518 : Real64 RefAirTemp = state.dataSurface->Surface(SurfNum).getInsideAirTemperature(state, SurfNum);
5494 :
5495 273768518 : if (state.dataSurface->Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window) {
5496 :
5497 : // Add to the convective internal gains
5498 37427799 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
5499 : // The shade area covers the area of the glazing plus the area of the dividers.
5500 277631 : Area += state.dataSurface->SurfWinDividerArea(SurfNum);
5501 : // If interior shade or blind is present it is assumed that both the convective and IR radiative gain
5502 : // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative
5503 : // interaction between divider and shade or blind is ignored due to the difficulty of calculating this interaction
5504 : // at the same time that the interaction between glass and shade is calculated.
5505 277631 : thisAirRpt.SumIntGains += state.dataSurface->SurfWinDividerHeatGain(SurfNum);
5506 : }
5507 :
5508 : // Other convection term is applicable to equivalent layer window (ASHWAT) model
5509 37427799 : if (state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).WindowTypeEQL) {
5510 8163 : thisAirRpt.SumIntGains += state.dataSurface->SurfWinOtherConvHeatGain(SurfNum);
5511 : }
5512 :
5513 : // Convective heat gain from natural convection in gap between glass and interior shade or blind
5514 37427799 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
5515 277631 : thisAirRpt.SumIntGains += state.dataSurface->SurfWinConvHeatFlowNatural(SurfNum);
5516 : }
5517 :
5518 : // Convective heat gain from airflow window
5519 37427799 : if (state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
5520 20072 : thisAirRpt.SumIntGains += state.dataSurface->SurfWinConvHeatGainToZoneAir(SurfNum);
5521 20072 : if (thisZone.NoHeatToReturnAir) {
5522 20024 : thisAirRpt.SumIntGains += state.dataSurface->SurfWinRetHeatGainToZoneAir(SurfNum);
5523 : }
5524 : }
5525 :
5526 : // Add to the surface convection sums
5527 37427799 : if (state.dataSurface->SurfWinFrameArea(SurfNum) > 0.0) {
5528 : // Window frame contribution
5529 1437280 : thisAirRpt.SumHADTsurfs += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataSurface->SurfWinFrameArea(SurfNum) *
5530 1437280 : (1.0 + state.dataSurface->SurfWinProjCorrFrIn(SurfNum)) *
5531 1437280 : (state.dataSurface->SurfWinFrameTempIn(SurfNum) - RefAirTemp);
5532 : }
5533 :
5534 37927223 : if (state.dataSurface->SurfWinDividerArea(SurfNum) > 0.0 &&
5535 499424 : !ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
5536 : // Window divider contribution (only from shade or blind for window with divider and interior shade or blind)
5537 496435 : thisAirRpt.SumHADTsurfs += state.dataHeatBalSurf->SurfHConvInt(SurfNum) * state.dataSurface->SurfWinDividerArea(SurfNum) *
5538 496435 : (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum)) *
5539 496435 : (state.dataSurface->SurfWinDividerTempIn(SurfNum) - RefAirTemp);
5540 : }
5541 :
5542 : } // End of check if window
5543 :
5544 273768518 : thisAirRpt.SumHADTsurfs +=
5545 273768518 : state.dataHeatBalSurf->SurfHConvInt(SurfNum) * Area * (state.dataHeatBalSurf->SurfTempInTmp(SurfNum) - RefAirTemp);
5546 :
5547 : // Accumulate Zone Phase Change Material Melting/Freezing Enthalpy output variables
5548 273768518 : if (state.dataSurface->Surface(SurfNum).HeatTransferAlgorithm == DataSurfaces::HeatTransferModel::CondFD) {
5549 1710066 : thisAirRpt.SumEnthalpyM += state.dataHeatBalFiniteDiffMgr->SurfaceFD(SurfNum).EnthalpyM;
5550 1710066 : thisAirRpt.SumEnthalpyH += state.dataHeatBalFiniteDiffMgr->SurfaceFD(SurfNum).EnthalpyF;
5551 : }
5552 : }
5553 31431206 : }
5554 : // now calculate air energy storage source term.
5555 : // capacitance is volume * density * heat capacity
5556 31431206 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(thisHB->airHumRat);
5557 31431206 : Real64 RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisHB->MAT, thisHB->airHumRat);
5558 :
5559 31431206 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
5560 17089871 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
5561 17089871 : thisAirRpt.CzdTdt = RhoAir * CpAir * thisZone.Volume * thisZone.ZoneVolCapMultpSens * (thisHB->MAT - thisHB->ZTM[0]) / TimeStepSysSec;
5562 : // Exact solution
5563 17089871 : } break;
5564 14303125 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
5565 14303125 : thisAirRpt.CzdTdt = thisHB->TempIndCoef - thisHB->TempDepCoef * thisHB->MAT;
5566 14303125 : } break;
5567 38210 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
5568 38210 : thisAirRpt.CzdTdt = thisHB->AirPowerCap * (thisHB->MAT - thisHB->T1);
5569 38210 : } break;
5570 0 : default:
5571 0 : break;
5572 : }
5573 :
5574 31431206 : if (state.dataGlobal->DisplayZoneAirHeatBalanceOffBalance) {
5575 263377 : thisAirRpt.imBalance = thisAirRpt.SumIntGains + thisAirRpt.SumHADTsurfs + thisAirRpt.SumMCpDTzones + thisAirRpt.SumMCpDtInfil +
5576 263377 : thisAirRpt.SumMCpDTsystem + thisAirRpt.SumNonAirSystem - thisAirRpt.CzdTdt;
5577 :
5578 : // throw warning if seriously out of balance (this may need to be removed if too noisy... )
5579 : // formulate dynamic threshold value based on 20% of quadrature sum of components
5580 263377 : Real64 Threshold = 0.2 * std::sqrt(pow_2(thisAirRpt.SumIntGains) + pow_2(thisAirRpt.SumHADTsurfs) + pow_2(thisAirRpt.SumMCpDTzones) +
5581 263377 : pow_2(thisAirRpt.SumMCpDtInfil) + pow_2(thisAirRpt.SumMCpDTsystem) + pow_2(thisAirRpt.SumNonAirSystem) +
5582 263377 : pow_2(thisAirRpt.CzdTdt));
5583 264173 : if ((std::abs(thisAirRpt.imBalance) > Threshold) && (!state.dataGlobal->WarmupFlag) &&
5584 796 : (!state.dataGlobal->DoingSizing)) { // air balance is out by more than threshold
5585 796 : if (thisZone.AirHBimBalanceErrIndex == 0) {
5586 14 : ShowWarningMessage(state, format("Zone Air Heat Balance is out of balance for zone named {}", thisZone.Name));
5587 14 : ShowContinueError(state, format("Zone Air Heat Balance Deviation Rate is more than {:.1R} {{W}}", Threshold));
5588 14 : if (state.dataHVACGlobal->TurnFansOn) {
5589 0 : ShowContinueError(state, "Night cycle fan operation may be causing above error");
5590 : }
5591 :
5592 42 : ShowContinueErrorTimeStamp(state, " Occurrence info:");
5593 : }
5594 6368 : ShowRecurringWarningErrorAtEnd(state,
5595 1592 : format("Zone Air Heat Balance is out of balance ... zone named {}", thisZone.Name),
5596 796 : thisZone.AirHBimBalanceErrIndex,
5597 1592 : std::abs(thisAirRpt.imBalance) - Threshold,
5598 1592 : std::abs(thisAirRpt.imBalance) - Threshold,
5599 : _,
5600 : "{W}",
5601 : "{W}");
5602 : }
5603 : }
5604 31431206 : }
5605 :
5606 3642 : bool VerifyThermostatInZone(EnergyPlusData &state, std::string const &ZoneName) // Zone to verify
5607 : {
5608 :
5609 : // FUNCTION INFORMATION:
5610 : // AUTHOR Linda Lawrie
5611 : // DATE WRITTEN Feb 2005
5612 :
5613 : // PURPOSE OF THIS FUNCTION:
5614 : // This function verifies that a zone (by name) has a Zone Control:Thermostatic object entered.
5615 :
5616 3642 : if (state.dataZoneCtrls->GetZoneAirStatsInputFlag) {
5617 0 : GetZoneAirSetPoints(state);
5618 0 : state.dataZoneCtrls->GetZoneAirStatsInputFlag = false;
5619 : }
5620 3642 : if (state.dataZoneCtrls->NumTempControlledZones > 0) {
5621 3639 : if (Util::FindItemInList(ZoneName, state.dataZoneCtrls->TempControlledZone, &DataZoneControls::ZoneTempControls::ZoneName) > 0) {
5622 3638 : return true;
5623 : } else {
5624 1 : return false;
5625 : }
5626 : }
5627 3 : return false;
5628 : }
5629 :
5630 4334 : bool VerifyControlledZoneForThermostat(EnergyPlusData &state, std::string const &ZoneName) // Zone to verify
5631 : {
5632 :
5633 : // FUNCTION INFORMATION:
5634 : // AUTHOR Linda Lawrie
5635 : // DATE WRITTEN Mar 2007
5636 :
5637 : // PURPOSE OF THIS FUNCTION:
5638 : // This function verifies that a zone (by name) has a ZoneHVAC:EquipmentConnections object entered.
5639 :
5640 4334 : return (Util::FindItemInList(ZoneName, state.dataZoneEquip->ZoneEquipConfig, &DataZoneEquipment::EquipConfiguration::ZoneName) > 0);
5641 : }
5642 :
5643 3588830 : void DetectOscillatingZoneTemp(EnergyPlusData &state)
5644 : {
5645 : // SUBROUTINE INFORMATION:
5646 : // AUTHOR Jason Glazer
5647 : // DATE WRITTEN August 2005
5648 :
5649 : // PURPOSE OF THIS SUBROUTINE:
5650 : // Oscillating temperatures between HVAC timesteps indicate that the
5651 : // simulation may be poor. Code is trying to be fast since the purpose
5652 : // is to see the impact on oscillating by trying longer time steps in
5653 : // an attempt to speed up the simulation.
5654 : // Note that the OscillateMagnitude threshold must be less than
5655 : // MaxZoneTempDiff since ManageHVAC keeps shortening the timestep
5656 : // until that is reached unless it goes to less than the
5657 : // MinTimeStepSys.
5658 3588830 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
5659 :
5660 : // first time run allocate arrays and setup output variable
5661 3588830 : if (s_ztpc->SetupOscillationOutputFlag) {
5662 801 : s_ztpc->ZoneTempHist.allocate(4, state.dataGlobal->NumOfZones);
5663 801 : s_ztpc->ZoneTempHist = 0.0;
5664 801 : s_ztpc->ZoneTempOscillate.dimension(state.dataGlobal->NumOfZones, 0.0);
5665 801 : s_ztpc->ZoneTempOscillateDuringOccupancy.dimension(state.dataGlobal->NumOfZones, 0.0);
5666 801 : s_ztpc->ZoneTempOscillateInDeadband.dimension(state.dataGlobal->NumOfZones, 0.0);
5667 : // set up zone by zone variables, CurrentModuleObject='Zone'
5668 6002 : for (int iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
5669 5201 : auto &zone = state.dataHeatBal->Zone(iZone);
5670 10402 : SetupOutputVariable(state,
5671 : "Zone Oscillating Temperatures Time",
5672 : Constant::Units::hr,
5673 5201 : s_ztpc->ZoneTempOscillate(iZone),
5674 : OutputProcessor::TimeStepType::System,
5675 : OutputProcessor::StoreType::Sum,
5676 5201 : zone.Name);
5677 10402 : SetupOutputVariable(state,
5678 : "Zone Oscillating Temperatures During Occupancy Time",
5679 : Constant::Units::hr,
5680 5201 : s_ztpc->ZoneTempOscillateDuringOccupancy(iZone),
5681 : OutputProcessor::TimeStepType::System,
5682 : OutputProcessor::StoreType::Sum,
5683 5201 : zone.Name);
5684 10402 : SetupOutputVariable(state,
5685 : "Zone Oscillating Temperatures in Deadband Time",
5686 : Constant::Units::hr,
5687 5201 : s_ztpc->ZoneTempOscillateInDeadband(iZone),
5688 : OutputProcessor::TimeStepType::System,
5689 : OutputProcessor::StoreType::Sum,
5690 5201 : zone.Name);
5691 : }
5692 : // set up a variable covering all zones
5693 3204 : SetupOutputVariable(state,
5694 : "Facility Any Zone Oscillating Temperatures Time",
5695 : Constant::Units::hr,
5696 801 : s_ztpc->AnyZoneTempOscillate,
5697 : OutputProcessor::TimeStepType::System,
5698 : OutputProcessor::StoreType::Sum,
5699 : "Facility");
5700 3204 : SetupOutputVariable(state,
5701 : "Facility Any Zone Oscillating Temperatures During Occupancy Time",
5702 : Constant::Units::hr,
5703 801 : s_ztpc->AnyZoneTempOscillateDuringOccupancy,
5704 : OutputProcessor::TimeStepType::System,
5705 : OutputProcessor::StoreType::Sum,
5706 : "Facility");
5707 3204 : SetupOutputVariable(state,
5708 : "Facility Any Zone Oscillating Temperatures in Deadband Time",
5709 : Constant::Units::hr,
5710 801 : s_ztpc->AnyZoneTempOscillateInDeadband,
5711 : OutputProcessor::TimeStepType::System,
5712 : OutputProcessor::StoreType::Sum,
5713 : "Facility");
5714 : // test if the oscillation variables are even used
5715 2403 : if (ReportingThisVariable(state, "Zone Oscillating Temperatures Time") ||
5716 2403 : ReportingThisVariable(state, "Zone Oscillating Temperatures During Occupancy Time") ||
5717 2403 : ReportingThisVariable(state, "Zone Oscillating Temperatures in Deadband Time") ||
5718 2403 : ReportingThisVariable(state, "Facility Any Zone Oscillating Temperatures Time") ||
5719 4806 : ReportingThisVariable(state, "Facility Any Zone Oscillating Temperatures During Occupancy Time") ||
5720 2403 : ReportingThisVariable(state, "Facility Any Zone Oscillating Temperatures in Deadband Time")) {
5721 0 : s_ztpc->OscillationVariablesNeeded = true;
5722 : }
5723 801 : s_ztpc->SetupOscillationOutputFlag = false;
5724 : }
5725 :
5726 3588830 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
5727 3588830 : if (s_ztpc->OscillationVariablesNeeded) {
5728 : // precalc the negative value for performance
5729 27408 : Real64 NegOscillateMagnitude = -HVAC::OscillateMagnitude;
5730 : // assume no zone is oscillating
5731 27408 : bool isAnyZoneOscillating = false;
5732 27408 : bool isAnyZoneOscillatingDuringOccupancy = false;
5733 27408 : bool isAnyZoneOscillatingInDeadband = false;
5734 :
5735 378643 : for (int iZone = 1; iZone <= state.dataGlobal->NumOfZones; ++iZone) {
5736 351235 : bool isOscillate = false;
5737 351235 : s_ztpc->ZoneTempHist(4, iZone) = s_ztpc->ZoneTempHist(3, iZone);
5738 351235 : s_ztpc->ZoneTempHist(3, iZone) = s_ztpc->ZoneTempHist(2, iZone);
5739 351235 : s_ztpc->ZoneTempHist(2, iZone) = s_ztpc->ZoneTempHist(1, iZone);
5740 351235 : s_ztpc->ZoneTempHist(1, iZone) = s_ztpc->zoneHeatBalance(iZone).ZT;
5741 351235 : Real64 Diff34 = s_ztpc->ZoneTempHist(3, iZone) - s_ztpc->ZoneTempHist(4, iZone);
5742 351235 : Real64 Diff23 = s_ztpc->ZoneTempHist(2, iZone) - s_ztpc->ZoneTempHist(3, iZone);
5743 351235 : Real64 Diff12 = s_ztpc->ZoneTempHist(1, iZone) - s_ztpc->ZoneTempHist(2, iZone);
5744 : // roll out the conditionals for increased performance
5745 351235 : if (Diff12 > HVAC::OscillateMagnitude) {
5746 62909 : if (Diff23 < NegOscillateMagnitude) {
5747 11102 : if (Diff34 > HVAC::OscillateMagnitude) {
5748 2750 : isOscillate = true;
5749 : }
5750 : }
5751 : }
5752 : // now try the opposite sequence of swings
5753 351235 : if (Diff12 < NegOscillateMagnitude) {
5754 59455 : if (Diff23 > HVAC::OscillateMagnitude) {
5755 7703 : if (Diff34 < NegOscillateMagnitude) {
5756 2397 : isOscillate = true;
5757 : }
5758 : }
5759 : }
5760 351235 : s_ztpc->ZoneTempOscillateDuringOccupancy(iZone) = 0.0;
5761 351235 : s_ztpc->ZoneTempOscillateInDeadband(iZone) = 0.0;
5762 351235 : if (isOscillate) {
5763 5147 : s_ztpc->ZoneTempOscillate(iZone) = TimeStepSys;
5764 5147 : isAnyZoneOscillating = true;
5765 5147 : if (allocated(state.dataThermalComforts->ThermalComfortInASH55)) {
5766 5147 : if (state.dataThermalComforts->ThermalComfortInASH55(iZone).ZoneIsOccupied) {
5767 372 : s_ztpc->ZoneTempOscillateDuringOccupancy(iZone) = TimeStepSys;
5768 372 : isAnyZoneOscillatingDuringOccupancy = true;
5769 : }
5770 : }
5771 5147 : if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(iZone)) {
5772 884 : s_ztpc->ZoneTempOscillateInDeadband(iZone) = TimeStepSys;
5773 884 : isAnyZoneOscillatingInDeadband = true;
5774 : }
5775 : } else {
5776 346088 : s_ztpc->ZoneTempOscillate(iZone) = 0.0;
5777 : }
5778 : }
5779 : // any zone variable
5780 27408 : s_ztpc->AnyZoneTempOscillate = (isAnyZoneOscillating) ? TimeStepSys : 0.0;
5781 27408 : s_ztpc->AnyZoneTempOscillateDuringOccupancy = (isAnyZoneOscillatingDuringOccupancy) ? TimeStepSys : 0.0;
5782 27408 : s_ztpc->AnyZoneTempOscillateInDeadband = (isAnyZoneOscillatingInDeadband) ? TimeStepSys : 0.0;
5783 :
5784 : // annual/runperiod sum for _perflog.csv file
5785 27408 : s_ztpc->AnnualAnyZoneTempOscillate += s_ztpc->AnyZoneTempOscillate;
5786 27408 : s_ztpc->AnnualAnyZoneTempOscillateDuringOccupancy += s_ztpc->AnyZoneTempOscillateDuringOccupancy;
5787 27408 : s_ztpc->AnnualAnyZoneTempOscillateInDeadband += s_ztpc->AnyZoneTempOscillateInDeadband;
5788 : }
5789 3588830 : }
5790 :
5791 31204152 : void AdjustAirSetPointsforOpTempCntrl(EnergyPlusData &state, int const TempControlledZoneID, int const ActualZoneNum, Real64 &ZoneAirSetPoint)
5792 : {
5793 :
5794 : // SUBROUTINE INFORMATION:
5795 : // AUTHOR B. Griffith
5796 : // DATE WRITTEN June 2006
5797 :
5798 : // PURPOSE OF THIS SUBROUTINE:
5799 : // This subroutine modifies the air temperature setpoint to effect operative temperature control
5800 :
5801 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5802 31204152 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
5803 : Real64 thisMRTFraction; // local variable for fraction that MRT is in Op Temp definition
5804 :
5805 31204152 : if (!(state.dataZoneCtrls->AnyOpTempControl)) {
5806 31171008 : return; // do nothing to setpoint
5807 : }
5808 :
5809 33144 : auto &tempControlledZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneID);
5810 33144 : if (tempControlledZone.OpTempCtrl == DataZoneControls::TempCtrl::None) {
5811 0 : return; // do nothing to setpoint
5812 : }
5813 :
5814 : // is operative temp radiative fraction scheduled or fixed?
5815 66288 : thisMRTFraction = (tempControlledZone.OpTempCtrl == DataZoneControls::TempCtrl::Scheduled)
5816 33144 : ? tempControlledZone.opTempRadiativeFractionSched->getCurrentVal()
5817 : : tempControlledZone.FixedRadiativeFraction;
5818 :
5819 : // get mean radiant temperature for zone
5820 33144 : Real64 thisMRT = s_ztpc->zoneHeatBalance(ActualZoneNum).MRT;
5821 :
5822 : // modify setpoint for operative temperature control
5823 : // trapping for MRT fractions between 0.0 and 0.9 during get input, so shouldn't be able to divide by zero here.
5824 33144 : ZoneAirSetPoint = (ZoneAirSetPoint - thisMRTFraction * thisMRT) / (1.0 - thisMRTFraction);
5825 : }
5826 :
5827 6765 : void AdjustOperativeSetPointsforAdapComfort(EnergyPlusData &state, int const TempControlledZoneID, Real64 &ZoneAirSetPoint)
5828 : {
5829 : // SUBROUTINE INFORMATION:
5830 : // AUTHOR Xuan Luo
5831 : // DATE WRITTEN Jan 2017
5832 :
5833 : // PURPOSE OF THIS SUBROUTINE:
5834 : // This routine adjust the operative setpoints for each controlled adaptive thermal comfort models.
5835 :
5836 6765 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
5837 6765 : auto const &tempControlledZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneID);
5838 6765 : auto const &AdapComfortDailySetPointSchedule = s_ztpc->AdapComfortDailySetPointSchedule;
5839 :
5840 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5841 6765 : int originZoneAirSetPoint = ZoneAirSetPoint;
5842 6765 : int AdaptiveComfortModelTypeIndex = tempControlledZone.AdaptiveComfortModelTypeIndex;
5843 :
5844 : // adjust zone operative setpoint
5845 6765 : if (!(tempControlledZone.AdaptiveComfortTempControl)) {
5846 0 : return; // do nothing to setpoint
5847 : }
5848 6780 : if ((state.dataWeather->Environment(state.dataWeather->Envrn).KindOfEnvrn != Constant::KindOfSim::DesignDay) &&
5849 15 : (state.dataWeather->Environment(state.dataWeather->Envrn).KindOfEnvrn != Constant::KindOfSim::HVACSizeDesignDay)) {
5850 : // Adjust run period cooling set point
5851 15 : switch (AdaptiveComfortModelTypeIndex) {
5852 15 : case static_cast<int>(AdaptiveComfortModel::ASH55_CENTRAL):
5853 15 : ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Central(state.dataEnvrn->DayOfYear);
5854 15 : break;
5855 0 : case static_cast<int>(AdaptiveComfortModel::ASH55_UPPER_90):
5856 0 : ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_90(state.dataEnvrn->DayOfYear);
5857 0 : break;
5858 0 : case static_cast<int>(AdaptiveComfortModel::ASH55_UPPER_80):
5859 0 : ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveASH55_Upper_80(state.dataEnvrn->DayOfYear);
5860 0 : break;
5861 0 : case static_cast<int>(AdaptiveComfortModel::CEN15251_CENTRAL):
5862 0 : ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Central(state.dataEnvrn->DayOfYear);
5863 0 : break;
5864 0 : case static_cast<int>(AdaptiveComfortModel::CEN15251_UPPER_I):
5865 0 : ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_I(state.dataEnvrn->DayOfYear);
5866 0 : break;
5867 0 : case static_cast<int>(AdaptiveComfortModel::CEN15251_UPPER_II):
5868 0 : ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_II(state.dataEnvrn->DayOfYear);
5869 0 : break;
5870 0 : case static_cast<int>(AdaptiveComfortModel::CEN15251_UPPER_III):
5871 0 : ZoneAirSetPoint = AdapComfortDailySetPointSchedule.ThermalComfortAdaptiveCEN15251_Upper_III(state.dataEnvrn->DayOfYear);
5872 0 : break;
5873 0 : default:
5874 0 : break;
5875 : }
5876 : } else {
5877 6750 : int const envrnDayNum(state.dataWeather->Environment(state.dataWeather->Envrn).DesignDayNum);
5878 6750 : int constexpr summerDesignDayTypeIndex(9);
5879 : // Adjust summer design day set point
5880 6750 : if (state.dataWeather->DesDayInput(envrnDayNum).DayType == summerDesignDayTypeIndex) {
5881 6750 : ZoneAirSetPoint = s_ztpc->AdapComfortSetPointSummerDesDay[AdaptiveComfortModelTypeIndex - 2];
5882 : }
5883 : }
5884 : // If adaptive operative temperature not applicable, set back
5885 6765 : if (ZoneAirSetPoint < originZoneAirSetPoint) {
5886 15 : ZoneAirSetPoint = originZoneAirSetPoint;
5887 : }
5888 : // If meet fault flag, set back
5889 6765 : if (ZoneAirSetPoint == -1) {
5890 0 : ZoneAirSetPoint = originZoneAirSetPoint;
5891 : }
5892 : }
5893 :
5894 2025 : void CalcZoneAirComfortSetPoints(EnergyPlusData &state)
5895 : {
5896 :
5897 : // SUBROUTINE INFORMATION:
5898 : // AUTHOR Lixing Gu
5899 : // DATE WRITTEN May 2006
5900 :
5901 : // PURPOSE OF THIS SUBROUTINE:
5902 : // This routine sets the thermal comfort setpoints for each controlled zone based on air temperature obtained from thermal comfort models.
5903 :
5904 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5905 2025 : Real64 SetPointLo = 0.0;
5906 2025 : Real64 SetPointHi = 0.0;
5907 2025 : Real64 Tset = 0.0;
5908 2025 : int ObjectCount = 0;
5909 2025 : Real64 PeopleCount = 0.0;
5910 :
5911 2025 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
5912 2025 : auto &s_hbfs = state.dataHeatBalFanSys;
5913 : // Call thermal comfort module to read zone control comfort object
5914 2025 : if (s_ztpc->CalcZoneAirComfortSetPointsFirstTimeFlag) {
5915 1 : ThermalComfort::ManageThermalComfort(state, true);
5916 1 : s_ztpc->CalcZoneAirComfortSetPointsFirstTimeFlag = false;
5917 : }
5918 :
5919 2025 : s_hbfs->ComfortControlType = HVAC::SetptType::Uncontrolled; // Default
5920 :
5921 4050 : for (int RelativeZoneNum = 1; RelativeZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++RelativeZoneNum) {
5922 :
5923 2025 : auto &comfortZone = state.dataZoneCtrls->ComfortControlledZone(RelativeZoneNum);
5924 2025 : int ActualZoneNum = comfortZone.ActualZoneNum;
5925 2025 : auto &zone = state.dataHeatBal->Zone(ActualZoneNum);
5926 2025 : auto &zoneTstatSetpt = state.dataHeatBalFanSys->zoneTstatSetpts(ActualZoneNum);
5927 2025 : auto &zoneComfortControlsFanger = state.dataHeatBalFanSys->ZoneComfortControlsFanger(ActualZoneNum);
5928 2025 : s_hbfs->ComfortControlType(ActualZoneNum) = static_cast<HVAC::SetptType>(comfortZone.setptTypeSched->getCurrentVal());
5929 2025 : s_hbfs->ComfortControlTypeRpt(ActualZoneNum) = (int)s_hbfs->ComfortControlType(ActualZoneNum);
5930 :
5931 : // Get PMV values
5932 2025 : switch (s_hbfs->ComfortControlType(ActualZoneNum)) {
5933 1185 : case HVAC::SetptType::Uncontrolled: {
5934 1185 : zoneComfortControlsFanger.LowPMV = -999.0;
5935 1185 : zoneComfortControlsFanger.HighPMV = -999.0;
5936 1185 : } break;
5937 :
5938 210 : case HVAC::SetptType::SingleHeat: {
5939 210 : zoneComfortControlsFanger.FangerType = (int)HVAC::SetptType::SingleHeat;
5940 210 : zoneComfortControlsFanger.LowPMV = comfortZone.setpts[(int)HVAC::SetptType::SingleHeat].heatSetptSched->getCurrentVal();
5941 210 : zoneComfortControlsFanger.HighPMV = -999.0;
5942 210 : } break;
5943 :
5944 210 : case HVAC::SetptType::SingleCool: {
5945 210 : zoneComfortControlsFanger.FangerType = (int)HVAC::SetptType::SingleCool;
5946 210 : zoneComfortControlsFanger.LowPMV = -999.0;
5947 210 : zoneComfortControlsFanger.HighPMV = comfortZone.setpts[(int)HVAC::SetptType::SingleCool].coolSetptSched->getCurrentVal();
5948 210 : } break;
5949 :
5950 210 : case HVAC::SetptType::SingleHeatCool: {
5951 210 : zoneComfortControlsFanger.FangerType = (int)HVAC::SetptType::SingleHeatCool;
5952 210 : zoneComfortControlsFanger.LowPMV = zoneComfortControlsFanger.HighPMV =
5953 210 : comfortZone.setpts[(int)HVAC::SetptType::SingleHeatCool].coolSetptSched->getCurrentVal();
5954 210 : } break;
5955 :
5956 210 : case HVAC::SetptType::DualHeatCool: {
5957 210 : zoneComfortControlsFanger.FangerType = (int)HVAC::SetptType::DualHeatCool;
5958 210 : zoneComfortControlsFanger.LowPMV = comfortZone.setpts[(int)HVAC::SetptType::DualHeatCool].heatSetptSched->getCurrentVal();
5959 210 : zoneComfortControlsFanger.HighPMV = comfortZone.setpts[(int)HVAC::SetptType::DualHeatCool].coolSetptSched->getCurrentVal();
5960 210 : if (zoneComfortControlsFanger.LowPMV > zoneComfortControlsFanger.HighPMV) {
5961 0 : ++zoneComfortControlsFanger.DualPMVErrCount;
5962 0 : if (zoneComfortControlsFanger.DualPMVErrCount < 2) {
5963 0 : ShowWarningError(state,
5964 0 : format("ThermostatSetpoint:ThermalComfort:Fanger:DualSetpoint: The heating PMV setpoint is above the "
5965 : "cooling PMV setpoint in {}",
5966 0 : comfortZone.setpts[(int)HVAC::SetptType::DualHeatCool].Name));
5967 0 : ShowContinueError(state, "The zone dual heating PMV setpoint is set to the dual cooling PMV setpoint.");
5968 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
5969 : } else {
5970 0 : ShowRecurringWarningErrorAtEnd(state,
5971 : "The heating PMV setpoint is still above the cooling PMV setpoint",
5972 0 : zoneComfortControlsFanger.DualPMVErrIndex,
5973 0 : zoneComfortControlsFanger.LowPMV,
5974 0 : zoneComfortControlsFanger.LowPMV);
5975 : }
5976 0 : zoneComfortControlsFanger.LowPMV = zoneComfortControlsFanger.HighPMV;
5977 : }
5978 210 : } break;
5979 :
5980 0 : default: {
5981 0 : ShowSevereError(state,
5982 0 : format("CalcZoneAirTempSetpoints: Illegal thermal control control type for Zone={}, Found value={}, in Schedule={}",
5983 0 : zone.Name,
5984 0 : s_hbfs->ComfortControlTypeRpt(ActualZoneNum),
5985 0 : comfortZone.setptTypeSched->Name));
5986 0 : } break;
5987 : } // switch
5988 :
5989 : // Check Average method
5990 2025 : switch (comfortZone.averageMethod) {
5991 2025 : case DataZoneControls::AverageMethod::NO: {
5992 2025 : int PeopleNum = comfortZone.SpecificObjectNum;
5993 2025 : if (s_hbfs->ComfortControlType(ActualZoneNum) == HVAC::SetptType::SingleCool) {
5994 210 : GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, SetPointLo);
5995 : } else {
5996 1815 : GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.LowPMV, SetPointLo);
5997 : }
5998 2025 : if (s_hbfs->ComfortControlType(ActualZoneNum) == HVAC::SetptType::DualHeatCool) {
5999 210 : GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, SetPointHi);
6000 : }
6001 2025 : } break;
6002 :
6003 0 : case DataZoneControls::AverageMethod::SPE: {
6004 0 : int PeopleNum = comfortZone.SpecificObjectNum;
6005 0 : if (s_hbfs->ComfortControlType(ActualZoneNum) == HVAC::SetptType::SingleCool) {
6006 0 : GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, SetPointLo);
6007 : } else {
6008 0 : GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.LowPMV, SetPointLo);
6009 : }
6010 0 : if (s_hbfs->ComfortControlType(ActualZoneNum) == HVAC::SetptType::DualHeatCool) {
6011 0 : GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, SetPointHi);
6012 : }
6013 0 : } break;
6014 :
6015 0 : case DataZoneControls::AverageMethod::OBJ: {
6016 0 : SetPointLo = 0.0;
6017 0 : SetPointHi = 0.0;
6018 0 : for (int peopleNum = 1; peopleNum <= state.dataHeatBal->TotPeople; ++peopleNum) {
6019 0 : if (ActualZoneNum == state.dataHeatBal->People(peopleNum).ZonePtr) {
6020 0 : ++ObjectCount;
6021 0 : GetComfortSetPoints(state, peopleNum, RelativeZoneNum, zoneComfortControlsFanger.LowPMV, Tset);
6022 0 : SetPointLo += Tset;
6023 :
6024 0 : if (s_hbfs->ComfortControlType(ActualZoneNum) == HVAC::SetptType::DualHeatCool) {
6025 0 : GetComfortSetPoints(state, peopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, Tset);
6026 0 : SetPointHi += Tset;
6027 : }
6028 : }
6029 : }
6030 0 : SetPointLo /= ObjectCount;
6031 0 : if (s_hbfs->ComfortControlType(ActualZoneNum) == HVAC::SetptType::DualHeatCool) {
6032 0 : SetPointHi /= ObjectCount;
6033 : }
6034 0 : } break;
6035 :
6036 0 : case DataZoneControls::AverageMethod::PEO: {
6037 0 : SetPointLo = 0.0;
6038 0 : SetPointHi = 0.0;
6039 :
6040 0 : for (int PeopleNum = 1; PeopleNum <= state.dataHeatBal->TotPeople; ++PeopleNum) {
6041 0 : auto &people = state.dataHeatBal->People(PeopleNum);
6042 0 : if (ActualZoneNum == people.ZonePtr) {
6043 0 : int NumberOccupants = people.NumberOfPeople * people.sched->getCurrentVal();
6044 0 : PeopleCount += NumberOccupants;
6045 0 : GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.LowPMV, Tset);
6046 0 : SetPointLo += Tset * NumberOccupants;
6047 0 : if (s_hbfs->ComfortControlType(ActualZoneNum) == HVAC::SetptType::DualHeatCool) {
6048 0 : GetComfortSetPoints(state, PeopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, Tset);
6049 0 : SetPointHi += Tset * NumberOccupants;
6050 : }
6051 : }
6052 : }
6053 0 : if (PeopleCount > 0) {
6054 0 : SetPointLo /= PeopleCount;
6055 0 : if (s_hbfs->ComfortControlType(ActualZoneNum) == HVAC::SetptType::DualHeatCool) {
6056 0 : SetPointHi /= PeopleCount;
6057 : }
6058 : } else {
6059 0 : if (comfortZone.PeopleAverageErrIndex == 0) {
6060 0 : ShowWarningMessage(state,
6061 0 : format("ZoneControl:Thermostat:ThermalComfort: The total number of people in Zone = {} is zero. The People "
6062 : "Average option is not used.",
6063 0 : zone.Name));
6064 0 : ShowContinueError(state, "The Object Average option is used instead. Simulation continues .....");
6065 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
6066 : }
6067 0 : ShowRecurringWarningErrorAtEnd(state,
6068 0 : "ZoneControl:Thermostat:ThermalComfort: The total number of people in Zone = " + zone.Name +
6069 : " is still zero. The People Average option is not used",
6070 0 : comfortZone.PeopleAverageErrIndex,
6071 : PeopleCount,
6072 : PeopleCount);
6073 0 : SetPointLo = 0.0;
6074 0 : SetPointHi = 0.0;
6075 0 : for (int peopleNum = 1; peopleNum <= state.dataHeatBal->TotPeople; ++peopleNum) {
6076 0 : if (ActualZoneNum == state.dataHeatBal->People(peopleNum).ZonePtr) {
6077 0 : ++ObjectCount;
6078 0 : GetComfortSetPoints(state, peopleNum, RelativeZoneNum, zoneComfortControlsFanger.LowPMV, Tset);
6079 0 : SetPointLo += Tset;
6080 0 : if (s_hbfs->ComfortControlType(ActualZoneNum) == HVAC::SetptType::DualHeatCool) {
6081 0 : GetComfortSetPoints(state, peopleNum, RelativeZoneNum, zoneComfortControlsFanger.HighPMV, Tset);
6082 0 : SetPointHi += Tset;
6083 : }
6084 : }
6085 : }
6086 0 : SetPointLo /= ObjectCount;
6087 0 : if (s_hbfs->ComfortControlType(ActualZoneNum) == HVAC::SetptType::DualHeatCool) {
6088 0 : SetPointHi /= ObjectCount;
6089 : }
6090 : }
6091 0 : } break;
6092 :
6093 0 : default: {
6094 0 : } break;
6095 : } // switch
6096 :
6097 : // Assign setpoint
6098 2025 : switch (s_hbfs->ComfortControlType(ActualZoneNum)) {
6099 :
6100 1185 : case HVAC::SetptType::Uncontrolled: {
6101 1185 : switch (state.dataHeatBalFanSys->TempControlType(ActualZoneNum)) {
6102 594 : case HVAC::SetptType::SingleHeat:
6103 594 : zoneTstatSetpt.setptHi = 0.0;
6104 594 : break;
6105 591 : case HVAC::SetptType::SingleCool:
6106 591 : zoneTstatSetpt.setptLo = 0.0;
6107 591 : break;
6108 0 : default:
6109 0 : break;
6110 : }
6111 1185 : } break;
6112 :
6113 210 : case HVAC::SetptType::SingleHeat: {
6114 210 : if (SetPointLo < comfortZone.TdbMinSetPoint) {
6115 0 : SetPointLo = comfortZone.TdbMinSetPoint;
6116 0 : if (comfortZone.TdbMinErrIndex < 2) {
6117 0 : ShowWarningMessage(state,
6118 0 : format("ThermostatSetpoint:ThermalComfort:Fanger:SingleHeating temperature is below the Minimum dry-bulb "
6119 : "temperature setpoint {}",
6120 0 : comfortZone.Name));
6121 0 : ShowContinueError(state, "The zone heating setpoint is set to the Minimum dry-bulb temperature setpoint");
6122 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
6123 : }
6124 0 : ShowRecurringWarningErrorAtEnd(state,
6125 : "ThermostatSetpoint:ThermalComfort:Fanger:SingleHeating temperature is still below the "
6126 : "Minimum dry-bulb temperature setpoint ...",
6127 0 : comfortZone.TdbMinErrIndex,
6128 : SetPointLo,
6129 : SetPointLo);
6130 : }
6131 210 : zoneTstatSetpt.setpt = SetPointLo;
6132 210 : zoneTstatSetpt.setptLo = zoneTstatSetpt.setpt;
6133 210 : state.dataHeatBalFanSys->TempControlType(ActualZoneNum) = HVAC::SetptType::SingleHeat;
6134 210 : state.dataHeatBalFanSys->TempControlTypeRpt(ActualZoneNum) = static_cast<int>(state.dataHeatBalFanSys->TempControlType(ActualZoneNum));
6135 210 : } break;
6136 :
6137 210 : case HVAC::SetptType::SingleCool: {
6138 210 : if (SetPointLo > comfortZone.TdbMaxSetPoint) {
6139 0 : SetPointLo = comfortZone.TdbMaxSetPoint;
6140 0 : if (comfortZone.TdbMaxErrIndex == 0) {
6141 0 : ShowWarningMessage(state,
6142 0 : format("ThermostatSetpoint:ThermalComfort:Fanger:SingleCooling temperature is above the Maximum dry-bulb "
6143 : "temperature setpoint {}",
6144 0 : comfortZone.Name));
6145 0 : ShowContinueError(state, "The zone cooling setpoint is set to the Maximum dry-bulb temperature setpoint");
6146 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
6147 : }
6148 0 : ShowRecurringWarningErrorAtEnd(state,
6149 : "ThermostatSetpoint:ThermalComfort:Fanger:SingleCooling temperature is still above the "
6150 : "Maximum dry-bulb temperature setpoint ...",
6151 0 : comfortZone.TdbMaxErrIndex,
6152 : SetPointLo,
6153 : SetPointLo);
6154 : }
6155 210 : zoneTstatSetpt.setpt = SetPointLo;
6156 210 : zoneTstatSetpt.setptHi = zoneTstatSetpt.setpt;
6157 210 : state.dataHeatBalFanSys->TempControlType(ActualZoneNum) = HVAC::SetptType::SingleCool;
6158 210 : state.dataHeatBalFanSys->TempControlTypeRpt(ActualZoneNum) = static_cast<int>(state.dataHeatBalFanSys->TempControlType(ActualZoneNum));
6159 210 : } break;
6160 :
6161 210 : case HVAC::SetptType::SingleHeatCool: {
6162 210 : if (comfortZone.TdbMaxSetPoint == comfortZone.TdbMinSetPoint) {
6163 0 : SetPointLo = comfortZone.TdbMaxSetPoint;
6164 : }
6165 210 : if (SetPointLo > comfortZone.TdbMaxSetPoint) {
6166 0 : SetPointLo = comfortZone.TdbMaxSetPoint;
6167 : }
6168 210 : if (SetPointLo < comfortZone.TdbMinSetPoint) {
6169 0 : SetPointLo = comfortZone.TdbMinSetPoint;
6170 : }
6171 210 : if (SetPointLo < comfortZone.TdbMinSetPoint || SetPointLo > comfortZone.TdbMaxSetPoint) {
6172 0 : if (comfortZone.TdbHCErrIndex == 0) {
6173 0 : ShowWarningMessage(state,
6174 0 : format("ThermostatSetpoint:ThermalComfort:Fanger:SingleHeatingOrCooling temperature is above the Maximum or "
6175 : "below the Minimum dry-bulb temperature setpoint {}",
6176 0 : comfortZone.Name));
6177 0 : ShowContinueError(state,
6178 : "The zone setpoint is set to the Maximum dry-bulb temperature setpoint if above or the Minimum "
6179 : "dry-bulb temperature setpoint if below");
6180 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
6181 : }
6182 0 : ShowRecurringWarningErrorAtEnd(state,
6183 : "ThermostatSetpoint:ThermalComfort:Fanger:SingleHeatingOrCooling temperature is still beyond "
6184 : "the range between Maximum and Minimum dry-bulb temperature setpoint ...",
6185 0 : comfortZone.TdbHCErrIndex,
6186 : SetPointLo,
6187 : SetPointLo);
6188 : }
6189 :
6190 210 : zoneTstatSetpt.setpt = SetPointLo;
6191 210 : zoneTstatSetpt.setptHi = zoneTstatSetpt.setptLo = zoneTstatSetpt.setpt;
6192 210 : state.dataHeatBalFanSys->TempControlType(ActualZoneNum) = HVAC::SetptType::SingleHeatCool;
6193 210 : state.dataHeatBalFanSys->TempControlTypeRpt(ActualZoneNum) = static_cast<int>(state.dataHeatBalFanSys->TempControlType(ActualZoneNum));
6194 210 : } break;
6195 :
6196 210 : case HVAC::SetptType::DualHeatCool: {
6197 210 : if (SetPointLo < comfortZone.TdbMinSetPoint) {
6198 0 : SetPointLo = comfortZone.TdbMinSetPoint;
6199 :
6200 0 : if (comfortZone.TdbDualMinErrIndex == 0) {
6201 0 : ShowWarningMessage(state,
6202 0 : format("ThermostatSetpoint:ThermalComfort:Fanger:DualSetpoint temperature is below the Minimum dry-bulb "
6203 : "temperature setpoint {}",
6204 0 : comfortZone.Name));
6205 0 : ShowContinueError(state, "The zone dual heating setpoint is set to the Minimum dry-bulb temperature setpoint");
6206 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
6207 : }
6208 0 : ShowRecurringWarningErrorAtEnd(state,
6209 : "ThermostatSetpoint:ThermalComfort:Fanger:DualSetpoint temperature is still below the Minimum "
6210 : "dry-bulb temperature setpoint ...",
6211 0 : comfortZone.TdbDualMinErrIndex,
6212 : SetPointLo,
6213 : SetPointLo);
6214 : }
6215 210 : if (SetPointHi > comfortZone.TdbMaxSetPoint) {
6216 0 : SetPointHi = comfortZone.TdbMaxSetPoint;
6217 0 : if (comfortZone.TdbDualMaxErrIndex == 0) {
6218 0 : ShowWarningMessage(state,
6219 0 : format("ThermostatSetpoint:ThermalComfort:Fanger:DualSetpoint temperature is above the Maximum dry-bulb "
6220 : "temperature setpoint in zone = {}",
6221 0 : comfortZone.Name));
6222 0 : ShowContinueError(state, "The zone dual cooling setpoint is set to the Maximum dry-bulb temperature setpoint");
6223 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
6224 : }
6225 0 : ShowRecurringWarningErrorAtEnd(state,
6226 : "ThermostatSetpoint:ThermalComfort:Fanger:DualSetpoint temperature is still above the Maximum "
6227 : "dry-bulb temperature setpoint ...",
6228 0 : comfortZone.TdbDualMaxErrIndex,
6229 : SetPointLo,
6230 : SetPointLo);
6231 : }
6232 :
6233 210 : zoneTstatSetpt.setptLo = SetPointLo;
6234 210 : zoneTstatSetpt.setptHi = SetPointHi;
6235 210 : state.dataHeatBalFanSys->TempControlType(ActualZoneNum) = HVAC::SetptType::DualHeatCool;
6236 210 : state.dataHeatBalFanSys->TempControlTypeRpt(ActualZoneNum) = static_cast<int>(state.dataHeatBalFanSys->TempControlType(ActualZoneNum));
6237 210 : } break;
6238 :
6239 0 : default: {
6240 0 : ShowSevereError(state,
6241 0 : format("CalcZoneAirComfortSetpoints: Illegal thermal control control type for Zone={}, Found value={}, in Schedule={}",
6242 0 : zone.Name,
6243 0 : s_hbfs->ComfortControlTypeRpt(ActualZoneNum),
6244 0 : comfortZone.setptTypeSched->Name));
6245 0 : } break;
6246 : } // switch ()
6247 : }
6248 2025 : } // CalcZoneAirComfortSetpoints()
6249 :
6250 2235 : void GetComfortSetPoints(EnergyPlusData &state,
6251 : int const PeopleNum,
6252 : int const ComfortControlNum,
6253 : Real64 const PMVSet,
6254 : Real64 &Tset // drybulb setpoint temperature for a given PMV value
6255 : )
6256 : {
6257 :
6258 : // SUBROUTINE INFORMATION:
6259 : // AUTHOR Lixing Gu
6260 : // DATE WRITTEN May, 2006
6261 : // PURPOSE OF THIS SUBROUTINE:
6262 : // This routine sets what the thermal comfort setpoints for each controlled zone should be based on air temperature
6263 : // obtained from thermal comfort models. This is called each time step.
6264 :
6265 : // SUBROUTINE ARGUMENT DEFINITIONS:
6266 : // 0 = Solution; 1 = Set to Min; 2 Set to Max
6267 :
6268 : // SUBROUTINE PARAMETER DEFINITIONS:
6269 2235 : Real64 constexpr Acc(0.001); // accuracy control for SolveRoot
6270 2235 : int constexpr MaxIter(500); // iteration control for SolveRoot
6271 :
6272 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6273 2235 : Real64 PMVResult = 0.0; // Calculated PMV value
6274 :
6275 2235 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
6276 :
6277 2235 : auto &comfortControlledZone = state.dataZoneCtrls->ComfortControlledZone(ComfortControlNum);
6278 2235 : Real64 Tmin = comfortControlledZone.TdbMinSetPoint;
6279 2235 : Real64 Tmax = comfortControlledZone.TdbMaxSetPoint;
6280 :
6281 2235 : ThermalComfort::CalcThermalComfortFanger(state, PeopleNum, Tmin, PMVResult);
6282 2235 : Real64 PMVMin = PMVResult;
6283 2235 : ThermalComfort::CalcThermalComfortFanger(state, PeopleNum, Tmax, PMVResult);
6284 2235 : Real64 PMVMax = PMVResult;
6285 2235 : if (PMVSet > PMVMin && PMVSet < PMVMax) {
6286 :
6287 5281 : auto f = [&state, PMVSet, PeopleNum](Real64 Tset) {
6288 5281 : Real64 PMVresult = 0.0; // resulting PMV values
6289 5281 : ThermalComfort::CalcThermalComfortFanger(state, PeopleNum, Tset, PMVresult);
6290 5281 : return (PMVSet - PMVresult);
6291 1050 : };
6292 :
6293 1050 : int SolFla = 0; // feed back flag from SolveRoot
6294 1050 : General::SolveRoot(state, Acc, MaxIter, SolFla, Tset, f, Tmin, Tmax);
6295 1050 : if (SolFla == -1) {
6296 0 : if (!state.dataGlobal->WarmupFlag) {
6297 0 : ++s_ztpc->IterLimitExceededNum1;
6298 0 : if (s_ztpc->IterLimitExceededNum1 == 1) {
6299 0 : ShowWarningError(
6300 : state,
6301 0 : format("{}: Iteration limit exceeded calculating thermal comfort Fanger setpoint and non-converged setpoint is used",
6302 0 : comfortControlledZone.Name));
6303 : } else {
6304 0 : ShowRecurringWarningErrorAtEnd(state,
6305 0 : comfortControlledZone.Name + ": Iteration limit exceeded calculating thermal comfort setpoint.",
6306 0 : s_ztpc->IterLimitErrIndex1,
6307 : Tset,
6308 : Tset);
6309 : }
6310 : }
6311 1050 : } else if (SolFla == -2) {
6312 0 : if (!state.dataGlobal->WarmupFlag) {
6313 0 : ++s_ztpc->IterLimitExceededNum2;
6314 0 : if (s_ztpc->IterLimitExceededNum2 == 1) {
6315 0 : ShowWarningError(
6316 : state,
6317 0 : format("{}: Solution is not found in calculating thermal comfort Fanger setpoint and the minimum setpoint is used",
6318 0 : comfortControlledZone.Name));
6319 : } else {
6320 0 : ShowRecurringWarningErrorAtEnd(
6321 : state,
6322 0 : format("{}: Solution is not found in calculating thermal comfort Fanger setpoint.", comfortControlledZone.Name),
6323 0 : s_ztpc->IterLimitErrIndex2,
6324 : Tset,
6325 : Tset);
6326 : }
6327 : }
6328 : }
6329 2235 : } else if (PMVSet < PMVMin) {
6330 1185 : Tset = Tmin;
6331 0 : } else if (PMVSet > PMVMax) {
6332 0 : Tset = Tmax;
6333 : }
6334 2235 : }
6335 :
6336 15569599 : void AdjustCoolingSetPointforTempAndHumidityControl(EnergyPlusData &state,
6337 : int const TempControlledZoneID,
6338 : int const ActualZoneNum // controlled zone actual zone number
6339 : )
6340 : {
6341 : // SUBROUTINE INFORMATION:
6342 : // AUTHOR Bereket A Nigusse, FSEC/UCF
6343 : // DATE WRITTEN Nov 2010
6344 :
6345 : // PURPOSE OF THIS SUBROUTINE:
6346 : // This subroutine modifies the air cooling setpoint temperature to effect zone air Temperature and humidity control
6347 : // Alter the zone air cooling setpoint if the zone air relative humidity value exceeds the the zone dehumidifying relative humidity setpoint.
6348 :
6349 15569599 : auto const &s_ztpc = state.dataZoneTempPredictorCorrector;
6350 15569599 : auto &tempZone = state.dataZoneCtrls->TempControlledZone(TempControlledZoneID);
6351 15569599 : auto &zoneTstatSetpt = state.dataHeatBalFanSys->zoneTstatSetpts(ActualZoneNum);
6352 :
6353 15569599 : if (!state.dataZoneCtrls->AnyZoneTempAndHumidityControl) {
6354 15562960 : return; // do nothing to setpoint
6355 : }
6356 6639 : if (tempZone.OvercoolCtrl == DataZoneControls::TempCtrl::None) {
6357 0 : return; // do nothing to setpoint
6358 : }
6359 :
6360 6639 : Real64 ZoneOvercoolRange = (tempZone.OvercoolCtrl == DataZoneControls::TempCtrl::Scheduled) ? tempZone.zoneOvercoolRangeSched->getCurrentVal()
6361 6639 : : tempZone.ZoneOvercoolConstRange;
6362 :
6363 6639 : Real64 ZoneOvercoolControlRatio = tempZone.ZoneOvercoolControlRatio;
6364 :
6365 : // For Dual Setpoint thermostat the overcool range is limited by the temperature difference between cooling and heating setpoints
6366 6639 : Real64 MaxAllowedOvercoolRange = zoneTstatSetpt.setptHi - zoneTstatSetpt.setptLo;
6367 6639 : if (MaxAllowedOvercoolRange > 0.0) {
6368 6639 : ZoneOvercoolRange = min(ZoneOvercoolRange, MaxAllowedOvercoolRange);
6369 : }
6370 : // Calculate difference between zone air relative humidity and the dehumidifying setpoint
6371 6639 : Real64 RelativeHumidityDiff = s_ztpc->zoneHeatBalance(ActualZoneNum).airRelHum - tempZone.dehumidifyingSched->getCurrentVal();
6372 6639 : if (RelativeHumidityDiff > 0.0 && ZoneOvercoolControlRatio > 0.0) {
6373 : // proportionally reset the cooling setpoint temperature downward (zone Overcool)
6374 4906 : ZoneOvercoolRange = min(ZoneOvercoolRange, RelativeHumidityDiff / ZoneOvercoolControlRatio);
6375 4906 : zoneTstatSetpt.setptHi -= ZoneOvercoolRange;
6376 : }
6377 : }
6378 :
6379 2828450 : void OverrideAirSetPointsforEMSCntrl(EnergyPlusData &state)
6380 : {
6381 :
6382 : // SUBROUTINE INFORMATION:
6383 : // AUTHOR L. Gu
6384 : // DATE WRITTEN June 2017
6385 :
6386 : // PURPOSE OF THIS SUBROUTINE:
6387 : // This subroutine overrides the air temperature setpoint based on EMS
6388 2828450 : auto const &s_hbfs = state.dataHeatBalFanSys;
6389 :
6390 20391270 : for (int Loop = 1; Loop <= state.dataZoneCtrls->NumTempControlledZones; ++Loop) {
6391 17562820 : auto const &tempZone = state.dataZoneCtrls->TempControlledZone(Loop);
6392 17562820 : if (tempZone.EMSOverrideHeatingSetPointOn) {
6393 0 : int ZoneNum = tempZone.ActualZoneNum;
6394 0 : auto &zoneTstatSetpt = s_hbfs->zoneTstatSetpts(ZoneNum);
6395 :
6396 0 : switch (state.dataHeatBalFanSys->TempControlType(ZoneNum)) {
6397 0 : case HVAC::SetptType::SingleHeat:
6398 : case HVAC::SetptType::SingleHeatCool: {
6399 0 : zoneTstatSetpt.setptLo = zoneTstatSetpt.setpt = tempZone.EMSOverrideHeatingSetPointValue;
6400 0 : } break;
6401 :
6402 0 : case HVAC::SetptType::DualHeatCool: {
6403 0 : zoneTstatSetpt.setptLo = tempZone.EMSOverrideHeatingSetPointValue;
6404 0 : } break;
6405 :
6406 0 : default: {
6407 0 : } break;
6408 : } // switch ()
6409 : }
6410 :
6411 17562820 : if (tempZone.EMSOverrideCoolingSetPointOn) {
6412 0 : int ZoneNum = tempZone.ActualZoneNum;
6413 0 : auto &zoneTstatSetpt = s_hbfs->zoneTstatSetpts(ZoneNum);
6414 :
6415 0 : switch (s_hbfs->TempControlType(ZoneNum)) {
6416 0 : case HVAC::SetptType::SingleCool:
6417 : case HVAC::SetptType::SingleHeatCool: {
6418 0 : zoneTstatSetpt.setptHi = zoneTstatSetpt.setpt = tempZone.EMSOverrideCoolingSetPointValue;
6419 0 : } break;
6420 :
6421 0 : case HVAC::SetptType::DualHeatCool: {
6422 0 : zoneTstatSetpt.setptHi = tempZone.EMSOverrideCoolingSetPointValue;
6423 0 : } break;
6424 :
6425 0 : default: {
6426 0 : } break;
6427 : } // switch ()
6428 : }
6429 : }
6430 :
6431 2830475 : for (int Loop = 1; Loop <= state.dataZoneCtrls->NumComfortControlledZones; ++Loop) {
6432 2025 : auto &comfortZone = state.dataZoneCtrls->ComfortControlledZone(Loop);
6433 2025 : if (comfortZone.EMSOverrideHeatingSetPointOn) {
6434 0 : int ZoneNum = comfortZone.ActualZoneNum;
6435 0 : auto &zoneTstatSetpt = s_hbfs->zoneTstatSetpts(ZoneNum);
6436 :
6437 0 : switch (s_hbfs->ComfortControlType(ZoneNum)) {
6438 0 : case HVAC::SetptType::SingleHeat:
6439 : case HVAC::SetptType::SingleHeatCool: {
6440 0 : zoneTstatSetpt.setptLo = zoneTstatSetpt.setpt = comfortZone.EMSOverrideHeatingSetPointValue;
6441 0 : } break;
6442 :
6443 0 : case HVAC::SetptType::DualHeatCool: {
6444 0 : zoneTstatSetpt.setptLo = comfortZone.EMSOverrideHeatingSetPointValue;
6445 0 : } break;
6446 :
6447 0 : default: {
6448 0 : } break;
6449 :
6450 : } // switch ()
6451 : }
6452 :
6453 2025 : if (comfortZone.EMSOverrideCoolingSetPointOn) {
6454 :
6455 0 : int ZoneNum = comfortZone.ActualZoneNum;
6456 0 : auto &zoneTstatSetpt = s_hbfs->zoneTstatSetpts(ZoneNum);
6457 :
6458 0 : switch (static_cast<HVAC::SetptType>(s_hbfs->ComfortControlType(ZoneNum))) {
6459 0 : case HVAC::SetptType::SingleCool:
6460 : case HVAC::SetptType::SingleHeatCool: {
6461 0 : zoneTstatSetpt.setptHi = zoneTstatSetpt.setpt = comfortZone.EMSOverrideCoolingSetPointValue;
6462 0 : } break;
6463 :
6464 0 : case HVAC::SetptType::DualHeatCool: {
6465 0 : zoneTstatSetpt.setptHi = comfortZone.EMSOverrideCoolingSetPointValue;
6466 0 : } break;
6467 :
6468 0 : default: {
6469 0 : } break;
6470 :
6471 : } // switch ()
6472 : }
6473 : }
6474 2828450 : }
6475 :
6476 : // add values to the LEED tabular report related to schedules used by the thermostat objects
6477 799 : void FillPredefinedTableOnThermostatSetpoints(EnergyPlusData &state)
6478 : {
6479 : // J.Glazer - Aug 2017
6480 : using namespace OutputReportPredefined;
6481 799 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
6482 :
6483 799 : std::vector<int> uniqSch;
6484 799 : uniqSch.reserve(s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeat] + s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleCool] +
6485 799 : s_ztpc->NumTempControls[(int)HVAC::SetptType::SingleHeatCool] + s_ztpc->NumTempControls[(int)HVAC::SetptType::DualHeatCool] * 2);
6486 :
6487 : Real64 setPointAt11;
6488 : Real64 setPointAt23;
6489 : int numDays;
6490 799 : std::string monthAssumed;
6491 799 : std::string monthAssumed2;
6492 :
6493 1253 : for (auto &setpt : s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleHeat]) {
6494 454 : if (std::find(uniqSch.begin(), uniqSch.end(), setpt.heatSched->Num) != uniqSch.end()) {
6495 9 : continue;
6496 : }
6497 :
6498 445 : uniqSch.emplace_back(setpt.heatSched->Num);
6499 445 : PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtFirstObjUsed, setpt.heatSched->Name, setpt.Name);
6500 :
6501 445 : std::tie(setPointAt11, numDays, monthAssumed) = setpt.heatSched->getValAndCountOnDay(state, false, Sched::DayType::Wednesday, 11);
6502 445 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWednesday, setpt.heatSched->Name, setPointAt11);
6503 445 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWedCnt, setpt.heatSched->Name, numDays);
6504 :
6505 445 : std::tie(setPointAt23, numDays, monthAssumed) = setpt.heatSched->getValAndCountOnDay(state, false, Sched::DayType::Wednesday, 23);
6506 445 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWednesday, setpt.heatSched->Name, setPointAt23);
6507 445 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWedCnt, setpt.heatSched->Name, numDays);
6508 :
6509 445 : PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtMonthUsed, setpt.heatSched->Name, monthAssumed);
6510 : }
6511 :
6512 1247 : for (auto &setpt : s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleCool]) {
6513 448 : if (std::find(uniqSch.begin(), uniqSch.end(), setpt.coolSched->Num) != uniqSch.end()) {
6514 14 : continue;
6515 : }
6516 :
6517 434 : uniqSch.emplace_back(setpt.coolSched->Num);
6518 434 : PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtFirstObjUsed, setpt.coolSched->Name, setpt.Name);
6519 :
6520 434 : std::tie(setPointAt11, numDays, monthAssumed) = setpt.coolSched->getValAndCountOnDay(state, true, Sched::DayType::Wednesday, 11);
6521 434 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWednesday, setpt.coolSched->Name, setPointAt11);
6522 434 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWedCnt, setpt.coolSched->Name, numDays);
6523 :
6524 434 : std::tie(setPointAt23, numDays, monthAssumed) = setpt.coolSched->getValAndCountOnDay(state, true, Sched::DayType::Wednesday, 23);
6525 434 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWednesday, setpt.coolSched->Name, setPointAt23);
6526 434 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWedCnt, setpt.coolSched->Name, numDays);
6527 :
6528 434 : PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtMonthUsed, setpt.coolSched->Name, monthAssumed);
6529 : }
6530 :
6531 810 : for (auto &setpt : s_ztpc->tempSetptScheds[(int)HVAC::SetptType::SingleHeatCool]) {
6532 11 : if (std::find(uniqSch.begin(), uniqSch.end(), setpt.heatSched->Num) != uniqSch.end()) {
6533 0 : continue;
6534 : }
6535 :
6536 11 : uniqSch.emplace_back(setpt.heatSched->Num);
6537 11 : PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtFirstObjUsed, setpt.heatSched->Name, setpt.Name);
6538 :
6539 11 : std::string schNm = setpt.heatSched->Name + " (summer)";
6540 11 : std::tie(setPointAt11, numDays, monthAssumed) = setpt.heatSched->getValAndCountOnDay(state, true, Sched::DayType::Wednesday, 11);
6541 11 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWednesday, schNm, setPointAt11);
6542 11 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWedCnt, schNm, numDays);
6543 :
6544 11 : std::tie(setPointAt23, numDays, monthAssumed) = setpt.heatSched->getValAndCountOnDay(state, true, Sched::DayType::Wednesday, 23);
6545 11 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWednesday, schNm, setPointAt23);
6546 11 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWedCnt, schNm, numDays);
6547 :
6548 11 : schNm = setpt.heatSched->Name + " (winter)";
6549 11 : std::tie(setPointAt11, numDays, monthAssumed2) = setpt.heatSched->getValAndCountOnDay(state, false, Sched::DayType::Wednesday, 11);
6550 11 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWednesday, schNm, setPointAt11);
6551 11 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWedCnt, schNm, numDays);
6552 :
6553 11 : std::tie(setPointAt23, numDays, monthAssumed2) = setpt.heatSched->getValAndCountOnDay(state, false, Sched::DayType::Wednesday, 23);
6554 11 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWednesday, schNm, setPointAt23);
6555 11 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWedCnt, schNm, numDays);
6556 :
6557 11 : PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtMonthUsed, setpt.heatSched->Name, monthAssumed + " and " + monthAssumed2);
6558 11 : }
6559 :
6560 3390 : for (auto &setpt : s_ztpc->tempSetptScheds[(int)HVAC::SetptType::DualHeatCool]) {
6561 2591 : if (std::find(uniqSch.begin(), uniqSch.end(), setpt.heatSched->Num) == uniqSch.end()) {
6562 491 : uniqSch.emplace_back(setpt.heatSched->Num);
6563 491 : PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtFirstObjUsed, setpt.heatSched->Name, setpt.Name);
6564 :
6565 491 : std::tie(setPointAt11, numDays, monthAssumed) = setpt.heatSched->getValAndCountOnDay(state, false, Sched::DayType::Wednesday, 11);
6566 491 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWednesday, setpt.heatSched->Name, setPointAt11);
6567 491 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWedCnt, setpt.heatSched->Name, numDays);
6568 :
6569 491 : std::tie(setPointAt23, numDays, monthAssumed) = setpt.heatSched->getValAndCountOnDay(state, false, Sched::DayType::Wednesday, 23);
6570 491 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWednesday, setpt.heatSched->Name, setPointAt23);
6571 491 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWedCnt, setpt.heatSched->Name, numDays);
6572 :
6573 491 : PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtMonthUsed, setpt.heatSched->Name, monthAssumed);
6574 : }
6575 :
6576 2591 : if (std::find(uniqSch.begin(), uniqSch.end(), setpt.coolSched->Num) == uniqSch.end()) {
6577 485 : uniqSch.emplace_back(setpt.coolSched->Num);
6578 485 : PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtFirstObjUsed, setpt.coolSched->Name, setpt.Name);
6579 :
6580 485 : std::tie(setPointAt11, numDays, monthAssumed) = setpt.coolSched->getValAndCountOnDay(state, true, Sched::DayType::Wednesday, 11);
6581 485 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWednesday, setpt.coolSched->Name, setPointAt11);
6582 485 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11amWedCnt, setpt.coolSched->Name, numDays);
6583 :
6584 485 : std::tie(setPointAt23, numDays, monthAssumed) = setpt.coolSched->getValAndCountOnDay(state, true, Sched::DayType::Wednesday, 23);
6585 485 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWednesday, setpt.coolSched->Name, setPointAt23);
6586 485 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchLeedSchStPt11pmWedCnt, setpt.coolSched->Name, numDays);
6587 :
6588 485 : PreDefTableEntry(state, state.dataOutRptPredefined->pdChLeedSchStPtMonthUsed, setpt.coolSched->Name, monthAssumed);
6589 : }
6590 : }
6591 799 : }
6592 :
6593 799 : void FillPredefinedTableOnThermostatSchedules(EnergyPlusData &state)
6594 : {
6595 : // add values to the System Summary tabular report related to schedules used by the thermostat objects
6596 : // J.Glazer - March 2024
6597 : using OutputReportPredefined::PreDefTableEntry;
6598 799 : auto &orp = state.dataOutRptPredefined;
6599 :
6600 : // Helper struct so we can sort to ensure a consistent order.
6601 : // No matter the order in which the multiple Field Sets (Control Object Type, Control Name), the same thing is reported to the tabular outputs
6602 : // You don't actually need this anymore
6603 : struct ControlTypeInfo
6604 : {
6605 : // HVAC::ThermostatType tType = HVAC::ThermostatType::Invalid;
6606 : std::string thermostatType;
6607 : std::string controlTypeName;
6608 : std::string heatSchName;
6609 : std::string coolSchName;
6610 :
6611 : // Only need the operator<, and we use C++17 so I can't use a defaulted 3-way operator<=>
6612 53644 : bool operator<(const ControlTypeInfo &other) const
6613 : {
6614 53644 : return std::tie(this->thermostatType, this->controlTypeName, this->heatSchName, this->coolSchName) <
6615 107288 : std::tie(other.thermostatType, other.controlTypeName, other.heatSchName, other.coolSchName);
6616 : }
6617 : };
6618 : using ControlTypeInfoMemPtr = std::string ControlTypeInfo::*;
6619 :
6620 : // How many people on the EnergyPlus team understand this code?
6621 17292 : auto joinStrings = [](const std::vector<ControlTypeInfo> &infos, ControlTypeInfoMemPtr memPtr) -> std::string {
6622 17292 : std::vector<std::string> result;
6623 17292 : result.reserve(infos.size());
6624 128276 : for (const auto &info : infos) {
6625 110984 : std::string val = info.*memPtr;
6626 110984 : if (val.empty()) {
6627 88762 : continue;
6628 : }
6629 22222 : result.emplace_back(std::move(val));
6630 128276 : }
6631 51876 : return fmt::format("{}", fmt::join(result, ", "));
6632 17292 : };
6633 :
6634 5122 : for (int idx = 1; idx <= state.dataZoneCtrls->NumTempControlledZones; ++idx) {
6635 4323 : auto &tcz = state.dataZoneCtrls->TempControlledZone(idx);
6636 4323 : PreDefTableEntry(state, orp->pdchStatName, tcz.ZoneName, tcz.Name);
6637 4323 : PreDefTableEntry(state, orp->pdchStatCtrlTypeSchd, tcz.ZoneName, tcz.setptTypeSched->Name);
6638 :
6639 4323 : std::vector<ControlTypeInfo> infos;
6640 4323 : infos.resize((int)HVAC::SetptType::Num);
6641 21615 : for (HVAC::SetptType setptType : HVAC::controlledSetptTypes) {
6642 17292 : auto &setpt = tcz.setpts[(int)setptType];
6643 :
6644 17292 : auto &info = infos[(int)setptType];
6645 :
6646 17292 : if (setpt.Name.empty()) {
6647 11161 : continue;
6648 : }
6649 :
6650 6131 : info.thermostatType = HVAC::setptTypeNames[(int)setptType];
6651 6131 : info.controlTypeName = setpt.Name;
6652 6131 : switch (setptType) {
6653 3829 : case HVAC::SetptType::DualHeatCool:
6654 : case HVAC::SetptType::SingleHeatCool: {
6655 3829 : info.coolSchName = setpt.coolSetptSched->Name;
6656 3829 : info.heatSchName = setpt.heatSetptSched->Name;
6657 3829 : } break;
6658 :
6659 1144 : case HVAC::SetptType::SingleCool: {
6660 1144 : info.coolSchName = setpt.coolSetptSched->Name;
6661 1144 : } break;
6662 :
6663 1158 : case HVAC::SetptType::SingleHeat: {
6664 1158 : info.heatSchName = setpt.heatSetptSched->Name;
6665 1158 : } break;
6666 : }
6667 6131 : infos.emplace_back(std::move(info));
6668 : }
6669 4323 : std::sort(infos.begin(), infos.end());
6670 :
6671 4323 : PreDefTableEntry(state, orp->pdchStatSchdType1, tcz.ZoneName, joinStrings(infos, &ControlTypeInfo::thermostatType));
6672 4323 : PreDefTableEntry(state, orp->pdchStatSchdTypeName1, tcz.ZoneName, joinStrings(infos, &ControlTypeInfo::controlTypeName));
6673 4323 : if (auto heatSchNames = joinStrings(infos, &ControlTypeInfo::heatSchName); !heatSchNames.empty()) {
6674 4320 : PreDefTableEntry(state, orp->pdchStatSchdHeatName, tcz.ZoneName, heatSchNames);
6675 4323 : }
6676 4323 : if (auto coolSchNames = joinStrings(infos, &ControlTypeInfo::coolSchName); !coolSchNames.empty()) {
6677 4306 : PreDefTableEntry(state, orp->pdchStatSchdCoolName, tcz.ZoneName, coolSchNames);
6678 4323 : }
6679 4323 : }
6680 799 : }
6681 :
6682 31432634 : void ZoneSpaceHeatBalanceData::updateTemperatures(EnergyPlusData &state,
6683 : bool const ShortenTimeStepSys,
6684 : bool const UseZoneTimeStepHistory,
6685 : Real64 const PriorTimeStep,
6686 : int const zoneNum,
6687 : int const spaceNum)
6688 : {
6689 31432634 : assert(zoneNum > 0);
6690 31432634 : if (ShortenTimeStepSys) {
6691 : // timestep has just shifted from full zone timestep to a new shorter system timestep
6692 : // throw away last updates in corrector and rewind for resimulating smaller timestep
6693 3173070 : if (spaceNum == 0) {
6694 3164644 : if (state.dataHeatBal->Zone(zoneNum).SystemZoneNodeNumber > 0) { // roll back result for zone air node,
6695 2799459 : auto &zoneNode = state.dataLoopNodes->Node(state.dataHeatBal->Zone(zoneNum).SystemZoneNodeNumber);
6696 2799459 : zoneNode.Temp = this->XMAT[0];
6697 2799459 : state.dataHeatBalFanSys->TempTstatAir(zoneNum) = this->XMAT[0];
6698 2799459 : zoneNode.HumRat = this->WPrevZoneTS[0];
6699 2799459 : zoneNode.Enthalpy = Psychrometrics::PsyHFnTdbW(this->XMAT[0], this->WPrevZoneTS[0]);
6700 : }
6701 : } else {
6702 8426 : if (state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber > 0) { // roll back result for space air node,
6703 7776 : auto &spaceNode = state.dataLoopNodes->Node(state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber);
6704 7776 : spaceNode.Temp = this->XMAT[0];
6705 7776 : state.dataHeatBalFanSys->TempTstatAir(zoneNum) = this->XMAT[0];
6706 7776 : spaceNode.HumRat = this->WPrevZoneTS[0];
6707 7776 : spaceNode.Enthalpy = Psychrometrics::PsyHFnTdbW(this->XMAT[0], this->WPrevZoneTS[0]);
6708 : }
6709 : }
6710 :
6711 3173070 : if (state.dataHVACGlobal->NumOfSysTimeSteps !=
6712 3173070 : state.dataHVACGlobal->NumOfSysTimeStepsLastZoneTimeStep) { // cannot reuse existing DS data, interpolate from zone time
6713 1436337 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
6714 1436337 : this->MAT = DownInterpolate4HistoryValues(PriorTimeStep, TimeStepSys, this->XMAT, this->DSXMAT);
6715 1436337 : this->airHumRat = DownInterpolate4HistoryValues(PriorTimeStep, TimeStepSys, this->WPrevZoneTS, this->DSWPrevZoneTS);
6716 :
6717 1436337 : if (spaceNum == 0 && state.dataRoomAir->anyNonMixingRoomAirModel) {
6718 9127 : if (state.dataRoomAir->IsZoneDispVent3Node(zoneNum) || state.dataRoomAir->IsZoneUFAD(zoneNum)) {
6719 :
6720 2788 : state.dataRoomAir->MATFloor(zoneNum) = DownInterpolate4HistoryValues(
6721 2788 : PriorTimeStep, TimeStepSys, state.dataRoomAir->XMATFloor(zoneNum), state.dataRoomAir->DSXMATFloor(zoneNum));
6722 2788 : state.dataRoomAir->MATOC(zoneNum) = DownInterpolate4HistoryValues(
6723 2788 : PriorTimeStep, TimeStepSys, state.dataRoomAir->XMATOC(zoneNum), state.dataRoomAir->DSXMATOC(zoneNum));
6724 2788 : state.dataRoomAir->MATMX(zoneNum) = DownInterpolate4HistoryValues(
6725 2788 : PriorTimeStep, TimeStepSys, state.dataRoomAir->XMATMX(zoneNum), state.dataRoomAir->DSXMATMX(zoneNum));
6726 : }
6727 9127 : if (state.dataRoomAir->AirModel(zoneNum).AirModel == RoomAir::RoomAirModel::AirflowNetwork) {
6728 2219 : for (auto &afnNode : state.dataRoomAir->AFNZoneInfo(zoneNum).Node) {
6729 1902 : afnNode.AirTemp = DownInterpolate4HistoryValues(PriorTimeStep, TimeStepSys, afnNode.AirTempX, afnNode.AirTempDSX);
6730 :
6731 1902 : afnNode.HumRat = DownInterpolate4HistoryValues(PriorTimeStep, TimeStepSys, afnNode.HumRatX, afnNode.HumRatDSX);
6732 : }
6733 : }
6734 : }
6735 : } else { // reuse history data in DS terms from last zone time step to preserve information that would be lost
6736 : // do nothing because DS history would have been pushed prior and should be ready
6737 : }
6738 : }
6739 : // now update the variables actually used in the balance equations.
6740 31432634 : if (UseZoneTimeStepHistory) {
6741 20600445 : this->ZTM = this->XMAT;
6742 20600445 : this->WPrevZoneTSTemp = this->WPrevZoneTS;
6743 : } else { // use down-stepped history
6744 10832189 : this->ZTM = this->DSXMAT;
6745 10832189 : this->WPrevZoneTSTemp = this->DSWPrevZoneTS;
6746 : }
6747 31432634 : }
6748 :
6749 31432634 : void ZoneSpaceHeatBalanceData::calcPredictedSystemLoad(EnergyPlusData &state, Real64 const RAFNFrac, int const zoneNum, int const spaceNum)
6750 : {
6751 : // Calculate the predicted system load for a time step.
6752 :
6753 31432634 : assert(zoneNum > 0);
6754 31432634 : auto const &thisZone = state.dataHeatBal->Zone(zoneNum);
6755 31432634 : auto const &zoneTstatSetpt = state.dataHeatBalFanSys->zoneTstatSetpts(zoneNum);
6756 :
6757 31432634 : bool thisDeadBandOrSetBack = false;
6758 31432634 : Real64 ZoneSetPoint = 0.0;
6759 31432634 : Real64 totalLoad = 0.0;
6760 31432634 : Real64 LoadToHeatingSetPoint = 0.0;
6761 31432634 : Real64 LoadToCoolingSetPoint = 0.0;
6762 :
6763 31432634 : auto &s_ztpc = state.dataZoneTempPredictorCorrector;
6764 :
6765 31432634 : int zoneNodeNum = thisZone.SystemZoneNodeNumber;
6766 31432634 : if (spaceNum > 0) {
6767 86394 : zoneNodeNum = state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber;
6768 : }
6769 :
6770 31432634 : switch (state.dataHeatBalFanSys->TempControlType(zoneNum)) {
6771 4727336 : case HVAC::SetptType::Uncontrolled: {
6772 : // Uncontrolled Zone
6773 4727336 : LoadToHeatingSetPoint = 0.0;
6774 4727336 : LoadToCoolingSetPoint = 0.0;
6775 4727336 : totalLoad = 0.0;
6776 4727336 : } break;
6777 :
6778 2284514 : case HVAC::SetptType::SingleHeat: {
6779 2284514 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
6780 2284514 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
6781 2284514 : LoadToHeatingSetPoint = (this->tempDepLoad * zoneTstatSetpt.setpt - this->tempIndLoad);
6782 2284514 : break;
6783 : }
6784 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
6785 0 : if (this->tempDepLoad == 0.0) { // B=0
6786 0 : LoadToHeatingSetPoint = this->AirPowerCap * (zoneTstatSetpt.setpt - this->T1) - this->tempIndLoad;
6787 : } else {
6788 0 : Real64 const exp_700_TA(std::exp(min(700.0, -this->tempDepLoad / this->AirPowerCap)));
6789 0 : LoadToHeatingSetPoint = this->tempDepLoad * (zoneTstatSetpt.setpt - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
6790 : }
6791 0 : } break;
6792 :
6793 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
6794 0 : LoadToHeatingSetPoint =
6795 0 : this->AirPowerCap * (zoneTstatSetpt.setpt - this->T1) + this->tempDepLoad * (zoneTstatSetpt.setpt) - this->tempIndLoad;
6796 0 : } break;
6797 :
6798 0 : default: {
6799 0 : assert(false);
6800 : } break;
6801 : } // switch (Algo)
6802 :
6803 2284514 : if (RAFNFrac > 0.0) {
6804 0 : LoadToHeatingSetPoint = LoadToHeatingSetPoint / RAFNFrac;
6805 : }
6806 2284514 : totalLoad = LoadToHeatingSetPoint;
6807 2284514 : ZoneSetPoint = zoneTstatSetpt.setpt;
6808 2284514 : LoadToCoolingSetPoint = LoadToHeatingSetPoint;
6809 : // for consistency with the other cases, use LE instead of LT and don't subtract 1.0 Watt as a way of pushing the zero load
6810 : // case over the threshold
6811 2284514 : if ((totalLoad) <= 0.0) {
6812 375098 : thisDeadBandOrSetBack = true;
6813 : }
6814 2284514 : } break;
6815 :
6816 2742642 : case HVAC::SetptType::SingleCool: {
6817 2742642 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
6818 2742642 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
6819 2742642 : LoadToCoolingSetPoint = this->tempDepLoad * zoneTstatSetpt.setpt - this->tempIndLoad;
6820 2742642 : } break;
6821 :
6822 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
6823 0 : if (this->tempDepLoad == 0.0) { // B=0
6824 0 : LoadToCoolingSetPoint = this->AirPowerCap * (zoneTstatSetpt.setpt - this->T1) - this->tempIndLoad;
6825 : } else {
6826 0 : Real64 const exp_700_TA(std::exp(min(700.0, -this->tempDepLoad / this->AirPowerCap)));
6827 0 : LoadToCoolingSetPoint = this->tempDepLoad * (zoneTstatSetpt.setpt - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
6828 : }
6829 0 : } break;
6830 :
6831 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
6832 0 : LoadToCoolingSetPoint =
6833 0 : this->AirPowerCap * (zoneTstatSetpt.setpt - this->T1) + this->tempDepLoad * zoneTstatSetpt.setpt - this->tempIndLoad;
6834 0 : } break;
6835 0 : default: {
6836 0 : assert(false);
6837 : } break;
6838 : } // swtich (Algo)
6839 :
6840 2742642 : if (RAFNFrac > 0.0) {
6841 0 : LoadToHeatingSetPoint = LoadToHeatingSetPoint / RAFNFrac;
6842 : }
6843 2742642 : if (thisZone.HasAdjustedReturnTempByITE && !(state.dataGlobal->BeginSimFlag)) {
6844 0 : LoadToCoolingSetPoint = this->tempDepLoad * thisZone.AdjustedReturnTempByITE - this->tempIndLoad;
6845 : }
6846 2742642 : totalLoad = LoadToCoolingSetPoint;
6847 2742642 : ZoneSetPoint = zoneTstatSetpt.setpt;
6848 2742642 : LoadToHeatingSetPoint = LoadToCoolingSetPoint;
6849 : // for consistency with the other cases, use GE instead of GT and don't add 1.0 Watt as a way of pushing the zero load
6850 : // case over the threshold
6851 2742642 : if ((totalLoad) >= 0.0) {
6852 1147384 : thisDeadBandOrSetBack = true;
6853 : }
6854 2742642 : } break;
6855 :
6856 94330 : case HVAC::SetptType::SingleHeatCool: {
6857 94330 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
6858 94330 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
6859 94330 : LoadToHeatingSetPoint = (this->tempDepLoad * (zoneTstatSetpt.setpt) - this->tempIndLoad);
6860 94330 : LoadToCoolingSetPoint = (this->tempDepLoad * (zoneTstatSetpt.setpt) - this->tempIndLoad);
6861 94330 : } break;
6862 :
6863 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
6864 0 : if (this->tempDepLoad == 0.0) { // B=0
6865 0 : LoadToHeatingSetPoint = this->AirPowerCap * (zoneTstatSetpt.setpt - this->T1) - this->tempIndLoad;
6866 0 : LoadToCoolingSetPoint = this->AirPowerCap * (zoneTstatSetpt.setpt - this->T1) - this->tempIndLoad;
6867 : } else {
6868 0 : Real64 const exp_700_TA(std::exp(min(700.0, -this->tempDepLoad / this->AirPowerCap)));
6869 0 : LoadToHeatingSetPoint = this->tempDepLoad * (zoneTstatSetpt.setpt - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
6870 0 : LoadToCoolingSetPoint = this->tempDepLoad * (zoneTstatSetpt.setpt - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
6871 : }
6872 0 : } break;
6873 :
6874 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
6875 0 : LoadToHeatingSetPoint =
6876 0 : this->AirPowerCap * (zoneTstatSetpt.setpt - this->T1) + this->tempDepLoad * zoneTstatSetpt.setpt - this->tempIndLoad;
6877 0 : LoadToCoolingSetPoint =
6878 0 : this->AirPowerCap * (zoneTstatSetpt.setpt - this->T1) + this->tempDepLoad * zoneTstatSetpt.setpt - this->tempIndLoad;
6879 0 : } break;
6880 0 : default: {
6881 0 : assert(false);
6882 : } break;
6883 : } // swtich (Algo)
6884 :
6885 94330 : ZoneSetPoint = zoneTstatSetpt.setpt;
6886 94330 : if (RAFNFrac > 0.0) {
6887 0 : LoadToHeatingSetPoint = LoadToHeatingSetPoint / RAFNFrac;
6888 : }
6889 94330 : if (RAFNFrac > 0.0) {
6890 0 : LoadToCoolingSetPoint = LoadToCoolingSetPoint / RAFNFrac;
6891 : }
6892 :
6893 94330 : if (thisZone.HasAdjustedReturnTempByITE && !(state.dataGlobal->BeginSimFlag)) {
6894 0 : LoadToCoolingSetPoint = this->tempDepLoad * thisZone.AdjustedReturnTempByITE - this->tempIndLoad;
6895 : }
6896 :
6897 : // Note that LoadToHeatingSetPoint is generally not equal to LoadToCoolingSetPoint
6898 : // when the heating and cooling set-points are equal if the zone is unmixed,
6899 : // e.g. displacement ventilation or UFAD, since the stratification is generally not the same in heating and cooling modes
6900 :
6901 : // Possible combinations:
6902 : // 1/ LoadToHeatingSetPoint > 0 & LoadToCoolingSetPoint > 0 --> Heating required
6903 : // 2/ LoadToHeatingSetPoint > LoadToCoolingSetPoint --> Possible in the unmixed case but should be trapped
6904 : // as a poor choice of set-points
6905 : // 3/ LoadToHeatingSetPoint < 0 & LoadToCoolingSetPoint < 0 --> Cooling Required
6906 : // 4/ LoadToHeatingSetPoint <=0 & LoadToCoolingSetPoint >=0 --> Dead Band Operation ! includes zero load cases
6907 : // First trap bad set-points
6908 94330 : if (LoadToHeatingSetPoint > LoadToCoolingSetPoint) {
6909 0 : ShowSevereError(state,
6910 : "HVAC::SetptType::SingleHeatCool: Effective heating set-point higher than effective cooling set-point - use "
6911 : "DualSetPointWithDeadBand if using unmixed air model");
6912 0 : ShowContinueErrorTimeStamp(state, format("occurs in Zone={}", thisZone.Name));
6913 0 : ShowContinueError(state,
6914 0 : format("LoadToHeatingSetPoint={:.3R}, LoadToCoolingSetPoint={:.3R}", LoadToHeatingSetPoint, LoadToCoolingSetPoint));
6915 0 : ShowContinueError(state, format("Zone TempDepZnLd={:.2R}", this->tempDepLoad));
6916 0 : ShowContinueError(state, format("Zone TempIndZnLd={:.2R}", this->tempIndLoad));
6917 0 : ShowContinueError(state, format("Zone ThermostatSetPoint={:.2R}", zoneTstatSetpt.setpt));
6918 0 : ShowFatalError(state, "Program terminates due to above conditions.");
6919 : }
6920 :
6921 94330 : if (LoadToHeatingSetPoint > 0.0 && LoadToCoolingSetPoint > 0.0) {
6922 47377 : totalLoad = LoadToHeatingSetPoint;
6923 46953 : } else if (LoadToHeatingSetPoint < 0.0 && LoadToCoolingSetPoint < 0.0) {
6924 46953 : totalLoad = LoadToCoolingSetPoint;
6925 0 : } else if (LoadToHeatingSetPoint <= 0.0 && LoadToCoolingSetPoint >= 0.0) { // deadband includes zero loads
6926 0 : totalLoad = 0.0;
6927 0 : if (zoneNodeNum > 0) {
6928 0 : ZoneSetPoint = state.dataLoopNodes->Node(zoneNodeNum).Temp;
6929 0 : ZoneSetPoint = max(ZoneSetPoint, zoneTstatSetpt.setptLo); // trap out of deadband
6930 0 : ZoneSetPoint = min(ZoneSetPoint, zoneTstatSetpt.setptHi); // trap out of deadband
6931 : }
6932 0 : thisDeadBandOrSetBack = true;
6933 : } else { // this should never occur!
6934 0 : ShowSevereError(state,
6935 : "SingleHeatCoolSetPoint: Unanticipated combination of heating and cooling loads - report to EnergyPlus Development Team");
6936 0 : ShowContinueErrorTimeStamp(state, format("occurs in Zone={}", thisZone.Name));
6937 0 : ShowContinueError(state,
6938 0 : format("LoadToHeatingSetPoint={:.3R}, LoadToCoolingSetPoint={:.3R}", LoadToHeatingSetPoint, LoadToCoolingSetPoint));
6939 0 : ShowContinueError(state, format("Zone TempDepZnLd={:.2R}", this->tempDepLoad));
6940 0 : ShowContinueError(state, format("Zone TempIndZnLd={:.2R}", this->tempIndLoad));
6941 0 : ShowContinueError(state, format("Zone ThermostatSetPoint={:.2R}", zoneTstatSetpt.setpt));
6942 0 : ShowFatalError(state, "Program terminates due to above conditions.");
6943 : }
6944 94330 : } break;
6945 :
6946 21583812 : case HVAC::SetptType::DualHeatCool: {
6947 21583812 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
6948 8742818 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
6949 8742818 : LoadToHeatingSetPoint = (this->tempDepLoad * (zoneTstatSetpt.setptLo) - this->tempIndLoad);
6950 8742818 : LoadToCoolingSetPoint = (this->tempDepLoad * (zoneTstatSetpt.setptHi) - this->tempIndLoad);
6951 8742818 : } break;
6952 :
6953 12809392 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
6954 12809392 : if (this->tempDepLoad == 0.0) { // B=0
6955 0 : LoadToHeatingSetPoint = this->AirPowerCap * (zoneTstatSetpt.setptLo - this->T1) - this->tempIndLoad;
6956 0 : LoadToCoolingSetPoint = this->AirPowerCap * (zoneTstatSetpt.setptHi - this->T1) - this->tempIndLoad;
6957 : } else {
6958 12809392 : Real64 const exp_700_TA(std::exp(min(700.0, -this->tempDepLoad / this->AirPowerCap)));
6959 12809392 : LoadToHeatingSetPoint = this->tempDepLoad * (zoneTstatSetpt.setptLo - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
6960 12809392 : LoadToCoolingSetPoint = this->tempDepLoad * (zoneTstatSetpt.setptHi - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
6961 : }
6962 12809392 : } break;
6963 :
6964 31602 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
6965 31602 : LoadToHeatingSetPoint =
6966 31602 : this->AirPowerCap * (zoneTstatSetpt.setptLo - this->T1) + this->tempDepLoad * zoneTstatSetpt.setptLo - this->tempIndLoad;
6967 31602 : LoadToCoolingSetPoint =
6968 31602 : this->AirPowerCap * (zoneTstatSetpt.setptHi - this->T1) + this->tempDepLoad * zoneTstatSetpt.setptHi - this->tempIndLoad;
6969 31602 : } break;
6970 0 : default: {
6971 0 : assert(false);
6972 :
6973 : } break;
6974 : } // switch (Algo)
6975 :
6976 21583812 : if (RAFNFrac > 0.0) {
6977 7413 : LoadToHeatingSetPoint = LoadToHeatingSetPoint / RAFNFrac;
6978 : }
6979 21583812 : if (RAFNFrac > 0.0) {
6980 7413 : LoadToCoolingSetPoint = LoadToCoolingSetPoint / RAFNFrac;
6981 : }
6982 :
6983 21583812 : if (thisZone.HasAdjustedReturnTempByITE && !(state.dataGlobal->BeginSimFlag)) {
6984 11058 : LoadToCoolingSetPoint = this->tempDepLoad * thisZone.AdjustedReturnTempByITE - this->tempIndLoad;
6985 : }
6986 :
6987 : // Possible combinations:
6988 : // 1/ LoadToHeatingSetPoint > 0 & LoadToCoolingSetPoint > 0 --> Heating required
6989 : // 2/ LoadToHeatingSetPoint > LoadToCoolingSetPoint --> Possible in the unmixed case but should be trapped
6990 : // as a poor choice of set-points
6991 : // 3/ LoadToHeatingSetPoint < 0 & LoadToCoolingSetPoint < 0 --> Cooling Required
6992 : // 4/ LoadToHeatingSetPoint <=0 & LoadToCoolingSetPoint >=0 --> Dead Band Operation - includes zero load cases
6993 : // First trap bad set-points
6994 21583812 : if (LoadToHeatingSetPoint > LoadToCoolingSetPoint) {
6995 0 : ShowSevereError(state,
6996 : "DualSetPointWithDeadBand: Effective heating set-point higher than effective cooling set-point - increase "
6997 : "deadband if using unmixed air model");
6998 0 : ShowContinueErrorTimeStamp(state, format("occurs in Zone={}", thisZone.Name));
6999 0 : ShowContinueError(state,
7000 0 : format("LoadToHeatingSetPoint={:.3R}, LoadToCoolingSetPoint={:.3R}", LoadToHeatingSetPoint, LoadToCoolingSetPoint));
7001 0 : ShowContinueError(state, format("Zone TempDepZnLd={:.2R}", this->tempDepLoad));
7002 0 : ShowContinueError(state, format("Zone TempIndZnLd={:.2R}", this->tempIndLoad));
7003 0 : ShowContinueError(state, format("Zone Heating ThermostatSetPoint={:.2R}", zoneTstatSetpt.setptLo));
7004 0 : ShowContinueError(state, format("Zone Cooling ThermostatSetPoint={:.2R}", zoneTstatSetpt.setptHi));
7005 0 : ShowFatalError(state, "Program terminates due to above conditions.");
7006 : }
7007 :
7008 21583812 : if (LoadToHeatingSetPoint > 0.0 && LoadToCoolingSetPoint > 0.0) {
7009 8913301 : totalLoad = LoadToHeatingSetPoint;
7010 8913301 : ZoneSetPoint = zoneTstatSetpt.setptLo;
7011 12670511 : } else if (LoadToHeatingSetPoint < 0.0 && LoadToCoolingSetPoint < 0.0) {
7012 7822158 : totalLoad = LoadToCoolingSetPoint;
7013 7822158 : ZoneSetPoint = zoneTstatSetpt.setptHi;
7014 4848353 : } else if (LoadToHeatingSetPoint <= 0.0 && LoadToCoolingSetPoint >= 0.0) { // deadband includes zero loads
7015 : // this turns out to cause instabilities sometimes? that lead to setpoint errors if predictor is off.
7016 4848353 : totalLoad = 0.0;
7017 4848353 : if (zoneNodeNum > 0) {
7018 4848353 : ZoneSetPoint = state.dataLoopNodes->Node(zoneNodeNum).Temp;
7019 4848353 : ZoneSetPoint = max(ZoneSetPoint, zoneTstatSetpt.setptLo); // trap out of deadband
7020 4848353 : ZoneSetPoint = min(ZoneSetPoint, zoneTstatSetpt.setptHi); // trap out of deadband
7021 : }
7022 4848353 : thisDeadBandOrSetBack = true;
7023 : } else { // this should never occur!
7024 0 : ShowSevereError(
7025 : state, "DualSetPointWithDeadBand: Unanticipated combination of heating and cooling loads - report to EnergyPlus Development Team");
7026 0 : ShowContinueErrorTimeStamp(state, format("occurs in Zone={}", thisZone.Name));
7027 0 : ShowContinueError(state,
7028 0 : format("LoadToHeatingSetPoint={:.3R}, LoadToCoolingSetPoint={:.3R}", LoadToHeatingSetPoint, LoadToCoolingSetPoint));
7029 0 : ShowContinueError(state, format("Zone Heating Set-point={:.2R}", zoneTstatSetpt.setptLo));
7030 0 : ShowContinueError(state, format("Zone Cooling Set-point={:.2R}", zoneTstatSetpt.setptHi));
7031 0 : ShowContinueError(state, format("Zone TempDepZnLd={:.2R}", this->tempDepLoad));
7032 0 : ShowContinueError(state, format("Zone TempIndZnLd={:.2R}", this->tempIndLoad));
7033 0 : ShowContinueError(state, format("Zone ThermostatSetPoint={:.2R}", zoneTstatSetpt.setpt));
7034 :
7035 0 : ShowFatalError(state, "Program terminates due to above conditions.");
7036 : }
7037 21583812 : } break;
7038 :
7039 0 : default: {
7040 0 : } break;
7041 : } // swtich (setptType)
7042 :
7043 31432634 : int systemNodeNumber = 0;
7044 31432634 : int stageNum = 0;
7045 31432634 : if (spaceNum > 0) {
7046 86394 : systemNodeNumber = state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber;
7047 86394 : stageNum = state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).StageNum;
7048 86394 : assert(stageNum == state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).StageNum);
7049 : } else {
7050 31346240 : systemNodeNumber = thisZone.SystemZoneNodeNumber;
7051 31346240 : stageNum = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).StageNum;
7052 : }
7053 : // Staged control zone
7054 31432634 : if (s_ztpc->NumStageCtrZone > 0) {
7055 122502 : if (state.dataZoneCtrls->StageZoneLogic(zoneNum)) {
7056 100893 : if (stageNum == 0) { // No load
7057 44373 : LoadToHeatingSetPoint = 0.0;
7058 44373 : LoadToCoolingSetPoint = 0.0;
7059 44373 : totalLoad = 0.0;
7060 44373 : if (systemNodeNumber > 0) {
7061 44373 : ZoneSetPoint = state.dataLoopNodes->Node(systemNodeNumber).Temp;
7062 44373 : ZoneSetPoint = max(ZoneSetPoint, zoneTstatSetpt.setptLo); // trap out of deadband
7063 44373 : ZoneSetPoint = min(ZoneSetPoint, zoneTstatSetpt.setptHi); // trap out of deadband
7064 : }
7065 44373 : thisDeadBandOrSetBack = true;
7066 :
7067 56520 : } else if (stageNum < 0) { // Cooling load
7068 19407 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
7069 19407 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
7070 19407 : LoadToCoolingSetPoint = (this->tempDepLoad * (zoneTstatSetpt.setptHi) - this->tempIndLoad);
7071 19407 : } break;
7072 :
7073 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
7074 0 : if (this->tempDepLoad == 0.0) { // B=0
7075 0 : LoadToCoolingSetPoint = this->AirPowerCap * (zoneTstatSetpt.setptHi - this->T1) - this->tempIndLoad;
7076 : } else {
7077 0 : Real64 const exp_700_TA(std::exp(min(700.0, -this->tempDepLoad / this->AirPowerCap)));
7078 0 : LoadToCoolingSetPoint =
7079 0 : this->tempDepLoad * (zoneTstatSetpt.setptHi - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
7080 : }
7081 0 : } break;
7082 :
7083 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
7084 0 : LoadToCoolingSetPoint =
7085 0 : this->AirPowerCap * (zoneTstatSetpt.setptHi - this->T1) + this->tempDepLoad * zoneTstatSetpt.setptHi - this->tempIndLoad;
7086 0 : } break;
7087 0 : default: {
7088 0 : assert(false);
7089 : } break;
7090 : } // switch (Algo)
7091 :
7092 19407 : totalLoad = LoadToCoolingSetPoint;
7093 19407 : ZoneSetPoint = zoneTstatSetpt.setptHi;
7094 19407 : LoadToHeatingSetPoint = LoadToCoolingSetPoint;
7095 19407 : if ((totalLoad) >= 0.0) {
7096 5839 : thisDeadBandOrSetBack = true;
7097 : }
7098 : } else { // Heating load
7099 37113 : switch (state.dataHeatBal->ZoneAirSolutionAlgo) {
7100 37113 : case DataHeatBalance::SolutionAlgo::ThirdOrder: {
7101 37113 : LoadToHeatingSetPoint = (this->tempDepLoad * zoneTstatSetpt.setptLo - this->tempIndLoad);
7102 37113 : } break;
7103 :
7104 0 : case DataHeatBalance::SolutionAlgo::AnalyticalSolution: {
7105 0 : if (this->tempDepLoad == 0.0) { // B=0
7106 0 : LoadToHeatingSetPoint = this->AirPowerCap * (zoneTstatSetpt.setptLo - this->T1) - this->tempIndLoad;
7107 : } else {
7108 0 : Real64 const exp_700_TA(std::exp(min(700.0, -this->tempDepLoad / this->AirPowerCap)));
7109 0 : LoadToHeatingSetPoint =
7110 0 : this->tempDepLoad * (zoneTstatSetpt.setptLo - this->T1 * exp_700_TA) / (1.0 - exp_700_TA) - this->tempIndLoad;
7111 : }
7112 0 : } break;
7113 :
7114 0 : case DataHeatBalance::SolutionAlgo::EulerMethod: {
7115 0 : LoadToHeatingSetPoint =
7116 0 : this->AirPowerCap * (zoneTstatSetpt.setptLo - this->T1) + this->tempDepLoad * (zoneTstatSetpt.setptLo) - this->tempIndLoad;
7117 0 : } break;
7118 0 : default: {
7119 0 : assert(false);
7120 : } break;
7121 : } // switch (Algo)
7122 :
7123 37113 : totalLoad = LoadToHeatingSetPoint;
7124 37113 : ZoneSetPoint = zoneTstatSetpt.setptLo;
7125 37113 : LoadToCoolingSetPoint = LoadToHeatingSetPoint;
7126 37113 : if ((totalLoad) <= 0.0) {
7127 2164 : thisDeadBandOrSetBack = true;
7128 : }
7129 : }
7130 : }
7131 : }
7132 :
7133 : // If the ZoneNodeNum has been set for a Controlled Zone, then the zone setpoint is placed on the node.
7134 31432634 : if (zoneNodeNum > 0) {
7135 28285514 : state.dataLoopNodes->Node(zoneNodeNum).TempSetPoint = ZoneSetPoint;
7136 : }
7137 :
7138 31432634 : state.dataZoneEnergyDemand->Setback(zoneNum) = (ZoneSetPoint > this->setPointLast);
7139 :
7140 31432634 : this->setPointLast = ZoneSetPoint;
7141 31432634 : state.dataHeatBalFanSys->zoneTstatSetpts(zoneNum).setpt = ZoneSetPoint; // needed to fix Issue # 5048
7142 31432634 : state.dataZoneEnergyDemand->DeadBandOrSetback(zoneNum) = thisDeadBandOrSetBack;
7143 31432634 : state.dataZoneEnergyDemand->CurDeadBandOrSetback(zoneNum) = thisDeadBandOrSetBack;
7144 :
7145 : // Apply the Zone Multiplier and Load Correction factor as needed
7146 31432634 : if (spaceNum > 0) {
7147 86394 : state.dataZoneEnergyDemand->spaceSysEnergyDemand(spaceNum).reportSensibleLoadsZoneMultiplier(
7148 : state, zoneNum, totalLoad, LoadToHeatingSetPoint, LoadToCoolingSetPoint);
7149 : } else {
7150 31346240 : state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum).reportSensibleLoadsZoneMultiplier(
7151 : state, zoneNum, totalLoad, LoadToHeatingSetPoint, LoadToCoolingSetPoint);
7152 : }
7153 31432634 : }
7154 : } // namespace EnergyPlus::ZoneTempPredictorCorrector
|