LCOV - code coverage report
Current view: top level - EnergyPlus - EconomicTariff.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 51.6 % 2805 1446
Test Date: 2025-05-22 16:09:37 Functions: 80.5 % 41 33

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cassert>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/Array.functions.hh>
      53              : #include <ObjexxFCL/Fmath.hh>
      54              : #include <ObjexxFCL/numeric.hh>
      55              : #include <ObjexxFCL/string.functions.hh>
      56              : 
      57              : // EnergyPlus Headers
      58              : #include <EnergyPlus/CostEstimateManager.hh>
      59              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      60              : #include <EnergyPlus/DataEnvironment.hh>
      61              : #include <EnergyPlus/DataGlobalConstants.hh>
      62              : #include <EnergyPlus/DataIPShortCuts.hh>
      63              : #include <EnergyPlus/DisplayRoutines.hh>
      64              : #include <EnergyPlus/EconomicTariff.hh>
      65              : #include <EnergyPlus/General.hh>
      66              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      67              : #include <EnergyPlus/OutputProcessor.hh>
      68              : #include <EnergyPlus/OutputReportPredefined.hh>
      69              : #include <EnergyPlus/OutputReportTabular.hh>
      70              : #include <EnergyPlus/ResultsFramework.hh>
      71              : #include <EnergyPlus/SQLiteProcedures.hh>
      72              : #include <EnergyPlus/ScheduleManager.hh>
      73              : #include <EnergyPlus/UtilityRoutines.hh>
      74              : 
      75              : namespace EnergyPlus::EconomicTariff {
      76              : 
      77              : // MODULE INFORMATION:
      78              : //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
      79              : //    DATE WRITTEN   May 2004
      80              : 
      81              : //    Compute utility bills for a building based on energy
      82              : //    use estimate.
      83              : 
      84              : constexpr std::array<std::string_view, (int)EconConv::Num> convEnergyStrings = {
      85              :     "", "kWh", "Therm", "MMBtu", "MJ", "kBTU", "MCF", "CCF", "m3", "gal", "kgal"};
      86              : constexpr std::array<std::string_view, (int)EconConv::Num> convDemandStrings = {
      87              :     "", "kW", "Therm", "MMBtu", "MJ", "kBTU", "MCF", "CCF", "m3", "gal", "kgal"};
      88              : constexpr std::array<std::string_view, (int)EconConv::Num> econConvNamesUC = {
      89              :     "USERDEFINED", "KWH", "THERM", "MMBTU", "MJ", "KBTU", "MCF", "CCF", "M3", "GAL", "KGAL"};
      90              : 
      91              : constexpr std::array<std::string_view, (int)DemandWindow::Num> demandWindowStrings = {"/Hr", "/Hr", "/Hr", "/Day", "/Wk"};
      92              : 
      93              : constexpr std::array<std::string_view, (int)BuySell::Num> buySellNames = {"BuyFromUtility", "SellToUtility", "NetMetering"};
      94              : constexpr std::array<std::string_view, (int)BuySell::Num> buySellNamesUC = {"BUYFROMUTILITY", "SELLTOUTILITY", "NETMETERING"};
      95              : 
      96              : constexpr std::array<std::string_view, (int)Season::Num> seasonNames = {"Unused", "Winter", "Spring", "Summer", "Fall", "Annual", "Monthly"};
      97              : constexpr std::array<std::string_view, (int)Season::Num> seasonNamesUC = {"Unused", "WINTER", "SPRING", "SUMMER", "FALL", "ANNUAL", "MONTHLY"};
      98              : 
      99              : constexpr std::array<std::string_view, (int)Op::Num> opNamesUC = {"SUM",
     100              :                                                                   "MULTIPLY",
     101              :                                                                   "SUBTRACT",
     102              :                                                                   "DIVIDE",
     103              :                                                                   "ABSOLUTE",
     104              :                                                                   "INTEGER",
     105              :                                                                   "SIGN",
     106              :                                                                   "ROUND",
     107              :                                                                   "MAXIMUM",
     108              :                                                                   "MINIMUM",
     109              :                                                                   "EXCEEDS",
     110              :                                                                   "ANNUALMINIMUM",
     111              :                                                                   "ANNUALMAXIMUM",
     112              :                                                                   "ANNUALSUM",
     113              :                                                                   "ANNUALAVERAGE",
     114              :                                                                   "ANNUALOR",
     115              :                                                                   "ANNUALAND",
     116              :                                                                   "ANNUALMAXIMUMZERO",
     117              :                                                                   "ANNUALMINIMUMZERO",
     118              :                                                                   "IF",
     119              :                                                                   "GREATERTHAN",
     120              :                                                                   "GREATEREQUAL",
     121              :                                                                   "LESSTHAN",
     122              :                                                                   "LESSEQUAL",
     123              :                                                                   "EQUAL",
     124              :                                                                   "NOTEQUAL",
     125              :                                                                   "AND",
     126              :                                                                   "OR",
     127              :                                                                   "NOT",
     128              :                                                                   "ADD",
     129              :                                                                   "FROM"};
     130              : 
     131              : constexpr std::array<std::string_view, (int)Op::Num> opNames2UC = {
     132              :     "SUM",   "MULT",   "SUBT",   "DIV", "ABS", "INT", "SIGN", "ROUND", "MAX", "MIN", "EXCEEDS", "ANMIN", "ANMAX", "ANSUM", "ANAVG", "ANOR",
     133              :     "ANAND", "ANMAXZ", "ANMINZ", "IF",  "GT",  "GE",  "LT",   "LE",    "EQ",  "NE",  "AND",     "OR",    "NOT",   "ADD",   "NOOP"};
     134              : 
     135              : constexpr std::array<std::string_view, (int)Cat::Num> catNames = {
     136              :     "EnergyCharges", "DemandCharges", "ServiceCharges", "Basis", "Adjustment", "Surcharge", "Subtotal", "Taxes", "Total", "NotIncluded"};
     137              : constexpr std::array<std::string_view, (int)Cat::Num> catNamesUC = {
     138              :     "ENERGYCHARGES", "DEMANDCHARGES", "SERVICECHARGES", "BASIS", "ADJUSTMENT", "SURCHARGE", "SUBTOTAL", "TAXES", "TOTAL", "NOTINCLUDED"};
     139              : 
     140              : constexpr std::array<std::string_view, (int)Native::Num> nativeNames = {"TotalEnergy",
     141              :                                                                         "TotalDemand",
     142              :                                                                         "PeakEnergy",
     143              :                                                                         "PeakDemand",
     144              :                                                                         "ShoulderEnergy",
     145              :                                                                         "ShoulderDemand",
     146              :                                                                         "OffPeakEnergy",
     147              :                                                                         "OffPeakDemand",
     148              :                                                                         "MidPeakEnergy",
     149              :                                                                         "MidPeakDemand",
     150              :                                                                         "PeakExceedsOffPeak",
     151              :                                                                         "OffPeakExceedsPeak",
     152              :                                                                         "PeakExceedsMidPeak",
     153              :                                                                         "MidPeakExceedsPeak",
     154              :                                                                         "PeakExceedsShoulder",
     155              :                                                                         "ShoulderExceedsPeak",
     156              :                                                                         "IsWinter",
     157              :                                                                         "IsNotWinter",
     158              :                                                                         "IsSpring",
     159              :                                                                         "IsNotSpring",
     160              :                                                                         "IsSummer",
     161              :                                                                         "IsNotSummer",
     162              :                                                                         "IsAutumn",
     163              :                                                                         "IsNotAutumn",
     164              :                                                                         "PeakAndShoulderEnergy",
     165              :                                                                         "PeakAndShoulderDemand",
     166              :                                                                         "PeakAndMidPeakEnergy",
     167              :                                                                         "PeakAndMidPeakDemand",
     168              :                                                                         "ShoulderAndOffPeakEnergy",
     169              :                                                                         "ShoulderAndOffPeakDemand",
     170              :                                                                         "PeakAndOffPeakEnergy",
     171              :                                                                         "PeakAndOffPeakDemand",
     172              :                                                                         "RealTimePriceCosts",
     173              :                                                                         "AboveCustomerBaseCosts",
     174              :                                                                         "BelowCustomerBaseCosts",
     175              :                                                                         "AboveCustomerBaseEnergy",
     176              :                                                                         "BelowCustomerBaseEnergy"};
     177              : constexpr std::array<std::string_view, (int)Native::Num> nativeNamesUC = {"TOTALENERGY",
     178              :                                                                           "TOTALDEMAND",
     179              :                                                                           "PEAKENERGY",
     180              :                                                                           "PEAKDEMAND",
     181              :                                                                           "SHOULDERENERGY",
     182              :                                                                           "SHOULDERDEMAND",
     183              :                                                                           "OFFPEAKENERGY",
     184              :                                                                           "OFFPEAKDEMAND",
     185              :                                                                           "MIDPEAKENERGY",
     186              :                                                                           "MIDPEAKDEMAND",
     187              :                                                                           "PEAKEXCEEDSOFFPEAK",
     188              :                                                                           "OFFPEAKEXCEEDSPEAK",
     189              :                                                                           "PEAKEXCEEDSMIDPEAK",
     190              :                                                                           "MIDPEAKEXCEEDSPEAK",
     191              :                                                                           "PEAKEXCEEDSSHOULDER",
     192              :                                                                           "SHOULDEREXCEEDSPEAK",
     193              :                                                                           "ISWINTER",
     194              :                                                                           "ISNOTWINTER",
     195              :                                                                           "ISSPRING",
     196              :                                                                           "ISNOTSPRING",
     197              :                                                                           "ISSUMMER",
     198              :                                                                           "ISNOTSUMMER",
     199              :                                                                           "ISAUTUMN",
     200              :                                                                           "ISNOTAUTUMN",
     201              :                                                                           "PEAKANDSHOULDERENERGY",
     202              :                                                                           "PEAKANDSHOULDERDEMAND",
     203              :                                                                           "PEAKANDMIDPEAKENERGY",
     204              :                                                                           "PEAKANDMIDPEAKDEMAND",
     205              :                                                                           "SHOULDERANDOFFPEAKENERGY",
     206              :                                                                           "SHOULDERANDOFFPEAKDEMAND",
     207              :                                                                           "PEAKANDOFFPEAKENERGY",
     208              :                                                                           "PEAKANDOFFPEAKDEMAND",
     209              :                                                                           "REALTIMEPRICECOSTS",
     210              :                                                                           "ABOVECUSTOMERBASECOSTS",
     211              :                                                                           "BELOWCUSTOMERBASECOSTS",
     212              :                                                                           "ABOVECUSTOMERBASEENERGY",
     213              :                                                                           "BELOWCUSTOMERBASEENERGY"};
     214              : 
     215              : constexpr std::array<std::string_view, (int)VarUnitType::Num> varUnitTypeNames = {"Energy", "Demand", "Dimensionless", "Currency"};
     216              : constexpr std::array<std::string_view, (int)VarUnitType::Num> varUnitTypeNamesUC = {"ENERGY", "DEMAND", "DIMENSIONLESS", "CURRENCY"};
     217              : 
     218        18787 : void UpdateUtilityBills(EnergyPlusData &state)
     219              : {
     220              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
     221              :     //    DATE WRITTEN   September 2003
     222              : 
     223              :     //    Single routine used to call all get input
     224              :     //    routines for economics.
     225              : 
     226        18787 :     auto &s_econ = state.dataEconTariff;
     227              : 
     228        18787 :     if (s_econ->Update_GetInput) {
     229           80 :         bool ErrorsFound = false;
     230              : 
     231           80 :         GetInputEconomicsTariff(state, ErrorsFound);
     232              :         // do rest of GetInput only if at least one tariff is defined.
     233           80 :         GetInputEconomicsCurrencyType(state, ErrorsFound);
     234           80 :         if (s_econ->numTariff >= 1) {
     235            7 :             if (!ErrorsFound && state.dataOutRptTab->displayEconomicResultSummary)
     236            0 :                 OutputReportTabular::AddTOCEntry(state, "Economics Results Summary Report", "Entire Facility");
     237            7 :             CreateCategoryNativeVariables(state);
     238            7 :             GetInputEconomicsQualify(state, ErrorsFound);
     239            7 :             GetInputEconomicsChargeSimple(state, ErrorsFound);
     240            7 :             GetInputEconomicsChargeBlock(state, ErrorsFound);
     241            7 :             GetInputEconomicsRatchet(state, ErrorsFound);
     242            7 :             GetInputEconomicsVariable(state, ErrorsFound);
     243            7 :             GetInputEconomicsComputation(state, ErrorsFound);
     244            7 :             CreateDefaultComputation(state);
     245              :         }
     246           80 :         s_econ->Update_GetInput = false;
     247           80 :         if (ErrorsFound) ShowFatalError(state, "UpdateUtilityBills: Preceding errors cause termination.");
     248              :     }
     249        18787 :     if (state.dataGlobal->DoOutputReporting && (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather)) {
     250            3 :         GatherForEconomics(state);
     251              :     }
     252        18787 : }
     253              : 
     254              : //======================================================================================================================
     255              : //======================================================================================================================
     256              : 
     257              : //    GET INPUT ROUTINES
     258              : 
     259              : //======================================================================================================================
     260              : //======================================================================================================================
     261              : 
     262           80 : void GetInputEconomicsTariff(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
     263              : {
     264              :     // SUBROUTINE INFORMATION:
     265              :     //       AUTHOR         Jason Glazer of GARD Analytics, Inc.
     266              :     //       DATE WRITTEN   May 2004
     267              :     //       MODIFIED       Aug. 2017, Julien Marrec of EffiBEM. Handled conversions factor based on meter resources
     268              :     //
     269              :     // PURPOSE OF THIS SUBROUTINE:
     270              :     // This subroutine reads the input file for "UtilityCost:Tariff" objects
     271              :     // It will be the right conversion factors based on the associated meter resource type
     272              :     // meaning if "CCF" is picked, the conversion factor isn't the same whether it's a water meter or a fuel meter.
     273              : 
     274              :     static constexpr std::string_view RoutineName("GetInputEconomicsTariff: ");
     275              :     static constexpr std::string_view routineName = "GetInputEconomicsTariff";
     276              : 
     277              :     int NumAlphas; // Number of elements in the alpha array
     278              :     int NumNums;   // Number of elements in the numeric array
     279              :     int IOStat;    // IO Status when calling get input subroutine
     280              :     bool isNotNumeric;
     281              :     // variables for getting report variable/meter index
     282              :     int KeyCount;
     283              :     OutputProcessor::VariableType TypeVar;
     284              :     OutputProcessor::StoreType AvgSumVar;
     285              :     OutputProcessor::TimeStepType StepTypeVar;
     286           80 :     Constant::Units UnitsVar = Constant::Units::None; // Units sting, may be blank
     287           80 :     Array1D_string NamesOfKeys;                       // Specific key name
     288           80 :     Array1D_int IndexesForKeyVar;                     // Array index
     289              : 
     290           80 :     auto &s_ipsc = state.dataIPShortCut;
     291           80 :     auto &s_econ = state.dataEconTariff;
     292              : 
     293           80 :     std::string_view CurrentModuleObject = "UtilityCost:Tariff";
     294           80 :     s_econ->numTariff = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     295           80 :     s_econ->tariff.allocate(s_econ->numTariff);
     296           87 :     for (int iInObj = 1; iInObj <= s_econ->numTariff; ++iInObj) {
     297           14 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     298              :                                                                  CurrentModuleObject,
     299              :                                                                  iInObj,
     300            7 :                                                                  s_ipsc->cAlphaArgs,
     301              :                                                                  NumAlphas,
     302            7 :                                                                  s_ipsc->rNumericArgs,
     303              :                                                                  NumNums,
     304              :                                                                  IOStat,
     305            7 :                                                                  s_ipsc->lNumericFieldBlanks,
     306            7 :                                                                  s_ipsc->lAlphaFieldBlanks,
     307            7 :                                                                  s_ipsc->cAlphaFieldNames,
     308            7 :                                                                  s_ipsc->cNumericFieldNames);
     309              : 
     310            7 :         ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
     311            7 :         auto &tariff = s_econ->tariff(iInObj);
     312              : 
     313              :         // check to make sure none of the values are another economic object
     314           73 :         for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
     315              :             //  args are always turned to upper case but this is okay...
     316           66 :             if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
     317            0 :                 ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     318            0 :                 ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
     319              :             }
     320              :         }
     321              :         // name of the tariff
     322            7 :         tariff.tariffName = s_ipsc->cAlphaArgs(1);
     323              :         // check if tariff name is unique
     324            7 :         int found = 0;
     325            7 :         for (int jObj = 1; jObj <= iInObj - 1; ++jObj) {
     326            0 :             if (tariff.tariffName == s_econ->tariff(jObj).tariffName) {
     327            0 :                 found = jObj;
     328            0 :                 break;
     329              :             }
     330              :         }
     331            7 :         if (found > 0) {
     332            0 :             ShowSevereDuplicateName(state, eoh);
     333            0 :             ErrorsFound = true;
     334              :         }
     335              :         // name of the report meter
     336            7 :         tariff.reportMeter = s_ipsc->cAlphaArgs(2);
     337              :         // call the key count function but only need count during this pass
     338            7 :         GetVariableKeyCountandType(state, tariff.reportMeter, KeyCount, TypeVar, AvgSumVar, StepTypeVar, UnitsVar);
     339              :         // if no meters found for that name
     340            7 :         if (KeyCount == 0) {
     341            3 :             ShowWarningError(state, format("{}{}=\"{}\" missing meter", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     342            6 :             ShowContinueError(
     343              :                 state,
     344            6 :                 format("Meter referenced is not present due to a lack of equipment that uses that energy source/meter:\"{}\".", tariff.reportMeter));
     345            3 :             tariff.reportMeterIndx = -1;
     346              :         } else {
     347            4 :             NamesOfKeys.allocate(KeyCount);
     348            4 :             IndexesForKeyVar.allocate(KeyCount);
     349            4 :             GetVariableKeys(state, tariff.reportMeter, TypeVar, NamesOfKeys, IndexesForKeyVar);
     350              :             // although this retrieves all keys for a variable, we only need one so the first one is chosen
     351            4 :             if (KeyCount > 1) {
     352            0 :                 ShowWarningError(state, format("{}{}=\"{}\" multiple keys", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     353            0 :                 ShowContinueError(state, "... Multiple keys for variable select. First key will be used.");
     354              :             }
     355              :             // assign the index
     356            4 :             tariff.reportMeterIndx = IndexesForKeyVar(1);
     357              :             // get rid of the arrays used to get the variable number
     358            4 :             NamesOfKeys.deallocate();
     359            4 :             IndexesForKeyVar.deallocate();
     360              :         }
     361              : 
     362              :         // Start by checking what type of meter we do have, some units can be used for several resources with different conversion factors
     363              :         // Explicitly assume it's not a water meter nor an electric meter nor a gas meter (was already done in constructor though)
     364            7 :         tariff.kindMtr = MeterType::Other;
     365              : 
     366              :         // Determine whether this meter is related to electricity, or water, or gas
     367            7 :         if (tariff.reportMeterIndx != -1) {
     368            4 :             switch (state.dataOutputProcessor->meters[tariff.reportMeterIndx]->resource) {
     369              :             // Various types of electricity meters
     370            1 :             case Constant::eResource::Electricity: {
     371            1 :                 tariff.kindMtr = MeterType::ElecSimple;
     372            1 :             } break;
     373            0 :             case Constant::eResource::ElectricityProduced: {
     374            0 :                 tariff.kindMtr = MeterType::ElecProduced;
     375            0 :             } break;
     376            0 :             case Constant::eResource::ElectricityPurchased: {
     377            0 :                 tariff.kindMtr = MeterType::ElecPurchased;
     378            0 :             } break;
     379            0 :             case Constant::eResource::ElectricitySurplusSold: {
     380            0 :                 tariff.kindMtr = MeterType::ElecSurplusSold;
     381            0 :             } break;
     382            0 :             case Constant::eResource::ElectricityNet: {
     383            0 :                 tariff.kindMtr = MeterType::ElecNet;
     384            0 :             } break;
     385              :             // Handle the case where its a water meter
     386            2 :             case Constant::eResource::Water:
     387              :             case Constant::eResource::OnSiteWater:
     388              :             case Constant::eResource::MainsWater:
     389              :             case Constant::eResource::RainWater:
     390              :             case Constant::eResource::WellWater:
     391              :             case Constant::eResource::Condensate: {
     392            2 :                 tariff.kindMtr = MeterType::Water;
     393            2 :             } break;
     394              :             // Or a Natural Gas meter
     395            1 :             case Constant::eResource::NaturalGas: {
     396            1 :                 tariff.kindMtr = MeterType::Gas;
     397            1 :             } break;
     398            0 :             default: {
     399            0 :                 tariff.kindMtr = MeterType::Other; // Do or assert something here?
     400            0 :             } break;
     401              :             } // switch
     402              :         }
     403              : 
     404              :         // Assign the right conversion factors based on the resource type
     405              : 
     406              :         // If it's a water meter
     407              :         // We set demandConv to something analogous to m3/h
     408            7 :         switch (tariff.kindMtr) {
     409            2 :         case MeterType::Water: {
     410              :             // conversion factor
     411            2 :             tariff.convChoice = static_cast<EconConv>(getEnumValue(econConvNamesUC, s_ipsc->cAlphaArgs(3)));
     412            2 :             switch (tariff.convChoice) {
     413            0 :             case EconConv::USERDEF: {
     414            0 :                 tariff.energyConv = s_ipsc->rNumericArgs(1); // energy conversion factor
     415            0 :                 tariff.demandConv = s_ipsc->rNumericArgs(2); // demand conversion factor
     416            0 :             } break;
     417              : 
     418            0 :             case EconConv::M3: {
     419            0 :                 tariff.energyConv = 1.0;
     420            0 :                 tariff.demandConv = 3600.0;
     421            0 :             } break;
     422              : 
     423            1 :             case EconConv::CCF: {
     424            1 :                 tariff.energyConv = 0.35314666721488586;
     425            1 :                 tariff.demandConv = 0.35314666721488586 * 3600;
     426            1 :             } break;
     427              : 
     428            0 :             case EconConv::GAL: {
     429            0 :                 tariff.energyConv = 264.1720523602524;
     430            0 :                 tariff.demandConv = 264.1720523602524 * 3600;
     431            0 :             } break;
     432              : 
     433            0 :             case EconConv::KGAL: {
     434            0 :                 tariff.energyConv = 0.2641720523602524;
     435            0 :                 tariff.demandConv = 0.2641720523602524 * 3600;
     436            0 :             } break;
     437              : 
     438            1 :             default: { // ERROR: not a valid conversion, default to M3
     439            1 :                 tariff.convChoice = EconConv::M3;
     440            1 :                 tariff.energyConv = 1.0;
     441            1 :                 tariff.demandConv = 3600.0;
     442            1 :                 ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), "M3");
     443            1 :             } break;
     444              :             } // switch (tariff.convChoice)
     445              : 
     446            2 :         } break;
     447              : 
     448              :             // If it's an electric meter
     449              :             // Volumetric units such as MCF or CCF doesn't make sense IMHO (JM)
     450              :             // THERM is strange for an electric meter but currently I accept but issue a warning
     451            1 :         case MeterType::ElecSimple:
     452              :         case MeterType::ElecProduced:
     453              :         case MeterType::ElecPurchased:
     454              :         case MeterType::ElecSurplusSold:
     455              :         case MeterType::ElecNet: {
     456            1 :             tariff.convChoice = static_cast<EconConv>(getEnumValue(econConvNamesUC, s_ipsc->cAlphaArgs(3)));
     457              : 
     458            1 :             switch (tariff.convChoice) {
     459            0 :             case EconConv::USERDEF: {
     460            0 :                 tariff.energyConv = s_ipsc->rNumericArgs(1); // energy conversion factor
     461            0 :                 tariff.demandConv = s_ipsc->rNumericArgs(2); // demand conversion factor
     462            0 :             } break;
     463              : 
     464            0 :             case EconConv::KWH: {
     465            0 :                 tariff.energyConv = 0.0000002778;
     466            0 :                 tariff.demandConv = 0.001;
     467            0 :             } break;
     468              : 
     469            0 :             case EconConv::MJ: {
     470            0 :                 tariff.energyConv = 0.000001;
     471            0 :                 tariff.demandConv = 0.0036;
     472            0 :             } break;
     473              : 
     474            0 :             case EconConv::MMBTU: {
     475            0 :                 tariff.energyConv = 9.4781712e-10;
     476            0 :                 tariff.demandConv = 0.000003412;
     477            0 :             } break;
     478              : 
     479            0 :             case EconConv::KBTU: {
     480            0 :                 tariff.energyConv = 9.4781712e-7;
     481            0 :                 tariff.demandConv = 0.003412;
     482            0 :             } break;
     483              : 
     484              :                 // We accept the following choices, but issue a warning
     485            0 :             case EconConv::THERM: {
     486            0 :                 tariff.energyConv = 9.4781712e-9;
     487            0 :                 tariff.demandConv = 0.00003412;
     488            0 :                 ShowWarningCustom(
     489              :                     state,
     490              :                     eoh,
     491            0 :                     format("{}=\"{}\", Therm is an unusual choice for an electric resource.", s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)));
     492            0 :             } break;
     493              : 
     494              :                 // Otherwise, default to kWh
     495            1 :             default: {
     496            1 :                 tariff.convChoice = EconConv::KWH;
     497            1 :                 tariff.energyConv = 0.0000002778;
     498            1 :                 tariff.demandConv = 0.001;
     499            1 :                 ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), "KWH");
     500            1 :             } break;
     501              :             } // switch (tariff.convChoice)
     502            1 :         } break;
     503              : 
     504              :             // If it's a gas meter
     505            1 :         case MeterType::Gas: {
     506            1 :             tariff.convChoice = static_cast<EconConv>(getEnumValue(econConvNamesUC, s_ipsc->cAlphaArgs(3)));
     507            1 :             switch (tariff.convChoice) {
     508            0 :             case EconConv::USERDEF: {
     509            0 :                 tariff.energyConv = s_ipsc->rNumericArgs(1); // energy conversion factor
     510            0 :                 tariff.demandConv = s_ipsc->rNumericArgs(2); // demand conversion factor
     511            0 :             } break;
     512              : 
     513            0 :             case EconConv::KWH: {
     514            0 :                 tariff.energyConv = 0.0000002778;
     515            0 :                 tariff.demandConv = 0.001;
     516            0 :             } break;
     517              : 
     518            0 :             case EconConv::THERM: {
     519            0 :                 tariff.energyConv = 9.4781712e-9;
     520            0 :                 tariff.demandConv = 0.00003412;
     521            0 :             } break;
     522              : 
     523            0 :             case EconConv::MMBTU: {
     524            0 :                 tariff.energyConv = 9.4781712e-10;
     525            0 :                 tariff.demandConv = 0.000003412;
     526            0 :             } break;
     527              : 
     528            0 :             case EconConv::MJ: {
     529            0 :                 tariff.energyConv = 0.000001;
     530            0 :                 tariff.demandConv = 0.0036;
     531            0 :             } break;
     532              : 
     533            0 :             case EconConv::KBTU: {
     534            0 :                 tariff.energyConv = 9.4781712e-7;
     535            0 :                 tariff.demandConv = 0.003412;
     536            0 :             } break;
     537              :                 // Volumetric units for natural gas
     538              :                 // Actually assuming 1 therm = 1 CCF (= 100 ft^3)
     539            0 :             case EconConv::MCF: {
     540            0 :                 tariff.energyConv = 9.4781712e-10;
     541            0 :                 tariff.demandConv = 0.000003412;
     542            0 :             } break;
     543              : 
     544            1 :             case EconConv::CCF: {
     545            1 :                 tariff.energyConv = 9.4781712e-9;
     546            1 :                 tariff.demandConv = 0.00003412;
     547            1 :             } break;
     548              : 
     549              :                 // Obtained from converting CCF above to m^3 so the same heat content of natural gas is used (1 therm = 1 CCF)
     550            0 :             case EconConv::M3: {
     551            0 :                 tariff.energyConv = 2.6839192e-10;
     552            0 :                 tariff.demandConv = 9.6617081E-05;
     553            0 :             } break;
     554              : 
     555              :                 // Otherwise, default to kWh
     556            0 :             default: {
     557            0 :                 tariff.convChoice = EconConv::KWH;
     558            0 :                 tariff.energyConv = 0.0000002778;
     559            0 :                 tariff.demandConv = 0.001;
     560            0 :                 ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), "KWH");
     561            0 :             } break;
     562              :             } // witch (tariff.convChoice)
     563            1 :         } break;
     564              : 
     565              :             // It it's neither an electric, water or gas meter, we cannot accept volumetric units
     566              :             // because we cannot infer the heat content
     567            3 :         case MeterType::Other: {
     568            3 :             tariff.convChoice = static_cast<EconConv>(getEnumValue(econConvNamesUC, s_ipsc->cAlphaArgs(3)));
     569            3 :             switch (tariff.convChoice) {
     570            0 :             case EconConv::USERDEF: {
     571            0 :                 tariff.energyConv = s_ipsc->rNumericArgs(1); // energy conversion factor
     572            0 :                 tariff.demandConv = s_ipsc->rNumericArgs(2); // demand conversion factor
     573            0 :             } break;
     574              : 
     575            3 :             case EconConv::KWH: {
     576            3 :                 tariff.energyConv = 0.0000002778;
     577            3 :                 tariff.demandConv = 0.001;
     578            3 :             } break;
     579              : 
     580            0 :             case EconConv::THERM: {
     581            0 :                 tariff.energyConv = 9.4781712e-9;
     582            0 :                 tariff.demandConv = 0.00003412;
     583            0 :             } break;
     584              : 
     585            0 :             case EconConv::MMBTU: {
     586            0 :                 tariff.energyConv = 9.4781712e-10;
     587            0 :                 tariff.demandConv = 0.000003412;
     588            0 :             } break;
     589              : 
     590            0 :             case EconConv::MJ: {
     591            0 :                 tariff.energyConv = 0.000001;
     592            0 :                 tariff.demandConv = 0.0036;
     593            0 :             } break;
     594              : 
     595            0 :             case EconConv::KBTU: {
     596            0 :                 tariff.energyConv = 9.4781712e-7;
     597            0 :                 tariff.demandConv = 0.003412;
     598            0 :             } break;
     599              : 
     600              :                 // Otherwise, default to kWh
     601            0 :             default: {
     602            0 :                 tariff.convChoice = EconConv::KWH;
     603            0 :                 tariff.energyConv = 0.0000002778;
     604            0 :                 tariff.demandConv = 0.001;
     605            0 :                 ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), "KWH");
     606            0 :             } break;
     607              :             } // switch (tariff.convChoice)
     608            3 :         } break;
     609              : 
     610            0 :         default: {
     611            0 :         } break;
     612              :         } // Default conversion factors have been applied from here on
     613              : 
     614              :         // schedules
     615              :         // period schedule
     616            7 :         if (len(s_ipsc->cAlphaArgs(4)) > 0) {
     617            1 :             if ((tariff.periodSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(4))) == nullptr) {
     618            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
     619            0 :                 ErrorsFound = true;
     620              :             }
     621              :         }
     622              : 
     623              :         // season schedule
     624            7 :         if (len(s_ipsc->cAlphaArgs(5)) > 0) {
     625            3 :             if ((tariff.seasonSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(5))) == nullptr) {
     626            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5));
     627            0 :                 ErrorsFound = true;
     628              :             }
     629              :         }
     630              : 
     631              :         // month schedule
     632            7 :         if (len(s_ipsc->cAlphaArgs(6)) > 0) {
     633            0 :             if ((tariff.monthSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
     634            0 :                 ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
     635            0 :                 ErrorsFound = true;
     636              :             }
     637              :         }
     638              :         // type of demand window
     639            7 :         if (Util::SameString(s_ipsc->cAlphaArgs(7), "QuarterHour")) {
     640              :             // check to make sure that the demand window and the TIMESTEP IN HOUR are consistent.
     641              :             { // Why is this a nested scope?
     642            0 :                 switch (state.dataGlobal->TimeStepsInHour) {
     643            0 :                 case 1:
     644              :                 case 3:
     645              :                 case 5:
     646              :                 case 15: {
     647            0 :                     tariff.demandWindow = DemandWindow::Hour;
     648            0 :                     tariff.demWinTime = 1.00;
     649            0 :                     ShowWarningError(state, format("{}{}=\"{}\" invalid data", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     650            0 :                     ShowContinueError(state,
     651            0 :                                       format("Demand window of QuarterHour is not consistent with number of timesteps per hour [{}].",
     652            0 :                                              state.dataGlobal->TimeStepsInHour));
     653            0 :                     ShowContinueError(state, "Demand window will be set to FullHour, and the simulation continues.");
     654            0 :                 } break;
     655            0 :                 case 2:
     656              :                 case 6:
     657              :                 case 10:
     658              :                 case 30: {
     659            0 :                     tariff.demandWindow = DemandWindow::Half;
     660            0 :                     tariff.demWinTime = 0.50;
     661            0 :                     ShowWarningError(state, format("{}{}=\"{}\" invalid data", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     662            0 :                     ShowContinueError(state,
     663            0 :                                       format("Demand window of QuarterHour is not consistent with number of timesteps per hour [{}].",
     664            0 :                                              state.dataGlobal->TimeStepsInHour));
     665            0 :                     ShowContinueError(state, "Demand window will be set to HalfHour, and the simulation continues.");
     666            0 :                 } break;
     667            0 :                 case 4:
     668              :                 case 12:
     669              :                 case 20:
     670              :                 case 60: {
     671            0 :                     tariff.demandWindow = DemandWindow::Quarter;
     672            0 :                     tariff.demWinTime = 0.25;
     673            0 :                 } break;
     674            0 :                 default: {
     675            0 :                     assert(false);
     676              :                 } break;
     677              :                 }
     678              :             }
     679            7 :         } else if (Util::SameString(s_ipsc->cAlphaArgs(7), "HalfHour")) {
     680              :             {
     681            0 :                 switch (state.dataGlobal->TimeStepsInHour) {
     682            0 :                 case 1:
     683              :                 case 3:
     684              :                 case 5:
     685              :                 case 15: {
     686            0 :                     tariff.demandWindow = DemandWindow::Hour;
     687            0 :                     tariff.demWinTime = 1.00;
     688            0 :                     ShowWarningError(state, format("{}{}=\"{}\" invalid data", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     689            0 :                     ShowContinueError(state,
     690            0 :                                       format("Demand window of HalfHour is not consistent with number of timesteps per hour [{}].",
     691            0 :                                              state.dataGlobal->TimeStepsInHour));
     692            0 :                     ShowContinueError(state, "Demand window will be set to FullHour, and the simulation continues.");
     693            0 :                 } break;
     694            0 :                 case 2:
     695              :                 case 4:
     696              :                 case 6:
     697              :                 case 10:
     698              :                 case 12:
     699              :                 case 20:
     700              :                 case 30:
     701              :                 case 60: {
     702            0 :                     tariff.demandWindow = DemandWindow::Half;
     703            0 :                     tariff.demWinTime = 0.50;
     704            0 :                 } break;
     705            0 :                 default: {
     706              :                     // assert(false); // EconomicTariff unit test gets here with NumOfTimeStepInHour == 0
     707            0 :                 } break;
     708              :                 }
     709              :             }
     710            7 :         } else if (Util::SameString(s_ipsc->cAlphaArgs(7), "FullHour")) {
     711            0 :             tariff.demandWindow = DemandWindow::Hour;
     712            0 :             tariff.demWinTime = 1.00;
     713            7 :         } else if (Util::SameString(s_ipsc->cAlphaArgs(7), "Day")) {
     714            0 :             tariff.demandWindow = DemandWindow::Day;
     715            0 :             tariff.demWinTime = 24.00;
     716            7 :         } else if (Util::SameString(s_ipsc->cAlphaArgs(7), "Week")) {
     717            0 :             tariff.demandWindow = DemandWindow::Week;
     718            0 :             tariff.demWinTime = 24.0 * 7.0;
     719              :         } else {
     720              :             // if not entered default to the same logic as quarter of an hour
     721              :             {
     722            7 :                 switch (state.dataGlobal->TimeStepsInHour) {
     723            0 :                 case 1:
     724              :                 case 3:
     725              :                 case 5:
     726              :                 case 15: {
     727            0 :                     tariff.demandWindow = DemandWindow::Hour;
     728            0 :                     tariff.demWinTime = 1.00;
     729            0 :                 } break;
     730            0 :                 case 2:
     731              :                 case 6:
     732              :                 case 10:
     733              :                 case 30: {
     734            0 :                     tariff.demandWindow = DemandWindow::Half;
     735            0 :                     tariff.demWinTime = 0.50;
     736            0 :                 } break;
     737            7 :                 case 4:
     738              :                 case 12:
     739              :                 case 20:
     740              :                 case 60: {
     741            7 :                     tariff.demandWindow = DemandWindow::Quarter;
     742            7 :                     tariff.demWinTime = 0.25;
     743            7 :                 } break;
     744            0 :                 default: {
     745              :                     // assert(false); // EconomicTariff unit test got here with NumOfTimeStepInHour == 0
     746            0 :                 } break;
     747              :                 }
     748              :             }
     749              :         }
     750              :         // monthly charge
     751            7 :         tariff.monthChgVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(8), isNotNumeric);
     752            7 :         tariff.monthChgPt =
     753            7 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(8), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, iInObj);
     754              :         // minimum monthly charge
     755            7 :         if (len(s_ipsc->cAlphaArgs(9)) > 0) {
     756            0 :             tariff.minMonthChgVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(9), isNotNumeric);
     757              :         } else {
     758            7 :             tariff.minMonthChgVal = -HUGE_(-1.0); // set to a very negative value
     759              :         }
     760            7 :         tariff.minMonthChgPt =
     761            7 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(9), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, iInObj);
     762              :         // real time pricing
     763            7 :         tariff.chargeSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(10));
     764            7 :         tariff.baseUseSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(11));
     765              :         // group name for separate distribution and transmission rates
     766            7 :         tariff.groupName = s_ipsc->cAlphaArgs(12);
     767              :         // buy or sell option
     768              : 
     769            7 :         if (s_ipsc->lAlphaFieldBlanks(13)) {
     770            5 :             tariff.buyOrSell = BuySell::BuyFromUtility;
     771            2 :         } else if ((tariff.buyOrSell = static_cast<BuySell>(getEnumValue(buySellNamesUC, s_ipsc->cAlphaArgs(13)))) == BuySell::Invalid) {
     772            0 :             ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(13), s_ipsc->cAlphaArgs(13));
     773            0 :             ErrorsFound = true;
     774              :         }
     775              : 
     776              :         // check if meter is consistent with buy or sell option
     777            7 :         if (tariff.buyOrSell == BuySell::SellToUtility) {
     778            0 :             if (!Util::SameString(tariff.reportMeter, "ELECTRICITYSURPLUSSOLD:FACILITY")) {
     779            0 :                 ShowWarningError(state, format("{}{}=\"{}\" atypical meter", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     780            0 :                 ShowContinueError(state, format("The meter chosen \"{}\" is not typically used with the sellToUtility option.", tariff.reportMeter));
     781            0 :                 ShowContinueError(state, "Usually the ElectricitySurplusSold:Facility meter is selected when the sellToUtility option is used.");
     782              :             }
     783            7 :         } else if (tariff.buyOrSell == BuySell::NetMetering) {
     784            2 :             if (!Util::SameString(tariff.reportMeter, "ELECTRICITYNET:FACILITY")) {
     785            0 :                 ShowWarningError(state, format("{}{}=\"{}\" atypical meter", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     786            0 :                 ShowContinueError(state, format("The meter chosen \"{}\" is not typically used with the netMetering option.", tariff.reportMeter));
     787            0 :                 ShowContinueError(state, "Usually the ElectricityNet:Facility meter is selected when the netMetering option is used.");
     788              :             }
     789            5 :         } else if (tariff.buyOrSell == BuySell::BuyFromUtility) {
     790            5 :             if (hasi(tariff.reportMeter, "Elec")) { // test if electric meter
     791            3 :                 if (!(Util::SameString(tariff.reportMeter, "Electricity:Facility") ||
     792            3 :                       Util::SameString(tariff.reportMeter, "ElectricityPurchased:Facility"))) {
     793            0 :                     ShowWarningError(state, format("{}{}=\"{}\" atypical meter", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     794            0 :                     ShowContinueError(state,
     795            0 :                                       format("The meter chosen \"{}\" is not typically used with the buyFromUtility option.", tariff.reportMeter));
     796            0 :                     ShowContinueError(state,
     797              :                                       "Usually the Electricity:Facility meter or the ElectricityPurchased:Facility is selected when the "
     798              :                                       "buyFromUtility option is used.");
     799              :                 }
     800              :             }
     801              :         }
     802              : 
     803              :         // initialize gathering arrays
     804           91 :         for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
     805           84 :             tariff.seasonForMonth(kMonth) = Season::Invalid;
     806          504 :             for (int lPeriod = 0; lPeriod < (int)Period::Num; ++lPeriod) {
     807          420 :                 tariff.gatherEnergy(kMonth)[lPeriod] = 0.0;
     808          420 :                 tariff.gatherDemand(kMonth)[lPeriod] = 0.0;
     809              :             }
     810              :         }
     811              : 
     812              :         // assume that the tariff is qualified
     813            7 :         tariff.isQualified = true;
     814            7 :         tariff.ptDisqualifier = 0;
     815              :         // assume that the tariff is not selected
     816            7 :         tariff.isSelected = false;
     817            7 :         tariff.totalAnnualCost = 0.0;
     818              :         // now create the Table Of Contents entries for an HTML file
     819            7 :         if (state.dataOutRptTab->displayTariffReport) {
     820            0 :             OutputReportTabular::AddTOCEntry(state, "Tariff Report", tariff.tariffName);
     821              :         }
     822              :         // associate the resource number with each tariff
     823            7 :         if (tariff.reportMeterIndx != -1) {
     824            4 :             tariff.resource = state.dataOutputProcessor->meters[tariff.reportMeterIndx]->resource;
     825              :         }
     826              :     }
     827           80 : }
     828              : 
     829            7 : void GetInputEconomicsQualify(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
     830              : {
     831              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
     832              :     //    DATE WRITTEN   May 2004
     833              : 
     834              :     //    Read the input file for "Economics:Qualify" objects.
     835              : 
     836              :     static constexpr std::string_view RoutineName("GetInputEconomicsQualify: ");
     837              :     static constexpr std::string_view routineName = "GetInputEconomicsQualify";
     838              : 
     839              :     int iInObj;    // loop index variable for reading in objects
     840              :     int NumAlphas; // Number of elements in the alpha array
     841              :     int NumNums;   // Number of elements in the numeric array
     842              :     int IOStat;    // IO Status when calling get input subroutine
     843              :     bool isNotNumeric;
     844              :     int jFld;
     845              : 
     846            7 :     auto &s_econ = state.dataEconTariff;
     847            7 :     auto &s_ipsc = state.dataIPShortCut;
     848              : 
     849            7 :     s_ipsc->cCurrentModuleObject = "UtilityCost:Qualify";
     850            7 :     s_econ->numQualify = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     851            7 :     s_econ->qualify.allocate(s_econ->numQualify);
     852              : 
     853            8 :     for (iInObj = 1; iInObj <= s_econ->numQualify; ++iInObj) {
     854            2 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     855            1 :                                                                  s_ipsc->cCurrentModuleObject,
     856              :                                                                  iInObj,
     857            1 :                                                                  s_ipsc->cAlphaArgs,
     858              :                                                                  NumAlphas,
     859            1 :                                                                  s_ipsc->rNumericArgs,
     860              :                                                                  NumNums,
     861              :                                                                  IOStat,
     862            1 :                                                                  s_ipsc->lNumericFieldBlanks,
     863            1 :                                                                  s_ipsc->lAlphaFieldBlanks,
     864            1 :                                                                  s_ipsc->cAlphaFieldNames,
     865            1 :                                                                  s_ipsc->cNumericFieldNames);
     866              : 
     867            1 :         ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
     868              : 
     869            1 :         auto &qualify = s_econ->qualify(iInObj);
     870              : 
     871              :         // check to make sure none of the values are another economic object
     872            8 :         for (jFld = 1; jFld <= NumAlphas; ++jFld) {
     873            7 :             if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
     874            0 :                 ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     875            0 :                 ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
     876              :             }
     877              :         }
     878              :         // index of the tariff name in the tariff array
     879            1 :         qualify.tariffIndx = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
     880            1 :         warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), qualify.tariffIndx, ErrorsFound, s_ipsc->cCurrentModuleObject);
     881            1 :         qualify.namePt =
     882            1 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(1), true, varIsAssigned, varNotYetDefined, ObjType::Qualify, iInObj, qualify.tariffIndx);
     883              :         // index of the variable in the variable array
     884            1 :         qualify.sourcePt =
     885            1 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(3), true, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, qualify.tariffIndx);
     886              :         // indicator if maximum test otherwise minimum
     887            1 :         if (s_ipsc->cAlphaArgs(4) == "MINIMUM") {
     888            1 :             qualify.isMaximum = false;
     889            0 :         } else if (s_ipsc->cAlphaArgs(4) == "MAXIMUM") {
     890            0 :             qualify.isMaximum = true;
     891              :         } else {
     892            0 :             ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4), "Maximum");
     893            0 :             qualify.isMaximum = true;
     894              :         }
     895              :         // value of the threshold
     896            1 :         qualify.thresholdVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(5), isNotNumeric);
     897            1 :         qualify.thresholdPt =
     898            1 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(5), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, qualify.tariffIndx);
     899              :         // enumerated list of the kind of season
     900            1 :         if ((qualify.season = static_cast<Season>(getEnumValue(seasonNamesUC, s_ipsc->cAlphaArgs(6)))) == Season::Invalid) {
     901            0 :             ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6), "Annual");
     902            0 :             qualify.season = Season::Annual;
     903              :         }
     904              : 
     905              :         // indicator if consecutive months otherwise count
     906            1 :         if (s_ipsc->cAlphaArgs(7) == "COUNT") {
     907            1 :             qualify.isConsecutive = false;
     908            0 :         } else if (s_ipsc->cAlphaArgs(7) == "CONSECUTIVE") {
     909            0 :             qualify.isConsecutive = true;
     910              :         } else {
     911            0 :             ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5), "Consecutive");
     912            0 :             qualify.isConsecutive = true;
     913              :         }
     914              :         // number of months the test must be good for
     915            1 :         qualify.numberOfMonths = s_ipsc->rNumericArgs(1);
     916              :     }
     917            7 : }
     918              : 
     919            7 : void GetInputEconomicsChargeSimple(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
     920              : {
     921              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
     922              :     //    DATE WRITTEN   May 2004
     923              : 
     924              :     //    Read the input file for "Economics:Charge:Simple" objects.
     925              : 
     926              :     static constexpr std::string_view RoutineName("GetInputEconomicsChargeSimple: ");
     927              :     static constexpr std::string_view routineName = "GetInputEconomicsChargeSimple";
     928              :     int NumAlphas; // Number of elements in the alpha array
     929              :     int NumNums;   // Number of elements in the numeric array
     930              :     int IOStat;    // IO Status when calling get input subroutine
     931              :     bool isNotNumeric;
     932              : 
     933            7 :     auto &s_econ = state.dataEconTariff;
     934            7 :     auto &s_ipsc = state.dataIPShortCut;
     935            7 :     s_ipsc->cCurrentModuleObject = "UtilityCost:Charge:Simple";
     936              : 
     937            7 :     s_econ->numChargeSimple = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     938            7 :     s_econ->chargeSimple.allocate(s_econ->numChargeSimple);
     939           15 :     for (int iInObj = 1; iInObj <= s_econ->numChargeSimple; ++iInObj) {
     940            8 :         auto &chargeSimple = s_econ->chargeSimple(iInObj);
     941           16 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     942            8 :                                                                  s_ipsc->cCurrentModuleObject,
     943              :                                                                  iInObj,
     944            8 :                                                                  s_ipsc->cAlphaArgs,
     945              :                                                                  NumAlphas,
     946            8 :                                                                  s_ipsc->rNumericArgs,
     947              :                                                                  NumNums,
     948              :                                                                  IOStat,
     949            8 :                                                                  s_ipsc->lNumericFieldBlanks,
     950            8 :                                                                  s_ipsc->lAlphaFieldBlanks,
     951            8 :                                                                  s_ipsc->cAlphaFieldNames,
     952            8 :                                                                  s_ipsc->cNumericFieldNames);
     953              : 
     954            8 :         ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
     955              : 
     956              :         // check to make sure none of the values are another economic object
     957           56 :         for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
     958           48 :             if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
     959            0 :                 ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     960            0 :                 ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
     961              :             }
     962              :         }
     963              :         // index of the tariff name in the tariff array
     964            8 :         chargeSimple.tariffIndx = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
     965            8 :         warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), chargeSimple.tariffIndx, ErrorsFound, s_ipsc->cCurrentModuleObject);
     966            8 :         chargeSimple.namePt = AssignVariablePt(
     967            8 :             state, s_ipsc->cAlphaArgs(1), true, varIsAssigned, varNotYetDefined, ObjType::ChargeSimple, iInObj, chargeSimple.tariffIndx);
     968              :         // index of the variable in the variable array
     969            8 :         chargeSimple.sourcePt =
     970            8 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(3), true, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, chargeSimple.tariffIndx);
     971              :         // enumerated list of the kind of season
     972            8 :         chargeSimple.season = static_cast<Season>(getEnumValue(seasonNamesUC, s_ipsc->cAlphaArgs(4)));
     973            8 :         if (chargeSimple.season == Season::Invalid) {
     974            0 :             ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4), "Annual");
     975            0 :             chargeSimple.season = Season::Annual;
     976              :         }
     977              : 
     978              :         // check to make sure a seasonal schedule is specified if the season is not annual
     979            8 :         if (chargeSimple.season != Season::Annual) {
     980            7 :             if (chargeSimple.tariffIndx != 0) {
     981            7 :                 if (s_econ->tariff(chargeSimple.tariffIndx).seasonSched == nullptr) {
     982            0 :                     ShowWarningError(state, format("{}{}=\"{}\" invalid data", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     983            0 :                     ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)));
     984            0 :                     ShowContinueError(state,
     985              :                                       " a Season other than Annual is used but no Season Schedule Name is specified in the UtilityCost:Tariff.");
     986              :                 }
     987              :             }
     988              :         }
     989              :         // index of the category in the variable array
     990            8 :         chargeSimple.categoryPt =
     991            8 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(5), true, varIsAssigned, varNotYetDefined, ObjType::Category, iInObj, chargeSimple.tariffIndx);
     992              :         // cost per unit value or variable
     993            8 :         chargeSimple.costPerVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(6), isNotNumeric);
     994            8 :         chargeSimple.costPerPt = AssignVariablePt(
     995            8 :             state, s_ipsc->cAlphaArgs(6), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, chargeSimple.tariffIndx);
     996              :     }
     997            7 : }
     998              : 
     999            7 : void GetInputEconomicsChargeBlock(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
    1000              : {
    1001              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1002              :     //    DATE WRITTEN   May 2004
    1003              : 
    1004              :     //    Read the input file for "Economics:Charge:Block" objects.
    1005              : 
    1006              :     static constexpr std::string_view RoutineName("GetInputEconomicsChargeBlock: ");
    1007              :     static constexpr std::string_view routineName = "GetInputEconomicsChargeBlock";
    1008              : 
    1009              :     int NumAlphas; // Number of elements in the alpha array
    1010              :     int NumNums;   // Number of elements in the numeric array
    1011              :     int IOStat;    // IO Status when calling get input subroutine
    1012              :     bool isNotNumeric;
    1013              :     int alphaOffset;        // offset used in blocks for alpha array
    1014            7 :     Real64 hugeNumber(0.0); // Autodesk Value not used but suppresses warning about HUGE_() call
    1015              : 
    1016            7 :     auto &s_econ = state.dataEconTariff;
    1017            7 :     auto &s_ipsc = state.dataIPShortCut;
    1018            7 :     s_ipsc->cCurrentModuleObject = "UtilityCost:Charge:Block";
    1019              : 
    1020            7 :     hugeNumber = HUGE_(hugeNumber);
    1021            7 :     s_econ->numChargeBlock = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    1022            7 :     s_econ->chargeBlock.allocate(s_econ->numChargeBlock);
    1023            8 :     for (int iInObj = 1; iInObj <= s_econ->numChargeBlock; ++iInObj) {
    1024            1 :         auto &chargeBlock = s_econ->chargeBlock(iInObj);
    1025            2 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1026            1 :                                                                  s_ipsc->cCurrentModuleObject,
    1027              :                                                                  iInObj,
    1028            1 :                                                                  s_ipsc->cAlphaArgs,
    1029              :                                                                  NumAlphas,
    1030            1 :                                                                  s_ipsc->rNumericArgs,
    1031              :                                                                  NumNums,
    1032              :                                                                  IOStat,
    1033            1 :                                                                  s_ipsc->lNumericFieldBlanks,
    1034            1 :                                                                  s_ipsc->lAlphaFieldBlanks,
    1035            1 :                                                                  s_ipsc->cAlphaFieldNames,
    1036            1 :                                                                  s_ipsc->cNumericFieldNames);
    1037              : 
    1038            1 :         ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    1039              : 
    1040              :         // check to make sure none of the values are another economic object
    1041           14 :         for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
    1042           13 :             if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
    1043            0 :                 ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    1044            0 :                 ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
    1045              :             }
    1046              :         }
    1047              :         // index of the tariff name in the tariff array
    1048            1 :         chargeBlock.tariffIndx = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
    1049            1 :         warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), chargeBlock.tariffIndx, ErrorsFound, s_ipsc->cCurrentModuleObject);
    1050            1 :         chargeBlock.namePt = AssignVariablePt(
    1051            1 :             state, s_ipsc->cAlphaArgs(1), true, varIsAssigned, varNotYetDefined, ObjType::ChargeBlock, iInObj, chargeBlock.tariffIndx);
    1052              :         // index of the variable in the variable array
    1053            1 :         chargeBlock.sourcePt =
    1054            1 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(3), true, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, chargeBlock.tariffIndx);
    1055              :         // enumerated list of the kind of season
    1056            1 :         chargeBlock.season = static_cast<Season>(getEnumValue(seasonNamesUC, s_ipsc->cAlphaArgs(4)));
    1057            1 :         if (chargeBlock.season == Season::Invalid) {
    1058            0 :             ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4), "Annual");
    1059            0 :             chargeBlock.season = Season::Annual;
    1060              :         }
    1061              : 
    1062              :         // check to make sure a seasonal schedule is specified if the season is not annual
    1063            1 :         if (chargeBlock.season != Season::Annual) {
    1064            1 :             if (chargeBlock.tariffIndx != 0) {
    1065            1 :                 if (s_econ->tariff(chargeBlock.tariffIndx).seasonSched == nullptr) {
    1066            0 :                     ShowWarningError(state, format("{}{}=\"{}\" invalid data", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    1067            0 :                     ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)));
    1068            0 :                     ShowContinueError(state,
    1069              :                                       " a Season other than Annual is used but no Season Schedule Name is specified in the UtilityCost:Tariff.");
    1070              :                 }
    1071              :             }
    1072              :         }
    1073              :         // index of the category in the variable array
    1074            1 :         chargeBlock.categoryPt =
    1075            1 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(5), true, varIsAssigned, varNotYetDefined, ObjType::Category, iInObj, chargeBlock.tariffIndx);
    1076              :         // index of the remaining into variable in the variable array
    1077            1 :         chargeBlock.remainingPt =
    1078            1 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(6), true, varIsAssigned, varNotYetDefined, ObjType::Category, iInObj, chargeBlock.tariffIndx);
    1079              :         // block size multiplier
    1080            1 :         if (len(s_ipsc->cAlphaArgs(7)) == 0) { // if blank
    1081            1 :             chargeBlock.blkSzMultVal = 1.0;    // default is 1 if left blank
    1082            1 :             chargeBlock.blkSzMultPt = 0;
    1083              :         } else {
    1084            0 :             chargeBlock.blkSzMultVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(7), isNotNumeric);
    1085            0 :             chargeBlock.blkSzMultPt = AssignVariablePt(
    1086            0 :                 state, s_ipsc->cAlphaArgs(7), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, chargeBlock.tariffIndx);
    1087              :         }
    1088              :         // number of blocks used
    1089            1 :         chargeBlock.numBlk = (NumAlphas - 7) / 2;
    1090            4 :         for (int jBlk = 1; jBlk <= chargeBlock.numBlk; ++jBlk) {
    1091            3 :             alphaOffset = 7 + (jBlk - 1) * 2;
    1092              :             // catch the "remaining" code word for the block size
    1093            3 :             if (Util::SameString(s_ipsc->cAlphaArgs(alphaOffset + 1), "REMAINING")) {
    1094            1 :                 chargeBlock.blkSzVal(jBlk) = hugeNumber / 1000000; // using small portion of largest possible value to prevent overflow
    1095            1 :                 chargeBlock.blkSzPt(jBlk) = 0;
    1096              :             } else {
    1097              :                 // array of block size
    1098            2 :                 chargeBlock.blkSzVal(jBlk) = Util::ProcessNumber(s_ipsc->cAlphaArgs(alphaOffset + 1), isNotNumeric);
    1099              : 
    1100            2 :                 chargeBlock.blkSzPt(jBlk) = AssignVariablePt(state,
    1101            2 :                                                              s_ipsc->cAlphaArgs(alphaOffset + 1),
    1102              :                                                              isNotNumeric,
    1103              :                                                              varIsArgument,
    1104              :                                                              varNotYetDefined,
    1105              :                                                              ObjType::Invalid,
    1106              :                                                              0,
    1107              :                                                              chargeBlock.tariffIndx);
    1108              :             }
    1109              :             // array of block cost
    1110            3 :             chargeBlock.blkCostVal(jBlk) = Util::ProcessNumber(s_ipsc->cAlphaArgs(alphaOffset + 2), isNotNumeric);
    1111            3 :             chargeBlock.blkCostPt(jBlk) = AssignVariablePt(state,
    1112            3 :                                                            s_ipsc->cAlphaArgs(alphaOffset + 2),
    1113              :                                                            isNotNumeric,
    1114              :                                                            varIsArgument,
    1115              :                                                            varNotYetDefined,
    1116              :                                                            ObjType::Invalid,
    1117              :                                                            0,
    1118              :                                                            chargeBlock.tariffIndx);
    1119              :         }
    1120              :     }
    1121            7 : }
    1122              : 
    1123            7 : void GetInputEconomicsRatchet(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
    1124              : {
    1125              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1126              :     //    DATE WRITTEN   May 2004
    1127              : 
    1128              :     //    Read the input file for "Economics:Ratchet" objects.
    1129              : 
    1130              :     static constexpr std::string_view RoutineName("GetInputEconomicsRatchet: ");
    1131              :     static constexpr std::string_view routineName = "GetInputEconomicsRatchet";
    1132              : 
    1133              :     int NumAlphas; // Number of elements in the alpha array
    1134              :     int NumNums;   // Number of elements in the numeric array
    1135              :     int IOStat;    // IO Status when calling get input subroutine
    1136              :     bool isNotNumeric;
    1137              : 
    1138            7 :     auto &s_econ = state.dataEconTariff;
    1139            7 :     auto &s_ipsc = state.dataIPShortCut;
    1140            7 :     s_ipsc->cCurrentModuleObject = "UtilityCost:Ratchet";
    1141              : 
    1142            7 :     s_econ->numRatchet = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    1143            7 :     s_econ->ratchet.allocate(s_econ->numRatchet);
    1144            8 :     for (int iInObj = 1; iInObj <= s_econ->numRatchet; ++iInObj) {
    1145            1 :         auto &ratchet = s_econ->ratchet(iInObj);
    1146              : 
    1147            2 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1148            1 :                                                                  s_ipsc->cCurrentModuleObject,
    1149              :                                                                  iInObj,
    1150            1 :                                                                  s_ipsc->cAlphaArgs,
    1151              :                                                                  NumAlphas,
    1152            1 :                                                                  s_ipsc->rNumericArgs,
    1153              :                                                                  NumNums,
    1154              :                                                                  IOStat,
    1155            1 :                                                                  s_ipsc->lNumericFieldBlanks,
    1156            1 :                                                                  s_ipsc->lAlphaFieldBlanks,
    1157            1 :                                                                  s_ipsc->cAlphaFieldNames,
    1158            1 :                                                                  s_ipsc->cNumericFieldNames);
    1159              : 
    1160            1 :         ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    1161              : 
    1162              :         // check to make sure none of the values are another economic object
    1163            9 :         for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
    1164            8 :             if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
    1165            0 :                 ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    1166            0 :                 ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
    1167              :             }
    1168              :         }
    1169              :         // index of the tariff name in the tariff array
    1170            1 :         ratchet.tariffIndx = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
    1171            1 :         warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), ratchet.tariffIndx, ErrorsFound, s_ipsc->cCurrentModuleObject);
    1172            1 :         ratchet.namePt =
    1173            1 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(1), true, varIsAssigned, varNotYetDefined, ObjType::Ratchet, iInObj, ratchet.tariffIndx);
    1174              :         // index of the variable in the variable array
    1175            1 :         ratchet.baselinePt =
    1176            1 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(3), true, varIsArgument, varNotYetDefined, ObjType::Ratchet, iInObj, ratchet.tariffIndx);
    1177              :         // index of the variable in the variable array
    1178            1 :         ratchet.adjustmentPt =
    1179            1 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(4), true, varIsArgument, varNotYetDefined, ObjType::Ratchet, iInObj, ratchet.tariffIndx);
    1180              :         // seasons to and from
    1181            1 :         ratchet.seasonFrom = static_cast<Season>(getEnumValue(seasonNamesUC, s_ipsc->cAlphaArgs(5)));
    1182            1 :         if (ratchet.seasonFrom == Season::Invalid) {
    1183            0 :             ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5), "Annual");
    1184            0 :             ratchet.seasonFrom = Season::Annual;
    1185              :         }
    1186            1 :         ratchet.seasonTo = static_cast<Season>(getEnumValue(seasonNamesUC, s_ipsc->cAlphaArgs(6)));
    1187            1 :         if (ratchet.seasonTo == Season::Invalid) {
    1188            0 :             ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(56), "Annual");
    1189            0 :             ratchet.seasonTo = Season::Annual;
    1190              :         }
    1191              : 
    1192              :         // ratchet multiplier
    1193            1 :         ratchet.multiplierVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(7), isNotNumeric);
    1194            1 :         ratchet.multiplierPt =
    1195            1 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(7), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, ratchet.tariffIndx);
    1196              :         // ratchet offset
    1197            1 :         ratchet.offsetVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(8), isNotNumeric);
    1198            1 :         ratchet.offsetPt =
    1199            1 :             AssignVariablePt(state, s_ipsc->cAlphaArgs(8), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, ratchet.tariffIndx);
    1200              :     }
    1201            7 : }
    1202              : 
    1203           11 : void GetInputEconomicsVariable(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
    1204              : {
    1205              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1206              :     //    DATE WRITTEN   May 2004
    1207              : 
    1208              :     //    Read the input file for "Economics:Variable" objects.
    1209              : 
    1210              :     static constexpr std::string_view RoutineName("GetInputEconomicsVariable: ");
    1211              :     static constexpr std::string_view routineName = "GetInputEconomicsVariable";
    1212              : 
    1213              :     int NumAlphas; // Number of elements in the alpha array
    1214              :     int NumNums;   // Number of elements in the numeric array
    1215              :     int IOStat;    // IO Status when calling get input subroutine
    1216              : 
    1217           11 :     auto &s_econ = state.dataEconTariff;
    1218           11 :     auto &s_ipsc = state.dataIPShortCut;
    1219              : 
    1220           11 :     s_ipsc->cCurrentModuleObject = "UtilityCost:Variable";
    1221           11 :     int numEconVarObj = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    1222           15 :     for (int iInObj = 1; iInObj <= numEconVarObj; ++iInObj) {
    1223            8 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1224            4 :                                                                  s_ipsc->cCurrentModuleObject,
    1225              :                                                                  iInObj,
    1226            4 :                                                                  s_ipsc->cAlphaArgs,
    1227              :                                                                  NumAlphas,
    1228            4 :                                                                  s_ipsc->rNumericArgs,
    1229              :                                                                  NumNums,
    1230              :                                                                  IOStat,
    1231            4 :                                                                  s_ipsc->lNumericFieldBlanks,
    1232            4 :                                                                  s_ipsc->lAlphaFieldBlanks,
    1233            4 :                                                                  s_ipsc->cAlphaFieldNames,
    1234            4 :                                                                  s_ipsc->cNumericFieldNames);
    1235              : 
    1236            4 :         ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
    1237              : 
    1238              :         // check to make sure none of the values are another economic object
    1239           16 :         for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
    1240           12 :             if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
    1241            0 :                 ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    1242            0 :                 ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
    1243              :             }
    1244              :         }
    1245            4 :         int tariffPt = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
    1246            4 :         int variablePt = AssignVariablePt(state, s_ipsc->cAlphaArgs(1), true, varIsArgument, varUserDefined, ObjType::Variable, iInObj, tariffPt);
    1247            4 :         warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), tariffPt, ErrorsFound, s_ipsc->cCurrentModuleObject);
    1248            4 :         auto &econVar = s_econ->econVar(variablePt);
    1249              : 
    1250              :         // validate the kind of variable - not used internally except for validation
    1251            4 :         econVar.varUnitType = static_cast<VarUnitType>(getEnumValue(varUnitTypeNamesUC, s_ipsc->cAlphaArgs(3)));
    1252            4 :         if (econVar.varUnitType == VarUnitType::Invalid) {
    1253            0 :             ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
    1254            0 :             ErrorsFound = true;
    1255            0 :             econVar.varUnitType = VarUnitType::Dimensionless;
    1256              :         }
    1257              : 
    1258              :         // move number inputs into econVar
    1259           52 :         for (int jVal = 1; jVal <= NumNums; ++jVal) {
    1260           48 :             econVar.values(jVal) = s_ipsc->rNumericArgs(jVal);
    1261              :         }
    1262              :         // fill the rest of the array with the last value entered
    1263            4 :         if (NumNums < NumMonths) {
    1264            0 :             for (int jVal = NumNums + 1; jVal <= NumMonths; ++jVal) {
    1265            0 :                 econVar.values(jVal) = s_ipsc->rNumericArgs(NumNums);
    1266              :             }
    1267              :         }
    1268              :     }
    1269           11 : }
    1270              : 
    1271            7 : void GetInputEconomicsComputation(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
    1272              : {
    1273              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1274              :     //    DATE WRITTEN   May 2004
    1275              : 
    1276              :     //    Read the input file for "Economics:Computation" objects.
    1277              :     //    This object is only used for very complex rates.
    1278              : 
    1279              :     static constexpr std::string_view RoutineName("GetInputEconomicsComputation: ");
    1280              : 
    1281              :     int NumAlphas; // Number of elements in the alpha array
    1282              :     int NumNums;   // Number of elements in the numeric array
    1283              :     int IOStat;    // IO Status when calling get input subroutine
    1284              : 
    1285            7 :     auto &s_econ = state.dataEconTariff;
    1286            7 :     auto &s_ipsc = state.dataIPShortCut;
    1287              : 
    1288            7 :     s_ipsc->cCurrentModuleObject = "UtilityCost:Computation";
    1289            7 :     s_econ->numComputation = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    1290            7 :     s_econ->computation.allocate(s_econ->numTariff); // not the number of Computations but the number of tariffs
    1291              :     // set default values for computation
    1292           14 :     for (auto &e : s_econ->computation) {
    1293            7 :         e.computeName.clear();
    1294            7 :         e.firstStep = 0;
    1295            7 :         e.lastStep = -1;
    1296            7 :         e.isUserDef = false;
    1297              :     }
    1298            8 :     for (int iInObj = 1; iInObj <= s_econ->numComputation; ++iInObj) {
    1299            2 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1300            1 :                                                                  s_ipsc->cCurrentModuleObject,
    1301              :                                                                  iInObj,
    1302            1 :                                                                  s_ipsc->cAlphaArgs,
    1303              :                                                                  NumAlphas,
    1304            1 :                                                                  s_ipsc->rNumericArgs,
    1305              :                                                                  NumNums,
    1306              :                                                                  IOStat,
    1307            1 :                                                                  s_ipsc->lNumericFieldBlanks,
    1308            1 :                                                                  s_ipsc->lAlphaFieldBlanks,
    1309            1 :                                                                  s_ipsc->cAlphaFieldNames,
    1310            1 :                                                                  s_ipsc->cNumericFieldNames);
    1311              :         // check to make sure none of the values are another economic object
    1312            9 :         for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
    1313            8 :             if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
    1314            0 :                 ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    1315            0 :                 ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
    1316              :             }
    1317              :         }
    1318            1 :         int tariffPt = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
    1319            1 :         warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), tariffPt, ErrorsFound, s_ipsc->cCurrentModuleObject);
    1320              :         // tariff and computation share the same index, the tariff index
    1321              :         // so all references are to the tariffPt
    1322            1 :         auto &computation = s_econ->computation(tariffPt);
    1323              : 
    1324            1 :         if (isWithinRange(state, tariffPt, 1, s_econ->numTariff)) {
    1325            1 :             computation.computeName = s_ipsc->cAlphaArgs(1);
    1326            1 :             computation.firstStep = s_econ->numSteps + 1;
    1327            7 :             for (int jLine = 3; jLine <= NumAlphas; ++jLine) {
    1328            6 :                 parseComputeLine(state, s_ipsc->cAlphaArgs(jLine), tariffPt);
    1329              :             }
    1330            1 :             computation.lastStep = s_econ->numSteps;
    1331              :             // check to make sure that some steps were defined
    1332            1 :             if (computation.firstStep >= computation.lastStep) {
    1333            0 :                 computation.firstStep = 0;
    1334            0 :                 computation.lastStep = -1;
    1335            0 :                 computation.isUserDef = false;
    1336            0 :                 ShowSevereError(state, format("{}{}=\"{}\" invalid data.", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    1337            0 :                 ShowContinueError(state, "... No lines in the computation can be interpreted ");
    1338            0 :                 ErrorsFound = true;
    1339              :             } else {
    1340            1 :                 computation.isUserDef = true;
    1341              :             }
    1342              :         } else {
    1343            0 :             ShowSevereError(state, format("{}{}=\"{}\" invalid data.", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    1344            0 :             ShowContinueError(state, format("... not found {}=\"{}\".", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
    1345            0 :             ErrorsFound = true;
    1346              :         }
    1347              :     }
    1348            7 : }
    1349              : 
    1350           80 : void GetInputEconomicsCurrencyType(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
    1351              : {
    1352              :     //       AUTHOR         Jason Glazer
    1353              :     //       DATE WRITTEN   August 2008
    1354              : 
    1355              :     //   Sets the type of currency (U.S. Dollar, Euro, Yen, etc.. )
    1356              :     //   This is a "unique" object.
    1357              : 
    1358              :     static constexpr std::string_view RoutineName("GetInputEconomicsCurrencyType: ");
    1359              : 
    1360              :     int NumCurrencyType;
    1361              :     int NumAlphas; // Number of elements in the alpha array
    1362              :     int NumNums;   // Number of elements in the numeric array
    1363              :     int IOStat;    // IO Status when calling get input subroutine
    1364              :     int i;
    1365              : 
    1366           80 :     auto &s_ipsc = state.dataIPShortCut;
    1367           80 :     s_ipsc->cCurrentModuleObject = "CurrencyType";
    1368              : 
    1369           80 :     initializeMonetaryUnit(state);
    1370           80 :     NumCurrencyType = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    1371           80 :     state.dataCostEstimateManager->selectedMonetaryUnit = 0; // invalid
    1372           80 :     if (NumCurrencyType == 0) {
    1373           80 :         state.dataCostEstimateManager->selectedMonetaryUnit = 1; // USD - U.S. Dollar
    1374            0 :     } else if (NumCurrencyType == 1) {
    1375            0 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1376            0 :                                                                  s_ipsc->cCurrentModuleObject,
    1377              :                                                                  1,
    1378            0 :                                                                  s_ipsc->cAlphaArgs,
    1379              :                                                                  NumAlphas,
    1380            0 :                                                                  s_ipsc->rNumericArgs,
    1381              :                                                                  NumNums,
    1382              :                                                                  IOStat,
    1383            0 :                                                                  s_ipsc->lNumericFieldBlanks,
    1384            0 :                                                                  s_ipsc->lAlphaFieldBlanks,
    1385            0 :                                                                  s_ipsc->cAlphaFieldNames,
    1386            0 :                                                                  s_ipsc->cNumericFieldNames);
    1387              :         // Monetary Unit
    1388            0 :         for (i = 1; i <= (int)state.dataCostEstimateManager->monetaryUnit.size(); ++i) {
    1389            0 :             if (Util::SameString(s_ipsc->cAlphaArgs(1), state.dataCostEstimateManager->monetaryUnit(i).code)) {
    1390            0 :                 state.dataCostEstimateManager->selectedMonetaryUnit = i;
    1391            0 :                 break;
    1392              :             }
    1393              :         }
    1394            0 :         if (state.dataCostEstimateManager->selectedMonetaryUnit == 0) {
    1395            0 :             ShowSevereError(state, format("{}{}=\"{}\" invalid data.", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
    1396            0 :             ShowContinueError(state, format("... invalid {}.", s_ipsc->cAlphaFieldNames(1)));
    1397            0 :             ErrorsFound = true;
    1398              :         }
    1399            0 :     } else if (NumCurrencyType > 1) {
    1400            0 :         ShowWarningError(state,
    1401            0 :                          format("{}{} Only one instance of this object is allowed. USD will be used.", RoutineName, s_ipsc->cCurrentModuleObject));
    1402            0 :         state.dataCostEstimateManager->selectedMonetaryUnit = 1; // USD - U.S. Dollar
    1403              :     }
    1404           80 : }
    1405              : 
    1406            6 : void parseComputeLine(EnergyPlusData &state, std::string const &lineOfCompute, int const fromTariff)
    1407              : {
    1408              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1409              :     //    DATE WRITTEN   June 2004
    1410              : 
    1411              :     //   Converts a single line in the ECONOMICS:COMPUTE
    1412              :     //   command into tokens for computation
    1413              : 
    1414              :     //   Scan the line from the end of the line to the front of the
    1415              :     //   line and search for operators and variables. All items
    1416              :     //   are put into the step array.
    1417              : 
    1418            6 :     auto &s_econ = state.dataEconTariff;
    1419              : 
    1420            6 :     std::string word;
    1421              : 
    1422            6 :     size_t endOfWord = len(lineOfCompute) - 1;
    1423           32 :     while (endOfWord != std::string::npos) {
    1424              :         // get a single word (text string delimited by spaces)
    1425           26 :         GetLastWord(lineOfCompute, endOfWord, word);
    1426              :         // first see if word is an operator
    1427           26 :         Op op = static_cast<Op>(getEnumValue(opNamesUC, word));
    1428           26 :         if (op == Op::Invalid) static_cast<Op>(getEnumValue(opNames2UC, word));
    1429              : 
    1430              :         // if not an operator then look for
    1431           26 :         if (op != Op::Invalid) {
    1432            6 :             incrementSteps(state);
    1433            6 :             s_econ->steps(s_econ->numSteps).type = StepType::Op;
    1434            6 :             s_econ->steps(s_econ->numSteps).op = op;
    1435              : 
    1436              :         } else {
    1437              :             int varNum;
    1438              :             // see if argument or assignment (assignment will be first string on line)
    1439           20 :             if (endOfWord != std::string::npos) {
    1440           14 :                 varNum = AssignVariablePt(state, word, true, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, fromTariff);
    1441              :             } else {
    1442            6 :                 varNum = AssignVariablePt(state, word, true, varIsAssigned, varNotYetDefined, ObjType::AssignCompute, 0, fromTariff);
    1443              :             }
    1444              : 
    1445              :             // if a token is found then put it into step array
    1446           20 :             if (varNum == 0) {
    1447            0 :                 ShowWarningError(state, format("In UtilityCost:Computation line: {}", lineOfCompute));
    1448            0 :                 ShowContinueError(state, format("  Do not recognize: {} Will skip.", word));
    1449              :             } else {
    1450           20 :                 incrementSteps(state);
    1451           20 :                 s_econ->steps(s_econ->numSteps).type = StepType::Var;
    1452           20 :                 s_econ->steps(s_econ->numSteps).varNum = varNum;
    1453              :             }
    1454              :         }
    1455              :     }
    1456              : 
    1457            6 :     incrementSteps(state);
    1458            6 :     s_econ->steps(s_econ->numSteps).type = StepType::EOL; // at the end of the line show a zero to clear the stack
    1459            6 : }
    1460              : 
    1461           26 : void GetLastWord(std::string const &lineOfText, std::string::size_type &endOfScan, std::string &aWord)
    1462              : {
    1463              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1464              :     //    DATE WRITTEN   June 2004
    1465              : 
    1466              :     //   Returns the last substring of the line of text to the
    1467              :     //   left of the endOfSubStrg pointer. A substring is
    1468              :     //   delimited by spaces.  Quotes are not significant
    1469              :     //   (they are treated just like any other non-space character)
    1470              : 
    1471              :     //   Scan the string from the end.
    1472              : 
    1473           26 :     size_t curEndOfScan = endOfScan;
    1474           26 :     if (curEndOfScan != std::string::npos) {
    1475           26 :         if (curEndOfScan >= len(lineOfText)) {
    1476            0 :             curEndOfScan = len(lineOfText) - 1;
    1477              :         }
    1478              :         // check if currently on a space or not
    1479              :         bool isInWord;
    1480              :         size_t beginOfWord;
    1481              :         size_t endOfWord;
    1482           26 :         if (lineOfText[curEndOfScan] == ' ') {
    1483           20 :             isInWord = false;
    1484           20 :             beginOfWord = 0;
    1485           20 :             endOfWord = 0;
    1486              :         } else {
    1487            6 :             isInWord = true;
    1488            6 :             beginOfWord = curEndOfScan;
    1489            6 :             endOfWord = curEndOfScan;
    1490              :         }
    1491              :         // scan backwards from
    1492              :         bool isSpace;
    1493          274 :         for (size_t iString = curEndOfScan; iString <= curEndOfScan; --iString) { // Unsigned will wrap to npos after 0
    1494          268 :             if (lineOfText[iString] == ' ') {
    1495           40 :                 isSpace = true;
    1496              :             } else {
    1497          228 :                 isSpace = false;
    1498              :             }
    1499              :             // all logical conditions of isSpace and isInWord
    1500          268 :             if (isSpace) {
    1501           40 :                 if (isInWord) {
    1502              :                     // found the space in front of the word
    1503           20 :                     break;
    1504              :                 } else {
    1505              :                     // still have not found the back of the word
    1506              :                     // do nothing
    1507              :                 }
    1508              :             } else {
    1509          228 :                 if (isInWord) {
    1510              :                     // still have not found the space in front of the word
    1511          208 :                     beginOfWord = iString;
    1512              :                 } else {
    1513              :                     // found the last character of the word
    1514           20 :                     endOfWord = iString;
    1515           20 :                     beginOfWord = iString;
    1516           20 :                     isInWord = true;
    1517              :                 }
    1518              :             }
    1519              :         }
    1520           26 :         aWord = lineOfText.substr(beginOfWord, endOfWord - beginOfWord + 1);
    1521           26 :         endOfScan = beginOfWord - 1;
    1522              :     } else {
    1523            0 :         endOfScan = std::string::npos;
    1524            0 :         aWord = "";
    1525              :     }
    1526           26 : }
    1527              : 
    1528           80 : void initializeMonetaryUnit(EnergyPlusData &state)
    1529              : {
    1530              :     //       AUTHOR         Jason Glazer
    1531              :     //       DATE WRITTEN   August 2008
    1532              : 
    1533              :     //   Sets the type of monetary unit array.
    1534              : 
    1535              :     //   Uses get input structure similar to other objects
    1536              :     //   The monetaryUnitSymbols.xls spreadsheet helps create the code for this routine
    1537              : 
    1538              :     //   www.xe.com/symbols.php
    1539              : 
    1540           80 :     int numMonetaryUnit = 111;
    1541           80 :     state.dataCostEstimateManager->monetaryUnit.allocate(numMonetaryUnit);
    1542           80 :     state.dataCostEstimateManager->monetaryUnit(1).code = "USD";
    1543           80 :     state.dataCostEstimateManager->monetaryUnit(2).code = "AFN";
    1544           80 :     state.dataCostEstimateManager->monetaryUnit(3).code = "ALL";
    1545           80 :     state.dataCostEstimateManager->monetaryUnit(4).code = "ANG";
    1546           80 :     state.dataCostEstimateManager->monetaryUnit(5).code = "ARS";
    1547           80 :     state.dataCostEstimateManager->monetaryUnit(6).code = "AUD";
    1548           80 :     state.dataCostEstimateManager->monetaryUnit(7).code = "AWG";
    1549           80 :     state.dataCostEstimateManager->monetaryUnit(8).code = "AZN";
    1550           80 :     state.dataCostEstimateManager->monetaryUnit(9).code = "BAM";
    1551           80 :     state.dataCostEstimateManager->monetaryUnit(10).code = "BBD";
    1552           80 :     state.dataCostEstimateManager->monetaryUnit(11).code = "BGN";
    1553           80 :     state.dataCostEstimateManager->monetaryUnit(12).code = "BMD";
    1554           80 :     state.dataCostEstimateManager->monetaryUnit(13).code = "BND";
    1555           80 :     state.dataCostEstimateManager->monetaryUnit(14).code = "BOB";
    1556           80 :     state.dataCostEstimateManager->monetaryUnit(15).code = "BRL";
    1557           80 :     state.dataCostEstimateManager->monetaryUnit(16).code = "BSD";
    1558           80 :     state.dataCostEstimateManager->monetaryUnit(17).code = "BWP";
    1559           80 :     state.dataCostEstimateManager->monetaryUnit(18).code = "BYR";
    1560           80 :     state.dataCostEstimateManager->monetaryUnit(19).code = "BZD";
    1561           80 :     state.dataCostEstimateManager->monetaryUnit(20).code = "CAD";
    1562           80 :     state.dataCostEstimateManager->monetaryUnit(21).code = "CHF";
    1563           80 :     state.dataCostEstimateManager->monetaryUnit(22).code = "CLP";
    1564           80 :     state.dataCostEstimateManager->monetaryUnit(23).code = "CNY";
    1565           80 :     state.dataCostEstimateManager->monetaryUnit(24).code = "COP";
    1566           80 :     state.dataCostEstimateManager->monetaryUnit(25).code = "CRC";
    1567           80 :     state.dataCostEstimateManager->monetaryUnit(26).code = "CUP";
    1568           80 :     state.dataCostEstimateManager->monetaryUnit(27).code = "CZK";
    1569           80 :     state.dataCostEstimateManager->monetaryUnit(28).code = "DKK";
    1570           80 :     state.dataCostEstimateManager->monetaryUnit(29).code = "DOP";
    1571           80 :     state.dataCostEstimateManager->monetaryUnit(30).code = "EEK";
    1572           80 :     state.dataCostEstimateManager->monetaryUnit(31).code = "EGP";
    1573           80 :     state.dataCostEstimateManager->monetaryUnit(32).code = "EUR";
    1574           80 :     state.dataCostEstimateManager->monetaryUnit(33).code = "FJD";
    1575           80 :     state.dataCostEstimateManager->monetaryUnit(34).code = "GBP";
    1576           80 :     state.dataCostEstimateManager->monetaryUnit(35).code = "GHC";
    1577           80 :     state.dataCostEstimateManager->monetaryUnit(36).code = "GIP";
    1578           80 :     state.dataCostEstimateManager->monetaryUnit(37).code = "GTQ";
    1579           80 :     state.dataCostEstimateManager->monetaryUnit(38).code = "GYD";
    1580           80 :     state.dataCostEstimateManager->monetaryUnit(39).code = "HKD";
    1581           80 :     state.dataCostEstimateManager->monetaryUnit(40).code = "HNL";
    1582           80 :     state.dataCostEstimateManager->monetaryUnit(41).code = "HRK";
    1583           80 :     state.dataCostEstimateManager->monetaryUnit(42).code = "HUF";
    1584           80 :     state.dataCostEstimateManager->monetaryUnit(43).code = "IDR";
    1585           80 :     state.dataCostEstimateManager->monetaryUnit(44).code = "ILS";
    1586           80 :     state.dataCostEstimateManager->monetaryUnit(45).code = "IMP";
    1587           80 :     state.dataCostEstimateManager->monetaryUnit(46).code = "INR";
    1588           80 :     state.dataCostEstimateManager->monetaryUnit(47).code = "IRR";
    1589           80 :     state.dataCostEstimateManager->monetaryUnit(48).code = "ISK";
    1590           80 :     state.dataCostEstimateManager->monetaryUnit(49).code = "JEP";
    1591           80 :     state.dataCostEstimateManager->monetaryUnit(50).code = "JMD";
    1592           80 :     state.dataCostEstimateManager->monetaryUnit(51).code = "JPY";
    1593           80 :     state.dataCostEstimateManager->monetaryUnit(52).code = "KGS";
    1594           80 :     state.dataCostEstimateManager->monetaryUnit(53).code = "KHR";
    1595           80 :     state.dataCostEstimateManager->monetaryUnit(54).code = "KPW";
    1596           80 :     state.dataCostEstimateManager->monetaryUnit(55).code = "KRW";
    1597           80 :     state.dataCostEstimateManager->monetaryUnit(56).code = "KYD";
    1598           80 :     state.dataCostEstimateManager->monetaryUnit(57).code = "KZT";
    1599           80 :     state.dataCostEstimateManager->monetaryUnit(58).code = "LAK";
    1600           80 :     state.dataCostEstimateManager->monetaryUnit(59).code = "LBP";
    1601           80 :     state.dataCostEstimateManager->monetaryUnit(60).code = "LKR";
    1602           80 :     state.dataCostEstimateManager->monetaryUnit(61).code = "LRD";
    1603           80 :     state.dataCostEstimateManager->monetaryUnit(62).code = "LTL";
    1604           80 :     state.dataCostEstimateManager->monetaryUnit(63).code = "LVL";
    1605           80 :     state.dataCostEstimateManager->monetaryUnit(64).code = "MKD";
    1606           80 :     state.dataCostEstimateManager->monetaryUnit(65).code = "MNT";
    1607           80 :     state.dataCostEstimateManager->monetaryUnit(66).code = "MUR";
    1608           80 :     state.dataCostEstimateManager->monetaryUnit(67).code = "MXN";
    1609           80 :     state.dataCostEstimateManager->monetaryUnit(68).code = "MYR";
    1610           80 :     state.dataCostEstimateManager->monetaryUnit(69).code = "MZN";
    1611           80 :     state.dataCostEstimateManager->monetaryUnit(70).code = "NAD";
    1612           80 :     state.dataCostEstimateManager->monetaryUnit(71).code = "NGN";
    1613           80 :     state.dataCostEstimateManager->monetaryUnit(72).code = "NIO";
    1614           80 :     state.dataCostEstimateManager->monetaryUnit(73).code = "NOK";
    1615           80 :     state.dataCostEstimateManager->monetaryUnit(74).code = "NPR";
    1616           80 :     state.dataCostEstimateManager->monetaryUnit(75).code = "NZD";
    1617           80 :     state.dataCostEstimateManager->monetaryUnit(76).code = "OMR";
    1618           80 :     state.dataCostEstimateManager->monetaryUnit(77).code = "PAB";
    1619           80 :     state.dataCostEstimateManager->monetaryUnit(78).code = "PEN";
    1620           80 :     state.dataCostEstimateManager->monetaryUnit(79).code = "PHP";
    1621           80 :     state.dataCostEstimateManager->monetaryUnit(80).code = "PKR";
    1622           80 :     state.dataCostEstimateManager->monetaryUnit(81).code = "PLN";
    1623           80 :     state.dataCostEstimateManager->monetaryUnit(82).code = "PYG";
    1624           80 :     state.dataCostEstimateManager->monetaryUnit(83).code = "QAR";
    1625           80 :     state.dataCostEstimateManager->monetaryUnit(84).code = "RON";
    1626           80 :     state.dataCostEstimateManager->monetaryUnit(85).code = "RSD";
    1627           80 :     state.dataCostEstimateManager->monetaryUnit(86).code = "RUB";
    1628           80 :     state.dataCostEstimateManager->monetaryUnit(87).code = "SAR";
    1629           80 :     state.dataCostEstimateManager->monetaryUnit(88).code = "SBD";
    1630           80 :     state.dataCostEstimateManager->monetaryUnit(89).code = "SCR";
    1631           80 :     state.dataCostEstimateManager->monetaryUnit(90).code = "SEK";
    1632           80 :     state.dataCostEstimateManager->monetaryUnit(91).code = "SGD";
    1633           80 :     state.dataCostEstimateManager->monetaryUnit(92).code = "SHP";
    1634           80 :     state.dataCostEstimateManager->monetaryUnit(93).code = "SOS";
    1635           80 :     state.dataCostEstimateManager->monetaryUnit(94).code = "SRD";
    1636           80 :     state.dataCostEstimateManager->monetaryUnit(95).code = "SVC";
    1637           80 :     state.dataCostEstimateManager->monetaryUnit(96).code = "SYP";
    1638           80 :     state.dataCostEstimateManager->monetaryUnit(97).code = "THB";
    1639           80 :     state.dataCostEstimateManager->monetaryUnit(98).code = "TRL";
    1640           80 :     state.dataCostEstimateManager->monetaryUnit(99).code = "TRY";
    1641           80 :     state.dataCostEstimateManager->monetaryUnit(100).code = "TTD";
    1642           80 :     state.dataCostEstimateManager->monetaryUnit(101).code = "TVD";
    1643           80 :     state.dataCostEstimateManager->monetaryUnit(102).code = "TWD";
    1644           80 :     state.dataCostEstimateManager->monetaryUnit(103).code = "UAH";
    1645           80 :     state.dataCostEstimateManager->monetaryUnit(104).code = "UYU";
    1646           80 :     state.dataCostEstimateManager->monetaryUnit(105).code = "UZS";
    1647           80 :     state.dataCostEstimateManager->monetaryUnit(106).code = "VEF";
    1648           80 :     state.dataCostEstimateManager->monetaryUnit(107).code = "VND";
    1649           80 :     state.dataCostEstimateManager->monetaryUnit(108).code = "XCD";
    1650           80 :     state.dataCostEstimateManager->monetaryUnit(109).code = "YER";
    1651           80 :     state.dataCostEstimateManager->monetaryUnit(110).code = "ZAR";
    1652           80 :     state.dataCostEstimateManager->monetaryUnit(111).code = "ZWD";
    1653              : 
    1654           80 :     state.dataCostEstimateManager->monetaryUnit(1).txt = "$";
    1655           80 :     state.dataCostEstimateManager->monetaryUnit(2).txt = "AFN";
    1656           80 :     state.dataCostEstimateManager->monetaryUnit(3).txt = "Lek";
    1657           80 :     state.dataCostEstimateManager->monetaryUnit(4).txt = "ANG";
    1658           80 :     state.dataCostEstimateManager->monetaryUnit(5).txt = "$";
    1659           80 :     state.dataCostEstimateManager->monetaryUnit(6).txt = "$";
    1660           80 :     state.dataCostEstimateManager->monetaryUnit(7).txt = "AWG";
    1661           80 :     state.dataCostEstimateManager->monetaryUnit(8).txt = "AZN";
    1662           80 :     state.dataCostEstimateManager->monetaryUnit(9).txt = "KM";
    1663           80 :     state.dataCostEstimateManager->monetaryUnit(10).txt = "$";
    1664           80 :     state.dataCostEstimateManager->monetaryUnit(11).txt = "BGN";
    1665           80 :     state.dataCostEstimateManager->monetaryUnit(12).txt = "$";
    1666           80 :     state.dataCostEstimateManager->monetaryUnit(13).txt = "$";
    1667           80 :     state.dataCostEstimateManager->monetaryUnit(14).txt = "$b";
    1668           80 :     state.dataCostEstimateManager->monetaryUnit(15).txt = "R$";
    1669           80 :     state.dataCostEstimateManager->monetaryUnit(16).txt = "$";
    1670           80 :     state.dataCostEstimateManager->monetaryUnit(17).txt = "P";
    1671           80 :     state.dataCostEstimateManager->monetaryUnit(18).txt = "p.";
    1672           80 :     state.dataCostEstimateManager->monetaryUnit(19).txt = "BZ$";
    1673           80 :     state.dataCostEstimateManager->monetaryUnit(20).txt = "$";
    1674           80 :     state.dataCostEstimateManager->monetaryUnit(21).txt = "CHF";
    1675           80 :     state.dataCostEstimateManager->monetaryUnit(22).txt = "$";
    1676           80 :     state.dataCostEstimateManager->monetaryUnit(23).txt = "CNY";
    1677           80 :     state.dataCostEstimateManager->monetaryUnit(24).txt = "$";
    1678           80 :     state.dataCostEstimateManager->monetaryUnit(25).txt = "CRC";
    1679           80 :     state.dataCostEstimateManager->monetaryUnit(26).txt = "CUP";
    1680           80 :     state.dataCostEstimateManager->monetaryUnit(27).txt = "CZK";
    1681           80 :     state.dataCostEstimateManager->monetaryUnit(28).txt = "kr";
    1682           80 :     state.dataCostEstimateManager->monetaryUnit(29).txt = "RD$";
    1683           80 :     state.dataCostEstimateManager->monetaryUnit(30).txt = "kr";
    1684           80 :     state.dataCostEstimateManager->monetaryUnit(31).txt = "£";
    1685           80 :     state.dataCostEstimateManager->monetaryUnit(32).txt = "EUR";
    1686           80 :     state.dataCostEstimateManager->monetaryUnit(33).txt = "$";
    1687           80 :     state.dataCostEstimateManager->monetaryUnit(34).txt = "£";
    1688           80 :     state.dataCostEstimateManager->monetaryUnit(35).txt = "¢";
    1689           80 :     state.dataCostEstimateManager->monetaryUnit(36).txt = "£";
    1690           80 :     state.dataCostEstimateManager->monetaryUnit(37).txt = "Q";
    1691           80 :     state.dataCostEstimateManager->monetaryUnit(38).txt = "$";
    1692           80 :     state.dataCostEstimateManager->monetaryUnit(39).txt = "HK$";
    1693           80 :     state.dataCostEstimateManager->monetaryUnit(40).txt = "L";
    1694           80 :     state.dataCostEstimateManager->monetaryUnit(41).txt = "kn";
    1695           80 :     state.dataCostEstimateManager->monetaryUnit(42).txt = "Ft";
    1696           80 :     state.dataCostEstimateManager->monetaryUnit(43).txt = "Rp";
    1697           80 :     state.dataCostEstimateManager->monetaryUnit(44).txt = "ILS";
    1698           80 :     state.dataCostEstimateManager->monetaryUnit(45).txt = "£";
    1699           80 :     state.dataCostEstimateManager->monetaryUnit(46).txt = "INR";
    1700           80 :     state.dataCostEstimateManager->monetaryUnit(47).txt = "IRR";
    1701           80 :     state.dataCostEstimateManager->monetaryUnit(48).txt = "kr";
    1702           80 :     state.dataCostEstimateManager->monetaryUnit(49).txt = "£";
    1703           80 :     state.dataCostEstimateManager->monetaryUnit(50).txt = "J$";
    1704           80 :     state.dataCostEstimateManager->monetaryUnit(51).txt = "Â¥";
    1705           80 :     state.dataCostEstimateManager->monetaryUnit(52).txt = "KGS";
    1706           80 :     state.dataCostEstimateManager->monetaryUnit(53).txt = "KHR";
    1707           80 :     state.dataCostEstimateManager->monetaryUnit(54).txt = "KPW";
    1708           80 :     state.dataCostEstimateManager->monetaryUnit(55).txt = "KRW";
    1709           80 :     state.dataCostEstimateManager->monetaryUnit(56).txt = "$";
    1710           80 :     state.dataCostEstimateManager->monetaryUnit(57).txt = "KZT";
    1711           80 :     state.dataCostEstimateManager->monetaryUnit(58).txt = "LAK";
    1712           80 :     state.dataCostEstimateManager->monetaryUnit(59).txt = "£";
    1713           80 :     state.dataCostEstimateManager->monetaryUnit(60).txt = "LKR";
    1714           80 :     state.dataCostEstimateManager->monetaryUnit(61).txt = "$";
    1715           80 :     state.dataCostEstimateManager->monetaryUnit(62).txt = "Lt";
    1716           80 :     state.dataCostEstimateManager->monetaryUnit(63).txt = "Ls";
    1717           80 :     state.dataCostEstimateManager->monetaryUnit(64).txt = "MKD";
    1718           80 :     state.dataCostEstimateManager->monetaryUnit(65).txt = "MNT";
    1719           80 :     state.dataCostEstimateManager->monetaryUnit(66).txt = "MUR";
    1720           80 :     state.dataCostEstimateManager->monetaryUnit(67).txt = "$";
    1721           80 :     state.dataCostEstimateManager->monetaryUnit(68).txt = "RM";
    1722           80 :     state.dataCostEstimateManager->monetaryUnit(69).txt = "MT";
    1723           80 :     state.dataCostEstimateManager->monetaryUnit(70).txt = "$";
    1724           80 :     state.dataCostEstimateManager->monetaryUnit(71).txt = "NGN";
    1725           80 :     state.dataCostEstimateManager->monetaryUnit(72).txt = "C$";
    1726           80 :     state.dataCostEstimateManager->monetaryUnit(73).txt = "kr";
    1727           80 :     state.dataCostEstimateManager->monetaryUnit(74).txt = "NPR";
    1728           80 :     state.dataCostEstimateManager->monetaryUnit(75).txt = "$";
    1729           80 :     state.dataCostEstimateManager->monetaryUnit(76).txt = "OMR";
    1730           80 :     state.dataCostEstimateManager->monetaryUnit(77).txt = "B/.";
    1731           80 :     state.dataCostEstimateManager->monetaryUnit(78).txt = "S/.";
    1732           80 :     state.dataCostEstimateManager->monetaryUnit(79).txt = "Php";
    1733           80 :     state.dataCostEstimateManager->monetaryUnit(80).txt = "PKR";
    1734           80 :     state.dataCostEstimateManager->monetaryUnit(81).txt = "PLN";
    1735           80 :     state.dataCostEstimateManager->monetaryUnit(82).txt = "Gs";
    1736           80 :     state.dataCostEstimateManager->monetaryUnit(83).txt = "QAR";
    1737           80 :     state.dataCostEstimateManager->monetaryUnit(84).txt = "lei";
    1738           80 :     state.dataCostEstimateManager->monetaryUnit(85).txt = "RSD";
    1739           80 :     state.dataCostEstimateManager->monetaryUnit(86).txt = "RUB";
    1740           80 :     state.dataCostEstimateManager->monetaryUnit(87).txt = "SAR";
    1741           80 :     state.dataCostEstimateManager->monetaryUnit(88).txt = "$";
    1742           80 :     state.dataCostEstimateManager->monetaryUnit(89).txt = "SCR";
    1743           80 :     state.dataCostEstimateManager->monetaryUnit(90).txt = "kr";
    1744           80 :     state.dataCostEstimateManager->monetaryUnit(91).txt = "$";
    1745           80 :     state.dataCostEstimateManager->monetaryUnit(92).txt = "£";
    1746           80 :     state.dataCostEstimateManager->monetaryUnit(93).txt = "S";
    1747           80 :     state.dataCostEstimateManager->monetaryUnit(94).txt = "$";
    1748           80 :     state.dataCostEstimateManager->monetaryUnit(95).txt = "$";
    1749           80 :     state.dataCostEstimateManager->monetaryUnit(96).txt = "£";
    1750           80 :     state.dataCostEstimateManager->monetaryUnit(97).txt = "THB";
    1751           80 :     state.dataCostEstimateManager->monetaryUnit(98).txt = "TRL";
    1752           80 :     state.dataCostEstimateManager->monetaryUnit(99).txt = "YTL";
    1753           80 :     state.dataCostEstimateManager->monetaryUnit(100).txt = "TT$";
    1754           80 :     state.dataCostEstimateManager->monetaryUnit(101).txt = "$";
    1755           80 :     state.dataCostEstimateManager->monetaryUnit(102).txt = "NT$";
    1756           80 :     state.dataCostEstimateManager->monetaryUnit(103).txt = "UAH";
    1757           80 :     state.dataCostEstimateManager->monetaryUnit(104).txt = "$U";
    1758           80 :     state.dataCostEstimateManager->monetaryUnit(105).txt = "UZS";
    1759           80 :     state.dataCostEstimateManager->monetaryUnit(106).txt = "Bs";
    1760           80 :     state.dataCostEstimateManager->monetaryUnit(107).txt = "VND";
    1761           80 :     state.dataCostEstimateManager->monetaryUnit(108).txt = "$";
    1762           80 :     state.dataCostEstimateManager->monetaryUnit(109).txt = "YER";
    1763           80 :     state.dataCostEstimateManager->monetaryUnit(110).txt = "R";
    1764           80 :     state.dataCostEstimateManager->monetaryUnit(111).txt = "Z$";
    1765              : 
    1766           80 :     state.dataCostEstimateManager->monetaryUnit(1).html = "$";
    1767           80 :     state.dataCostEstimateManager->monetaryUnit(2).html = "&#x060b;";
    1768           80 :     state.dataCostEstimateManager->monetaryUnit(3).html = "Lek";
    1769           80 :     state.dataCostEstimateManager->monetaryUnit(4).html = "&#x0192;";
    1770           80 :     state.dataCostEstimateManager->monetaryUnit(5).html = "$";
    1771           80 :     state.dataCostEstimateManager->monetaryUnit(6).html = "$";
    1772           80 :     state.dataCostEstimateManager->monetaryUnit(7).html = "&#x0192;";
    1773           80 :     state.dataCostEstimateManager->monetaryUnit(8).html = "&#x043c;&#x0430;&#x043d;";
    1774           80 :     state.dataCostEstimateManager->monetaryUnit(9).html = "KM";
    1775           80 :     state.dataCostEstimateManager->monetaryUnit(10).html = "$";
    1776           80 :     state.dataCostEstimateManager->monetaryUnit(11).html = "&#x043b;&#x0432;";
    1777           80 :     state.dataCostEstimateManager->monetaryUnit(12).html = "$";
    1778           80 :     state.dataCostEstimateManager->monetaryUnit(13).html = "$";
    1779           80 :     state.dataCostEstimateManager->monetaryUnit(14).html = "$b";
    1780           80 :     state.dataCostEstimateManager->monetaryUnit(15).html = "R$";
    1781           80 :     state.dataCostEstimateManager->monetaryUnit(16).html = "$";
    1782           80 :     state.dataCostEstimateManager->monetaryUnit(17).html = "P";
    1783           80 :     state.dataCostEstimateManager->monetaryUnit(18).html = "p.";
    1784           80 :     state.dataCostEstimateManager->monetaryUnit(19).html = "BZ$";
    1785           80 :     state.dataCostEstimateManager->monetaryUnit(20).html = "$";
    1786           80 :     state.dataCostEstimateManager->monetaryUnit(21).html = "CHF";
    1787           80 :     state.dataCostEstimateManager->monetaryUnit(22).html = "$";
    1788           80 :     state.dataCostEstimateManager->monetaryUnit(23).html = "&#x5143;";
    1789           80 :     state.dataCostEstimateManager->monetaryUnit(24).html = "$";
    1790           80 :     state.dataCostEstimateManager->monetaryUnit(25).html = "&#x20a1;";
    1791           80 :     state.dataCostEstimateManager->monetaryUnit(26).html = "&#x20b1;";
    1792           80 :     state.dataCostEstimateManager->monetaryUnit(27).html = "&#x004b;&#x010d;";
    1793           80 :     state.dataCostEstimateManager->monetaryUnit(28).html = "kr";
    1794           80 :     state.dataCostEstimateManager->monetaryUnit(29).html = "RD$";
    1795           80 :     state.dataCostEstimateManager->monetaryUnit(30).html = "kr";
    1796           80 :     state.dataCostEstimateManager->monetaryUnit(31).html = "£";
    1797           80 :     state.dataCostEstimateManager->monetaryUnit(32).html = "&#x20ac;";
    1798           80 :     state.dataCostEstimateManager->monetaryUnit(33).html = "$";
    1799           80 :     state.dataCostEstimateManager->monetaryUnit(34).html = "£";
    1800           80 :     state.dataCostEstimateManager->monetaryUnit(35).html = "¢";
    1801           80 :     state.dataCostEstimateManager->monetaryUnit(36).html = "£";
    1802           80 :     state.dataCostEstimateManager->monetaryUnit(37).html = "Q";
    1803           80 :     state.dataCostEstimateManager->monetaryUnit(38).html = "$";
    1804           80 :     state.dataCostEstimateManager->monetaryUnit(39).html = "HK$";
    1805           80 :     state.dataCostEstimateManager->monetaryUnit(40).html = "L";
    1806           80 :     state.dataCostEstimateManager->monetaryUnit(41).html = "kn";
    1807           80 :     state.dataCostEstimateManager->monetaryUnit(42).html = "Ft";
    1808           80 :     state.dataCostEstimateManager->monetaryUnit(43).html = "Rp";
    1809           80 :     state.dataCostEstimateManager->monetaryUnit(44).html = "&#x20aa;";
    1810           80 :     state.dataCostEstimateManager->monetaryUnit(45).html = "£";
    1811           80 :     state.dataCostEstimateManager->monetaryUnit(46).html = "&#x20a8;";
    1812           80 :     state.dataCostEstimateManager->monetaryUnit(47).html = "&#xfdfc;";
    1813           80 :     state.dataCostEstimateManager->monetaryUnit(48).html = "kr";
    1814           80 :     state.dataCostEstimateManager->monetaryUnit(49).html = "£";
    1815           80 :     state.dataCostEstimateManager->monetaryUnit(50).html = "J$";
    1816           80 :     state.dataCostEstimateManager->monetaryUnit(51).html = "Â¥";
    1817           80 :     state.dataCostEstimateManager->monetaryUnit(52).html = "&#x043b;&#x0432;";
    1818           80 :     state.dataCostEstimateManager->monetaryUnit(53).html = "&#x17db;";
    1819           80 :     state.dataCostEstimateManager->monetaryUnit(54).html = "&#x20a9;";
    1820           80 :     state.dataCostEstimateManager->monetaryUnit(55).html = "&#x20a9;";
    1821           80 :     state.dataCostEstimateManager->monetaryUnit(56).html = "$";
    1822           80 :     state.dataCostEstimateManager->monetaryUnit(57).html = "&#x043b;&#x0432;";
    1823           80 :     state.dataCostEstimateManager->monetaryUnit(58).html = "&#x20ad;";
    1824           80 :     state.dataCostEstimateManager->monetaryUnit(59).html = "£";
    1825           80 :     state.dataCostEstimateManager->monetaryUnit(60).html = "&#x20a8;";
    1826           80 :     state.dataCostEstimateManager->monetaryUnit(61).html = "$";
    1827           80 :     state.dataCostEstimateManager->monetaryUnit(62).html = "Lt";
    1828           80 :     state.dataCostEstimateManager->monetaryUnit(63).html = "Ls";
    1829           80 :     state.dataCostEstimateManager->monetaryUnit(64).html = "&#x0434;&#x0435;&#x043d;";
    1830           80 :     state.dataCostEstimateManager->monetaryUnit(65).html = "&#x20ae;";
    1831           80 :     state.dataCostEstimateManager->monetaryUnit(66).html = "&#x20a8;";
    1832           80 :     state.dataCostEstimateManager->monetaryUnit(67).html = "$";
    1833           80 :     state.dataCostEstimateManager->monetaryUnit(68).html = "RM";
    1834           80 :     state.dataCostEstimateManager->monetaryUnit(69).html = "MT";
    1835           80 :     state.dataCostEstimateManager->monetaryUnit(70).html = "$";
    1836           80 :     state.dataCostEstimateManager->monetaryUnit(71).html = "&#x20a6;";
    1837           80 :     state.dataCostEstimateManager->monetaryUnit(72).html = "C$";
    1838           80 :     state.dataCostEstimateManager->monetaryUnit(73).html = "kr";
    1839           80 :     state.dataCostEstimateManager->monetaryUnit(74).html = "&#x20a8;";
    1840           80 :     state.dataCostEstimateManager->monetaryUnit(75).html = "$";
    1841           80 :     state.dataCostEstimateManager->monetaryUnit(76).html = "&#xfdfc;";
    1842           80 :     state.dataCostEstimateManager->monetaryUnit(77).html = "B/.";
    1843           80 :     state.dataCostEstimateManager->monetaryUnit(78).html = "S/.";
    1844           80 :     state.dataCostEstimateManager->monetaryUnit(79).html = "Php";
    1845           80 :     state.dataCostEstimateManager->monetaryUnit(80).html = "&#x20a8;";
    1846           80 :     state.dataCostEstimateManager->monetaryUnit(81).html = "&#x007a;&#x0142;";
    1847           80 :     state.dataCostEstimateManager->monetaryUnit(82).html = "Gs";
    1848           80 :     state.dataCostEstimateManager->monetaryUnit(83).html = "&#xfdfc;";
    1849           80 :     state.dataCostEstimateManager->monetaryUnit(84).html = "lei";
    1850           80 :     state.dataCostEstimateManager->monetaryUnit(85).html = "&#x0414;&#x0438;&#x043d;&#x002e;";
    1851           80 :     state.dataCostEstimateManager->monetaryUnit(86).html = "&#x0440;&#x0443;&#x0431;";
    1852           80 :     state.dataCostEstimateManager->monetaryUnit(87).html = "&#xfdfc;";
    1853           80 :     state.dataCostEstimateManager->monetaryUnit(88).html = "$";
    1854           80 :     state.dataCostEstimateManager->monetaryUnit(89).html = "&#x20a8;";
    1855           80 :     state.dataCostEstimateManager->monetaryUnit(90).html = "kr";
    1856           80 :     state.dataCostEstimateManager->monetaryUnit(91).html = "$";
    1857           80 :     state.dataCostEstimateManager->monetaryUnit(92).html = "£";
    1858           80 :     state.dataCostEstimateManager->monetaryUnit(93).html = "S";
    1859           80 :     state.dataCostEstimateManager->monetaryUnit(94).html = "$";
    1860           80 :     state.dataCostEstimateManager->monetaryUnit(95).html = "$";
    1861           80 :     state.dataCostEstimateManager->monetaryUnit(96).html = "£";
    1862           80 :     state.dataCostEstimateManager->monetaryUnit(97).html = "&#x0e3f;";
    1863           80 :     state.dataCostEstimateManager->monetaryUnit(98).html = "&#x20a4;";
    1864           80 :     state.dataCostEstimateManager->monetaryUnit(99).html = "YTL";
    1865           80 :     state.dataCostEstimateManager->monetaryUnit(100).html = "TT$";
    1866           80 :     state.dataCostEstimateManager->monetaryUnit(101).html = "$";
    1867           80 :     state.dataCostEstimateManager->monetaryUnit(102).html = "NT$";
    1868           80 :     state.dataCostEstimateManager->monetaryUnit(103).html = "&#x20b4;";
    1869           80 :     state.dataCostEstimateManager->monetaryUnit(104).html = "$U";
    1870           80 :     state.dataCostEstimateManager->monetaryUnit(105).html = "&#x043b;&#x0432;";
    1871           80 :     state.dataCostEstimateManager->monetaryUnit(106).html = "Bs";
    1872           80 :     state.dataCostEstimateManager->monetaryUnit(107).html = "&#x20ab;";
    1873           80 :     state.dataCostEstimateManager->monetaryUnit(108).html = "$";
    1874           80 :     state.dataCostEstimateManager->monetaryUnit(109).html = "&#xfdfc;";
    1875           80 :     state.dataCostEstimateManager->monetaryUnit(110).html = "R";
    1876           80 :     state.dataCostEstimateManager->monetaryUnit(111).html = "Z$";
    1877           80 : }
    1878              : 
    1879           16 : int FindTariffIndex(
    1880              :     EnergyPlusData &state, std::string const &nameOfTariff, std::string const &nameOfReferingObj, bool &ErrorsFound, std::string const &nameOfCurObj)
    1881              : {
    1882              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1883              :     //    DATE WRITTEN   May 2004
    1884              : 
    1885              :     //    Find the index for the tariff string provided or else
    1886              :     //    raise a warning.
    1887              : 
    1888           16 :     auto &s_econ = state.dataEconTariff;
    1889              : 
    1890              :     int FindTariffIndex;
    1891           16 :     int found = 0;
    1892              : 
    1893           16 :     for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    1894           12 :         if (Util::SameString(nameOfTariff, s_econ->tariff(iTariff).tariffName)) {
    1895           12 :             found = iTariff;
    1896           12 :             break;
    1897              :         }
    1898              :     }
    1899           16 :     if (found > 0) {
    1900           12 :         FindTariffIndex = found;
    1901              :     } else {
    1902            4 :         ShowSevereError(state, format("{}=\"{}\" invalid tariff referenced", nameOfCurObj, nameOfReferingObj));
    1903            4 :         ShowContinueError(state, format("not found UtilityCost:Tariff=\"{}\".", nameOfTariff));
    1904            4 :         ErrorsFound = true;
    1905            4 :         FindTariffIndex = 0;
    1906              :     }
    1907           16 :     return FindTariffIndex;
    1908              : }
    1909              : 
    1910           16 : void warnIfNativeVarname(
    1911              :     EnergyPlusData &state, std::string const &objName, int const curTariffIndex, bool &ErrorsFound, std::string const &curobjName)
    1912              : {
    1913              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1914              :     //    DATE WRITTEN   March 2007
    1915              : 
    1916              :     //   Issue a warning if the variable name (usually the object name) is
    1917              :     //   one of the names of native variables
    1918           16 :     auto &s_econ = state.dataEconTariff;
    1919              : 
    1920           16 :     bool throwError = false;
    1921           16 :     if (getEnumValue(nativeNamesUC, objName) != -1)
    1922            0 :         throwError = true;
    1923           16 :     else if (getEnumValue(catNamesUC, objName) != -1)
    1924            0 :         throwError = true;
    1925              : 
    1926           16 :     if (throwError) {
    1927            0 :         ErrorsFound = true;
    1928            0 :         if (curTariffIndex >= 1 && curTariffIndex <= s_econ->numTariff) {
    1929            0 :             ShowSevereError(state, format("UtilityCost:Tariff=\"{}\" invalid referenced name", s_econ->tariff(curTariffIndex).tariffName));
    1930            0 :             ShowContinueError(state, format("{}=\"{}\" You cannot name an object using the same name as a native variable.", curobjName, objName));
    1931              :         } else {
    1932            0 :             ShowSevereError(state, format("{}=\"{}\" You cannot name an object using the same name as a native variable.", curobjName, objName));
    1933              :         }
    1934              :     }
    1935           16 : }
    1936              : 
    1937          416 : int AssignVariablePt(EnergyPlusData &state,
    1938              :                      std::string_view const stringIn,
    1939              :                      bool const flagIfNotNumeric,
    1940              :                      int const useOfVar,
    1941              :                      int const varSpecific,
    1942              :                      ObjType const econObjKind,
    1943              :                      int const objIndex,
    1944              :                      int const tariffPt)
    1945              : {
    1946              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1947              :     //    DATE WRITTEN   May 2004
    1948              : 
    1949              :     //   If the string is not numeric, check if it is a valid string to use as
    1950              :     //   a variable name. Check if name has been used before and if not create
    1951              :     //   the variable using the string as its name.
    1952              :     //   Return the index of the variable.
    1953              : 
    1954          416 :     auto &s_econ = state.dataEconTariff;
    1955              :     int AssignVariablePt;
    1956              : 
    1957          416 :     if (flagIfNotNumeric && (len(stringIn) >= 1)) {
    1958          385 :         std::string inNoSpaces = RemoveSpaces(state, stringIn);
    1959          385 :         int found = 0;
    1960          385 :         if (allocated(s_econ->econVar)) {
    1961         9071 :             for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
    1962         8736 :                 if (s_econ->econVar(iVar).tariffIndx == tariffPt) {
    1963         8736 :                     if (Util::SameString(s_econ->econVar(iVar).name, inNoSpaces)) {
    1964           39 :                         found = iVar;
    1965           39 :                         break;
    1966              :                     }
    1967              :                 }
    1968              :             }
    1969              :         }
    1970          385 :         if (found > 0) {
    1971           39 :             AssignVariablePt = found;
    1972           39 :             if (s_econ->econVar(found).kindOfObj == ObjType::Invalid) {
    1973            0 :                 s_econ->econVar(found).kindOfObj = econObjKind;
    1974            0 :                 if (s_econ->econVar(found).index == 0) s_econ->econVar(found).index = objIndex;
    1975              :             }
    1976              :         } else {
    1977          346 :             incrementEconVar(state);
    1978          346 :             s_econ->econVar(s_econ->numEconVar).name = inNoSpaces;
    1979          346 :             s_econ->econVar(s_econ->numEconVar).kindOfObj = econObjKind;
    1980          346 :             s_econ->econVar(s_econ->numEconVar).index = objIndex;
    1981          346 :             AssignVariablePt = s_econ->numEconVar;
    1982              :         }
    1983              :         // now set the flag for the type of usage the variable has
    1984          385 :         if (useOfVar == varIsArgument) {
    1985          289 :             s_econ->econVar(AssignVariablePt).isArgument = true;
    1986           96 :         } else if (useOfVar == varIsAssigned) {
    1987           96 :             s_econ->econVar(AssignVariablePt).isAssigned = true;
    1988              :         }
    1989          385 :         s_econ->econVar(AssignVariablePt).tariffIndx = tariffPt;
    1990              :         // if the user defines the UtilityCost:Computation then this is called when reading the
    1991              :         // UtilityCost:Tariff with varNotYetDefined but they are already defined because
    1992              :         // the subroutine CreateCategoryNativeVariables has already been called.
    1993              : 
    1994              :         //        if (!((varSpecific == varNotYetDefined) && (econVar(AssignVariablePt).specific >= catEnergyCharges))) {
    1995          437 :         if ((varSpecific != varNotYetDefined) ||
    1996           52 :             (s_econ->econVar(AssignVariablePt).kindOfObj != ObjType::Category && s_econ->econVar(AssignVariablePt).kindOfObj != ObjType::Native)) {
    1997          352 :             s_econ->econVar(AssignVariablePt).specific = varSpecific;
    1998              :         }
    1999          385 :     } else { // if the string was numeric return a zero
    2000           31 :         AssignVariablePt = 0;
    2001              :     }
    2002          416 :     return AssignVariablePt;
    2003              : }
    2004              : 
    2005          346 : void incrementEconVar(EnergyPlusData &state)
    2006              : {
    2007              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    2008              :     //    DATE WRITTEN   May 2004
    2009              : 
    2010              :     //   Increment the Increase the size of the
    2011              : 
    2012          346 :     int constexpr sizeIncrement(100);
    2013          346 :     auto &s_econ = state.dataEconTariff;
    2014              : 
    2015          346 :     if (!allocated(s_econ->econVar)) {
    2016           11 :         s_econ->econVar.allocate(sizeIncrement);
    2017           11 :         s_econ->sizeEconVar = sizeIncrement;
    2018           11 :         s_econ->numEconVar = 1;
    2019              :     } else {
    2020          335 :         ++s_econ->numEconVar;
    2021              :         // if larger than current size grow the array
    2022          335 :         if (s_econ->numEconVar > s_econ->sizeEconVar) {
    2023            0 :             s_econ->econVar.redimension(s_econ->sizeEconVar += sizeIncrement);
    2024              :         }
    2025              :     }
    2026          346 :     auto &econVar = s_econ->econVar(s_econ->numEconVar);
    2027              : 
    2028              :     // initialize new record) //Autodesk Most of these match default initialization so not needed
    2029          346 :     econVar.name = "";
    2030          346 :     econVar.tariffIndx = 0;
    2031          346 :     econVar.kindOfObj = ObjType::Invalid;
    2032          346 :     econVar.index = 0;
    2033          346 :     std::fill(econVar.values.begin(), econVar.values.end(), 0.0);
    2034          346 :     econVar.isArgument = false;
    2035          346 :     econVar.isAssigned = false;
    2036          346 :     econVar.specific = varNotYetDefined;
    2037              :     //        econVar( numEconVar ).values = 0.0; //Autodesk Already initialized above
    2038              :     // Autodesk Don't initialize cntMeDependOn
    2039          346 :     econVar.Operator = Op::Invalid;
    2040          346 :     econVar.firstOperand = 1; // Autodesk Default initialization sets this to 0
    2041          346 :     econVar.lastOperand = 0;
    2042          346 :     econVar.activeNow = false;
    2043          346 :     econVar.isEvaluated = false;
    2044              :     // Autodesk Don't initialize isReported
    2045              :     // Autodesk Don't initialize varUnitType
    2046          346 : }
    2047              : 
    2048          168 : void incrementSteps(EnergyPlusData &state)
    2049              : {
    2050              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    2051              :     //    DATE WRITTEN   June 2004
    2052              : 
    2053              :     //   Increment the step array counter and if
    2054              :     //   necessary increase the size of the array.
    2055              : 
    2056          168 :     auto &s_econ = state.dataEconTariff;
    2057          168 :     int constexpr sizeIncrement(100);
    2058              : 
    2059          168 :     if (!allocated(s_econ->steps)) {
    2060            7 :         s_econ->steps.allocate(sizeIncrement);
    2061            7 :         s_econ->sizeSteps = sizeIncrement;
    2062            7 :         s_econ->numSteps = 1;
    2063              :     } else {
    2064          161 :         ++s_econ->numSteps;
    2065              :         // if larger than current size grow the array
    2066          161 :         if (s_econ->numSteps > s_econ->sizeSteps) {
    2067            0 :             s_econ->steps.redimension(s_econ->sizeSteps += sizeIncrement);
    2068              :         }
    2069              :     }
    2070              :     // initialize new record
    2071          168 :     s_econ->steps(s_econ->numSteps).type = StepType::EOL;
    2072          168 : }
    2073              : 
    2074          385 : std::string RemoveSpaces(EnergyPlusData &state, std::string_view const StringIn)
    2075              : {
    2076              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    2077              :     //    DATE WRITTEN   May 2004
    2078              : 
    2079              :     //   Return the string with all spaces removed.
    2080              : 
    2081          385 :     std::string StringOut;
    2082          385 :     bool foundSpaces = false;
    2083         5884 :     for (std::string::size_type iString = 0; iString < len(StringIn); ++iString) {
    2084         5499 :         if (StringIn[iString] != ' ') {
    2085         5499 :             StringOut += StringIn[iString];
    2086              :         } else {
    2087            0 :             foundSpaces = true;
    2088              :         }
    2089              :     }
    2090          385 :     if (foundSpaces) {
    2091            0 :         ShowWarningError(state, format("UtilityCost: Spaces were removed from the variable=\"{}\".", StringIn));
    2092            0 :         ShowContinueError(state, format("...Resultant variable=\"{}\".", StringOut));
    2093              :     }
    2094          385 :     return StringOut;
    2095            0 : }
    2096              : 
    2097            7 : void CreateCategoryNativeVariables(EnergyPlusData &state)
    2098              : {
    2099              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    2100              :     //    DATE WRITTEN   May 2004
    2101              : 
    2102              :     //    For each tariff create variables that are used for the
    2103              :     //    categories (i.e., EnergyCharges).
    2104              : 
    2105            7 :     auto &s_econ = state.dataEconTariff;
    2106           14 :     for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    2107            7 :         auto &tariff = s_econ->tariff(iTariff);
    2108              : 
    2109              :         // category variables first
    2110           77 :         for (int iCat = 0; iCat < (int)Cat::Num; ++iCat) {
    2111           70 :             tariff.cats[iCat] = AssignVariablePt(state, catNames[iCat], true, varIsAssigned, iCat, ObjType::Category, 0, iTariff);
    2112              :         }
    2113              : 
    2114            7 :         tariff.firstCategory = tariff.cats[(int)Cat::EnergyCharges];
    2115            7 :         tariff.lastCategory = tariff.cats[(int)Cat::NotIncluded];
    2116              : 
    2117              :         // category variables first
    2118              : 
    2119          266 :         for (int iNative = 0; iNative < (int)Native::Num; ++iNative) {
    2120          259 :             tariff.natives[iNative] = AssignVariablePt(state, nativeNames[iNative], true, varIsArgument, iNative, ObjType::Native, 0, iTariff);
    2121              :         }
    2122            7 :         tariff.firstNative = tariff.natives[(int)Native::TotalEnergy];
    2123            7 :         tariff.lastNative = tariff.natives[(int)Native::BelowCustomerBaseEnergy];
    2124              :     }
    2125            7 : }
    2126              : 
    2127              : //======================================================================================================================
    2128              : //======================================================================================================================
    2129              : 
    2130              : //    DEFAULT COMPUTATION RELATED ROUTINES
    2131              : 
    2132              : //======================================================================================================================
    2133              : //======================================================================================================================
    2134              : 
    2135            7 : void CreateDefaultComputation(EnergyPlusData &state)
    2136              : {
    2137              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    2138              :     //    DATE WRITTEN   June 2004
    2139              : 
    2140              :     // PURPOSE OF THIS SUBROUTINE:
    2141              :     //    For most tariffs defined in EnergyPlus no specific
    2142              :     //    ECONOMICS:COMPUTATION will be entered. In that case,
    2143              :     //    a default sequence of computation steps needs to be
    2144              :     //    created.  This routine creates the default
    2145              :     //    computation steps.
    2146              :     //    Object           Fields         Depend On Fields
    2147              :     //    Qualify          namePt         sourcePt
    2148              :     //                                    thresholdPt
    2149              :     //    Charge:Simple    namePt         sourcePt
    2150              :     //                     categoryPt     costPerPt
    2151              :     //    Charge:Block     namePt         sourcePt
    2152              :     //                     categoryPt     blkSzMultPt
    2153              :     //                     remainingPt    blkSzPt
    2154              :     //                                    blkCostPt
    2155              :     //    Ratchet          namePt         baselinePt
    2156              :     //                                    adjustmentPt
    2157              :     //                                    multiplierPt
    2158              :     //                                    offsetPt
    2159              :     //    These will be formed into expressions that look like
    2160              :     //      namePt NOOP sourcePt thresholdPt
    2161              :     //    The different Charges are combined using the SUM operation
    2162              :     //    into categories.
    2163              :     //      category SUM chg1Name chg2Name chg3Name
    2164              :     //    Since the dependency array has one target and multiple
    2165              :     //    parameters, remainingPt is shown as a separate equation that
    2166              :     //    depends on namePt for Charge:Block. The equation will not be
    2167              :     //    displayed or processed except in the sort.
    2168              :     //      remainingPt NOOP namePt
    2169              :     //    Many lines of the computation will include just the name of
    2170              :     //    a single variable which triggers the calculation for that
    2171              :     //    charge, ratchet or qualify.
    2172              :     //      chg1Name
    2173              :     //    It is also possible that two variables referenced within one
    2174              :     //    object could include a dependency relationship also. For
    2175              :     //    example, the blkSzPt could be calculated using the same sourePt
    2176              :     //    in Charge:Block.
    2177              : 
    2178              :     // METHODOLOGY EMPLOYED:
    2179              :     //    Since some ECONOMCIS:* objects depend on other variables
    2180              :     //    first must create the order of when to perform the
    2181              :     //    computations. First a dependency table is created that
    2182              :     //    indicates what variables are dependent on other variables.
    2183              :     //    A directed acyclic graph (DAG) describes the general
    2184              :     //    problem which is usually solved using a topological
    2185              :     //    sorting algorithm.
    2186              :     //    Each line/step is generated and put into the depend
    2187              :     //    array. Also in the array are counts of how many items it
    2188              :     //    depends on and a list of entries that are dependent on that
    2189              :     //    line.
    2190              : 
    2191            7 :     auto &s_econ = state.dataEconTariff;
    2192              : 
    2193              :     // for each tariff that does not have a UtilityCost:Computation object go through the variables
    2194           14 :     for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    2195            7 :         auto &tariff = s_econ->tariff(iTariff);
    2196            7 :         auto &computation = s_econ->computation(iTariff);
    2197            7 :         if (!computation.isUserDef) {
    2198              :             // clear all variables so that they are not active
    2199          293 :             for (int jVar = 1; jVar <= s_econ->numEconVar; ++jVar) {
    2200          287 :                 s_econ->econVar(jVar).activeNow = false;
    2201              :             }
    2202              :             // make all native variables active
    2203          228 :             for (int jVar = tariff.firstNative; jVar <= tariff.lastNative; ++jVar) {
    2204          222 :                 s_econ->econVar(jVar).activeNow = true;
    2205              :             }
    2206              :             //"clear" the dependOn array
    2207            6 :             s_econ->numOperand = 0;
    2208              :             // Define the preset equations (category summation)
    2209            6 :             int curTotal = tariff.cats[(int)Cat::Total];
    2210            6 :             int curSubtotal = tariff.cats[(int)Cat::Subtotal];
    2211            6 :             int curBasis = tariff.cats[(int)Cat::Basis];
    2212              :             // total SUM subtotal taxes
    2213            6 :             s_econ->econVar(curTotal).Operator = Op::SUM;
    2214            6 :             s_econ->econVar(curTotal).activeNow = true;
    2215            6 :             addOperand(state, curTotal, curSubtotal);
    2216            6 :             addOperand(state, curTotal, tariff.cats[(int)Cat::Taxes]);
    2217              :             // subtotal SUM basis adjustments surcharges
    2218            6 :             s_econ->econVar(curSubtotal).Operator = Op::SUM;
    2219            6 :             s_econ->econVar(curSubtotal).activeNow = true;
    2220            6 :             addOperand(state, curSubtotal, curBasis);
    2221            6 :             addOperand(state, curSubtotal, tariff.cats[(int)Cat::Adjustment]);
    2222            6 :             addOperand(state, curSubtotal, tariff.cats[(int)Cat::Surcharge]);
    2223              :             // basis SUM EnergyCharges DemandCharges ServiceCharges
    2224            6 :             s_econ->econVar(curBasis).Operator = Op::SUM;
    2225            6 :             s_econ->econVar(curBasis).activeNow = true;
    2226            6 :             addOperand(state, curBasis, tariff.cats[(int)Cat::EnergyCharges]);
    2227            6 :             addOperand(state, curBasis, tariff.cats[(int)Cat::DemandCharges]);
    2228            6 :             addOperand(state, curBasis, tariff.cats[(int)Cat::ServiceCharges]);
    2229              :             // set up the equations for other objects
    2230            6 :             addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::EnergyCharges]);
    2231            6 :             addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::DemandCharges]);
    2232            6 :             addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::ServiceCharges]);
    2233            6 :             addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::Adjustment]);
    2234            6 :             addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::Surcharge]);
    2235            6 :             addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::Taxes]);
    2236              :             // add the real time pricing to the energy charges
    2237            6 :             if (tariff.chargeSched != nullptr) {
    2238            0 :                 addOperand(state, tariff.cats[(int)Cat::EnergyCharges], tariff.natives[(int)Native::RealTimePriceCosts]);
    2239              :             }
    2240              :             // now add equations with NOOP to represent each object with its
    2241              :             // dependencies
    2242              :             // Qualify
    2243            6 :             for (int kObj = 1; kObj <= s_econ->numQualify; ++kObj) {
    2244            0 :                 auto const &qualify = s_econ->qualify(kObj);
    2245            0 :                 if (qualify.tariffIndx == iTariff) {
    2246            0 :                     int curObject = qualify.namePt;
    2247            0 :                     s_econ->econVar(curObject).Operator = Op::NOOP;
    2248            0 :                     s_econ->econVar(curObject).activeNow = true;
    2249            0 :                     addOperand(state, curObject, qualify.sourcePt);
    2250            0 :                     addOperand(state, curObject, qualify.thresholdPt);
    2251              :                 }
    2252              :             }
    2253              :             // Ratchet
    2254            6 :             for (int kObj = 1; kObj <= s_econ->numRatchet; ++kObj) {
    2255            0 :                 auto const &ratchet = s_econ->ratchet(kObj);
    2256            0 :                 if (ratchet.tariffIndx == iTariff) {
    2257            0 :                     int curObject = ratchet.namePt;
    2258            0 :                     s_econ->econVar(curObject).Operator = Op::NOOP;
    2259            0 :                     s_econ->econVar(curObject).activeNow = true;
    2260            0 :                     addOperand(state, curObject, ratchet.baselinePt);
    2261            0 :                     addOperand(state, curObject, ratchet.adjustmentPt);
    2262            0 :                     addOperand(state, curObject, ratchet.multiplierPt);
    2263            0 :                     addOperand(state, curObject, ratchet.offsetPt);
    2264              :                 }
    2265              :             }
    2266              :             // ChargeSimple
    2267           11 :             for (int kObj = 1; kObj <= s_econ->numChargeSimple; ++kObj) {
    2268            5 :                 auto const &chargeSimple = s_econ->chargeSimple(kObj);
    2269            5 :                 if (chargeSimple.tariffIndx == iTariff) {
    2270            5 :                     int curObject = chargeSimple.namePt;
    2271            5 :                     s_econ->econVar(curObject).Operator = Op::NOOP;
    2272            5 :                     s_econ->econVar(curObject).activeNow = true;
    2273            5 :                     addOperand(state, curObject, chargeSimple.sourcePt);
    2274            5 :                     addOperand(state, curObject, chargeSimple.costPerPt);
    2275              :                 }
    2276              :             }
    2277              :             // ChargeBlock
    2278            6 :             for (int kObj = 1; kObj <= s_econ->numChargeBlock; ++kObj) {
    2279            0 :                 auto const &chargeBlock = s_econ->chargeBlock(kObj);
    2280            0 :                 if (chargeBlock.tariffIndx == iTariff) {
    2281            0 :                     int curObject = chargeBlock.namePt;
    2282            0 :                     s_econ->econVar(curObject).Operator = Op::NOOP;
    2283            0 :                     s_econ->econVar(curObject).activeNow = true;
    2284            0 :                     addOperand(state, curObject, chargeBlock.sourcePt);
    2285            0 :                     addOperand(state, curObject, chargeBlock.blkSzMultPt);
    2286            0 :                     for (int mBlock = 1; mBlock <= chargeBlock.numBlk; ++mBlock) {
    2287            0 :                         addOperand(state, curObject, chargeBlock.blkSzPt(mBlock));
    2288            0 :                         addOperand(state, curObject, chargeBlock.blkCostPt(mBlock));
    2289              :                     }
    2290              :                     // now add a new "equation" for dependency of remainingPt on namePt
    2291            0 :                     int remainPt = chargeBlock.remainingPt;
    2292            0 :                     if (remainPt > 0) {
    2293            0 :                         s_econ->econVar(remainPt).Operator = Op::NOOP;
    2294            0 :                         s_econ->econVar(remainPt).activeNow = true;
    2295            0 :                         addOperand(state, remainPt, curObject);
    2296              :                     }
    2297              :                 }
    2298              :             }
    2299              :             // Economic:Variable
    2300              :             // make all of the user defined variables as active
    2301          293 :             for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
    2302          287 :                 if (s_econ->econVar(iVar).tariffIndx == iTariff) {
    2303          287 :                     if (s_econ->econVar(iVar).kindOfObj == ObjType::Variable) {
    2304            0 :                         s_econ->econVar(iVar).activeNow = true;
    2305              :                     }
    2306              :                 }
    2307              :             }
    2308              :             // make sure no computation is already user defined
    2309            6 :             if (computation.firstStep != 0) {
    2310            0 :                 ShowWarningError(state, format("In UtilityCost:Tariff: Overwriting user defined tariff {}", tariff.tariffName));
    2311              :             }
    2312              :             // initialize the computation
    2313            6 :             computation.computeName = "Autogenerated - " + tariff.tariffName;
    2314            6 :             computation.firstStep = s_econ->numSteps + 1;
    2315            6 :             computation.lastStep = -1; // this will be incremented by addStep
    2316            6 :             computation.isUserDef = false;
    2317              :             // now all "equations" are defined, treat the variables with the list
    2318              :             // of dependencies as a directed acyclic graph and use "count down" algorithm
    2319              :             // to do a topological sort of the variables into the order for computation
    2320              :             // First, clear the counters
    2321          293 :             for (int jVar = 1; jVar <= s_econ->numEconVar; ++jVar) {
    2322          287 :                 s_econ->econVar(jVar).cntMeDependOn = 0;
    2323              :             }
    2324              :             // Second, add up the number of dependencies on each variable
    2325          293 :             for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
    2326          287 :                 if (s_econ->econVar(iVar).activeNow) {
    2327          281 :                     if (s_econ->econVar(iVar).lastOperand >= s_econ->econVar(iVar).firstOperand) {
    2328           26 :                         s_econ->econVar(iVar).cntMeDependOn = 1 + s_econ->econVar(iVar).lastOperand - s_econ->econVar(iVar).firstOperand;
    2329              :                     }
    2330              :                 }
    2331              :             }
    2332              :             // Third, start removing items with zero connections and decrease each
    2333              :             //   counter.
    2334            6 :             int numNoDepend = -1;
    2335            6 :             int loopCount = 0;
    2336           21 :             while ((numNoDepend != 0) || (loopCount > 100000)) {
    2337           15 :                 numNoDepend = 0;
    2338          735 :                 for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
    2339          720 :                     if (s_econ->econVar(iVar).activeNow) {
    2340              :                         // find a variable that has no more dangling dependencies
    2341          293 :                         if (s_econ->econVar(iVar).cntMeDependOn == 0) {
    2342              :                             // If the variable is a native variable then
    2343              :                             // IF (econVar(iVar)%kindOfObj .NE. iEconVarObjType::Native) THEN
    2344          281 :                             if ((s_econ->econVar(iVar).kindOfObj != ObjType::Native) && (s_econ->econVar(iVar).kindOfObj != ObjType::Variable)) {
    2345           59 :                                 if (s_econ->econVar(iVar).lastOperand >= s_econ->econVar(iVar).firstOperand) {
    2346              :                                     // transfer variables and operator to the computation and list of steps
    2347              :                                     // go through the operands backwards (end of line is evaluated first)
    2348           84 :                                     for (int kOperand = s_econ->econVar(iVar).lastOperand; kOperand >= s_econ->econVar(iVar).firstOperand;
    2349              :                                          --kOperand) {
    2350           58 :                                         incrementSteps(state);
    2351           58 :                                         s_econ->steps(s_econ->numSteps) = s_econ->operands(kOperand);
    2352              :                                     }
    2353              :                                     // append the operator (either SUM or NOOP)
    2354           26 :                                     incrementSteps(state);
    2355           26 :                                     s_econ->steps(s_econ->numSteps).type = StepType::Op;
    2356           26 :                                     s_econ->steps(s_econ->numSteps).op = s_econ->econVar(iVar).Operator;
    2357              :                                     // append the variable itself
    2358           26 :                                     incrementSteps(state);
    2359           26 :                                     s_econ->steps(s_econ->numSteps).type = StepType::Var;
    2360           26 :                                     s_econ->steps(s_econ->numSteps).varNum = iVar;
    2361              :                                     // at the end of the line show a zero to clear the stack
    2362           26 :                                     incrementSteps(state);
    2363           26 :                                     s_econ->steps(s_econ->numSteps).type = StepType::EOL;
    2364              :                                 }
    2365              :                             }
    2366              :                             // go through each other variable looking for places where this variable is used
    2367              :                             // and decrement their counters.
    2368        13727 :                             for (int jVar = 1; jVar <= s_econ->numEconVar; ++jVar) {
    2369        13446 :                                 if (s_econ->econVar(jVar).activeNow) {
    2370         8434 :                                     for (int kOperand = s_econ->econVar(jVar).firstOperand; kOperand <= s_econ->econVar(jVar).lastOperand;
    2371              :                                          ++kOperand) {
    2372         1711 :                                         int referVar = s_econ->operands(kOperand).varNum;
    2373         1711 :                                         if (iVar == referVar) {
    2374           58 :                                             --s_econ->econVar(jVar).cntMeDependOn;
    2375              :                                             // for each variable that has been decremented to zero increment the counter
    2376           58 :                                             if (s_econ->econVar(jVar).cntMeDependOn <= 0) {
    2377           26 :                                                 ++numNoDepend;
    2378              :                                             }
    2379              :                                         }
    2380              :                                     }
    2381              :                                 }
    2382              :                             }
    2383              :                             // make the variable inactive
    2384          281 :                             s_econ->econVar(iVar).activeNow = false;
    2385              :                         }
    2386              :                     }
    2387              :                 }
    2388           15 :                 ++loopCount;
    2389              :             }
    2390            6 :             if (loopCount > 100000) {
    2391            0 :                 ShowWarningError(state,
    2392            0 :                                  format("UtilityCost:Tariff: Loop count exceeded when counting dependencies in tariff: {}", tariff.tariffName));
    2393              :             }
    2394              :             // make sure that all variables associated with the tariff are included
    2395            6 :             bool remainingVarFlag = false;
    2396          293 :             for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
    2397          287 :                 if (s_econ->econVar(iVar).activeNow) {
    2398            0 :                     remainingVarFlag = true;
    2399              :                 }
    2400              :             }
    2401            6 :             if (remainingVarFlag) {
    2402            0 :                 ShowWarningError(state,
    2403            0 :                                  format("CreateDefaultComputation: In UtilityCost:Computation: Circular or invalid dependencies found in tariff: {}",
    2404            0 :                                         tariff.tariffName));
    2405            0 :                 ShowContinueError(state, "  UtilityCost variables that may have invalid dependencies and the variables they are dependent on.");
    2406            0 :                 for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
    2407            0 :                     if (s_econ->econVar(iVar).tariffIndx == iTariff) {
    2408            0 :                         if (s_econ->econVar(iVar).activeNow) {
    2409            0 :                             ShowContinueError(state, format("     {}", s_econ->econVar(iVar).name));
    2410            0 :                             for (int kOperand = s_econ->econVar(iVar).firstOperand; kOperand <= s_econ->econVar(iVar).lastOperand; ++kOperand) {
    2411            0 :                                 ShowContinueError(state, format("        ->  {}", s_econ->econVar(s_econ->operands(kOperand).varNum).name));
    2412              :                             }
    2413              :                         }
    2414              :                     }
    2415              :                 }
    2416              :             }
    2417              :             // set the end of the computations
    2418            6 :             computation.lastStep = s_econ->numSteps;
    2419            6 :             if (computation.firstStep >= computation.lastStep) {
    2420            0 :                 computation.firstStep = 0;
    2421            0 :                 computation.lastStep = -1;
    2422            0 :                 ShowWarningError(state,
    2423            0 :                                  format("CreateDefaultComputation: In UtilityCost:Computation: No lines in the auto-generated computation can be "
    2424              :                                         "interpreted in tariff: {}",
    2425            0 :                                         tariff.tariffName));
    2426              :             }
    2427              :         }
    2428              :     }
    2429            7 : }
    2430              : 
    2431           63 : void addOperand(EnergyPlusData &state, int const varMe, int const varOperand)
    2432              : {
    2433              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    2434              :     //    DATE WRITTEN   July 2004
    2435              : 
    2436              :     //   Used by CreateDefaultComputation to create the dependency
    2437              :     //   relationship in the EconVar array
    2438              : 
    2439           63 :     int constexpr sizeIncrement(100);
    2440           63 :     auto &s_econ = state.dataEconTariff;
    2441              : 
    2442           63 :     if (varOperand != 0) {
    2443              :         // increment the numOperand and allocate/reallocate the array
    2444              :         // if necessary
    2445           58 :         if (!allocated(s_econ->operands)) {
    2446            6 :             s_econ->operands.allocate(sizeIncrement);
    2447            6 :             s_econ->sizeOperand = sizeIncrement;
    2448            6 :             s_econ->numOperand = 1;
    2449              :         } else {
    2450           52 :             ++s_econ->numOperand;
    2451              :             // if larger than current size grow the array
    2452           52 :             if (s_econ->numOperand > s_econ->sizeOperand) {
    2453            0 :                 s_econ->operands.redimension(s_econ->sizeOperand += sizeIncrement);
    2454              :             }
    2455              :         }
    2456           58 :         auto &econVar = s_econ->econVar(varMe);
    2457              : 
    2458              :         // now add the dependency relationship
    2459           58 :         s_econ->operands(s_econ->numOperand).type = StepType::Var;
    2460           58 :         s_econ->operands(s_econ->numOperand).varNum = varOperand;
    2461           58 :         econVar.lastOperand = s_econ->numOperand;
    2462              :         // if it is the first time addOperand was called with the varMe value
    2463              :         // then set the first pointer as well
    2464           58 :         if (varMe != s_econ->addOperand_prevVarMe) {
    2465           26 :             econVar.firstOperand = s_econ->numOperand;
    2466           26 :             s_econ->addOperand_prevVarMe = varMe;
    2467              :         }
    2468              :     }
    2469           63 : }
    2470              : 
    2471           36 : void addChargesToOperand(EnergyPlusData &state, int const curTariff, int const curPointer)
    2472              : {
    2473              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    2474              :     //    DATE WRITTEN   July 2004
    2475              : 
    2476              :     //   Used by CreateDefaultComputation to create the "equation"
    2477              :     //   for the categories that are summations of ECONOMICS:CHARGES:BLOCK
    2478              :     //   and ECONOMICS:CHARGES:SIMPLE
    2479              : 
    2480           36 :     auto const &s_econ = state.dataEconTariff;
    2481           36 :     auto const &chargeSimple = s_econ->chargeSimple;
    2482           36 :     auto const &chargeBlock = s_econ->chargeBlock;
    2483              : 
    2484           36 :     s_econ->econVar(curPointer).Operator = Op::SUM;
    2485           36 :     s_econ->econVar(curPointer).activeNow = true;
    2486           66 :     for (int kObj = 1; kObj <= s_econ->numChargeSimple; ++kObj) {
    2487           30 :         if (chargeSimple(kObj).tariffIndx == curTariff) {
    2488           30 :             if (chargeSimple(kObj).categoryPt == curPointer) {
    2489            5 :                 addOperand(state, curPointer, chargeSimple(kObj).namePt);
    2490              :             }
    2491              :         }
    2492              :     }
    2493           36 :     for (int kObj = 1; kObj <= s_econ->numChargeBlock; ++kObj) {
    2494            0 :         if (chargeBlock(kObj).tariffIndx == curTariff) {
    2495            0 :             if (chargeBlock(kObj).categoryPt == curPointer) {
    2496            0 :                 addOperand(state, curPointer, chargeBlock(kObj).namePt);
    2497              :             }
    2498              :         }
    2499              :     }
    2500           36 : }
    2501              : 
    2502              : //======================================================================================================================
    2503              : //======================================================================================================================
    2504              : 
    2505              : //    GATHER TIMESTEP VALUES ROUTINE
    2506              : 
    2507              : //======================================================================================================================
    2508              : //======================================================================================================================
    2509              : 
    2510            4 : void GatherForEconomics(EnergyPlusData &state)
    2511              : {
    2512              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    2513              :     //    DATE WRITTEN   June 2004
    2514              : 
    2515              :     //   Gathers the data each timestep and updates the arrays
    2516              :     //   holding the data that will be used by the tariff
    2517              :     //   calculation.
    2518              : 
    2519              :     Real64 curInstantValue;
    2520              :     Real64 curDemand;
    2521              :     Real64 curEnergy;
    2522              :     Real64 curRTPprice;    // real time price
    2523              :     Real64 curRTPbaseline; // real time price customer baseline load
    2524              :     Real64 curRTPenergy;   // energy applied to real time price
    2525              :     Real64 curRTPcost;     // cost for energy for current time
    2526              : 
    2527            4 :     auto &s_econ = state.dataEconTariff;
    2528              : 
    2529            4 :     if (s_econ->numTariff >= 1) {
    2530            8 :         for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    2531            4 :             auto &tariff = s_econ->tariff(iTariff);
    2532              :             // if the meter is defined get the value
    2533            4 :             if (tariff.reportMeterIndx != -1) {
    2534            1 :                 curInstantValue = GetCurrentMeterValue(state, tariff.reportMeterIndx);
    2535              :             } else {
    2536            3 :                 curInstantValue = 0.0;
    2537              :             }
    2538              :             // remember the demand is still energy over a period of time divided by the
    2539              :             // length of time. This gathers the energy also.
    2540            4 :             tariff.collectEnergy += curInstantValue;
    2541            4 :             tariff.collectTime += state.dataGlobal->TimeStepZoneSec;
    2542              :             // added *SecInHour when adding RTP support August 2008
    2543            4 :             if (tariff.collectTime >= tariff.demWinTime * Constant::rSecsInHour) {
    2544              :                 // get current value that has been converted into desired units
    2545            4 :                 curDemand = tariff.demandConv * tariff.collectEnergy / tariff.collectTime;
    2546            4 :                 curEnergy = tariff.energyConv * tariff.collectEnergy;
    2547              :                 // get the schedule values
    2548              :                 // remember no confirmation of schedule values occurs prior to now
    2549              :                 // The season schedule
    2550            4 :                 Season curSeason = (tariff.seasonSched != nullptr) ? static_cast<Season>(tariff.seasonSched->getCurrentVal()) : Season::Winter;
    2551            4 :                 int curPeriod = (tariff.periodSched != nullptr) ? tariff.periodSched->getCurrentVal() : 1;
    2552              : 
    2553              :                 int curMonth =
    2554            0 :                     (tariff.monthSched != nullptr) ? tariff.monthSched->getCurrentVal() :
    2555              :                                                    // #7814 - Have to be careful with DST. tariff::seasonForMonth is overwritten at each timestep, and
    2556              :                                                    // only the last value is retained, so make sure to capture the right one
    2557            7 :                         (((state.dataGlobal->HourOfDay + state.dataEnvrn->DSTIndicator) <= Constant::iHoursInDay) ? state.dataEnvrn->Month
    2558           11 :                                                                                                                   : state.dataEnvrn->MonthTomorrow);
    2559              : 
    2560            4 :                 bool isGood = false;
    2561            4 :                 if (curSeason == Season::Winter || curSeason == Season::Spring || curSeason == Season::Summer || curSeason == Season::Fall ||
    2562              :                     curSeason == Season::Annual) {
    2563            4 :                     if (isWithinRange(state, curPeriod, 1, 4)) {
    2564            4 :                         if (isWithinRange(state, curMonth, 1, 12)) {
    2565            4 :                             isGood = true;
    2566              :                         }
    2567              :                     }
    2568              :                 }
    2569            4 :                 if (isGood) {
    2570            4 :                     tariff.seasonForMonth(curMonth) = curSeason;
    2571            4 :                     tariff.gatherEnergy(curMonth)[(int)curPeriod] += curEnergy;
    2572            4 :                     if (tariff.gatherDemand(curMonth)[(int)curPeriod] < curDemand) {
    2573            0 :                         tariff.gatherDemand(curMonth)[(int)curPeriod] = curDemand;
    2574              :                     }
    2575              :                 } else {
    2576            0 :                     ShowWarningError(state, format("UtilityCost:Tariff: While gathering for: {}", tariff.tariffName));
    2577            0 :                     ShowContinueError(state, "Invalid schedule values - outside of range");
    2578              :                 }
    2579              :                 // Real Time Pricing
    2580            4 :                 if (tariff.chargeSched != nullptr) {
    2581            0 :                     curRTPprice = tariff.chargeSched->getCurrentVal();
    2582              :                     // if customer baseline load schedule is used, subtract that off of the
    2583              :                     // current energy
    2584            0 :                     if (tariff.baseUseSched != nullptr) {
    2585            0 :                         curRTPbaseline = tariff.baseUseSched->getCurrentVal();
    2586            0 :                         curRTPenergy = curEnergy - curRTPbaseline;
    2587              :                     } else {
    2588            0 :                         curRTPenergy = curEnergy;
    2589              :                     }
    2590              :                     // calculate the real time cost for current times energy
    2591            0 :                     curRTPcost = curRTPenergy * curRTPprice;
    2592            0 :                     tariff.RTPcost(curMonth) += curRTPcost;
    2593            0 :                     if (curRTPcost > 0) {
    2594            0 :                         tariff.RTPaboveBaseCost(curMonth) += curRTPcost;
    2595              :                     } else {
    2596            0 :                         tariff.RTPbelowBaseCost(curMonth) += curRTPcost;
    2597              :                     }
    2598            0 :                     if (curRTPenergy > 0) {
    2599            0 :                         tariff.RTPaboveBaseEnergy(curMonth) += curRTPenergy;
    2600              :                     } else {
    2601            0 :                         tariff.RTPbelowBaseEnergy(curMonth) += curRTPenergy;
    2602              :                     }
    2603              :                 }
    2604              :                 // reset the counters
    2605            4 :                 tariff.collectEnergy = 0.0;
    2606            4 :                 tariff.collectTime = 0.0;
    2607              :             }
    2608              :         }
    2609              :     }
    2610            4 : }
    2611              : 
    2612            9 : bool isWithinRange(EnergyPlusData &state, int const testVal, int const minThreshold, int const maxThreshold)
    2613              : {
    2614              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    2615              :     //    DATE WRITTEN   July 2004
    2616              : 
    2617              :     //   Simple function to check if an integer is equal to or between
    2618              :     //   two other values.
    2619              : 
    2620              :     bool isWithinRange;
    2621              : 
    2622            9 :     if (maxThreshold < minThreshold) {
    2623            0 :         ShowWarningError(state, "UtilityCost: Invalid thresholds in IsWithinRange routine.");
    2624              :     }
    2625            9 :     if ((testVal <= maxThreshold) && (testVal >= minThreshold)) {
    2626            9 :         isWithinRange = true;
    2627              :     } else {
    2628            0 :         isWithinRange = false;
    2629              :     }
    2630            9 :     return isWithinRange;
    2631              : }
    2632              : 
    2633              : //======================================================================================================================
    2634              : //======================================================================================================================
    2635              : 
    2636              : //    COMPUTE THE UTILITY BILLS AND CREATE REPORTS
    2637              : 
    2638              : //======================================================================================================================
    2639              : //======================================================================================================================
    2640              : 
    2641           73 : void ComputeTariff(EnergyPlusData &state)
    2642              : {
    2643              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    2644              :     //    DATE WRITTEN   July 2004
    2645              : 
    2646              :     //    Perform the calculation steps to compute the monthly
    2647              :     //    utility bills for the user entered tariffs.
    2648              :     //    The list of steps for the tariff computation are in order
    2649              :     //    for stack based computation (reverse polish notation)
    2650              : 
    2651           73 :     auto &s_econ = state.dataEconTariff;
    2652              : 
    2653              :     // values used in specific operations
    2654           73 :     Array1D<Real64> a(NumMonths);
    2655           73 :     Array1D<Real64> b(NumMonths);
    2656           73 :     Array1D<Real64> c(NumMonths);
    2657           73 :     Array1D<Real64> d(NumMonths);
    2658              : 
    2659           73 :     int constexpr noVar(0);
    2660              : 
    2661              :     Real64 annualAggregate;
    2662              : 
    2663           73 :     if (!state.files.outputControl.writeTabular(state)) {
    2664            0 :         state.dataOutRptTab->WriteTabularFiles = false;
    2665            0 :         return;
    2666              :     }
    2667              : 
    2668           73 :     Real64 hugeValue = HUGE_(Real64());
    2669              :     //  Clear the isEvaluated flags for all economics variables.
    2670           73 :     for (int nVar = 1; nVar <= s_econ->numEconVar; ++nVar) {
    2671            0 :         s_econ->econVar(nVar).isEvaluated = false;
    2672              :     }
    2673              : 
    2674           73 :     if (s_econ->numTariff == 0) return;
    2675              : 
    2676            0 :     state.dataOutRptTab->WriteTabularFiles = true;
    2677            0 :     setNativeVariables(state);
    2678              :     int aPt;
    2679              :     int bPt;
    2680              :     int cPt;
    2681            0 :     for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    2682            0 :         for (int jStep = s_econ->computation(iTariff).firstStep; jStep <= s_econ->computation(iTariff).lastStep; ++jStep) {
    2683            0 :             auto const &step = s_econ->steps(jStep);
    2684            0 :             int annualCnt = 0;
    2685              : 
    2686              :             // end of line - assign variable and clear stack
    2687              :             // if the stack still has two items on it then assign the values to the
    2688              :             // pointer otherwise if it follows a NOOP line it will only have one item
    2689              :             // that has already been assigned and no further action is required.
    2690            0 :             if (step.type == StepType::EOL) {
    2691            0 :                 if (s_econ->topOfStack >= 2) {
    2692            0 :                     popStack(state, b, bPt); // pop the variable pointer
    2693            0 :                     popStack(state, a, aPt); // pop the values
    2694            0 :                     if (isWithinRange(state, bPt, 1, s_econ->numEconVar)) {
    2695            0 :                         s_econ->econVar(bPt).values = a;
    2696              :                     }
    2697              :                 }
    2698            0 :                 s_econ->topOfStack = 0;
    2699              : 
    2700              :                 // Variable
    2701            0 :             } else if (step.type == StepType::Var) {
    2702            0 :                 pushStack(state, s_econ->econVar(step.varNum).values, step.varNum);
    2703              : 
    2704              :                 // Operator
    2705            0 :             } else if (step.type == StepType::Op) {
    2706            0 :                 switch (step.op) {
    2707              : 
    2708            0 :                 case Op::SUM: {
    2709            0 :                     a = 0.0;
    2710            0 :                     for (int kStack = 1, kStack_end = s_econ->topOfStack; kStack <= kStack_end; ++kStack) { // popStack modifies topOfStack
    2711            0 :                         popStack(state, b, bPt);
    2712            0 :                         a += b;
    2713              :                     }
    2714            0 :                     pushStack(state, a, noVar);
    2715            0 :                 } break;
    2716              : 
    2717            0 :                 case Op::MULTIPLY: {
    2718            0 :                     popStack(state, b, bPt);
    2719            0 :                     popStack(state, a, aPt);
    2720            0 :                     pushStack(state, a * b, noVar);
    2721            0 :                 } break;
    2722              : 
    2723            0 :                 case Op::SUBTRACT: {
    2724            0 :                     popStack(state, b, bPt);
    2725            0 :                     popStack(state, a, aPt);
    2726            0 :                     pushStack(state, b - a, noVar);
    2727            0 :                 } break;
    2728              : 
    2729            0 :                 case Op::DIVIDE: {
    2730            0 :                     popStack(state, a, aPt);
    2731            0 :                     popStack(state, b, bPt);
    2732            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2733            0 :                         c(lMonth) = (b(lMonth) != 0.0) ? (a(lMonth) / b(lMonth)) : 0.0;
    2734              :                     }
    2735            0 :                     pushStack(state, c, noVar);
    2736            0 :                 } break;
    2737              : 
    2738            0 :                 case Op::ABSOLUTEVALUE: {
    2739            0 :                     popStack(state, a, aPt);
    2740            0 :                     pushStack(state, ObjexxFCL::abs(a), noVar);
    2741            0 :                 } break;
    2742              : 
    2743            0 :                 case Op::INTEGER: {
    2744            0 :                     popStack(state, a, aPt);
    2745            0 :                     pushStack(state, Array1D_double(Array1D_int(a)), noVar);
    2746            0 :                 } break;
    2747              : 
    2748            0 :                 case Op::SIGN: {
    2749            0 :                     popStack(state, a, aPt);
    2750            0 :                     pushStack(state, sign(1.0, a), noVar);
    2751              :                     //        CASE (opROUND)
    2752              :                     //          CALL popStack(b,bPt)
    2753              :                     //          CALL popStack(a,aPt)
    2754              :                     //          DO lMonth = 1,MaxNumMonths
    2755              :                     //            IF ((b(lMonth) .LE. 5) .AND. (b(lMonth) .GE. -5)) THEN
    2756              :                     //              c(lMonth) = FLOAT(INT(a(lMonth) / (10 ** b(lMonth))) * (10 ** b(lMonth)))
    2757              :                     //            END IF
    2758              :                     //          END DO
    2759              :                     //          CALL pushStack(c,noVar)
    2760            0 :                 } break;
    2761              : 
    2762            0 :                 case Op::MAXIMUM: {
    2763            0 :                     a = -hugeValue;
    2764            0 :                     for (int kStack = 1, kStack_end = s_econ->topOfStack; kStack <= kStack_end; ++kStack) { // popStack modifies topOfStack
    2765            0 :                         popStack(state, b, bPt);
    2766            0 :                         for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2767            0 :                             if (b(lMonth) > a(lMonth)) {
    2768            0 :                                 a(lMonth) = b(lMonth);
    2769              :                             }
    2770              :                         }
    2771              :                     }
    2772            0 :                     pushStack(state, a, noVar);
    2773            0 :                 } break;
    2774              : 
    2775            0 :                 case Op::MINIMUM: {
    2776            0 :                     a = hugeValue;
    2777            0 :                     for (int kStack = 1, kStack_end = s_econ->topOfStack; kStack <= kStack_end; ++kStack) { // popStack modifies topOfStack
    2778            0 :                         popStack(state, b, bPt);
    2779            0 :                         for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2780            0 :                             if (b(lMonth) < a(lMonth)) {
    2781            0 :                                 a(lMonth) = b(lMonth);
    2782              :                             }
    2783              :                         }
    2784              :                     }
    2785            0 :                     pushStack(state, a, noVar);
    2786            0 :                 } break;
    2787              : 
    2788            0 :                 case Op::EXCEEDS: {
    2789            0 :                     popStack(state, b, bPt);
    2790            0 :                     popStack(state, a, aPt);
    2791            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2792            0 :                         if (a(lMonth) > b(lMonth)) {
    2793            0 :                             c(lMonth) = a(lMonth) - b(lMonth);
    2794              :                         } else {
    2795            0 :                             c(lMonth) = 0.0;
    2796              :                         }
    2797              :                     }
    2798            0 :                     pushStack(state, c, noVar);
    2799            0 :                 } break;
    2800              : 
    2801            0 :                 case Op::ANNUALMINIMUM: {
    2802              :                     // takes the minimum but ignores zeros
    2803            0 :                     annualAggregate = hugeValue;
    2804            0 :                     popStack(state, a, aPt);
    2805            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2806            0 :                         if (a(lMonth) != 0) {
    2807            0 :                             if (a(lMonth) < annualAggregate) {
    2808            0 :                                 annualAggregate = a(lMonth);
    2809              :                             }
    2810              :                         }
    2811              :                     }
    2812              :                     // if all months are zero then hugeValue still in annual but should be zero
    2813            0 :                     if (annualAggregate == hugeValue) {
    2814            0 :                         annualAggregate = 0.0;
    2815              :                     }
    2816            0 :                     c = annualAggregate;
    2817            0 :                     pushStack(state, c, noVar);
    2818            0 :                 } break;
    2819              : 
    2820            0 :                 case Op::ANNUALMAXIMUM: {
    2821              :                     // takes the maximum but ignores zeros
    2822            0 :                     annualAggregate = -hugeValue;
    2823            0 :                     popStack(state, a, aPt);
    2824            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2825            0 :                         if (a(lMonth) != 0) {
    2826            0 :                             if (a(lMonth) > annualAggregate) {
    2827            0 :                                 annualAggregate = a(lMonth);
    2828              :                             }
    2829              :                         }
    2830              :                     }
    2831              :                     // if all months are zero then hugeValue still in annual but should be zero
    2832            0 :                     if (annualAggregate == -hugeValue) {
    2833            0 :                         annualAggregate = 0.0;
    2834              :                     }
    2835            0 :                     c = annualAggregate;
    2836            0 :                     pushStack(state, c, noVar);
    2837            0 :                 } break;
    2838              : 
    2839            0 :                 case Op::ANNUALSUM: {
    2840              :                     // takes the maximum but ignores zeros
    2841            0 :                     annualAggregate = 0.0;
    2842            0 :                     popStack(state, a, aPt);
    2843            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2844            0 :                         annualAggregate += a(lMonth);
    2845              :                     }
    2846            0 :                     c = annualAggregate;
    2847            0 :                     pushStack(state, c, noVar);
    2848            0 :                 } break;
    2849              : 
    2850            0 :                 case Op::ANNUALAVERAGE: {
    2851              :                     // takes the annual sum but ignores zeros
    2852            0 :                     annualAggregate = 0.0;
    2853            0 :                     popStack(state, a, aPt);
    2854            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2855            0 :                         if (a(lMonth) != 0) {
    2856            0 :                             annualAggregate += a(lMonth);
    2857            0 :                             ++annualCnt;
    2858              :                         }
    2859              :                     }
    2860              :                     // if all months are zero then return zero
    2861            0 :                     c = (annualCnt != 0) ? (annualAggregate / annualCnt) : 0.0;
    2862            0 :                     pushStack(state, c, noVar);
    2863            0 :                 } break;
    2864              : 
    2865            0 :                 case Op::ANNUALOR: {
    2866            0 :                     popStack(state, a, aPt);
    2867            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2868            0 :                         if (a(lMonth) != 0) {
    2869            0 :                             ++annualCnt;
    2870              :                         }
    2871              :                     }
    2872              :                     // if any months is not zero then "true"
    2873            0 :                     c = (annualCnt >= 1) ? 1.0 : 0.0;
    2874            0 :                     pushStack(state, c, noVar);
    2875            0 :                 } break;
    2876              : 
    2877            0 :                 case Op::ANNUALAND: {
    2878            0 :                     popStack(state, a, aPt);
    2879            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2880            0 :                         if (a(lMonth) != 0) {
    2881            0 :                             ++annualCnt;
    2882              :                         }
    2883              :                     }
    2884              :                     // if all months are not zero then "true"
    2885            0 :                     c = (annualCnt == NumMonths) ? 1.0 : 0.0;
    2886            0 :                     pushStack(state, c, noVar);
    2887            0 :                 } break;
    2888              : 
    2889            0 :                 case Op::ANNUALMAXIMUMZERO: {
    2890              :                     // takes the maximum including zeros
    2891            0 :                     annualAggregate = -hugeValue;
    2892            0 :                     popStack(state, a, aPt);
    2893            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2894            0 :                         if (a(lMonth) > annualAggregate) {
    2895            0 :                             annualAggregate = a(lMonth);
    2896              :                         }
    2897              :                     }
    2898            0 :                     c = annualAggregate;
    2899            0 :                     pushStack(state, c, noVar);
    2900            0 :                 } break;
    2901              : 
    2902            0 :                 case Op::ANNUALMINIMUMZERO: {
    2903              :                     // takes the maximum including zeros
    2904            0 :                     annualAggregate = hugeValue;
    2905            0 :                     popStack(state, a, aPt);
    2906            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2907            0 :                         if (a(lMonth) < annualAggregate) {
    2908            0 :                             annualAggregate = a(lMonth);
    2909              :                         }
    2910              :                     }
    2911            0 :                     c = annualAggregate;
    2912            0 :                     pushStack(state, c, noVar);
    2913            0 :                 } break;
    2914              : 
    2915            0 :                 case Op::IF: {
    2916            0 :                     popStack(state, c, cPt);
    2917            0 :                     popStack(state, b, bPt);
    2918            0 :                     popStack(state, a, aPt);
    2919            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2920            0 :                         d(lMonth) = (a(lMonth) != 0) ? b(lMonth) : c(lMonth);
    2921              :                     }
    2922            0 :                     pushStack(state, d, noVar);
    2923            0 :                 } break;
    2924              : 
    2925            0 :                 case Op::GREATERTHAN: {
    2926            0 :                     popStack(state, b, bPt);
    2927            0 :                     popStack(state, a, aPt);
    2928            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2929            0 :                         c(lMonth) = (a(lMonth) > b(lMonth)) ? 1.0 : 0.0;
    2930              :                     }
    2931            0 :                     pushStack(state, c, noVar);
    2932            0 :                 } break;
    2933              : 
    2934            0 :                 case Op::GREATEREQUAL: {
    2935            0 :                     popStack(state, b, bPt);
    2936            0 :                     popStack(state, a, aPt);
    2937            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2938            0 :                         if (a(lMonth) >= b(lMonth)) {
    2939            0 :                             c(lMonth) = 1.0;
    2940              :                         } else {
    2941            0 :                             c(lMonth) = 0.0;
    2942              :                         }
    2943              :                     }
    2944            0 :                     pushStack(state, c, noVar);
    2945            0 :                 } break;
    2946              : 
    2947            0 :                 case Op::LESSTHAN: {
    2948            0 :                     popStack(state, b, bPt);
    2949            0 :                     popStack(state, a, aPt);
    2950            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2951            0 :                         c(lMonth) = (a(lMonth) < b(lMonth)) ? 1.0 : 0.0;
    2952              :                     }
    2953            0 :                     pushStack(state, c, noVar);
    2954            0 :                 } break;
    2955              : 
    2956            0 :                 case Op::LESSEQUAL: {
    2957            0 :                     popStack(state, b, bPt);
    2958            0 :                     popStack(state, a, aPt);
    2959            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2960            0 :                         c(lMonth) = (a(lMonth) <= b(lMonth)) ? 1.0 : 0.0;
    2961              :                     }
    2962            0 :                     pushStack(state, c, noVar);
    2963            0 :                 } break;
    2964              : 
    2965            0 :                 case Op::EQUAL: {
    2966            0 :                     popStack(state, b, bPt);
    2967            0 :                     popStack(state, a, aPt);
    2968            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2969            0 :                         c(lMonth) = (a(lMonth) == b(lMonth)) ? 1.0 : 0.0;
    2970              :                     }
    2971            0 :                     pushStack(state, c, noVar);
    2972            0 :                 } break;
    2973              : 
    2974            0 :                 case Op::NOTEQUAL: {
    2975            0 :                     popStack(state, b, bPt);
    2976            0 :                     popStack(state, a, aPt);
    2977            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2978            0 :                         c(lMonth) = (a(lMonth) != b(lMonth)) ? 1.0 : 0.0;
    2979              :                     }
    2980            0 :                     pushStack(state, c, noVar);
    2981            0 :                 } break;
    2982              : 
    2983            0 :                 case Op::AND: {
    2984            0 :                     popStack(state, b, bPt);
    2985            0 :                     popStack(state, a, aPt);
    2986            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2987            0 :                         c(lMonth) = ((a(lMonth) != 0) && (b(lMonth) != 0)) ? 1.0 : 0.0;
    2988              :                     }
    2989            0 :                     pushStack(state, c, noVar);
    2990            0 :                 } break;
    2991              : 
    2992            0 :                 case Op::OR: {
    2993            0 :                     popStack(state, b, bPt);
    2994            0 :                     popStack(state, a, aPt);
    2995            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    2996            0 :                         c(lMonth) = ((a(lMonth) != 0) || (b(lMonth) != 0)) ? 1.0 : 0.0;
    2997              :                     }
    2998            0 :                     pushStack(state, c, noVar);
    2999            0 :                 } break;
    3000              : 
    3001            0 :                 case Op::NOT: {
    3002            0 :                     popStack(state, a, aPt);
    3003            0 :                     for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
    3004            0 :                         c(lMonth) = (a(lMonth) == 0) ? 1.0 : 0.0;
    3005              :                     }
    3006            0 :                     pushStack(state, c, noVar);
    3007            0 :                 } break;
    3008              : 
    3009            0 :                 case Op::ADD: {
    3010            0 :                     popStack(state, b, bPt);
    3011            0 :                     popStack(state, a, aPt);
    3012            0 :                     pushStack(state, a + b, noVar);
    3013            0 :                 } break;
    3014              : 
    3015            0 :                 case Op::NOOP: {
    3016              :                     // do nothing but clear the stack
    3017            0 :                     s_econ->topOfStack = 0;
    3018              :                     // No longer pushing a zero to fix bug
    3019              :                     // and push zero
    3020              :                     // a = 0
    3021            0 :                 } break;
    3022              : 
    3023            0 :                 default: {
    3024            0 :                 } break;
    3025              :                 }
    3026              :             }
    3027              :         }
    3028            0 :         checkMinimumMonthlyCharge(state, iTariff);
    3029              :     }
    3030            0 :     selectTariff(state);
    3031            0 :     LEEDtariffReporting(state);
    3032          292 : }
    3033              : 
    3034            3 : void pushStack(EnergyPlusData &state, Array1A<Real64> const monthlyArray, int const variablePointer)
    3035              : {
    3036              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    3037              :     //    DATE WRITTEN   July 2004
    3038              : 
    3039              :     //    A stack is used in the evaluation of the tariff since
    3040              :     //    the variables and operators are in a reverse polish
    3041              :     //    notation order. The stack operates on a last-in
    3042              :     //    first out basis. The stack consists of both a pointer
    3043              :     //    to the variable and the twelve monthly values.
    3044              :     //    This routine puts an item on the top of the stack.
    3045              : 
    3046            3 :     monthlyArray.dim(NumMonths);
    3047              : 
    3048            3 :     Array1D<Real64> curMonthlyArray(NumMonths);
    3049            3 :     int constexpr sizeIncrement(50);
    3050              : 
    3051            3 :     auto &s_econ = state.dataEconTariff;
    3052            3 :     auto &stack = s_econ->stack;
    3053            3 :     auto const &econVar = s_econ->econVar;
    3054            3 :     auto const &tariff = s_econ->tariff;
    3055              : 
    3056            3 :     curMonthlyArray = monthlyArray;
    3057            3 :     if (!allocated(stack)) {
    3058            1 :         stack.allocate(sizeIncrement);
    3059            1 :         s_econ->sizeStack = sizeIncrement;
    3060            1 :         s_econ->topOfStack = 1;
    3061              :     } else {
    3062            2 :         ++s_econ->topOfStack;
    3063              :         // if larger than current size grow the array
    3064            2 :         if (s_econ->topOfStack > s_econ->sizeStack) {
    3065            0 :             stack.redimension(s_econ->sizeStack += sizeIncrement);
    3066              :         }
    3067              :     }
    3068              :     // now push the values on to the stack
    3069            3 :     stack(s_econ->topOfStack).varPt = variablePointer;
    3070              :     // check if variable has been evaluated if it is CHARGE:SIMPLE, CHARGE:BLOCK, RATCHET, or QUALIFY
    3071              :     // if it has not overwrite the values for monthlyArray with the evaluated values
    3072            3 :     if (variablePointer != 0) {
    3073            1 :         if (!econVar(variablePointer).isEvaluated) {
    3074              : 
    3075            1 :             switch (econVar(variablePointer).kindOfObj) {
    3076            0 :             case ObjType::ChargeSimple:
    3077            0 :                 evaluateChargeSimple(state, variablePointer);
    3078            0 :                 break;
    3079            0 :             case ObjType::ChargeBlock:
    3080            0 :                 evaluateChargeBlock(state, variablePointer);
    3081            0 :                 break;
    3082            0 :             case ObjType::Ratchet:
    3083            0 :                 evaluateRatchet(state, variablePointer);
    3084            0 :                 break;
    3085            0 :             case ObjType::Qualify:
    3086            0 :                 evaluateQualify(state, variablePointer);
    3087            0 :                 break;
    3088            0 :             case ObjType::Invalid:
    3089            0 :                 ShowWarningError(state, format("UtilityCost variable not defined: {}", econVar(variablePointer).name));
    3090            0 :                 ShowContinueError(state, format("   In tariff: {}", tariff(econVar(variablePointer).tariffIndx).tariffName));
    3091            0 :                 ShowContinueError(state, "   This may be the result of a misspelled variable name in the UtilityCost:Computation object.");
    3092            0 :                 ShowContinueError(state, "   All zero values will be assumed for this variable.");
    3093            0 :                 break;
    3094            1 :             case ObjType::Variable:
    3095              :             case ObjType::Category:
    3096              :             case ObjType::Native:
    3097              :             case ObjType::AssignCompute:
    3098              :             case ObjType::Tariff:
    3099              :             case ObjType::Computation:
    3100              :                 // do nothing
    3101            1 :                 break;
    3102            0 :             default:
    3103            0 :                 ShowWarningError(state,
    3104            0 :                                  format("UtilityCost Debugging issue. Invalid kind of variable used (pushStack). {} in tariff: {}",
    3105            0 :                                         econVar(variablePointer).kindOfObj,
    3106            0 :                                         tariff(econVar(variablePointer).tariffIndx).tariffName));
    3107              :             }
    3108              :             // if the serviceCharges are being evaluated add in the monthly charges
    3109            1 :             if (econVar(variablePointer).kindOfObj == ObjType::Category && econVar(variablePointer).specific == (int)Cat::ServiceCharges)
    3110            0 :                 addMonthlyCharge(state, variablePointer);
    3111              :             // get the results of performing the evaluation - should have been
    3112              :             // put into the econVar values
    3113            1 :             curMonthlyArray = econVar(variablePointer).values;
    3114              :         }
    3115              :     }
    3116              :     // now assign
    3117            3 :     stack(s_econ->topOfStack).values = curMonthlyArray;
    3118            3 : }
    3119              : 
    3120            3 : void popStack(EnergyPlusData &state, Array1A<Real64> monthlyArray, int &variablePointer)
    3121              : {
    3122              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    3123              :     //    DATE WRITTEN   July 2004
    3124              : 
    3125              :     //    A stack is used in the evaluation of the tariff since
    3126              :     //    the variables and operators are in a reverse polish
    3127              :     //    notation order. The stack operates on a last-in
    3128              :     //    first out basis. The stack consists of both a pointer
    3129              :     //    to the variable and the twelve monthly values.
    3130              :     //    This routine returns the item on the top of the stack
    3131              :     //    and removes it from the stack.
    3132              : 
    3133            3 :     monthlyArray.dim(NumMonths);
    3134              : 
    3135            3 :     auto &s_econ = state.dataEconTariff;
    3136            3 :     auto const &stack = s_econ->stack;
    3137              : 
    3138            3 :     if (s_econ->topOfStack >= 1) {
    3139            3 :         variablePointer = stack(s_econ->topOfStack).varPt;
    3140            3 :         monthlyArray = stack(s_econ->topOfStack).values;
    3141              :     } else {
    3142            0 :         ShowWarningError(
    3143              :             state,
    3144            0 :             format("UtilityCost:Tariff: stack underflow in calculation of utility bills. On variable: {}", s_econ->econVar(variablePointer).name));
    3145            0 :         variablePointer = 0;
    3146            0 :         monthlyArray = {0.0};
    3147            0 :         s_econ->topOfStack = 0;
    3148              :     }
    3149            3 :     --s_econ->topOfStack;
    3150            3 : }
    3151              : 
    3152            3 : void evaluateChargeSimple(EnergyPlusData &state, int const usingVariable)
    3153              : {
    3154              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    3155              :     //    DATE WRITTEN   July 2004
    3156              : 
    3157            3 :     Array1D<Real64> sourceVals(NumMonths);
    3158            3 :     Array1D<Real64> costPer(NumMonths);
    3159            3 :     Array1D<Real64> resultChg(NumMonths);
    3160            3 :     Array1D<Real64> seasonMask(NumMonths);
    3161              : 
    3162            3 :     auto &s_econ = state.dataEconTariff;
    3163            3 :     int curTariff = s_econ->econVar(usingVariable).tariffIndx;
    3164            3 :     auto const &tariff = s_econ->tariff(curTariff);
    3165            3 :     int indexInChg = s_econ->econVar(usingVariable).index;
    3166            3 :     auto const &chargeSimple = s_econ->chargeSimple(indexInChg);
    3167              : 
    3168              :     // check the tariff - make sure they match
    3169            3 :     if (chargeSimple.namePt != usingVariable) {
    3170            0 :         ShowWarningError(state, "UtilityCost:Tariff Debugging issue. ChargeSimple index does not match variable pointer.");
    3171            0 :         ShowContinueError(state, format("   Between: {}", s_econ->econVar(usingVariable).name));
    3172            0 :         ShowContinueError(state, format("       And: {}", s_econ->econVar(chargeSimple.namePt).name));
    3173              :     }
    3174            3 :     if (chargeSimple.tariffIndx != curTariff) {
    3175            0 :         ShowWarningError(state, "UtilityCost:Tariff Debugging issue. ChargeSimple index does not match tariff index.");
    3176            0 :         ShowContinueError(state, format("   Between: {}", tariff.tariffName));
    3177            0 :         ShowContinueError(state, format("       And: {}", s_econ->tariff(chargeSimple.tariffIndx).tariffName));
    3178              :     }
    3179              :     // data from the Charge:Simple
    3180            3 :     sourceVals = s_econ->econVar(chargeSimple.sourcePt).values;
    3181              :     // determine if costPer should be based on variable or value
    3182            3 :     if (chargeSimple.costPerPt != 0) {
    3183            1 :         costPer = s_econ->econVar(chargeSimple.costPerPt).values;
    3184              :     } else {
    3185            2 :         costPer = chargeSimple.costPerVal;
    3186              :     }
    3187              :     // find proper season mask
    3188            3 :     if (chargeSimple.season == Season::Summer) {
    3189            1 :         seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
    3190            2 :     } else if (chargeSimple.season == Season::Winter) {
    3191            0 :         seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
    3192            2 :     } else if (chargeSimple.season == Season::Spring) {
    3193            0 :         seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
    3194            2 :     } else if (chargeSimple.season == Season::Fall) {
    3195            0 :         seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
    3196            2 :     } else if (chargeSimple.season == Season::Annual) {
    3197            2 :         seasonMask = 1.0; // all months are 1
    3198              :     }
    3199              : 
    3200              :     // finally perform calculations
    3201            3 :     resultChg = sourceVals * costPer * seasonMask;
    3202              :     // store the cost in the name of the variable
    3203            3 :     s_econ->econVar(usingVariable).values = resultChg;
    3204              :     // set the flag that it has been evaluated so it won't be evaluated multiple times
    3205            3 :     s_econ->econVar(usingVariable).isEvaluated = true;
    3206            3 : }
    3207              : 
    3208            1 : void evaluateChargeBlock(EnergyPlusData &state, int const usingVariable)
    3209              : {
    3210              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    3211              :     //    DATE WRITTEN   July 2004
    3212              : 
    3213            1 :     Array1D<Real64> sourceVals(NumMonths);
    3214            1 :     Array1D<Real64> blkSzMult(NumMonths);
    3215            1 :     Array1D<Real64> remainVals(NumMonths);
    3216            1 :     Array1D<Real64> resultChg(NumMonths);
    3217            1 :     Array1D<Real64> amountForBlk(NumMonths);
    3218            1 :     Array1D<Real64> curBlkSz(NumMonths);
    3219            1 :     Array1D<Real64> curBlkCost(NumMonths);
    3220            1 :     Array1D<Real64> seasonMask(NumMonths);
    3221              : 
    3222            1 :     auto &s_econ = state.dataEconTariff;
    3223            1 :     int curTariff = s_econ->econVar(usingVariable).tariffIndx;
    3224            1 :     auto const &tariff = s_econ->tariff(curTariff);
    3225            1 :     int indexInChg = s_econ->econVar(usingVariable).index;
    3226            1 :     auto const &chargeBlock = s_econ->chargeBlock(indexInChg);
    3227              : 
    3228              :     // check the tariff - make sure they match
    3229            1 :     if (chargeBlock.namePt != usingVariable) {
    3230            0 :         ShowWarningError(state, "UtilityCost:Tariff Debugging issue. chargeBlock index does not match variable pointer.");
    3231            0 :         ShowContinueError(state, format("   Between: {}", s_econ->econVar(usingVariable).name));
    3232            0 :         ShowContinueError(state, format("       And: {}", s_econ->econVar(chargeBlock.namePt).name));
    3233              :     }
    3234            1 :     if (chargeBlock.tariffIndx != curTariff) {
    3235            0 :         ShowWarningError(state, "UtilityCost:Tariff Debugging issue. chargeBlock index does not match tariff index.");
    3236            0 :         ShowContinueError(state, format("   Between: {}", tariff.tariffName));
    3237            0 :         ShowContinueError(state, format("       And: {}", s_econ->tariff(chargeBlock.tariffIndx).tariffName));
    3238              :     }
    3239              :     // data from the chargeBlock
    3240            1 :     sourceVals = s_econ->econVar(chargeBlock.sourcePt).values;
    3241              :     // find proper season mask
    3242              : 
    3243            1 :     if (chargeBlock.season == Season::Summer) {
    3244            0 :         seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
    3245            1 :     } else if (chargeBlock.season == Season::Winter) {
    3246            0 :         seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
    3247            1 :     } else if (chargeBlock.season == Season::Spring) {
    3248            0 :         seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
    3249            1 :     } else if (chargeBlock.season == Season::Fall) {
    3250            0 :         seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
    3251            1 :     } else if (chargeBlock.season == Season::Annual) {
    3252            1 :         seasonMask = 1.0; // all months are 1
    3253              :     }
    3254              :     // get block size multiplier
    3255            1 :     if (chargeBlock.blkSzMultPt != 0) {
    3256            0 :         blkSzMult = s_econ->econVar(chargeBlock.blkSzMultPt).values;
    3257              :     } else {
    3258            1 :         blkSzMult = chargeBlock.blkSzMultVal;
    3259              :     }
    3260              :     // initially set the remaining energy or demand to the source
    3261            1 :     remainVals = sourceVals;
    3262              :     // initially set the result (cost) to zero
    3263            1 :     resultChg = 0.0;
    3264              :     // loop through the blocks performing calculations
    3265            4 :     for (int iBlk = 1; iBlk <= chargeBlock.numBlk; ++iBlk) {
    3266            3 :         if (chargeBlock.blkSzPt(iBlk) != 0) {
    3267            0 :             curBlkSz = s_econ->econVar(chargeBlock.blkSzPt(iBlk)).values;
    3268              :         } else {
    3269            3 :             curBlkSz = chargeBlock.blkSzVal(iBlk);
    3270              :         }
    3271            3 :         if (chargeBlock.blkCostPt(iBlk) != 0) {
    3272            0 :             curBlkCost = s_econ->econVar(chargeBlock.blkCostPt(iBlk)).values;
    3273              :         } else {
    3274            3 :             curBlkCost = chargeBlock.blkCostVal(iBlk);
    3275              :         }
    3276              :         // loop through the months
    3277           39 :         for (int jMonth = 1; jMonth <= NumMonths; ++jMonth) {
    3278           36 :             if (seasonMask(jMonth) == 1) {
    3279              :                 // IF ((curBlkSz(jMonth) * blkSzMult(jMonth)) .GT. remainVals(jMonth)) THEN - CR 6547
    3280           36 :                 if (blkSzMult(jMonth) != 0) {
    3281           36 :                     if (curBlkSz(jMonth) > (remainVals(jMonth) / blkSzMult(jMonth))) {
    3282           21 :                         amountForBlk(jMonth) = remainVals(jMonth);
    3283              :                     } else {
    3284           15 :                         amountForBlk(jMonth) = curBlkSz(jMonth) * blkSzMult(jMonth);
    3285              :                     }
    3286              :                 } else {
    3287            0 :                     amountForBlk(jMonth) = 0.0;
    3288              :                 }
    3289           36 :                 resultChg(jMonth) += amountForBlk(jMonth) * curBlkCost(jMonth);
    3290           36 :                 remainVals(jMonth) -= amountForBlk(jMonth);
    3291              :             }
    3292              :         }
    3293              :     }
    3294              :     // store the amount remaining if a variable is specified
    3295            1 :     if (chargeBlock.remainingPt != 0) {
    3296            0 :         s_econ->econVar(chargeBlock.remainingPt).values = remainVals;
    3297              :     } else {
    3298            1 :         bool flagAllZero = true;
    3299           13 :         for (int jMonth = 1; jMonth <= NumMonths; ++jMonth) {
    3300           12 :             if (seasonMask(jMonth) == 1) {
    3301           12 :                 if (remainVals(jMonth) != 0) {
    3302            0 :                     flagAllZero = false;
    3303              :                 }
    3304              :             }
    3305              :         }
    3306            1 :         if (!flagAllZero) {
    3307            0 :             ShowWarningError(
    3308              :                 state,
    3309            0 :                 format("UtilityCost:Tariff Not all energy or demand was assigned in the block charge: {}", s_econ->econVar(usingVariable).name));
    3310              :         }
    3311              :     }
    3312              :     // store the cost in the name of the variable
    3313            1 :     s_econ->econVar(usingVariable).values = resultChg;
    3314              :     // set the flag that it has been evaluated so it won't be evaluated multiple times
    3315            1 :     s_econ->econVar(usingVariable).isEvaluated = true;
    3316            1 : }
    3317              : 
    3318            0 : void evaluateRatchet(EnergyPlusData &state, int const usingVariable)
    3319              : {
    3320              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    3321              :     //    DATE WRITTEN   July 2004
    3322              : 
    3323            0 :     Array1D<Real64> baselineVals(NumMonths);
    3324            0 :     Array1D<Real64> adjustmentVals(NumMonths);
    3325            0 :     Array1D<Real64> multiplierVals(NumMonths);
    3326            0 :     Array1D<Real64> offsetVals(NumMonths);
    3327            0 :     Array1D<Real64> seasonFromMask(NumMonths);
    3328            0 :     Array1D<Real64> seasonToMask(NumMonths);
    3329            0 :     Array1D<Real64> adjSeasonal(NumMonths);
    3330            0 :     Array1D<Real64> adjPeak(NumMonths);
    3331            0 :     Array1D<Real64> maxAdjBase(NumMonths);
    3332            0 :     Array1D<Real64> finalResult(NumMonths);
    3333              : 
    3334            0 :     auto &s_econ = state.dataEconTariff;
    3335            0 :     int curTariff = s_econ->econVar(usingVariable).tariffIndx;
    3336            0 :     auto const &tariff = s_econ->tariff(curTariff);
    3337            0 :     int indexInChg = s_econ->econVar(usingVariable).index;
    3338            0 :     auto const &ratchet = s_econ->ratchet(indexInChg);
    3339            0 :     bool isMonthly = false;
    3340              : 
    3341              :     // check the tariff - make sure they match
    3342            0 :     if (ratchet.namePt != usingVariable) {
    3343            0 :         ShowWarningError(state, "UtilityCost:Tariff Debugging issue. Ratchet index does not match variable pointer.");
    3344            0 :         ShowContinueError(state, format("   Between: {}", s_econ->econVar(usingVariable).name));
    3345            0 :         ShowContinueError(state, format("       And: {}", s_econ->econVar(ratchet.namePt).name));
    3346              :     }
    3347            0 :     if (ratchet.tariffIndx != curTariff) {
    3348            0 :         ShowWarningError(state, "UtilityCost:Tariff Debugging issue. Ratchet index does not match tariff index.");
    3349            0 :         ShowContinueError(state, format("   Between: {}", tariff.tariffName));
    3350            0 :         ShowContinueError(state, format("       And: {}", s_econ->tariff(ratchet.tariffIndx).tariffName));
    3351              :     }
    3352              :     // data from the Ratchet
    3353            0 :     baselineVals = s_econ->econVar(ratchet.baselinePt).values;
    3354            0 :     adjustmentVals = s_econ->econVar(ratchet.adjustmentPt).values;
    3355              :     // determine if multiplier should be based on variable or value
    3356            0 :     if (ratchet.multiplierPt != 0) {
    3357            0 :         multiplierVals = s_econ->econVar(ratchet.multiplierPt).values;
    3358              :     } else {
    3359            0 :         multiplierVals = ratchet.multiplierVal;
    3360              :     }
    3361              :     // determine if offset should be based on variable or value
    3362            0 :     if (ratchet.offsetPt != 0) {
    3363            0 :         offsetVals = s_econ->econVar(ratchet.offsetPt).values;
    3364              :     } else {
    3365            0 :         offsetVals = ratchet.offsetVal;
    3366              :     }
    3367              :     // find proper season from mask
    3368            0 :     if (ratchet.seasonFrom == Season::Summer) {
    3369            0 :         seasonFromMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
    3370            0 :         isMonthly = false;
    3371            0 :     } else if (ratchet.seasonFrom == Season::Winter) {
    3372            0 :         seasonFromMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
    3373            0 :         isMonthly = false;
    3374            0 :     } else if (ratchet.seasonFrom == Season::Spring) {
    3375            0 :         seasonFromMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
    3376            0 :         isMonthly = false;
    3377            0 :     } else if (ratchet.seasonFrom == Season::Fall) {
    3378            0 :         seasonFromMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
    3379            0 :         isMonthly = false;
    3380            0 :     } else if (ratchet.seasonFrom == Season::Annual) {
    3381            0 :         seasonFromMask = 1.0; // all months are 1
    3382            0 :         isMonthly = false;
    3383            0 :     } else if (ratchet.seasonFrom == Season::Monthly) {
    3384            0 :         seasonFromMask = 1.0; // all months are 1
    3385            0 :         isMonthly = true;
    3386              :     } else {
    3387            0 :         assert(false);
    3388              :     }
    3389              : 
    3390              :     // find proper season to mask
    3391            0 :     if (ratchet.seasonTo == Season::Summer) {
    3392            0 :         seasonToMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
    3393            0 :     } else if (ratchet.seasonTo == Season::Winter) {
    3394            0 :         seasonToMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
    3395            0 :     } else if (ratchet.seasonTo == Season::Spring) {
    3396            0 :         seasonToMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
    3397            0 :     } else if (ratchet.seasonTo == Season::Fall) {
    3398            0 :         seasonToMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
    3399            0 :     } else if (ratchet.seasonTo == Season::Annual) {
    3400            0 :         seasonToMask = 1.0; // all months are 1
    3401              :     }
    3402              :     // finally perform calculations
    3403            0 :     if (isMonthly) {
    3404            0 :         adjSeasonal = adjustmentVals;
    3405              :     } else {
    3406            0 :         Real64 maximumVal = -HUGE_(Real64());
    3407            0 :         for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
    3408            0 :             if (seasonFromMask(iMonth) == 1) {
    3409            0 :                 if (adjustmentVals(iMonth) > maximumVal) {
    3410            0 :                     maximumVal = adjustmentVals(iMonth);
    3411              :                 }
    3412              :             }
    3413              :         }
    3414            0 :         adjSeasonal = maximumVal;
    3415              :     }
    3416            0 :     for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
    3417              :         // calculate adjusted peak value after offset and multiplier
    3418            0 :         adjPeak(iMonth) = (adjSeasonal(iMonth) + offsetVals(iMonth)) * multiplierVals(iMonth);
    3419              :         // the maximum of the adjustment and the baseline
    3420            0 :         if (adjPeak(iMonth) > baselineVals(iMonth)) {
    3421            0 :             maxAdjBase(iMonth) = adjPeak(iMonth);
    3422              :         } else {
    3423            0 :             maxAdjBase(iMonth) = baselineVals(iMonth);
    3424              :         }
    3425              :     }
    3426            0 :     for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
    3427            0 :         if (seasonToMask(iMonth) == 1) {
    3428            0 :             finalResult(iMonth) = maxAdjBase(iMonth);
    3429              :         } else {
    3430            0 :             finalResult(iMonth) = baselineVals(iMonth);
    3431              :         }
    3432              :     }
    3433              :     // store the cost in the name of the variable
    3434            0 :     s_econ->econVar(usingVariable).values = finalResult;
    3435              :     // set the flag that it has been evaluated so it won't be evaluated multiple times
    3436            0 :     s_econ->econVar(usingVariable).isEvaluated = true;
    3437            0 : }
    3438              : 
    3439            0 : void evaluateQualify(EnergyPlusData &state, int const usingVariable)
    3440              : {
    3441              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    3442              :     //    DATE WRITTEN   July 2004
    3443              : 
    3444            0 :     Array1D<Real64> sourceVals(NumMonths);
    3445            0 :     Array1D<Real64> thresholdVals(NumMonths);
    3446            0 :     Array1D_int monthsQualify(NumMonths);
    3447            0 :     Array1D<Real64> seasonMask(NumMonths);
    3448              :     int adjNumberOfMonths;
    3449              :     bool isQualified;
    3450              : 
    3451            0 :     auto &s_econ = state.dataEconTariff;
    3452            0 :     auto &econVar = s_econ->econVar(usingVariable);
    3453              : 
    3454            0 :     int curTariff = econVar.tariffIndx;
    3455            0 :     auto &tariff = s_econ->tariff(curTariff);
    3456            0 :     int indexInQual = econVar.index;
    3457            0 :     auto const &qualify = s_econ->qualify(indexInQual);
    3458              :     // check the tariff - make sure they match
    3459            0 :     if (qualify.namePt != usingVariable) {
    3460            0 :         ShowWarningError(state, "UtilityCost:Tariff Debugging issue. Qualify index does not match variable pointer.");
    3461            0 :         ShowContinueError(state, format("   Between: {}", econVar.name));
    3462            0 :         ShowContinueError(state, format("       And: {}", s_econ->econVar(qualify.namePt).name));
    3463              :     }
    3464            0 :     if (qualify.tariffIndx != curTariff) {
    3465            0 :         ShowWarningError(state, "UtilityCost:Tariff Debugging issue. Qualify index does not match tariff index.");
    3466            0 :         ShowContinueError(state, format("   Between: {}", tariff.tariffName));
    3467            0 :         ShowContinueError(state, format("       And: {}", s_econ->tariff(qualify.tariffIndx).tariffName));
    3468              :     }
    3469              :     // data from the Qualify
    3470            0 :     sourceVals = s_econ->econVar(qualify.sourcePt).values;
    3471            0 :     bool curIsMaximum = qualify.isMaximum;
    3472            0 :     bool curIsConsecutive = qualify.isConsecutive;
    3473            0 :     int curNumberOfMonths = qualify.numberOfMonths;
    3474              :     // determine if threshold should be based on variable or value
    3475            0 :     if (qualify.thresholdPt != 0) {
    3476            0 :         thresholdVals = s_econ->econVar(qualify.thresholdPt).values;
    3477              :     } else {
    3478            0 :         thresholdVals = qualify.thresholdVal;
    3479              :     }
    3480              :     // find proper season mask
    3481              : 
    3482            0 :     if (qualify.season == Season::Summer) {
    3483            0 :         seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
    3484            0 :     } else if (qualify.season == Season::Winter) {
    3485            0 :         seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
    3486            0 :     } else if (qualify.season == Season::Spring) {
    3487            0 :         seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
    3488            0 :     } else if (qualify.season == Season::Fall) {
    3489            0 :         seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
    3490            0 :     } else if (qualify.season == Season::Annual) {
    3491            0 :         seasonMask = 1.0; // all months are 1
    3492              :     }
    3493              : 
    3494              :     // any months with no energy use are excluded from the qualification process
    3495            0 :     for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
    3496            0 :         if (s_econ->econVar(tariff.natives[(int)Native::TotalEnergy]).values(iMonth) == 0) {
    3497            0 :             seasonMask(iMonth) = 0.0;
    3498              :         }
    3499              :     }
    3500              :     // finally perform calculations
    3501              :     // loop through the months
    3502            0 :     int monthsInSeason = 0;
    3503            0 :     for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
    3504            0 :         if (seasonMask(iMonth) == 1) {
    3505            0 :             ++monthsInSeason;
    3506              :             // use threshold as maximum or minimum
    3507            0 :             if (curIsMaximum) {
    3508            0 :                 if (sourceVals(iMonth) > thresholdVals(iMonth)) {
    3509            0 :                     monthsQualify(iMonth) = 0; // greater than maximum threshold so it is not qualified
    3510              :                 } else {
    3511            0 :                     monthsQualify(iMonth) = 1; // less than maximum threshold so it is qualified
    3512              :                 }
    3513              :             } else {
    3514            0 :                 if (sourceVals(iMonth) < thresholdVals(iMonth)) {
    3515            0 :                     monthsQualify(iMonth) = 0; // less than minimum threshold so it is not qualified
    3516              :                 } else {
    3517            0 :                     monthsQualify(iMonth) = 1; // greater than minimum threshold so it is qualified
    3518              :                 }
    3519              :             }
    3520              :         } else {
    3521            0 :             monthsQualify(iMonth) = -1; // flag that indicates not part of the season
    3522              :         }
    3523              :     }
    3524              :     // see if the number of months is longer then the number of months and adjust
    3525            0 :     if (curNumberOfMonths > monthsInSeason) {
    3526            0 :         adjNumberOfMonths = monthsInSeason;
    3527              :     } else {
    3528            0 :         adjNumberOfMonths = curNumberOfMonths;
    3529              :     }
    3530              :     // now that each month is qualified or not, depending on the type of test see if the entire qualify pass or not
    3531            0 :     int cntAllQualMonths = 0;
    3532            0 :     int cntConsecQualMonths = 0;
    3533            0 :     int maxConsecQualMonths = 0;
    3534            0 :     for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
    3535              :         {
    3536            0 :             int const SELECT_CASE_var(monthsQualify(iMonth));
    3537            0 :             if (SELECT_CASE_var == 1) { // qualified
    3538            0 :                 ++cntAllQualMonths;
    3539            0 :                 ++cntConsecQualMonths;
    3540              :                 // see if the count is greater then the previous count and if it is make it the new count
    3541            0 :                 if (cntConsecQualMonths > maxConsecQualMonths) {
    3542            0 :                     maxConsecQualMonths = cntConsecQualMonths;
    3543              :                 }
    3544            0 :             } else if (SELECT_CASE_var == 0) { // not qualified
    3545              :                 // reset the counter on consecutive months
    3546            0 :                 cntConsecQualMonths = 0;
    3547              :             }
    3548              :         }
    3549              :     }
    3550              :     // if test is for consecutive months
    3551            0 :     if (curIsConsecutive) {
    3552            0 :         if (maxConsecQualMonths >= adjNumberOfMonths) {
    3553            0 :             isQualified = true;
    3554              :         } else {
    3555            0 :             isQualified = false;
    3556              :         }
    3557              :     } else { // count not consecutive
    3558            0 :         if (cntAllQualMonths >= adjNumberOfMonths) {
    3559            0 :             isQualified = true;
    3560              :         } else {
    3561            0 :             isQualified = false;
    3562              :         }
    3563              :     }
    3564              :     // now update the tariff level qualifier - only update if the tariff is still qualified
    3565              :     // and the current qualifier fails.
    3566            0 :     if (tariff.isQualified) {
    3567            0 :         if (!isQualified) {
    3568            0 :             tariff.isQualified = false;
    3569            0 :             tariff.ptDisqualifier = usingVariable;
    3570              :         }
    3571              :     }
    3572              :     // store the cost in the name of the variable
    3573            0 :     econVar.values = monthsQualify;
    3574              :     // set the flag that it has been evaluated so it won't be evaluated multiple times
    3575            0 :     econVar.isEvaluated = true;
    3576            0 : }
    3577              : 
    3578            0 : void addMonthlyCharge(EnergyPlusData &state, int const usingVariable)
    3579              : {
    3580              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    3581              :     //    DATE WRITTEN   July 2004
    3582              : 
    3583              :     //    Include the monthly charges in the calculations
    3584              : 
    3585            0 :     auto &s_econ = state.dataEconTariff;
    3586            0 :     int curTariff = s_econ->econVar(usingVariable).tariffIndx;
    3587            0 :     auto const &tariff = s_econ->tariff(curTariff);
    3588              :     // check the tariff - make sure they match
    3589            0 :     if (tariff.cats[(int)Cat::ServiceCharges] != usingVariable) {
    3590            0 :         ShowWarningError(state, "UtilityCost:Tariff Debugging issue. Tariff index for service charge does not match variable pointer.");
    3591            0 :         ShowContinueError(state, format("   Between: {}", tariff.tariffName));
    3592            0 :         ShowContinueError(state, format("       And: {}", s_econ->tariff(tariff.cats[(int)Cat::ServiceCharges]).tariffName));
    3593              :     }
    3594            0 :     if (tariff.monthChgPt != 0) {
    3595            0 :         s_econ->econVar(usingVariable).values += s_econ->econVar(tariff.monthChgPt).values;
    3596              :     } else {
    3597            0 :         s_econ->econVar(usingVariable).values += tariff.monthChgVal;
    3598              :     }
    3599              :     // zero out months with no energy consumption
    3600              :     // curTotalEnergy = tariff.nativeTotalEnergy
    3601              :     // DO iMonth = 1, NumMonths
    3602              :     //  IF (s_econ->econVar(curTotalEnergy)%values(iMonth) .EQ. 0) THEN
    3603              :     //    s_econ->econVar(usingVariable)%values(iMonth) = 0
    3604              :     //  END IF
    3605              :     // END DO
    3606            0 : }
    3607              : 
    3608            0 : void checkMinimumMonthlyCharge(EnergyPlusData &state, int const curTariff)
    3609              : {
    3610              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    3611              :     //    DATE WRITTEN   August 2008
    3612              : 
    3613              :     //    Check if the total is as big as the minimum monthly charge
    3614              : 
    3615            0 :     auto &s_econ = state.dataEconTariff;
    3616            0 :     auto const &tariff = s_econ->tariff(curTariff);
    3617              : 
    3618            0 :     int totalVar = tariff.cats[(int)Cat::Total];
    3619            0 :     int minMonVar = tariff.minMonthChgPt;
    3620              :     // if a variable is defined use that
    3621            0 :     if (minMonVar != 0) {
    3622            0 :         for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
    3623            0 :             if (s_econ->econVar(totalVar).values(iMonth) < s_econ->econVar(minMonVar).values(iMonth)) {
    3624            0 :                 s_econ->econVar(totalVar).values(iMonth) = s_econ->econVar(minMonVar).values(iMonth);
    3625              :             }
    3626              :         }
    3627              :     } else { // use the constant value
    3628            0 :         for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
    3629            0 :             if (s_econ->econVar(totalVar).values(iMonth) < tariff.minMonthChgVal) {
    3630            0 :                 s_econ->econVar(totalVar).values(iMonth) = tariff.minMonthChgVal;
    3631              :             }
    3632              :         }
    3633              :     }
    3634            0 : }
    3635              : 
    3636            0 : void setNativeVariables(EnergyPlusData &state)
    3637              : {
    3638              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    3639              :     //    DATE WRITTEN   July 2004
    3640              : 
    3641              :     //    Set up the "built in" i.e. native variables that hold
    3642              :     //    the energy and demand from the simulation.
    3643              : 
    3644            0 :     auto &s_econ = state.dataEconTariff;
    3645              : 
    3646            0 :     Array1D<Real64> monthVal(NumMonths);
    3647            0 :     Real64 bigNumber(0.0); // Autodesk Value not used but suppresses warning about HUGE_() call
    3648              : 
    3649            0 :     bigNumber = HUGE_(bigNumber);
    3650            0 :     for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    3651            0 :         auto &tariff = s_econ->tariff(iTariff);
    3652              :         // nativeTotalEnergy
    3653            0 :         monthVal = 0.0;
    3654            0 :         for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
    3655            0 :             for (int jPeriod = 1; jPeriod <= (int)Period::Num; ++jPeriod) {
    3656            0 :                 monthVal(kMonth) += tariff.gatherEnergy(kMonth)[jPeriod];
    3657              :             }
    3658              :         }
    3659            0 :         s_econ->econVar(tariff.natives[(int)Native::TotalEnergy]).values = monthVal;
    3660              :         // nativeTotalDemand
    3661            0 :         monthVal = -bigNumber;
    3662            0 :         for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
    3663            0 :             for (int jPeriod = 1; jPeriod <= (int)Period::Num; ++jPeriod) {
    3664            0 :                 if (tariff.gatherDemand(kMonth)[jPeriod] > monthVal(kMonth)) {
    3665            0 :                     monthVal(kMonth) = tariff.gatherDemand(kMonth)[jPeriod];
    3666              :                 }
    3667              :             }
    3668              :         }
    3669              :         // if no maximum was set just set to zero
    3670            0 :         for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
    3671            0 :             if (monthVal(kMonth) == -bigNumber) {
    3672            0 :                 monthVal(kMonth) = 0.0;
    3673              :             }
    3674              :         }
    3675            0 :         s_econ->econVar(tariff.natives[(int)Native::TotalDemand]).values = monthVal;
    3676            0 :         for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
    3677              :             // nativePeakEnergy
    3678            0 :             s_econ->econVar(tariff.natives[(int)Native::PeakEnergy]).values(kMonth) = tariff.gatherEnergy(kMonth)[(int)Period::Peak];
    3679              :             // nativePeakDemand
    3680            0 :             s_econ->econVar(tariff.natives[(int)Native::PeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak];
    3681              :             // nativeShoulderEnergy
    3682            0 :             s_econ->econVar(tariff.natives[(int)Native::ShoulderEnergy]).values(kMonth) = tariff.gatherEnergy(kMonth)[(int)Period::Shoulder];
    3683              :             // nativeShoulderDemand
    3684            0 :             s_econ->econVar(tariff.natives[(int)Native::ShoulderDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Shoulder];
    3685              :             // nativeOffPeakEnergy
    3686            0 :             s_econ->econVar(tariff.natives[(int)Native::OffPeakEnergy]).values(kMonth) = tariff.gatherEnergy(kMonth)[(int)Period::OffPeak];
    3687              :             // nativeOffPeakDemand
    3688            0 :             s_econ->econVar(tariff.natives[(int)Native::OffPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::OffPeak];
    3689              :             // nativeMidPeakEnergy
    3690            0 :             s_econ->econVar(tariff.natives[(int)Native::MidPeakEnergy]).values(kMonth) = tariff.gatherEnergy(kMonth)[(int)Period::MidPeak];
    3691              :             // nativeMidPeakDemand
    3692            0 :             s_econ->econVar(tariff.natives[(int)Native::MidPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::MidPeak];
    3693              :             // nativePeakExceedsOffPeak
    3694            0 :             monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak] - tariff.gatherDemand(kMonth)[(int)Period::OffPeak];
    3695            0 :             if (monthVal(kMonth) > 0) {
    3696            0 :                 s_econ->econVar(tariff.natives[(int)Native::PeakExceedsOffPeak]).values(kMonth) = monthVal(kMonth);
    3697              :             } else {
    3698            0 :                 s_econ->econVar(tariff.natives[(int)Native::PeakExceedsOffPeak]).values(kMonth) = 0.0;
    3699              :             }
    3700              :             // nativeOffPeakExceedsPeak
    3701            0 :             monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::OffPeak] - tariff.gatherDemand(kMonth)[(int)Period::Peak];
    3702            0 :             if (monthVal(kMonth) > 0) {
    3703            0 :                 s_econ->econVar(tariff.natives[(int)Native::OffPeakExceedsPeak]).values(kMonth) = monthVal(kMonth);
    3704              :             } else {
    3705            0 :                 s_econ->econVar(tariff.natives[(int)Native::OffPeakExceedsPeak]).values(kMonth) = 0.0;
    3706              :             }
    3707              :             // nativePeakExceedsMidPeak
    3708            0 :             monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak] - tariff.gatherDemand(kMonth)[(int)Period::MidPeak];
    3709            0 :             if (monthVal(kMonth) > 0) {
    3710            0 :                 s_econ->econVar(tariff.natives[(int)Native::PeakExceedsMidPeak]).values(kMonth) = monthVal(kMonth);
    3711              :             } else {
    3712            0 :                 s_econ->econVar(tariff.natives[(int)Native::PeakExceedsOffPeak]).values(kMonth) = 0.0;
    3713              :             }
    3714              :             // nativeMidPeakExceedsPeak
    3715            0 :             monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::MidPeak] - tariff.gatherDemand(kMonth)[(int)Period::Peak];
    3716            0 :             if (monthVal(kMonth) > 0) {
    3717            0 :                 s_econ->econVar(tariff.natives[(int)Native::MidPeakExceedsPeak]).values(kMonth) = monthVal(kMonth);
    3718              :             } else {
    3719            0 :                 s_econ->econVar(tariff.natives[(int)Native::MidPeakExceedsPeak]).values(kMonth) = 0.0;
    3720              :             }
    3721              :             // nativePeakExceedsShoulder
    3722            0 :             monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak] - tariff.gatherDemand(kMonth)[(int)Period::Shoulder];
    3723            0 :             if (monthVal(kMonth) > 0) {
    3724            0 :                 s_econ->econVar(tariff.natives[(int)Native::PeakExceedsShoulder]).values(kMonth) = monthVal(kMonth);
    3725              :             } else {
    3726            0 :                 s_econ->econVar(tariff.natives[(int)Native::PeakExceedsShoulder]).values(kMonth) = 0.0;
    3727              :             }
    3728              :             // nativeShoulderExceedsPeak
    3729            0 :             monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Shoulder] - tariff.gatherDemand(kMonth)[(int)Period::Peak];
    3730            0 :             if (monthVal(kMonth) > 0) {
    3731            0 :                 s_econ->econVar(tariff.natives[(int)Native::ShoulderExceedsPeak]).values(kMonth) = monthVal(kMonth);
    3732              :             } else {
    3733            0 :                 s_econ->econVar(tariff.natives[(int)Native::ShoulderExceedsPeak]).values(kMonth) = 0.0;
    3734              :             }
    3735              :             // nativeIsWinter
    3736              :             // nativeIsNotWinter
    3737            0 :             if (tariff.seasonForMonth(kMonth) == Season::Winter) {
    3738            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values(kMonth) = 1.0;
    3739            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsNotWinter]).values(kMonth) = 0.0;
    3740              :             } else {
    3741            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values(kMonth) = 0.0;
    3742            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsNotWinter]).values(kMonth) = 1.0;
    3743              :             }
    3744              :             // nativeIsSpring
    3745              :             // nativeIsNotSpring
    3746            0 :             if (tariff.seasonForMonth(kMonth) == Season::Spring) {
    3747            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values(kMonth) = 1.0;
    3748            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsNotSpring]).values(kMonth) = 0.0;
    3749              :             } else {
    3750            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values(kMonth) = 0.0;
    3751            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsNotSpring]).values(kMonth) = 1.0;
    3752              :             }
    3753              :             // nativeIsSummer
    3754              :             // nativeIsNotSummer
    3755            0 :             if (tariff.seasonForMonth(kMonth) == Season::Summer) {
    3756            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values(kMonth) = 1.0;
    3757            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsNotSummer]).values(kMonth) = 0.0;
    3758              :             } else {
    3759            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values(kMonth) = 0.0;
    3760            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsNotSummer]).values(kMonth) = 1.0;
    3761              :             }
    3762              :             // nativeIsAutumn
    3763              :             // nativeIsNotAutumn
    3764            0 :             if (tariff.seasonForMonth(kMonth) == Season::Fall) {
    3765            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values(kMonth) = 1.0;
    3766            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsNotAutumn]).values(kMonth) = 0.0;
    3767              :             } else {
    3768            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values(kMonth) = 0.0;
    3769            0 :                 s_econ->econVar(tariff.natives[(int)Native::IsNotAutumn]).values(kMonth) = 1.0;
    3770              :             }
    3771              :             // nativePeakAndShoulderEnergy
    3772            0 :             s_econ->econVar(tariff.natives[(int)Native::PeakAndShoulderEnergy]).values(kMonth) =
    3773            0 :                 tariff.gatherEnergy(kMonth)[(int)Period::Peak] + tariff.gatherEnergy(kMonth)[(int)Period::Shoulder];
    3774              :             // nativePeakAndShoulderDemand
    3775            0 :             if (tariff.gatherDemand(kMonth)[(int)Period::Peak] > tariff.gatherDemand(kMonth)[(int)Period::Shoulder]) {
    3776            0 :                 s_econ->econVar(tariff.natives[(int)Native::PeakAndShoulderDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak];
    3777              :             } else {
    3778            0 :                 s_econ->econVar(tariff.natives[(int)Native::PeakAndShoulderDemand]).values(kMonth) =
    3779            0 :                     tariff.gatherDemand(kMonth)[(int)Period::Shoulder];
    3780              :             }
    3781              :             // nativePeakAndMidPeakEnergy
    3782            0 :             s_econ->econVar(tariff.natives[(int)Native::PeakAndMidPeakEnergy]).values(kMonth) =
    3783            0 :                 tariff.gatherEnergy(kMonth)[(int)Period::Peak] + tariff.gatherEnergy(kMonth)[(int)Period::MidPeak];
    3784              :             // nativePeakAndMidPeakDemand
    3785            0 :             if (tariff.gatherDemand(kMonth)[(int)Period::Peak] > tariff.gatherDemand(kMonth)[(int)Period::MidPeak]) {
    3786            0 :                 s_econ->econVar(tariff.natives[(int)Native::PeakAndMidPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak];
    3787              :             } else {
    3788            0 :                 s_econ->econVar(tariff.natives[(int)Native::PeakAndMidPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::MidPeak];
    3789              :             }
    3790              :             // nativeShoulderAndOffPeakEnergy
    3791            0 :             s_econ->econVar(tariff.natives[(int)Native::ShoulderAndOffPeakEnergy]).values(kMonth) =
    3792            0 :                 tariff.gatherEnergy(kMonth)[(int)Period::Shoulder] + tariff.gatherEnergy(kMonth)[(int)Period::OffPeak];
    3793              :             // nativeShoulderAndOffPeakDemand
    3794            0 :             if (tariff.gatherDemand(kMonth)[(int)Period::Shoulder] > tariff.gatherDemand(kMonth)[(int)Period::OffPeak]) {
    3795            0 :                 s_econ->econVar(tariff.natives[(int)Native::ShoulderAndOffPeakDemand]).values(kMonth) =
    3796            0 :                     tariff.gatherDemand(kMonth)[(int)Period::Shoulder];
    3797              :             } else {
    3798            0 :                 s_econ->econVar(tariff.natives[(int)Native::ShoulderAndOffPeakDemand]).values(kMonth) =
    3799            0 :                     tariff.gatherDemand(kMonth)[(int)Period::OffPeak];
    3800              :             }
    3801              :             // nativePeakAndOffPeakEnergy
    3802            0 :             s_econ->econVar(tariff.natives[(int)Native::PeakAndOffPeakEnergy]).values(kMonth) =
    3803            0 :                 tariff.gatherEnergy(kMonth)[(int)Period::Peak] + tariff.gatherEnergy(kMonth)[(int)Period::OffPeak];
    3804              :             // nativePeakAndOffPeakDemand
    3805            0 :             if (tariff.gatherDemand(kMonth)[(int)Period::Peak] > tariff.gatherDemand(kMonth)[(int)Period::OffPeak]) {
    3806            0 :                 s_econ->econVar(tariff.natives[(int)Native::PeakAndOffPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak];
    3807              :             } else {
    3808            0 :                 s_econ->econVar(tariff.natives[(int)Native::PeakAndOffPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::OffPeak];
    3809              :             }
    3810              :             // nativeRealTimePriceCosts
    3811            0 :             s_econ->econVar(tariff.natives[(int)Native::RealTimePriceCosts]).values(kMonth) = tariff.RTPcost(kMonth);
    3812              :             // nativeAboveCustomerBaseCosts
    3813            0 :             s_econ->econVar(tariff.natives[(int)Native::AboveCustomerBaseCosts]).values(kMonth) = tariff.RTPaboveBaseCost(kMonth);
    3814              :             // nativeBelowCustomerBaseCosts
    3815            0 :             s_econ->econVar(tariff.natives[(int)Native::BelowCustomerBaseCosts]).values(kMonth) = tariff.RTPbelowBaseCost(kMonth);
    3816              :             // nativeAboveCustomerBaseEnergy
    3817            0 :             s_econ->econVar(tariff.natives[(int)Native::AboveCustomerBaseEnergy]).values(kMonth) = tariff.RTPaboveBaseEnergy(kMonth);
    3818              :             // nativeBelowCustomerBaseEnergy
    3819            0 :             s_econ->econVar(tariff.natives[(int)Native::BelowCustomerBaseEnergy]).values(kMonth) = tariff.RTPbelowBaseEnergy(kMonth);
    3820              :         }
    3821              :     }
    3822            0 : }
    3823              : 
    3824            2 : void LEEDtariffReporting(EnergyPlusData &state)
    3825              : {
    3826              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    3827              :     //    DATE WRITTEN   October 2012
    3828              : 
    3829              :     //    Write the economic results for LEED reporting
    3830              : 
    3831              :     Real64 elecTotalEne;
    3832              :     Real64 gasTotalEne;
    3833              :     Real64 distCoolTotalEne;
    3834              :     Real64 distHeatWaterTotalEne;
    3835              :     Real64 distHeatSteamTotalEne;
    3836              :     Real64 otherTotalEne;
    3837              :     Real64 elecTotalCost;
    3838              :     Real64 gasTotalCost;
    3839              :     Real64 otherTotalCost;
    3840              :     Real64 distCoolTotalCost;
    3841              :     Real64 distHeatWaterTotalCost;
    3842              :     Real64 distHeatSteamTotalCost;
    3843              :     Real64 allTotalCost;
    3844              :     EconConv elecUnits;
    3845              :     EconConv gasUnits;
    3846              :     EconConv distCoolUnits;
    3847              :     EconConv distHeatWaterUnits;
    3848              :     EconConv distHeatSteamUnits;
    3849              :     EconConv othrUnits;
    3850              :     DemandWindow gasDemWindowUnits;
    3851              :     DemandWindow distCoolDemWindowUnits;
    3852              :     DemandWindow distHeatWaterDemWindowUnits;
    3853              :     DemandWindow distHeatSteamDemWindowUnits;
    3854              :     DemandWindow othrDemWindowUnits;
    3855              : 
    3856            2 :     auto &s_orp = state.dataOutRptPredefined;
    3857              : 
    3858            2 :     auto &s_econ = state.dataEconTariff;
    3859              : 
    3860            2 :     if (s_econ->numTariff > 0) {
    3861            4 :         int distCoolFacilMeter = GetMeterIndex(state, "DISTRICTCOOLING:FACILITY");
    3862            4 :         int distHeatWaterFacilMeter = GetMeterIndex(state, "DISTRICTHEATINGWATER:FACILITY");
    3863            2 :         int distHeatSteamFacilMeter = GetMeterIndex(state, "DISTRICTHEATINGSTEAM:FACILITY");
    3864            2 :         elecTotalEne = 0.0;
    3865            2 :         gasTotalEne = 0.0;
    3866            2 :         distCoolTotalEne = 0.0;
    3867            2 :         distHeatWaterTotalEne = 0.0;
    3868            2 :         distHeatSteamTotalEne = 0.0;
    3869            2 :         otherTotalEne = 0.0;
    3870            2 :         elecTotalCost = 0.0;
    3871            2 :         gasTotalCost = 0.0;
    3872            2 :         distCoolTotalCost = 0.0;
    3873            2 :         distHeatWaterTotalCost = 0.0;
    3874            2 :         distHeatSteamTotalCost = 0.0;
    3875            2 :         otherTotalCost = 0.0;
    3876            2 :         allTotalCost = 0.0;
    3877            2 :         elecUnits = EconConv::USERDEF;
    3878            2 :         gasUnits = EconConv::USERDEF;
    3879            2 :         distCoolUnits = EconConv::USERDEF;
    3880            2 :         distHeatWaterUnits = EconConv::USERDEF;
    3881            2 :         distHeatSteamUnits = EconConv::USERDEF;
    3882            2 :         othrUnits = EconConv::USERDEF;
    3883            2 :         gasDemWindowUnits = DemandWindow::Invalid;
    3884            2 :         othrDemWindowUnits = DemandWindow::Invalid;
    3885            4 :         std::string elecTariffNames = "";
    3886            4 :         std::string gasTariffNames = "";
    3887            4 :         std::string distCoolTariffNames = "";
    3888            4 :         std::string distHeatWaterTariffNames = "";
    3889            4 :         std::string distHeatSteamTariffNames = "";
    3890            2 :         std::string othrTariffNames = "";
    3891           13 :         for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    3892           11 :             auto &tariff = s_econ->tariff(iTariff);
    3893           11 :             if (tariff.isSelected) {
    3894           11 :                 allTotalCost += tariff.totalAnnualCost;
    3895           11 :                 if (tariff.kindMtr == MeterType::ElecSimple || tariff.kindMtr == MeterType::ElecProduced ||
    3896           11 :                     tariff.kindMtr == MeterType::ElecPurchased || tariff.kindMtr == MeterType::ElecSurplusSold ||
    3897            8 :                     tariff.kindMtr == MeterType::ElecNet) {
    3898            3 :                     if (tariff.totalAnnualEnergy > elecTotalEne) elecTotalEne = tariff.totalAnnualEnergy;
    3899            3 :                     elecTotalCost += tariff.totalAnnualCost;
    3900            3 :                     elecTariffNames += ' ' + tariff.tariffName;
    3901            3 :                     elecUnits = tariff.convChoice;
    3902            8 :                 } else if (tariff.kindMtr == MeterType::Gas) {
    3903            3 :                     if (tariff.totalAnnualEnergy > gasTotalEne) gasTotalEne = tariff.totalAnnualEnergy;
    3904            3 :                     gasTotalCost += tariff.totalAnnualCost;
    3905            3 :                     gasTariffNames += ' ' + tariff.tariffName;
    3906            3 :                     gasUnits = tariff.convChoice;
    3907            3 :                     gasDemWindowUnits = tariff.demandWindow;
    3908            5 :                 } else if (tariff.reportMeterIndx == distCoolFacilMeter) {
    3909            2 :                     if (tariff.totalAnnualEnergy > distCoolTotalEne) distCoolTotalEne = tariff.totalAnnualEnergy;
    3910            2 :                     distCoolTotalCost += tariff.totalAnnualCost;
    3911            2 :                     distCoolTariffNames += ' ' + tariff.tariffName;
    3912            2 :                     distCoolUnits = tariff.convChoice;
    3913            2 :                     distCoolDemWindowUnits = tariff.demandWindow;
    3914            3 :                 } else if (tariff.reportMeterIndx == distHeatWaterFacilMeter) {
    3915            2 :                     if (tariff.totalAnnualEnergy > distHeatWaterTotalEne) distHeatWaterTotalEne = tariff.totalAnnualEnergy;
    3916            2 :                     distHeatWaterTotalCost += tariff.totalAnnualCost;
    3917            2 :                     distHeatWaterTariffNames += ' ' + tariff.tariffName;
    3918            2 :                     distHeatWaterUnits = tariff.convChoice;
    3919            2 :                     distHeatWaterDemWindowUnits = tariff.demandWindow;
    3920            1 :                 } else if (tariff.reportMeterIndx == distHeatSteamFacilMeter) {
    3921            0 :                     if (tariff.totalAnnualEnergy > distHeatSteamTotalEne) distHeatSteamTotalEne = tariff.totalAnnualEnergy;
    3922            0 :                     distHeatSteamTotalCost += tariff.totalAnnualCost;
    3923            0 :                     distHeatSteamTariffNames += ' ' + tariff.tariffName;
    3924            0 :                     distHeatSteamUnits = tariff.convChoice;
    3925            0 :                     distHeatSteamDemWindowUnits = tariff.demandWindow;
    3926            1 :                 } else if (tariff.kindMtr != MeterType::Water) {
    3927            0 :                     if (tariff.totalAnnualEnergy > otherTotalEne) otherTotalEne = tariff.totalAnnualEnergy;
    3928            0 :                     otherTotalCost += tariff.totalAnnualCost;
    3929            0 :                     othrTariffNames += ' ' + tariff.tariffName;
    3930            0 :                     othrUnits = tariff.convChoice;
    3931            0 :                     othrDemWindowUnits = tariff.demandWindow;
    3932              :                 } else {
    3933              :                 }
    3934              :             }
    3935              :         }
    3936              :         // names of the rates
    3937            2 :         OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "Electricity", elecTariffNames);
    3938            2 :         OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "Natural Gas", gasTariffNames);
    3939            2 :         if (distCoolTotalEne != 0) OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "District Cooling", distCoolTariffNames);
    3940            2 :         if (distHeatWaterTotalEne != 0)
    3941            2 :             OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "District Heating Water", distHeatWaterTariffNames);
    3942            2 :         if (distHeatSteamTotalEne != 0)
    3943            0 :             OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "District Heating Steam", distHeatSteamTariffNames);
    3944            2 :         OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "Other", othrTariffNames);
    3945              :         // virtual rate
    3946            2 :         if (elecTotalEne != 0)
    3947            2 :             OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsVirt, "Electricity", elecTotalCost / elecTotalEne, 3);
    3948            2 :         if (gasTotalEne != 0) OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsVirt, "Natural Gas", gasTotalCost / gasTotalEne, 3);
    3949            2 :         if (otherTotalEne != 0) OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsVirt, "Other", otherTotalCost / otherTotalEne, 3);
    3950              :         // units
    3951            2 :         OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsEneUnt, "Electricity", format("{}", convEnergyStrings[(int)elecUnits]));
    3952            2 :         OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsEneUnt, "Natural Gas", format("{}", convEnergyStrings[(int)gasUnits]));
    3953            2 :         OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsEneUnt, "Other", format("{}", convEnergyStrings[(int)othrUnits]));
    3954            2 :         OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsDemUnt, "Electricity", format("{}", convDemandStrings[(int)elecUnits]));
    3955            4 :         OutputReportPredefined::PreDefTableEntry(
    3956              :             state,
    3957            2 :             s_orp->pdchLeedEtsDemUnt,
    3958              :             "Natural Gas",
    3959            4 :             format("{}{}",
    3960            2 :                    convDemandStrings[(int)gasUnits],
    3961            2 :                    (gasDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)gasDemWindowUnits]));
    3962            4 :         OutputReportPredefined::PreDefTableEntry(
    3963              :             state,
    3964            2 :             s_orp->pdchLeedEtsDemUnt,
    3965              :             "Other",
    3966            4 :             format("{}{}",
    3967            2 :                    convDemandStrings[(int)othrUnits],
    3968            2 :                    (othrDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)othrDemWindowUnits]));
    3969              : 
    3970              :         // total cost
    3971            2 :         OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "Electricity", elecTotalCost, 2);
    3972            2 :         OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "Natural Gas", gasTotalCost, 2);
    3973            2 :         OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "Other", otherTotalCost, 2);
    3974              :         // show district energy if used
    3975            2 :         if (distCoolTotalEne != 0) {
    3976            2 :             OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsVirt, "District Cooling", distCoolTotalCost / distCoolTotalEne, 3);
    3977            4 :             OutputReportPredefined::PreDefTableEntry(
    3978            6 :                 state, s_orp->pdchLeedEtsEneUnt, "District Cooling", format("{}", convEnergyStrings[(int)distCoolUnits]));
    3979            4 :             OutputReportPredefined::PreDefTableEntry(
    3980              :                 state,
    3981            2 :                 s_orp->pdchLeedEtsDemUnt,
    3982              :                 "District Cooling",
    3983            4 :                 format("{}{}",
    3984            2 :                        convDemandStrings[(int)distCoolUnits],
    3985            2 :                        (distCoolDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)distCoolDemWindowUnits]));
    3986            2 :             OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "District Cooling", distCoolTotalCost, 2);
    3987              :         }
    3988            2 :         if (distHeatWaterTotalEne != 0) {
    3989            4 :             OutputReportPredefined::PreDefTableEntry(
    3990            4 :                 state, s_orp->pdchLeedEtsVirt, "District Heating Water", distHeatWaterTotalCost / distHeatWaterTotalEne, 3);
    3991            4 :             OutputReportPredefined::PreDefTableEntry(
    3992            6 :                 state, s_orp->pdchLeedEtsEneUnt, "District Heating Water", format("{}", convEnergyStrings[(int)distHeatWaterUnits]));
    3993            4 :             OutputReportPredefined::PreDefTableEntry(
    3994              :                 state,
    3995            2 :                 s_orp->pdchLeedEtsDemUnt,
    3996              :                 "District Heating Water",
    3997            4 :                 format("{}{}",
    3998            2 :                        convDemandStrings[(int)distHeatWaterUnits],
    3999            2 :                        (distHeatWaterDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)distHeatWaterDemWindowUnits]));
    4000            2 :             OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "District Heating Water", distHeatWaterTotalCost, 2);
    4001              :         }
    4002            2 :         if (distHeatSteamTotalEne != 0) {
    4003            0 :             OutputReportPredefined::PreDefTableEntry(
    4004            0 :                 state, s_orp->pdchLeedEtsVirt, "District Heating Steam", distHeatSteamTotalCost / distHeatSteamTotalEne, 3);
    4005            0 :             OutputReportPredefined::PreDefTableEntry(
    4006            0 :                 state, s_orp->pdchLeedEtsEneUnt, "District Heating Steam", format("{}", convEnergyStrings[(int)distHeatSteamUnits]));
    4007            0 :             OutputReportPredefined::PreDefTableEntry(
    4008              :                 state,
    4009            0 :                 s_orp->pdchLeedEtsDemUnt,
    4010              :                 "District Heating Steam",
    4011            0 :                 format("{}{}",
    4012            0 :                        convDemandStrings[(int)distHeatSteamUnits],
    4013            0 :                        (distHeatSteamDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)distHeatSteamDemWindowUnits]));
    4014            0 :             OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "District Heating Steam", distHeatSteamTotalCost, 2);
    4015              :         }
    4016              :         // save the total costs for later to compute process fraction
    4017            2 :         s_orp->LEEDelecCostTotal = elecTotalCost;
    4018            2 :         s_orp->LEEDgasCostTotal = gasTotalCost;
    4019            2 :         s_orp->LEEDothrCostTotal = distCoolTotalCost + distHeatWaterTotalCost + distHeatSteamTotalCost + otherTotalCost;
    4020            2 :         OutputReportPredefined::PreDefTableEntry(state,
    4021            2 :                                                  s_orp->pdchLeedEcsTotal,
    4022              :                                                  "Total",
    4023            2 :                                                  elecTotalCost + gasTotalCost + distCoolTotalCost + distHeatWaterTotalCost + distHeatSteamTotalCost +
    4024              :                                                      otherTotalCost,
    4025            2 :                                                  2);
    4026            2 :     }
    4027            2 : }
    4028              : 
    4029           75 : void WriteTabularTariffReports(EnergyPlusData &state)
    4030              : {
    4031              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    4032              :     //    DATE WRITTEN   July 2004
    4033              :     //    MODIFIED       January 2010, Kyle Benne
    4034              :     //                   Added SQLite output
    4035              : 
    4036              :     // all arrays are in the format: (row, column)
    4037           75 :     Array1D_string columnHead;
    4038           75 :     Array1D_int columnWidth;
    4039           75 :     Array1D_string rowHead;
    4040           75 :     Array2D_string tableBody;
    4041              :     // other local variables
    4042              :     Real64 elecTotalCost;
    4043              :     Real64 gasTotalCost;
    4044              :     Real64 otherTotalCost;
    4045              :     Real64 allTotalCost;
    4046           75 :     Real64 perAreaUnitConv(0.0);
    4047              : 
    4048           75 :     auto &s_econ = state.dataEconTariff;
    4049              : 
    4050              :     // Here to it is ready to assign ort->unitStyle_SQLite (not in SQLiteProcedures.cc)
    4051              :     // when ort->unitsStyle inputs should have been concretely processed and assigned.
    4052              :     // Included this here to make sure the units specifications are correctly updated.
    4053           75 :     if (state.dataOutRptTab->unitsStyle_SQLite == OutputReportTabular::UnitsStyle::NotFound) {
    4054            0 :         state.dataOutRptTab->unitsStyle_SQLite = state.dataOutRptTab->unitsStyle; // This is the default UseOutputControlTableStyles
    4055              :     }
    4056              : 
    4057              :     // compute floor area if no ABUPS
    4058           75 :     if (state.dataOutRptTab->buildingConditionedFloorArea == 0.0) {
    4059           59 :         OutputReportTabular::DetermineBuildingFloorArea(state);
    4060              :     }
    4061              : 
    4062           75 :     if (s_econ->numTariff > 0) {
    4063            2 :         auto &econVar = s_econ->econVar;
    4064              : 
    4065            2 :         if (state.dataOutRptTab->displayEconomicResultSummary) {
    4066            2 :             DisplayString(state, "Writing Tariff Reports");
    4067          202 :             for (auto &e : econVar)
    4068          200 :                 e.isReported = false;
    4069            2 :             showWarningsBasedOnTotal(state);
    4070              :             //---------------------------------
    4071              :             // Economics Results Summary Report
    4072              :             //---------------------------------
    4073            6 :             OutputReportTabular::WriteReportHeaders(
    4074              :                 state, "Economics Results Summary Report", "Entire Facility", OutputProcessor::StoreType::Average);
    4075              : 
    4076            5 :             for (int iUnitSystem = 0; iUnitSystem <= 1; iUnitSystem++) {
    4077            4 :                 OutputReportTabular::UnitsStyle unitsStyle_cur = state.dataOutRptTab->unitsStyle;
    4078            4 :                 bool produceTabular = true;
    4079            4 :                 bool produceSQLite = false;
    4080            4 :                 if (produceDualUnitsFlags(iUnitSystem,
    4081            4 :                                           state.dataOutRptTab->unitsStyle,
    4082            4 :                                           state.dataOutRptTab->unitsStyle_SQLite,
    4083              :                                           unitsStyle_cur,
    4084              :                                           produceTabular,
    4085              :                                           produceSQLite))
    4086            1 :                     break;
    4087              : 
    4088              :                 // do unit conversions if necessary
    4089            3 :                 std::string perAreaUnitName;
    4090            3 :                 if ((unitsStyle_cur == OutputReportTabular::UnitsStyle::InchPound) ||
    4091            2 :                     (unitsStyle_cur == OutputReportTabular::UnitsStyle::InchPoundExceptElectricity)) {
    4092            1 :                     int unitConvIndex = 0;
    4093            1 :                     std::string SIunit = "[~~$~~/m2]";
    4094            1 :                     OutputReportTabular::LookupSItoIP(state, SIunit, unitConvIndex, perAreaUnitName);
    4095            1 :                     perAreaUnitConv = OutputReportTabular::ConvertIP(state, unitConvIndex, 1.0);
    4096            1 :                 } else {
    4097            2 :                     perAreaUnitName = "[~~$~~/m2]";
    4098            2 :                     perAreaUnitConv = 1.0;
    4099              :                 }
    4100              : 
    4101              :                 //---- Annual Summary
    4102            3 :                 rowHead.allocate(3);
    4103            3 :                 columnHead.allocate(4);
    4104            3 :                 columnWidth.allocate(4);
    4105            3 :                 tableBody.allocate(4, 3);
    4106            3 :                 tableBody = "";
    4107            3 :                 columnHead(1) = "Electricity";
    4108            3 :                 columnHead(2) = "Natural Gas";
    4109            3 :                 columnHead(3) = "Other";
    4110            3 :                 columnHead(4) = "Total";
    4111            3 :                 rowHead(1) = "Cost [~~$~~]";
    4112            3 :                 rowHead(2) = "Cost per Total Building Area " + perAreaUnitName;
    4113            3 :                 rowHead(3) = "Cost per Net Conditioned Building Area " + perAreaUnitName;
    4114            3 :                 elecTotalCost = 0.0;
    4115            3 :                 gasTotalCost = 0.0;
    4116            3 :                 otherTotalCost = 0.0;
    4117            3 :                 allTotalCost = 0.0;
    4118            6 :                 for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    4119            3 :                     auto const &tariff = s_econ->tariff(iTariff);
    4120            3 :                     if (tariff.isSelected) {
    4121            3 :                         allTotalCost += tariff.totalAnnualCost;
    4122            3 :                         if (tariff.kindMtr == MeterType::ElecSimple || tariff.kindMtr == MeterType::ElecProduced ||
    4123            3 :                             tariff.kindMtr == MeterType::ElecPurchased || tariff.kindMtr == MeterType::ElecSurplusSold ||
    4124            3 :                             tariff.kindMtr == MeterType::ElecNet) {
    4125            0 :                             elecTotalCost += tariff.totalAnnualCost;
    4126            3 :                         } else if (tariff.kindMtr == MeterType::Gas) {
    4127            0 :                             gasTotalCost += tariff.totalAnnualCost;
    4128            3 :                         } else if (tariff.kindMtr != MeterType::Water) {
    4129            3 :                             otherTotalCost += tariff.totalAnnualCost;
    4130              :                             // removed because this was confusing        columnHead(3) = tariff.reportMeter
    4131              :                         }
    4132              :                     }
    4133              :                 }
    4134            3 :                 tableBody(1, 1) = OutputReportTabular::RealToStr(elecTotalCost, 2);
    4135            3 :                 tableBody(2, 1) = OutputReportTabular::RealToStr(gasTotalCost, 2);
    4136            3 :                 tableBody(3, 1) = OutputReportTabular::RealToStr(otherTotalCost, 2);
    4137            3 :                 tableBody(4, 1) = OutputReportTabular::RealToStr(allTotalCost, 2);
    4138            3 :                 if (state.dataOutRptTab->buildingGrossFloorArea > 0.0) {
    4139            3 :                     tableBody(1, 2) =
    4140            6 :                         OutputReportTabular::RealToStr((elecTotalCost / state.dataOutRptTab->buildingGrossFloorArea) * perAreaUnitConv, 2);
    4141            3 :                     tableBody(2, 2) =
    4142            6 :                         OutputReportTabular::RealToStr((gasTotalCost / state.dataOutRptTab->buildingGrossFloorArea) * perAreaUnitConv, 2);
    4143            3 :                     tableBody(3, 2) =
    4144            6 :                         OutputReportTabular::RealToStr((otherTotalCost / state.dataOutRptTab->buildingGrossFloorArea) * perAreaUnitConv, 2);
    4145            3 :                     tableBody(4, 2) =
    4146            6 :                         OutputReportTabular::RealToStr((allTotalCost / state.dataOutRptTab->buildingGrossFloorArea) * perAreaUnitConv, 2);
    4147              :                 }
    4148            3 :                 if (state.dataOutRptTab->buildingConditionedFloorArea > 0.0) {
    4149            3 :                     tableBody(1, 3) =
    4150            6 :                         OutputReportTabular::RealToStr((elecTotalCost / state.dataOutRptTab->buildingConditionedFloorArea) * perAreaUnitConv, 2);
    4151            3 :                     tableBody(2, 3) =
    4152            6 :                         OutputReportTabular::RealToStr((gasTotalCost / state.dataOutRptTab->buildingConditionedFloorArea) * perAreaUnitConv, 2);
    4153            3 :                     tableBody(3, 3) =
    4154            6 :                         OutputReportTabular::RealToStr((otherTotalCost / state.dataOutRptTab->buildingConditionedFloorArea) * perAreaUnitConv, 2);
    4155            3 :                     tableBody(4, 3) =
    4156            6 :                         OutputReportTabular::RealToStr((allTotalCost / state.dataOutRptTab->buildingConditionedFloorArea) * perAreaUnitConv, 2);
    4157              :                 }
    4158            3 :                 columnWidth = 14; // array assignment - same for all columns
    4159            3 :                 if (produceTabular) {
    4160            2 :                     OutputReportTabular::WriteSubtitle(state, "Annual Cost");
    4161            2 :                     OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    4162              :                 }
    4163            3 :                 if (produceSQLite) {
    4164            2 :                     if (state.dataSQLiteProcedures->sqlite) {
    4165            2 :                         state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    4166              :                             tableBody, rowHead, columnHead, "Economics Results Summary Report", "Entire Facility", "Annual Cost");
    4167              :                     }
    4168              :                 }
    4169            3 :                 if (produceTabular) {
    4170            2 :                     if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    4171            0 :                         state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    4172              :                             tableBody, rowHead, columnHead, "Economics Results Summary Report", "Entire Facility", "Annual Cost");
    4173              :                     }
    4174              :                 }
    4175            3 :                 columnHead.deallocate();
    4176            3 :                 rowHead.deallocate();
    4177            3 :                 columnWidth.deallocate();
    4178            3 :                 tableBody.deallocate();
    4179            3 :             }
    4180              :             //---- Tariff Summary
    4181            2 :             rowHead.allocate(s_econ->numTariff);
    4182            2 :             columnHead.allocate(6);
    4183            2 :             columnWidth.allocate(6);
    4184            2 :             tableBody.allocate(6, s_econ->numTariff);
    4185            2 :             tableBody = "";
    4186            2 :             columnHead(1) = "Selected";
    4187            2 :             columnHead(2) = "Qualified";
    4188            2 :             columnHead(3) = "Meter";
    4189            2 :             columnHead(4) = "Buy or Sell";
    4190            2 :             columnHead(5) = "Group";
    4191            2 :             columnHead(6) = "Annual Cost (~~$~~)";
    4192            4 :             for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    4193            2 :                 auto const &tariff = s_econ->tariff(iTariff);
    4194            2 :                 rowHead(iTariff) = tariff.tariffName;
    4195            2 :                 tableBody(1, iTariff) = yesNoNames[(int)tariff.isSelected];
    4196            2 :                 tableBody(2, iTariff) = yesNoNames[(int)tariff.isQualified];
    4197              : 
    4198            2 :                 tableBody(3, iTariff) = tariff.reportMeter;
    4199              : 
    4200            2 :                 if (tariff.buyOrSell == BuySell::BuyFromUtility) {
    4201            0 :                     tableBody(4, iTariff) = "Buy";
    4202            2 :                 } else if (tariff.buyOrSell == BuySell::SellToUtility) {
    4203            0 :                     tableBody(4, iTariff) = "Sell";
    4204            2 :                 } else if (tariff.buyOrSell == BuySell::NetMetering) {
    4205            2 :                     tableBody(4, iTariff) = "Net";
    4206              :                 }
    4207              : 
    4208            2 :                 if (tariff.groupName == "") {
    4209            2 :                     tableBody(5, iTariff) = "(none)";
    4210              :                 } else {
    4211            0 :                     tableBody(5, iTariff) = tariff.groupName;
    4212              :                 }
    4213            2 :                 tableBody(6, iTariff) = OutputReportTabular::RealToStr(tariff.totalAnnualCost, 2);
    4214              :             }
    4215            2 :             columnWidth = 14; // array assignment - same for all columns
    4216            2 :             OutputReportTabular::WriteSubtitle(state, "Tariff Summary");
    4217            2 :             OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    4218            2 :             if (state.dataSQLiteProcedures->sqlite) {
    4219            2 :                 state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    4220              :                     tableBody, rowHead, columnHead, "Economics Results Summary Report", "Entire Facility", "Tariff Summary");
    4221              :             }
    4222            2 :             if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    4223            0 :                 state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    4224              :                     tableBody, rowHead, columnHead, "Economics Results Summary Report", "Entire Facility", "Tariff Summary");
    4225              :             }
    4226            2 :             columnHead.deallocate();
    4227            2 :             rowHead.deallocate();
    4228            2 :             columnWidth.deallocate();
    4229            2 :             tableBody.deallocate();
    4230              :         }
    4231              :         //---------------------------------
    4232              :         // Tariff Report
    4233              :         //---------------------------------
    4234            2 :         if (state.dataOutRptTab->displayTariffReport) {
    4235            0 :             for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    4236            0 :                 auto const &tariff = s_econ->tariff(iTariff);
    4237            0 :                 auto const &computation = s_econ->computation(iTariff);
    4238            0 :                 OutputReportTabular::WriteReportHeaders(state, "Tariff Report", tariff.tariffName, OutputProcessor::StoreType::Average);
    4239            0 :                 rowHead.allocate(7);
    4240            0 :                 columnHead.allocate(1);
    4241            0 :                 columnWidth.allocate(1);
    4242            0 :                 tableBody.allocate(1, 7);
    4243            0 :                 tableBody = "";
    4244            0 :                 columnHead(1) = "Parameter";
    4245            0 :                 rowHead(1) = "Meter";
    4246            0 :                 rowHead(2) = "Selected";
    4247            0 :                 rowHead(3) = "Group";
    4248            0 :                 rowHead(4) = "Qualified";
    4249            0 :                 rowHead(5) = "Disqualifier";
    4250            0 :                 rowHead(6) = "Computation";
    4251            0 :                 rowHead(7) = "Units";
    4252            0 :                 tableBody(1, 1) = tariff.reportMeter;
    4253            0 :                 if (tariff.isSelected) {
    4254            0 :                     tableBody(1, 2) = "Yes";
    4255              :                 } else {
    4256            0 :                     tableBody(1, 2) = "No";
    4257              :                 }
    4258            0 :                 if (tariff.groupName == "") {
    4259            0 :                     tableBody(1, 3) = "(none)";
    4260              :                 } else {
    4261            0 :                     tableBody(1, 3) = tariff.groupName;
    4262              :                 }
    4263            0 :                 if (tariff.isQualified) {
    4264            0 :                     tableBody(1, 4) = "Yes";
    4265              :                 } else {
    4266            0 :                     tableBody(1, 4) = "No";
    4267              :                 }
    4268            0 :                 if (tariff.isQualified) {
    4269            0 :                     tableBody(1, 5) = "n/a";
    4270              :                 } else {
    4271            0 :                     tableBody(1, 5) = econVar(tariff.ptDisqualifier).name;
    4272              :                 }
    4273            0 :                 if (computation.isUserDef) {
    4274            0 :                     tableBody(1, 6) = computation.computeName;
    4275              :                 } else {
    4276            0 :                     tableBody(1, 6) = "automatic";
    4277              :                 }
    4278            0 :                 switch (tariff.convChoice) {
    4279            0 :                 case EconConv::USERDEF: {
    4280            0 :                     tableBody(1, 7) = "User Defined";
    4281            0 :                 } break;
    4282            0 :                 case EconConv::KWH: {
    4283            0 :                     tableBody(1, 7) = "kWh";
    4284            0 :                 } break;
    4285            0 :                 case EconConv::THERM: {
    4286            0 :                     tableBody(1, 7) = "Therm";
    4287            0 :                 } break;
    4288            0 :                 case EconConv::MMBTU: {
    4289            0 :                     tableBody(1, 7) = "MMBtu";
    4290            0 :                 } break;
    4291            0 :                 case EconConv::MJ: {
    4292            0 :                     tableBody(1, 7) = "MJ";
    4293            0 :                 } break;
    4294            0 :                 case EconConv::KBTU: {
    4295            0 :                     tableBody(1, 7) = "kBtu";
    4296            0 :                 } break;
    4297            0 :                 case EconConv::MCF: {
    4298            0 :                     tableBody(1, 7) = "MCF";
    4299            0 :                 } break;
    4300            0 :                 case EconConv::CCF: {
    4301            0 :                     tableBody(1, 7) = "CCF";
    4302            0 :                 } break;
    4303            0 :                 default:
    4304            0 :                     break;
    4305              :                 }
    4306            0 :                 columnWidth = 14; // array assignment - same for all columns
    4307            0 :                 OutputReportTabular::WriteSubtitle(state, "General");
    4308            0 :                 OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    4309            0 :                 if (state.dataSQLiteProcedures->sqlite) {
    4310            0 :                     state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    4311              :                         tableBody, rowHead, columnHead, "Tariff Report", tariff.tariffName, "General");
    4312              :                 }
    4313            0 :                 if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    4314            0 :                     state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    4315            0 :                         tableBody, rowHead, columnHead, "Tariff Report", tariff.tariffName, "General");
    4316              :                 }
    4317            0 :                 columnHead.deallocate();
    4318            0 :                 rowHead.deallocate();
    4319            0 :                 columnWidth.deallocate();
    4320            0 :                 tableBody.deallocate();
    4321              :                 //---- Categories
    4322            0 :                 for (auto &e : econVar)
    4323            0 :                     e.activeNow = false;
    4324            0 :                 econVar(tariff.cats[(int)Cat::EnergyCharges]).activeNow = true;
    4325            0 :                 econVar(tariff.cats[(int)Cat::DemandCharges]).activeNow = true;
    4326            0 :                 econVar(tariff.cats[(int)Cat::ServiceCharges]).activeNow = true;
    4327            0 :                 econVar(tariff.cats[(int)Cat::Basis]).activeNow = true;
    4328            0 :                 econVar(tariff.cats[(int)Cat::Adjustment]).activeNow = true;
    4329            0 :                 econVar(tariff.cats[(int)Cat::Surcharge]).activeNow = true;
    4330            0 :                 econVar(tariff.cats[(int)Cat::Subtotal]).activeNow = true;
    4331            0 :                 econVar(tariff.cats[(int)Cat::Taxes]).activeNow = true;
    4332            0 :                 econVar(tariff.cats[(int)Cat::Total]).activeNow = true;
    4333            0 :                 ReportEconomicVariable(state, "Categories", false, true, tariff.tariffName);
    4334              :                 //---- Charges
    4335            0 :                 for (auto &e : econVar)
    4336            0 :                     e.activeNow = false;
    4337            0 :                 for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
    4338            0 :                     if (econVar(kVar).tariffIndx == iTariff) {
    4339            0 :                         if ((econVar(kVar).kindOfObj == ObjType::ChargeSimple) || (econVar(kVar).kindOfObj == ObjType::ChargeBlock)) {
    4340            0 :                             econVar(kVar).activeNow = true;
    4341              :                         }
    4342              :                     }
    4343              :                 }
    4344            0 :                 ReportEconomicVariable(state, "Charges", true, true, tariff.tariffName);
    4345              :                 //---- Sources for Charges
    4346            0 :                 for (auto &e : econVar)
    4347            0 :                     e.activeNow = false;
    4348            0 :                 for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
    4349            0 :                     if (econVar(kVar).tariffIndx == iTariff) {
    4350            0 :                         int indexInChg = econVar(kVar).index;
    4351            0 :                         if (econVar(kVar).kindOfObj == ObjType::ChargeSimple) {
    4352            0 :                             auto &chargeSimple = s_econ->chargeSimple(indexInChg);
    4353            0 :                             if (chargeSimple.sourcePt > 0) {
    4354            0 :                                 econVar(chargeSimple.sourcePt).activeNow = true;
    4355              :                             }
    4356            0 :                         } else if (econVar(kVar).kindOfObj == ObjType::ChargeBlock) {
    4357            0 :                             auto &chargeBlock = s_econ->chargeBlock(indexInChg);
    4358            0 :                             if (chargeBlock.sourcePt > 0) {
    4359            0 :                                 econVar(chargeBlock.sourcePt).activeNow = true;
    4360              :                             }
    4361              :                         }
    4362              :                     }
    4363              :                 }
    4364            0 :                 ReportEconomicVariable(state, "Corresponding Sources for Charges", false, false, tariff.tariffName);
    4365              :                 //---- Rachets
    4366            0 :                 for (auto &e : econVar)
    4367            0 :                     e.activeNow = false;
    4368            0 :                 for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
    4369            0 :                     if (econVar(kVar).tariffIndx == iTariff) {
    4370            0 :                         if (econVar(kVar).kindOfObj == ObjType::Ratchet) {
    4371            0 :                             econVar(kVar).activeNow = true;
    4372              :                         }
    4373              :                     }
    4374              :                 }
    4375            0 :                 ReportEconomicVariable(state, "Ratchets", false, false, tariff.tariffName);
    4376              :                 //---- Qualifies
    4377            0 :                 for (auto &e : econVar)
    4378            0 :                     e.activeNow = false;
    4379            0 :                 for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
    4380            0 :                     if (econVar(kVar).tariffIndx == iTariff) {
    4381            0 :                         if (econVar(kVar).kindOfObj == ObjType::Qualify) {
    4382            0 :                             econVar(kVar).activeNow = true;
    4383              :                         }
    4384              :                     }
    4385              :                 }
    4386            0 :                 ReportEconomicVariable(state, "Qualifies", false, false, tariff.tariffName);
    4387              :                 //---- Native Variables
    4388            0 :                 for (auto &e : econVar)
    4389            0 :                     e.activeNow = false;
    4390            0 :                 for (int kVar = tariff.firstNative; kVar <= tariff.lastNative; ++kVar) {
    4391            0 :                     econVar(kVar).activeNow = true;
    4392              :                 }
    4393            0 :                 ReportEconomicVariable(state, "Native Variables", false, false, tariff.tariffName);
    4394              :                 //---- Other Variables
    4395            0 :                 for (auto &e : econVar)
    4396            0 :                     e.activeNow = false;
    4397            0 :                 for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
    4398            0 :                     if (econVar(kVar).tariffIndx == iTariff) {
    4399            0 :                         if (!econVar(kVar).isReported) {
    4400            0 :                             econVar(kVar).activeNow = true;
    4401              :                         }
    4402              :                     }
    4403              :                 }
    4404            0 :                 ReportEconomicVariable(state, "Other Variables", false, false, tariff.tariffName);
    4405              :                 //---- Computation
    4406            0 :                 if (computation.isUserDef) {
    4407            0 :                     OutputReportTabular::WriteTextLine(state, "Computation -  User Defined", true);
    4408              :                 } else {
    4409            0 :                     OutputReportTabular::WriteTextLine(state, "Computation -  Automatic", true);
    4410              :                 }
    4411            0 :                 std::string outString = "";
    4412            0 :                 for (int lStep = computation.firstStep; lStep <= computation.lastStep; ++lStep) {
    4413            0 :                     auto &step = s_econ->steps(lStep);
    4414              : 
    4415            0 :                     if (step.type == StepType::EOL) {
    4416            0 :                         OutputReportTabular::WriteTextLine(state, rstrip(outString));
    4417            0 :                         outString = "";
    4418            0 :                     } else if (step.type == StepType::Var) {
    4419            0 :                         outString = econVar(step.varNum).name + ' ' + outString;
    4420            0 :                     } else if (step.type == StepType::Op) {
    4421            0 :                         outString = format("{} {}", opNamesUC[(int)step.op], outString);
    4422              :                     }
    4423              :                 }
    4424              :             }
    4425              :         }
    4426              :     }
    4427           75 : }
    4428              : 
    4429            2 : void showWarningsBasedOnTotal(EnergyPlusData &state)
    4430              : {
    4431              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    4432              :     //    DATE WRITTEN   July 2004
    4433              : 
    4434              :     //    Get the annual maximum and sum for the econVariable.
    4435              : 
    4436            2 :     auto &s_econ = state.dataEconTariff;
    4437            4 :     for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    4438            2 :         auto const &tariff = s_econ->tariff(iTariff);
    4439            2 :         if (tariff.buyOrSell == BuySell::BuyFromUtility) {
    4440            0 :             if (tariff.totalAnnualCost < 0) {
    4441            0 :                 ShowWarningError(state, "UtilityCost:Tariff: A negative annual total cost when buying electricity from a utility is unusual. ");
    4442            0 :                 ShowContinueError(state, format("  In UtilityCost:Tariff named {}", tariff.tariffName));
    4443              :             }
    4444            2 :         } else if (tariff.buyOrSell == BuySell::SellToUtility) {
    4445            0 :             if (tariff.totalAnnualCost > 0) {
    4446            0 :                 ShowWarningError(state, "UtilityCost:Tariff: A positive annual total cost when selling electricity to a utility is unusual. ");
    4447            0 :                 ShowContinueError(state, format("  In UtilityCost:Tariff named {}", tariff.tariffName));
    4448              :             }
    4449              :         }
    4450              :     }
    4451            2 : }
    4452              : 
    4453            0 : void getMaxAndSum(EnergyPlusData &state, int const varPointer, Real64 &sumResult, Real64 &maxResult)
    4454              : {
    4455              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    4456              :     //    DATE WRITTEN   July 2004
    4457              : 
    4458              :     //    Get the annual maximum and sum for the econVariable.
    4459              : 
    4460            0 :     Real64 maximumVal(0.0); // Autodesk Value not used but suppresses warning about HUGE_() call
    4461              : 
    4462            0 :     auto const &s_econ = state.dataEconTariff;
    4463            0 :     auto const &econVar = s_econ->econVar(varPointer);
    4464              : 
    4465            0 :     Real64 sumVal = 0.0;
    4466            0 :     maximumVal = -HUGE_(maximumVal);
    4467            0 :     for (int jMonth = 1; jMonth <= 12; ++jMonth) { // note not all months get printed out if more than 12 are used.- need to fix this later
    4468            0 :         Real64 curVal = econVar.values(jMonth);
    4469            0 :         sumVal += curVal;
    4470            0 :         if (curVal > maximumVal) {
    4471            0 :             maximumVal = curVal;
    4472              :         }
    4473              :     }
    4474            0 :     sumResult = sumVal;
    4475            0 :     maxResult = maximumVal;
    4476            0 : }
    4477              : 
    4478            0 : void ReportEconomicVariable(
    4479              :     EnergyPlusData &state, std::string const &titleString, bool const includeCategory, bool const showCurrencySymbol, std::string const &forString)
    4480              : {
    4481              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    4482              :     //    DATE WRITTEN   July 2004
    4483              :     //    MODIFIED       January 2010, Kyle Benne
    4484              :     //                   Added sqlite output
    4485              : 
    4486              :     //    Report all econVar that show as activeNow
    4487              : 
    4488              :     // all arrays are in the format: (row, column)
    4489            0 :     Array1D_string columnHead;
    4490            0 :     Array1D_int columnWidth;
    4491            0 :     Array1D_string rowHead;
    4492            0 :     Array2D_string tableBody;
    4493              :     Real64 sumVal;
    4494              :     Real64 maximumVal;
    4495              :     Real64 curVal;
    4496              :     int curIndex;
    4497              :     int curCatPt;
    4498              :     int curCategory;
    4499              : 
    4500              :     int iVar;
    4501              :     int jMonth;
    4502              :     int cntOfVar;
    4503              :     int nCntOfVar;
    4504              : 
    4505            0 :     auto const &s_econ = state.dataEconTariff;
    4506            0 :     auto const &econVar = s_econ->econVar;
    4507            0 :     auto const &chargeBlock = s_econ->chargeBlock;
    4508            0 :     auto const &chargeSimple = s_econ->chargeSimple;
    4509              : 
    4510            0 :     cntOfVar = 0;
    4511            0 :     for (iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
    4512            0 :         if (econVar(iVar).activeNow) {
    4513            0 :             ++cntOfVar;
    4514              :         }
    4515              :     }
    4516            0 :     if (includeCategory) {
    4517            0 :         rowHead.allocate(cntOfVar);
    4518            0 :         columnHead.allocate(15);
    4519            0 :         columnWidth.allocate(15);
    4520            0 :         tableBody.allocate(15, cntOfVar);
    4521              :     } else {
    4522            0 :         rowHead.allocate(cntOfVar);
    4523            0 :         columnHead.allocate(14);
    4524            0 :         columnWidth.allocate(14);
    4525            0 :         tableBody.allocate(14, cntOfVar);
    4526              :     }
    4527              :     // column names
    4528            0 :     columnHead(1) = "Jan";
    4529            0 :     columnHead(2) = "Feb";
    4530            0 :     columnHead(3) = "Mar";
    4531            0 :     columnHead(4) = "Apr";
    4532            0 :     columnHead(5) = "May";
    4533            0 :     columnHead(6) = "Jun";
    4534            0 :     columnHead(7) = "Jul";
    4535            0 :     columnHead(8) = "Aug";
    4536            0 :     columnHead(9) = "Sep";
    4537            0 :     columnHead(10) = "Oct";
    4538            0 :     columnHead(11) = "Nov";
    4539            0 :     columnHead(12) = "Dec";
    4540            0 :     columnHead(13) = "Sum";
    4541            0 :     columnHead(14) = "Max";
    4542            0 :     if (includeCategory) {
    4543            0 :         columnHead(15) = "Category";
    4544              :     }
    4545            0 :     nCntOfVar = 0;
    4546              :     // row names
    4547            0 :     for (iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
    4548            0 :         if (econVar(iVar).activeNow) {
    4549            0 :             ++nCntOfVar;
    4550            0 :             if (showCurrencySymbol) {
    4551            0 :                 rowHead(nCntOfVar) = econVar(iVar).name + " (~~$~~)";
    4552              :             } else {
    4553            0 :                 rowHead(nCntOfVar) = econVar(iVar).name;
    4554              :             }
    4555              :         }
    4556              :     }
    4557              :     // fill the body
    4558            0 :     nCntOfVar = 0;
    4559            0 :     for (iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
    4560            0 :         if (econVar(iVar).activeNow) {
    4561            0 :             ++nCntOfVar;
    4562            0 :             for (jMonth = 1; jMonth <= 12; ++jMonth) { // note not all months get printed out if more than 12 are used.- need to fix this later
    4563            0 :                 curVal = econVar(iVar).values(jMonth);
    4564            0 :                 if ((curVal > 0) && (curVal < 1)) {
    4565            0 :                     tableBody(jMonth, nCntOfVar) = OutputReportTabular::RealToStr(curVal, 4);
    4566              :                 } else {
    4567            0 :                     tableBody(jMonth, nCntOfVar) = OutputReportTabular::RealToStr(curVal, 2);
    4568              :                 }
    4569              :             }
    4570            0 :             getMaxAndSum(state, iVar, sumVal, maximumVal);
    4571            0 :             tableBody(13, nCntOfVar) = OutputReportTabular::RealToStr(sumVal, 2);
    4572            0 :             tableBody(14, nCntOfVar) = OutputReportTabular::RealToStr(maximumVal, 2);
    4573            0 :             if (includeCategory) {
    4574              :                 // first find category
    4575            0 :                 curCategory = 0;
    4576            0 :                 curIndex = econVar(iVar).index;
    4577              : 
    4578            0 :                 switch (econVar(iVar).kindOfObj) {
    4579            0 :                 case ObjType::ChargeSimple:
    4580            0 :                     if ((curIndex >= 1) && (curIndex <= s_econ->numChargeSimple)) {
    4581            0 :                         curCatPt = chargeSimple(curIndex).categoryPt;
    4582              :                     }
    4583            0 :                     break;
    4584            0 :                 case ObjType::ChargeBlock:
    4585            0 :                     if ((curIndex >= 1) && (curIndex <= s_econ->numChargeBlock)) {
    4586            0 :                         curCatPt = chargeBlock(curIndex).categoryPt;
    4587              :                     }
    4588            0 :                     break;
    4589            0 :                 default:
    4590            0 :                     break;
    4591              :                 }
    4592              : 
    4593            0 :                 if ((curCatPt >= 1) && (curCatPt <= s_econ->numEconVar)) {
    4594            0 :                     curCategory = econVar(curCatPt).specific;
    4595              :                 }
    4596              : 
    4597              :                 // In this specific table, "NotIncluded" is written as "none" so need a special case for that
    4598            0 :                 tableBody(15, nCntOfVar) =
    4599            0 :                     (econVar(curCatPt).kindOfObj == ObjType::Category)
    4600            0 :                         ? ((econVar(curCatPt).specific == (int)Cat::NotIncluded) ? "none" : catNames[econVar(curCatPt).specific])
    4601            0 :                         : "none";
    4602              :             }
    4603            0 :             s_econ->econVar(iVar).isReported = true;
    4604              :         }
    4605              :     }
    4606            0 :     columnWidth = 14; // array assignment - same for all columns
    4607            0 :     OutputReportTabular::WriteSubtitle(state, titleString);
    4608            0 :     OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    4609            0 :     if (state.dataSQLiteProcedures->sqlite) {
    4610            0 :         state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(tableBody, rowHead, columnHead, "Tariff Report", forString, titleString);
    4611              :     }
    4612            0 :     if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    4613            0 :         state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    4614              :             tableBody, rowHead, columnHead, "Tariff Report", forString, titleString);
    4615              :     }
    4616            0 :     columnHead.deallocate();
    4617            0 :     rowHead.deallocate();
    4618            0 :     columnWidth.deallocate();
    4619            0 :     tableBody.deallocate();
    4620            0 : }
    4621              : 
    4622            0 : void selectTariff(EnergyPlusData &state)
    4623              : {
    4624              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    4625              :     //    DATE WRITTEN   July 2004
    4626              : 
    4627              :     //    To select tariffs for each combination of meter and
    4628              :     //    group.  If multiple tariffs have the same meter and
    4629              :     //    group, then select the one with the lowest cost.
    4630              :     //    For electric tariffs, since they may have buy, sell, or
    4631              :     //    netmetering, they need to be combined more carefully.
    4632              :     //    Multiple meters are used but buy + sell might be more or
    4633              :     //    less expensive than netmeter.
    4634              : 
    4635            0 :     Array1D_int groupIndex;     // index number (in tariff) for the group name
    4636            0 :     Array1D_int MinTariffIndex; // tariff index for the Minimum value
    4637              :     int curMinTariffIndex;
    4638              : 
    4639            0 :     auto const &s_econ = state.dataEconTariff;
    4640            0 :     auto const &econVar(s_econ->econVar);
    4641              : 
    4642            0 :     groupIndex.dimension(s_econ->numTariff, 0);
    4643            0 :     int groupCount = 0;
    4644            0 :     int numMins = 0;
    4645            0 :     MinTariffIndex.dimension(s_econ->numTariff, 0);
    4646            0 :     for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    4647            0 :         auto &tariff = s_econ->tariff(iTariff);
    4648              :         // compute the total annual cost of each tariff
    4649            0 :         int totalVarPt = tariff.cats[(int)Cat::Total];
    4650            0 :         int totEneVarPt = tariff.natives[(int)Native::TotalEnergy];
    4651            0 :         Real64 annualTotal = 0.0;
    4652            0 :         Real64 annEneTotal = 0.0;
    4653            0 :         for (int jMonth = 1; jMonth <= NumMonths; ++jMonth) {
    4654            0 :             annualTotal += econVar(totalVarPt).values(jMonth);
    4655            0 :             annEneTotal += econVar(totEneVarPt).values(jMonth);
    4656              :         }
    4657            0 :         tariff.totalAnnualCost = annualTotal;
    4658            0 :         tariff.totalAnnualEnergy = annEneTotal;
    4659              :         // Set the groupIndex
    4660            0 :         if (groupIndex(iTariff) == 0) {
    4661              :             // set the current item to the tariff index
    4662            0 :             ++groupCount;
    4663            0 :             groupIndex(iTariff) = groupCount;
    4664              :             // set all remaining matching items to the same index
    4665            0 :             for (int kTariff = iTariff + 1; kTariff <= s_econ->numTariff; ++kTariff) {
    4666            0 :                 if (Util::SameString(s_econ->tariff(kTariff).groupName, tariff.groupName)) {
    4667            0 :                     groupIndex(kTariff) = groupCount;
    4668              :                 }
    4669              :             }
    4670              :         }
    4671              :     }
    4672              :     // First process the all tariff and identify the lowest cost for each type of meter and group.
    4673            0 :     for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    4674            0 :         auto &tariff = s_econ->tariff(iTariff);
    4675            0 :         if (tariff.isQualified) {
    4676            0 :             bool isFound = false;
    4677            0 :             for (int lMin = 1; lMin <= numMins; ++lMin) {
    4678            0 :                 curMinTariffIndex = MinTariffIndex(lMin);
    4679              :                 // find matching meter and group
    4680            0 :                 if (tariff.reportMeterIndx == s_econ->tariff(curMinTariffIndex).reportMeterIndx) {
    4681            0 :                     if (groupIndex(iTariff) == groupIndex(curMinTariffIndex)) {
    4682            0 :                         isFound = true;
    4683              :                         // found the matching mater and group now test if smaller Min is current tariff
    4684            0 :                         if (tariff.totalAnnualCost < s_econ->tariff(curMinTariffIndex).totalAnnualCost) {
    4685            0 :                             MinTariffIndex(lMin) = iTariff;
    4686              :                             // select the new Minimum tariff and deselect the one that was just exceeded
    4687            0 :                             s_econ->tariff(curMinTariffIndex).isSelected = false;
    4688            0 :                             tariff.isSelected = true;
    4689              :                         }
    4690              :                     }
    4691              :                 }
    4692              :             }
    4693            0 :             if (!isFound) {
    4694            0 :                 ++numMins;
    4695            0 :                 if (numMins > s_econ->numTariff) {
    4696            0 :                     ShowWarningError(state, "UtilityCost:Tariff Debugging error numMins greater than numTariff.");
    4697              :                 }
    4698            0 :                 MinTariffIndex(numMins) = iTariff;
    4699              :                 // tariff(numMins)%isSelected = .TRUE.  !original
    4700            0 :                 tariff.isSelected = true; // BTG changed 2/7/2005     CR6573
    4701              :             }
    4702              :         }
    4703              :     }
    4704              :     // Now select for the electric meters. If electric buying and selling and netmetering all are going
    4705              :     // on, need to determine which combination should be selected. Within each group select just one set
    4706              :     // of electric results.  The electric results can be either the buy rate only, the buy rate plus the
    4707              :     // sell rate, or the netmetering rate, whichever of these three is the lowest combination.
    4708              :     // (The kindElectricMtr was assigned in GetInputEconomicsTariff)
    4709            0 :     for (int mGroup = 1; mGroup <= groupCount; ++mGroup) {
    4710            0 :         int lowestSimpleTariff = 0;
    4711            0 :         int lowestPurchaseTariff = 0;
    4712            0 :         int lowestSurplusSoldTariff = 0;
    4713            0 :         int lowestNetMeterTariff = 0;
    4714            0 :         for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    4715            0 :             auto &tariff = s_econ->tariff(iTariff);
    4716            0 :             if (tariff.isQualified) {
    4717            0 :                 if (tariff.isSelected) {
    4718            0 :                     if (groupIndex(iTariff) == mGroup) {
    4719            0 :                         if (tariff.kindMtr == MeterType::ElecSimple) {
    4720            0 :                             lowestSimpleTariff = iTariff;
    4721            0 :                         } else if (tariff.kindMtr == MeterType::ElecProduced) {
    4722              :                             // don't show electric produced rates as ever selected since surplus sold is more relevant
    4723            0 :                             tariff.isSelected = false;
    4724            0 :                         } else if (tariff.kindMtr == MeterType::ElecPurchased) {
    4725            0 :                             lowestPurchaseTariff = iTariff;
    4726            0 :                         } else if (tariff.kindMtr == MeterType::ElecSurplusSold) {
    4727            0 :                             lowestSurplusSoldTariff = iTariff;
    4728            0 :                         } else if (tariff.kindMtr == MeterType::ElecNet) {
    4729            0 :                             lowestNetMeterTariff = iTariff;
    4730              :                         }
    4731              :                     }
    4732              :                 }
    4733              :             }
    4734              :         }
    4735              :         // compare the simple and purchased metered tariffs
    4736            0 :         if ((lowestSimpleTariff > 0) && (lowestPurchaseTariff > 0)) {
    4737            0 :             if (s_econ->tariff(lowestSimpleTariff).totalAnnualCost < s_econ->tariff(lowestPurchaseTariff).totalAnnualCost) {
    4738            0 :                 s_econ->tariff(lowestPurchaseTariff).isSelected = false;
    4739            0 :                 lowestPurchaseTariff = 0;
    4740              :             } else {
    4741            0 :                 s_econ->tariff(lowestSimpleTariff).isSelected = false;
    4742            0 :                 lowestSimpleTariff = 0;
    4743              :             }
    4744              :         }
    4745              :         // if surplus sold is negative use it otherwise don't
    4746            0 :         if (lowestSurplusSoldTariff > 0) {
    4747            0 :             if (s_econ->tariff(lowestSurplusSoldTariff).totalAnnualCost > 0) {
    4748            0 :                 s_econ->tariff(lowestSurplusSoldTariff).isSelected = false;
    4749            0 :                 lowestSurplusSoldTariff = 0;
    4750              :             }
    4751              :         }
    4752              :         // if netmetering is used compare it to simple plus surplus
    4753            0 :         if (((lowestNetMeterTariff > 0) && (lowestSurplusSoldTariff > 0)) && (lowestSimpleTariff > 0)) {
    4754            0 :             if (s_econ->tariff(lowestNetMeterTariff).totalAnnualCost <
    4755            0 :                 (s_econ->tariff(lowestSimpleTariff).totalAnnualCost + s_econ->tariff(lowestSurplusSoldTariff).totalAnnualCost)) {
    4756            0 :                 s_econ->tariff(lowestSimpleTariff).isSelected = false;
    4757            0 :                 lowestSimpleTariff = 0;
    4758            0 :                 s_econ->tariff(lowestSurplusSoldTariff).isSelected = false;
    4759            0 :                 lowestSurplusSoldTariff = 0;
    4760              :             } else {
    4761            0 :                 s_econ->tariff(lowestNetMeterTariff).isSelected = false;
    4762            0 :                 lowestNetMeterTariff = 0;
    4763              :             }
    4764              :         }
    4765              :         // if netmetering is used compare it to purchased plus surplus
    4766            0 :         if (((lowestNetMeterTariff > 0) && (lowestSurplusSoldTariff > 0)) && (lowestPurchaseTariff > 0)) {
    4767            0 :             if (s_econ->tariff(lowestNetMeterTariff).totalAnnualCost <
    4768            0 :                 (s_econ->tariff(lowestPurchaseTariff).totalAnnualCost + s_econ->tariff(lowestSurplusSoldTariff).totalAnnualCost)) {
    4769            0 :                 s_econ->tariff(lowestPurchaseTariff).isSelected = false;
    4770            0 :                 lowestPurchaseTariff = 0;
    4771            0 :                 s_econ->tariff(lowestSurplusSoldTariff).isSelected = false;
    4772              :                 // lowestSurplusSoldTariff = 0; // not used after this point
    4773              :             } else {
    4774            0 :                 s_econ->tariff(lowestNetMeterTariff).isSelected = false;
    4775            0 :                 lowestNetMeterTariff = 0;
    4776              :             }
    4777              :         }
    4778              :         // if netmetering is used compare it to simple only
    4779            0 :         if ((lowestNetMeterTariff > 0) && (lowestSimpleTariff > 0)) {
    4780            0 :             if (s_econ->tariff(lowestNetMeterTariff).totalAnnualCost < s_econ->tariff(lowestSimpleTariff).totalAnnualCost) {
    4781            0 :                 s_econ->tariff(lowestSimpleTariff).isSelected = false;
    4782              :                 // lowestSimpleTariff = 0; // not used after this point
    4783              :             } else {
    4784            0 :                 s_econ->tariff(lowestNetMeterTariff).isSelected = false;
    4785            0 :                 lowestNetMeterTariff = 0;
    4786              :             }
    4787              :         }
    4788              :         // if netmetering is used compare it to purchased only
    4789            0 :         if ((lowestNetMeterTariff > 0) && (lowestPurchaseTariff > 0)) {
    4790            0 :             if (s_econ->tariff(lowestNetMeterTariff).totalAnnualCost < s_econ->tariff(lowestPurchaseTariff).totalAnnualCost) {
    4791            0 :                 s_econ->tariff(lowestPurchaseTariff).isSelected = false;
    4792              :                 // lowestPurchaseTariff = 0; // not used after this point
    4793              :             } else {
    4794            0 :                 s_econ->tariff(lowestNetMeterTariff).isSelected = false;
    4795              :                 // lowestNetMeterTariff = 0; // not used after this point
    4796              :             }
    4797              :         }
    4798              :     }
    4799            0 :     groupIndex.deallocate();
    4800            0 :     MinTariffIndex.deallocate();
    4801            0 : }
    4802              : 
    4803           48 : void GetMonthlyCostForResource(EnergyPlusData &state, Constant::eResource const inResourceNumber, Array1A<Real64> outMonthlyCosts)
    4804              : {
    4805              :     //       AUTHOR         Jason Glazer
    4806              :     //       DATE WRITTEN   May 2010
    4807              : 
    4808              :     //  Return the total annual cost for a given resource number.
    4809              : 
    4810              :     // Argument array dimensioning
    4811           48 :     auto const &s_econ = state.dataEconTariff;
    4812              : 
    4813           48 :     outMonthlyCosts.dim(12);
    4814              : 
    4815           48 :     outMonthlyCosts = 0.0;
    4816           96 :     for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
    4817           48 :         auto const &tariff = s_econ->tariff(iTariff);
    4818           48 :         if (tariff.isSelected) {
    4819           48 :             if (tariff.resource == inResourceNumber) {
    4820            1 :                 auto const &econVar = s_econ->econVar(tariff.cats[(int)Cat::Total]);
    4821           13 :                 for (int jMonth = 1; jMonth <= 12; ++jMonth) { // use 12 because LCC assume 12 months
    4822           12 :                     outMonthlyCosts(jMonth) += econVar.values(jMonth);
    4823              :                 }
    4824              :             }
    4825              :         }
    4826              :     }
    4827           48 : }
    4828              : 
    4829              : } // namespace EnergyPlus::EconomicTariff
        

Generated by: LCOV version 2.0-1