LCOV - code coverage report
Current view: top level - EnergyPlus - HybridEvapCoolingModel.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 85.0 % 983 836
Test Date: 2025-06-02 07:23:51 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       114224 :     CMode::CMode()
     108       228448 :         : ModeID(0.0), Max_Msa(0.0), Min_Msa(0.0), Min_OAF(0.0), Max_OAF(0.0), Minimum_Outdoor_Air_Temperature(0.0),
     109       114224 :           Maximum_Outdoor_Air_Temperature(0.0), Minimum_Outdoor_Air_Humidity_Ratio(0.0), Maximum_Outdoor_Air_Humidity_Ratio(0.0),
     110       114224 :           ModelScalingFactor(0.0)
     111              :     {
     112       114224 :         MODE_BLOCK_OFFSET_Alpha = 9;
     113       114224 :         BLOCK_HEADER_OFFSET_Alpha = 20;
     114       114224 :         MODE1_BLOCK_OFFSET_Number = 2;
     115       114224 :         MODE_BLOCK_OFFSET_Number = 16;
     116       114224 :         BLOCK_HEADER_OFFSET_Number = 6;
     117       114224 :     }
     118              : 
     119            5 :     bool CMode::InitializeOutdoorAirTemperatureConstraints(Real64 min, Real64 max)
     120              :     {
     121              :         // note If this field is blank, there should be no lower constraint on outside air temperature
     122            5 :         Minimum_Outdoor_Air_Temperature = min;
     123            5 :         Maximum_Outdoor_Air_Temperature = max;
     124            5 :         return true;
     125              :     }
     126            5 :     bool CMode::InitializeOutdoorAirHumidityRatioConstraints(Real64 min, Real64 max)
     127              :     {
     128              :         // minimum 0.00 maximum 0.10, units kgWater / kgDryAir
     129              :         // note Mode0 will not be 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            5 :         Minimum_Outdoor_Air_Humidity_Ratio = min;
     133            5 :         Maximum_Outdoor_Air_Humidity_Ratio = max;
     134            5 :         return true;
     135              :     }
     136            5 :     bool CMode::InitializeOutdoorAirRelativeHumidityConstraints(Real64 min, Real64 max)
     137              :     {
     138              :         // minimum 0.00,maximum 100.00, units percent, Mode0 will not be considered when the outside air relative humidity is below the value in this
     139              :         // field.
     140              :         // note If this field is blank, the lower constraint on outside air relative humidity will be 0.00% (default 0.00), the upper constraint on
     141              :         // outside air relative humidity will be 100.00%, (default 100.00)
     142            5 :         Minimum_Outdoor_Air_Relative_Humidity = min;
     143            5 :         Maximum_Outdoor_Air_Relative_Humidity = max;
     144            5 :         return true;
     145              :     }
     146            5 :     bool CMode::InitializeReturnAirTemperatureConstraints(Real64 min, Real64 max)
     147              :     {
     148              :         // will not be considered when the return air temperature is below the value in this field.
     149              :         // If this field is blank, there will be no lower constraint on return air temperature
     150            5 :         Minimum_Return_Air_Temperature = min;
     151            5 :         Maximum_Return_Air_Temperature = max;
     152            5 :         return true;
     153              :     }
     154            5 :     bool CMode::InitializeReturnAirHumidityRatioConstraints(Real64 min, Real64 max)
     155              :     {
     156              :         // minimum 0.00 maximum 0.10, units kgWater / kgDryAir
     157              :         // note Mode0 will not be 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            5 :         Minimum_Return_Air_Humidity_Ratio = min;
     161            5 :         Maximum_Return_Air_Humidity_Ratio = max;
     162            5 :         return true;
     163              :     }
     164            5 :     bool CMode::InitializeReturnAirRelativeHumidityConstraints(Real64 min, Real64 max)
     165              :     {
     166              :         // minimum 0.00,maximum 100.00, units percent, Mode0 will not be considered when the outside air relative humidity is below the value in this
     167              :         // field.
     168              :         // note If this field is blank, the lower constraint on outside air relative humidity will be 0.00% (default 0.00), the upper constraint on
     169              :         // outside air relative humidity will be 100.00%, (default 100.00)
     170            5 :         Minimum_Return_Air_Relative_Humidity = min;
     171            5 :         Maximum_Return_Air_Relative_Humidity = max;
     172            5 :         return true;
     173              :     }
     174            5 :     bool CMode::InitializeOSAFConstraints(Real64 minOSAF, Real64 maxOSAF)
     175              :     {
     176              :         // minimum 0.00, maximum 1.00, Outdoor air fractions below this value will not be considered.
     177              :         // If this field is blank, the lower constraint on outside air fraction will be 0.00,default 0.10
     178            5 :         Min_OAF = minOSAF;
     179            5 :         Max_OAF = maxOSAF;
     180            5 :         return true;
     181              :     }
     182            5 :     bool CMode::InitializeMsaRatioConstraints(Real64 minMsa, Real64 maxMsa)
     183              :     {
     184              :         // minimum 0.00, maximum 1.00, Supply air mass flow rate ratios below this value will not be considered.
     185              :         // Supply air mass flow rate ratio describes supply air mass flow rate as a fraction of mass flow rate associated with the value in field :
     186              :         // "System Maximum Supply Air Flow Rate".  If this field is blank, the lower constraint on outside air fraction will be 0.00,default 0.10
     187            5 :         Min_Msa = minMsa;
     188            5 :         Max_Msa = maxMsa;
     189            5 :         return true;
     190              :     }
     191      1282389 :     bool CMode::ValidPointer(int curve_pointer)
     192              :     {
     193      1282389 :         if (curve_pointer >= 0) {
     194      1060741 :             return true;
     195              :         } else {
     196       221648 :             return false;
     197              :         }
     198              :     }
     199      1282389 :     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      1282389 :         Real64 Y_val = 0;
     230              : 
     231      1282389 :         switch (curveType) {
     232       221180 :         case TEMP_CURVE:
     233       221180 :             if (ValidPointer(Tsa_curve_pointer)) {
     234       221180 :                 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       221180 :             break;
     239              : 
     240       221180 :         case W_CURVE:
     241       221180 :             if (ValidPointer(HRsa_curve_pointer)) {
     242       221180 :                 Y_val = CurveValue(state, HRsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
     243       221180 :                 Y_val = max(min(Y_val, 1.0), 0.0);
     244              :             } else {
     245            0 :                 Y_val = Wra; // return HR
     246              :             }
     247       221180 :             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       114204 :         case POWER_CURVE:
     251       114204 :             if (ValidPointer(Psa_curve_pointer)) {
     252       114204 :                 Y_val = ModelScalingFactor * CurveValue(state, Psa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
     253              :             } else {
     254            0 :                 Y_val = 0;
     255              :             }
     256       114204 :             break;
     257              : 
     258       322109 :         case SUPPLY_FAN_POWER:
     259       322109 :             if (ValidPointer(SFPsa_curve_pointer)) {
     260       322109 :                 Y_val = ModelScalingFactor * CurveValue(state, SFPsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
     261              :             } else {
     262            0 :                 Y_val = 0;
     263              :             }
     264       322109 :             break;
     265              : 
     266       100929 :         case EXTERNAL_STATIC_PRESSURE:
     267       100929 :             if (ValidPointer(ESPsa_curve_pointer)) {
     268       100929 :                 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       100929 :             break;
     273              : 
     274       100929 :         case SECOND_FUEL_USE:
     275       100929 :             if (ValidPointer(SFUsa_curve_pointer)) {
     276        46017 :                 Y_val = ModelScalingFactor * CurveValue(state, SFUsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
     277              :             } else {
     278        54912 :                 Y_val = 0; // or set a more reasonable default
     279              :             }
     280       100929 :             break;
     281              : 
     282       100929 :         case THIRD_FUEL_USE:
     283       100929 :             if (ValidPointer(TFUsa_curve_pointer)) {
     284            0 :                 Y_val = ModelScalingFactor * CurveValue(state, TFUsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
     285              :             } else {
     286       100929 :                 Y_val = 0; // or set a more reasonable default
     287              :             }
     288       100929 :             break;
     289              : 
     290       100929 :         case WATER_USE:
     291       100929 :             if (ValidPointer(WUsa_curve_pointer)) {
     292        35122 :                 Y_val = ModelScalingFactor * CurveValue(state, WUsa_curve_pointer, Tosa, Wosa, Tra, Wra, Msa, OSAF);
     293              :             } else {
     294        65807 :                 Y_val = 0; // or set a more reasonable default
     295              :             }
     296       100929 :             break;
     297              : 
     298            0 :         default:
     299            0 :             break;
     300              :         }
     301              : 
     302      1282389 :         return Y_val;
     303              :     }
     304           48 :     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           48 :         switch (curveType) {
     323            6 :         case TEMP_CURVE:
     324            6 :             Tsa_curve_pointer = curve_ID;
     325            6 :             break;
     326            6 :         case W_CURVE:
     327            6 :             HRsa_curve_pointer = curve_ID;
     328            6 :             break;
     329            6 :         case POWER_CURVE:
     330            6 :             Psa_curve_pointer = curve_ID;
     331            6 :             break;
     332            6 :         case SUPPLY_FAN_POWER:
     333            6 :             SFPsa_curve_pointer = curve_ID;
     334            6 :             break;
     335            6 :         case EXTERNAL_STATIC_PRESSURE:
     336            6 :             ESPsa_curve_pointer = curve_ID;
     337            6 :             break;
     338            6 :         case SECOND_FUEL_USE:
     339            6 :             SFUsa_curve_pointer = curve_ID;
     340            6 :             break;
     341            6 :         case THIRD_FUEL_USE:
     342            6 :             TFUsa_curve_pointer = curve_ID;
     343            6 :             break;
     344            6 :         case WATER_USE:
     345            6 :             WUsa_curve_pointer = curve_ID;
     346            6 :             break;
     347            0 :         default:
     348            0 :             break;
     349              :         }
     350           48 :     }
     351              : 
     352            6 :     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            6 :         if (Min_Msa == Max_Msa) {
     378            1 :             sol.MassFlowRatio.push_back(Max_Msa);
     379              :         } else {
     380            5 :             Real64 ResolutionMsa = (Max_Msa - Min_Msa) * 0.2;
     381           33 :             for (Real64 Msa_val = Max_Msa; Msa_val >= Min_Msa; Msa_val -= ResolutionMsa) {
     382           28 :                 sol.MassFlowRatio.push_back(Msa_val);
     383              :             }
     384              :         }
     385              : 
     386            6 :         if (Min_OAF == Max_OAF) {
     387            6 :             sol.OutdoorAirFraction.push_back(Max_OAF);
     388              :         } else {
     389            0 :             Real64 ResolutionOSA = (Max_OAF - Min_OAF) * 0.2;
     390            0 :             for (Real64 OAF_val = Max_OAF; OAF_val >= Min_OAF; OAF_val -= ResolutionOSA) {
     391            0 :                 sol.OutdoorAirFraction.push_back(OAF_val);
     392              :             }
     393              :         }
     394            6 :     }
     395              : 
     396            6 :     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            6 :         CMode newMode;
     405            6 :         bool error = newMode.ParseMode(
     406              :             state, ModeCounter, &OperatingModes, ScalingFactor, Alphas, cAlphaFields, Numbers, cNumericFields, lAlphaBlanks, cCurrentModuleObject);
     407            6 :         ModeCounter++;
     408            6 :         return error;
     409            6 :     }
     410              : 
     411            6 :     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            6 :         ModeID = ModeCounter;
     441            6 :         ModelScalingFactor = ScalingFactor;
     442              : 
     443              :         int inter_Number;
     444            6 :         bool ErrorsFound = false;
     445            6 :         int inter_Alpha = BLOCK_HEADER_OFFSET_Alpha + MODE_BLOCK_OFFSET_Alpha * ModeID;
     446            6 :         if (ModeID > 0) {
     447            5 :             inter_Number = BLOCK_HEADER_OFFSET_Number + MODE1_BLOCK_OFFSET_Number + MODE_BLOCK_OFFSET_Number * (ModeID - 1);
     448              :         } else {
     449            1 :             inter_Number = BLOCK_HEADER_OFFSET_Number + MODE1_BLOCK_OFFSET_Number;
     450              :         }
     451            6 :         std::ostringstream strs;
     452            6 :         strs << ModeID;
     453              : 
     454            6 :         int curveID = -1;
     455            6 :         if (lAlphaBlanks(inter_Alpha)) {
     456            0 :             ModeName = "Mode" + strs.str();
     457              :         } else {
     458            6 :             ModeName = Alphas(inter_Alpha);
     459              :         }
     460              : 
     461            6 :         curveID = -1;
     462            6 :         inter_Alpha = inter_Alpha + 1;
     463            6 :         if (lAlphaBlanks(inter_Alpha)) {
     464            1 :             InitializeCurve(TEMP_CURVE, curveID); // as this is invalid curve id CalculateCurveVal will return a default when called
     465              :         } else {
     466            5 :             curveID = GetCurveIndex(state, Alphas(inter_Alpha));
     467            5 :             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            5 :                 InitializeCurve(TEMP_CURVE, curveID);
     474              :             }
     475              :         }
     476              : 
     477            6 :         inter_Alpha = inter_Alpha + 1;
     478              : 
     479              :         // A22, \field Mode0 Supply Air Humidity Ratio Lookup Table Name
     480            6 :         curveID = -1;
     481            6 :         if (lAlphaBlanks(inter_Alpha)) {
     482            1 :             InitializeCurve(W_CURVE, curveID); // as this is invalid curve id CalculateCurveVal will return a default  when called
     483              :         } else {
     484            5 :             curveID = GetCurveIndex(state, Alphas(inter_Alpha));
     485            5 :             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            5 :                 InitializeCurve(W_CURVE, curveID);
     492              :             }
     493              :         }
     494            6 :         inter_Alpha = inter_Alpha + 1;
     495              :         // A23, \field Mode0 System Electric Power Lookup Table Name
     496            6 :         curveID = -1;
     497            6 :         if (lAlphaBlanks(inter_Alpha)) {
     498            0 :             InitializeCurve(POWER_CURVE, curveID); // as this is invalid curve id CalculateCurveVal will return a default
     499              :         } else {
     500            6 :             curveID = GetCurveIndex(state, Alphas(inter_Alpha));
     501            6 :             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            6 :                 InitializeCurve(POWER_CURVE, curveID);
     508              :             }
     509              :         }
     510              :         // A24, \field Mode0 Supply Fan Electric Power Lookup Table Name
     511            6 :         inter_Alpha = inter_Alpha + 1;
     512            6 :         curveID = -1;
     513            6 :         if (lAlphaBlanks(inter_Alpha)) {
     514            1 :             InitializeCurve(SUPPLY_FAN_POWER, curveID); // as this is invalid curve id CalculateCurveVal will return a default
     515              :         } else {
     516            5 :             curveID = GetCurveIndex(state, Alphas(inter_Alpha));
     517            5 :             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            5 :                 InitializeCurve(SUPPLY_FAN_POWER, curveID);
     524              :             }
     525              :         }
     526              :         // A25, \field Mode0 External Static Pressure Lookup Table Name
     527            6 :         inter_Alpha = inter_Alpha + 1;
     528            6 :         curveID = -1;
     529            6 :         if (lAlphaBlanks(inter_Alpha)) {
     530            1 :             InitializeCurve(EXTERNAL_STATIC_PRESSURE, curveID); // as this is invalid curve id CalculateCurveVal will return a default
     531              :         } else {
     532            5 :             curveID = GetCurveIndex(state, Alphas(inter_Alpha));
     533            5 :             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            5 :                 InitializeCurve(EXTERNAL_STATIC_PRESSURE, curveID);
     540              :             }
     541              :         }
     542              :         //
     543              :         // A26, \field Mode0 System Second Fuel Consumption Lookup Table Nam
     544            6 :         inter_Alpha = inter_Alpha + 1;
     545            6 :         curveID = -1;
     546            6 :         if (lAlphaBlanks(inter_Alpha)) {
     547            5 :             InitializeCurve(SECOND_FUEL_USE, curveID); // as this is invalid curve id CalculateCurveVal will return a default
     548              :         } else {
     549            1 :             curveID = GetCurveIndex(state, Alphas(inter_Alpha));
     550            1 :             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            1 :                 InitializeCurve(SECOND_FUEL_USE, curveID);
     557              :             }
     558              :         }
     559              :         // A27, \field Mode0 System Third Fuel Consumption Lookup Table Name
     560            6 :         inter_Alpha = inter_Alpha + 1;
     561            6 :         curveID = -1;
     562            6 :         if (lAlphaBlanks(inter_Alpha)) {
     563            6 :             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            6 :         inter_Alpha = inter_Alpha + 1;
     577            6 :         curveID = -1;
     578            6 :         if (lAlphaBlanks(inter_Alpha)) {
     579            3 :             InitializeCurve(WATER_USE, curveID); // as this is invalid curve id CalculateCurveVal will return a default
     580              :         } else {
     581            3 :             curveID = GetCurveIndex(state, Alphas(inter_Alpha));
     582            3 :             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            3 :                 InitializeCurve(WATER_USE, curveID);
     589              :             }
     590              :         }
     591            6 :         if (ModeID == 0) {
     592            1 :             (*OperatingModes).push_back(*this);
     593            1 :             return ErrorsFound;
     594              :         }
     595              :         // N8, \field Mode1  Minimum Outdoor Air Temperature
     596              :         // N9, \field Mode1  Maximum Outdoor Air Temperature
     597            5 :         bool ok = InitializeOutdoorAirTemperatureConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
     598            5 :         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            5 :         inter_Number = inter_Number + 2;
     604              :         // N10, \field Mode1  Minimum Outdoor Air Humidity Ratio
     605              :         // N11, \field Mode1  Maximum Outdoor Air Humidity Ratio
     606            5 :         ok = InitializeOutdoorAirHumidityRatioConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
     607            5 :         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            5 :         inter_Number = inter_Number + 2;
     613              :         // N12, \field Mode1 Minimum Outdoor Air Relative Humidity
     614              :         // N13, \field Mode1 Maximum Outdoor Air Relative Humidity
     615            5 :         ok = InitializeOutdoorAirRelativeHumidityConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
     616            5 :         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            5 :         inter_Number = inter_Number + 2;
     622              :         // N14, \field Mode1 Minimum Return Air Temperature
     623              :         // N15, \field Mode1 Maximum Return Air Temperature
     624            5 :         ok = InitializeReturnAirTemperatureConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
     625            5 :         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            5 :         inter_Number = inter_Number + 2;
     631              :         // N16, \field Mode1 Minimum Return Air Humidity Ratio
     632              :         // N17, \field Mode1 Maximum Return Air Humidity Ratio
     633            5 :         ok = InitializeReturnAirHumidityRatioConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
     634            5 :         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            5 :         inter_Number = inter_Number + 2;
     640              :         // N18, \field Mode1 Minimum Return Air Relative HumidityInitialize
     641              :         // N19, \field Mode1 Maximum Return Air Relative Humidity
     642            5 :         ok = InitializeReturnAirRelativeHumidityConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
     643            5 :         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            5 :         inter_Number = inter_Number + 2;
     654              :         // N20, \field Mode1 Minimum Outdoor Air Fraction
     655              :         // N21, \field Mode1 Maximum Outdoor Air Fraction
     656              : 
     657            5 :         ok = InitializeOSAFConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
     658            5 :         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            5 :         inter_Number = inter_Number + 2;
     666            5 :         ok = InitializeMsaRatioConstraints(Numbers(inter_Number), Numbers(inter_Number + 1));
     667            5 :         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            5 :         (*OperatingModes).push_back(*this);
     673            5 :         return ErrorsFound;
     674            6 :     }
     675              : 
     676        66085 :     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        66085 :         bool OATempConstraintmet = false;
     696        66085 :         bool OAHRConstraintmet = false;
     697        66085 :         bool OARHConstraintmet = false;
     698              : 
     699        66085 :         if (Tosa >= Minimum_Outdoor_Air_Temperature && Tosa <= Maximum_Outdoor_Air_Temperature) {
     700        66085 :             OATempConstraintmet = true;
     701              :         }
     702              : 
     703        66085 :         if (Wosa >= Minimum_Outdoor_Air_Humidity_Ratio && Wosa <= Maximum_Outdoor_Air_Humidity_Ratio) {
     704        66085 :             OAHRConstraintmet = true;
     705              :         }
     706              : 
     707        66085 :         if (RHosa >= Minimum_Outdoor_Air_Relative_Humidity && RHosa <= Maximum_Outdoor_Air_Relative_Humidity) {
     708        66085 :             OARHConstraintmet = true;
     709              :         }
     710        66085 :         if (OATempConstraintmet && OAHRConstraintmet && OARHConstraintmet) {
     711        66085 :             return true;
     712              :         } else {
     713            0 :             return false;
     714              :         }
     715              :     }
     716              : 
     717       221180 :     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       221180 :         Real64 MinSAT = 10;
     737       221180 :         Real64 MaxSAT = 20;
     738       221180 :         if (TsaMinSched != nullptr) {
     739       221180 :             MinSAT = TsaMinSched->getCurrentVal();
     740              :         }
     741       221180 :         if (TsaMaxSched != nullptr) {
     742       221180 :             MaxSAT = TsaMaxSched->getCurrentVal();
     743              :         }
     744       221180 :         if (Tsupplyair < MinSAT || Tsupplyair > MaxSAT) {
     745       120251 :             return false;
     746              :         }
     747       100929 :         return true;
     748              :     }
     749              : 
     750       221180 :     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       221180 :         Real64 MinRH = 0;
     770       221180 :         Real64 MaxRH = 1;
     771       221180 :         if (RHsaMinSched != nullptr) {
     772       221180 :             MinRH = RHsaMinSched->getCurrentVal();
     773              :         }
     774       221180 :         if (RHsaMaxSched != nullptr) {
     775       221180 :             MaxRH = RHsaMaxSched->getCurrentVal();
     776              :         }
     777       221180 :         if (SupplyW < MinRH || SupplyW > MaxRH) {
     778            0 :             return false;
     779              :         }
     780       221180 :         return true;
     781              :     }
     782              : 
     783            2 :     Model::Model()
     784            6 :         : Initialized(false), ZoneNum(0), SystemMaximumSupplyAirFlowRate(0.0), ScalingFactor(0.0), ScaledSystemMaximumSupplyAirMassFlowRate(0.0),
     785            2 :           UnitOn(0), UnitTotalCoolingRate(0.0), UnitTotalCoolingEnergy(0.0), UnitSensibleCoolingRate(0.0), UnitSensibleCoolingEnergy(0.0),
     786            2 :           UnitLatentCoolingRate(0.0), UnitLatentCoolingEnergy(0.0), SystemTotalCoolingRate(0.0), SystemTotalCoolingEnergy(0.0),
     787            2 :           SystemSensibleCoolingRate(0.0), SystemSensibleCoolingEnergy(0.0), SystemLatentCoolingRate(0.0), SystemLatentCoolingEnergy(0.0),
     788            2 :           UnitTotalHeatingRate(0.0), UnitTotalHeatingEnergy(0.0), UnitSensibleHeatingRate(0.0), UnitSensibleHeatingEnergy(0.0),
     789            2 :           UnitLatentHeatingRate(0.0), UnitLatentHeatingEnergy(0.0), SystemTotalHeatingRate(0.0), SystemTotalHeatingEnergy(0.0),
     790            2 :           SystemSensibleHeatingRate(0.0), SystemSensibleHeatingEnergy(0.0), SystemLatentHeatingRate(0.0), SystemLatentHeatingEnergy(0.0),
     791            2 :           SupplyFanElectricPower(0.0), SupplyFanElectricEnergy(0.0), SecondaryFuelConsumptionRate(0.0), SecondaryFuelConsumption(0.0),
     792            2 :           ThirdFuelConsumptionRate(0.0), ThirdFuelConsumption(0.0), WaterConsumptionRate(0.0), WaterConsumption(0.0), QSensZoneOut(0),
     793            2 :           QLatentZoneOut(0), QLatentZoneOutMass(0), ExternalStaticPressure(0.0), RequestedHumidificationMass(0.0), RequestedHumidificationLoad(0.0),
     794            2 :           RequestedHumidificationEnergy(0.0), RequestedDeHumidificationMass(0.0), RequestedDeHumidificationLoad(0.0),
     795            2 :           RequestedDeHumidificationEnergy(0.0), RequestedLoadToHeatingSetpoint(0.0), RequestedLoadToCoolingSetpoint(0.0), PrimaryMode(0),
     796            2 :           PrimaryModeRuntimeFraction(0.0), averageOSAF(0), ErrorCode(0), InletNode(0), OutletNode(0), SecondaryInletNode(0), SecondaryOutletNode(0),
     797            2 :           FinalElectricalPower(0.0), FinalElectricalEnergy(0.0), InletMassFlowRate(0.0), InletTemp(0.0), InletWetBulbTemp(0.0), InletHumRat(0.0),
     798            2 :           InletEnthalpy(0.0), InletPressure(0.0), InletRH(0.0), OutletVolumetricFlowRate(0.0), OutletMassFlowRate(0.0), PowerLossToAir(0.0),
     799            2 :           FanHeatTemp(0.0), OutletTemp(0.0), OutletWetBulbTemp(0.0), OutletHumRat(0.0), OutletEnthalpy(0.0), OutletPressure(0.0), OutletRH(0.0),
     800            2 :           SecInletMassFlowRate(0.0), SecInletTemp(0.0), SecInletWetBulbTemp(0.0), SecInletHumRat(0.0), SecInletEnthalpy(0.0), SecInletPressure(0.0),
     801            2 :           SecInletRH(0.0), SecOutletMassFlowRate(0.0), SecOutletTemp(0.0), SecOutletWetBulbTemp(0.0), SecOutletHumRat(0.0), SecOutletEnthalpy(0.0),
     802            2 :           SecOutletPressure(0.0), SecOutletRH(0.0), Wsa(0.0), SupplyVentilationAir(0.0), SupplyVentilationVolume(0.0), OutdoorAir(false),
     803            2 :           MinOA_Msa(0.0), OARequirementsPtr(0), Tsa(0.0), ModeCounter(0), CoolingRequested(false), HeatingRequested(false),
     804            2 :           VentilationRequested(false), DehumidificationRequested(false), HumidificationRequested(false)
     805              :     {
     806            2 :         WarnOnceFlag = false;
     807            2 :         count_EnvironmentConditionsMetOnce = 0;
     808            2 :         count_EnvironmentConditionsNotMet = 0;
     809            2 :         count_SAHR_OC_MetOnce = 0;
     810            2 :         count_SAT_OC_MetOnce = 0;
     811            2 :         count_DidWeMeetLoad = 0;
     812            2 :         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            2 :         std::vector<int> temp(25);
     815            2 :         SAT_OC_MetinMode_v = temp;
     816            2 :         SAHR_OC_MetinMode_v = temp;
     817              : 
     818            2 :         ModeCounter = 0;
     819              : 
     820            2 :         CurrentOperatingSettings.resize(5);
     821              : 
     822            2 :         InitializeModelParams();
     823            2 :     }
     824              : 
     825        26552 :     void Model::ResetOutputs()
     826              :     {
     827        26552 :         UnitTotalCoolingRate = 0;
     828        26552 :         UnitTotalCoolingEnergy = 0;
     829        26552 :         UnitSensibleCoolingRate = 0;
     830        26552 :         UnitSensibleCoolingEnergy = 0;
     831        26552 :         UnitLatentCoolingRate = 0;
     832        26552 :         UnitLatentCoolingEnergy = 0;
     833        26552 :         SystemTotalCoolingRate = 0;
     834        26552 :         SystemTotalCoolingEnergy = 0;
     835        26552 :         SystemSensibleCoolingRate = 0;
     836        26552 :         SystemSensibleCoolingEnergy = 0;
     837        26552 :         SystemLatentCoolingRate = 0;
     838        26552 :         SystemLatentCoolingEnergy = 0;
     839        26552 :         UnitTotalHeatingRate = 0;
     840        26552 :         UnitTotalHeatingEnergy = 0;
     841        26552 :         UnitSensibleHeatingRate = 0;
     842        26552 :         UnitSensibleHeatingEnergy = 0;
     843        26552 :         UnitLatentHeatingRate = 0;
     844        26552 :         UnitLatentHeatingEnergy = 0;
     845        26552 :         SystemTotalHeatingRate = 0;
     846        26552 :         SystemTotalHeatingEnergy = 0;
     847        26552 :         SystemSensibleHeatingRate = 0;
     848        26552 :         SystemSensibleHeatingEnergy = 0;
     849        26552 :         SystemLatentHeatingRate = 0;
     850        26552 :         SystemLatentHeatingEnergy = 0;
     851        26552 :         SupplyFanElectricPower = 0;
     852        26552 :         SupplyFanElectricEnergy = 0;
     853        26552 :         SecondaryFuelConsumptionRate = 0;
     854        26552 :         SecondaryFuelConsumption = 0;
     855        26552 :         ThirdFuelConsumptionRate = 0;
     856        26552 :         ThirdFuelConsumption = 0;
     857        26552 :         WaterConsumptionRate = 0;
     858        26552 :         WaterConsumption = 0;
     859        26552 :         ExternalStaticPressure = 0;
     860        26552 :     }
     861              : 
     862        13277 :     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        13277 :         ResetOutputs();
     881        13277 :         PrimaryMode = 0;
     882        13277 :         PrimaryModeRuntimeFraction = 0;
     883        13277 :         optimal_EnvCondMet = false;
     884        13277 :         Tsa = 0;
     885              :         // reset the power use to a high value, this is replaced during the calculation keeping the "best" setting.
     886              : 
     887        13277 :         RunningPeakCapacity_EnvCondMet = false;
     888        13277 :         Settings.clear();
     889        13277 :     }
     890              : 
     891            1 :     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            1 :         ZoneNum = ZoneNumber;
     911            1 :         if (Initialized) {
     912            0 :             return;
     913              :         }
     914            1 :         Initialized = true;
     915              : 
     916              :         // Iterate through modes of operation generating a matrix of OSAF and Msa to test in the algorithm.
     917            7 :         for (auto &thisOperatingMode : OperatingModes) {
     918            6 :             thisOperatingMode.GenerateSolutionSpace();
     919            1 :         }
     920              : 
     921            1 :         Initialized = true;
     922              :     }
     923              : 
     924       114204 :     Real64 Model::CheckVal_W(EnergyPlusData &state, Real64 W, Real64 T, Real64 P)
     925              :     {
     926              :         // P must be in pascals NOT kPa
     927       114204 :         Real64 OutletRHtest = PsyRhFnTdbWPb(state, T, W, P); // could also use outlet pressure instead of fixed
     928              :         Real64 OutletW =
     929       114204 :             PsyWFnTdbRhPb(state, T, OutletRHtest, P, "Humidity ratio exceeded realistic range error called in " + Name + ", check performance curve");
     930       114204 :         return OutletW;
     931              :     }
     932        13275 :     Real64 Model::CheckVal_T(EnergyPlusData &state, Real64 T)
     933              :     {
     934        13275 :         if ((T > 100) || (T < 0)) {
     935            2 :             ShowWarningError(state, format("Supply air temperature exceeded realistic range error called in {}, check performance curve", Name));
     936              :         }
     937        13275 :         return T;
     938              :     }
     939        13275 :     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        13275 :         if (Mode0.sol.MassFlowRatio.size() > 0) {
     960        13275 :             Real64 MsaRatio = Mode0.sol.MassFlowRatio[0];
     961        13275 :             Real64 OSAF = Mode0.sol.OutdoorAirFraction[0];
     962              : 
     963        13275 :             oStandBy.ScaledSupply_Air_Mass_Flow_Rate = MsaRatio * ScaledSystemMaximumSupplyAirMassFlowRate;
     964        13275 :             oStandBy.Unscaled_Supply_Air_Mass_Flow_Rate = oStandBy.ScaledSupply_Air_Mass_Flow_Rate / ScalingFactor;
     965        13275 :             oStandBy.ScaledSupply_Air_Ventilation_Volume = MsaRatio * ScaledSystemMaximumSupplyAirMassFlowRate / state.dataEnvrn->StdRhoAir;
     966        13275 :             oStandBy.Supply_Air_Mass_Flow_Rate_Ratio = MsaRatio;
     967        13275 :             oStandBy.ElectricalPower =
     968        13275 :                 Mode0.CalculateCurveVal(state, Tosa, Wosa, Tra, Wra, oStandBy.Unscaled_Supply_Air_Mass_Flow_Rate, OSAF, POWER_CURVE);
     969        13275 :             oStandBy.Outdoor_Air_Fraction = OSAF;
     970        13275 :             oStandBy.SupplyAirTemperature = Tra;
     971        13275 :             oStandBy.SupplyAirW = Wra;
     972        13275 :             oStandBy.Mode = 0;
     973        13275 :             oStandBy.Mixed_Air_Temperature = Tra;
     974        13275 :             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        13275 :         return false;
     981              :     }
     982              : 
     983       159300 :     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       159300 :         Real64 averagedVal = 0;
    1014       159300 :         Real64 MassFlowDependentDenominator = 0;
    1015       159300 :         Real64 value = 0;
    1016              : 
    1017       955800 :         for (auto const &thisOperatingSettings : CurrentOperatingSettings) {
    1018       796500 :             switch (val) {
    1019        66375 :             case SYSTEMOUTPUTS::VENTILATION_AIR_V:
    1020        66375 :                 value = thisOperatingSettings.ScaledSupply_Air_Ventilation_Volume;
    1021        66375 :                 break;
    1022        66375 :             case SYSTEMOUTPUTS::SYSTEM_FUEL_USE:
    1023        66375 :                 value = thisOperatingSettings.ElectricalPower;
    1024        66375 :                 break;
    1025        66375 :             case SYSTEMOUTPUTS::OSUPPLY_FAN_POWER:
    1026        66375 :                 value = thisOperatingSettings.SupplyFanElectricPower;
    1027        66375 :                 break;
    1028        66375 :             case SYSTEMOUTPUTS::OSECOND_FUEL_USE:
    1029        66375 :                 value = thisOperatingSettings.SecondaryFuelConsumptionRate;
    1030        66375 :                 break;
    1031        66375 :             case SYSTEMOUTPUTS::OTHIRD_FUEL_USE:
    1032        66375 :                 value = thisOperatingSettings.ThirdFuelConsumptionRate;
    1033        66375 :                 break;
    1034        66375 :             case SYSTEMOUTPUTS::OEXTERNAL_STATIC_PRESSURE:
    1035        66375 :                 value = thisOperatingSettings.ExternalStaticPressure * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
    1036        66375 :                 break;
    1037        66375 :             case SYSTEMOUTPUTS::OWATER_USE:
    1038        66375 :                 value = thisOperatingSettings.WaterConsumptionRate;
    1039        66375 :                 break;
    1040        66375 :             case SYSTEMOUTPUTS::SUPPLY_AIR_TEMP:
    1041        66375 :                 value = thisOperatingSettings.SupplyAirTemperature * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
    1042        66375 :                 break;
    1043        66375 :             case SYSTEMOUTPUTS::MIXED_AIR_TEMP:
    1044        66375 :                 value = thisOperatingSettings.Mixed_Air_Temperature * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
    1045        66375 :                 break;
    1046        66375 :             case SYSTEMOUTPUTS::SUPPLY_MASS_FLOW:
    1047        66375 :                 value = thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
    1048        66375 :                 break;
    1049        66375 :             case SYSTEMOUTPUTS::SUPPLY_AIR_HR:
    1050        66375 :                 value = thisOperatingSettings.SupplyAirW * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
    1051        66375 :                 break;
    1052        66375 :             case SYSTEMOUTPUTS::MIXED_AIR_HR:
    1053        66375 :                 value = thisOperatingSettings.Mixed_Air_W * thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate;
    1054        66375 :                 break;
    1055            0 :             default:
    1056            0 :                 assert(false);
    1057              :             }
    1058       796500 :             Real64 part_run = thisOperatingSettings.Runtime_Fraction;
    1059       796500 :             averagedVal = averagedVal + value * part_run;
    1060       796500 :             MassFlowDependentDenominator = thisOperatingSettings.ScaledSupply_Air_Mass_Flow_Rate * part_run + MassFlowDependentDenominator;
    1061       159300 :         }
    1062              : 
    1063       159300 :         CSetting StandbyMode = (*(CurrentOperatingSettings.begin()));
    1064       159300 :         switch (val) {
    1065        13275 :         case SYSTEMOUTPUTS::SUPPLY_AIR_TEMP:
    1066        13275 :             if (MassFlowDependentDenominator == 0) {
    1067         7740 :                 averagedVal = StandbyMode.SupplyAirTemperature;
    1068              :             } else {
    1069         5535 :                 averagedVal = averagedVal / MassFlowDependentDenominator;
    1070              :             }
    1071        13275 :             break;
    1072        13275 :         case SYSTEMOUTPUTS::OEXTERNAL_STATIC_PRESSURE:
    1073        13275 :             if (MassFlowDependentDenominator == 0) {
    1074         7740 :                 averagedVal = StandbyMode.ExternalStaticPressure;
    1075              :             } else {
    1076         5535 :                 averagedVal = averagedVal / MassFlowDependentDenominator;
    1077              :             }
    1078        13275 :             break;
    1079        13275 :         case SYSTEMOUTPUTS::SUPPLY_AIR_HR:
    1080        13275 :             if (MassFlowDependentDenominator == 0) {
    1081         7740 :                 averagedVal = StandbyMode.SupplyAirW;
    1082              :             } else {
    1083         5535 :                 averagedVal = averagedVal / MassFlowDependentDenominator;
    1084              :             }
    1085        13275 :             break;
    1086        13275 :         case SYSTEMOUTPUTS::MIXED_AIR_TEMP:
    1087        13275 :             if (MassFlowDependentDenominator == 0) {
    1088         7740 :                 averagedVal = StandbyMode.Mixed_Air_Temperature;
    1089              :             } else {
    1090         5535 :                 averagedVal = averagedVal / MassFlowDependentDenominator;
    1091              :             }
    1092        13275 :             break;
    1093        13275 :         case SYSTEMOUTPUTS::MIXED_AIR_HR:
    1094        13275 :             if (MassFlowDependentDenominator == 0) {
    1095         7740 :                 averagedVal = StandbyMode.Mixed_Air_W;
    1096              :             } else {
    1097         5535 :                 averagedVal = averagedVal / MassFlowDependentDenominator;
    1098              :             }
    1099        13275 :             break;
    1100        92925 :         default:
    1101        92925 :             break;
    1102              :         }
    1103       318600 :         return averagedVal;
    1104              :     }
    1105              : 
    1106       100929 :     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       100929 :         PLHumidRatio = PLDehumidRatio = PLVentRatio = PLSensibleCoolingRatio = PLSensibleHeatingRatio = 0;
    1138              : 
    1139       100929 :         if (Mvent > 0) {
    1140       100929 :             PLVentRatio = MinOA_Msa / Mvent;
    1141              :         }
    1142       100929 :         PartRuntimeFraction = PLVentRatio;
    1143              : 
    1144       100929 :         if (SensibleRoomORZone > 0) {
    1145        67087 :             PLSensibleCoolingRatio = std::abs(RequestedCoolingLoad) / std::abs(SensibleRoomORZone);
    1146              :         }
    1147       100929 :         if (PLSensibleCoolingRatio > PartRuntimeFraction) {
    1148        40465 :             PartRuntimeFraction = PLSensibleCoolingRatio;
    1149              :         }
    1150              : 
    1151       100929 :         if (SensibleRoomORZone < 0) {
    1152        33842 :             PLSensibleHeatingRatio = std::abs(RequestedHeatingLoad) / std::abs(SensibleRoomORZone);
    1153              :         }
    1154              : 
    1155       100929 :         if (PLSensibleHeatingRatio > PartRuntimeFraction) {
    1156        17310 :             PartRuntimeFraction = PLSensibleHeatingRatio;
    1157              :         }
    1158              : 
    1159       100929 :         if (RequestedDehumidificationLoad > 0) {
    1160         3326 :             PLDehumidRatio = std::abs(RequestedDehumidificationLoad) / std::abs(LatentRoomORZone);
    1161              :         }
    1162              : 
    1163       100929 :         if (PLDehumidRatio > PartRuntimeFraction) {
    1164         3318 :             PartRuntimeFraction = PLDehumidRatio;
    1165              :         }
    1166              : 
    1167       100929 :         if (RequestedMoistureLoad > 0) {
    1168        97595 :             PLHumidRatio = std::abs(RequestedMoistureLoad) / std::abs(LatentRoomORZone);
    1169              :         }
    1170       100929 :         if (PLHumidRatio > PartRuntimeFraction) {
    1171        94885 :             PartRuntimeFraction = PLHumidRatio;
    1172              :         }
    1173              : 
    1174       100929 :         if (PartRuntimeFraction < 0) {
    1175            0 :             PartRuntimeFraction = 0;
    1176              :         }
    1177       100929 :         if (PartRuntimeFraction > 1) {
    1178        93249 :             PartRuntimeFraction = 1;
    1179              :         }
    1180              : 
    1181       100929 :         return PartRuntimeFraction;
    1182              :     }
    1183              : 
    1184        13217 :     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        13217 :         bool DidWeMeetLoad = false;
    1252        13217 :         bool DidWeMeetHumidificaiton = false;
    1253        13217 :         bool DidWePartlyMeetLoad = false;
    1254        13217 :         Real64 OptimalSetting_RunFractionTotalFuel = IMPLAUSIBLE_POWER;
    1255              :         Real64 Tma;
    1256              :         Real64 Wma;
    1257              :         Real64 Hsa;
    1258              :         Real64 Hma;
    1259        13217 :         Real64 PreviousMaxiumConditioningOutput = 0;
    1260        13217 :         Real64 PreviousMaxiumHumidOrDehumidOutput = 0;
    1261        13217 :         std::string ObjectID = Name.c_str();
    1262        13217 :         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        13217 :         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        13217 :         Real64 Wosa = PsyWFnTdbRhPb(state, StepIns.Tosa, StepIns.RHosa, state.dataEnvrn->OutBaroPress);
    1277        13217 :         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        13217 :         EnvironmentConditionsMetOnce = SAT_OC_Met = SAT_OC_MetOnce = SARH_OC_Met = SAHR_OC_MetOnce = false;
    1280              : 
    1281        13217 :         MinOA_Msa = StepIns.MinimumOA; // Set object version of minimum VR Kg/s
    1282              : 
    1283        79302 :         for (std::vector<CMode>::const_iterator iterator = OperatingModes.begin() + 1; iterator != OperatingModes.end();
    1284        66085 :              ++iterator) // iterate though the modes.
    1285              :         {
    1286        66085 :             CMode Mode = *iterator;
    1287        66085 :             bool SAHR_OC_MetinMode = false;
    1288        66085 :             bool SAT_OC_MetinMode = false;
    1289        66085 :             int solution_map_sizeX = Mode.sol.MassFlowRatio.size();
    1290        66085 :             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        66085 :             if (Mode.MeetsOAEnvConstraints(StepIns.Tosa, Wosa, 100 * StepIns.RHosa)) {
    1295        66085 :                 EnvironmentConditionsMet = EnvironmentConditionsMetOnce = true;
    1296              :             } else {
    1297            0 :                 EnvironmentConditionsMet = false;
    1298              :             }
    1299              : 
    1300        66085 :             if (EnvironmentConditionsMet) {
    1301       436161 :                 for (int indexMassFlowRatio = 0; indexMassFlowRatio < solution_map_sizeX;
    1302              :                      indexMassFlowRatio++) // within each mode go though all the combinations of solution spaces.
    1303              :                 {
    1304       740152 :                     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       370076 :                         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       370076 :                         Real64 OSAF = Mode.sol.OutdoorAirFraction[indexOutdoorAirFraction];
    1311       370076 :                         Real64 ScaledMsa = ScaledSystemMaximumSupplyAirMassFlowRate * MsaRatio;
    1312       370076 :                         Real64 UnscaledMsa = ScaledSystemMaximumSupplyAirMassFlowRate / ScalingFactor;
    1313       370076 :                         Real64 Supply_Air_Ventilation_Volume = 0;
    1314              :                         // Calculate the ventilation mass flow rate
    1315       370076 :                         Real64 Mvent = ScaledMsa * OSAF;
    1316              : 
    1317       370076 :                         if (state.dataEnvrn->StdRhoAir > 1) {
    1318       370076 :                             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       370076 :                         if (Mvent - MinOA_Msa > -0.000001) {
    1324       221180 :                             MinVRMet = true;
    1325              :                         } else {
    1326       148896 :                             MinVRMet = false;
    1327              :                         }
    1328              : 
    1329       370076 :                         if (MinVRMet) {
    1330              :                             // reset outside air temp and return air temp before calculating curve values for each mode
    1331       221180 :                             StepIns.Tosa = SecInletTemp;
    1332       221180 :                             StepIns.Tra = InletTemp;
    1333              :                             Real64 FanPower =
    1334       221180 :                                 Mode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SUPPLY_FAN_POWER) *
    1335       221180 :                                 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       221180 :                             if (FanHeatGain && FanHeatGainLocation == "MIXEDAIRSTREAM") {
    1339            0 :                                 PowerLossToAir = FanPower * FanHeatInAirFrac;
    1340              :                             } else {
    1341       221180 :                                 PowerLossToAir = 0.0;
    1342              :                             }
    1343       221180 :                             Real64 FanHeatTempOA = PowerLossToAir / (PsyCpAirFnW(Wosa) * (ScaledMsa * OSAF));
    1344       221180 :                             StepIns.Tosa = StepIns.Tosa + FanHeatTempOA;
    1345       221180 :                             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       221180 :                             Tsa = Mode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, TEMP_CURVE);
    1352              :                             // Calculate prospective supply air Humidity Ratio
    1353       221180 :                             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       221180 :                             if (FanHeatGain && FanHeatGainLocation == "SUPPLYAIRSTREAM") {
    1358            0 :                                 PowerLossToAir = FanPower * FanHeatInAirFrac;
    1359              :                             } else {
    1360       221180 :                                 PowerLossToAir = 0.0;
    1361              :                             }
    1362       221180 :                             FanHeatTemp = PowerLossToAir / (PsyCpAirFnW(Wsa) * ScaledMsa);
    1363       221180 :                             Tsa = Tsa + FanHeatTemp;
    1364              : 
    1365              :                             // Check it meets constraints
    1366       221180 :                             if (MeetsSupplyAirTOC(state, Tsa)) {
    1367       100929 :                                 SAT_OC_Met = SAT_OC_MetOnce = SAT_OC_MetinMode = true;
    1368              :                             } else {
    1369       120251 :                                 SAT_OC_Met = false;
    1370              :                             }
    1371              :                             // Return Air Relative Humidity(0 - 100 % ) //Return Air Humidity Ratio(g / g)
    1372       221180 :                             if (MeetsSupplyAirRHOC(state, Wsa)) {
    1373       221180 :                                 SARH_OC_Met = SAHR_OC_MetOnce = SAHR_OC_MetinMode = true;
    1374              :                             } else {
    1375            0 :                                 SARH_OC_Met = false;
    1376              :                             }
    1377              : 
    1378       221180 :                             if (SARH_OC_Met && SAT_OC_Met) {
    1379       100929 :                                 CSetting CandidateSetting;
    1380       100929 :                                 CandidateSetting.Supply_Air_Ventilation_Volume = Supply_Air_Ventilation_Volume;
    1381       100929 :                                 CandidateSetting.Mode = Mode.ModeID;
    1382       100929 :                                 CandidateSetting.Outdoor_Air_Fraction = OSAF;
    1383       100929 :                                 CandidateSetting.Supply_Air_Mass_Flow_Rate_Ratio = MsaRatio;
    1384       100929 :                                 CandidateSetting.Unscaled_Supply_Air_Mass_Flow_Rate = UnscaledMsa;
    1385       100929 :                                 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       100929 :                                 if (!CoolingRequested && !HeatingRequested && !DehumidificationRequested && !HumidificationRequested) {
    1390            4 :                                     CandidateSetting.ScaledSupply_Air_Mass_Flow_Rate =
    1391            4 :                                         min(MinOA_Msa, CandidateSetting.ScaledSupply_Air_Mass_Flow_Rate);
    1392              :                                     // add fan heat if not included in lookup tables for supply air stream
    1393            4 :                                     Tsa = StepIns.Tosa + FanHeatTemp;
    1394              :                                 }
    1395              : 
    1396       100929 :                                 CandidateSetting.ScaledSupply_Air_Ventilation_Volume =
    1397       100929 :                                     CandidateSetting.ScaledSupply_Air_Mass_Flow_Rate / state.dataEnvrn->StdRhoAir;
    1398       100929 :                                 CandidateSetting.oMode = Mode;
    1399       100929 :                                 CandidateSetting.SupplyAirTemperature = Tsa;
    1400       100929 :                                 CandidateSetting.SupplyAirW = CheckVal_W(state, Wsa, Tsa, OutletPressure);
    1401       100929 :                                 CandidateSetting.Mode = Mode.ModeID;
    1402       100929 :                                 Settings.push_back(CandidateSetting);
    1403       100929 :                             }
    1404              :                         }
    1405              :                     }
    1406              :                 }
    1407              :             }
    1408        66085 :             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         9310 :                 if (!SAT_OC_MetinMode) {
    1412         5820 :                     SAT_OC_MetinMode_v[Mode.ModeID] = SAT_OC_MetinMode_v[Mode.ModeID] + 1;
    1413              :                 }
    1414         9310 :                 if (!SAHR_OC_MetinMode) {
    1415         1732 :                     SAHR_OC_MetinMode_v[Mode.ModeID] = SAHR_OC_MetinMode_v[Mode.ModeID] + 1;
    1416              :                 }
    1417              :             }
    1418        79302 :         }
    1419              : 
    1420       114146 :         for (auto &thisSetting : Settings) {
    1421              :             // Calculate the delta H
    1422       100929 :             Real64 OSAF = thisSetting.Outdoor_Air_Fraction;
    1423       100929 :             Real64 UnscaledMsa = thisSetting.Unscaled_Supply_Air_Mass_Flow_Rate;
    1424       100929 :             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       100929 :             Tsa = thisSetting.SupplyAirTemperature;
    1428       100929 :             Wsa = thisSetting.SupplyAirW;
    1429       100929 :             Tma = StepIns.Tra + OSAF * (StepIns.Tosa - StepIns.Tra);
    1430       100929 :             Wma = Wra + OSAF * (Wosa - Wra);
    1431       100929 :             thisSetting.Mixed_Air_Temperature = Tma;
    1432       100929 :             thisSetting.Mixed_Air_W = Wma;
    1433              : 
    1434       100929 :             Hma = PsyHFnTdbW(Tma, Wma);
    1435              :             // Calculate Enthalpy of return air
    1436       100929 :             Real64 Hra = PsyHFnTdbW(StepIns.Tra, Wra);
    1437              : 
    1438       100929 :             Hsa = PsyHFnTdbW(Tsa, Wsa);
    1439              : 
    1440       100929 :             Real64 SupplyAirCp = PsyCpAirFnW(Wsa);   // J/degreesK.kg
    1441       100929 :             Real64 ReturnAirCP = PsyCpAirFnW(Wra);   // J/degreesK.kg
    1442       100929 :             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       100929 :             Real64 SystemCp = ReturnAirCP + OSAF * (OutdoorAirCP - ReturnAirCP) + SupplyAirCp; // J/degreesK.kg
    1451       100929 :             Real64 SensibleSystem = ScaledMsa * 0.5 * SystemCp * (Tma - Tsa);                  // W dynamic cp
    1452       100929 :             Real64 MsaDry = ScaledMsa * (1 - Wsa);
    1453       100929 :             Real64 LambdaSa = Psychrometrics::PsyHfgAirFnWTdb(0, Tsa);
    1454       100929 :             Real64 LatentSystem = LambdaSa * MsaDry * (Wma - Wsa); // W
    1455              :                                                                    // Total system cooling
    1456       100929 :             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       100929 :             Real64 SensibleRoomORZone = ScaledMsa * 0.5 * (SupplyAirCp + ReturnAirCP) * (StepIns.Tra - Tsa); // W dynamic cp
    1464       100929 :             Real64 latentRoomORZone = LambdaSa * MsaDry * (Wra - Wsa);                                       // W
    1465              :                                                                                                              // Total room cooling
    1466       100929 :             Real64 TotalRoomORZone = (Hra - Hsa) * ScaledMsa;                                                // W
    1467              :                                                                                                              // Perform latent check
    1468              :             // Real64 latentRoomORZoneCheck = TotalRoomORZone - SensibleRoomORZone;
    1469              : 
    1470       100929 :             thisSetting.SensibleSystem = SensibleSystem;
    1471       100929 :             thisSetting.LatentSystem = LatentSystem;
    1472       100929 :             thisSetting.TotalZone = TotalRoomORZone;
    1473       100929 :             thisSetting.SensibleZone = SensibleRoomORZone;
    1474       100929 :             thisSetting.LatentZone = latentRoomORZone;
    1475              : 
    1476       100929 :             bool Conditioning_load_met = false;
    1477       100929 :             if (CoolingRequested && (SensibleRoomORZone > StepIns.RequestedCoolingLoad)) {
    1478        14048 :                 Conditioning_load_met = true;
    1479              :             }
    1480       100929 :             if (HeatingRequested && (SensibleRoomORZone < StepIns.RequestedHeatingLoad)) {
    1481            0 :                 Conditioning_load_met = true;
    1482              :             }
    1483       100929 :             if (!(HeatingRequested || CoolingRequested)) {
    1484        42507 :                 Conditioning_load_met = true;
    1485              :             }
    1486              : 
    1487       100929 :             bool Humidification_load_met = false;
    1488              : 
    1489       100929 :             Real64 RequestedDeHumidificationLoad = StepIns.ZoneDehumidificationLoad;
    1490       100929 :             if (DehumidificationRequested && latentRoomORZone > RequestedDeHumidificationLoad) {
    1491            4 :                 Humidification_load_met = true;
    1492              :             }
    1493       100929 :             Real64 RequestedHumidificationLoad = StepIns.ZoneMoistureLoad;
    1494       100929 :             if (HumidificationRequested && latentRoomORZone < RequestedHumidificationLoad) {
    1495        97595 :                 Humidification_load_met = true;
    1496              :             }
    1497              : 
    1498       100929 :             if (!(HumidificationRequested || DehumidificationRequested)) {
    1499         3326 :                 Humidification_load_met = true;
    1500              :             }
    1501              : 
    1502       100929 :             thisSetting.ElectricalPower = thisSetting.oMode.CalculateCurveVal(
    1503              :                 state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, POWER_CURVE); // [Kw] calculations for fuel in Kw
    1504       100929 :             thisSetting.SupplyFanElectricPower =
    1505       100929 :                 thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SUPPLY_FAN_POWER);
    1506       100929 :             thisSetting.ExternalStaticPressure =
    1507       100929 :                 thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, EXTERNAL_STATIC_PRESSURE);
    1508       100929 :             thisSetting.SecondaryFuelConsumptionRate =
    1509       100929 :                 thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SECOND_FUEL_USE);
    1510       100929 :             thisSetting.ThirdFuelConsumptionRate =
    1511       100929 :                 thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, THIRD_FUEL_USE);
    1512       100929 :             thisSetting.WaterConsumptionRate =
    1513       100929 :                 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       100929 :             Real64 PartRuntimeFraction = 0;
    1517       201858 :             PartRuntimeFraction = CalculatePartRuntimeFraction(MinOA_Msa,
    1518       100929 :                                                                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       100929 :             Real64 RunFractionTotalFuel =
    1527       100929 :                 thisSetting.ElectricalPower * PartRuntimeFraction; // fraction can be above 1 meaning its not able to do it completely in a time step.
    1528       100929 :             thisSetting.Runtime_Fraction = PartRuntimeFraction;
    1529              : 
    1530       100929 :             if (Conditioning_load_met && Humidification_load_met) {
    1531              :                 // store best performing mode
    1532        56555 :                 if (RunFractionTotalFuel < OptimalSetting_RunFractionTotalFuel) {
    1533         6288 :                     OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel;
    1534         6288 :                     OptimalSetting = thisSetting;
    1535         6288 :                     DidWeMeetLoad = true;
    1536         6288 :                     DidWeMeetHumidificaiton = true;
    1537              :                 }
    1538              :             } else {
    1539        44374 :                 if (!DidWeMeetLoad && !DidWeMeetHumidificaiton) {
    1540        30298 :                     bool store_best_attempt = false;
    1541              : 
    1542        30298 :                     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        30298 :                         if (!DidWeMeetLoad) {
    1555        30298 :                             if (CoolingRequested && (SensibleRoomORZone > PreviousMaxiumConditioningOutput)) {
    1556         1142 :                                 store_best_attempt = true;
    1557              :                             }
    1558        30298 :                             if (HeatingRequested && (SensibleRoomORZone < PreviousMaxiumConditioningOutput)) {
    1559            0 :                                 store_best_attempt = true;
    1560              :                             }
    1561        30298 :                             if (store_best_attempt) {
    1562         1142 :                                 PreviousMaxiumConditioningOutput = SensibleRoomORZone;
    1563              :                             }
    1564              :                         }
    1565              :                     }
    1566        30298 :                     if (store_best_attempt) {
    1567         1142 :                         OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel;
    1568         1142 :                         OptimalSetting = thisSetting;
    1569         1142 :                         DidWePartlyMeetLoad = true;
    1570              :                     }
    1571              :                 }
    1572              :             }
    1573        13217 :         }
    1574              : 
    1575        13217 :         if (!EnvironmentConditionsMetOnce) {
    1576            0 :             ErrorCode = 1;
    1577            0 :             count_EnvironmentConditionsNotMet++;
    1578              :         }
    1579        13217 :         if (!SAHR_OC_MetOnce) {
    1580            0 :             count_SAHR_OC_MetOnce++;
    1581            0 :             ErrorCode = 2;
    1582              :         }
    1583        13217 :         if (!SAT_OC_MetOnce) {
    1584            0 :             count_SAT_OC_MetOnce++;
    1585            0 :             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        13217 :         if (DidWeMeetLoad) {
    1589              :             // add first setting to operating modes
    1590         4393 :             ErrorCode = 0;
    1591              :             // save the optimal setting in the
    1592         4393 :             CurrentOperatingSettings[0] = OptimalSetting;
    1593         4393 :             PrimaryModeRuntimeFraction = OptimalSetting.Runtime_Fraction;
    1594         4393 :             oStandBy.Runtime_Fraction = (1 - PrimaryModeRuntimeFraction);
    1595         4393 :             if (oStandBy.Runtime_Fraction < 0) {
    1596            0 :                 oStandBy.Runtime_Fraction = 0;
    1597              :             }
    1598         4393 :             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         8824 :             if (!DidWeMeetLoad && DidWePartlyMeetLoad) {
    1602         1142 :                 ErrorCode = 0;
    1603         1142 :                 count_DidWeNotMeetLoad++;
    1604         1142 :                 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         1142 :                 OptimalSetting.Runtime_Fraction = 1;
    1609         1142 :                 CurrentOperatingSettings[0] = OptimalSetting;
    1610         1142 :                 PrimaryMode = OptimalSetting.Mode;
    1611         1142 :                 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         7682 :                 oStandBy.Runtime_Fraction = 1;
    1616         7682 :                 CurrentOperatingSettings[0] = oStandBy;
    1617         7682 :                 ErrorCode = -1;
    1618         7682 :                 StandBy = true;
    1619         7682 :                 count_DidWeNotMeetLoad++;
    1620              :             }
    1621              :         }
    1622              : 
    1623              :         Real64 TimeElapsed =
    1624        13217 :             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        13217 :         if ((TimeElapsed > 24) && WarnOnceFlag && !state.dataGlobal->WarmupFlag) {
    1630            2 :             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            2 :             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            2 :             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            4 :             ShowWarningError(state,
    1658            4 :                              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            2 :                                     (Real64)state.dataGlobal->DayOfSim,
    1661            2 :                                     Name,
    1662            2 :                                     (Real64)count_DidWeNotMeetLoad));
    1663              : 
    1664            2 :             count_SAT_OC_MetOnce = 0;
    1665            2 :             count_DidWeNotMeetLoad = 0;
    1666            2 :             count_SAHR_OC_MetOnce = 0;
    1667            2 :             count_EnvironmentConditionsMetOnce = 0;
    1668            2 :             count_EnvironmentConditionsNotMet = 0;
    1669            2 :             WarnOnceFlag = false;
    1670              :         }
    1671        13217 :         if (state.dataGlobal->HourOfDay == 1 && !WarnOnceFlag && !state.dataGlobal->WarmupFlag) {
    1672            2 :             WarnOnceFlag = true;
    1673              :         }
    1674        13217 :         return ErrorCode;
    1675        13217 :     }
    1676              : 
    1677         5535 :     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         5535 :         if (CurrentOperatingSettings.size() > 0) {
    1697         5535 :             return CurrentOperatingSettings[0].Mode;
    1698              :         } else {
    1699            0 :             return -1;
    1700              :         }
    1701              :     }
    1702         5535 :     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         5535 :         if (CurrentOperatingSettings.size() > 0) {
    1721         5535 :             return CurrentOperatingSettings[0].Runtime_Fraction;
    1722              :         } else {
    1723            0 :             return -1;
    1724              :         }
    1725              :     }
    1726        13275 :     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        13275 :         CoolingRequested = false;
    1745        13275 :         HeatingRequested = false;
    1746        13275 :         VentilationRequested = false;
    1747        13275 :         DehumidificationRequested = false;
    1748        13275 :         HumidificationRequested = false;
    1749              :         // establish if conditioning needed
    1750        13275 :         if (StepIns.RequestedCoolingLoad >= MINIMUM_LOAD_TO_ACTIVATE) {
    1751         2656 :             CoolingRequested = true;
    1752         2656 :             StepIns.RequestedHeatingLoad = 0;
    1753              :         }
    1754        13275 :         if (StepIns.RequestedHeatingLoad <= -MINIMUM_LOAD_TO_ACTIVATE) {
    1755         7682 :             HeatingRequested = true;
    1756         7682 :             StepIns.RequestedCoolingLoad = 0;
    1757              :         }
    1758              :         // establish if ventilation needed
    1759        13275 :         if (StepIns.MinimumOA > 0) {
    1760         6204 :             VentilationRequested = true;
    1761              :         }
    1762              :         // Load required to meet dehumidifying setpoint (<0 = a dehumidify load)  [kgWater/s]
    1763        13275 :         if (StepIns.ZoneDehumidificationLoad < 0) {
    1764            4 :             DehumidificationRequested = true;
    1765            4 :             StepIns.ZoneMoistureLoad = 0;
    1766              :         }
    1767              :         // Load required to meet humidifying setpoint (>0 = a humidify load) [kgWater/s]
    1768        13275 :         if (StepIns.ZoneMoistureLoad > 0) {
    1769        12333 :             StepIns.ZoneDehumidificationLoad = 0;
    1770        12333 :             HumidificationRequested = true;
    1771              :         }
    1772        13275 :     }
    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        13275 :     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        13275 :         RequestedLoadToHeatingSetpoint = RequestedHeatingLoad;
    1809        13275 :         RequestedLoadToCoolingSetpoint = RequestedCoolingLoad;
    1810        13275 :         Real64 LambdaRa = Psychrometrics::PsyHfgAirFnWTdb(0, InletTemp);
    1811        13275 :         RequestedHumidificationMass = OutputRequiredToHumidify;
    1812        13275 :         RequestedHumidificationLoad = OutputRequiredToHumidify * LambdaRa;                                          // [W];
    1813        13275 :         RequestedHumidificationEnergy = OutputRequiredToHumidify * LambdaRa * state.dataHVACGlobal->TimeStepSysSec; // [j]
    1814              : 
    1815        13275 :         RequestedDeHumidificationMass = OutputRequiredToDehumidify;
    1816        13275 :         RequestedDeHumidificationLoad = OutputRequiredToDehumidify * LambdaRa;                                          // [W];
    1817        13275 :         RequestedDeHumidificationEnergy = OutputRequiredToDehumidify * LambdaRa * state.dataHVACGlobal->TimeStepSysSec; // [j]
    1818              : 
    1819        13275 :         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        13275 :         CStepInputs StepIns;
    1824        13275 :         StepIns.Tosa = SecInletTemp; // degrees C
    1825        13275 :         StepIns.Tra = InletTemp;     // degrees C
    1826        13275 :         StepIns.RHosa = SecInletRH;  // RH as 0-1
    1827        13275 :         StepIns.RHra = InletRH;
    1828              :         // For historical reasons cooling is  positive, heating negative throughout the calculation
    1829        13275 :         StepIns.RequestedCoolingLoad = -RequestedCoolingLoad; // Cooling positive now, heating negative
    1830        13275 :         StepIns.RequestedHeatingLoad = -RequestedHeatingLoad; // Cooling positive now, heating negative
    1831              : 
    1832        13275 :         StepIns.ZoneMoistureLoad = RequestedHumidificationLoad;
    1833        13275 :         StepIns.ZoneDehumidificationLoad = RequestedDeHumidificationLoad;
    1834        13275 :         StepIns.MinimumOA = DesignMinVR;
    1835              :         // calculate W humidity ratios for outdoor air and return air
    1836        13275 :         Real64 Wosa = PsyWFnTdbRhPb(state, StepIns.Tosa, StepIns.RHosa, state.dataEnvrn->OutBaroPress);
    1837        13275 :         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        13275 :         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        13275 :         CMode Mode = *(OperatingModes.begin());
    1845        13275 :         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        13275 :         UnitOn = 1;
    1854        13275 :         bool ForceOff = false;
    1855        13275 :         StandBy = false;
    1856        13275 :         if (availSched->getCurrentVal() <= 0 || availStatus == Avail::Status::ForceOff) {
    1857            0 :             UnitOn = 0;
    1858            0 :             ForceOff = true;
    1859              :         }
    1860              : 
    1861              :         // Initialize all settings for all operating modes
    1862        13275 :         int size = CurrentOperatingSettings.size();
    1863        13275 :         CSetting empty_setting;
    1864        66375 :         for (int i = 1; i < size; i++) {
    1865        53100 :             CurrentOperatingSettings[i] = empty_setting;
    1866              :         }
    1867              : 
    1868              :         // Go into standby if unit is off or not needed
    1869        13275 :         if ((!CoolingRequested && !HeatingRequested && !VentilationRequested && !HumidificationRequested && !DehumidificationRequested) || ForceOff) {
    1870           58 :             StandBy = true;
    1871           58 :             oStandBy.Runtime_Fraction = 1;
    1872           58 :             CurrentOperatingSettings[0] = oStandBy;
    1873           58 :             ErrorCode = 0;
    1874           58 :             PrimaryMode = 0;
    1875           58 :             PrimaryModeRuntimeFraction = 0;
    1876              :         } else {
    1877              :             // set the operating conditions and respective part load fractions.
    1878        13217 :             ErrorCode = SetOperatingSetting(state, StepIns);
    1879              :         }
    1880              : 
    1881        13275 :         Real64 QTotZoneOut = 0;
    1882              :         // now class members QSensZoneOut = 0;
    1883              :         // QLatentZoneOut = 0;
    1884              : 
    1885        13275 :         Real64 QTotSystemOut = 0;
    1886        13275 :         Real64 QSensSystemOut = 0;
    1887        13275 :         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        13275 :         SupplyVentilationVolume = CalculateTimeStepAverage(SYSTEMOUTPUTS::VENTILATION_AIR_V);
    1892        13275 :         if (state.dataEnvrn->StdRhoAir > 1) {
    1893        13275 :             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        13275 :         OutletTemp = CheckVal_T(state, CalculateTimeStepAverage(SYSTEMOUTPUTS::SUPPLY_AIR_TEMP));
    1899        13275 :         OutletHumRat = CheckVal_W(state, CalculateTimeStepAverage(SYSTEMOUTPUTS::SUPPLY_AIR_HR), OutletTemp, OutletPressure);
    1900              : 
    1901        13275 :         OutletRH = PsyRhFnTdbWPb(state, OutletTemp, OutletHumRat, OutletPressure);
    1902        13275 :         Real64 OperatingAverageMixedAirTemperature = CalculateTimeStepAverage(SYSTEMOUTPUTS::MIXED_AIR_TEMP);
    1903        13275 :         Real64 OperatingMixedAirW = CalculateTimeStepAverage(SYSTEMOUTPUTS::MIXED_AIR_HR);
    1904        13275 :         Real64 MixedAirEnthalpy = PsyHFnTdbW(OperatingAverageMixedAirTemperature, OperatingMixedAirW);
    1905        13275 :         OutletEnthalpy = PsyHFnTdbRhPb(state, OutletTemp, OutletRH, InletPressure);
    1906        13275 :         OutletMassFlowRate = CalculateTimeStepAverage(SYSTEMOUTPUTS::SUPPLY_MASS_FLOW);
    1907              : 
    1908        13275 :         if (state.dataEnvrn->StdRhoAir > 1) {
    1909        13275 :             OutletVolumetricFlowRate = OutletMassFlowRate / state.dataEnvrn->StdRhoAir;
    1910              :         } else {
    1911            0 :             OutletVolumetricFlowRate = OutletMassFlowRate / 1.225;
    1912              :         }
    1913              : 
    1914        13275 :         if (!StandBy) {
    1915         5535 :             if (OutletMassFlowRate > 0) {
    1916         5535 :                 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         5535 :             PrimaryMode = CurrentPrimaryMode();
    1929         5535 :             PrimaryModeRuntimeFraction = CurrentPrimaryRuntimeFraction();
    1930         5535 :             Real64 Outletcp = PsyCpAirFnW(OutletHumRat); // J/degreesK.kg
    1931         5535 :             Real64 Returncp = PsyCpAirFnW(Wra);          // J/degreesK.kg
    1932         5535 :             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         5535 :             QSensZoneOut = OutletMassFlowRate * 0.5 * (Returncp + Outletcp) * (StepIns.Tra - OutletTemp); // Watts
    1937         5535 :             Real64 OutletMassFlowRateDry = OutletMassFlowRate * (1 - Wsa);
    1938         5535 :             Real64 LambdaSa = Psychrometrics::PsyHfgAirFnWTdb(0, OutletTemp);
    1939         5535 :             QLatentZoneOutMass = OutletMassFlowRateDry * (InletHumRat - OutletHumRat); // Watts
    1940         5535 :             QLatentZoneOut = QLatentZoneOutMass * LambdaSa;
    1941         5535 :             QTotZoneOut = OutletMassFlowRateDry * (InletEnthalpy - OutletEnthalpy); // Watts
    1942         5535 :             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         5535 :             Real64 SystemTimeStepCp = Returncp + averageOSAF * (Outdoorcp - Returncp) + Outletcp; // cpRA + OSAF*(cpOSA-cpRA) + cpSA //J/degreesK.kg
    1949         5535 :             Real64 SystemTimeStepW = InletHumRat + averageOSAF * (Wosa - Wra) - OutletHumRat;     // HR_RA + OSAF *(HR_OSA - HR_RA) - HR_SA
    1950         5535 :             Real64 SystemTimeStepT = StepIns.Tra + averageOSAF * (StepIns.Tosa - StepIns.Tra) - OutletTemp; // T_RA + OSAF *(T_OSA - T_RA) - T_SA
    1951         5535 :             QSensSystemOut = 0.5 * SystemTimeStepCp * OutletMassFlowRate * SystemTimeStepT;                 // Watts
    1952              : 
    1953         5535 :             QLatentSystemOut = LambdaSa * OutletMassFlowRateDry * SystemTimeStepW;       // Watts
    1954         5535 :             QTotSystemOut = OutletMassFlowRateDry * (MixedAirEnthalpy - OutletEnthalpy); // Watts
    1955         5535 :             QLatentCheck = QTotSystemOut - QSensSystemOut;                               // Watts
    1956              : 
    1957              :             // reset outputs
    1958         5535 :             ResetOutputs();
    1959              :             // set UNIT outputs for cooling and heating
    1960         5535 :             if (QTotZoneOut > 0) // zone cooling is positive, else remain zero
    1961              :             {
    1962         4044 :                 UnitTotalCoolingRate = std::abs(QTotZoneOut);                                         // Watts
    1963         4044 :                 UnitTotalCoolingEnergy = UnitTotalCoolingRate * state.dataHVACGlobal->TimeStepSysSec; // J
    1964              :             } else {
    1965         1491 :                 UnitTotalHeatingRate = std::abs(QTotZoneOut);                                         // Watts
    1966         1491 :                 UnitTotalHeatingEnergy = UnitTotalHeatingRate * state.dataHVACGlobal->TimeStepSysSec; // J
    1967              :             }
    1968              : 
    1969         5535 :             if (QSensZoneOut > 0) // zone cooling is positive, else remain zero
    1970              :             {
    1971         4039 :                 UnitSensibleCoolingRate = std::abs(QSensZoneOut);                                           // Watts
    1972         4039 :                 UnitSensibleCoolingEnergy = UnitSensibleCoolingRate * state.dataHVACGlobal->TimeStepSysSec; // J
    1973              :             } else {
    1974         1496 :                 UnitSensibleHeatingRate = std::abs(QSensZoneOut);                                           // Watts
    1975         1496 :                 UnitSensibleHeatingEnergy = UnitSensibleHeatingRate * state.dataHVACGlobal->TimeStepSysSec; // J
    1976              :             }
    1977              : 
    1978         5535 :             if ((UnitTotalCoolingRate - UnitSensibleCoolingRate) > 0) {
    1979         1654 :                 UnitLatentCoolingRate = UnitTotalCoolingRate - UnitSensibleCoolingRate;       // Watts
    1980         1654 :                 UnitLatentCoolingEnergy = UnitTotalCoolingEnergy - UnitSensibleCoolingEnergy; // J
    1981              :             }
    1982         5535 :             if ((UnitTotalCoolingRate - UnitSensibleCoolingRate) < 0) {
    1983         2395 :                 UnitLatentHeatingRate = UnitTotalHeatingRate - UnitSensibleHeatingRate;       // Watts
    1984         2395 :                 UnitLatentHeatingEnergy = UnitTotalHeatingEnergy - UnitSensibleHeatingEnergy; // J
    1985              :             }
    1986              : 
    1987              :             // set SYSTEM outputs
    1988         5535 :             if (QTotSystemOut > 0) // system cooling
    1989              :             {
    1990         3032 :                 SystemTotalCoolingRate = std::abs(QTotSystemOut);
    1991         3032 :                 SystemTotalCoolingEnergy = SystemTotalCoolingRate * state.dataHVACGlobal->TimeStepSysSec;
    1992              :             } else {
    1993         2503 :                 SystemTotalHeatingRate = std::abs(QTotSystemOut);
    1994         2503 :                 SystemTotalHeatingEnergy = SystemTotalHeatingRate * state.dataHVACGlobal->TimeStepSysSec;
    1995              :             }
    1996              : 
    1997         5535 :             if (QSensSystemOut > 0) // system sensible cooling
    1998              :             {
    1999         3030 :                 SystemSensibleCoolingRate = std::abs(QSensSystemOut);
    2000         3030 :                 SystemSensibleCoolingEnergy = SystemSensibleCoolingRate * state.dataHVACGlobal->TimeStepSysSec;
    2001              :             } else {
    2002         2505 :                 SystemSensibleHeatingRate = std::abs(QSensSystemOut);
    2003         2505 :                 SystemSensibleHeatingEnergy = SystemSensibleHeatingRate * state.dataHVACGlobal->TimeStepSysSec;
    2004              :             }
    2005         5535 :             if ((SystemTotalCoolingRate - SystemSensibleCoolingRate) > 0) {
    2006          408 :                 SystemLatentCoolingRate = SystemTotalCoolingRate - SystemSensibleCoolingRate;
    2007          408 :                 SystemLatentCoolingEnergy = SystemTotalCoolingEnergy - SystemSensibleCoolingEnergy;
    2008              :             }
    2009         5535 :             if ((SystemTotalHeatingRate - SystemSensibleHeatingRate) < 0) {
    2010         1472 :                 SystemLatentHeatingRate = SystemTotalHeatingRate - SystemSensibleHeatingRate;
    2011         1472 :                 SystemLatentHeatingEnergy = SystemTotalHeatingEnergy - SystemSensibleHeatingEnergy;
    2012              :             }
    2013              :         } else // unit is in standby so reset conditioning outputs
    2014              :         {
    2015         7740 :             QTotZoneOut = 0;
    2016         7740 :             QSensZoneOut = 0;
    2017         7740 :             QLatentZoneOut = 0;
    2018         7740 :             QLatentZoneOutMass = 0;
    2019         7740 :             QTotSystemOut = 0;
    2020         7740 :             QSensSystemOut = 0;
    2021         7740 :             QLatentSystemOut = 0;
    2022              :             // reset outputs
    2023         7740 :             ResetOutputs();
    2024              :         }
    2025              : 
    2026              :         // set timestep outputs calculated considering different runtime fractions.
    2027        13275 :         SupplyFanElectricPower = CalculateTimeStepAverage(SYSTEMOUTPUTS::OSUPPLY_FAN_POWER); // Watts
    2028        13275 :         SupplyFanElectricEnergy = SupplyFanElectricPower * state.dataHVACGlobal->TimeStepSysSec;
    2029        13275 :         SecondaryFuelConsumptionRate = CalculateTimeStepAverage(SYSTEMOUTPUTS::OSECOND_FUEL_USE);
    2030        13275 :         SecondaryFuelConsumption = SecondaryFuelConsumptionRate * state.dataHVACGlobal->TimeStepSysSec;
    2031        13275 :         ThirdFuelConsumptionRate = CalculateTimeStepAverage(SYSTEMOUTPUTS::OTHIRD_FUEL_USE);
    2032        13275 :         ThirdFuelConsumption = ThirdFuelConsumptionRate * state.dataHVACGlobal->TimeStepSysSec;
    2033        13275 :         WaterConsumptionRate = CalculateTimeStepAverage(SYSTEMOUTPUTS::OWATER_USE);
    2034        13275 :         WaterConsumption = WaterConsumptionRate * state.dataHVACGlobal->TimeStepSysSec;
    2035        13275 :         ExternalStaticPressure = CalculateTimeStepAverage(SYSTEMOUTPUTS::OEXTERNAL_STATIC_PRESSURE);
    2036              : 
    2037        13275 :         FinalElectricalPower = CalculateTimeStepAverage(SYSTEMOUTPUTS::SYSTEM_FUEL_USE);
    2038        13275 :         FinalElectricalEnergy = FinalElectricalPower * state.dataHVACGlobal->TimeStepSysSec;
    2039        13275 :     }
    2040              : 
    2041              : } // namespace HybridEvapCoolingModel
    2042              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1