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

Generated by: LCOV version 2.0-1