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 <EnergyPlus/CurveManager.hh>
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataEnvironment.hh>
60 : #include <EnergyPlus/DataHVACGlobals.hh>
61 : #include <EnergyPlus/General.hh>
62 : #include <EnergyPlus/HybridEvapCoolingModel.hh>
63 : #include <EnergyPlus/Psychrometrics.hh>
64 : #include <EnergyPlus/ScheduleManager.hh>
65 : #include <EnergyPlus/UtilityRoutines.hh>
66 :
67 : namespace EnergyPlus { //***************
68 :
69 : namespace HybridEvapCoolingModel {
70 : // Module containing the EvaporativeCoolers simulation routines
71 :
72 : // MODULE INFORMATION:
73 : // AUTHOR Spencer Dutton
74 : // DATE WRITTEN May 2017
75 : // MODIFIED na
76 : // RE-ENGINEERED na
77 :
78 : // PURPOSE OF THIS MODULE:
79 : // To encapsulate the data and algorithms required for the HybridUnitaryHVAC system.
80 :
81 : // METHODOLOGY EMPLOYED:
82 : // uses 6D lookup tables to provide performance data that describe 8 key performance metrics .
83 :
84 : // Supply Air Temperature, Supply Air Humidity Ratio, Electric Power, Supply Fan Electric Power, External Static Pressure
85 : // System Second Fuel Consumption, System Third Fuel Consumption, System Water Use
86 :
87 : // USE STATEMENTS:
88 : using namespace EnergyPlus::DataEnvironment;
89 : using namespace Psychrometrics;
90 : using Curve::CurveValue;
91 : using Curve::GetCurveIndex;
92 : using Curve::GetCurveMinMaxValues;
93 : using ScheduleManager::GetCurrentScheduleValue;
94 :
95 : #define DEF_Tdb 0
96 : #define DEF_RH 1
97 :
98 : #define TEMP_CURVE 0
99 : #define W_CURVE 1
100 : #define POWER_CURVE 2
101 : #define SUPPLY_FAN_POWER 3
102 : #define EXTERNAL_STATIC_PRESSURE 4
103 : #define SECOND_FUEL_USE 5
104 : #define THIRD_FUEL_USE 6
105 : #define WATER_USE 7
106 :
107 114224 : CMode::CMode()
108 228448 : : ModeID(0.0), Max_Msa(0.0), Min_Msa(0.0), Min_OAF(0.0), Max_OAF(0.0), Minimum_Outdoor_Air_Temperature(0.0),
109 114224 : Maximum_Outdoor_Air_Temperature(0.0), Minimum_Outdoor_Air_Humidity_Ratio(0.0), Maximum_Outdoor_Air_Humidity_Ratio(0.0),
110 114224 : ModelScalingFactor(0.0)
111 : {
112 114224 : MODE_BLOCK_OFFSET_Alpha = 9;
113 114224 : BLOCK_HEADER_OFFSET_Alpha = 20;
114 114224 : MODE1_BLOCK_OFFSET_Number = 2;
115 114224 : MODE_BLOCK_OFFSET_Number = 16;
116 114224 : BLOCK_HEADER_OFFSET_Number = 6;
117 114224 : }
118 :
119 5 : bool CMode::InitializeOutdoorAirTemperatureConstraints(Real64 min, Real64 max)
120 : {
121 : // note If this field is blank, there should be no lower constraint on outside air temperature
122 5 : Minimum_Outdoor_Air_Temperature = min;
123 5 : Maximum_Outdoor_Air_Temperature = max;
124 5 : return true;
125 : }
126 5 : bool CMode::InitializeOutdoorAirHumidityRatioConstraints(Real64 min, Real64 max)
127 : {
128 : // minimum 0.00 maximum 0.10, units kgWater / kgDryAir
129 : // note Mode0 will not be considerd when outside air absolute humidity is below the value in this field.
130 : // note If this field is blank, the lower constraint on outside air humidity ratio will be 0.00 kgWater / kgDryAir., default 0.00
131 : // the upper constraint on outside air humidity ratio will be 0.10 kgWater / kgDryAir, default 0.10
132 5 : Minimum_Outdoor_Air_Humidity_Ratio = min;
133 5 : Maximum_Outdoor_Air_Humidity_Ratio = max;
134 5 : return true;
135 : }
136 5 : bool CMode::InitializeOutdoorAirRelativeHumidityConstraints(Real64 min, Real64 max)
137 : {
138 : // minimum 0.00,maximum 100.00, units percent, Mode0 will not be considered when the outside air relative humidity is below the value in this
139 : // field.
140 : // note If this field is blank, the lower constraint on outside air relative humidity will be 0.00% (default 0.00), the upper constraint on
141 : // outside air relative humidity will be 100.00%, (default 100.00)
142 5 : Minimum_Outdoor_Air_Relative_Humidity = min;
143 5 : Maximum_Outdoor_Air_Relative_Humidity = max;
144 5 : return true;
145 : }
146 5 : bool CMode::InitializeReturnAirTemperatureConstraints(Real64 min, Real64 max)
147 : {
148 : // will not be considered when the return air temperature is below the value in this field.
149 : // If this field is blank, there will be no lower constraint on return air temperature
150 5 : Minimum_Return_Air_Temperature = min;
151 5 : Maximum_Return_Air_Temperature = max;
152 5 : return true;
153 : }
154 5 : bool CMode::InitializeReturnAirHumidityRatioConstraints(Real64 min, Real64 max)
155 : {
156 : // minimum 0.00 maximum 0.10, units kgWater / kgDryAir
157 : // note Mode0 will not be considerd when outside air absolute humidity is below the value in this field.
158 : // note If this field is blank, the lower constraint on outside air humidity ratio will be 0.00 kgWater / kgDryAir., default 0.00
159 : // the upper constraint on outside air humidity ratio will be 0.10 kgWater / kgDryAir, default 0.10
160 5 : Minimum_Return_Air_Humidity_Ratio = min;
161 5 : Maximum_Return_Air_Humidity_Ratio = max;
162 5 : return true;
163 : }
164 5 : bool CMode::InitializeReturnAirRelativeHumidityConstraints(Real64 min, Real64 max)
165 : {
166 : // minimum 0.00,maximum 100.00, units percent, Mode0 will not be considered when the outside air relative humidity is below the value in this
167 : // field.
168 : // note If this field is blank, the lower constraint on outside air relative humidity will be 0.00% (default 0.00), the upper constraint on
169 : // outside air relative humidity will be 100.00%, (default 100.00)
170 5 : Minimum_Return_Air_Relative_Humidity = min;
171 5 : Maximum_Return_Air_Relative_Humidity = max;
172 5 : return true;
173 : }
174 5 : bool CMode::InitializeOSAFConstraints(Real64 minOSAF, Real64 maxOSAF)
175 : {
176 : // minimum 0.00, maximum 1.00, Outdoor air fractions below this value will not be considered.
177 : // If this field is blank, the lower constraint on outside air fraction will be 0.00,default 0.10
178 5 : Min_OAF = minOSAF;
179 5 : Max_OAF = maxOSAF;
180 5 : return true;
181 : }
182 5 : bool CMode::InitializeMsaRatioConstraints(Real64 minMsa, Real64 maxMsa)
183 : {
184 : // minimum 0.00, maximum 1.00, Supply air mass flow rate ratios below this value will not be considered.
185 : // Supply air mass flow rate ratio describes supply air mass flow rate as a fraction of mass flow rate associated with the value in field :
186 : // "System Maximum Supply Air Flow Rate". If this field is blank, the lower constraint on outside air fraction will be 0.00,default 0.10
187 5 : Min_Msa = minMsa;
188 5 : Max_Msa = maxMsa;
189 5 : return true;
190 : }
191 1282389 : bool CMode::ValidPointer(int curve_pointer)
192 : {
193 1282389 : if (curve_pointer >= 0)
194 1060741 : return true;
195 : else
196 221648 : return false;
197 : }
198 1282389 : Real64 CMode::CalculateCurveVal(EnergyPlusData &state, Real64 Tosa, Real64 Wosa, Real64 Tra, Real64 Wra, Real64 Msa, Real64 OSAF, int curveType)
199 : {
200 : // SUBROUTINE INFORMATION:
201 : // AUTHOR Spencer Maxwell Dutton
202 : // DATE WRITTEN October 2017
203 : // MODIFIED
204 : // RE-ENGINEERED na
205 :
206 : // PURPOSE OF THIS SUBROUTINE:
207 : // Returns the normalized or scaled output from the performance curve as specified by curveType. 6 independent variables are required.
208 :
209 : // METHODOLOGY EMPLOYED:
210 : // Makes a call to the curve manager, then multiplies the result by either the by the ModelScalingFactor for extensive variables.
211 : // The ModelScalingFactor is the parent model's Scaling Factor, which is input by the user in the idf for this unit, and passed to
212 : // this CMode from the parent Model.
213 : // The following tables are for intensive variables : Supply Air Temperature, Supply Air Humidity, External Static Pressure
214 : // The following tables are for extensive variables : Electric Power, Fan Electric Power, Second Fuel Consumption,
215 : // Third Fuel Consumption, Water Use Lookup Table
216 : //
217 : // Tosa is the outside air temperature
218 : // Wosa is the outside humidity ratio
219 : // Tra return air temp
220 : // Wra return humidity ratio,
221 : // Msa supply air mass flow rate
222 : // OSAF outside air fraction
223 :
224 : // REFERENCES:
225 : // na
226 :
227 : // Using/Aliasing
228 1282389 : Real64 Y_val = 0;
229 :
230 1282389 : switch (curveType) {
231 221180 : case TEMP_CURVE:
232 221180 : if (ValidPointer(Tsa_curve_pointer)) {
233 221180 : Y_val = CurveValue(state, Tsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
234 : } else {
235 0 : Y_val = Tra; // return air temp
236 : }
237 221180 : break;
238 :
239 221180 : case W_CURVE:
240 221180 : if (ValidPointer(HRsa_curve_pointer)) {
241 221180 : Y_val = CurveValue(state, HRsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
242 221180 : Y_val = max(min(Y_val, 1.0), 0.0);
243 : } else {
244 0 : Y_val = Wra; // return HR
245 : }
246 221180 : break;
247 :
248 : // The ModelScalingFactor factor for the Power, Fan Power, Water, and Fuel Use curves is equal to the Parent Model's Scaling Factor
249 114204 : case POWER_CURVE:
250 114204 : if (ValidPointer(Psa_curve_pointer)) {
251 114204 : Y_val = ModelScalingFactor * CurveValue(state, Psa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
252 : } else {
253 0 : Y_val = 0;
254 : }
255 114204 : break;
256 :
257 322109 : case SUPPLY_FAN_POWER:
258 322109 : if (ValidPointer(SFPsa_curve_pointer)) {
259 322109 : Y_val = ModelScalingFactor * CurveValue(state, SFPsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
260 : } else {
261 0 : Y_val = 0;
262 : }
263 322109 : break;
264 :
265 100929 : case EXTERNAL_STATIC_PRESSURE:
266 100929 : if (ValidPointer(ESPsa_curve_pointer)) {
267 100929 : Y_val = CurveValue(state, ESPsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
268 : } else {
269 0 : Y_val = 0; // or set a more reasonable default
270 : }
271 100929 : break;
272 :
273 100929 : case SECOND_FUEL_USE:
274 100929 : if (ValidPointer(SFUsa_curve_pointer)) {
275 46017 : Y_val = ModelScalingFactor * CurveValue(state, SFUsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
276 : } else {
277 54912 : Y_val = 0; // or set a more reasonable default
278 : }
279 100929 : break;
280 :
281 100929 : case THIRD_FUEL_USE:
282 100929 : if (ValidPointer(TFUsa_curve_pointer)) {
283 0 : Y_val = ModelScalingFactor * CurveValue(state, TFUsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
284 : } else {
285 100929 : Y_val = 0; // or set a more reasonable default
286 : }
287 100929 : break;
288 :
289 100929 : case WATER_USE:
290 100929 : if (ValidPointer(WUsa_curve_pointer)) {
291 35122 : Y_val = ModelScalingFactor * CurveValue(state, WUsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
292 : } else {
293 65807 : Y_val = 0; // or set a more reasonable default
294 : }
295 100929 : break;
296 :
297 0 : default:
298 0 : break;
299 : }
300 :
301 1282389 : return Y_val;
302 : }
303 48 : void CMode::InitializeCurve(int curveType, int curve_ID)
304 : {
305 : // SUBROUTINE INFORMATION:
306 : // AUTHOR Spencer Maxwell Dutton
307 : // DATE WRITTEN October 2017
308 : // MODIFIED
309 : // RE-ENGINEERED na
310 :
311 : // PURPOSE OF THIS SUBROUTINE:
312 : // Sets the curve ID assigned by the curve manager for the specific lookup Table, to a member variable.
313 :
314 : // METHODOLOGY EMPLOYED:
315 : //
316 :
317 : // REFERENCES:
318 : // na
319 :
320 : // Using/Aliasing
321 48 : switch (curveType) {
322 6 : case TEMP_CURVE:
323 6 : Tsa_curve_pointer = curve_ID;
324 6 : break;
325 6 : case W_CURVE:
326 6 : HRsa_curve_pointer = curve_ID;
327 6 : break;
328 6 : case POWER_CURVE:
329 6 : Psa_curve_pointer = curve_ID;
330 6 : break;
331 6 : case SUPPLY_FAN_POWER:
332 6 : SFPsa_curve_pointer = curve_ID;
333 6 : break;
334 6 : case EXTERNAL_STATIC_PRESSURE:
335 6 : ESPsa_curve_pointer = curve_ID;
336 6 : break;
337 6 : case SECOND_FUEL_USE:
338 6 : SFUsa_curve_pointer = curve_ID;
339 6 : break;
340 6 : case THIRD_FUEL_USE:
341 6 : TFUsa_curve_pointer = curve_ID;
342 6 : break;
343 6 : case WATER_USE:
344 6 : WUsa_curve_pointer = curve_ID;
345 6 : break;
346 0 : default:
347 0 : break;
348 : }
349 48 : }
350 :
351 6 : void CMode::GenerateSolutionSpace()
352 : {
353 : // SUBROUTINE INFORMATION:
354 : // AUTHOR Spencer Maxwell Dutton
355 : // DATE WRITTEN October 2017
356 : // MODIFIED
357 : // RE-ENGINEERED na
358 :
359 : // PURPOSE OF THIS SUBROUTINE:
360 : // Generates a matrix of all possible combinations of OSAF and supply air mass flow rates.
361 :
362 : // METHODOLOGY EMPLOYED:
363 : // Calculate the range of supply air mass flow rate (SAMF) and OSAF the mode can operate under.
364 : // Calculate a step size to increment through the ranges of SAMF and OSAF, based on the ResolutionMsa and
365 : // ResolutionOSAs respectively (these are hard coded in the constructor, this is an important consideration
366 : // because the number of increments greatly effects the simulation run time).
367 : //
368 : // if the range is smaller than the minimum resolution, then use the minimum resolution size as the minimum range over which to iterate
369 : // this should have the effect of keeping the number of solutions constant even if the range size varies.
370 :
371 : // REFERENCES:
372 : // na
373 :
374 : // Using/Aliasing
375 :
376 6 : if (Min_Msa == Max_Msa) {
377 1 : sol.MassFlowRatio.push_back(Max_Msa);
378 : } else {
379 5 : Real64 ResolutionMsa = (Max_Msa - Min_Msa) * 0.2;
380 33 : for (Real64 Msa_val = Max_Msa; Msa_val >= Min_Msa; Msa_val -= ResolutionMsa) {
381 28 : sol.MassFlowRatio.push_back(Msa_val);
382 : }
383 : }
384 :
385 6 : if (Min_OAF == Max_OAF) {
386 6 : sol.OutdoorAirFraction.push_back(Max_OAF);
387 : } else {
388 0 : Real64 ResolutionOSA = (Max_OAF - Min_OAF) * 0.2;
389 0 : for (Real64 OAF_val = Max_OAF; OAF_val >= Min_OAF; OAF_val -= ResolutionOSA) {
390 0 : sol.OutdoorAirFraction.push_back(OAF_val);
391 : }
392 : }
393 6 : }
394 :
395 6 : bool Model::ParseMode(EnergyPlusData &state,
396 : Array1D_string Alphas,
397 : Array1D_string cAlphaFields,
398 : Array1D<Real64> Numbers,
399 : Array1D_string cNumericFields,
400 : Array1D<bool> lAlphaBlanks,
401 : std::string cCurrentModuleObject)
402 : {
403 6 : CMode newMode;
404 6 : bool error = newMode.ParseMode(
405 : state, ModeCounter, &OperatingModes, ScalingFactor, Alphas, cAlphaFields, Numbers, cNumericFields, lAlphaBlanks, cCurrentModuleObject);
406 6 : ModeCounter++;
407 6 : return error;
408 6 : }
409 :
410 6 : bool CMode::ParseMode(EnergyPlusData &state,
411 : int ModeCounter,
412 : std::vector<CMode> *OperatingModes,
413 : Real64 ScalingFactor,
414 : Array1D_string Alphas,
415 : Array1D_string cAlphaFields,
416 : Array1D<Real64> Numbers,
417 : Array1D_string cNumericFields,
418 : Array1D<bool> lAlphaBlanks,
419 : std::string cCurrentModuleObject)
420 : {
421 : // SUBROUTINE INFORMATION:
422 : // AUTHOR Spencer Maxwell Dutton
423 : // DATE WRITTEN October 2017
424 : // MODIFIED
425 : // RE-ENGINEERED na
426 :
427 : // PURPOSE OF THIS SUBROUTINE:
428 : // Does the processing of each of the seperate modes
429 :
430 : // METHODOLOGY EMPLOYED:
431 : // As the number of modes defined in the idf is not known until its read in, this method uses two counters to keep track of the inputs in the
432 : // Alphas and Numbers arrays. Three constants are used, BLOCK_HEADER_OFFSET_Alpha, BLOCK_HEADER_OFFSET_Number and MODE1_BLOCK_OFFSET_Number
433 : // if ever additional input parameters are added to the idf these offset counters would have to be adjusted accordingly.
434 :
435 : // REFERENCES:
436 : // na
437 :
438 : // Using/Aliasing
439 6 : ModeID = ModeCounter;
440 6 : ModelScalingFactor = ScalingFactor;
441 :
442 : int inter_Number;
443 6 : bool ErrorsFound = false;
444 6 : int inter_Alpha = BLOCK_HEADER_OFFSET_Alpha + MODE_BLOCK_OFFSET_Alpha * ModeID;
445 6 : if (ModeID > 0) {
446 5 : inter_Number = BLOCK_HEADER_OFFSET_Number + MODE1_BLOCK_OFFSET_Number + MODE_BLOCK_OFFSET_Number * (ModeID - 1);
447 : } else {
448 1 : inter_Number = BLOCK_HEADER_OFFSET_Number + MODE1_BLOCK_OFFSET_Number;
449 : }
450 6 : std::ostringstream strs;
451 6 : strs << ModeID;
452 :
453 6 : int curveID = -1;
454 6 : if (lAlphaBlanks(inter_Alpha)) {
455 0 : ModeName = "Mode" + strs.str();
456 : } else {
457 6 : ModeName = Alphas(inter_Alpha);
458 : }
459 :
460 6 : curveID = -1;
461 6 : inter_Alpha = inter_Alpha + 1;
462 6 : if (lAlphaBlanks(inter_Alpha)) {
463 1 : InitializeCurve(TEMP_CURVE, curveID); // as this is invalid curve id CalculateCurveVal will return a default when called
464 : } else {
465 5 : curveID = GetCurveIndex(state, Alphas(inter_Alpha));
466 5 : if (curveID == 0) {
467 0 : ShowSevereError(state, format("Invalid {}={}", cAlphaFields(inter_Alpha), Alphas(inter_Alpha)));
468 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
469 0 : ErrorsFound = true;
470 0 : InitializeCurve(TEMP_CURVE, -1);
471 : } else {
472 5 : InitializeCurve(TEMP_CURVE, curveID);
473 : }
474 : }
475 :
476 6 : inter_Alpha = inter_Alpha + 1;
477 :
478 : // A22, \field Mode0 Supply Air Humidity Ratio Lookup Table Name
479 6 : curveID = -1;
480 6 : if (lAlphaBlanks(inter_Alpha)) {
481 1 : InitializeCurve(W_CURVE, curveID); // as this is invalid curve id CalculateCurveVal will return a default when called
482 : } else {
483 5 : curveID = GetCurveIndex(state, Alphas(inter_Alpha));
484 5 : if (curveID == 0) {
485 0 : ShowSevereError(state, format("Invalid {}={}", cAlphaFields(inter_Alpha), Alphas(inter_Alpha)));
486 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
487 0 : ErrorsFound = true;
488 0 : InitializeCurve(W_CURVE, -1);
489 : } else {
490 5 : InitializeCurve(W_CURVE, curveID);
491 : }
492 : }
493 6 : inter_Alpha = inter_Alpha + 1;
494 : // A23, \field Mode0 System Electric Power Lookup Table Name
495 6 : curveID = -1;
496 6 : if (lAlphaBlanks(inter_Alpha)) {
497 0 : InitializeCurve(POWER_CURVE, curveID); // as this is invalid curve id CalculateCurveVal will return a default
498 : } else {
499 6 : curveID = GetCurveIndex(state, Alphas(inter_Alpha));
500 6 : if (curveID == 0) {
501 0 : ShowSevereError(state, format("Invalid {}={}", cAlphaFields(inter_Alpha), Alphas(inter_Alpha)));
502 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
503 0 : ErrorsFound = true;
504 0 : InitializeCurve(POWER_CURVE, -1);
505 : } else {
506 6 : InitializeCurve(POWER_CURVE, curveID);
507 : }
508 : }
509 : // A24, \field Mode0 Supply Fan Electric Power Lookup Table Name
510 6 : inter_Alpha = inter_Alpha + 1;
511 6 : curveID = -1;
512 6 : if (lAlphaBlanks(inter_Alpha)) {
513 1 : InitializeCurve(SUPPLY_FAN_POWER, curveID); // as this is invalid curve id CalculateCurveVal will return a default
514 : } else {
515 5 : curveID = GetCurveIndex(state, Alphas(inter_Alpha));
516 5 : if (curveID == 0) {
517 0 : ShowSevereError(state, format("Invalid {}={}", cAlphaFields(inter_Alpha), Alphas(inter_Alpha)));
518 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
519 0 : ErrorsFound = true;
520 0 : InitializeCurve(SUPPLY_FAN_POWER, -1);
521 : } else {
522 5 : InitializeCurve(SUPPLY_FAN_POWER, curveID);
523 : }
524 : }
525 : // A25, \field Mode0 External Static Pressure Lookup Table Name
526 6 : inter_Alpha = inter_Alpha + 1;
527 6 : curveID = -1;
528 6 : if (lAlphaBlanks(inter_Alpha)) {
529 1 : InitializeCurve(EXTERNAL_STATIC_PRESSURE, curveID); // as this is invalid curve id CalculateCurveVal will return a default
530 : } else {
531 5 : curveID = GetCurveIndex(state, Alphas(inter_Alpha));
532 5 : if (curveID == 0) {
533 0 : ShowSevereError(state, format("Invalid {}={}", cAlphaFields(inter_Alpha), Alphas(inter_Alpha)));
534 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
535 0 : ErrorsFound = true;
536 0 : InitializeCurve(EXTERNAL_STATIC_PRESSURE, -1);
537 : } else {
538 5 : InitializeCurve(EXTERNAL_STATIC_PRESSURE, curveID);
539 : }
540 : }
541 : //
542 : // A26, \field Mode0 System Second Fuel Consumption Lookup Table Nam
543 6 : inter_Alpha = inter_Alpha + 1;
544 6 : curveID = -1;
545 6 : if (lAlphaBlanks(inter_Alpha)) {
546 5 : InitializeCurve(SECOND_FUEL_USE, curveID); // as this is invalid curve id CalculateCurveVal will return a default
547 : } else {
548 1 : curveID = GetCurveIndex(state, Alphas(inter_Alpha));
549 1 : if (curveID == 0) {
550 0 : ShowSevereError(state, format("Invalid {}={}", cAlphaFields(inter_Alpha), Alphas(inter_Alpha)));
551 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
552 0 : ErrorsFound = true;
553 0 : InitializeCurve(SECOND_FUEL_USE, -1);
554 : } else {
555 1 : InitializeCurve(SECOND_FUEL_USE, curveID);
556 : }
557 : }
558 : // A27, \field Mode0 System Third Fuel Consumption Lookup Table Name
559 6 : inter_Alpha = inter_Alpha + 1;
560 6 : curveID = -1;
561 6 : if (lAlphaBlanks(inter_Alpha)) {
562 6 : InitializeCurve(THIRD_FUEL_USE, curveID); // as this is invalid curve id CalculateCurveVal will return a default
563 : } else {
564 0 : curveID = GetCurveIndex(state, Alphas(inter_Alpha));
565 0 : if (curveID == 0) {
566 0 : ShowSevereError(state, format("Invalid {}={}", cAlphaFields(inter_Alpha), Alphas(inter_Alpha)));
567 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
568 0 : ErrorsFound = true;
569 0 : InitializeCurve(THIRD_FUEL_USE, -1);
570 : } else {
571 0 : InitializeCurve(THIRD_FUEL_USE, curveID);
572 : }
573 : }
574 : // A28, \field Mode0 System Water Use Lookup Table Name
575 6 : inter_Alpha = inter_Alpha + 1;
576 6 : curveID = -1;
577 6 : if (lAlphaBlanks(inter_Alpha)) {
578 3 : InitializeCurve(WATER_USE, curveID); // as this is invalid curve id CalculateCurveVal will return a default
579 : } else {
580 3 : curveID = GetCurveIndex(state, Alphas(inter_Alpha));
581 3 : if (curveID == 0) {
582 0 : ShowSevereError(state, format("Invalid {}={}", cAlphaFields(inter_Alpha), Alphas(inter_Alpha)));
583 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
584 0 : ErrorsFound = true;
585 0 : InitializeCurve(WATER_USE, -1);
586 : } else {
587 3 : InitializeCurve(WATER_USE, curveID);
588 : }
589 : }
590 6 : if (ModeID == 0) {
591 1 : (*OperatingModes).push_back(*this);
592 1 : return ErrorsFound;
593 : }
594 : // N8, \field Mode1 Minimum Outdoor Air Temperature
595 : // N9, \field Mode1 Maximum Outdoor Air Temperature
596 5 : bool ok = InitializeOutdoorAirTemperatureConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
597 5 : if (!ok) {
598 0 : ShowSevereError(state, format("Invalid {}Or Invalid{}", cNumericFields(inter_Number), cNumericFields(inter_Number + 1)));
599 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
600 0 : ErrorsFound = true;
601 : }
602 5 : inter_Number = inter_Number + 2;
603 : // N10, \field Mode1 Minimum Outdoor Air Humidity Ratio
604 : // N11, \field Mode1 Maximum Outdoor Air Humidity Ratio
605 5 : ok = InitializeOutdoorAirHumidityRatioConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
606 5 : if (!ok) {
607 0 : ShowSevereError(state, format("Invalid {}Or Invalid{}", cNumericFields(inter_Number), cNumericFields(inter_Number + 1)));
608 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
609 0 : ErrorsFound = true;
610 : }
611 5 : inter_Number = inter_Number + 2;
612 : // N12, \field Mode1 Minimum Outdoor Air Relative Humidity
613 : // N13, \field Mode1 Maximum Outdoor Air Relative Humidity
614 5 : ok = InitializeOutdoorAirRelativeHumidityConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
615 5 : if (!ok) {
616 0 : ShowSevereError(state, format("Invalid {}Or Invalid{}", cNumericFields(inter_Number), cNumericFields(inter_Number + 1)));
617 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
618 0 : ErrorsFound = true;
619 : }
620 5 : inter_Number = inter_Number + 2;
621 : // N14, \field Mode1 Minimum Return Air Temperature
622 : // N15, \field Mode1 Maximum Return Air Temperature
623 5 : ok = InitializeReturnAirTemperatureConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
624 5 : if (!ok) {
625 0 : ShowSevereError(state, format("Invalid {}Or Invalid{}", cNumericFields(inter_Number), cNumericFields(inter_Number + 1)));
626 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
627 0 : ErrorsFound = true;
628 : }
629 5 : inter_Number = inter_Number + 2;
630 : // N16, \field Mode1 Minimum Return Air Humidity Ratio
631 : // N17, \field Mode1 Maximum Return Air Humidity Ratio
632 5 : ok = InitializeReturnAirHumidityRatioConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
633 5 : if (!ok) {
634 0 : ShowSevereError(state, format("Invalid {}Or Invalid{}", cNumericFields(inter_Number), cNumericFields(inter_Number + 1)));
635 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
636 0 : ErrorsFound = true;
637 : }
638 5 : inter_Number = inter_Number + 2;
639 : // N18, \field Mode1 Minimum Return Air Relative HumidityInitialize
640 : // N19, \field Mode1 Maximum Return Air Relative Humidity
641 5 : ok = InitializeReturnAirRelativeHumidityConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
642 5 : if (!ok) {
643 0 : ShowSevereError(state,
644 0 : format("Invalid {}={}Or Invalid{}={}",
645 : cAlphaFields(inter_Number),
646 : Alphas(inter_Number),
647 : cAlphaFields(inter_Number + 1),
648 : Alphas(inter_Number + 1)));
649 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
650 0 : ErrorsFound = true;
651 : }
652 5 : inter_Number = inter_Number + 2;
653 : // N20, \field Mode1 Minimum Outdoor Air Fraction
654 : // N21, \field Mode1 Maximum Outdoor Air Fraction
655 :
656 5 : ok = InitializeOSAFConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
657 5 : if (!ok) {
658 0 : ShowSevereError(state, format("Error in OSAFConstraints{}through{}", cAlphaFields(inter_Number), cAlphaFields(inter_Number + 1)));
659 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
660 0 : ErrorsFound = true;
661 : }
662 : // N22, \field Mode1 Minimum Supply Air Mass Flow Rate Ratio
663 : // N23, \field Mode1 Maximum Supply Air Mass Flow Rate Ratio
664 5 : inter_Number = inter_Number + 2;
665 5 : ok = InitializeMsaRatioConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
666 5 : if (!ok) {
667 0 : ShowSevereError(state, format("Error in OSAFConstraints{}through{}", cAlphaFields(inter_Number), cAlphaFields(inter_Number + 1)));
668 0 : ShowContinueError(state, format("Entered in {}", cCurrentModuleObject));
669 0 : ErrorsFound = true;
670 : }
671 5 : (*OperatingModes).push_back(*this);
672 5 : return ErrorsFound;
673 6 : }
674 :
675 66085 : bool CMode::MeetsOAEnvConstraints(Real64 Tosa, Real64 Wosa, Real64 RHosa)
676 : {
677 : // SUBROUTINE INFORMATION:
678 : // AUTHOR Spencer Maxwell Dutton
679 : // DATE WRITTEN October 2017
680 : // MODIFIED
681 : // RE-ENGINEERED na
682 :
683 : // PURPOSE OF THIS SUBROUTINE:
684 : // To check to see if this mode of operation is able to operate given the specified outdoor environmental conditions.
685 :
686 : // METHODOLOGY EMPLOYED:
687 : // Constraining certain modes to only operate over certain environmental conditions gives the user greater control in which
688 : // modes the algorithm selects.
689 :
690 : // REFERENCES:
691 : // na
692 :
693 : // Using/Aliasing
694 66085 : bool OATempConstraintmet = false;
695 66085 : bool OAHRConstraintmet = false;
696 66085 : bool OARHConstraintmet = false;
697 :
698 66085 : if (Tosa >= Minimum_Outdoor_Air_Temperature && Tosa <= Maximum_Outdoor_Air_Temperature) {
699 66085 : OATempConstraintmet = true;
700 : }
701 :
702 66085 : if (Wosa >= Minimum_Outdoor_Air_Humidity_Ratio && Wosa <= Maximum_Outdoor_Air_Humidity_Ratio) {
703 66085 : OAHRConstraintmet = true;
704 : }
705 :
706 66085 : if (RHosa >= Minimum_Outdoor_Air_Relative_Humidity && RHosa <= Maximum_Outdoor_Air_Relative_Humidity) {
707 66085 : OARHConstraintmet = true;
708 : }
709 66085 : if (OATempConstraintmet && OAHRConstraintmet && OARHConstraintmet) {
710 66085 : return true;
711 : } else {
712 0 : return false;
713 : }
714 : }
715 :
716 221180 : bool Model::MeetsSupplyAirTOC(EnergyPlusData &state, Real64 Tsupplyair)
717 : {
718 : // SUBROUTINE INFORMATION:
719 : // AUTHOR Spencer Maxwell Dutton
720 : // DATE WRITTEN October 2017
721 : // MODIFIED
722 : // RE-ENGINEERED na
723 :
724 : // PURPOSE OF THIS SUBROUTINE:
725 : // To check to see if this this particular setting (combination of mode, OSAF and Msa) meets the required minumum
726 : // supply air temperature specified in the schedules
727 :
728 : // METHODOLOGY EMPLOYED:
729 : // Checks the minimum and maximum supply air temperatures and tests to see if the proposed supply air temperature is in the acceptable range.
730 :
731 : // REFERENCES:
732 : // na
733 :
734 : // Using/Aliasing
735 221180 : Real64 MinSAT = 10;
736 221180 : Real64 MaxSAT = 20;
737 221180 : if (TsaMin_schedule_pointer > 0) {
738 221180 : MinSAT = GetCurrentScheduleValue(state, TsaMin_schedule_pointer);
739 : }
740 221180 : if (TsaMax_schedule_pointer > 0) {
741 221180 : MaxSAT = GetCurrentScheduleValue(state, TsaMax_schedule_pointer);
742 : }
743 221180 : if (Tsupplyair < MinSAT || Tsupplyair > MaxSAT) return false;
744 100929 : return true;
745 : }
746 :
747 221180 : bool Model::MeetsSupplyAirRHOC(EnergyPlusData &state, Real64 SupplyW)
748 : {
749 : // SUBROUTINE INFORMATION:
750 : // AUTHOR Spencer Maxwell Dutton
751 : // DATE WRITTEN October 2017
752 : // MODIFIED
753 : // RE-ENGINEERED na
754 :
755 : // PURPOSE OF THIS SUBROUTINE:
756 : // To check to see if this this particular setting (combination of mode, OSAF and Msa) meets the required minumum
757 : // supply air relative humidity specified in the schedules
758 :
759 : // METHODOLOGY EMPLOYED:
760 : // Checks the scheduled minimum and maximum supply air RH and tests to see if the proposed supply air RH is in the acceptable range.
761 :
762 : // REFERENCES:
763 : // na
764 :
765 : // Using/Aliasing
766 221180 : Real64 MinRH = 0;
767 221180 : Real64 MaxRH = 1;
768 221180 : if (RHsaMin_schedule_pointer > 0) {
769 221180 : MinRH = GetCurrentScheduleValue(state, RHsaMin_schedule_pointer);
770 : }
771 221180 : if (RHsaMax_schedule_pointer > 0) {
772 221180 : MaxRH = GetCurrentScheduleValue(state, RHsaMax_schedule_pointer);
773 : }
774 221180 : if (SupplyW < MinRH || SupplyW > MaxRH) return false;
775 221180 : return true;
776 : }
777 :
778 2 : Model::Model()
779 6 : : Initialized(false), ZoneNum(0), SchedPtr(0), SystemMaximumSupplyAirFlowRate(0.0), ScalingFactor(0.0),
780 2 : ScaledSystemMaximumSupplyAirMassFlowRate(0.0), UnitOn(0), UnitTotalCoolingRate(0.0), UnitTotalCoolingEnergy(0.0),
781 2 : UnitSensibleCoolingRate(0.0), UnitSensibleCoolingEnergy(0.0), UnitLatentCoolingRate(0.0), UnitLatentCoolingEnergy(0.0),
782 2 : SystemTotalCoolingRate(0.0), SystemTotalCoolingEnergy(0.0), SystemSensibleCoolingRate(0.0), SystemSensibleCoolingEnergy(0.0),
783 2 : SystemLatentCoolingRate(0.0), SystemLatentCoolingEnergy(0.0), UnitTotalHeatingRate(0.0), UnitTotalHeatingEnergy(0.0),
784 2 : UnitSensibleHeatingRate(0.0), UnitSensibleHeatingEnergy(0.0), UnitLatentHeatingRate(0.0), UnitLatentHeatingEnergy(0.0),
785 2 : SystemTotalHeatingRate(0.0), SystemTotalHeatingEnergy(0.0), SystemSensibleHeatingRate(0.0), SystemSensibleHeatingEnergy(0.0),
786 2 : SystemLatentHeatingRate(0.0), SystemLatentHeatingEnergy(0.0), SupplyFanElectricPower(0.0), SupplyFanElectricEnergy(0.0),
787 2 : SecondaryFuelConsumptionRate(0.0), SecondaryFuelConsumption(0.0), ThirdFuelConsumptionRate(0.0), ThirdFuelConsumption(0.0),
788 2 : WaterConsumptionRate(0.0), WaterConsumption(0.0), QSensZoneOut(0), QLatentZoneOut(0), QLatentZoneOutMass(0), ExternalStaticPressure(0.0),
789 2 : RequestedHumdificationMass(0.0), RequestedHumdificationLoad(0.0), RequestedHumdificationEnergy(0.0), RequestedDeHumdificationMass(0.0),
790 2 : RequestedDeHumdificationLoad(0.0), RequestedDeHumdificationEnergy(0.0), RequestedLoadToHeatingSetpoint(0.0),
791 2 : RequestedLoadToCoolingSetpoint(0.0), TsaMin_schedule_pointer(0), TsaMax_schedule_pointer(0), RHsaMin_schedule_pointer(0),
792 2 : RHsaMax_schedule_pointer(0), PrimaryMode(0), PrimaryModeRuntimeFraction(0.0), averageOSAF(0), ErrorCode(0), InletNode(0), OutletNode(0),
793 2 : SecondaryInletNode(0), SecondaryOutletNode(0), FinalElectricalPower(0.0), FinalElectricalEnergy(0.0), InletMassFlowRate(0.0),
794 2 : InletTemp(0.0), InletWetBulbTemp(0.0), InletHumRat(0.0), InletEnthalpy(0.0), InletPressure(0.0), InletRH(0.0),
795 2 : OutletVolumetricFlowRate(0.0), OutletMassFlowRate(0.0), PowerLossToAir(0.0), FanHeatTemp(0.0), OutletTemp(0.0), OutletWetBulbTemp(0.0),
796 2 : OutletHumRat(0.0), OutletEnthalpy(0.0), OutletPressure(0.0), OutletRH(0.0), SecInletMassFlowRate(0.0), SecInletTemp(0.0),
797 2 : SecInletWetBulbTemp(0.0), SecInletHumRat(0.0), SecInletEnthalpy(0.0), SecInletPressure(0.0), SecInletRH(0.0), SecOutletMassFlowRate(0.0),
798 2 : SecOutletTemp(0.0), SecOutletWetBulbTemp(0.0), SecOutletHumRat(0.0), SecOutletEnthalpy(0.0), SecOutletPressure(0.0), SecOutletRH(0.0),
799 2 : Wsa(0.0), SupplyVentilationAir(0.0), SupplyVentilationVolume(0.0), OutdoorAir(false), MinOA_Msa(0.0), OARequirementsPtr(0), Tsa(0.0),
800 2 : ModeCounter(0), CoolingRequested(false), HeatingRequested(false), VentilationRequested(false), DehumidificationRequested(false),
801 2 : HumidificationRequested(false)
802 : {
803 2 : WarnOnceFlag = false;
804 2 : count_EnvironmentConditionsMetOnce = 0;
805 2 : count_EnvironmentConditionsNotMet = 0;
806 2 : count_SAHR_OC_MetOnce = 0;
807 2 : count_SAT_OC_MetOnce = 0;
808 2 : count_DidWeMeetLoad = 0;
809 2 : count_DidWeNotMeetLoad = 0;
810 : // vector below used store the modes in each timestep that don't meet humidity or temperature limits, used in warnings
811 2 : std::vector<int> temp(25);
812 2 : SAT_OC_MetinMode_v = temp;
813 2 : SAHR_OC_MetinMode_v = temp;
814 :
815 2 : ModeCounter = 0;
816 :
817 2 : CurrentOperatingSettings.resize(5);
818 :
819 2 : InitializeModelParams();
820 2 : }
821 :
822 26552 : void Model::ResetOutputs()
823 : {
824 26552 : UnitTotalCoolingRate = 0;
825 26552 : UnitTotalCoolingEnergy = 0;
826 26552 : UnitSensibleCoolingRate = 0;
827 26552 : UnitSensibleCoolingEnergy = 0;
828 26552 : UnitLatentCoolingRate = 0;
829 26552 : UnitLatentCoolingEnergy = 0;
830 26552 : SystemTotalCoolingRate = 0;
831 26552 : SystemTotalCoolingEnergy = 0;
832 26552 : SystemSensibleCoolingRate = 0;
833 26552 : SystemSensibleCoolingEnergy = 0;
834 26552 : SystemLatentCoolingRate = 0;
835 26552 : SystemLatentCoolingEnergy = 0;
836 26552 : UnitTotalHeatingRate = 0;
837 26552 : UnitTotalHeatingEnergy = 0;
838 26552 : UnitSensibleHeatingRate = 0;
839 26552 : UnitSensibleHeatingEnergy = 0;
840 26552 : UnitLatentHeatingRate = 0;
841 26552 : UnitLatentHeatingEnergy = 0;
842 26552 : SystemTotalHeatingRate = 0;
843 26552 : SystemTotalHeatingEnergy = 0;
844 26552 : SystemSensibleHeatingRate = 0;
845 26552 : SystemSensibleHeatingEnergy = 0;
846 26552 : SystemLatentHeatingRate = 0;
847 26552 : SystemLatentHeatingEnergy = 0;
848 26552 : SupplyFanElectricPower = 0;
849 26552 : SupplyFanElectricEnergy = 0;
850 26552 : SecondaryFuelConsumptionRate = 0;
851 26552 : SecondaryFuelConsumption = 0;
852 26552 : ThirdFuelConsumptionRate = 0;
853 26552 : ThirdFuelConsumption = 0;
854 26552 : WaterConsumptionRate = 0;
855 26552 : WaterConsumption = 0;
856 26552 : ExternalStaticPressure = 0;
857 26552 : }
858 :
859 13277 : void Model::InitializeModelParams()
860 : {
861 : // SUBROUTINE INFORMATION:
862 : // AUTHOR Spencer Maxwell Dutton
863 : // DATE WRITTEN October 2017
864 : // MODIFIED
865 : // RE-ENGINEERED na
866 :
867 : // PURPOSE OF THIS SUBROUTINE:
868 : // Reset calculation values
869 :
870 : // METHODOLOGY EMPLOYED:
871 : //
872 :
873 : // REFERENCES:
874 : // na
875 :
876 : // Using/Aliasing
877 13277 : ResetOutputs();
878 13277 : PrimaryMode = 0;
879 13277 : PrimaryModeRuntimeFraction = 0;
880 13277 : optimal_EnvCondMet = false;
881 13277 : Tsa = 0;
882 : // reset the power use to a high value, this is replaced during the calculation keeping the "best" setting.
883 :
884 13277 : RunningPeakCapacity_EnvCondMet = false;
885 13277 : Settings.clear();
886 13277 : }
887 :
888 1 : void Model::Initialize(int ZoneNumber)
889 : {
890 : // SUBROUTINE INFORMATION:
891 : // AUTHOR Spencer Maxwell Dutton
892 : // DATE WRITTEN October 2017
893 : // MODIFIED
894 : // RE-ENGINEERED na
895 :
896 : // PURPOSE OF THIS SUBROUTINE:
897 : // Specify solution space resolution, and populate the solution spaces in each mode
898 :
899 : // METHODOLOGY EMPLOYED:
900 : // Solution spaces are the matrices of possible settings settings (combination of OSA fraction and supply air mass flow rate)
901 : // This method calls the GenerateSolutionSpace for each of the modes defined in the idf.
902 : // REFERENCES:
903 : // na
904 :
905 : // Using/Aliasing
906 :
907 1 : ZoneNum = ZoneNumber;
908 1 : if (Initialized) {
909 0 : return;
910 : }
911 1 : Initialized = true;
912 :
913 : // Iterate through modes of operation generating a matrix of OSAF and Msa to test in the algorithm.
914 7 : for (auto &thisOperatingMode : OperatingModes) {
915 6 : thisOperatingMode.GenerateSolutionSpace();
916 1 : }
917 :
918 1 : Initialized = true;
919 : }
920 :
921 114204 : Real64 Model::CheckVal_W(EnergyPlusData &state, Real64 W, Real64 T, Real64 P)
922 : {
923 : // P must be in pascals NOT kPa
924 114204 : Real64 OutletRHtest = PsyRhFnTdbWPb(state, T, W, P); // could also use outlet pressure instead of fixed
925 : Real64 OutletW =
926 114204 : PsyWFnTdbRhPb(state, T, OutletRHtest, P, "Humidity ratio exceeded realistic range error called in " + Name + ", check performance curve");
927 114204 : return OutletW;
928 : }
929 13275 : Real64 Model::CheckVal_T(EnergyPlusData &state, Real64 T)
930 : {
931 13275 : if ((T > 100) || (T < 0)) {
932 2 : ShowWarningError(state, format("Supply air temperature exceeded realistic range error called in {}, check performance curve", Name));
933 : }
934 13275 : return T;
935 : }
936 13275 : bool Model::SetStandByMode(EnergyPlusData &state, CMode Mode0, Real64 Tosa, Real64 Wosa, Real64 Tra, Real64 Wra)
937 : {
938 : // SUBROUTINE INFORMATION:
939 : // AUTHOR Spencer Maxwell Dutton
940 : // DATE WRITTEN October 2017
941 : // MODIFIED
942 : // RE-ENGINEERED na
943 :
944 : // PURPOSE OF THIS SUBROUTINE:
945 : // Set the supply air mass flow rate, power use, and all the other parameters for a setting.
946 :
947 : // METHODOLOGY EMPLOYED:
948 : // Uses the relevant lookup take to specify the parameters, or uses default conditions.
949 : // In setting the supply air temperature for now just use return air future improvement will use look up table
950 :
951 : // REFERENCES:
952 : // na
953 :
954 : // if the map of the solution space looks valid then populate the class member oStandBy (CSetting) with the settings data (what OSAF it runs
955 : // at, and how much power it uses etc.
956 13275 : if (Mode0.sol.MassFlowRatio.size() > 0) {
957 13275 : Real64 MsaRatio = Mode0.sol.MassFlowRatio[0];
958 13275 : Real64 OSAF = Mode0.sol.OutdoorAirFraction[0];
959 :
960 13275 : oStandBy.ScaledSupply_Air_Mass_Flow_Rate = MsaRatio * ScaledSystemMaximumSupplyAirMassFlowRate;
961 13275 : oStandBy.Unscaled_Supply_Air_Mass_Flow_Rate = oStandBy.ScaledSupply_Air_Mass_Flow_Rate / ScalingFactor;
962 13275 : oStandBy.ScaledSupply_Air_Ventilation_Volume = MsaRatio * ScaledSystemMaximumSupplyAirMassFlowRate / state.dataEnvrn->StdRhoAir;
963 13275 : oStandBy.Supply_Air_Mass_Flow_Rate_Ratio = MsaRatio;
964 13275 : oStandBy.ElectricalPower =
965 13275 : Mode0.CalculateCurveVal(state, Tosa, Wosa, Tra, Wra, oStandBy.Unscaled_Supply_Air_Mass_Flow_Rate, OSAF, POWER_CURVE);
966 13275 : oStandBy.Outdoor_Air_Fraction = OSAF;
967 13275 : oStandBy.SupplyAirTemperature = Tra;
968 13275 : oStandBy.SupplyAirW = Wra;
969 13275 : oStandBy.Mode = 0;
970 13275 : oStandBy.Mixed_Air_Temperature = Tra;
971 13275 : oStandBy.Mixed_Air_W = Wra;
972 : } else {
973 : // if the solution space is invalid return true that an error occurred.
974 0 : return true;
975 : }
976 :
977 13275 : return false;
978 : }
979 :
980 159300 : Real64 Model::CalculateTimeStepAverage(SYSTEMOUTPUTS val)
981 : {
982 : // SUBROUTINE INFORMATION:
983 : // AUTHOR Spencer Maxwell Dutton
984 : // DATE WRITTEN October 2017
985 : // MODIFIED
986 : // RE-ENGINEERED na
987 :
988 : // PURPOSE OF THIS SUBROUTINE:
989 : // Calculates the resultant supply air conditions when the system operates in
990 : // multiple settings within a timestep.
991 :
992 : // METHODOLOGY EMPLOYED:
993 : // For longer simulation timesteps this model can consider partial runtime fractions
994 : // operating in different settings for a fraction of the total simulation time step reducing the likelyhood of over conditioning.
995 : // Intensive variables that do not depend on system size (like temperature, pressure,etc), and extensive variables (variable whose values
996 : // depend on the quantity of substance) are handled differently
997 : //
998 : // Extensive variables ( Mass Flow, Volume flow, Fuel use etc), are averaged weighted by the amount of time spent in each setting.
999 : // for example if then system operates for 25% of the time with a mass flow of 4kg/s, and 75% of the time at a mass flow of 0kg/s then the
1000 : // resultant time step average mass flow rate would be 1 kg/s.
1001 :
1002 : // Intensive values in each part runtime fraction are first multiplied by the Scaled Supply Air Mass Flow Rate for each setting
1003 : // and then once all the various runtime fractions are added up, the resultant is divided by the overal time step average Scaled Supply Air
1004 : // Mass Flow Rate
1005 : //
1006 : // REFERENCES:
1007 : // na
1008 :
1009 : // Using/Aliasing
1010 159300 : Real64 averagedVal = 0;
1011 159300 : Real64 MassFlowDependentDenominator = 0;
1012 159300 : Real64 value = 0;
1013 :
1014 955800 : for (auto &thisOperatingSettings : CurrentOperatingSettings) {
1015 796500 : switch (val) {
1016 66375 : case SYSTEMOUTPUTS::VENTILATION_AIR_V:
1017 66375 : value = thisOperatingSettings.ScaledSupply_Air_Ventilation_Volume;
1018 66375 : break;
1019 66375 : case SYSTEMOUTPUTS::SYSTEM_FUEL_USE:
1020 66375 : value = thisOperatingSettings.ElectricalPower;
1021 66375 : break;
1022 66375 : case SYSTEMOUTPUTS::OSUPPLY_FAN_POWER:
1023 66375 : value = thisOperatingSettings.SupplyFanElectricPower;
1024 66375 : break;
1025 66375 : case SYSTEMOUTPUTS::OSECOND_FUEL_USE:
1026 66375 : value = thisOperatingSettings.SecondaryFuelConsumptionRate;
1027 66375 : break;
1028 66375 : case SYSTEMOUTPUTS::OTHIRD_FUEL_USE:
1029 66375 : value = thisOperatingSettings.ThirdFuelConsumptionRate;
1030 66375 : break;
1031 66375 : case SYSTEMOUTPUTS::OEXTERNAL_STATIC_PRESSURE:
1032 66375 : value = thisOperatingSettings.ExternalStaticPressure * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
1033 66375 : break;
1034 66375 : case SYSTEMOUTPUTS::OWATER_USE:
1035 66375 : value = thisOperatingSettings.WaterConsumptionRate;
1036 66375 : break;
1037 66375 : case SYSTEMOUTPUTS::SUPPLY_AIR_TEMP:
1038 66375 : value = thisOperatingSettings.SupplyAirTemperature * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
1039 66375 : break;
1040 66375 : case SYSTEMOUTPUTS::MIXED_AIR_TEMP:
1041 66375 : value = thisOperatingSettings.Mixed_Air_Temperature * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
1042 66375 : break;
1043 66375 : case SYSTEMOUTPUTS::SUPPLY_MASS_FLOW:
1044 66375 : value = thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
1045 66375 : break;
1046 66375 : case SYSTEMOUTPUTS::SUPPLY_AIR_HR:
1047 66375 : value = thisOperatingSettings.SupplyAirW * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
1048 66375 : break;
1049 66375 : case SYSTEMOUTPUTS::MIXED_AIR_HR:
1050 66375 : value = thisOperatingSettings.Mixed_Air_W * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
1051 66375 : break;
1052 0 : default:
1053 0 : assert(false);
1054 : }
1055 796500 : Real64 part_run = thisOperatingSettings.Runtime_Fraction;
1056 796500 : averagedVal = averagedVal + value * part_run;
1057 796500 : MassFlowDependentDenominator = thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate * part_run + MassFlowDependentDenominator;
1058 159300 : }
1059 :
1060 159300 : CSetting StandbyMode = (*(CurrentOperatingSettings.begin()));
1061 159300 : switch (val) {
1062 13275 : case SYSTEMOUTPUTS::SUPPLY_AIR_TEMP:
1063 13275 : if (MassFlowDependentDenominator == 0) {
1064 7740 : averagedVal = StandbyMode.SupplyAirTemperature;
1065 : } else {
1066 5535 : averagedVal = averagedVal / MassFlowDependentDenominator;
1067 : }
1068 13275 : break;
1069 13275 : case SYSTEMOUTPUTS::OEXTERNAL_STATIC_PRESSURE:
1070 13275 : if (MassFlowDependentDenominator == 0) {
1071 7740 : averagedVal = StandbyMode.ExternalStaticPressure;
1072 : } else {
1073 5535 : averagedVal = averagedVal / MassFlowDependentDenominator;
1074 : }
1075 13275 : break;
1076 13275 : case SYSTEMOUTPUTS::SUPPLY_AIR_HR:
1077 13275 : if (MassFlowDependentDenominator == 0) {
1078 7740 : averagedVal = StandbyMode.SupplyAirW;
1079 : } else {
1080 5535 : averagedVal = averagedVal / MassFlowDependentDenominator;
1081 : }
1082 13275 : break;
1083 13275 : case SYSTEMOUTPUTS::MIXED_AIR_TEMP:
1084 13275 : if (MassFlowDependentDenominator == 0) {
1085 7740 : averagedVal = StandbyMode.Mixed_Air_Temperature;
1086 : } else {
1087 5535 : averagedVal = averagedVal / MassFlowDependentDenominator;
1088 : }
1089 13275 : break;
1090 13275 : case SYSTEMOUTPUTS::MIXED_AIR_HR:
1091 13275 : if (MassFlowDependentDenominator == 0) {
1092 7740 : averagedVal = StandbyMode.Mixed_Air_W;
1093 : } else {
1094 5535 : averagedVal = averagedVal / MassFlowDependentDenominator;
1095 : }
1096 13275 : break;
1097 92925 : default:
1098 92925 : break;
1099 : }
1100 318600 : return averagedVal;
1101 : }
1102 :
1103 100929 : Real64 Model::CalculatePartRuntimeFraction(Real64 MinOA_Msa,
1104 : Real64 Mvent,
1105 : Real64 RequestedCoolingLoad,
1106 : Real64 RequestedHeatingLoad,
1107 : Real64 SensibleRoomORZone,
1108 : Real64 RequestedDehumidificationLoad,
1109 : Real64 RequestedMoistureLoad,
1110 : Real64 LatentRoomORZone)
1111 : {
1112 : // SUBROUTINE INFORMATION:
1113 : // AUTHOR Spencer Maxwell Dutton
1114 : // DATE WRITTEN October 2017
1115 : // MODIFIED
1116 : // RE-ENGINEERED na
1117 :
1118 : // PURPOSE OF THIS SUBROUTINE:
1119 : // Calculates the minimum runtime fraction in a given setting needed to meet the
1120 : // sensible cooling, sensible heating, dehumidification and humidification loads
1121 : // and ventilation loads.
1122 :
1123 : // METHODOLOGY EMPLOYED:
1124 : // Calculate the minimum runtime fractions for each load that needs to be met and find the lowest of those runtime fractions.
1125 : // Go through each of the requirements (ventilation, heating, cooling, dehumidification, humidification and work out what the minimum runtime
1126 : // fraction you would need in order to meet all these requirements. Importantly the SensibleRoomORZone is either (-) for heating or (+) for
1127 : // cooling, where as the RequestedCoolingLoad and RequestedHeatingLoad, are both positive (never below 0).
1128 :
1129 : // REFERENCES:
1130 : // na
1131 :
1132 : // Using/Aliasing
1133 : Real64 PLHumidRatio, PLDehumidRatio, PLVentRatio, PLSensibleCoolingRatio, PLSensibleHeatingRatio, PartRuntimeFraction;
1134 100929 : PLHumidRatio = PLDehumidRatio = PLVentRatio = PLSensibleCoolingRatio = PLSensibleHeatingRatio = 0;
1135 :
1136 100929 : if (Mvent > 0) {
1137 100929 : PLVentRatio = MinOA_Msa / Mvent;
1138 : }
1139 100929 : PartRuntimeFraction = PLVentRatio;
1140 :
1141 100929 : if (SensibleRoomORZone > 0) {
1142 67087 : PLSensibleCoolingRatio = std::abs(RequestedCoolingLoad) / std::abs(SensibleRoomORZone);
1143 : }
1144 100929 : if (PLSensibleCoolingRatio > PartRuntimeFraction) {
1145 40465 : PartRuntimeFraction = PLSensibleCoolingRatio;
1146 : }
1147 :
1148 100929 : if (SensibleRoomORZone < 0) {
1149 33842 : PLSensibleHeatingRatio = std::abs(RequestedHeatingLoad) / std::abs(SensibleRoomORZone);
1150 : }
1151 :
1152 100929 : if (PLSensibleHeatingRatio > PartRuntimeFraction) {
1153 17310 : PartRuntimeFraction = PLSensibleHeatingRatio;
1154 : }
1155 :
1156 100929 : if (RequestedDehumidificationLoad > 0) {
1157 3326 : PLDehumidRatio = std::abs(RequestedDehumidificationLoad) / std::abs(LatentRoomORZone);
1158 : }
1159 :
1160 100929 : if (PLDehumidRatio > PartRuntimeFraction) {
1161 3318 : PartRuntimeFraction = PLDehumidRatio;
1162 : }
1163 :
1164 100929 : if (RequestedMoistureLoad > 0) {
1165 97595 : PLHumidRatio = std::abs(RequestedMoistureLoad) / std::abs(LatentRoomORZone);
1166 : }
1167 100929 : if (PLHumidRatio > PartRuntimeFraction) {
1168 94885 : PartRuntimeFraction = PLHumidRatio;
1169 : }
1170 :
1171 100929 : if (PartRuntimeFraction < 0) {
1172 0 : PartRuntimeFraction = 0;
1173 : }
1174 100929 : if (PartRuntimeFraction > 1) {
1175 93249 : PartRuntimeFraction = 1;
1176 : }
1177 :
1178 100929 : return PartRuntimeFraction;
1179 : }
1180 :
1181 13217 : int Model::SetOperatingSetting(EnergyPlusData &state, CStepInputs StepIns)
1182 : {
1183 : // SUBROUTINE INFORMATION:
1184 : // AUTHOR Spencer Dutton
1185 : // DATE WRITTEN May 2017
1186 : // MODIFIED na
1187 : // RE-ENGINEERED na
1188 :
1189 : // PURPOSE OF THIS SUBROUTINE:
1190 : // This subroutine determines the set of operating settings for the HybridUniaryHVAC
1191 : // It is called from Model::doStep, the main calculation step
1192 : // at the system time step.
1193 :
1194 : // METHODOLOGY EMPLOYED:
1195 : // 1) Clear out the set of operating settings from the previous time step.
1196 : // 2) Iterate through each operating mode and weed out modes that are not intended to operate in current environmental conditions.
1197 : // -> For each mode that is viable iterate thought the solution space and identify settings that meet the ventilation
1198 : // requirements
1199 : // -> settings that do are stored in the a container (Settings)
1200 : // 3) Iterate through all the settings in Settings
1201 : //
1202 : // 4) Calculate the setting zone sensible cooling and heating load and humidifcation and dehumidifcation.
1203 : // 5) Test to see if conditioning and humidification loads are met.
1204 : // 6) Calculate setting power consumption, use the setting delivered ventilation and loads to calculate the
1205 : // 7) minimum runtime fraction needed to meet those loads, then assuming that part runtime fraction calculate the setting part run time power
1206 : // use. 8) If the setting meets both the conditioning and humidification loads then test to see if its optimal in terms of energy use.
1207 : // ->if so, save that setting as the current optimal.
1208 : // ->if not ignore it.
1209 : // If the setting failed ot meet either the conditioning or humidification loads, then
1210 : // -> firstly check to see if no previous other setting (in this calculation step) has met both the load and humidification requirements
1211 : // -> if so
1212 : // -> check if this setting meets the conditioning load (only)
1213 : // -> if so
1214 : // ->check to see if this setting is better at meeting the dehumidification or humidification lad
1215 : // than any previous setting this step.
1216 : // -> if its not, ignore it.
1217 : // -> if not
1218 : // ->check to see if any previous setting met the conditioning load
1219 : // ->if not:
1220 : // ->see if this setting is better at meeting the conditioning load than
1221 : // any previous setting this calculation step.
1222 : // -> if so save as current optimal
1223 : // -> if its not, ignore it.
1224 : // -> if so: then ignore it.
1225 : // ->if not, then a previous setting is better than this one by default, and so ignore it.
1226 : // 9) Identify error states if the no setting meets the environmental conditions, or the supply air humidity or temperature constraints.
1227 : // 10) if we met the load set operating settings to be a combination of the optimal setting at the minium required runtime fraction
1228 : // 11) if we partly met the load then do the best we can and run full out in that optimal setting.
1229 : // 12) if we didn't even partially meet the load make sure the operational settings are just the standby mode.
1230 : // 13) generate summary statistics for warnings.
1231 :
1232 : // REFERENCES:
1233 : // na
1234 :
1235 : // Using/Aliasing
1236 :
1237 : // Locals
1238 : // SUBROUTINE ARGUMENT DEFINITIONS:
1239 : // The CStepInputs are defined in the CStepInputs class definition.
1240 : // SUBROUTINE PARAMETER DEFINITIONS:
1241 : // na
1242 : // INTERFACE BLOCK SPECIFICATIONS
1243 : // na
1244 : // DERIVED TYPE DEFINITIONS
1245 : // na
1246 :
1247 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1248 13217 : bool DidWeMeetLoad = false;
1249 13217 : bool DidWeMeetHumidificaiton = false;
1250 13217 : bool DidWePartlyMeetLoad = false;
1251 13217 : Real64 OptimalSetting_RunFractionTotalFuel = IMPLAUSIBLE_POWER;
1252 : Real64 Tma;
1253 : Real64 Wma;
1254 : Real64 Hsa;
1255 : Real64 Hma;
1256 13217 : Real64 PreviousMaxiumConditioningOutput = 0;
1257 13217 : Real64 PreviousMaxiumHumidOrDehumidOutput = 0;
1258 13217 : std::string ObjectID = Name.c_str();
1259 13217 : if (StepIns.RHosa > 1) {
1260 0 : ShowSevereError(state,
1261 0 : format("Unitary hybrid system error, required relative humidity value 0-1, called in object{}.Check inputs", ObjectID));
1262 : assert(true);
1263 0 : return -1;
1264 : } // because it should be fractional, this should only really be possible if its called from a unit test
1265 :
1266 13217 : if (StepIns.RHra > 1) {
1267 0 : ShowSevereError(state,
1268 0 : format("Unitary hybrid system error, required relative humidity value 0-1, called in object{}.Check inputs", ObjectID));
1269 : assert(true);
1270 0 : return -1;
1271 : } // because it should be fractional, this should only really be possible if its called from a unit test
1272 :
1273 13217 : Real64 Wosa = PsyWFnTdbRhPb(state, StepIns.Tosa, StepIns.RHosa, state.dataEnvrn->OutBaroPress);
1274 13217 : Real64 Wra = PsyWFnTdbRhPb(state, StepIns.Tra, StepIns.RHra, InletPressure);
1275 : bool EnvironmentConditionsMet, EnvironmentConditionsMetOnce, MinVRMet, SAT_OC_Met, SAT_OC_MetOnce, SARH_OC_Met, SAHR_OC_MetOnce;
1276 13217 : EnvironmentConditionsMetOnce = SAT_OC_Met = SAT_OC_MetOnce = SARH_OC_Met = SAHR_OC_MetOnce = false;
1277 :
1278 13217 : MinOA_Msa = StepIns.MinimumOA; // Set object version of minimum VR Kg/s
1279 :
1280 92519 : for (std::vector<CMode>::const_iterator iterator = OperatingModes.begin() + 1; iterator != OperatingModes.end();
1281 66085 : ++iterator) // iterate though the modes.
1282 : {
1283 66085 : CMode Mode = *iterator;
1284 66085 : bool SAHR_OC_MetinMode = false;
1285 66085 : bool SAT_OC_MetinMode = false;
1286 66085 : int solution_map_sizeX = Mode.sol.MassFlowRatio.size();
1287 66085 : int solution_map_sizeY = Mode.sol.OutdoorAirFraction.size();
1288 :
1289 : // Check that in this mode the //Outdoor Air Relative Humidity(0 - 100 % ) //Outdoor Air Humidity Ratio(g / g)//Outdoor Air
1290 : // Temperature(degC)
1291 66085 : if (Mode.MeetsOAEnvConstraints(StepIns.Tosa, Wosa, 100 * StepIns.RHosa)) {
1292 66085 : EnvironmentConditionsMet = EnvironmentConditionsMetOnce = true;
1293 : } else {
1294 0 : EnvironmentConditionsMet = false;
1295 : }
1296 :
1297 66085 : if (EnvironmentConditionsMet) {
1298 436161 : for (int indexMassFlowRatio = 0; indexMassFlowRatio < solution_map_sizeX;
1299 : indexMassFlowRatio++) // within each mode go though all the combinations of solution spaces.
1300 : {
1301 740152 : for (int indexOutdoorAirFraction = 0; indexOutdoorAirFraction < solution_map_sizeY; indexOutdoorAirFraction++) {
1302 : // Supply Air Mass Flow Rate(kg / s)
1303 : // Outdoor Air Fraction(0 - 1)
1304 :
1305 370076 : Real64 MsaRatio = Mode.sol.MassFlowRatio[indexMassFlowRatio]; // fractions of rated mass flow rate, so for some modes this
1306 : // might be low but others hi
1307 370076 : Real64 OSAF = Mode.sol.OutdoorAirFraction[indexOutdoorAirFraction];
1308 370076 : Real64 ScaledMsa = ScaledSystemMaximumSupplyAirMassFlowRate * MsaRatio;
1309 370076 : Real64 UnscaledMsa = ScaledSystemMaximumSupplyAirMassFlowRate / ScalingFactor;
1310 370076 : Real64 Supply_Air_Ventilation_Volume = 0;
1311 : // Calculate the ventilation mass flow rate
1312 370076 : Real64 Mvent = ScaledMsa * OSAF;
1313 :
1314 370076 : if (state.dataEnvrn->StdRhoAir > 1) {
1315 370076 : Supply_Air_Ventilation_Volume = Mvent / state.dataEnvrn->StdRhoAir;
1316 : } else {
1317 0 : Supply_Air_Ventilation_Volume = Mvent / 1.225; // stored as volumetric flow for reporting
1318 : }
1319 :
1320 370076 : if (Mvent - MinOA_Msa > -0.000001) {
1321 221180 : MinVRMet = true;
1322 : } else {
1323 148896 : MinVRMet = false;
1324 : }
1325 :
1326 370076 : if (MinVRMet) {
1327 : // reset outside air temp and return air temp before calculating curve values for each mode
1328 221180 : StepIns.Tosa = SecInletTemp;
1329 221180 : StepIns.Tra = InletTemp;
1330 : Real64 FanPower =
1331 221180 : Mode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SUPPLY_FAN_POWER) *
1332 221180 : ScalingFactor;
1333 :
1334 : // calculate power loss to air if in mixed air stream and divide fan heat between outside air stream and return air stream
1335 221180 : if (FanHeatGain && FanHeatGainLocation == "MIXEDAIRSTREAM") {
1336 0 : PowerLossToAir = FanPower * FanHeatInAirFrac;
1337 : } else {
1338 221180 : PowerLossToAir = 0.0;
1339 : }
1340 221180 : Real64 FanHeatTempOA = PowerLossToAir / (PsyCpAirFnW(Wosa) * (ScaledMsa * OSAF));
1341 221180 : StepIns.Tosa = StepIns.Tosa + FanHeatTempOA;
1342 221180 : if (OSAF < 1.0) {
1343 0 : Real64 FanHeatTempRA = PowerLossToAir / (PsyCpAirFnW(Wra) * (ScaledMsa * (1 - OSAF)));
1344 0 : StepIns.Tra = StepIns.Tra + FanHeatTempRA;
1345 : }
1346 :
1347 : // Calculate prospective supply air temperature
1348 221180 : Tsa = Mode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, TEMP_CURVE);
1349 : // Calculate prospective supply air Humidity Ratio
1350 221180 : Wsa = Mode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, W_CURVE);
1351 :
1352 : // calculate power loss to supply air stream from fan power determined by curve value and fraction of fan heat in air
1353 : // stream
1354 221180 : if (FanHeatGain && FanHeatGainLocation == "SUPPLYAIRSTREAM") {
1355 0 : PowerLossToAir = FanPower * FanHeatInAirFrac;
1356 : } else {
1357 221180 : PowerLossToAir = 0.0;
1358 : }
1359 221180 : FanHeatTemp = PowerLossToAir / (PsyCpAirFnW(Wsa) * ScaledMsa);
1360 221180 : Tsa = Tsa + FanHeatTemp;
1361 :
1362 : // Check it meets constraints
1363 221180 : if (MeetsSupplyAirTOC(state, Tsa)) {
1364 100929 : SAT_OC_Met = SAT_OC_MetOnce = SAT_OC_MetinMode = true;
1365 : } else {
1366 120251 : SAT_OC_Met = false;
1367 : }
1368 : // Return Air Relative Humidity(0 - 100 % ) //Return Air Humidity Ratio(g / g)
1369 221180 : if (MeetsSupplyAirRHOC(state, Wsa)) {
1370 221180 : SARH_OC_Met = SAHR_OC_MetOnce = SAHR_OC_MetinMode = true;
1371 : } else {
1372 0 : SARH_OC_Met = false;
1373 : }
1374 :
1375 221180 : if (SARH_OC_Met && SAT_OC_Met) {
1376 100929 : CSetting CandidateSetting;
1377 100929 : CandidateSetting.Supply_Air_Ventilation_Volume = Supply_Air_Ventilation_Volume;
1378 100929 : CandidateSetting.Mode = Mode.ModeID;
1379 100929 : CandidateSetting.Outdoor_Air_Fraction = OSAF;
1380 100929 : CandidateSetting.Supply_Air_Mass_Flow_Rate_Ratio = MsaRatio;
1381 100929 : CandidateSetting.Unscaled_Supply_Air_Mass_Flow_Rate = UnscaledMsa;
1382 100929 : CandidateSetting.ScaledSupply_Air_Mass_Flow_Rate = ScaledMsa;
1383 :
1384 : // If no load is requested but ventilation is required, set the supply air mass flow rate to the minimum of the
1385 : // required ventilation flow rate and the maximum supply air flow rate
1386 100929 : if (!CoolingRequested && !HeatingRequested && !DehumidificationRequested && !HumidificationRequested) {
1387 4 : CandidateSetting.ScaledSupply_Air_Mass_Flow_Rate =
1388 4 : min(MinOA_Msa, CandidateSetting.ScaledSupply_Air_Mass_Flow_Rate);
1389 : // add fan heat if not included in lookup tables for supply air stream
1390 4 : Tsa = StepIns.Tosa + FanHeatTemp;
1391 : }
1392 :
1393 100929 : CandidateSetting.ScaledSupply_Air_Ventilation_Volume =
1394 100929 : CandidateSetting.ScaledSupply_Air_Mass_Flow_Rate / state.dataEnvrn->StdRhoAir;
1395 100929 : CandidateSetting.oMode = Mode;
1396 100929 : CandidateSetting.SupplyAirTemperature = Tsa;
1397 100929 : CandidateSetting.SupplyAirW = CheckVal_W(state, Wsa, Tsa, OutletPressure);
1398 100929 : CandidateSetting.Mode = Mode.ModeID;
1399 100929 : Settings.push_back(CandidateSetting);
1400 100929 : }
1401 : }
1402 : }
1403 : }
1404 : }
1405 66085 : if (!state.dataGlobal->WarmupFlag) {
1406 : // Keep an account of the number of times the supply air temperature and humidity constraints were not met for a given mode but only
1407 : // do this when its not warmup.
1408 9310 : if (!SAT_OC_MetinMode) {
1409 5820 : SAT_OC_MetinMode_v[Mode.ModeID] = SAT_OC_MetinMode_v[Mode.ModeID] + 1;
1410 : }
1411 9310 : if (!SAHR_OC_MetinMode) {
1412 1732 : SAHR_OC_MetinMode_v[Mode.ModeID] = SAHR_OC_MetinMode_v[Mode.ModeID] + 1;
1413 : }
1414 : }
1415 79302 : }
1416 :
1417 114146 : for (auto &thisSetting : Settings) {
1418 : // Calculate the delta H
1419 100929 : Real64 OSAF = thisSetting.Outdoor_Air_Fraction;
1420 100929 : Real64 UnscaledMsa = thisSetting.Unscaled_Supply_Air_Mass_Flow_Rate;
1421 100929 : Real64 ScaledMsa = thisSetting.ScaledSupply_Air_Mass_Flow_Rate;
1422 :
1423 : // send the scaled Msa to calculate energy and the unscaled for sending to curves.
1424 100929 : Tsa = thisSetting.SupplyAirTemperature;
1425 100929 : Wsa = thisSetting.SupplyAirW;
1426 100929 : Tma = StepIns.Tra + OSAF * (StepIns.Tosa - StepIns.Tra);
1427 100929 : Wma = Wra + OSAF * (Wosa - Wra);
1428 100929 : thisSetting.Mixed_Air_Temperature = Tma;
1429 100929 : thisSetting.Mixed_Air_W = Wma;
1430 :
1431 100929 : Hma = PsyHFnTdbW(Tma, Wma);
1432 : // Calculate Enthalpy of return air
1433 100929 : Real64 Hra = PsyHFnTdbW(StepIns.Tra, Wra);
1434 :
1435 100929 : Hsa = PsyHFnTdbW(Tsa, Wsa);
1436 :
1437 100929 : Real64 SupplyAirCp = PsyCpAirFnW(Wsa); // J/degreesK.kg
1438 100929 : Real64 ReturnAirCP = PsyCpAirFnW(Wra); // J/degreesK.kg
1439 100929 : Real64 OutdoorAirCP = PsyCpAirFnW(Wosa); // J/degreesK.kg
1440 :
1441 : // Calculations below of system cooling and heating capacity are ultimately reassessed when the resultant part runtime fraction is
1442 : // assessed. However its valuable that they are calculated here to at least provide a check.
1443 :
1444 : // System Sensible Cooling{ W } = m'SA {kg/s} * 0.5*(cpRA + OSAF*(cpOSA-cpRA) + cpSA) {kJ/kg-C} * (T_RA + OSAF*(T_OSA - T_RA) - T_SA)
1445 : // System Latent Cooling{ W } = m'SAdryair {kg/s} * L {kJ/kgWater} * (HR_RA + OSAF *(HR_OSA - HR_RA) - HR_SA) {kgWater/kgDryAir}
1446 : // System Total Cooling{ W } = m'SAdryair {kg/s} * (h_RA + OSAF*(h_OSA - h_RA) - h_SA) {kJ/kgDryAir}
1447 100929 : Real64 SystemCp = ReturnAirCP + OSAF * (OutdoorAirCP - ReturnAirCP) + SupplyAirCp; // J/degreesK.kg
1448 100929 : Real64 SensibleSystem = ScaledMsa * 0.5 * SystemCp * (Tma - Tsa); // W dynamic cp
1449 100929 : Real64 MsaDry = ScaledMsa * (1 - Wsa);
1450 100929 : Real64 LambdaSa = Psychrometrics::PsyHfgAirFnWTdb(0, Tsa);
1451 100929 : Real64 LatentSystem = LambdaSa * MsaDry * (Wma - Wsa); // W
1452 : // Total system cooling
1453 100929 : thisSetting.TotalSystem = (Hma - Hsa) * ScaledMsa;
1454 : // Perform latent check
1455 : // Real64 latentCheck = TotalSystem - SensibleSystem;
1456 :
1457 : // Zone Sensible Cooling{ W } = m'SA {kg/s} * 0.5*(cpRA+cpSA) {kJ/kg-C} * (T_RA - T_SA) {C}
1458 : // Zone Latent Cooling{ W } = m'SAdryair {kg/s} * L {kJ/kgWater} * (HR_RA - HR_SA) {kgWater/kgDryAir}
1459 : // Zone Total Cooling{ W } = m'SAdryair {kg/s} * (h_RA - h_SA) {kJ/kgDryAir}
1460 100929 : Real64 SensibleRoomORZone = ScaledMsa * 0.5 * (SupplyAirCp + ReturnAirCP) * (StepIns.Tra - Tsa); // W dynamic cp
1461 100929 : Real64 latentRoomORZone = LambdaSa * MsaDry * (Wra - Wsa); // W
1462 : // Total room cooling
1463 100929 : Real64 TotalRoomORZone = (Hra - Hsa) * ScaledMsa; // W
1464 : // Perform latent check
1465 : // Real64 latentRoomORZoneCheck = TotalRoomORZone - SensibleRoomORZone;
1466 :
1467 100929 : thisSetting.SensibleSystem = SensibleSystem;
1468 100929 : thisSetting.LatentSystem = LatentSystem;
1469 100929 : thisSetting.TotalZone = TotalRoomORZone;
1470 100929 : thisSetting.SensibleZone = SensibleRoomORZone;
1471 100929 : thisSetting.LatentZone = latentRoomORZone;
1472 :
1473 100929 : bool Conditioning_load_met = false;
1474 100929 : if (CoolingRequested && (SensibleRoomORZone > StepIns.RequestedCoolingLoad)) {
1475 14048 : Conditioning_load_met = true;
1476 : }
1477 100929 : if (HeatingRequested && (SensibleRoomORZone < StepIns.RequestedHeatingLoad)) {
1478 0 : Conditioning_load_met = true;
1479 : }
1480 100929 : if (!(HeatingRequested || CoolingRequested)) {
1481 42507 : Conditioning_load_met = true;
1482 : }
1483 :
1484 100929 : bool Humidification_load_met = false;
1485 :
1486 100929 : Real64 RequestedDeHumdificationLoad = StepIns.ZoneDehumidificationLoad;
1487 100929 : if (DehumidificationRequested && latentRoomORZone > RequestedDeHumdificationLoad) {
1488 4 : Humidification_load_met = true;
1489 : }
1490 100929 : Real64 RequestedHumdificationLoad = StepIns.ZoneMoistureLoad;
1491 100929 : if (HumidificationRequested && latentRoomORZone < RequestedHumdificationLoad) {
1492 97595 : Humidification_load_met = true;
1493 : }
1494 :
1495 100929 : if (!(HumidificationRequested || DehumidificationRequested)) {
1496 3326 : Humidification_load_met = true;
1497 : }
1498 :
1499 100929 : thisSetting.ElectricalPower = thisSetting.oMode.CalculateCurveVal(
1500 : state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, POWER_CURVE); // [Kw] calculations for fuel in Kw
1501 100929 : thisSetting.SupplyFanElectricPower =
1502 100929 : thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SUPPLY_FAN_POWER);
1503 100929 : thisSetting.ExternalStaticPressure =
1504 100929 : thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, EXTERNAL_STATIC_PRESSURE);
1505 100929 : thisSetting.SecondaryFuelConsumptionRate =
1506 100929 : thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SECOND_FUEL_USE);
1507 100929 : thisSetting.ThirdFuelConsumptionRate =
1508 100929 : thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, THIRD_FUEL_USE);
1509 100929 : thisSetting.WaterConsumptionRate =
1510 100929 : thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, WATER_USE);
1511 :
1512 : // Calculate partload fraction required to meet all requirements
1513 100929 : Real64 PartRuntimeFraction = 0;
1514 302787 : PartRuntimeFraction = CalculatePartRuntimeFraction(MinOA_Msa,
1515 100929 : thisSetting.Supply_Air_Ventilation_Volume * state.dataEnvrn->StdRhoAir,
1516 : StepIns.RequestedCoolingLoad,
1517 : StepIns.RequestedHeatingLoad,
1518 : SensibleRoomORZone,
1519 : StepIns.ZoneDehumidificationLoad,
1520 : StepIns.ZoneMoistureLoad,
1521 : latentRoomORZone); //
1522 :
1523 100929 : Real64 RunFractionTotalFuel =
1524 100929 : thisSetting.ElectricalPower * PartRuntimeFraction; // fraction can be above 1 meaning its not able to do it completely in a time step.
1525 100929 : thisSetting.Runtime_Fraction = PartRuntimeFraction;
1526 :
1527 100929 : if (Conditioning_load_met && Humidification_load_met) {
1528 : // store best performing mode
1529 56555 : if (RunFractionTotalFuel < OptimalSetting_RunFractionTotalFuel) {
1530 6288 : OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel;
1531 6288 : OptimalSetting = thisSetting;
1532 6288 : DidWeMeetLoad = true;
1533 6288 : DidWeMeetHumidificaiton = true;
1534 : }
1535 : } else {
1536 44374 : if (!DidWeMeetLoad && !DidWeMeetHumidificaiton) {
1537 30298 : bool store_best_attempt = false;
1538 :
1539 30298 : if (Conditioning_load_met) {
1540 0 : DidWeMeetLoad = true;
1541 0 : if (HumidificationRequested && (latentRoomORZone < PreviousMaxiumHumidOrDehumidOutput)) {
1542 0 : store_best_attempt = true;
1543 : }
1544 0 : if (DehumidificationRequested && (latentRoomORZone > PreviousMaxiumHumidOrDehumidOutput)) {
1545 0 : store_best_attempt = true;
1546 : }
1547 0 : if (store_best_attempt) {
1548 0 : PreviousMaxiumHumidOrDehumidOutput = latentRoomORZone;
1549 : }
1550 : } else {
1551 30298 : if (!DidWeMeetLoad) {
1552 30298 : if (CoolingRequested && (SensibleRoomORZone > PreviousMaxiumConditioningOutput)) {
1553 1142 : store_best_attempt = true;
1554 : }
1555 30298 : if (HeatingRequested && (SensibleRoomORZone < PreviousMaxiumConditioningOutput)) {
1556 0 : store_best_attempt = true;
1557 : }
1558 30298 : if (store_best_attempt) {
1559 1142 : PreviousMaxiumConditioningOutput = SensibleRoomORZone;
1560 : }
1561 : }
1562 : }
1563 30298 : if (store_best_attempt) {
1564 1142 : OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel;
1565 1142 : OptimalSetting = thisSetting;
1566 1142 : DidWePartlyMeetLoad = true;
1567 : }
1568 : }
1569 : }
1570 13217 : }
1571 :
1572 13217 : if (!EnvironmentConditionsMetOnce) {
1573 0 : ErrorCode = 1;
1574 0 : count_EnvironmentConditionsNotMet++;
1575 : }
1576 13217 : if (!SAHR_OC_MetOnce) {
1577 0 : count_SAHR_OC_MetOnce++;
1578 0 : ErrorCode = 2;
1579 : }
1580 13217 : if (!SAT_OC_MetOnce) {
1581 0 : count_SAT_OC_MetOnce++;
1582 0 : ErrorCode = 3;
1583 : }
1584 : // if we met the load set operating settings to be a combination of the optimal setting at the minium required runtime fraction
1585 13217 : if (DidWeMeetLoad) {
1586 : // add first setting to operating modes
1587 4393 : ErrorCode = 0;
1588 : // save the optimal setting in the
1589 4393 : CurrentOperatingSettings[0] = OptimalSetting;
1590 4393 : PrimaryModeRuntimeFraction = OptimalSetting.Runtime_Fraction;
1591 4393 : oStandBy.Runtime_Fraction = (1 - PrimaryModeRuntimeFraction);
1592 4393 : if (oStandBy.Runtime_Fraction < 0) {
1593 0 : oStandBy.Runtime_Fraction = 0;
1594 : }
1595 4393 : CurrentOperatingSettings[1] = oStandBy;
1596 : } else {
1597 : // if we partly met the load then do the best we can and run full out in that optimal setting.
1598 8824 : if (!DidWeMeetLoad && DidWePartlyMeetLoad) {
1599 1142 : ErrorCode = 0;
1600 1142 : count_DidWeNotMeetLoad++;
1601 1142 : if (OptimalSetting.ElectricalPower == IMPLAUSIBLE_POWER) {
1602 0 : ShowWarningError(state, "Model was not able to provide cooling for a time step, called in HybridEvapCooling:dostep");
1603 0 : OptimalSetting.ElectricalPower = 0;
1604 : }
1605 1142 : OptimalSetting.Runtime_Fraction = 1;
1606 1142 : CurrentOperatingSettings[0] = OptimalSetting;
1607 1142 : PrimaryMode = OptimalSetting.Mode;
1608 1142 : PrimaryModeRuntimeFraction = 1;
1609 : }
1610 : // if we didn't even partially meet the load make sure the operational settings are just the standby mode.
1611 : else {
1612 7682 : oStandBy.Runtime_Fraction = 1;
1613 7682 : CurrentOperatingSettings[0] = oStandBy;
1614 7682 : ErrorCode = -1;
1615 7682 : StandBy = true;
1616 7682 : count_DidWeNotMeetLoad++;
1617 : }
1618 : }
1619 :
1620 : Real64 TimeElapsed =
1621 13217 : state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
1622 :
1623 : // Use the elapsed time to only give a summary of warnings related to the number of Timesteps environmental conditions, or supply air
1624 : // temperature constraints were not met for a given day. ideally there would be a clear flag that indicates "this is the last timestep of the
1625 : // day, so report", but that doesn't seem to exist.
1626 13217 : if ((TimeElapsed > 24) && WarnOnceFlag && !state.dataGlobal->WarmupFlag) {
1627 2 : if (count_EnvironmentConditionsNotMet > 0)
1628 0 : ShowWarningError(state,
1629 0 : format("In day {:.1R} was unable to operate for of simulation, {}{:.1R} timesteps because environment conditions "
1630 : "were beyond the allowable operating range for any mode.",
1631 0 : (Real64)state.dataGlobal->DayOfSim,
1632 0 : Name,
1633 0 : (Real64)count_EnvironmentConditionsNotMet));
1634 2 : if (count_SAHR_OC_MetOnce > 0)
1635 0 : ShowWarningError(state,
1636 0 : format("In day {:.1R} of simulation, {} failed to meet supply air humidity ratio for {:.1R} time steps. For these "
1637 : "time steps For these time steps was set to mode 0{}",
1638 0 : (Real64)state.dataGlobal->DayOfSim,
1639 0 : Name,
1640 0 : Real64(count_SAHR_OC_MetOnce),
1641 0 : Name));
1642 2 : if (count_SAT_OC_MetOnce > 0)
1643 0 : ShowWarningError(state,
1644 0 : format("In day {:.1R} of simulation, {} failed to meet supply air temperature constraints for {:.1R} time steps. "
1645 : "For these time steps For these time steps{} was set to mode 0",
1646 0 : (Real64)state.dataGlobal->DayOfSim,
1647 0 : Name,
1648 0 : Real64(count_SAT_OC_MetOnce),
1649 0 : Name));
1650 :
1651 4 : ShowWarningError(state,
1652 4 : format("In day {:.1R} of simulation, {} failed to satisfy sensible load for {:.1R} time steps. For these time steps "
1653 : "settings were selected to provide as much sensible cooling or heating as possible, given other constraints.",
1654 2 : (Real64)state.dataGlobal->DayOfSim,
1655 2 : Name,
1656 2 : (Real64)count_DidWeNotMeetLoad));
1657 :
1658 2 : count_SAT_OC_MetOnce = 0;
1659 2 : count_DidWeNotMeetLoad = 0;
1660 2 : count_SAHR_OC_MetOnce = 0;
1661 2 : count_EnvironmentConditionsMetOnce = 0;
1662 2 : count_EnvironmentConditionsNotMet = 0;
1663 2 : WarnOnceFlag = false;
1664 : }
1665 13217 : if (state.dataGlobal->HourOfDay == 1 && !WarnOnceFlag && !state.dataGlobal->WarmupFlag) {
1666 2 : WarnOnceFlag = true;
1667 : }
1668 13217 : return ErrorCode;
1669 13217 : }
1670 :
1671 5535 : int Model::CurrentPrimaryMode()
1672 : {
1673 : // SUBROUTINE INFORMATION:
1674 : // AUTHOR Spencer Maxwell Dutton
1675 : // DATE WRITTEN October 2017
1676 : // MODIFIED
1677 : // RE-ENGINEERED na
1678 :
1679 : // PURPOSE OF THIS SUBROUTINE:
1680 : // retunrs the primary mode of operation
1681 :
1682 : // METHODOLOGY EMPLOYED:
1683 : //
1684 :
1685 : // REFERENCES:
1686 : // na
1687 :
1688 : // Using/Aliasing
1689 :
1690 5535 : if (CurrentOperatingSettings.size() > 0) {
1691 5535 : return CurrentOperatingSettings[0].Mode;
1692 : } else
1693 0 : return -1;
1694 : }
1695 5535 : Real64 Model::CurrentPrimaryRuntimeFraction()
1696 : {
1697 : // SUBROUTINE INFORMATION:
1698 : // AUTHOR Spencer Maxwell Dutton
1699 : // DATE WRITTEN October 2017
1700 : // MODIFIED
1701 : // RE-ENGINEERED na
1702 :
1703 : // PURPOSE OF THIS SUBROUTINE:
1704 : // returns the runtime fraction of the primary setting.
1705 :
1706 : // METHODOLOGY EMPLOYED:
1707 : //
1708 :
1709 : // REFERENCES:
1710 : // na
1711 :
1712 : // Using/Aliasing
1713 5535 : if (CurrentOperatingSettings.size() > 0) {
1714 5535 : return CurrentOperatingSettings[0].Runtime_Fraction;
1715 : } else
1716 0 : return -1;
1717 : }
1718 13275 : void Model::DetermineCoolingVentilationOrHumidificationNeeds(CStepInputs &StepIns)
1719 : {
1720 : // SUBROUTINE INFORMATION:
1721 : // AUTHOR Spencer Maxwell Dutton
1722 : // DATE WRITTEN October 2017
1723 : // MODIFIED
1724 : // RE-ENGINEERED na
1725 :
1726 : // PURPOSE OF THIS SUBROUTINE:
1727 : // Sets member boolean variables to establish if the Cooling, Heating, ventilation or dehumidifcation needs are met.
1728 :
1729 : // METHODOLOGY EMPLOYED:
1730 : //
1731 :
1732 : // REFERENCES:
1733 : // na
1734 :
1735 : // Using/Aliasing
1736 13275 : CoolingRequested = false;
1737 13275 : HeatingRequested = false;
1738 13275 : VentilationRequested = false;
1739 13275 : DehumidificationRequested = false;
1740 13275 : HumidificationRequested = false;
1741 : // establish if conditioning needed
1742 13275 : if (StepIns.RequestedCoolingLoad >= MINIMUM_LOAD_TO_ACTIVATE) {
1743 2656 : CoolingRequested = true;
1744 2656 : StepIns.RequestedHeatingLoad = 0;
1745 : }
1746 13275 : if (StepIns.RequestedHeatingLoad <= -MINIMUM_LOAD_TO_ACTIVATE) {
1747 7682 : HeatingRequested = true;
1748 7682 : StepIns.RequestedCoolingLoad = 0;
1749 : }
1750 : // establish if ventilation needed
1751 13275 : if (StepIns.MinimumOA > 0) VentilationRequested = true;
1752 : // Load required to meet dehumidifying setpoint (<0 = a dehumidify load) [kgWater/s]
1753 13275 : if (StepIns.ZoneDehumidificationLoad < 0) {
1754 4 : DehumidificationRequested = true;
1755 4 : StepIns.ZoneMoistureLoad = 0;
1756 : }
1757 : // Load required to meet humidifying setpoint (>0 = a humidify load) [kgWater/s]
1758 13275 : if (StepIns.ZoneMoistureLoad > 0) {
1759 12333 : StepIns.ZoneDehumidificationLoad = 0;
1760 12333 : HumidificationRequested = true;
1761 : }
1762 13275 : }
1763 :
1764 : // doStep is passed some variables that could have just used the class members, but this adds clarity about whats needed, especially helpful in
1765 : // unit testing
1766 13275 : void Model::doStep(EnergyPlusData &state,
1767 : Real64 RequestedCoolingLoad, // in joules, cooling load as negitive
1768 : Real64 RequestedHeatingLoad, // in joules, heating load as positive
1769 : Real64 OutputRequiredToHumidify, // Load required to meet humidifying setpoint (>0 = a humidify load) [kgWater/s]
1770 : Real64 OutputRequiredToDehumidify, // Load required to meet dehumidifying setpoint (<0 = a dehumidify load) [kgWater/s]
1771 : Real64 DesignMinVR) // mass flow rate of design ventilation air kg/s
1772 : {
1773 : // SUBROUTINE INFORMATION:
1774 : // AUTHOR Spencer Dutton
1775 : // DATE WRITTEN May 2017
1776 : // MODIFIED na
1777 : // RE-ENGINEERED na
1778 :
1779 : // PURPOSE OF THIS SUBROUTINE:
1780 : // This subroutine Model::doStep, the main calculation steps
1781 : // 1)Collate required inputs into a CStepInputs, this helps with the unit tests
1782 : // so we always know what values need to be set.
1783 : // 2)Calculate W humidity ratios for outdoor air and return air.
1784 : // 3)Sets boolean values for each potential conditioning requirement;
1785 : // CoolingRequested, HeatingRequested, VentilationRequested, DehumidificationRequested, HumidificationRequested
1786 : // 4)Take the first operating mode which is always standby and calculate the use curves to determine performance metrics for
1787 : // the standby mode including energy use and other outputs
1788 : // 5)Test system availbility status and go into standby if unit is off or not needed (booleans listed in 3 are all false)
1789 : // 6) Set the operating conditions and respective part load fractions.
1790 : // 7) Set timestep average outlet condition, considering all operating conditions and runtimes.
1791 : // METHODOLOGY EMPLOYED:
1792 : // na
1793 :
1794 : // REFERENCES: OutletVolumetricFlowRate, SupplyVentilationVolume, MinOA_Msa, SupplyVentilationAir
1795 : // na
1796 :
1797 : // set requested loads to output variables
1798 13275 : RequestedLoadToHeatingSetpoint = RequestedHeatingLoad;
1799 13275 : RequestedLoadToCoolingSetpoint = RequestedCoolingLoad;
1800 13275 : Real64 LambdaRa = Psychrometrics::PsyHfgAirFnWTdb(0, InletTemp);
1801 13275 : RequestedHumdificationMass = OutputRequiredToHumidify;
1802 13275 : RequestedHumdificationLoad = OutputRequiredToHumidify * LambdaRa; // [W];
1803 13275 : RequestedHumdificationEnergy = OutputRequiredToHumidify * LambdaRa * state.dataHVACGlobal->TimeStepSysSec; // [j]
1804 :
1805 13275 : RequestedDeHumdificationMass = OutputRequiredToDehumidify;
1806 13275 : RequestedDeHumdificationLoad = OutputRequiredToDehumidify * LambdaRa; // [W];
1807 13275 : RequestedDeHumdificationEnergy = OutputRequiredToDehumidify * LambdaRa * state.dataHVACGlobal->TimeStepSysSec; // [j]
1808 :
1809 13275 : MinOA_Msa = DesignMinVR; // as mass flow kg/s
1810 :
1811 : // Collate all the inputs required for calculation into one local data structure CStepInputs, this helps with the unit tests so we always know
1812 : // what values need to be set
1813 13275 : CStepInputs StepIns;
1814 13275 : StepIns.Tosa = SecInletTemp; // degrees C
1815 13275 : StepIns.Tra = InletTemp; // degrees C
1816 13275 : StepIns.RHosa = SecInletRH; // RH as 0-1
1817 13275 : StepIns.RHra = InletRH;
1818 : // For historical reasons cooling is positive, heating negative throughout the calculation
1819 13275 : StepIns.RequestedCoolingLoad = -RequestedCoolingLoad; // Cooling positive now, heating negative
1820 13275 : StepIns.RequestedHeatingLoad = -RequestedHeatingLoad; // Cooling positive now, heating negative
1821 :
1822 13275 : StepIns.ZoneMoistureLoad = RequestedHumdificationLoad;
1823 13275 : StepIns.ZoneDehumidificationLoad = RequestedDeHumdificationLoad;
1824 13275 : StepIns.MinimumOA = DesignMinVR;
1825 : // calculate W humidity ratios for outdoor air and return air
1826 13275 : Real64 Wosa = PsyWFnTdbRhPb(state, StepIns.Tosa, StepIns.RHosa, state.dataEnvrn->OutBaroPress);
1827 13275 : Real64 Wra = PsyWFnTdbRhPb(state, StepIns.Tra, StepIns.RHra, InletPressure);
1828 : // Sets boolean values for each potential conditioning requirement; CoolingRequested, HeatingRequested, VentilationRequested,
1829 : // DehumidificationRequested, HumidificationRequested
1830 13275 : DetermineCoolingVentilationOrHumidificationNeeds(StepIns);
1831 : // Take the first operating mode which is always standby and calculate the curve values
1832 : // to determine performance metrics for the standby mode including energy use and other outputs
1833 :
1834 13275 : CMode Mode = *(OperatingModes.begin());
1835 13275 : if (SetStandByMode(state, Mode, StepIns.Tosa, Wosa, StepIns.Tra, Wra)) {
1836 0 : std::string ObjectID = Name.c_str();
1837 0 : ShowSevereError(state,
1838 0 : format("Standby mode not defined correctly, as the mode is defined there are zero combinations of acceptible outside air "
1839 : "fractions and supply air mass flow rate, called in object {}",
1840 : ObjectID));
1841 0 : }
1842 : // Test system availability status
1843 13275 : UnitOn = 1;
1844 13275 : bool ForceOff = false;
1845 13275 : StandBy = false;
1846 13275 : if (GetCurrentScheduleValue(state, SchedPtr) <= 0 || availStatus == Avail::Status::ForceOff) {
1847 0 : UnitOn = 0;
1848 0 : ForceOff = true;
1849 : }
1850 :
1851 : // Initialize all settings for all operating modes
1852 13275 : int size = CurrentOperatingSettings.size();
1853 13275 : CSetting empty_setting;
1854 66375 : for (int i = 1; i < size; i++) {
1855 53100 : CurrentOperatingSettings[i] = empty_setting;
1856 : }
1857 :
1858 : // Go into standby if unit is off or not needed
1859 13275 : if ((!CoolingRequested && !HeatingRequested && !VentilationRequested && !HumidificationRequested && !DehumidificationRequested) || ForceOff) {
1860 58 : StandBy = true;
1861 58 : oStandBy.Runtime_Fraction = 1;
1862 58 : CurrentOperatingSettings[0] = oStandBy;
1863 58 : ErrorCode = 0;
1864 58 : PrimaryMode = 0;
1865 58 : PrimaryModeRuntimeFraction = 0;
1866 : } else {
1867 : // set the operating conditions and respective part load fractions.
1868 13217 : ErrorCode = SetOperatingSetting(state, StepIns);
1869 : }
1870 :
1871 13275 : Real64 QTotZoneOut = 0;
1872 : // now class members QSensZoneOut = 0;
1873 : // QLatentZoneOut = 0;
1874 :
1875 13275 : Real64 QTotSystemOut = 0;
1876 13275 : Real64 QSensSystemOut = 0;
1877 13275 : Real64 QLatentSystemOut = 0;
1878 : // Even if its off or in standby we still need to continue to calculate standby loads
1879 : // All powers are calculated in Watts amd energies in Joules
1880 :
1881 13275 : SupplyVentilationVolume = CalculateTimeStepAverage(SYSTEMOUTPUTS::VENTILATION_AIR_V);
1882 13275 : if (state.dataEnvrn->StdRhoAir > 1) {
1883 13275 : SupplyVentilationAir = SupplyVentilationVolume * state.dataEnvrn->StdRhoAir;
1884 : } else {
1885 0 : SupplyVentilationAir = SupplyVentilationVolume * 1.225;
1886 : }
1887 : // set timestep average outlet condition, considering all operating conditions and runtimes.
1888 13275 : OutletTemp = CheckVal_T(state, CalculateTimeStepAverage(SYSTEMOUTPUTS::SUPPLY_AIR_TEMP));
1889 13275 : OutletHumRat = CheckVal_W(state, CalculateTimeStepAverage(SYSTEMOUTPUTS::SUPPLY_AIR_HR), OutletTemp, OutletPressure);
1890 :
1891 13275 : OutletRH = PsyRhFnTdbWPb(state, OutletTemp, OutletHumRat, OutletPressure);
1892 13275 : Real64 OperatingAverageMixedAirTemperature = CalculateTimeStepAverage(SYSTEMOUTPUTS::MIXED_AIR_TEMP);
1893 13275 : Real64 OperatingMixedAirW = CalculateTimeStepAverage(SYSTEMOUTPUTS::MIXED_AIR_HR);
1894 13275 : Real64 MixedAirEnthalpy = PsyHFnTdbW(OperatingAverageMixedAirTemperature, OperatingMixedAirW);
1895 13275 : OutletEnthalpy = PsyHFnTdbRhPb(state, OutletTemp, OutletRH, InletPressure);
1896 13275 : OutletMassFlowRate = CalculateTimeStepAverage(SYSTEMOUTPUTS::SUPPLY_MASS_FLOW);
1897 :
1898 13275 : if (state.dataEnvrn->StdRhoAir > 1) {
1899 13275 : OutletVolumetricFlowRate = OutletMassFlowRate / state.dataEnvrn->StdRhoAir;
1900 : } else {
1901 0 : OutletVolumetricFlowRate = OutletMassFlowRate / 1.225;
1902 : }
1903 :
1904 13275 : if (!StandBy) {
1905 5535 : if (OutletMassFlowRate > 0) {
1906 5535 : averageOSAF = SupplyVentilationAir / OutletMassFlowRate;
1907 : } else {
1908 0 : std::string ObjectID = Name.c_str();
1909 0 : if (CoolingRequested || HeatingRequested) {
1910 0 : ShowSevereError(
1911 : state,
1912 0 : format("Outlet air mass flow rate of zero during period with conditioning need, check mode definition. Called in object {}",
1913 0 : Name));
1914 : }
1915 0 : averageOSAF = 1;
1916 0 : }
1917 : // Calculate timestep average unit and system
1918 5535 : PrimaryMode = CurrentPrimaryMode();
1919 5535 : PrimaryModeRuntimeFraction = CurrentPrimaryRuntimeFraction();
1920 5535 : Real64 Outletcp = PsyCpAirFnW(OutletHumRat); // J/degreesK.kg
1921 5535 : Real64 Returncp = PsyCpAirFnW(Wra); // J/degreesK.kg
1922 5535 : Real64 Outdoorcp = PsyCpAirFnW(Wosa); // J/degreesK.kg
1923 : // Zone Sensible Cooling{ W } = m'SA {kg/s} * 0.5*(cpRA+cpSA) {kJ/kg-C} * (T_RA - T_SA) {C}
1924 : // Zone Latent Cooling{ W } = m'SAdryair {kg/s} * L {kJ/kgWater} * (HR_RA - HR_SA) {kgWater/kgDryAir}
1925 : // Zone Total Cooling{ W } = m'SAdryair {kg/s} * (h_RA - h_SA) {kJ/kgDryAir}
1926 5535 : QSensZoneOut = OutletMassFlowRate * 0.5 * (Returncp + Outletcp) * (StepIns.Tra - OutletTemp); // Watts
1927 5535 : Real64 OutletMassFlowRateDry = OutletMassFlowRate * (1 - Wsa);
1928 5535 : Real64 LambdaSa = Psychrometrics::PsyHfgAirFnWTdb(0, OutletTemp);
1929 5535 : QLatentZoneOutMass = OutletMassFlowRateDry * (InletHumRat - OutletHumRat); // Watts
1930 5535 : QLatentZoneOut = QLatentZoneOutMass * LambdaSa;
1931 5535 : QTotZoneOut = OutletMassFlowRateDry * (InletEnthalpy - OutletEnthalpy); // Watts
1932 5535 : Real64 QLatentCheck = QTotZoneOut - QSensZoneOut; // Watts
1933 :
1934 : // System Sensible Cooling{ W } = m'SA {kg/s} * 0.5*(cpRA + OSAF*(cpOSA-cpRA) + cpSA) {kJ/kg-C} * (T_RA + OSAF*(T_OSA - T_RA) - T_SA)
1935 : // System Latent Cooling{ W } = m'SAdryair {kg/s} * L {kJ/kgWater} * (HR_RA + OSAF *(HR_OSA - HR_RA) - HR_SA) {kgWater/kgDryAir}
1936 : // System Total Cooling{ W } = m'SAdryair {kg/s} * (h_RA + OSAF*(h_OSA - h_RA) - h_SA) {kJ/kgDryAir}
1937 :
1938 5535 : Real64 SystemTimeStepCp = Returncp + averageOSAF * (Outdoorcp - Returncp) + Outletcp; // cpRA + OSAF*(cpOSA-cpRA) + cpSA //J/degreesK.kg
1939 5535 : Real64 SystemTimeStepW = InletHumRat + averageOSAF * (Wosa - Wra) - OutletHumRat; // HR_RA + OSAF *(HR_OSA - HR_RA) - HR_SA
1940 5535 : Real64 SystemTimeStepT = StepIns.Tra + averageOSAF * (StepIns.Tosa - StepIns.Tra) - OutletTemp; // T_RA + OSAF *(T_OSA - T_RA) - T_SA
1941 5535 : QSensSystemOut = 0.5 * SystemTimeStepCp * OutletMassFlowRate * SystemTimeStepT; // Watts
1942 :
1943 5535 : QLatentSystemOut = LambdaSa * OutletMassFlowRateDry * SystemTimeStepW; // Watts
1944 5535 : QTotSystemOut = OutletMassFlowRateDry * (MixedAirEnthalpy - OutletEnthalpy); // Watts
1945 5535 : QLatentCheck = QTotSystemOut - QSensSystemOut; // Watts
1946 :
1947 : // reset outputs
1948 5535 : ResetOutputs();
1949 : // set UNIT outputs for cooling and heating
1950 5535 : if (QTotZoneOut > 0) // zone cooling is positive, else remain zero
1951 : {
1952 4044 : UnitTotalCoolingRate = std::abs(QTotZoneOut); // Watts
1953 4044 : UnitTotalCoolingEnergy = UnitTotalCoolingRate * state.dataHVACGlobal->TimeStepSysSec; // J
1954 : } else {
1955 1491 : UnitTotalHeatingRate = std::abs(QTotZoneOut); // Watts
1956 1491 : UnitTotalHeatingEnergy = UnitTotalHeatingRate * state.dataHVACGlobal->TimeStepSysSec; // J
1957 : }
1958 :
1959 5535 : if (QSensZoneOut > 0) // zone cooling is positive, else remain zero
1960 : {
1961 4039 : UnitSensibleCoolingRate = std::abs(QSensZoneOut); // Watts
1962 4039 : UnitSensibleCoolingEnergy = UnitSensibleCoolingRate * state.dataHVACGlobal->TimeStepSysSec; // J
1963 : } else {
1964 1496 : UnitSensibleHeatingRate = std::abs(QSensZoneOut); // Watts
1965 1496 : UnitSensibleHeatingEnergy = UnitSensibleHeatingRate * state.dataHVACGlobal->TimeStepSysSec; // J
1966 : }
1967 :
1968 5535 : if ((UnitTotalCoolingRate - UnitSensibleCoolingRate) > 0) {
1969 1654 : UnitLatentCoolingRate = UnitTotalCoolingRate - UnitSensibleCoolingRate; // Watts
1970 1654 : UnitLatentCoolingEnergy = UnitTotalCoolingEnergy - UnitSensibleCoolingEnergy; // J
1971 : }
1972 5535 : if ((UnitTotalCoolingRate - UnitSensibleCoolingRate) < 0) {
1973 2395 : UnitLatentHeatingRate = UnitTotalHeatingRate - UnitSensibleHeatingRate; // Watts
1974 2395 : UnitLatentHeatingEnergy = UnitTotalHeatingEnergy - UnitSensibleHeatingEnergy; // J
1975 : }
1976 :
1977 : // set SYSTEM outputs
1978 5535 : if (QTotSystemOut > 0) // system cooling
1979 : {
1980 3032 : SystemTotalCoolingRate = std::abs(QTotSystemOut);
1981 3032 : SystemTotalCoolingEnergy = SystemTotalCoolingRate * state.dataHVACGlobal->TimeStepSysSec;
1982 : } else {
1983 2503 : SystemTotalHeatingRate = std::abs(QTotSystemOut);
1984 2503 : SystemTotalHeatingEnergy = SystemTotalHeatingRate * state.dataHVACGlobal->TimeStepSysSec;
1985 : }
1986 :
1987 5535 : if (QSensSystemOut > 0) // system sensible cooling
1988 : {
1989 3030 : SystemSensibleCoolingRate = std::abs(QSensSystemOut);
1990 3030 : SystemSensibleCoolingEnergy = SystemSensibleCoolingRate * state.dataHVACGlobal->TimeStepSysSec;
1991 : } else {
1992 2505 : SystemSensibleHeatingRate = std::abs(QSensSystemOut);
1993 2505 : SystemSensibleHeatingEnergy = SystemSensibleHeatingRate * state.dataHVACGlobal->TimeStepSysSec;
1994 : }
1995 5535 : if ((SystemTotalCoolingRate - SystemSensibleCoolingRate) > 0) {
1996 408 : SystemLatentCoolingRate = SystemTotalCoolingRate - SystemSensibleCoolingRate;
1997 408 : SystemLatentCoolingEnergy = SystemTotalCoolingEnergy - SystemSensibleCoolingEnergy;
1998 : }
1999 5535 : if ((SystemTotalHeatingRate - SystemSensibleHeatingRate) < 0) {
2000 1472 : SystemLatentHeatingRate = SystemTotalHeatingRate - SystemSensibleHeatingRate;
2001 1472 : SystemLatentHeatingEnergy = SystemTotalHeatingEnergy - SystemSensibleHeatingEnergy;
2002 : }
2003 : } else // unit is in standby so reset conditioning outputs
2004 : {
2005 7740 : QTotZoneOut = 0;
2006 7740 : QSensZoneOut = 0;
2007 7740 : QLatentZoneOut = 0;
2008 7740 : QLatentZoneOutMass = 0;
2009 7740 : QTotSystemOut = 0;
2010 7740 : QSensSystemOut = 0;
2011 7740 : QLatentSystemOut = 0;
2012 : // reset outputs
2013 7740 : ResetOutputs();
2014 : }
2015 :
2016 : // set timestep outputs calculated considering different runtime fractions.
2017 13275 : SupplyFanElectricPower = CalculateTimeStepAverage(SYSTEMOUTPUTS::OSUPPLY_FAN_POWER); // Watts
2018 13275 : SupplyFanElectricEnergy = SupplyFanElectricPower * state.dataHVACGlobal->TimeStepSysSec;
2019 13275 : SecondaryFuelConsumptionRate = CalculateTimeStepAverage(SYSTEMOUTPUTS::OSECOND_FUEL_USE);
2020 13275 : SecondaryFuelConsumption = SecondaryFuelConsumptionRate * state.dataHVACGlobal->TimeStepSysSec;
2021 13275 : ThirdFuelConsumptionRate = CalculateTimeStepAverage(SYSTEMOUTPUTS::OTHIRD_FUEL_USE);
2022 13275 : ThirdFuelConsumption = ThirdFuelConsumptionRate * state.dataHVACGlobal->TimeStepSysSec;
2023 13275 : WaterConsumptionRate = CalculateTimeStepAverage(SYSTEMOUTPUTS::OWATER_USE);
2024 13275 : WaterConsumption = WaterConsumptionRate * state.dataHVACGlobal->TimeStepSysSec;
2025 13275 : ExternalStaticPressure = CalculateTimeStepAverage(SYSTEMOUTPUTS::OEXTERNAL_STATIC_PRESSURE);
2026 :
2027 13275 : FinalElectricalPower = CalculateTimeStepAverage(SYSTEMOUTPUTS::SYSTEM_FUEL_USE);
2028 13275 : FinalElectricalEnergy = FinalElectricalPower * state.dataHVACGlobal->TimeStepSysSec;
2029 13275 : }
2030 :
2031 : } // namespace HybridEvapCoolingModel
2032 : } // namespace EnergyPlus
|