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