LCOV - code coverage report
Current view: top level - EnergyPlus - HybridEvapCoolingModel.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 805 947 85.0 %
Date: 2023-01-17 19:17:23 Functions: 34 34 100.0 %

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

Generated by: LCOV version 1.13