LCOV - code coverage report
Current view: top level - EnergyPlus - HybridEvapCoolingModel.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 83.9 % 977 820
Test Date: 2025-05-22 16:09:37 Functions: 100.0 % 32 32

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

Generated by: LCOV version 2.0-1