Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // ObjexxFCL Headers
49 : #include <ObjexxFCL/Array.functions.hh>
50 :
51 : // EnergyPlus Headers
52 : #include <EnergyPlus/Data/EnergyPlusData.hh>
53 : #include <EnergyPlus/DataHeatBalance.hh>
54 : #include <EnergyPlus/DataIPShortCuts.hh>
55 : #include <EnergyPlus/DataRoomAirModel.hh>
56 : #include <EnergyPlus/HeatBalanceManager.hh>
57 : #include <EnergyPlus/HybridModel.hh>
58 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
59 : #include <EnergyPlus/OutputProcessor.hh>
60 : #include <EnergyPlus/ScheduleManager.hh>
61 : #include <EnergyPlus/UtilityRoutines.hh>
62 :
63 : namespace EnergyPlus {
64 :
65 : namespace HybridModel {
66 :
67 : // MODULE INFORMATION:
68 : // AUTHOR Sang Hoon Lee, Tianzhen Hong, Rongpeng Zhang. LBNL
69 : // DATE WRITTEN Oct 2015
70 :
71 : // PURPOSE OF THIS MODULE:
72 : // This module manages hybrid model.
73 :
74 : // METHODOLOGY EMPLOYED:
75 : // The model uses measured zone air temperature to calculate internal thermal mass or infiltration air flow rate.
76 :
77 : // USE STATEMENTS:
78 :
79 : // Using/Aliasing
80 : using namespace DataHeatBalance;
81 :
82 : // Functions
83 :
84 110 : void GetHybridModelZone(EnergyPlusData &state)
85 : {
86 110 : Array1D_bool lAlphaFieldBlanks(16, false);
87 110 : Array1D_bool lNumericFieldBlanks(4, false);
88 110 : std::string CurrentModuleObject; // to assist in getting input
89 110 : Array1D_string cAlphaArgs(16); // Alpha input items for object
90 110 : Array1D_string cAlphaFieldNames(16);
91 110 : Array1D_string cNumericFieldNames(16);
92 110 : Array1D<Real64> rNumericArgs(4); // Numeric input items for object
93 :
94 : // Read hybrid model input
95 110 : CurrentModuleObject = "HybridModel:Zone";
96 110 : state.dataHybridModel->NumOfHybridModelZones = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
97 :
98 110 : if (state.dataHybridModel->NumOfHybridModelZones > 0) {
99 0 : state.dataHybridModel->hybridModelZones.allocate(state.dataGlobal->NumOfZones);
100 0 : bool ErrorsFound = false; // If errors detected in input
101 0 : int NumAlphas = 0; // Number of Alphas for each GetobjectItem call
102 0 : int NumNumbers = 0; // Number of Numbers for each GetobjectItem call
103 0 : int IOStatus = 0;
104 0 : int ZonePtr = 0;
105 0 : for (int HybridModelNum = 1; HybridModelNum <= state.dataHybridModel->NumOfHybridModelZones; ++HybridModelNum) {
106 :
107 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
108 : CurrentModuleObject,
109 : HybridModelNum,
110 : cAlphaArgs,
111 : NumAlphas,
112 : rNumericArgs,
113 : NumNumbers,
114 : IOStatus,
115 : lNumericFieldBlanks,
116 : lAlphaFieldBlanks,
117 : cAlphaFieldNames,
118 : cNumericFieldNames);
119 :
120 0 : ZonePtr = Util::FindItemInList(cAlphaArgs(2), state.dataHeatBal->Zone); // "Zone" is a 1D array, cAlphaArgs(2) is the zone name
121 0 : if (ZonePtr > 0) {
122 0 : auto &hmZone = state.dataHybridModel->hybridModelZones(ZonePtr);
123 0 : hmZone.Name = cAlphaArgs(1); // Zone HybridModel name
124 0 : state.dataHybridModel->FlagHybridModel_TM = Util::SameString(cAlphaArgs(3), "Yes"); // Calculate thermal mass option
125 0 : state.dataHybridModel->FlagHybridModel_AI = Util::SameString(cAlphaArgs(4), "Yes"); // Calculate infiltration rate option
126 0 : state.dataHybridModel->FlagHybridModel_PC = Util::SameString(cAlphaArgs(5), "Yes"); // Calculate people count option
127 :
128 : // Pointers used to help decide which unknown parameter to solve
129 : // Zone Air Infiltration Rate and Zone Internal Thermal Mass calculations cannot be performed simultaneously
130 0 : Sched::Schedule *temperatureSched = Sched::GetSchedule(state, cAlphaArgs(6));
131 0 : Sched::Schedule *humidityRatioSched = Sched::GetSchedule(state, cAlphaArgs(7));
132 0 : Sched::Schedule *CO2ConcentrationSched = Sched::GetSchedule(state, cAlphaArgs(8));
133 :
134 : // Not used for now
135 0 : Sched::Schedule *peopleActivityLevelSched = Sched::GetSchedule(state, cAlphaArgs(9));
136 0 : Sched::Schedule *peopleSensibleFractionSched = Sched::GetSchedule(state, cAlphaArgs(10));
137 0 : Sched::Schedule *peopleRadiantFractionSched = Sched::GetSchedule(state, cAlphaArgs(11));
138 0 : Sched::Schedule *peopleCO2GenRateSched = Sched::GetSchedule(state, cAlphaArgs(12));
139 :
140 : // Pointers used to help decide wheather to include system supply terms in the inverse algorithms
141 0 : Sched::Schedule *supplyAirTemperatureSched = Sched::GetSchedule(state, cAlphaArgs(13));
142 0 : Sched::Schedule *supplyAirMassFlowRateSched = Sched::GetSchedule(state, cAlphaArgs(14));
143 0 : Sched::Schedule *supplyAirHumidityRatioSched = Sched::GetSchedule(state, cAlphaArgs(15));
144 0 : Sched::Schedule *supplyAirCO2ConcentrationSched = Sched::GetSchedule(state, cAlphaArgs(16));
145 :
146 : // Note: Internal thermal mass can be calculated only with measured temperature.
147 : // Air infiltration rate can be calculated with either measured temperature, humidity ratio, or CO2
148 : // concentration. People count can be calculated with either measured temperature, humidity ratio, or CO2
149 : // concentration.
150 :
151 : // Initially set all flags to be false
152 0 : hmZone.InternalThermalMassCalc_T = false;
153 0 : hmZone.InfiltrationCalc_T = false;
154 0 : hmZone.InfiltrationCalc_H = false;
155 0 : hmZone.InfiltrationCalc_C = false;
156 0 : hmZone.PeopleCountCalc_T = false;
157 0 : hmZone.PeopleCountCalc_H = false;
158 0 : hmZone.PeopleCountCalc_C = false;
159 :
160 : // Scenario 1: Only one unknown parameter to solve
161 : // Scenario 1-1: To solve thermal mass
162 0 : if (state.dataHybridModel->FlagHybridModel_TM) {
163 0 : if (state.dataHybridModel->FlagHybridModel_AI) {
164 0 : ShowSevereError(state,
165 0 : format("Field \"{} and {}\" cannot be both set to YES.", cAlphaFieldNames(3), cAlphaFieldNames(4)));
166 0 : ErrorsFound = true;
167 : }
168 :
169 0 : if (state.dataHybridModel->FlagHybridModel_PC) {
170 0 : ShowSevereError(state,
171 0 : format("Field \"{} and {}\" cannot be both set to YES.", cAlphaFieldNames(3), cAlphaFieldNames(5)));
172 0 : ErrorsFound = true;
173 : }
174 :
175 0 : if (temperatureSched == nullptr) {
176 0 : ShowSevereError(state, format("Measured Zone Air Tempearture Schedule is not defined for: {}", CurrentModuleObject));
177 0 : ErrorsFound = true;
178 : } else {
179 0 : hmZone.InternalThermalMassCalc_T = true;
180 : }
181 : }
182 :
183 : // Scenario 1-2: To solve infiltration rate
184 0 : if (state.dataHybridModel->FlagHybridModel_AI) {
185 0 : if (state.dataHybridModel->FlagHybridModel_PC) {
186 0 : ShowSevereError(state,
187 0 : format("Field \"{}\" and \"{}\" cannot be both set to YES.", cAlphaFieldNames(4), cAlphaFieldNames(5)));
188 0 : ErrorsFound = true;
189 : }
190 0 : if (temperatureSched == nullptr && humidityRatioSched == nullptr && CO2ConcentrationSched == nullptr) {
191 : // Show fatal error if no measurement schedule is provided
192 0 : ShowSevereError(state, format("No measured environmental parameter is provided for: {}", CurrentModuleObject));
193 0 : ShowContinueError(state,
194 0 : format("One of the field \"{}\", \"{}\", or {}\" must be provided for the HybridModel:Zone.",
195 : cAlphaFieldNames(6),
196 : cAlphaFieldNames(7),
197 : cAlphaFieldNames(8)));
198 0 : ErrorsFound = true;
199 : } else {
200 0 : if (temperatureSched != nullptr && !state.dataHybridModel->FlagHybridModel_TM) {
201 : // Temperature schedule is provided, igonore humidity ratio and CO2 concentration schedules.
202 0 : hmZone.InfiltrationCalc_T = true;
203 0 : if (humidityRatioSched != nullptr) {
204 0 : ShowWarningError(state, format("Field \"{}\" is provided.", cAlphaFieldNames(6)));
205 0 : ShowContinueError(state, format("Field \"{}\" will not be used.", cAlphaFieldNames(7)));
206 : }
207 0 : if (CO2ConcentrationSched != nullptr) {
208 0 : ShowWarningError(state, format("Field \"{}\" is provided.", cAlphaFieldNames(6)));
209 0 : ShowContinueError(state, format("Field \"{}\" will not be used.", cAlphaFieldNames(8)));
210 : }
211 : }
212 0 : if (humidityRatioSched != nullptr && temperatureSched == nullptr) {
213 : // Humidity ratio schedule is provided, ignore CO2 concentration schedule.
214 0 : hmZone.InfiltrationCalc_H = true;
215 0 : if (CO2ConcentrationSched != nullptr) {
216 0 : ShowWarningError(state, format("Field \"{}\" is provided.", cAlphaFieldNames(7)));
217 0 : ShowContinueError(state, format("Field \"{}\" will not be used.", cAlphaFieldNames(8)));
218 : }
219 : }
220 0 : if (CO2ConcentrationSched != nullptr && temperatureSched == nullptr && humidityRatioSched == nullptr) {
221 : // Only CO2 concentration schedule is provided.
222 0 : hmZone.InfiltrationCalc_C = true;
223 : }
224 : }
225 : }
226 :
227 : // Scenario 1-3: To solve people count
228 0 : if (state.dataHybridModel->FlagHybridModel_PC) {
229 0 : if (temperatureSched == nullptr && humidityRatioSched == nullptr && CO2ConcentrationSched == nullptr) {
230 : // Show fatal error if no measurement schedule is provided
231 0 : ShowSevereError(state, format("No measured environmental parameter is provided for: {}", CurrentModuleObject));
232 0 : ShowContinueError(state,
233 0 : format("One of the field \"{}\", \"{}\", or {}\" must be provided for the HybridModel:Zone.",
234 : cAlphaFieldNames(6),
235 : cAlphaFieldNames(7),
236 : cAlphaFieldNames(8)));
237 0 : ErrorsFound = true;
238 : } else {
239 0 : if (temperatureSched != nullptr && !state.dataHybridModel->FlagHybridModel_TM) {
240 : // Temperature schedule is provided, igonore humidity ratio and CO2 concentration schedules.
241 0 : hmZone.PeopleCountCalc_T = true;
242 0 : if (humidityRatioSched != nullptr) {
243 0 : ShowWarningError(
244 : state,
245 : "The measured air humidity ratio schedule will not be used since measured air temperature is provided.");
246 : }
247 0 : if (CO2ConcentrationSched != nullptr) {
248 0 : ShowWarningError(
249 : state,
250 : "The measured air CO2 concentration schedule will not be used since measured air temperature is provided.");
251 : }
252 : }
253 0 : if (humidityRatioSched != nullptr && temperatureSched == nullptr) {
254 : // Humidity ratio schedule is provided, ignore CO2 concentration schedule.
255 0 : hmZone.PeopleCountCalc_H = true;
256 0 : if (CO2ConcentrationSched != nullptr) {
257 0 : ShowWarningError(state,
258 : "The measured air CO2 concentration schedule will not be used since measured air humidity "
259 : "ratio is provided.");
260 : }
261 : }
262 0 : if (CO2ConcentrationSched != nullptr && temperatureSched == nullptr && humidityRatioSched == nullptr) {
263 : // Only CO2 concentration schedule is provided.
264 0 : hmZone.PeopleCountCalc_C = true;
265 : }
266 : }
267 : }
268 :
269 : // Decide if system supply terms are valid to be included in the inverse solution
270 0 : if (supplyAirTemperatureSched != nullptr && supplyAirMassFlowRateSched != nullptr && supplyAirHumidityRatioSched != nullptr) {
271 0 : if (hmZone.InfiltrationCalc_T || hmZone.PeopleCountCalc_T) {
272 0 : hmZone.IncludeSystemSupplyParameters = true;
273 : } else {
274 0 : ShowWarningError(state,
275 0 : format("Field \"{}\", {}, and \"{}\" will not be used in the inverse balance equation.",
276 : cAlphaFieldNames(13),
277 : cAlphaFieldNames(14),
278 : cAlphaFieldNames(15)));
279 : }
280 : }
281 :
282 0 : if (supplyAirHumidityRatioSched != nullptr && supplyAirMassFlowRateSched != nullptr) {
283 0 : if (hmZone.InfiltrationCalc_H || hmZone.PeopleCountCalc_H) {
284 0 : hmZone.IncludeSystemSupplyParameters = true;
285 : } else {
286 0 : ShowWarningError(state,
287 0 : format("Field \"{}\" and \"{}\" will not be used in the inverse balance equation.",
288 : cAlphaFieldNames(15),
289 : cAlphaFieldNames(14)));
290 : }
291 : }
292 :
293 0 : if (supplyAirCO2ConcentrationSched != nullptr && supplyAirMassFlowRateSched != nullptr) {
294 0 : if (hmZone.InfiltrationCalc_C || hmZone.PeopleCountCalc_C) {
295 0 : hmZone.IncludeSystemSupplyParameters = true;
296 : } else {
297 0 : ShowWarningError(state,
298 0 : format("Field \"{}\" and \"{}\" will not be used in the inverse balance equation.",
299 : cAlphaFieldNames(16),
300 : cAlphaFieldNames(14)));
301 : }
302 : }
303 :
304 : // Flags showing Hybrid Modeling settings
305 0 : state.dataHybridModel->FlagHybridModel = hmZone.InternalThermalMassCalc_T || hmZone.InfiltrationCalc_T ||
306 0 : hmZone.InfiltrationCalc_H || hmZone.InfiltrationCalc_C || hmZone.PeopleCountCalc_T ||
307 0 : hmZone.PeopleCountCalc_H || hmZone.PeopleCountCalc_C;
308 :
309 0 : if (hmZone.InternalThermalMassCalc_T || hmZone.InfiltrationCalc_T || hmZone.PeopleCountCalc_T) {
310 0 : hmZone.measuredTempSched = temperatureSched;
311 : }
312 :
313 0 : if (hmZone.InfiltrationCalc_H || hmZone.PeopleCountCalc_H) {
314 0 : hmZone.measuredHumRatSched = humidityRatioSched;
315 : }
316 :
317 0 : if (hmZone.InfiltrationCalc_C || hmZone.PeopleCountCalc_C) {
318 0 : hmZone.measuredCO2ConcSched = CO2ConcentrationSched;
319 : }
320 :
321 0 : if (hmZone.IncludeSystemSupplyParameters) {
322 0 : hmZone.supplyAirTempSched = supplyAirTemperatureSched;
323 0 : hmZone.supplyAirMassFlowRateSched = supplyAirMassFlowRateSched;
324 0 : hmZone.supplyAirHumRatSched = supplyAirHumidityRatioSched;
325 0 : hmZone.supplyAirCO2ConcSched = supplyAirCO2ConcentrationSched;
326 : }
327 :
328 : // Get optional people related schedules
329 0 : if (hmZone.PeopleCountCalc_T || hmZone.PeopleCountCalc_H || hmZone.PeopleCountCalc_C) {
330 0 : if (peopleActivityLevelSched != nullptr) {
331 0 : hmZone.peopleActivityLevelSched = peopleActivityLevelSched;
332 : } else {
333 0 : ShowWarningError(
334 : state,
335 0 : format("Field \"{}\": default people activity level is not provided, default value of 130W/person will be used.",
336 : cAlphaFieldNames(9)));
337 : }
338 0 : if (peopleSensibleFractionSched != nullptr) {
339 0 : hmZone.peopleSensibleFracSched = peopleSensibleFractionSched;
340 : } else {
341 0 : ShowWarningError(
342 : state,
343 0 : format("Field \"{}\": default people sensible heat rate is not provided, default value of 0.6 will be used.",
344 : cAlphaFieldNames(10)));
345 : }
346 0 : if (peopleRadiantFractionSched != nullptr) {
347 0 : hmZone.peopleRadiantFracSched = peopleRadiantFractionSched;
348 : } else {
349 0 : ShowWarningError(state,
350 0 : format("Field \"{}\": default people radiant heat portion (of sensible heat) is not provided, default "
351 : "value of 0.7 will be used.",
352 : cAlphaFieldNames(11)));
353 : }
354 0 : if (peopleCO2GenRateSched != nullptr) {
355 0 : hmZone.peopleCO2GenRateSched = peopleCO2GenRateSched;
356 : } else {
357 0 : ShowWarningError(state,
358 0 : format("Field \"{}\": default people CO2 generation rate is not provided, default value of 0.0000000382 "
359 : "kg/W will be used.",
360 : cAlphaFieldNames(12)));
361 : }
362 : }
363 :
364 0 : if (state.dataHybridModel->FlagHybridModel) {
365 : // prepare start and end date for Hybrid Modeling
366 0 : hmZone.measuredTempStartMonth = rNumericArgs(1);
367 0 : hmZone.measuredTempStartDate = rNumericArgs(2);
368 0 : hmZone.measuredTempEndMonth = rNumericArgs(3);
369 0 : hmZone.measuredTempEndDate = rNumericArgs(4);
370 : {
371 0 : int const HMDayArr[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
372 :
373 0 : int HybridModelStartMonth = hmZone.measuredTempStartMonth;
374 0 : int HybridModelStartDate = hmZone.measuredTempStartDate;
375 0 : int HybridModelEndMonth = hmZone.measuredTempEndMonth;
376 0 : int HybridModelEndDate = hmZone.measuredTempEndDate;
377 :
378 0 : int HMStartDay = 0;
379 0 : int HMEndDay = 0;
380 0 : if (HybridModelStartMonth >= 1 && HybridModelStartMonth <= 12) {
381 0 : HMStartDay = HMDayArr[HybridModelStartMonth - 1];
382 : }
383 :
384 0 : if (HybridModelEndMonth >= 1 && HybridModelEndMonth <= 12) {
385 0 : HMEndDay = HMDayArr[HybridModelEndMonth - 1];
386 : }
387 :
388 0 : hmZone.HybridStartDayOfYear = HMStartDay + HybridModelStartDate;
389 0 : hmZone.HybridEndDayOfYear = HMEndDay + HybridModelEndDate;
390 : }
391 : }
392 :
393 : // Output variable
394 0 : if (hmZone.InfiltrationCalc_T || hmZone.InfiltrationCalc_H || hmZone.InfiltrationCalc_C) {
395 0 : SetupOutputVariable(state,
396 : "Zone Infiltration Hybrid Model Air Change Rate",
397 : Constant::Units::ach,
398 0 : state.dataHeatBal->Zone(ZonePtr).InfilOAAirChangeRateHM,
399 : OutputProcessor::TimeStepType::Zone,
400 : OutputProcessor::StoreType::Average,
401 0 : state.dataHeatBal->Zone(ZonePtr).Name);
402 0 : SetupOutputVariable(state,
403 : "Zone Infiltration Hybrid Model Mass Flow Rate",
404 : Constant::Units::kg_s,
405 0 : state.dataHeatBal->Zone(ZonePtr).MCPIHM,
406 : OutputProcessor::TimeStepType::Zone,
407 : OutputProcessor::StoreType::Average,
408 0 : state.dataHeatBal->Zone(ZonePtr).Name);
409 : }
410 0 : if (hmZone.PeopleCountCalc_T || hmZone.PeopleCountCalc_H || hmZone.PeopleCountCalc_C) {
411 0 : SetupOutputVariable(state,
412 : "Zone Hybrid Model People Count",
413 : Constant::Units::None,
414 0 : state.dataHeatBal->Zone(ZonePtr).NumOccHM,
415 : OutputProcessor::TimeStepType::Zone,
416 : OutputProcessor::StoreType::Average,
417 0 : state.dataHeatBal->Zone(ZonePtr).Name);
418 : }
419 0 : if (hmZone.InternalThermalMassCalc_T) {
420 0 : SetupOutputVariable(state,
421 : "Zone Hybrid Model Thermal Mass Multiplier",
422 : Constant::Units::None,
423 0 : state.dataHeatBal->Zone(ZonePtr).ZoneVolCapMultpSensHM,
424 : OutputProcessor::TimeStepType::Zone,
425 : OutputProcessor::StoreType::Average,
426 0 : state.dataHeatBal->Zone(ZonePtr).Name);
427 : }
428 :
429 : // ZoneAirMassFlowConservation should not be activated during the Hybrid Modeling infiltration calculations
430 0 : if (hmZone.InfiltrationCalc_T && state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance) {
431 0 : state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance = false;
432 0 : ShowWarningError(state, "ZoneAirMassFlowConservation is deactivated when Hybrid Modeling is performed.");
433 : }
434 : } else {
435 0 : ShowSevereError(
436 : state,
437 0 : format("{}=\"{}\" invalid {}=\"{}\" not found.", CurrentModuleObject, cAlphaArgs(1), cAlphaFieldNames(2), cAlphaArgs(2)));
438 0 : ErrorsFound = true;
439 : }
440 : }
441 :
442 : // RoomAirModelType should be Mixing if Hybrid Modeling is performed for the zone
443 0 : if (state.dataHybridModel->FlagHybridModel) {
444 0 : for (int ZonePtr = 1; ZonePtr <= state.dataGlobal->NumOfZones; ZonePtr++) {
445 0 : auto &hmZone = state.dataHybridModel->hybridModelZones(ZonePtr);
446 0 : if ((hmZone.InternalThermalMassCalc_T || hmZone.InfiltrationCalc_T) &&
447 0 : (state.dataRoomAir->AirModel(ZonePtr).AirModel != RoomAir::RoomAirModel::Mixing)) {
448 0 : state.dataRoomAir->AirModel(ZonePtr).AirModel = RoomAir::RoomAirModel::Mixing;
449 0 : ShowWarningError(state, "Room Air Model Type should be Mixing if Hybrid Modeling is performed for the zone.");
450 : }
451 : }
452 0 : if (state.dataHeatBal->doSpaceHeatBalanceSimulation || state.dataHeatBal->doSpaceHeatBalanceSizing) {
453 0 : ShowSevereError(state, "Hybrid Modeling is not supported with ZoneAirHeatBalanceAlgorithm Space Heat Balance.");
454 0 : ErrorsFound = true;
455 : }
456 : }
457 :
458 0 : if (ErrorsFound) {
459 0 : ShowFatalError(state, "Errors getting Hybrid Model input data. Preceding condition(s) cause termination.");
460 : }
461 : }
462 110 : }
463 :
464 : // Needed for unit tests, should not be normally called.
465 :
466 : } // namespace HybridModel
467 :
468 : } // namespace EnergyPlus
|