Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2023, 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 111690 : CMode::CMode()
108 : : 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 : Maximum_Outdoor_Air_Temperature(0.0), Minimum_Outdoor_Air_Humidity_Ratio(0.0), Maximum_Outdoor_Air_Humidity_Ratio(0.0),
110 111690 : ModelScalingFactor(0.0)
111 : {
112 111690 : MODE_BLOCK_OFFSET_Alpha = 9;
113 111690 : BLOCK_HEADER_OFFSET_Alpha = 20;
114 111690 : MODE1_BLOCK_OFFSET_Number = 2;
115 111690 : MODE_BLOCK_OFFSET_Number = 16;
116 111690 : BLOCK_HEADER_OFFSET_Number = 6;
117 111690 : }
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 1248863 : bool CMode::ValidPointer(int curve_pointer)
192 : {
193 1248863 : if (curve_pointer >= 0)
194 1031495 : return true;
195 : else
196 217368 : return false;
197 : }
198 1248863 : 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 1248863 : Real64 Y_val = 0;
229 :
230 1248863 : switch (curveType) {
231 214276 : case TEMP_CURVE:
232 214276 : if (ValidPointer(Tsa_curve_pointer)) {
233 214276 : 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 214276 : break;
238 :
239 214276 : case W_CURVE:
240 214276 : if (ValidPointer(HRsa_curve_pointer)) {
241 214276 : Y_val = CurveValue(state, HRsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
242 214276 : Y_val = max(min(Y_val, 1.0), 0.0);
243 : } else {
244 0 : Y_val = Wra; // return HR
245 : }
246 214276 : 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 111670 : case POWER_CURVE:
250 111670 : if (ValidPointer(Psa_curve_pointer)) {
251 111670 : Y_val = ModelScalingFactor * CurveValue(state, Psa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
252 : } else {
253 0 : Y_val = 0;
254 : }
255 111670 : break;
256 :
257 313149 : case SUPPLY_FAN_POWER:
258 313149 : if (ValidPointer(SFPsa_curve_pointer)) {
259 313149 : Y_val = ModelScalingFactor * CurveValue(state, SFPsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
260 : } else {
261 0 : Y_val = 0;
262 : }
263 313149 : break;
264 :
265 98873 : case EXTERNAL_STATIC_PRESSURE:
266 98873 : if (ValidPointer(ESPsa_curve_pointer)) {
267 98873 : 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 98873 : break;
272 :
273 98873 : case SECOND_FUEL_USE:
274 98873 : if (ValidPointer(SFUsa_curve_pointer)) {
275 44437 : Y_val = ModelScalingFactor * CurveValue(state, SFUsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
276 : } else {
277 54436 : Y_val = 0; // or set a more reasonable default
278 : }
279 98873 : break;
280 :
281 98873 : case THIRD_FUEL_USE:
282 98873 : if (ValidPointer(TFUsa_curve_pointer)) {
283 0 : Y_val = ModelScalingFactor * CurveValue(state, TFUsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
284 : } else {
285 98873 : Y_val = 0; // or set a more reasonable default
286 : }
287 98873 : break;
288 :
289 98873 : case WATER_USE:
290 98873 : if (ValidPointer(WUsa_curve_pointer)) {
291 34814 : Y_val = ModelScalingFactor * CurveValue(state, WUsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
292 : } else {
293 64059 : Y_val = 0; // or set a more reasonable default
294 : }
295 98873 : break;
296 :
297 0 : default:
298 0 : break;
299 : }
300 :
301 1248863 : 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 12 : CMode newMode;
404 12 : bool error = newMode.ParseMode(
405 6 : state, ModeCounter, &OperatingModes, ScalingFactor, Alphas, cAlphaFields, Numbers, cNumericFields, lAlphaBlanks, cCurrentModuleObject);
406 6 : ModeCounter++;
407 12 : return error;
408 : }
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 12 : 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, "Invalid " + cAlphaFields(inter_Alpha) + '=' + Alphas(inter_Alpha));
468 0 : ShowContinueError(state, "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, "Invalid " + cAlphaFields(inter_Alpha) + '=' + Alphas(inter_Alpha));
486 0 : ShowContinueError(state, "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, "Invalid " + cAlphaFields(inter_Alpha) + '=' + Alphas(inter_Alpha));
502 0 : ShowContinueError(state, "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, "Invalid " + cAlphaFields(inter_Alpha) + '=' + Alphas(inter_Alpha));
518 0 : ShowContinueError(state, "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, "Invalid " + cAlphaFields(inter_Alpha) + '=' + Alphas(inter_Alpha));
534 0 : ShowContinueError(state, "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, "Invalid " + cAlphaFields(inter_Alpha) + '=' + Alphas(inter_Alpha));
551 0 : ShowContinueError(state, "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, "Invalid " + cAlphaFields(inter_Alpha) + '=' + Alphas(inter_Alpha));
567 0 : ShowContinueError(state, "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, "Invalid " + cAlphaFields(inter_Alpha) + '=' + Alphas(inter_Alpha));
583 0 : ShowContinueError(state, "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, "Invalid " + cNumericFields(inter_Number) + "Or Invalid" + cNumericFields(inter_Number + 1));
599 0 : ShowContinueError(state, "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, "Invalid " + cNumericFields(inter_Number) + "Or Invalid" + cNumericFields(inter_Number + 1));
608 0 : ShowContinueError(state, "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, "Invalid " + cNumericFields(inter_Number) + "Or Invalid" + cNumericFields(inter_Number + 1));
617 0 : ShowContinueError(state, "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, "Invalid " + cNumericFields(inter_Number) + "Or Invalid" + cNumericFields(inter_Number + 1));
626 0 : ShowContinueError(state, "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, "Invalid " + cNumericFields(inter_Number) + "Or Invalid" + cNumericFields(inter_Number + 1));
635 0 : ShowContinueError(state, "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 : "Invalid " + cAlphaFields(inter_Number) + '=' + Alphas(inter_Number) + "Or Invalid" + cAlphaFields(inter_Number + 1) +
645 0 : '=' + Alphas(inter_Number + 1));
646 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject);
647 0 : ErrorsFound = true;
648 : }
649 5 : inter_Number = inter_Number + 2;
650 : // N20, \field Mode1 Minimum Outdoor Air Fraction
651 : // N21, \field Mode1 Maximum Outdoor Air Fraction
652 :
653 5 : ok = InitializeOSAFConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
654 5 : if (!ok) {
655 0 : ShowSevereError(state, "Error in OSAFConstraints" + cAlphaFields(inter_Number) + "through" + cAlphaFields(inter_Number + 1));
656 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject);
657 0 : ErrorsFound = true;
658 : }
659 : // N22, \field Mode1 Minimum Supply Air Mass Flow Rate Ratio
660 : // N23, \field Mode1 Maximum Supply Air Mass Flow Rate Ratio
661 5 : inter_Number = inter_Number + 2;
662 5 : ok = InitializeMsaRatioConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
663 5 : if (!ok) {
664 0 : ShowSevereError(state, "Error in OSAFConstraints" + cAlphaFields(inter_Number) + "through" + cAlphaFields(inter_Number + 1));
665 0 : ShowContinueError(state, "Entered in " + cCurrentModuleObject);
666 0 : ErrorsFound = true;
667 : }
668 5 : (*OperatingModes).push_back(*this);
669 5 : return ErrorsFound;
670 : }
671 :
672 63695 : bool CMode::MeetsOAEnvConstraints(Real64 Tosa, Real64 Wosa, Real64 RHosa)
673 : {
674 : // SUBROUTINE INFORMATION:
675 : // AUTHOR Spencer Maxwell Dutton
676 : // DATE WRITTEN October 2017
677 : // MODIFIED
678 : // RE-ENGINEERED na
679 :
680 : // PURPOSE OF THIS SUBROUTINE:
681 : // To check to see if this mode of operation is able to operate given the specified outdoor environmental conditions.
682 :
683 : // METHODOLOGY EMPLOYED:
684 : // Constraining certain modes to only operate over certain environmental conditions gives the user greater control in which
685 : // modes the algorithm selects.
686 :
687 : // REFERENCES:
688 : // na
689 :
690 : // Using/Aliasing
691 63695 : bool OATempConstraintmet = false;
692 63695 : bool OAHRConstraintmet = false;
693 63695 : bool OARHConstraintmet = false;
694 :
695 63695 : if (Tosa >= Minimum_Outdoor_Air_Temperature && Tosa <= Maximum_Outdoor_Air_Temperature) {
696 63695 : OATempConstraintmet = true;
697 : }
698 :
699 63695 : if (Wosa >= Minimum_Outdoor_Air_Humidity_Ratio && Wosa <= Maximum_Outdoor_Air_Humidity_Ratio) {
700 63695 : OAHRConstraintmet = true;
701 : }
702 :
703 63695 : if (RHosa >= Minimum_Outdoor_Air_Relative_Humidity && RHosa <= Maximum_Outdoor_Air_Relative_Humidity) {
704 63695 : OARHConstraintmet = true;
705 : }
706 63695 : if (OATempConstraintmet && OAHRConstraintmet && OARHConstraintmet) {
707 63695 : return true;
708 : } else {
709 0 : return false;
710 : }
711 : }
712 :
713 214276 : bool Model::MeetsSupplyAirTOC(EnergyPlusData &state, Real64 Tsupplyair)
714 : {
715 : // SUBROUTINE INFORMATION:
716 : // AUTHOR Spencer Maxwell Dutton
717 : // DATE WRITTEN October 2017
718 : // MODIFIED
719 : // RE-ENGINEERED na
720 :
721 : // PURPOSE OF THIS SUBROUTINE:
722 : // To check to see if this this particular setting (combination of mode, OSAF and Msa) meets the required minumum
723 : // supply air temperature specified in the schedules
724 :
725 : // METHODOLOGY EMPLOYED:
726 : // Checks the minimum and maximum supply air temperatures and tests to see if the proposed supply air temperature is in the acceptable range.
727 :
728 : // REFERENCES:
729 : // na
730 :
731 : // Using/Aliasing
732 214276 : Real64 MinSAT = 10;
733 214276 : Real64 MaxSAT = 20;
734 214276 : if (TsaMin_schedule_pointer > 0) {
735 214276 : MinSAT = GetCurrentScheduleValue(state, TsaMin_schedule_pointer);
736 : }
737 214276 : if (TsaMax_schedule_pointer > 0) {
738 214276 : MaxSAT = GetCurrentScheduleValue(state, TsaMax_schedule_pointer);
739 : }
740 214276 : if (Tsupplyair < MinSAT || Tsupplyair > MaxSAT) return false;
741 98873 : return true;
742 : }
743 :
744 214276 : bool Model::MeetsSupplyAirRHOC(EnergyPlusData &state, Real64 SupplyW)
745 : {
746 : // SUBROUTINE INFORMATION:
747 : // AUTHOR Spencer Maxwell Dutton
748 : // DATE WRITTEN October 2017
749 : // MODIFIED
750 : // RE-ENGINEERED na
751 :
752 : // PURPOSE OF THIS SUBROUTINE:
753 : // To check to see if this this particular setting (combination of mode, OSAF and Msa) meets the required minumum
754 : // supply air relative humidity specified in the schedules
755 :
756 : // METHODOLOGY EMPLOYED:
757 : // Checks the scheduled minimum and maximum supply air RH and tests to see if the proposed supply air RH is in the acceptable range.
758 :
759 : // REFERENCES:
760 : // na
761 :
762 : // Using/Aliasing
763 214276 : Real64 MinRH = 0;
764 214276 : Real64 MaxRH = 1;
765 214276 : if (RHsaMin_schedule_pointer > 0) {
766 214276 : MinRH = GetCurrentScheduleValue(state, RHsaMin_schedule_pointer);
767 : }
768 214276 : if (RHsaMax_schedule_pointer > 0) {
769 214276 : MaxRH = GetCurrentScheduleValue(state, RHsaMax_schedule_pointer);
770 : }
771 214276 : if (SupplyW < MinRH || SupplyW > MaxRH) return false;
772 214276 : return true;
773 : }
774 :
775 2 : Model::Model()
776 : : Initialized(false), ZoneNum(0), SchedPtr(0), SystemMaximumSupplyAirFlowRate(0.0), ScalingFactor(0.0),
777 : ScaledSystemMaximumSupplyAirMassFlowRate(0.0), UnitOn(0), UnitTotalCoolingRate(0.0), UnitTotalCoolingEnergy(0.0),
778 : UnitSensibleCoolingRate(0.0), UnitSensibleCoolingEnergy(0.0), UnitLatentCoolingRate(0.0), UnitLatentCoolingEnergy(0.0),
779 : SystemTotalCoolingRate(0.0), SystemTotalCoolingEnergy(0.0), SystemSensibleCoolingRate(0.0), SystemSensibleCoolingEnergy(0.0),
780 : SystemLatentCoolingRate(0.0), SystemLatentCoolingEnergy(0.0), UnitTotalHeatingRate(0.0), UnitTotalHeatingEnergy(0.0),
781 : UnitSensibleHeatingRate(0.0), UnitSensibleHeatingEnergy(0.0), UnitLatentHeatingRate(0.0), UnitLatentHeatingEnergy(0.0),
782 : SystemTotalHeatingRate(0.0), SystemTotalHeatingEnergy(0.0), SystemSensibleHeatingRate(0.0), SystemSensibleHeatingEnergy(0.0),
783 : SystemLatentHeatingRate(0.0), SystemLatentHeatingEnergy(0.0), SupplyFanElectricPower(0.0), SupplyFanElectricEnergy(0.0),
784 : SecondaryFuelConsumptionRate(0.0), SecondaryFuelConsumption(0.0), ThirdFuelConsumptionRate(0.0), ThirdFuelConsumption(0.0),
785 : WaterConsumptionRate(0.0), WaterConsumption(0.0), QSensZoneOut(0), QLatentZoneOut(0), QLatentZoneOutMass(0), ExternalStaticPressure(0.0),
786 : RequestedHumdificationMass(0.0), RequestedHumdificationLoad(0.0), RequestedHumdificationEnergy(0.0), RequestedDeHumdificationMass(0.0),
787 : RequestedDeHumdificationLoad(0.0), RequestedDeHumdificationEnergy(0.0), RequestedLoadToHeatingSetpoint(0.0),
788 : RequestedLoadToCoolingSetpoint(0.0), TsaMin_schedule_pointer(0), TsaMax_schedule_pointer(0), RHsaMin_schedule_pointer(0),
789 : RHsaMax_schedule_pointer(0), PrimaryMode(0), PrimaryModeRuntimeFraction(0.0), averageOSAF(0), ErrorCode(0), InletNode(0), OutletNode(0),
790 : SecondaryInletNode(0), SecondaryOutletNode(0), FinalElectricalPower(0.0), FinalElectricalEnergy(0.0), InletMassFlowRate(0.0),
791 : InletTemp(0.0), InletWetBulbTemp(0.0), InletHumRat(0.0), InletEnthalpy(0.0), InletPressure(0.0), InletRH(0.0),
792 : OutletVolumetricFlowRate(0.0), OutletMassFlowRate(0.0), PowerLossToAir(0.0), FanHeatTemp(0.0), OutletTemp(0.0), OutletWetBulbTemp(0.0),
793 : OutletHumRat(0.0), OutletEnthalpy(0.0), OutletPressure(0.0), OutletRH(0.0), SecInletMassFlowRate(0.0), SecInletTemp(0.0),
794 : SecInletWetBulbTemp(0.0), SecInletHumRat(0.0), SecInletEnthalpy(0.0), SecInletPressure(0.0), SecInletRH(0.0), SecOutletMassFlowRate(0.0),
795 : SecOutletTemp(0.0), SecOutletWetBulbTemp(0.0), SecOutletHumRat(0.0), SecOutletEnthalpy(0.0), SecOutletPressure(0.0), SecOutletRH(0.0),
796 : Wsa(0.0), SupplyVentilationAir(0.0), SupplyVentilationVolume(0.0), OutdoorAir(false), MinOA_Msa(0.0), OARequirementsPtr(0), Tsa(0.0),
797 : ModeCounter(0), CoolingRequested(false), HeatingRequested(false), VentilationRequested(false), DehumidificationRequested(false),
798 2 : HumidificationRequested(false)
799 : {
800 2 : WarnOnceFlag = false;
801 2 : count_EnvironmentConditionsMetOnce = 0;
802 2 : count_EnvironmentConditionsNotMet = 0;
803 2 : count_SAHR_OC_MetOnce = 0;
804 2 : count_SAT_OC_MetOnce = 0;
805 2 : count_DidWeMeetLoad = 0;
806 2 : count_DidWeNotMeetLoad = 0;
807 : // vector below used store the modes in each timestep that don't meet humidity or temperature limits, used in warnings
808 4 : std::vector<int> temp(25);
809 2 : SAT_OC_MetinMode_v = temp;
810 2 : SAHR_OC_MetinMode_v = temp;
811 :
812 2 : ModeCounter = 0;
813 :
814 2 : CurrentOperatingSettings.resize(5);
815 :
816 2 : InitializeModelParams();
817 2 : }
818 :
819 25596 : void Model::ResetOutputs()
820 : {
821 25596 : UnitTotalCoolingRate = 0;
822 25596 : UnitTotalCoolingEnergy = 0;
823 25596 : UnitSensibleCoolingRate = 0;
824 25596 : UnitSensibleCoolingEnergy = 0;
825 25596 : UnitLatentCoolingRate = 0;
826 25596 : UnitLatentCoolingEnergy = 0;
827 25596 : SystemTotalCoolingRate = 0;
828 25596 : SystemTotalCoolingEnergy = 0;
829 25596 : SystemSensibleCoolingRate = 0;
830 25596 : SystemSensibleCoolingEnergy = 0;
831 25596 : SystemLatentCoolingRate = 0;
832 25596 : SystemLatentCoolingEnergy = 0;
833 25596 : UnitTotalHeatingRate = 0;
834 25596 : UnitTotalHeatingEnergy = 0;
835 25596 : UnitSensibleHeatingRate = 0;
836 25596 : UnitSensibleHeatingEnergy = 0;
837 25596 : UnitLatentHeatingRate = 0;
838 25596 : UnitLatentHeatingEnergy = 0;
839 25596 : SystemTotalHeatingRate = 0;
840 25596 : SystemTotalHeatingEnergy = 0;
841 25596 : SystemSensibleHeatingRate = 0;
842 25596 : SystemSensibleHeatingEnergy = 0;
843 25596 : SystemLatentHeatingRate = 0;
844 25596 : SystemLatentHeatingEnergy = 0;
845 25596 : SupplyFanElectricPower = 0;
846 25596 : SupplyFanElectricEnergy = 0;
847 25596 : SecondaryFuelConsumptionRate = 0;
848 25596 : SecondaryFuelConsumption = 0;
849 25596 : ThirdFuelConsumptionRate = 0;
850 25596 : ThirdFuelConsumption = 0;
851 25596 : WaterConsumptionRate = 0;
852 25596 : WaterConsumption = 0;
853 25596 : ExternalStaticPressure = 0;
854 25596 : }
855 :
856 12799 : void Model::InitializeModelParams()
857 : {
858 : // SUBROUTINE INFORMATION:
859 : // AUTHOR Spencer Maxwell Dutton
860 : // DATE WRITTEN October 2017
861 : // MODIFIED
862 : // RE-ENGINEERED na
863 :
864 : // PURPOSE OF THIS SUBROUTINE:
865 : // Reset calculation values
866 :
867 : // METHODOLOGY EMPLOYED:
868 : //
869 :
870 : // REFERENCES:
871 : // na
872 :
873 : // Using/Aliasing
874 12799 : ResetOutputs();
875 12799 : PrimaryMode = 0;
876 12799 : PrimaryModeRuntimeFraction = 0;
877 12799 : optimal_EnvCondMet = false;
878 12799 : Tsa = 0;
879 : // reset the power use to a high value, this is replaced during the calculation keeping the "best" setting.
880 :
881 12799 : RunningPeakCapacity_EnvCondMet = false;
882 12799 : Settings.clear();
883 12799 : }
884 :
885 1 : void Model::Initialize(int ZoneNumber)
886 : {
887 : // SUBROUTINE INFORMATION:
888 : // AUTHOR Spencer Maxwell Dutton
889 : // DATE WRITTEN October 2017
890 : // MODIFIED
891 : // RE-ENGINEERED na
892 :
893 : // PURPOSE OF THIS SUBROUTINE:
894 : // Specify solution space resolution, and populate the solution spaces in each mode
895 :
896 : // METHODOLOGY EMPLOYED:
897 : // Solution spaces are the matrices of possible settings settings (combination of OSA fraction and supply air mass flow rate)
898 : // This method calls the GenerateSolutionSpace for each of the modes defined in the idf.
899 : // REFERENCES:
900 : // na
901 :
902 : // Using/Aliasing
903 :
904 1 : ZoneNum = ZoneNumber;
905 1 : if (Initialized) {
906 0 : return;
907 : }
908 1 : Initialized = true;
909 :
910 : // Iterate through modes of operation generating a matrix of OSAF and Msa to test in the algorithm.
911 7 : for (auto &thisOperatingMode : OperatingModes) {
912 6 : thisOperatingMode.GenerateSolutionSpace();
913 : }
914 :
915 1 : Initialized = true;
916 : }
917 :
918 111670 : Real64 Model::CheckVal_W(EnergyPlusData &state, Real64 W, Real64 T, Real64 P)
919 : {
920 : // P must be in pascals NOT kPa
921 111670 : Real64 OutletRHtest = PsyRhFnTdbWPb(state, T, W, P); // could also use outlet pressure instead of fixed
922 : Real64 OutletW =
923 111670 : PsyWFnTdbRhPb(state, T, OutletRHtest, P, "Humidity ratio exceeded realistic range error called in " + Name + ", check performance curve");
924 111670 : return OutletW;
925 : }
926 12797 : Real64 Model::CheckVal_T(EnergyPlusData &state, Real64 T)
927 : {
928 12797 : if ((T > 100) || (T < 0)) {
929 2 : ShowWarningError(state, "Supply air temperature exceeded realistic range error called in " + Name + ", check performance curve");
930 : }
931 12797 : return T;
932 : }
933 12797 : bool Model::SetStandByMode(EnergyPlusData &state, CMode Mode0, Real64 Tosa, Real64 Wosa, Real64 Tra, Real64 Wra)
934 : {
935 : // SUBROUTINE INFORMATION:
936 : // AUTHOR Spencer Maxwell Dutton
937 : // DATE WRITTEN October 2017
938 : // MODIFIED
939 : // RE-ENGINEERED na
940 :
941 : // PURPOSE OF THIS SUBROUTINE:
942 : // Set the supply air mass flow rate, power use, and all the other parameters for a setting.
943 :
944 : // METHODOLOGY EMPLOYED:
945 : // Uses the relevant lookup take to specify the parameters, or uses default conditions.
946 : // In setting the supply air temperature for now just use return air future improvement will use look up table
947 :
948 : // REFERENCES:
949 : // na
950 :
951 : // if the map of the solution space looks valid then populate the class member oStandBy (CSetting) with the settings data (what OSAF it runs
952 : // at, and how much power it uses etc.
953 12797 : if (Mode0.sol.MassFlowRatio.size() > 0) {
954 12797 : Real64 MsaRatio = Mode0.sol.MassFlowRatio[0];
955 12797 : Real64 OSAF = Mode0.sol.OutdoorAirFraction[0];
956 :
957 12797 : oStandBy.ScaledSupply_Air_Mass_Flow_Rate = MsaRatio * ScaledSystemMaximumSupplyAirMassFlowRate;
958 12797 : oStandBy.Unscaled_Supply_Air_Mass_Flow_Rate = oStandBy.ScaledSupply_Air_Mass_Flow_Rate / ScalingFactor;
959 12797 : oStandBy.ScaledSupply_Air_Ventilation_Volume = MsaRatio * ScaledSystemMaximumSupplyAirMassFlowRate / state.dataEnvrn->StdRhoAir;
960 12797 : oStandBy.Supply_Air_Mass_Flow_Rate_Ratio = MsaRatio;
961 12797 : oStandBy.ElectricalPower =
962 12797 : Mode0.CalculateCurveVal(state, Tosa, Wosa, Tra, Wra, oStandBy.Unscaled_Supply_Air_Mass_Flow_Rate, OSAF, POWER_CURVE);
963 12797 : oStandBy.Outdoor_Air_Fraction = OSAF;
964 12797 : oStandBy.SupplyAirTemperature = Tra;
965 12797 : oStandBy.SupplyAirW = Wra;
966 12797 : oStandBy.Mode = 0;
967 12797 : oStandBy.Mixed_Air_Temperature = Tra;
968 12797 : oStandBy.Mixed_Air_W = Wra;
969 : } else {
970 : // if the solution space is invalid return true that an error occurred.
971 0 : return true;
972 : }
973 :
974 12797 : return false;
975 : }
976 :
977 153564 : Real64 Model::CalculateTimeStepAverage(SYSTEMOUTPUTS val)
978 : {
979 : // SUBROUTINE INFORMATION:
980 : // AUTHOR Spencer Maxwell Dutton
981 : // DATE WRITTEN October 2017
982 : // MODIFIED
983 : // RE-ENGINEERED na
984 :
985 : // PURPOSE OF THIS SUBROUTINE:
986 : // Calculates the resultant supply air conditions when the system operates in
987 : // multiple settings within a timestep.
988 :
989 : // METHODOLOGY EMPLOYED:
990 : // For longer simulation timesteps this model can consider partial runtime fractions
991 : // operating in different settings for a fraction of the total simulation time step reducing the likelyhood of over conditioning.
992 : // Intensive variables that do not depend on system size (like temperature, pressure,etc), and extensive variables (variable whose values
993 : // depend on the quantity of substance) are handled differently
994 : //
995 : // Extensive variables ( Mass Flow, Volume flow, Fuel use etc), are averaged weighted by the amount of time spent in each setting.
996 : // 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
997 : // resultant time step average mass flow rate would be 1 kg/s.
998 :
999 : // Intensive values in each part runtime fraction are first multiplied by the Scaled Supply Air Mass Flow Rate for each setting
1000 : // and then once all the various runtime fractions are added up, the resultant is divided by the overal time step average Scaled Supply Air
1001 : // Mass Flow Rate
1002 : //
1003 : // REFERENCES:
1004 : // na
1005 :
1006 : // Using/Aliasing
1007 153564 : Real64 averagedVal = 0;
1008 153564 : Real64 MassFlowDependentDenominator = 0;
1009 153564 : Real64 value = 0;
1010 :
1011 921384 : for (auto &thisOperatingSettings : CurrentOperatingSettings) {
1012 767820 : switch (val) {
1013 63985 : case SYSTEMOUTPUTS::VENTILATION_AIR_V:
1014 63985 : value = thisOperatingSettings.ScaledSupply_Air_Ventilation_Volume;
1015 63985 : break;
1016 63985 : case SYSTEMOUTPUTS::SYSTEM_FUEL_USE:
1017 63985 : value = thisOperatingSettings.ElectricalPower;
1018 63985 : break;
1019 63985 : case SYSTEMOUTPUTS::OSUPPLY_FAN_POWER:
1020 63985 : value = thisOperatingSettings.SupplyFanElectricPower;
1021 63985 : break;
1022 63985 : case SYSTEMOUTPUTS::OSECOND_FUEL_USE:
1023 63985 : value = thisOperatingSettings.SecondaryFuelConsumptionRate;
1024 63985 : break;
1025 63985 : case SYSTEMOUTPUTS::OTHIRD_FUEL_USE:
1026 63985 : value = thisOperatingSettings.ThirdFuelConsumptionRate;
1027 63985 : break;
1028 63985 : case SYSTEMOUTPUTS::OEXTERNAL_STATIC_PRESSURE:
1029 63985 : value = thisOperatingSettings.ExternalStaticPressure * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
1030 63985 : break;
1031 63985 : case SYSTEMOUTPUTS::OWATER_USE:
1032 63985 : value = thisOperatingSettings.WaterConsumptionRate;
1033 63985 : break;
1034 63985 : case SYSTEMOUTPUTS::SUPPLY_AIR_TEMP:
1035 63985 : value = thisOperatingSettings.SupplyAirTemperature * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
1036 63985 : break;
1037 63985 : case SYSTEMOUTPUTS::MIXED_AIR_TEMP:
1038 63985 : value = thisOperatingSettings.Mixed_Air_Temperature * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
1039 63985 : break;
1040 63985 : case SYSTEMOUTPUTS::SUPPLY_MASS_FLOW:
1041 63985 : value = thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
1042 63985 : break;
1043 63985 : case SYSTEMOUTPUTS::SUPPLY_AIR_HR:
1044 63985 : value = thisOperatingSettings.SupplyAirW * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
1045 63985 : break;
1046 63985 : case SYSTEMOUTPUTS::MIXED_AIR_HR:
1047 63985 : value = thisOperatingSettings.Mixed_Air_W * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
1048 63985 : break;
1049 0 : default:
1050 0 : assert(false);
1051 : }
1052 767820 : Real64 part_run = thisOperatingSettings.Runtime_Fraction;
1053 767820 : averagedVal = averagedVal + value * part_run;
1054 767820 : MassFlowDependentDenominator = thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate * part_run + MassFlowDependentDenominator;
1055 : }
1056 :
1057 307128 : CSetting StandbyMode = (*(CurrentOperatingSettings.begin()));
1058 153564 : switch (val) {
1059 12797 : case SYSTEMOUTPUTS::SUPPLY_AIR_TEMP:
1060 12797 : if (MassFlowDependentDenominator == 0) {
1061 7274 : averagedVal = StandbyMode.SupplyAirTemperature;
1062 : } else {
1063 5523 : averagedVal = averagedVal / MassFlowDependentDenominator;
1064 : }
1065 12797 : break;
1066 12797 : case SYSTEMOUTPUTS::OEXTERNAL_STATIC_PRESSURE:
1067 12797 : if (MassFlowDependentDenominator == 0) {
1068 7274 : averagedVal = StandbyMode.ExternalStaticPressure;
1069 : } else {
1070 5523 : averagedVal = averagedVal / MassFlowDependentDenominator;
1071 : }
1072 12797 : break;
1073 12797 : case SYSTEMOUTPUTS::SUPPLY_AIR_HR:
1074 12797 : if (MassFlowDependentDenominator == 0) {
1075 7274 : averagedVal = StandbyMode.SupplyAirW;
1076 : } else {
1077 5523 : averagedVal = averagedVal / MassFlowDependentDenominator;
1078 : }
1079 12797 : break;
1080 12797 : case SYSTEMOUTPUTS::MIXED_AIR_TEMP:
1081 12797 : if (MassFlowDependentDenominator == 0) {
1082 7274 : averagedVal = StandbyMode.Mixed_Air_Temperature;
1083 : } else {
1084 5523 : averagedVal = averagedVal / MassFlowDependentDenominator;
1085 : }
1086 12797 : break;
1087 12797 : case SYSTEMOUTPUTS::MIXED_AIR_HR:
1088 12797 : if (MassFlowDependentDenominator == 0) {
1089 7274 : averagedVal = StandbyMode.Mixed_Air_W;
1090 : } else {
1091 5523 : averagedVal = averagedVal / MassFlowDependentDenominator;
1092 : }
1093 12797 : break;
1094 89579 : default:
1095 89579 : break;
1096 : }
1097 307128 : return averagedVal;
1098 : }
1099 :
1100 98873 : Real64 Model::CalculatePartRuntimeFraction(Real64 MinOA_Msa,
1101 : Real64 Mvent,
1102 : Real64 RequestedCoolingLoad,
1103 : Real64 RequestedHeatingLoad,
1104 : Real64 SensibleRoomORZone,
1105 : Real64 RequestedDehumidificationLoad,
1106 : Real64 RequestedMoistureLoad,
1107 : Real64 LatentRoomORZone)
1108 : {
1109 : // SUBROUTINE INFORMATION:
1110 : // AUTHOR Spencer Maxwell Dutton
1111 : // DATE WRITTEN October 2017
1112 : // MODIFIED
1113 : // RE-ENGINEERED na
1114 :
1115 : // PURPOSE OF THIS SUBROUTINE:
1116 : // Calculates the minimum runtime fraction in a given setting needed to meet the
1117 : // sensible cooling, sensible heating, dehumidification and humidification loads
1118 : // and ventilation loads.
1119 :
1120 : // METHODOLOGY EMPLOYED:
1121 : // Calculate the minimum runtime fractions for each load that needs to be met and find the lowest of those runtime fractions.
1122 : // Go through each of the requirements (ventilation, heating, cooling, dehumidification, humidification and work out what the minimum runtime
1123 : // fraction you would need in order to meet all these requirements. Importantly the SensibleRoomORZone is either (-) for heating or (+) for
1124 : // cooling, where as the RequestedCoolingLoad and RequestedHeatingLoad, are both positive (never below 0).
1125 :
1126 : // REFERENCES:
1127 : // na
1128 :
1129 : // Using/Aliasing
1130 : Real64 PLHumidRatio, PLDehumidRatio, PLVentRatio, PLSensibleCoolingRatio, PLSensibleHeatingRatio, PartRuntimeFraction;
1131 98873 : PLHumidRatio = PLDehumidRatio = PLVentRatio = PLSensibleCoolingRatio = PLSensibleHeatingRatio = 0;
1132 :
1133 98873 : if (Mvent > 0) {
1134 98873 : PLVentRatio = MinOA_Msa / Mvent;
1135 : }
1136 98873 : PartRuntimeFraction = PLVentRatio;
1137 :
1138 98873 : if (SensibleRoomORZone > 0) {
1139 65135 : PLSensibleCoolingRatio = std::abs(RequestedCoolingLoad) / std::abs(SensibleRoomORZone);
1140 : }
1141 98873 : if (PLSensibleCoolingRatio > PartRuntimeFraction) {
1142 40075 : PartRuntimeFraction = PLSensibleCoolingRatio;
1143 : }
1144 :
1145 98873 : if (SensibleRoomORZone < 0) {
1146 33738 : PLSensibleHeatingRatio = std::abs(RequestedHeatingLoad) / std::abs(SensibleRoomORZone);
1147 : }
1148 :
1149 98873 : if (PLSensibleHeatingRatio > PartRuntimeFraction) {
1150 17262 : PartRuntimeFraction = PLSensibleHeatingRatio;
1151 : }
1152 :
1153 98873 : if (RequestedDehumidificationLoad > 0) {
1154 2962 : PLDehumidRatio = std::abs(RequestedDehumidificationLoad) / std::abs(LatentRoomORZone);
1155 : }
1156 :
1157 98873 : if (PLDehumidRatio > PartRuntimeFraction) {
1158 2950 : PartRuntimeFraction = PLDehumidRatio;
1159 : }
1160 :
1161 98873 : if (RequestedMoistureLoad > 0) {
1162 95907 : PLHumidRatio = std::abs(RequestedMoistureLoad) / std::abs(LatentRoomORZone);
1163 : }
1164 98873 : if (PLHumidRatio > PartRuntimeFraction) {
1165 93507 : PartRuntimeFraction = PLHumidRatio;
1166 : }
1167 :
1168 98873 : if (PartRuntimeFraction < 0) {
1169 0 : PartRuntimeFraction = 0;
1170 : }
1171 98873 : if (PartRuntimeFraction > 1) {
1172 92275 : PartRuntimeFraction = 1;
1173 : }
1174 :
1175 98873 : return PartRuntimeFraction;
1176 : }
1177 :
1178 12739 : int Model::SetOperatingSetting(EnergyPlusData &state, CStepInputs StepIns)
1179 : {
1180 : // SUBROUTINE INFORMATION:
1181 : // AUTHOR Spencer Dutton
1182 : // DATE WRITTEN May 2017
1183 : // MODIFIED na
1184 : // RE-ENGINEERED na
1185 :
1186 : // PURPOSE OF THIS SUBROUTINE:
1187 : // This subroutine determines the set of operating settings for the HybridUniaryHVAC
1188 : // It is called from Model::doStep, the main calculation step
1189 : // at the system time step.
1190 :
1191 : // METHODOLOGY EMPLOYED:
1192 : // 1) Clear out the set of operating settings from the previous time step.
1193 : // 2) Iterate through each operating mode and weed out modes that are not intended to operate in current environmental conditions.
1194 : // -> For each mode that is viable iterate thought the solution space and identify settings that meet the ventilation
1195 : // requirements
1196 : // -> settings that do are stored in the a container (Settings)
1197 : // 3) Iterate through all the settings in Settings
1198 : //
1199 : // 4) Calculate the setting zone sensible cooling and heating load and humidifcation and dehumidifcation.
1200 : // 5) Test to see if conditioning and humidification loads are met.
1201 : // 6) Calculate setting power consumption, use the setting delivered ventilation and loads to calculate the
1202 : // 7) minimum runtime fraction needed to meet those loads, then assuming that part runtime fraction calculate the setting part run time power
1203 : // use. 8) If the setting meets both the conditioning and humidification loads then test to see if its optimal in terms of energy use.
1204 : // ->if so, save that setting as the current optimal.
1205 : // ->if not ignore it.
1206 : // If the setting failed ot meet either the conditioning or humidification loads, then
1207 : // -> firstly check to see if no previous other setting (in this calculation step) has met both the load and humidification requirements
1208 : // -> if so
1209 : // -> check if this setting meets the conditioning load (only)
1210 : // -> if so
1211 : // ->check to see if this setting is better at meeting the dehumidification or humidification lad
1212 : // than any previous setting this step.
1213 : // -> if its not, ignore it.
1214 : // -> if not
1215 : // ->check to see if any previous setting met the conditioning load
1216 : // ->if not:
1217 : // ->see if this setting is better at meeting the conditioning load than
1218 : // any previous setting this calculation step.
1219 : // -> if so save as current optimal
1220 : // -> if its not, ignore it.
1221 : // -> if so: then ignore it.
1222 : // ->if not, then a previous setting is better than this one by default, and so ignore it.
1223 : // 9) Identify error states if the no setting meets the environmental conditions, or the supply air humidity or temperature constraints.
1224 : // 10) if we met the load set operating settings to be a combination of the optimal setting at the minium required runtime fraction
1225 : // 11) if we partly met the load then do the best we can and run full out in that optimal setting.
1226 : // 12) if we didn't even partially meet the load make sure the operational settings are just the standby mode.
1227 : // 13) generate summary statistics for warnings.
1228 :
1229 : // REFERENCES:
1230 : // na
1231 :
1232 : // Using/Aliasing
1233 :
1234 : // Locals
1235 : // SUBROUTINE ARGUMENT DEFINITIONS:
1236 : // The CStepInputs are defined in the CStepInputs class definition.
1237 : // SUBROUTINE PARAMETER DEFINITIONS:
1238 : // na
1239 : // INTERFACE BLOCK SPECIFICATIONS
1240 : // na
1241 : // DERIVED TYPE DEFINITIONS
1242 : // na
1243 :
1244 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1245 12739 : bool DidWeMeetLoad = false;
1246 12739 : bool DidWeMeetHumidificaiton = false;
1247 12739 : bool DidWePartlyMeetLoad = false;
1248 12739 : Real64 OptimalSetting_RunFractionTotalFuel = IMPLAUSIBLE_POWER;
1249 : Real64 Tma;
1250 : Real64 Wma;
1251 : Real64 Hsa;
1252 : Real64 Hma;
1253 12739 : Real64 PreviousMaxiumConditioningOutput = 0;
1254 12739 : Real64 PreviousMaxiumHumidOrDehumidOutput = 0;
1255 25478 : std::string ObjectID = Name.c_str();
1256 12739 : if (StepIns.RHosa > 1) {
1257 0 : ShowSevereError(state,
1258 0 : "Unitary hybrid system error, required relative humidity value 0-1, called in object" + ObjectID + ".Check inputs");
1259 : assert(true);
1260 0 : return -1;
1261 : } // because it should be fractional, this should only really be possible if its called from a unit test
1262 :
1263 12739 : if (StepIns.RHra > 1) {
1264 0 : ShowSevereError(state,
1265 0 : "Unitary hybrid system error, required relative humidity value 0-1, called in object" + ObjectID + ".Check inputs");
1266 : assert(true);
1267 0 : return -1;
1268 : } // because it should be fractional, this should only really be possible if its called from a unit test
1269 :
1270 12739 : Real64 Wosa = PsyWFnTdbRhPb(state, StepIns.Tosa, StepIns.RHosa, state.dataEnvrn->OutBaroPress);
1271 12739 : Real64 Wra = PsyWFnTdbRhPb(state, StepIns.Tra, StepIns.RHra, InletPressure);
1272 : bool EnvironmentConditionsMet, EnvironmentConditionsMetOnce, MinVRMet, SAT_OC_Met, SAT_OC_MetOnce, SARH_OC_Met, SAHR_OC_MetOnce;
1273 12739 : EnvironmentConditionsMetOnce = SAT_OC_Met = SAT_OC_MetOnce = SARH_OC_Met = SAHR_OC_MetOnce = false;
1274 :
1275 12739 : MinOA_Msa = StepIns.MinimumOA; // Set object version of minimum VR Kg/s
1276 :
1277 76434 : for (std::vector<CMode>::const_iterator iterator = OperatingModes.begin() + 1; iterator != OperatingModes.end();
1278 : ++iterator) // iterate though the modes.
1279 : {
1280 127390 : CMode Mode = *iterator;
1281 63695 : bool SAHR_OC_MetinMode = false;
1282 63695 : bool SAT_OC_MetinMode = false;
1283 63695 : int solution_map_sizeX = Mode.sol.MassFlowRatio.size();
1284 63695 : int solution_map_sizeY = Mode.sol.OutdoorAirFraction.size();
1285 :
1286 : // Check that in this mode the //Outdoor Air Relative Humidity(0 - 100 % ) //Outdoor Air Humidity Ratio(g / g)//Outdoor Air
1287 : // Temperature(degC)
1288 63695 : if (Mode.MeetsOAEnvConstraints(StepIns.Tosa, Wosa, 100 * StepIns.RHosa)) {
1289 63695 : EnvironmentConditionsMet = EnvironmentConditionsMetOnce = true;
1290 : } else {
1291 0 : EnvironmentConditionsMet = false;
1292 : }
1293 :
1294 63695 : if (EnvironmentConditionsMet) {
1295 420387 : for (int indexMassFlowRatio = 0; indexMassFlowRatio < solution_map_sizeX;
1296 : indexMassFlowRatio++) // within each mode go though all the combinations of solution spaces.
1297 : {
1298 713384 : for (int indexOutdoorAirFraction = 0; indexOutdoorAirFraction < solution_map_sizeY; indexOutdoorAirFraction++) {
1299 : // Supply Air Mass Flow Rate(kg / s)
1300 : // Outdoor Air Fraction(0 - 1)
1301 :
1302 356692 : Real64 MsaRatio = Mode.sol.MassFlowRatio[indexMassFlowRatio]; // fractions of rated mass flow rate, so for some modes this
1303 : // might be low but others hi
1304 356692 : Real64 OSAF = Mode.sol.OutdoorAirFraction[indexOutdoorAirFraction];
1305 356692 : Real64 ScaledMsa = ScaledSystemMaximumSupplyAirMassFlowRate * MsaRatio;
1306 356692 : Real64 UnscaledMsa = ScaledSystemMaximumSupplyAirMassFlowRate / ScalingFactor;
1307 356692 : Real64 Supply_Air_Ventilation_Volume = 0;
1308 : // Calculate the ventilation mass flow rate
1309 356692 : Real64 Mvent = ScaledMsa * OSAF;
1310 :
1311 356692 : if (state.dataEnvrn->StdRhoAir > 1) {
1312 356692 : Supply_Air_Ventilation_Volume = Mvent / state.dataEnvrn->StdRhoAir;
1313 : } else {
1314 0 : Supply_Air_Ventilation_Volume = Mvent / 1.225; // stored as volumetric flow for reporting
1315 : }
1316 :
1317 356692 : if (Mvent - MinOA_Msa > -0.000001) {
1318 214276 : MinVRMet = true;
1319 : } else {
1320 142416 : MinVRMet = false;
1321 : }
1322 :
1323 356692 : if (MinVRMet) {
1324 : // reset outside air temp and return air temp before calculating curve values for each mode
1325 214276 : StepIns.Tosa = SecInletTemp;
1326 214276 : StepIns.Tra = InletTemp;
1327 : Real64 FanPower =
1328 214276 : Mode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SUPPLY_FAN_POWER) *
1329 214276 : ScalingFactor;
1330 :
1331 : // calculate power loss to air if in mixed air stream and divide fan heat between outside air stream and return air stream
1332 214276 : if (FanHeatGain && FanHeatGainLocation == "MIXEDAIRSTREAM") {
1333 0 : PowerLossToAir = FanPower * FanHeatInAirFrac;
1334 : } else {
1335 214276 : PowerLossToAir = 0.0;
1336 : }
1337 214276 : Real64 FanHeatTempOA = PowerLossToAir / (PsyCpAirFnW(Wosa) * (ScaledMsa * OSAF));
1338 214276 : StepIns.Tosa = StepIns.Tosa + FanHeatTempOA;
1339 214276 : if (OSAF < 1.0) {
1340 0 : Real64 FanHeatTempRA = PowerLossToAir / (PsyCpAirFnW(Wra) * (ScaledMsa * (1 - OSAF)));
1341 0 : StepIns.Tra = StepIns.Tra + FanHeatTempRA;
1342 : }
1343 :
1344 : // Calculate prospective supply air temperature
1345 214276 : Tsa = Mode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, TEMP_CURVE);
1346 : // Calculate prospective supply air Humidity Ratio
1347 214276 : Wsa = Mode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, W_CURVE);
1348 :
1349 : // calculate power loss to supply air stream from fan power determined by curve value and fraction of fan heat in air
1350 : // stream
1351 214276 : if (FanHeatGain && FanHeatGainLocation == "SUPPLYAIRSTREAM") {
1352 0 : PowerLossToAir = FanPower * FanHeatInAirFrac;
1353 : } else {
1354 214276 : PowerLossToAir = 0.0;
1355 : }
1356 214276 : FanHeatTemp = PowerLossToAir / (PsyCpAirFnW(Wsa) * ScaledMsa);
1357 214276 : Tsa = Tsa + FanHeatTemp;
1358 :
1359 : // Check it meets constraints
1360 214276 : if (MeetsSupplyAirTOC(state, Tsa)) {
1361 98873 : SAT_OC_Met = SAT_OC_MetOnce = SAT_OC_MetinMode = true;
1362 : } else {
1363 115403 : SAT_OC_Met = false;
1364 : }
1365 : // Return Air Relative Humidity(0 - 100 % ) //Return Air Humidity Ratio(g / g)
1366 214276 : if (MeetsSupplyAirRHOC(state, Wsa)) {
1367 214276 : SARH_OC_Met = SAHR_OC_MetOnce = SAHR_OC_MetinMode = true;
1368 : } else {
1369 0 : SARH_OC_Met = false;
1370 : }
1371 :
1372 214276 : if (SARH_OC_Met && SAT_OC_Met) {
1373 197746 : CSetting CandidateSetting;
1374 98873 : CandidateSetting.Supply_Air_Ventilation_Volume = Supply_Air_Ventilation_Volume;
1375 98873 : CandidateSetting.Mode = Mode.ModeID;
1376 98873 : CandidateSetting.Outdoor_Air_Fraction = OSAF;
1377 98873 : CandidateSetting.Supply_Air_Mass_Flow_Rate_Ratio = MsaRatio;
1378 98873 : CandidateSetting.Unscaled_Supply_Air_Mass_Flow_Rate = UnscaledMsa;
1379 98873 : CandidateSetting.ScaledSupply_Air_Mass_Flow_Rate = ScaledMsa;
1380 :
1381 : // If no load is requested but ventilation is required, set the supply air mass flow rate to the minimum of the
1382 : // required ventilation flow rate and the maximum supply air flow rate
1383 98873 : if (!CoolingRequested && !HeatingRequested && !DehumidificationRequested && !HumidificationRequested) {
1384 4 : CandidateSetting.ScaledSupply_Air_Mass_Flow_Rate =
1385 4 : min(MinOA_Msa, CandidateSetting.ScaledSupply_Air_Mass_Flow_Rate);
1386 : // add fan heat if not included in lookup tables for supply air stream
1387 4 : Tsa = StepIns.Tosa + FanHeatTemp;
1388 : }
1389 :
1390 98873 : CandidateSetting.ScaledSupply_Air_Ventilation_Volume =
1391 98873 : CandidateSetting.ScaledSupply_Air_Mass_Flow_Rate / state.dataEnvrn->StdRhoAir;
1392 98873 : CandidateSetting.oMode = Mode;
1393 98873 : CandidateSetting.SupplyAirTemperature = Tsa;
1394 98873 : CandidateSetting.SupplyAirW = CheckVal_W(state, Wsa, Tsa, OutletPressure);
1395 98873 : CandidateSetting.Mode = Mode.ModeID;
1396 98873 : Settings.push_back(CandidateSetting);
1397 : }
1398 : }
1399 : }
1400 : }
1401 : }
1402 63695 : if (!state.dataGlobal->WarmupFlag) {
1403 : // Keep an account of the number of times the supply air temperature and humidity constraints were not met for a given mode but only
1404 : // do this when its not warmup.
1405 8770 : if (!SAT_OC_MetinMode) {
1406 5406 : SAT_OC_MetinMode_v[Mode.ModeID] = SAT_OC_MetinMode_v[Mode.ModeID] + 1;
1407 : }
1408 8770 : if (!SAHR_OC_MetinMode) {
1409 1656 : SAHR_OC_MetinMode_v[Mode.ModeID] = SAHR_OC_MetinMode_v[Mode.ModeID] + 1;
1410 : }
1411 : }
1412 : }
1413 :
1414 111612 : for (auto &thisSetting : Settings) {
1415 : // Calculate the delta H
1416 98873 : Real64 OSAF = thisSetting.Outdoor_Air_Fraction;
1417 98873 : Real64 UnscaledMsa = thisSetting.Unscaled_Supply_Air_Mass_Flow_Rate;
1418 98873 : Real64 ScaledMsa = thisSetting.ScaledSupply_Air_Mass_Flow_Rate;
1419 :
1420 : // send the scaled Msa to calculate energy and the unscaled for sending to curves.
1421 98873 : Tsa = thisSetting.SupplyAirTemperature;
1422 98873 : Wsa = thisSetting.SupplyAirW;
1423 98873 : Tma = StepIns.Tra + OSAF * (StepIns.Tosa - StepIns.Tra);
1424 98873 : Wma = Wra + OSAF * (Wosa - Wra);
1425 98873 : thisSetting.Mixed_Air_Temperature = Tma;
1426 98873 : thisSetting.Mixed_Air_W = Wma;
1427 :
1428 98873 : Hma = PsyHFnTdbW(Tma, Wma);
1429 : // Calculate Enthalpy of return air
1430 98873 : Real64 Hra = PsyHFnTdbW(StepIns.Tra, Wra);
1431 :
1432 98873 : Hsa = PsyHFnTdbW(Tsa, Wsa);
1433 :
1434 98873 : Real64 SupplyAirCp = PsyCpAirFnW(Wsa); // J/degreesK.kg
1435 98873 : Real64 ReturnAirCP = PsyCpAirFnW(Wra); // J/degreesK.kg
1436 98873 : Real64 OutdoorAirCP = PsyCpAirFnW(Wosa); // J/degreesK.kg
1437 :
1438 : // Calculations below of system cooling and heating capacity are ultimately reassessed when the resultant part runtime fraction is
1439 : // assessed. However its valuable that they are calculated here to at least provide a check.
1440 :
1441 : // 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)
1442 : // System Latent Cooling{ W } = m'SAdryair {kg/s} * L {kJ/kgWater} * (HR_RA + OSAF *(HR_OSA - HR_RA) - HR_SA) {kgWater/kgDryAir}
1443 : // System Total Cooling{ W } = m'SAdryair {kg/s} * (h_RA + OSAF*(h_OSA - h_RA) - h_SA) {kJ/kgDryAir}
1444 98873 : Real64 SystemCp = ReturnAirCP + OSAF * (OutdoorAirCP - ReturnAirCP) + SupplyAirCp; // J/degreesK.kg
1445 98873 : Real64 SensibleSystem = ScaledMsa * 0.5 * SystemCp * (Tma - Tsa); // W dynamic cp
1446 98873 : Real64 MsaDry = ScaledMsa * (1 - Wsa);
1447 98873 : Real64 LambdaSa = Psychrometrics::PsyHfgAirFnWTdb(0, Tsa);
1448 98873 : Real64 LatentSystem = LambdaSa * MsaDry * (Wma - Wsa); // W
1449 : // Total system cooling
1450 98873 : thisSetting.TotalSystem = (Hma - Hsa) * ScaledMsa;
1451 : // Perform latent check
1452 : // Real64 latentCheck = TotalSystem - SensibleSystem;
1453 :
1454 : // Zone Sensible Cooling{ W } = m'SA {kg/s} * 0.5*(cpRA+cpSA) {kJ/kg-C} * (T_RA - T_SA) {C}
1455 : // Zone Latent Cooling{ W } = m'SAdryair {kg/s} * L {kJ/kgWater} * (HR_RA - HR_SA) {kgWater/kgDryAir}
1456 : // Zone Total Cooling{ W } = m'SAdryair {kg/s} * (h_RA - h_SA) {kJ/kgDryAir}
1457 98873 : Real64 SensibleRoomORZone = ScaledMsa * 0.5 * (SupplyAirCp + ReturnAirCP) * (StepIns.Tra - Tsa); // W dynamic cp
1458 98873 : Real64 latentRoomORZone = LambdaSa * MsaDry * (Wra - Wsa); // W
1459 : // Total room cooling
1460 98873 : Real64 TotalRoomORZone = (Hra - Hsa) * ScaledMsa; // W
1461 : // Perform latent check
1462 : // Real64 latentRoomORZoneCheck = TotalRoomORZone - SensibleRoomORZone;
1463 :
1464 98873 : thisSetting.SensibleSystem = SensibleSystem;
1465 98873 : thisSetting.LatentSystem = LatentSystem;
1466 98873 : thisSetting.TotalZone = TotalRoomORZone;
1467 98873 : thisSetting.SensibleZone = SensibleRoomORZone;
1468 98873 : thisSetting.LatentZone = latentRoomORZone;
1469 :
1470 98873 : bool Conditioning_load_met = false;
1471 98873 : if (CoolingRequested && (SensibleRoomORZone > StepIns.RequestedCoolingLoad)) {
1472 14096 : Conditioning_load_met = true;
1473 : }
1474 98873 : if (HeatingRequested && (SensibleRoomORZone < StepIns.RequestedHeatingLoad)) {
1475 0 : Conditioning_load_met = true;
1476 : }
1477 98873 : if (!(HeatingRequested || CoolingRequested)) {
1478 42071 : Conditioning_load_met = true;
1479 : }
1480 :
1481 98873 : bool Humidification_load_met = false;
1482 :
1483 98873 : Real64 RequestedDeHumdificationLoad = StepIns.ZoneDehumidificationLoad;
1484 98873 : if (DehumidificationRequested && latentRoomORZone > RequestedDeHumdificationLoad) {
1485 0 : Humidification_load_met = true;
1486 : }
1487 98873 : Real64 RequestedHumdificationLoad = StepIns.ZoneMoistureLoad;
1488 98873 : if (HumidificationRequested && latentRoomORZone < RequestedHumdificationLoad) {
1489 95907 : Humidification_load_met = true;
1490 : }
1491 :
1492 98873 : if (!(HumidificationRequested || DehumidificationRequested)) {
1493 2962 : Humidification_load_met = true;
1494 : }
1495 :
1496 98873 : thisSetting.ElectricalPower = thisSetting.oMode.CalculateCurveVal(
1497 : state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, POWER_CURVE); // [Kw] calculations for fuel in Kw
1498 98873 : thisSetting.SupplyFanElectricPower =
1499 98873 : thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SUPPLY_FAN_POWER);
1500 98873 : thisSetting.ExternalStaticPressure =
1501 98873 : thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, EXTERNAL_STATIC_PRESSURE);
1502 98873 : thisSetting.SecondaryFuelConsumptionRate =
1503 98873 : thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SECOND_FUEL_USE);
1504 98873 : thisSetting.ThirdFuelConsumptionRate =
1505 98873 : thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, THIRD_FUEL_USE);
1506 98873 : thisSetting.WaterConsumptionRate =
1507 98873 : thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, WATER_USE);
1508 :
1509 : // Calculate partload fraction required to meet all requirements
1510 98873 : Real64 PartRuntimeFraction = 0;
1511 197746 : PartRuntimeFraction = CalculatePartRuntimeFraction(MinOA_Msa,
1512 98873 : thisSetting.Supply_Air_Ventilation_Volume * state.dataEnvrn->StdRhoAir,
1513 : StepIns.RequestedCoolingLoad,
1514 : StepIns.RequestedHeatingLoad,
1515 : SensibleRoomORZone,
1516 : StepIns.ZoneDehumidificationLoad,
1517 : StepIns.ZoneMoistureLoad,
1518 : latentRoomORZone); //
1519 :
1520 98873 : Real64 RunFractionTotalFuel =
1521 98873 : thisSetting.ElectricalPower * PartRuntimeFraction; // fraction can be above 1 meaning its not able to do it completely in a time step.
1522 98873 : thisSetting.Runtime_Fraction = PartRuntimeFraction;
1523 :
1524 98873 : if (Conditioning_load_met && Humidification_load_met) {
1525 : // store best performing mode
1526 112334 : if (RunFractionTotalFuel < OptimalSetting_RunFractionTotalFuel) {
1527 6262 : OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel;
1528 6262 : OptimalSetting = thisSetting;
1529 6262 : DidWeMeetLoad = true;
1530 6262 : DidWeMeetHumidificaiton = true;
1531 : }
1532 : } else {
1533 42706 : if (!DidWeMeetLoad && !DidWeMeetHumidificaiton) {
1534 28724 : bool store_best_attempt = false;
1535 :
1536 28724 : if (Conditioning_load_met) {
1537 0 : DidWeMeetLoad = true;
1538 0 : if (HumidificationRequested && (latentRoomORZone < PreviousMaxiumHumidOrDehumidOutput)) {
1539 0 : store_best_attempt = true;
1540 : }
1541 0 : if (DehumidificationRequested && (latentRoomORZone > PreviousMaxiumHumidOrDehumidOutput)) {
1542 0 : store_best_attempt = true;
1543 : }
1544 0 : if (store_best_attempt) {
1545 0 : PreviousMaxiumHumidOrDehumidOutput = latentRoomORZone;
1546 : }
1547 : } else {
1548 28724 : if (!DidWeMeetLoad) {
1549 28724 : if (CoolingRequested && (SensibleRoomORZone > PreviousMaxiumConditioningOutput)) {
1550 1138 : store_best_attempt = true;
1551 : }
1552 28724 : if (HeatingRequested && (SensibleRoomORZone < PreviousMaxiumConditioningOutput)) {
1553 0 : store_best_attempt = true;
1554 : }
1555 28724 : if (store_best_attempt) {
1556 1138 : PreviousMaxiumConditioningOutput = SensibleRoomORZone;
1557 : }
1558 : }
1559 : }
1560 28724 : if (store_best_attempt) {
1561 1138 : OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel;
1562 1138 : OptimalSetting = thisSetting;
1563 1138 : DidWePartlyMeetLoad = true;
1564 : }
1565 : }
1566 : }
1567 : }
1568 :
1569 12739 : if (!EnvironmentConditionsMetOnce) {
1570 0 : ErrorCode = 1;
1571 0 : count_EnvironmentConditionsNotMet++;
1572 : }
1573 12739 : if (!SAHR_OC_MetOnce) {
1574 0 : count_SAHR_OC_MetOnce++;
1575 0 : ErrorCode = 2;
1576 : }
1577 12739 : if (!SAT_OC_MetOnce) {
1578 0 : count_SAT_OC_MetOnce++;
1579 0 : ErrorCode = 3;
1580 : }
1581 : // if we met the load set operating settings to be a combination of the optimal setting at the minium required runtime fraction
1582 12739 : if (DidWeMeetLoad) {
1583 : // add first setting to operating modes
1584 4385 : ErrorCode = 0;
1585 : // save the optimal setting in the
1586 4385 : CurrentOperatingSettings[0] = OptimalSetting;
1587 4385 : PrimaryModeRuntimeFraction = OptimalSetting.Runtime_Fraction;
1588 4385 : oStandBy.Runtime_Fraction = (1 - PrimaryModeRuntimeFraction);
1589 4385 : if (oStandBy.Runtime_Fraction < 0) {
1590 0 : oStandBy.Runtime_Fraction = 0;
1591 : }
1592 4385 : CurrentOperatingSettings[1] = oStandBy;
1593 : } else {
1594 : // if we partly met the load then do the best we can and run full out in that optimal setting.
1595 8354 : if (!DidWeMeetLoad && DidWePartlyMeetLoad) {
1596 1138 : ErrorCode = 0;
1597 1138 : count_DidWeNotMeetLoad++;
1598 1138 : if (OptimalSetting.ElectricalPower == IMPLAUSIBLE_POWER) {
1599 0 : ShowWarningError(state, "Model was not able to provide cooling for a time step, called in HybridEvapCooling:dostep");
1600 0 : OptimalSetting.ElectricalPower = 0;
1601 : }
1602 1138 : OptimalSetting.Runtime_Fraction = 1;
1603 1138 : CurrentOperatingSettings[0] = OptimalSetting;
1604 1138 : PrimaryMode = OptimalSetting.Mode;
1605 1138 : PrimaryModeRuntimeFraction = 1;
1606 : }
1607 : // if we didn't even partially meet the load make sure the operational settings are just the standby mode.
1608 : else {
1609 7216 : oStandBy.Runtime_Fraction = 1;
1610 7216 : CurrentOperatingSettings[0] = oStandBy;
1611 7216 : ErrorCode = -1;
1612 7216 : StandBy = true;
1613 7216 : count_DidWeNotMeetLoad++;
1614 : }
1615 : }
1616 :
1617 : Real64 TimeElapsed =
1618 12739 : state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
1619 :
1620 : // Use the elapsed time to only give a summary of warnings related to the number of Timesteps environmental conditions, or supply air
1621 : // 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
1622 : // day, so report", but that doesn't seem to exist.
1623 12739 : if ((TimeElapsed > 24) && WarnOnceFlag && !state.dataGlobal->WarmupFlag) {
1624 2 : if (count_EnvironmentConditionsNotMet > 0)
1625 0 : ShowWarningError(state,
1626 0 : format("In day {:.1R} was unable to operate for of simulation, {}{:.1R} timesteps because environment conditions "
1627 : "were beyond the allowable operating range for any mode.",
1628 0 : (Real64)state.dataGlobal->DayOfSim,
1629 : Name,
1630 0 : (Real64)count_EnvironmentConditionsNotMet));
1631 2 : if (count_SAHR_OC_MetOnce > 0)
1632 0 : ShowWarningError(state,
1633 0 : format("In day {:.1R} of simulation, {} failed to meet supply air humidity ratio for {:.1R} time steps. For these "
1634 : "time steps For these time steps was set to mode 0{}",
1635 0 : (Real64)state.dataGlobal->DayOfSim,
1636 : Name,
1637 0 : Real64(count_SAHR_OC_MetOnce),
1638 0 : Name));
1639 2 : if (count_SAT_OC_MetOnce > 0)
1640 0 : ShowWarningError(state,
1641 0 : format("In day {:.1R} of simulation, {} failed to meet supply air temperature constraints for {:.1R} time steps. "
1642 : "For these time steps For these time steps{} was set to mode 0",
1643 0 : (Real64)state.dataGlobal->DayOfSim,
1644 : Name,
1645 0 : Real64(count_SAT_OC_MetOnce),
1646 0 : Name));
1647 :
1648 6 : ShowWarningError(state,
1649 6 : format("In day {:.1R} of simulation, {} failed to satisfy sensible load for {:.1R} time steps. For these time steps "
1650 : "settings were selected to provide as much sensible cooling or heating as possible, given other constraints.",
1651 4 : (Real64)state.dataGlobal->DayOfSim,
1652 : Name,
1653 6 : (Real64)count_DidWeNotMeetLoad));
1654 :
1655 2 : count_SAT_OC_MetOnce = 0;
1656 2 : count_DidWeNotMeetLoad = 0;
1657 2 : count_SAHR_OC_MetOnce = 0;
1658 2 : count_EnvironmentConditionsMetOnce = 0;
1659 2 : count_EnvironmentConditionsNotMet = 0;
1660 2 : WarnOnceFlag = false;
1661 : }
1662 12739 : if (state.dataGlobal->HourOfDay == 1 && !WarnOnceFlag && !state.dataGlobal->WarmupFlag) {
1663 2 : WarnOnceFlag = true;
1664 : }
1665 12739 : return ErrorCode;
1666 : }
1667 :
1668 5523 : int Model::CurrentPrimaryMode()
1669 : {
1670 : // SUBROUTINE INFORMATION:
1671 : // AUTHOR Spencer Maxwell Dutton
1672 : // DATE WRITTEN October 2017
1673 : // MODIFIED
1674 : // RE-ENGINEERED na
1675 :
1676 : // PURPOSE OF THIS SUBROUTINE:
1677 : // retunrs the primary mode of operation
1678 :
1679 : // METHODOLOGY EMPLOYED:
1680 : //
1681 :
1682 : // REFERENCES:
1683 : // na
1684 :
1685 : // Using/Aliasing
1686 :
1687 5523 : if (CurrentOperatingSettings.size() > 0) {
1688 5523 : return CurrentOperatingSettings[0].Mode;
1689 : } else
1690 0 : return -1;
1691 : }
1692 5523 : Real64 Model::CurrentPrimaryRuntimeFraction()
1693 : {
1694 : // SUBROUTINE INFORMATION:
1695 : // AUTHOR Spencer Maxwell Dutton
1696 : // DATE WRITTEN October 2017
1697 : // MODIFIED
1698 : // RE-ENGINEERED na
1699 :
1700 : // PURPOSE OF THIS SUBROUTINE:
1701 : // returns the runtime fraction of the primary setting.
1702 :
1703 : // METHODOLOGY EMPLOYED:
1704 : //
1705 :
1706 : // REFERENCES:
1707 : // na
1708 :
1709 : // Using/Aliasing
1710 5523 : if (CurrentOperatingSettings.size() > 0) {
1711 5523 : return CurrentOperatingSettings[0].Runtime_Fraction;
1712 : } else
1713 0 : return -1;
1714 : }
1715 12797 : void Model::DetermineCoolingVentilationOrHumidificationNeeds(CStepInputs &StepIns)
1716 : {
1717 : // SUBROUTINE INFORMATION:
1718 : // AUTHOR Spencer Maxwell Dutton
1719 : // DATE WRITTEN October 2017
1720 : // MODIFIED
1721 : // RE-ENGINEERED na
1722 :
1723 : // PURPOSE OF THIS SUBROUTINE:
1724 : // Sets member boolean variables to establish if the Cooling, Heating, ventilation or dehumidifcation needs are met.
1725 :
1726 : // METHODOLOGY EMPLOYED:
1727 : //
1728 :
1729 : // REFERENCES:
1730 : // na
1731 :
1732 : // Using/Aliasing
1733 12797 : CoolingRequested = false;
1734 12797 : HeatingRequested = false;
1735 12797 : VentilationRequested = false;
1736 12797 : DehumidificationRequested = false;
1737 12797 : HumidificationRequested = false;
1738 : // establish if conditioning needed
1739 12797 : if (StepIns.RequestedCoolingLoad >= MINIMUM_LOAD_TO_ACTIVATE) {
1740 2652 : CoolingRequested = true;
1741 2652 : StepIns.RequestedHeatingLoad = 0;
1742 : }
1743 12797 : if (StepIns.RequestedHeatingLoad <= -MINIMUM_LOAD_TO_ACTIVATE) {
1744 7216 : HeatingRequested = true;
1745 7216 : StepIns.RequestedCoolingLoad = 0;
1746 : }
1747 : // establish if ventilation needed
1748 12797 : if (StepIns.MinimumOA > 0) VentilationRequested = true;
1749 : // Load required to meet dehumidifying setpoint (<0 = a dehumidify load) [kgWater/s]
1750 12797 : if (StepIns.ZoneDehumidificationLoad < 0) {
1751 2 : DehumidificationRequested = true;
1752 2 : StepIns.ZoneMoistureLoad = 0;
1753 : }
1754 : // Load required to meet humidifying setpoint (>0 = a humidify load) [kgWater/s]
1755 12797 : if (StepIns.ZoneMoistureLoad > 0) {
1756 11961 : StepIns.ZoneDehumidificationLoad = 0;
1757 11961 : HumidificationRequested = true;
1758 : }
1759 12797 : }
1760 :
1761 : // doStep is passed some variables that could have just used the class members, but this adds clarity about whats needed, especially helpful in
1762 : // unit testing
1763 12797 : void Model::doStep(EnergyPlusData &state,
1764 : Real64 RequestedCoolingLoad, // in joules, cooling load as negitive
1765 : Real64 RequestedHeatingLoad, // in joules, heating load as positive
1766 : Real64 OutputRequiredToHumidify, // Load required to meet humidifying setpoint (>0 = a humidify load) [kgWater/s]
1767 : Real64 OutputRequiredToDehumidify, // Load required to meet dehumidifying setpoint (<0 = a dehumidify load) [kgWater/s]
1768 : Real64 DesignMinVR) // mass flow rate of design ventilation air kg/s
1769 : {
1770 : // SUBROUTINE INFORMATION:
1771 : // AUTHOR Spencer Dutton
1772 : // DATE WRITTEN May 2017
1773 : // MODIFIED na
1774 : // RE-ENGINEERED na
1775 :
1776 : // PURPOSE OF THIS SUBROUTINE:
1777 : // This subroutine Model::doStep, the main calculation steps
1778 : // 1)Collate required inputs into a CStepInputs, this helps with the unit tests
1779 : // so we always know what values need to be set.
1780 : // 2)Calculate W humidity ratios for outdoor air and return air.
1781 : // 3)Sets boolean values for each potential conditioning requirement;
1782 : // CoolingRequested, HeatingRequested, VentilationRequested, DehumidificationRequested, HumidificationRequested
1783 : // 4)Take the first operating mode which is always standby and calculate the use curves to determine performance metrics for
1784 : // the standby mode including energy use and other outputs
1785 : // 5)Test system availbility status and go into standby if unit is off or not needed (booleans listed in 3 are all false)
1786 : // 6) Set the operating conditions and respective part load fractions.
1787 : // 7) Set timestep average outlet condition, considering all operating conditions and runtimes.
1788 : // METHODOLOGY EMPLOYED:
1789 : // na
1790 :
1791 : // REFERENCES: OutletVolumetricFlowRate, SupplyVentilationVolume, MinOA_Msa, SupplyVentilationAir
1792 : // na
1793 :
1794 : // set requested loads to output variables
1795 12797 : RequestedLoadToHeatingSetpoint = RequestedHeatingLoad;
1796 12797 : RequestedLoadToCoolingSetpoint = RequestedCoolingLoad;
1797 12797 : Real64 LambdaRa = Psychrometrics::PsyHfgAirFnWTdb(0, InletTemp);
1798 12797 : RequestedHumdificationMass = OutputRequiredToHumidify;
1799 12797 : RequestedHumdificationLoad = OutputRequiredToHumidify * LambdaRa; // [W];
1800 12797 : RequestedHumdificationEnergy =
1801 12797 : OutputRequiredToHumidify * LambdaRa * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour; // [j]
1802 :
1803 12797 : RequestedDeHumdificationMass = OutputRequiredToDehumidify;
1804 12797 : RequestedDeHumdificationLoad = OutputRequiredToDehumidify * LambdaRa; // [W];
1805 12797 : RequestedDeHumdificationEnergy =
1806 12797 : OutputRequiredToDehumidify * LambdaRa * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour; // [j]
1807 :
1808 12797 : MinOA_Msa = DesignMinVR; // as mass flow kg/s
1809 :
1810 : // Collate all the inputs required for calculation into one local data structure CStepInputs, this helps with the unit tests so we always know
1811 : // what values need to be set
1812 12797 : CStepInputs StepIns;
1813 12797 : StepIns.Tosa = SecInletTemp; // degrees C
1814 12797 : StepIns.Tra = InletTemp; // degrees C
1815 12797 : StepIns.RHosa = SecInletRH; // RH as 0-1
1816 12797 : StepIns.RHra = InletRH;
1817 : // For historical reasons cooling is positive, heating negative throughout the calculation
1818 12797 : StepIns.RequestedCoolingLoad = -RequestedCoolingLoad; // Cooling positive now, heating negative
1819 12797 : StepIns.RequestedHeatingLoad = -RequestedHeatingLoad; // Cooling positive now, heating negative
1820 :
1821 12797 : StepIns.ZoneMoistureLoad = RequestedHumdificationLoad;
1822 12797 : StepIns.ZoneDehumidificationLoad = RequestedDeHumdificationLoad;
1823 12797 : StepIns.MinimumOA = DesignMinVR;
1824 : // calculate W humidity ratios for outdoor air and return air
1825 12797 : Real64 Wosa = PsyWFnTdbRhPb(state, StepIns.Tosa, StepIns.RHosa, state.dataEnvrn->OutBaroPress);
1826 12797 : Real64 Wra = PsyWFnTdbRhPb(state, StepIns.Tra, StepIns.RHra, InletPressure);
1827 : // Sets boolean values for each potential conditioning requirement; CoolingRequested, HeatingRequested, VentilationRequested,
1828 : // DehumidificationRequested, HumidificationRequested
1829 12797 : DetermineCoolingVentilationOrHumidificationNeeds(StepIns);
1830 : // Take the first operating mode which is always standby and calculate the curve values
1831 : // to determine performance metrics for the standby mode including energy use and other outputs
1832 :
1833 25594 : CMode Mode = *(OperatingModes.begin());
1834 12797 : if (SetStandByMode(state, Mode, StepIns.Tosa, Wosa, StepIns.Tra, Wra)) {
1835 0 : std::string ObjectID = Name.c_str();
1836 0 : ShowSevereError(state,
1837 : "Standby mode not defined correctly, as the mode is defined there are zero combinations of acceptible outside air "
1838 0 : "fractions and supply air mass flow rate, called in object " +
1839 : ObjectID);
1840 : }
1841 : // Test system availability status
1842 12797 : UnitOn = 1;
1843 12797 : bool ForceOff = false;
1844 12797 : StandBy = false;
1845 12797 : if (GetCurrentScheduleValue(state, SchedPtr) <= 0 || AvailStatus == 1) {
1846 0 : UnitOn = 0;
1847 0 : ForceOff = true;
1848 : }
1849 :
1850 : // Initialize all settings for all operating modes
1851 12797 : int size = CurrentOperatingSettings.size();
1852 25594 : CSetting empty_setting;
1853 63985 : for (int i = 1; i < size; i++) {
1854 51188 : CurrentOperatingSettings[i] = empty_setting;
1855 : }
1856 :
1857 : // Go into standby if unit is off or not needed
1858 12797 : if ((!CoolingRequested && !HeatingRequested && !VentilationRequested && !HumidificationRequested && !DehumidificationRequested) || ForceOff) {
1859 58 : StandBy = true;
1860 58 : oStandBy.Runtime_Fraction = 1;
1861 58 : CurrentOperatingSettings[0] = oStandBy;
1862 58 : ErrorCode = 0;
1863 58 : PrimaryMode = 0;
1864 58 : PrimaryModeRuntimeFraction = 0;
1865 : } else {
1866 : // set the operating conditions and respective part load fractions.
1867 12739 : ErrorCode = SetOperatingSetting(state, StepIns);
1868 : }
1869 :
1870 12797 : Real64 QTotZoneOut = 0;
1871 : // now class members QSensZoneOut = 0;
1872 : // QLatentZoneOut = 0;
1873 :
1874 12797 : Real64 QTotSystemOut = 0;
1875 12797 : Real64 QSensSystemOut = 0;
1876 12797 : Real64 QLatentSystemOut = 0;
1877 : // Even if its off or in standby we still need to continue to calculate standby loads
1878 : // All powers are calculated in Watts amd energies in Joules
1879 :
1880 12797 : SupplyVentilationVolume = CalculateTimeStepAverage(SYSTEMOUTPUTS::VENTILATION_AIR_V);
1881 12797 : if (state.dataEnvrn->StdRhoAir > 1) {
1882 12797 : SupplyVentilationAir = SupplyVentilationVolume * state.dataEnvrn->StdRhoAir;
1883 : } else {
1884 0 : SupplyVentilationAir = SupplyVentilationVolume * 1.225;
1885 : }
1886 : // set timestep average outlet condition, considering all operating conditions and runtimes.
1887 12797 : OutletTemp = CheckVal_T(state, CalculateTimeStepAverage(SYSTEMOUTPUTS::SUPPLY_AIR_TEMP));
1888 12797 : OutletHumRat = CheckVal_W(state, CalculateTimeStepAverage(SYSTEMOUTPUTS::SUPPLY_AIR_HR), OutletTemp, OutletPressure);
1889 :
1890 12797 : OutletRH = PsyRhFnTdbWPb(state, OutletTemp, OutletHumRat, OutletPressure);
1891 12797 : Real64 OperatingAverageMixedAirTemperature = CalculateTimeStepAverage(SYSTEMOUTPUTS::MIXED_AIR_TEMP);
1892 12797 : Real64 OperatingMixedAirW = CalculateTimeStepAverage(SYSTEMOUTPUTS::MIXED_AIR_HR);
1893 12797 : Real64 MixedAirEnthalpy = PsyHFnTdbW(OperatingAverageMixedAirTemperature, OperatingMixedAirW);
1894 12797 : OutletEnthalpy = PsyHFnTdbRhPb(state, OutletTemp, OutletRH, InletPressure);
1895 12797 : OutletMassFlowRate = CalculateTimeStepAverage(SYSTEMOUTPUTS::SUPPLY_MASS_FLOW);
1896 :
1897 12797 : if (state.dataEnvrn->StdRhoAir > 1) {
1898 12797 : OutletVolumetricFlowRate = OutletMassFlowRate / state.dataEnvrn->StdRhoAir;
1899 : } else {
1900 0 : OutletVolumetricFlowRate = OutletMassFlowRate / 1.225;
1901 : }
1902 :
1903 12797 : if (!StandBy) {
1904 5523 : if (OutletMassFlowRate > 0) {
1905 5523 : averageOSAF = SupplyVentilationAir / OutletMassFlowRate;
1906 : } else {
1907 0 : std::string ObjectID = Name.c_str();
1908 0 : if (CoolingRequested || HeatingRequested) {
1909 0 : ShowSevereError(
1910 : state,
1911 0 : "Outlet air mass flow rate of zero during period with conditioning need, check mode definition. Called in object " + Name);
1912 : }
1913 0 : averageOSAF = 1;
1914 : }
1915 : // Calculate timestep average unit and system
1916 5523 : PrimaryMode = CurrentPrimaryMode();
1917 5523 : PrimaryModeRuntimeFraction = CurrentPrimaryRuntimeFraction();
1918 5523 : Real64 Outletcp = PsyCpAirFnW(OutletHumRat); // J/degreesK.kg
1919 5523 : Real64 Returncp = PsyCpAirFnW(Wra); // J/degreesK.kg
1920 5523 : Real64 Outdoorcp = PsyCpAirFnW(Wosa); // J/degreesK.kg
1921 : // Zone Sensible Cooling{ W } = m'SA {kg/s} * 0.5*(cpRA+cpSA) {kJ/kg-C} * (T_RA - T_SA) {C}
1922 : // Zone Latent Cooling{ W } = m'SAdryair {kg/s} * L {kJ/kgWater} * (HR_RA - HR_SA) {kgWater/kgDryAir}
1923 : // Zone Total Cooling{ W } = m'SAdryair {kg/s} * (h_RA - h_SA) {kJ/kgDryAir}
1924 5523 : QSensZoneOut = OutletMassFlowRate * 0.5 * (Returncp + Outletcp) * (StepIns.Tra - OutletTemp); // Watts
1925 5523 : Real64 OutletMassFlowRateDry = OutletMassFlowRate * (1 - Wsa);
1926 5523 : Real64 LambdaSa = Psychrometrics::PsyHfgAirFnWTdb(0, OutletTemp);
1927 5523 : QLatentZoneOutMass = OutletMassFlowRateDry * (InletHumRat - OutletHumRat); // Watts
1928 5523 : QLatentZoneOut = QLatentZoneOutMass * LambdaSa;
1929 5523 : QTotZoneOut = OutletMassFlowRateDry * (InletEnthalpy - OutletEnthalpy); // Watts
1930 5523 : Real64 QLatentCheck = QTotZoneOut - QSensZoneOut; // Watts
1931 :
1932 : // 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)
1933 : // System Latent Cooling{ W } = m'SAdryair {kg/s} * L {kJ/kgWater} * (HR_RA + OSAF *(HR_OSA - HR_RA) - HR_SA) {kgWater/kgDryAir}
1934 : // System Total Cooling{ W } = m'SAdryair {kg/s} * (h_RA + OSAF*(h_OSA - h_RA) - h_SA) {kJ/kgDryAir}
1935 :
1936 5523 : Real64 SystemTimeStepCp = Returncp + averageOSAF * (Outdoorcp - Returncp) + Outletcp; // cpRA + OSAF*(cpOSA-cpRA) + cpSA //J/degreesK.kg
1937 5523 : Real64 SystemTimeStepW = InletHumRat + averageOSAF * (Wosa - Wra) - OutletHumRat; // HR_RA + OSAF *(HR_OSA - HR_RA) - HR_SA
1938 5523 : Real64 SystemTimeStepT = StepIns.Tra + averageOSAF * (StepIns.Tosa - StepIns.Tra) - OutletTemp; // T_RA + OSAF *(T_OSA - T_RA) - T_SA
1939 5523 : QSensSystemOut = 0.5 * SystemTimeStepCp * OutletMassFlowRate * SystemTimeStepT; // Watts
1940 :
1941 5523 : QLatentSystemOut = LambdaSa * OutletMassFlowRateDry * SystemTimeStepW; // Watts
1942 5523 : QTotSystemOut = OutletMassFlowRateDry * (MixedAirEnthalpy - OutletEnthalpy); // Watts
1943 5523 : QLatentCheck = QTotSystemOut - QSensSystemOut; // Watts
1944 :
1945 : // reset outputs
1946 5523 : ResetOutputs();
1947 : // set UNIT outputs for cooling and heating
1948 5523 : if (QTotZoneOut > 0) // zone cooling is positive, else remain zero
1949 : {
1950 4010 : UnitTotalCoolingRate = std::abs(QTotZoneOut); // Watts
1951 4010 : UnitTotalCoolingEnergy = UnitTotalCoolingRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour; // J
1952 : } else {
1953 1513 : UnitTotalHeatingRate = std::abs(QTotZoneOut); // Watts
1954 1513 : UnitTotalHeatingEnergy = UnitTotalHeatingRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour; // J
1955 : }
1956 :
1957 5523 : if (QSensZoneOut > 0) // zone cooling is positive, else remain zero
1958 : {
1959 4015 : UnitSensibleCoolingRate = std::abs(QSensZoneOut); // Watts
1960 4015 : UnitSensibleCoolingEnergy = UnitSensibleCoolingRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour; // J
1961 : } else {
1962 1508 : UnitSensibleHeatingRate = std::abs(QSensZoneOut); // Watts
1963 1508 : UnitSensibleHeatingEnergy = UnitSensibleHeatingRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour; // J
1964 : }
1965 :
1966 5523 : if ((UnitTotalCoolingRate - UnitSensibleCoolingRate) > 0) {
1967 1654 : UnitLatentCoolingRate = UnitTotalCoolingRate - UnitSensibleCoolingRate; // Watts
1968 1654 : UnitLatentCoolingEnergy = UnitTotalCoolingEnergy - UnitSensibleCoolingEnergy; // J
1969 : }
1970 5523 : if ((UnitTotalCoolingRate - UnitSensibleCoolingRate) < 0) {
1971 2361 : UnitLatentHeatingRate = UnitTotalHeatingRate - UnitSensibleHeatingRate; // Watts
1972 2361 : UnitLatentHeatingEnergy = UnitTotalHeatingEnergy - UnitSensibleHeatingEnergy; // J
1973 : }
1974 :
1975 : // set SYSTEM outputs
1976 5523 : if (QTotSystemOut > 0) // system cooling
1977 : {
1978 3020 : SystemTotalCoolingRate = std::abs(QTotSystemOut);
1979 3020 : SystemTotalCoolingEnergy = SystemTotalCoolingRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
1980 : } else {
1981 2503 : SystemTotalHeatingRate = std::abs(QTotSystemOut);
1982 2503 : SystemTotalHeatingEnergy = SystemTotalHeatingRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
1983 : }
1984 :
1985 5523 : if (QSensSystemOut > 0) // system sensible cooling
1986 : {
1987 3018 : SystemSensibleCoolingRate = std::abs(QSensSystemOut);
1988 3018 : SystemSensibleCoolingEnergy = SystemSensibleCoolingRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
1989 : } else {
1990 2505 : SystemSensibleHeatingRate = std::abs(QSensSystemOut);
1991 2505 : SystemSensibleHeatingEnergy = SystemSensibleHeatingRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
1992 : }
1993 5523 : if ((SystemTotalCoolingRate - SystemSensibleCoolingRate) > 0) {
1994 408 : SystemLatentCoolingRate = SystemTotalCoolingRate - SystemSensibleCoolingRate;
1995 408 : SystemLatentCoolingEnergy = SystemTotalCoolingEnergy - SystemSensibleCoolingEnergy;
1996 : }
1997 5523 : if ((SystemTotalHeatingRate - SystemSensibleHeatingRate) < 0) {
1998 1454 : SystemLatentHeatingRate = SystemTotalHeatingRate - SystemSensibleHeatingRate;
1999 1454 : SystemLatentHeatingEnergy = SystemTotalHeatingEnergy - SystemSensibleHeatingEnergy;
2000 : }
2001 : } else // unit is in standby so reset conditioning outputs
2002 : {
2003 7274 : QTotZoneOut = 0;
2004 7274 : QSensZoneOut = 0;
2005 7274 : QLatentZoneOut = 0;
2006 7274 : QLatentZoneOutMass = 0;
2007 7274 : QTotSystemOut = 0;
2008 7274 : QSensSystemOut = 0;
2009 7274 : QLatentSystemOut = 0;
2010 : // reset outputs
2011 7274 : ResetOutputs();
2012 : }
2013 :
2014 : // set timestep outputs calculated considering different runtime fractions.
2015 12797 : SupplyFanElectricPower = CalculateTimeStepAverage(SYSTEMOUTPUTS::OSUPPLY_FAN_POWER); // Watts
2016 12797 : SupplyFanElectricEnergy = SupplyFanElectricPower * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
2017 12797 : SecondaryFuelConsumptionRate = CalculateTimeStepAverage(SYSTEMOUTPUTS::OSECOND_FUEL_USE);
2018 12797 : SecondaryFuelConsumption = SecondaryFuelConsumptionRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
2019 12797 : ThirdFuelConsumptionRate = CalculateTimeStepAverage(SYSTEMOUTPUTS::OTHIRD_FUEL_USE);
2020 12797 : ThirdFuelConsumption = ThirdFuelConsumptionRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
2021 12797 : WaterConsumptionRate = CalculateTimeStepAverage(SYSTEMOUTPUTS::OWATER_USE);
2022 12797 : WaterConsumption = WaterConsumptionRate * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
2023 12797 : ExternalStaticPressure = CalculateTimeStepAverage(SYSTEMOUTPUTS::OEXTERNAL_STATIC_PRESSURE);
2024 :
2025 12797 : FinalElectricalPower = CalculateTimeStepAverage(SYSTEMOUTPUTS::SYSTEM_FUEL_USE);
2026 12797 : FinalElectricalEnergy = FinalElectricalPower * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
2027 12797 : }
2028 :
2029 : } // namespace HybridEvapCoolingModel
2030 2313 : } // namespace EnergyPlus
|