LCOV - code coverage report
Current view: top level - EnergyPlus - EconomicLifeCycleCost.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 76.3 % 1140 870
Test Date: 2025-06-02 07:23:51 Functions: 100.0 % 12 12

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/Fmath.hh>
      53              : #include <ObjexxFCL/string.functions.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <EnergyPlus/CostEstimateManager.hh>
      57              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      58              : #include <EnergyPlus/DataGlobalConstants.hh>
      59              : #include <EnergyPlus/DataIPShortCuts.hh>
      60              : #include <EnergyPlus/DisplayRoutines.hh>
      61              : #include <EnergyPlus/EconomicLifeCycleCost.hh>
      62              : #include <EnergyPlus/EconomicTariff.hh>
      63              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      64              : #include <EnergyPlus/OutputReportTabular.hh>
      65              : #include <EnergyPlus/ResultsFramework.hh>
      66              : #include <EnergyPlus/SQLiteProcedures.hh>
      67              : #include <EnergyPlus/UtilityRoutines.hh>
      68              : 
      69              : namespace EnergyPlus::EconomicLifeCycleCost {
      70              : 
      71              : // Module containing the routines dealing with the EconomicLifeCycleCost
      72              : 
      73              : // MODULE INFORMATION:
      74              : //       AUTHOR         Jason Glazer of GARD Analytics, Inc.
      75              : //       DATE WRITTEN   May 2010
      76              : //       MODIFIED       na
      77              : //       RE-ENGINEERED  na
      78              : 
      79              : // PURPOSE OF THIS MODULE:
      80              : //   To compute life-cycle cost measures such as present value based
      81              : //   on input provided by the user as well as calculated energy costs.
      82              : 
      83              : // METHODOLOGY EMPLOYED:
      84              : //   Uses NIST Handbook 135 "Life-Cycle Costing Manual for the Federal
      85              : //   Energy Management Program" for most computations.
      86              : 
      87              : // REFERENCES:
      88              : //   To compute the net present value for all costs entered in the
      89              : //   LifeCycleCosts objects, the algorithms from NIST Handbook 135
      90              : //   "Life-Cycle Costing Manual for the Federal Energy Management
      91              : //   Program" will be used as the primary source. Supplemental sources
      92              : //   of algorithms will be derived from ASTM E833-09a "Standard
      93              : //   Terminology of Building Economics", ASTM E917-05 "Standard
      94              : //   Practice for Measuring Life-Cycle Cost of Buildings and Building
      95              : //   Systems", and "Engineering Economic Analysis, Ninth Edition", by
      96              : //   Donald Newnan, Ted Eschenback, and Jerome Lavelle.
      97              : 
      98          800 : void GetInputForLifeCycleCost(EnergyPlusData &state)
      99              : {
     100              :     // SUBROUTINE INFORMATION:
     101              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
     102              :     //    DATE WRITTEN   May 2010
     103              :     //    MODIFIED       na
     104              :     //    RE-ENGINEERED  na
     105              : 
     106              :     // PURPOSE OF THIS SUBROUTINE:
     107              :     //    Read the input file for "LifeCycleCost:Parameters" object.
     108              : 
     109          800 :     if (state.dataEconLifeCycleCost->GetInput_GetLifeCycleCostInput) {
     110          800 :         GetInputLifeCycleCostParameters(state);
     111          800 :         GetInputLifeCycleCostRecurringCosts(state);
     112          800 :         GetInputLifeCycleCostNonrecurringCost(state);
     113          800 :         GetInputLifeCycleCostUsePriceEscalation(state);
     114          800 :         GetInputLifeCycleCostUseAdjustment(state);
     115          800 :         state.dataEconLifeCycleCost->GetInput_GetLifeCycleCostInput = false;
     116              :     }
     117          800 : }
     118              : 
     119          799 : void ComputeLifeCycleCostAndReport(EnergyPlusData &state)
     120              : {
     121              :     // SUBROUTINE INFORMATION:
     122              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
     123              :     //    DATE WRITTEN   May 2010
     124              :     //    MODIFIED       na
     125              :     //    RE-ENGINEERED  na
     126              : 
     127              :     // PURPOSE OF THIS SUBROUTINE:
     128              :     //    Perform the life cycle cost computations and write report.
     129              : 
     130          799 :     if (state.dataEconLifeCycleCost->LCCparamPresent) {
     131            2 :         DisplayString(state, "Computing Life Cycle Costs and Reporting");
     132            2 :         ExpressAsCashFlows(state);
     133            2 :         ComputePresentValue(state);
     134            2 :         ComputeEscalatedEnergyCosts(state);
     135            2 :         ComputeTaxAndDepreciation(state);
     136            2 :         WriteTabularLifeCycleCostReport(state);
     137              :     }
     138          799 : }
     139              : 
     140              : //======================================================================================================================
     141              : //======================================================================================================================
     142              : 
     143              : //    GET INPUT ROUTINES
     144              : 
     145              : //======================================================================================================================
     146              : //======================================================================================================================
     147              : 
     148          800 : void GetInputLifeCycleCostParameters(EnergyPlusData &state)
     149              : {
     150              :     // SUBROUTINE INFORMATION:
     151              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
     152              :     //    DATE WRITTEN   May 2010
     153              : 
     154              :     // PURPOSE OF THIS SUBROUTINE:
     155              :     //    Read the input file for "LifeCycleCost:Parameters" object.
     156              : 
     157              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     158              : 
     159              :     int jFld;                        // loop counter
     160              :     int NumFields;                   // Total number of elements
     161              :     int NumAlphas;                   // Number of elements in the alpha array
     162              :     int NumNums;                     // Number of elements in the numeric array
     163          800 :     Array1D_string AlphaArray;       // character string data
     164          800 :     Array1D<Real64> NumArray;        // numeric data
     165              :     int IOStat;                      // IO Status when calling get input subroutine
     166          800 :     std::string CurrentModuleObject; // for ease in renaming.
     167              :     int NumObj;                      // count of objects
     168              : 
     169          800 :     CurrentModuleObject = "LifeCycleCost:Parameters";
     170          800 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNums);
     171          800 :     NumArray.allocate(NumNums);
     172          800 :     AlphaArray.allocate(NumAlphas);
     173          800 :     NumObj = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     174              : 
     175          800 :     auto const &elcc = state.dataEconLifeCycleCost;
     176              : 
     177          800 :     if (NumObj == 0) {
     178          798 :         elcc->LCCparamPresent = false;
     179            2 :     } else if (NumObj == 1) {
     180            2 :         elcc->LCCparamPresent = true;
     181            4 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     182              :                                                                  CurrentModuleObject,
     183              :                                                                  1,
     184              :                                                                  AlphaArray,
     185              :                                                                  NumAlphas,
     186              :                                                                  NumArray,
     187              :                                                                  NumNums,
     188              :                                                                  IOStat,
     189            2 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
     190            2 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     191            2 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     192            2 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     193              :         // check to make sure none of the values are another life cycle cost object
     194           14 :         for (jFld = 1; jFld <= NumAlphas; ++jFld) {
     195           12 :             if (hasi(AlphaArray(jFld), "LifeCycleCost:")) {
     196            0 :                 ShowWarningError(state,
     197            0 :                                  format("In {} named {} a field was found containing LifeCycleCost: which may indicate a missing comma.",
     198              :                                         CurrentModuleObject,
     199              :                                         AlphaArray(1)));
     200              :             }
     201              :         }
     202              :         // start to extract values from input array into appropriate fields
     203              :         //  A1,  \field Name
     204              :         //       \required-field
     205              :         //       \type alpha
     206            2 :         elcc->LCCname = AlphaArray(1);
     207              :         //  A2, \field Discounting Convention
     208              :         //      \type choice
     209              :         //      \key EndOfYear
     210              :         //      \key MidYear
     211              :         //      \key BeginningOfYear
     212              :         //      \default EndOfYear
     213            2 :         elcc->discountConvention = static_cast<DiscConv>(getEnumValue(DiscConvNamesUC, Util::makeUPPER(AlphaArray(2))));
     214            2 :         if (elcc->discountConvention == DiscConv::Invalid) {
     215            0 :             elcc->discountConvention = DiscConv::EndOfYear;
     216            0 :             ShowWarningError(
     217              :                 state,
     218            0 :                 format(
     219            0 :                     "{}: Invalid {}=\"{}\". EndOfYear will be used.", CurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(2), AlphaArray(2)));
     220              :         }
     221              :         // A3,  \field Inflation Approach
     222              :         //      \type choice
     223              :         //      \key ConstantDollar
     224              :         //      \key CurrentDollar
     225              :         //      \default ConstantDollar
     226            2 :         elcc->inflationApproach = static_cast<InflAppr>(getEnumValue(InflApprNamesUC, Util::makeUPPER(AlphaArray(3))));
     227            2 :         if (elcc->inflationApproach == InflAppr::Invalid) {
     228            0 :             elcc->inflationApproach = InflAppr::ConstantDollar;
     229            0 :             ShowWarningError(state,
     230            0 :                              format("{}: Invalid {}=\"{}\". ConstantDollar will be used.",
     231              :                                     CurrentModuleObject,
     232            0 :                                     state.dataIPShortCut->cAlphaFieldNames(3),
     233              :                                     AlphaArray(3)));
     234              :         }
     235              :         // N1,  \field Real Discount Rate
     236              :         //      \type real
     237            2 :         elcc->realDiscountRate = NumArray(1);
     238            2 :         if ((elcc->inflationApproach == InflAppr::ConstantDollar) && state.dataIPShortCut->lNumericFieldBlanks(1)) {
     239            0 :             ShowWarningError(state,
     240            0 :                              format("{}: Invalid for field {} to be blank when ConstantDollar analysis is be used.",
     241              :                                     CurrentModuleObject,
     242            0 :                                     state.dataIPShortCut->cNumericFieldNames(1)));
     243              :         }
     244            2 :         if ((elcc->realDiscountRate > 0.30) || (elcc->realDiscountRate < -0.30)) {
     245            0 :             ShowWarningError(
     246              :                 state,
     247            0 :                 format("{}: Invalid value in field {}.  This value is the decimal value not a percentage so most values are between 0.02 and 0.15. ",
     248              :                        CurrentModuleObject,
     249            0 :                        state.dataIPShortCut->cNumericFieldNames(1)));
     250              :         }
     251              :         // N2,  \field Nominal Discount Rate
     252              :         //      \type real
     253            2 :         elcc->nominalDiscountRate = NumArray(2);
     254            2 :         if ((elcc->inflationApproach == InflAppr::CurrentDollar) && state.dataIPShortCut->lNumericFieldBlanks(2)) {
     255            0 :             ShowWarningError(state,
     256            0 :                              format("{}: Invalid for field {} to be blank when CurrentDollar analysis is be used.",
     257              :                                     CurrentModuleObject,
     258            0 :                                     state.dataIPShortCut->cNumericFieldNames(2)));
     259              :         }
     260            2 :         if ((elcc->nominalDiscountRate > 0.30) || (elcc->nominalDiscountRate < -0.30)) {
     261            0 :             ShowWarningError(
     262              :                 state,
     263            0 :                 format("{}: Invalid value in field {}.  This value is the decimal value not a percentage so most values are between 0.02 and 0.15. ",
     264              :                        CurrentModuleObject,
     265            0 :                        state.dataIPShortCut->cNumericFieldNames(2)));
     266              :         }
     267              :         // N3,  \field Inflation
     268              :         //      \type real
     269            2 :         elcc->inflation = NumArray(3);
     270            2 :         if ((elcc->inflationApproach == InflAppr::ConstantDollar) && (!state.dataIPShortCut->lNumericFieldBlanks(3))) {
     271            0 :             ShowWarningError(state,
     272            0 :                              format("{}: Invalid for field {} contain a value when ConstantDollar analysis is be used.",
     273              :                                     CurrentModuleObject,
     274            0 :                                     state.dataIPShortCut->cNumericFieldNames(3)));
     275              :         }
     276            2 :         if ((elcc->inflation > 0.30) || (elcc->inflation < -0.30)) {
     277            0 :             ShowWarningError(
     278              :                 state,
     279            0 :                 format("{}: Invalid value in field {}.  This value is the decimal value not a percentage so most values are between 0.02 and 0.15. ",
     280              :                        CurrentModuleObject,
     281            0 :                        state.dataIPShortCut->cNumericFieldNames(3)));
     282              :         }
     283              :         // A4,  \field Base Date Month
     284              :         //      \type choice
     285              :         //      \key January
     286              :         //      \key February
     287              :         //      \key March
     288              :         //      \key April
     289              :         //      \key May
     290              :         //      \key June
     291              :         //      \key July
     292              :         //      \key August
     293              :         //      \key September
     294              :         //      \key October
     295              :         //      \key November
     296              :         //      \key December
     297              :         //      \default January
     298            2 :         elcc->baseDateMonth = getEnumValue(Util::MonthNamesUC, Util::makeUPPER(AlphaArray(4)));
     299            2 :         if (elcc->baseDateMonth == -1) {
     300            0 :             elcc->baseDateMonth = 0;
     301            0 :             ShowWarningError(state,
     302            0 :                              format("{}: Invalid month entered in field {}. Using January instead of \"{}\"",
     303              :                                     CurrentModuleObject,
     304            0 :                                     state.dataIPShortCut->cAlphaFieldNames(4),
     305              :                                     AlphaArray(4)));
     306              :         }
     307              :         // N4,  \field Base Date Year
     308              :         //      \type integer
     309              :         //      \minimum 1900
     310              :         //      \maximum 2100
     311            2 :         elcc->baseDateYear = int(NumArray(4));
     312            2 :         if (elcc->baseDateYear > 2100) {
     313            0 :             ShowWarningError(state,
     314            0 :                              format("{}: Invalid value in field {}.  Value greater than 2100 yet it is representing a year. ",
     315              :                                     CurrentModuleObject,
     316            0 :                                     state.dataIPShortCut->cNumericFieldNames(4)));
     317              :         }
     318            2 :         if (elcc->baseDateYear < 1900) {
     319            0 :             ShowWarningError(state,
     320            0 :                              format("{}: Invalid value in field {}.  Value less than 1900 yet it is representing a year. ",
     321              :                                     CurrentModuleObject,
     322            0 :                                     state.dataIPShortCut->cNumericFieldNames(4)));
     323              :         }
     324              :         // A5,  \field Service Date Month
     325              :         //      \type choice
     326              :         //      \key January
     327              :         //      \key February
     328              :         //      \key March
     329              :         //      \key April
     330              :         //      \key May
     331              :         //      \key June
     332              :         //      \key July
     333              :         //      \key August
     334              :         //      \key September
     335              :         //      \key October
     336              :         //      \key November
     337              :         //      \key December
     338              :         //      \default January
     339            2 :         elcc->serviceDateMonth = getEnumValue(Util::MonthNamesUC, Util::makeUPPER(AlphaArray(5)));
     340            2 :         if (elcc->serviceDateMonth == -1) {
     341            0 :             elcc->serviceDateMonth = 0;
     342            0 :             ShowWarningError(state,
     343            0 :                              format("{}: Invalid month entered in field {}. Using January instead of \"{}\"",
     344              :                                     CurrentModuleObject,
     345            0 :                                     state.dataIPShortCut->cAlphaFieldNames(5),
     346              :                                     AlphaArray(5)));
     347              :         }
     348              :         // N5,  \field Service Date Year
     349              :         //      \type integer
     350              :         //      \minimum 1900
     351              :         //      \maximum 2100
     352            2 :         elcc->serviceDateYear = int(NumArray(5));
     353            2 :         if (elcc->serviceDateYear > 2100) {
     354            0 :             ShowWarningError(state,
     355            0 :                              format("{}: Invalid value in field {}.  Value greater than 2100 yet it is representing a year. ",
     356              :                                     CurrentModuleObject,
     357            0 :                                     state.dataIPShortCut->cNumericFieldNames(5)));
     358              :         }
     359            2 :         if (elcc->serviceDateYear < 1900) {
     360            0 :             ShowWarningError(state,
     361            0 :                              format("{}: Invalid value in field {}.  Value less than 1900 yet it is representing a year. ",
     362              :                                     CurrentModuleObject,
     363            0 :                                     state.dataIPShortCut->cNumericFieldNames(5)));
     364              :         }
     365              :         // N6,  \field Length of Study Period in Years
     366              :         //      \type integer
     367              :         //      \minimum 1
     368              :         //      \maximum 100
     369            2 :         elcc->lengthStudyYears = int(NumArray(6));
     370            2 :         if (elcc->lengthStudyYears > 100) {
     371            0 :             ShowWarningError(state,
     372            0 :                              format("{}: Invalid value in field {}.  A value greater than 100 is not reasonable for an economic evaluation. ",
     373              :                                     CurrentModuleObject,
     374            0 :                                     state.dataIPShortCut->cNumericFieldNames(6)));
     375              :         }
     376            2 :         if (elcc->lengthStudyYears < 1) {
     377            0 :             ShowWarningError(state,
     378            0 :                              format("{}: Invalid value in field {}.  A value less than 1 is not reasonable for an economic evaluation. ",
     379              :                                     CurrentModuleObject,
     380            0 :                                     state.dataIPShortCut->cNumericFieldNames(6)));
     381              :         }
     382            2 :         elcc->lengthStudyTotalMonths = elcc->lengthStudyYears * 12;
     383              :         // N7, \field Tax rate
     384              :         //      \type real
     385              :         //      \minimum 0.0
     386            2 :         elcc->taxRate = NumArray(7);
     387            2 :         if (elcc->taxRate < 0.0 && (!state.dataIPShortCut->lNumericFieldBlanks(7))) {
     388            0 :             ShowWarningError(state,
     389            0 :                              format("{}: Invalid value in field {}.  A value less than 0 is not reasonable for a tax rate. ",
     390              :                                     CurrentModuleObject,
     391            0 :                                     state.dataIPShortCut->cNumericFieldNames(10)));
     392              :         }
     393              :         // A6;  \field Depreciation Method
     394              :         //      \type choice
     395              :         //      \key ModifiedAcceleratedCostRecoverySystem-3year
     396              :         //      \key ModifiedAcceleratedCostRecoverySystem-5year
     397              :         //      \key ModifiedAcceleratedCostRecoverySystem-7year
     398              :         //      \key ModifiedAcceleratedCostRecoverySystem-10year
     399              :         //      \key ModifiedAcceleratedCostRecoverySystem-15year
     400              :         //      \key ModifiedAcceleratedCostRecoverySystem-20year
     401              :         //      \key StraightLine-27year
     402              :         //      \key StraightLine-31year
     403              :         //      \key StraightLine-39year
     404              :         //      \key StraightLine-40year
     405              :         //      \key None
     406              :         //      \default None
     407            2 :         elcc->depreciationMethod = static_cast<DeprMethod>(getEnumValue(DeprMethodNamesUC, Util::makeUPPER(AlphaArray(6))));
     408            2 :         if (elcc->depreciationMethod == DeprMethod::Invalid) {
     409            0 :             elcc->depreciationMethod = DeprMethod::None;
     410            0 :             if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
     411            0 :                 ShowWarningError(
     412              :                     state,
     413            0 :                     format("{}: The input field {}is blank. \"None\" will be used.", CurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(6)));
     414              :             } else {
     415            0 :                 ShowWarningError(state,
     416            0 :                                  format("{}: Invalid {}=\"{}{}",
     417              :                                         CurrentModuleObject,
     418            0 :                                         state.dataIPShortCut->cAlphaFieldNames(6),
     419              :                                         AlphaArray(6),
     420              :                                         R"(". "None" will be used.)"));
     421              :             }
     422              :         }
     423              :         // compute derived variables
     424            2 :         elcc->lastDateYear = elcc->baseDateYear + elcc->lengthStudyYears - 1;
     425              :     } else {
     426            0 :         ShowWarningError(
     427            0 :             state, format("{}: Only one instance of this object is allowed. No life-cycle cost reports will be generated.", CurrentModuleObject));
     428            0 :         elcc->LCCparamPresent = false;
     429              :     }
     430          800 : }
     431              : 
     432          800 : void GetInputLifeCycleCostRecurringCosts(EnergyPlusData &state)
     433              : {
     434              :     // SUBROUTINE INFORMATION:
     435              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
     436              :     //    DATE WRITTEN   May 2010
     437              : 
     438              :     // PURPOSE OF THIS SUBROUTINE:
     439              :     //    Read the input file for "LifeCycleCost:RecurringCosts" object.
     440              : 
     441              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     442              : 
     443              :     int iInObj;                      // loop index variable for reading in objects
     444              :     int jFld;                        // loop counter
     445              :     int NumFields;                   // Total number of elements
     446              :     int NumAlphas;                   // Number of elements in the alpha array
     447              :     int NumNums;                     // Number of elements in the numeric array
     448          800 :     Array1D_string AlphaArray;       // character string data
     449          800 :     Array1D<Real64> NumArray;        // numeric data
     450              :     int IOStat;                      // IO Status when calling get input subroutine
     451          800 :     std::string CurrentModuleObject; // for ease in renaming.
     452              : 
     453          800 :     auto &elcc(state.dataEconLifeCycleCost);
     454              : 
     455          800 :     if (!elcc->LCCparamPresent) {
     456          798 :         return;
     457              :     }
     458            2 :     CurrentModuleObject = "LifeCycleCost:RecurringCosts";
     459            2 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNums);
     460            2 :     NumArray.allocate(NumNums);
     461            2 :     AlphaArray.allocate(NumAlphas);
     462            2 :     elcc->numRecurringCosts = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     463            2 :     elcc->RecurringCosts.resize(elcc->numRecurringCosts);
     464            3 :     for (iInObj = 0; iInObj < elcc->numRecurringCosts; ++iInObj) {
     465            2 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     466              :                                                                  CurrentModuleObject,
     467              :                                                                  iInObj + 1, // since this index needs to start from 1
     468              :                                                                  AlphaArray,
     469              :                                                                  NumAlphas,
     470              :                                                                  NumArray,
     471              :                                                                  NumNums,
     472              :                                                                  IOStat,
     473            1 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
     474            1 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     475            1 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     476            1 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     477              :         // check to make sure none of the values are another life cycle cost object
     478            4 :         for (jFld = 1; jFld <= NumAlphas; ++jFld) {
     479            3 :             if (hasi(AlphaArray(jFld), "LifeCycleCost:")) {
     480            0 :                 ShowWarningError(state,
     481            0 :                                  format("In {} named {} a field was found containing LifeCycleCost: which may indicate a missing comma.",
     482              :                                         CurrentModuleObject,
     483              :                                         AlphaArray(1)));
     484              :             }
     485              :         }
     486              :         // start to extract values from input array into appropriate fields
     487              :         //   A1,  \field Name
     488              :         //        \required-field
     489              :         //        \type alpha
     490            1 :         elcc->RecurringCosts[iInObj].name = AlphaArray(1);
     491              :         //   A2,  \field Category
     492              :         //        \type choice
     493              :         //        \key Maintenance
     494              :         //        \key Repair
     495              :         //        \key Operation
     496              :         //        \key Replacement
     497              :         //        \key MinorOverhaul
     498              :         //        \key MajorOverhaul
     499              :         //        \key OtherOperational
     500              :         //        \default Maintenance
     501            1 :         elcc->RecurringCosts[iInObj].category = static_cast<CostCategory>(getEnumValue(CostCategoryNamesUCNoSpace, Util::makeUPPER(AlphaArray(2))));
     502              :         bool isNotRecurringCost =
     503            1 :             (elcc->RecurringCosts[iInObj].category != CostCategory::Maintenance && elcc->RecurringCosts[iInObj].category != CostCategory::Repair &&
     504            0 :              elcc->RecurringCosts[iInObj].category != CostCategory::Operation && elcc->RecurringCosts[iInObj].category != CostCategory::Replacement &&
     505            0 :              elcc->RecurringCosts[iInObj].category != CostCategory::MinorOverhaul &&
     506            1 :              elcc->RecurringCosts[iInObj].category != CostCategory::MajorOverhaul &&
     507            0 :              elcc->RecurringCosts[iInObj].category != CostCategory::OtherOperational);
     508            1 :         if (isNotRecurringCost) {
     509            0 :             elcc->RecurringCosts[iInObj].category = CostCategory::Maintenance;
     510            0 :             ShowWarningError(state,
     511            0 :                              format("{}: Invalid {}=\"{}\". The category of Maintenance will be used.",
     512              :                                     CurrentModuleObject,
     513            0 :                                     state.dataIPShortCut->cAlphaFieldNames(2),
     514              :                                     AlphaArray(2)));
     515              :         }
     516              :         //   N1,  \field Cost
     517              :         //        \type real
     518            1 :         elcc->RecurringCosts[iInObj].cost = NumArray(1);
     519              :         //   A3,  \field Start of Costs
     520              :         //        \type choice
     521              :         //        \key ServicePeriod
     522              :         //        \key BasePeriod
     523              :         //        \default ServicePeriod
     524            1 :         elcc->RecurringCosts[iInObj].startOfCosts = static_cast<StartCosts>(getEnumValue(StartCostNamesUC, Util::makeUPPER(AlphaArray(3))));
     525            1 :         if (elcc->RecurringCosts[iInObj].startOfCosts == StartCosts::Invalid) {
     526            0 :             elcc->RecurringCosts[iInObj].startOfCosts = StartCosts::ServicePeriod;
     527            0 :             ShowWarningError(state,
     528            0 :                              format("{}: Invalid {}=\"{}\". The start of the service period will be used.",
     529              :                                     CurrentModuleObject,
     530            0 :                                     state.dataIPShortCut->cAlphaFieldNames(3),
     531              :                                     AlphaArray(3)));
     532              :         }
     533              :         //   N2,  \field Years from Start
     534              :         //        \type integer
     535              :         //        \minimum 0
     536              :         //        \maximum 100
     537            1 :         elcc->RecurringCosts[iInObj].yearsFromStart = int(NumArray(2));
     538            1 :         if (elcc->RecurringCosts[iInObj].yearsFromStart > 100) {
     539            0 :             ShowWarningError(state,
     540            0 :                              format("{}: Invalid value in field {}.  This value is the number of years from the start so a value greater than 100 is "
     541              :                                     "not reasonable for an economic evaluation. ",
     542              :                                     CurrentModuleObject,
     543            0 :                                     state.dataIPShortCut->cNumericFieldNames(2)));
     544              :         }
     545            1 :         if (elcc->RecurringCosts[iInObj].yearsFromStart < 0) {
     546            0 :             ShowWarningError(state,
     547            0 :                              format("{}: Invalid value in field {}.  This value is the number of years from the start so a value less than 0 is not "
     548              :                                     "reasonable for an economic evaluation. ",
     549              :                                     CurrentModuleObject,
     550            0 :                                     state.dataIPShortCut->cNumericFieldNames(2)));
     551              :         }
     552              :         //   N3,  \field Months from Start
     553              :         //        \type integer
     554              :         //        \minimum 0
     555              :         //        \maximum 1200
     556            1 :         elcc->RecurringCosts[iInObj].monthsFromStart = int(NumArray(3));
     557            1 :         if (elcc->RecurringCosts[iInObj].monthsFromStart > 1200) {
     558            0 :             ShowWarningError(state,
     559            0 :                              format("{}: Invalid value in field {}.  This value is the number of months from the start so a value greater than 1200 "
     560              :                                     "is not reasonable for an economic evaluation. ",
     561              :                                     CurrentModuleObject,
     562            0 :                                     state.dataIPShortCut->cNumericFieldNames(3)));
     563              :         }
     564            1 :         if (elcc->RecurringCosts[iInObj].monthsFromStart < 0) {
     565            0 :             ShowWarningError(state,
     566            0 :                              format("{}: Invalid value in field {}.  This value is the number of months from the start so a value less than 0 is not "
     567              :                                     "reasonable for an economic evaluation. ",
     568              :                                     CurrentModuleObject,
     569            0 :                                     state.dataIPShortCut->cNumericFieldNames(3)));
     570              :         }
     571              :         //   N4,  \field Repeat Period Years
     572              :         //        \type integer
     573              :         //        \minimum 1
     574              :         //        \maximum 100
     575            1 :         elcc->RecurringCosts[iInObj].repeatPeriodYears = int(NumArray(4));
     576            1 :         if (elcc->RecurringCosts[iInObj].repeatPeriodYears > 100) {
     577            0 :             ShowWarningError(state,
     578            0 :                              format("{}: Invalid value in field {}.  This value is the number of years between occurrences of the cost so a value "
     579              :                                     "greater than 100 is not reasonable for an economic evaluation. ",
     580              :                                     CurrentModuleObject,
     581            0 :                                     state.dataIPShortCut->cNumericFieldNames(4)));
     582              :         }
     583            1 :         if (elcc->RecurringCosts[iInObj].repeatPeriodYears < 1) {
     584            0 :             ShowWarningError(state,
     585            0 :                              format("{}: Invalid value in field {}.  This value is the number of years between occurrences of the cost so a value "
     586              :                                     "less than 1 is not reasonable for an economic evaluation. ",
     587              :                                     CurrentModuleObject,
     588            0 :                                     state.dataIPShortCut->cNumericFieldNames(4)));
     589              :         }
     590              :         //   N5,  \field Repeat Period Months
     591              :         //        \type integer
     592              :         //        \minimum 0
     593              :         //        \maximum 1200
     594            1 :         elcc->RecurringCosts[iInObj].repeatPeriodMonths = int(NumArray(5));
     595            1 :         if (elcc->RecurringCosts[iInObj].repeatPeriodMonths > 1200) {
     596            0 :             ShowWarningError(state,
     597            0 :                              format("{}: Invalid value in field {}.  This value is the number of months between occurrences of the cost so a value "
     598              :                                     "greater than 1200 is not reasonable for an economic evaluation. ",
     599              :                                     CurrentModuleObject,
     600            0 :                                     state.dataIPShortCut->cNumericFieldNames(5)));
     601              :         }
     602            1 :         if (elcc->RecurringCosts[iInObj].repeatPeriodMonths < 0) {
     603            0 :             ShowWarningError(state,
     604            0 :                              format("{}: Invalid value in field {}.  This value is the number of months between occurrences of the cost so a value "
     605              :                                     "less than 0 is not reasonable for an economic evaluation. ",
     606              :                                     CurrentModuleObject,
     607            0 :                                     state.dataIPShortCut->cNumericFieldNames(5)));
     608              :         }
     609            1 :         if ((elcc->RecurringCosts[iInObj].repeatPeriodMonths == 0) && (elcc->RecurringCosts[iInObj].repeatPeriodYears == 0)) {
     610            0 :             ShowWarningError(state,
     611            0 :                              format("{}: Invalid value in fields {} and {}.  The repeat period must not be zero months and zero years. ",
     612              :                                     CurrentModuleObject,
     613            0 :                                     state.dataIPShortCut->cNumericFieldNames(5),
     614            0 :                                     state.dataIPShortCut->cNumericFieldNames(4)));
     615              :         }
     616              :         //   N6;  \field Annual escalation rate
     617              :         //        \type real
     618            1 :         elcc->RecurringCosts[iInObj].annualEscalationRate = int(NumArray(6));
     619            1 :         if (elcc->RecurringCosts[iInObj].annualEscalationRate > 0.30) {
     620            0 :             ShowWarningError(state,
     621            0 :                              format("{}: Invalid value in field {}.  This value is the decimal value for the annual escalation so most values are "
     622              :                                     "between 0.02 and 0.15. ",
     623              :                                     CurrentModuleObject,
     624            0 :                                     state.dataIPShortCut->cNumericFieldNames(6)));
     625              :         }
     626            1 :         if (elcc->RecurringCosts[iInObj].annualEscalationRate < -0.30) {
     627            0 :             ShowWarningError(state,
     628            0 :                              format("{}: Invalid value in field {}.  This value is the decimal value for the annual escalation so most values are "
     629              :                                     "between 0.02 and 0.15. ",
     630              :                                     CurrentModuleObject,
     631            0 :                                     state.dataIPShortCut->cNumericFieldNames(6)));
     632              :         }
     633              :         // express the years and months fields in total months
     634            1 :         elcc->RecurringCosts[iInObj].totalMonthsFromStart =
     635            1 :             elcc->RecurringCosts[iInObj].yearsFromStart * 12 + elcc->RecurringCosts[iInObj].monthsFromStart;
     636            1 :         elcc->RecurringCosts[iInObj].totalRepeatPeriodMonths =
     637            1 :             elcc->RecurringCosts[iInObj].repeatPeriodYears * 12 + elcc->RecurringCosts[iInObj].repeatPeriodMonths;
     638              :     }
     639         2396 : }
     640              : 
     641          800 : void GetInputLifeCycleCostNonrecurringCost(EnergyPlusData &state)
     642              : {
     643              :     // SUBROUTINE INFORMATION:
     644              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
     645              :     //    DATE WRITTEN   May 2010
     646              : 
     647              :     // PURPOSE OF THIS SUBROUTINE:
     648              :     //    Read the input file for "LifeCycleCost:NonrecurringCost" object.
     649              : 
     650              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     651              : 
     652              :     int iInObj;                      // loop index variable for reading in objects
     653              :     int jFld;                        // loop counter
     654              :     int NumFields;                   // Total number of elements
     655              :     int NumAlphas;                   // Number of elements in the alpha array
     656              :     int NumNums;                     // Number of elements in the numeric array
     657          800 :     Array1D_string AlphaArray;       // character string data
     658          800 :     Array1D<Real64> NumArray;        // numeric data
     659              :     int IOStat;                      // IO Status when calling get input subroutine
     660          800 :     std::string CurrentModuleObject; // for ease in renaming.
     661              :     int numComponentCostLineItems;   // number of ComponentCost:LineItem objects
     662              : 
     663          800 :     auto &elcc(state.dataEconLifeCycleCost);
     664              : 
     665          800 :     if (!elcc->LCCparamPresent) {
     666          798 :         return;
     667              :     }
     668            2 :     CurrentModuleObject = "LifeCycleCost:NonrecurringCost";
     669            2 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNums);
     670            2 :     NumArray.allocate(NumNums);
     671            2 :     AlphaArray.allocate(NumAlphas);
     672            2 :     elcc->numNonrecurringCost = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     673            2 :     numComponentCostLineItems = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ComponentCost:LineItem");
     674            2 :     if (numComponentCostLineItems > 0) {                              // leave room for component cost total
     675            0 :         elcc->NonrecurringCost.resize(elcc->numNonrecurringCost + 1); // add a place for CostEstimate total
     676              :     } else {
     677            2 :         elcc->NonrecurringCost.resize(elcc->numNonrecurringCost);
     678              :     }
     679            8 :     for (iInObj = 0; iInObj < elcc->numNonrecurringCost; ++iInObj) {
     680           12 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     681              :                                                                  CurrentModuleObject,
     682              :                                                                  iInObj + 1, // since this index needs to start from 1
     683              :                                                                  AlphaArray,
     684              :                                                                  NumAlphas,
     685              :                                                                  NumArray,
     686              :                                                                  NumNums,
     687              :                                                                  IOStat,
     688            6 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
     689            6 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     690            6 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     691            6 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     692              :         // check to make sure none of the values are another life cycle cost object
     693           24 :         for (jFld = 1; jFld <= NumAlphas; ++jFld) {
     694           18 :             if (hasi(AlphaArray(jFld), "LifeCycleCost:")) {
     695            0 :                 ShowWarningError(state,
     696            0 :                                  format("In {} named {} a field was found containing LifeCycleCost: which may indicate a missing comma.",
     697              :                                         CurrentModuleObject,
     698              :                                         AlphaArray(1)));
     699              :             }
     700              :         }
     701              :         // start to extract values from input array into appropriate fields
     702              :         // A1,  \field Name
     703              :         //      \required-field
     704              :         //      \type alpha
     705            6 :         elcc->NonrecurringCost[iInObj].name = AlphaArray(1);
     706              :         // A2,  \field Category
     707              :         //      \type choice
     708              :         //      \key Construction
     709              :         //      \key Salvage
     710              :         //      \key OtherCapital
     711              :         //      \default Construction
     712            6 :         elcc->NonrecurringCost[iInObj].category = static_cast<CostCategory>(getEnumValue(CostCategoryNamesUCNoSpace, Util::makeUPPER(AlphaArray(2))));
     713            6 :         bool isNotNonRecurringCost = (elcc->NonrecurringCost[iInObj].category != CostCategory::Construction &&
     714            8 :                                       elcc->NonrecurringCost[iInObj].category != CostCategory::Salvage &&
     715            2 :                                       elcc->NonrecurringCost[iInObj].category != CostCategory::OtherCapital);
     716            6 :         if (isNotNonRecurringCost) {
     717            0 :             elcc->NonrecurringCost[iInObj].category = CostCategory::Construction;
     718            0 :             ShowWarningError(state,
     719            0 :                              format("{}: Invalid {}=\"{}\". The category of Construction will be used.",
     720              :                                     CurrentModuleObject,
     721            0 :                                     state.dataIPShortCut->cAlphaFieldNames(2),
     722              :                                     AlphaArray(2)));
     723              :         }
     724              :         // N1,  \field Cost
     725              :         //      \type real
     726            6 :         elcc->NonrecurringCost[iInObj].cost = NumArray(1);
     727              :         // A3,  \field Start of Costs
     728              :         //      \type choice
     729              :         //      \key ServicePeriod
     730              :         //      \key BasePeriod
     731              :         //      \default ServicePeriod
     732            6 :         elcc->NonrecurringCost[iInObj].startOfCosts = static_cast<StartCosts>(getEnumValue(StartCostNamesUC, Util::makeUPPER(AlphaArray(3))));
     733            6 :         if (elcc->NonrecurringCost[iInObj].startOfCosts == StartCosts::Invalid) {
     734            0 :             elcc->NonrecurringCost[iInObj].startOfCosts = StartCosts::ServicePeriod;
     735            0 :             ShowWarningError(state,
     736            0 :                              format("{}: Invalid {}=\"{}\". The start of the service period will be used.",
     737              :                                     CurrentModuleObject,
     738            0 :                                     state.dataIPShortCut->cAlphaFieldNames(3),
     739              :                                     AlphaArray(3)));
     740              :         }
     741              :         // N2,  \field Years from Start
     742              :         //      \type integer
     743              :         //      \minimum 0
     744              :         //      \maximum 100
     745            6 :         elcc->NonrecurringCost[iInObj].yearsFromStart = int(NumArray(2));
     746            6 :         if (elcc->NonrecurringCost[iInObj].yearsFromStart > 100) {
     747            0 :             ShowWarningError(state,
     748            0 :                              format("{}: Invalid value in field {}.  This value is the number of years from the start so a value greater than 100 is "
     749              :                                     "not reasonable for an economic evaluation. ",
     750              :                                     CurrentModuleObject,
     751            0 :                                     state.dataIPShortCut->cNumericFieldNames(2)));
     752              :         }
     753            6 :         if (elcc->NonrecurringCost[iInObj].yearsFromStart < 0) {
     754            0 :             ShowWarningError(state,
     755            0 :                              format("{}: Invalid value in field {}.  This value is the number of years from the start so a value less than 0 is not "
     756              :                                     "reasonable for an economic evaluation. ",
     757              :                                     CurrentModuleObject,
     758            0 :                                     state.dataIPShortCut->cNumericFieldNames(2)));
     759              :         }
     760              :         //  N3;  \field Months from Start
     761              :         //       \type integer
     762              :         //       \minimum 0
     763              :         //       \maximum 11
     764            6 :         elcc->NonrecurringCost[iInObj].monthsFromStart = int(NumArray(3));
     765            6 :         if (elcc->NonrecurringCost[iInObj].monthsFromStart > 1200) {
     766            0 :             ShowWarningError(state,
     767            0 :                              format("{}: Invalid value in field {}.  This value is the number of months from the start so a value greater than 1200 "
     768              :                                     "is not reasonable for an economic evaluation. ",
     769              :                                     CurrentModuleObject,
     770            0 :                                     state.dataIPShortCut->cNumericFieldNames(3)));
     771              :         }
     772            6 :         if (elcc->NonrecurringCost[iInObj].monthsFromStart < 0) {
     773            0 :             ShowWarningError(state,
     774            0 :                              format("{}: Invalid value in field {}.  This value is the number of months from the start so a value less than 0 is not "
     775              :                                     "reasonable for an economic evaluation. ",
     776              :                                     CurrentModuleObject,
     777            0 :                                     state.dataIPShortCut->cNumericFieldNames(3)));
     778              :         }
     779              :         // express the years and months fields in total months
     780            6 :         elcc->NonrecurringCost[iInObj].totalMonthsFromStart =
     781            6 :             elcc->NonrecurringCost[iInObj].yearsFromStart * 12 + elcc->NonrecurringCost[iInObj].monthsFromStart;
     782              :     }
     783         2396 : }
     784              : 
     785          800 : void GetInputLifeCycleCostUsePriceEscalation(EnergyPlusData &state)
     786              : {
     787              :     // SUBROUTINE INFORMATION:
     788              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
     789              :     //    DATE WRITTEN   May 2010
     790              : 
     791              :     // PURPOSE OF THIS SUBROUTINE:
     792              :     //    Read the input file for "LifeCycleCost:UsePriceEscalation" object.
     793              : 
     794              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     795              : 
     796              :     int iInObj;                      // loop index variable for reading in objects
     797              :     int NumFields;                   // Total number of elements
     798              :     int NumAlphas;                   // Number of elements in the alpha array
     799              :     int NumNums;                     // Number of elements in the numeric array
     800          800 :     Array1D_string AlphaArray;       // character string data
     801          800 :     Array1D<Real64> NumArray;        // numeric data
     802          800 :     std::string CurrentModuleObject; // for ease in renaming.
     803              : 
     804          800 :     auto &elcc(state.dataEconLifeCycleCost);
     805              : 
     806          800 :     if (!elcc->LCCparamPresent) {
     807          798 :         return;
     808              :     }
     809            2 :     CurrentModuleObject = "LifeCycleCost:UsePriceEscalation";
     810            2 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNums);
     811            2 :     NumArray.allocate(NumNums);
     812            2 :     AlphaArray.allocate(NumAlphas);
     813            2 :     elcc->numUsePriceEscalation = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     814            2 :     elcc->UsePriceEscalation.allocate(elcc->numUsePriceEscalation);
     815           10 :     for (iInObj = 1; iInObj <= elcc->numUsePriceEscalation; ++iInObj) {
     816            8 :         elcc->UsePriceEscalation(iInObj).Escalation.allocate(elcc->lengthStudyYears);
     817              :     }
     818            2 :     if (elcc->numUsePriceEscalation > 0) {
     819              :         int IOStat; // IO Status when calling get input subroutine
     820           10 :         for (iInObj = 1; iInObj <= elcc->numUsePriceEscalation; ++iInObj) {
     821           16 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     822              :                                                                      CurrentModuleObject,
     823              :                                                                      iInObj,
     824              :                                                                      AlphaArray,
     825              :                                                                      NumAlphas,
     826              :                                                                      NumArray,
     827              :                                                                      NumNums,
     828              :                                                                      IOStat,
     829            8 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     830            8 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     831            8 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     832            8 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     833              :             // check to make sure none of the values are another life cycle cost object
     834           32 :             for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
     835           24 :                 if (hasi(AlphaArray(jFld), "LifeCycleCost:")) {
     836            0 :                     ShowWarningError(state,
     837            0 :                                      format("In {} named {} a field was found containing LifeCycleCost: which may indicate a missing comma.",
     838              :                                             CurrentModuleObject,
     839              :                                             AlphaArray(1)));
     840              :                 }
     841              :             }
     842              :             // start to extract values from input array into appropriate fields
     843              :             // A1,  \field Name
     844              :             //      \required-field
     845              :             //      \type alpha
     846            8 :             elcc->UsePriceEscalation(iInObj).name = AlphaArray(1);
     847              :             //  A2,  \field Resource
     848              :             //       \required-field
     849              :             //       \type choice
     850              :             //       \key Electricity
     851              :             //       \key NaturalGas
     852              :             //       \key Steam
     853              :             //       \key Gasoline
     854              :             //       \key Diesel
     855              :             //       \key Coal
     856              :             //       \key FuelOilNo1
     857              :             //       \key FuelOilNo2
     858              :             //       \key Propane
     859              :             //       \key Water
     860              :             //       \key OtherFuel1
     861              :             //       \key OtherFuel2
     862            8 :             elcc->UsePriceEscalation(iInObj).resource = static_cast<Constant::eResource>(getEnumValue(Constant::eResourceNamesUC, AlphaArray(2)));
     863            8 :             if (NumAlphas > 3) {
     864            0 :                 ShowWarningError(state, format("In {} contains more alpha fields than expected.", CurrentModuleObject));
     865              :             }
     866              :             // N1,  \field Escalation Start Year
     867              :             //      \type integer
     868              :             //      \minimum 1900
     869              :             //      \maximum 2100
     870            8 :             elcc->UsePriceEscalation(iInObj).escalationStartYear = int(NumArray(1));
     871            8 :             if (elcc->UsePriceEscalation(iInObj).escalationStartYear > 2100) {
     872            0 :                 ShowWarningError(state,
     873            0 :                                  format("{}: Invalid value in field {}.  Value greater than 2100 yet it is representing a year. ",
     874              :                                         CurrentModuleObject,
     875            0 :                                         state.dataIPShortCut->cNumericFieldNames(1)));
     876              :             }
     877            8 :             if (elcc->UsePriceEscalation(iInObj).escalationStartYear < 1900) {
     878            0 :                 ShowWarningError(state,
     879            0 :                                  format("{}: Invalid value in field {}.  Value less than 1900 yet it is representing a year. ",
     880              :                                         CurrentModuleObject,
     881            0 :                                         state.dataIPShortCut->cNumericFieldNames(1)));
     882              :             }
     883              :             // A3,  \field Escalation Start Month
     884              :             //      \type choice
     885              :             //      \key January
     886              :             //      \key February
     887              :             //      \key March
     888              :             //      \key April
     889              :             //      \key May
     890              :             //      \key June
     891              :             //      \key July
     892              :             //      \key August
     893              :             //      \key September
     894              :             //      \key October
     895              :             //      \key November
     896              :             //      \key December
     897              :             //      \default January
     898            8 :             elcc->UsePriceEscalation(iInObj).escalationStartMonth = getEnumValue(Util::MonthNamesUC, Util::makeUPPER(AlphaArray(3)));
     899            8 :             if (elcc->UsePriceEscalation(iInObj).escalationStartMonth == -1) {
     900            0 :                 elcc->UsePriceEscalation(iInObj).escalationStartMonth = 0;
     901            0 :                 ShowWarningError(state,
     902            0 :                                  format("{}: Invalid month entered in field {}. Using January instead of \"{}\"",
     903              :                                         CurrentModuleObject,
     904            0 :                                         state.dataIPShortCut->cAlphaFieldNames(3),
     905              :                                         AlphaArray(3)));
     906              :             }
     907              :             // N2,  \field Year 1 Escalation
     908              :             //      \type real
     909              :             //      \begin-extensible
     910              :             // The array is from the baseDateYear until baseDateYear + lengthStudyYears
     911              :             // Set the array to default to 1.0
     912          199 :             for (int jYear = 1; jYear <= elcc->lengthStudyYears; ++jYear) {
     913          191 :                 elcc->UsePriceEscalation(iInObj).Escalation(jYear) = 1.0;
     914              :             }
     915              :             // Since the years in the UsePriceEscalation may not match up with the baseDateYear and
     916              :             // the lenghtStudyYears, need to make adjustments when reading in the values to align
     917              :             // with the baseDateYear (the first item in all yearly arrays)
     918            8 :             elcc->UsePriceEscalation_escStartYear = elcc->UsePriceEscalation(iInObj).escalationStartYear;
     919            8 :             elcc->UsePriceEscalation_escNumYears = NumNums - 1;
     920            8 :             elcc->UsePriceEscalation_escEndYear = elcc->UsePriceEscalation_escStartYear + elcc->UsePriceEscalation_escNumYears - 1;
     921            8 :             elcc->UsePriceEscalation_earlierEndYear = min(elcc->UsePriceEscalation_escEndYear, elcc->lastDateYear);   // pick the earlier ending date
     922            8 :             elcc->UsePriceEscalation_laterStartYear = max(elcc->UsePriceEscalation_escStartYear, elcc->baseDateYear); // pick the later starting date
     923          199 :             for (int jYear = elcc->UsePriceEscalation_laterStartYear; jYear <= elcc->UsePriceEscalation_earlierEndYear; ++jYear) {
     924          191 :                 elcc->UsePriceEscalation_curFld = 2 + jYear - elcc->UsePriceEscalation_escStartYear;
     925          191 :                 elcc->UsePriceEscalation_curEsc = 1 + jYear - elcc->baseDateYear;
     926          191 :                 if ((elcc->UsePriceEscalation_curFld <= NumNums) && (elcc->UsePriceEscalation_curFld >= 1)) {
     927          191 :                     if ((elcc->UsePriceEscalation_curEsc <= elcc->lengthStudyYears) && (elcc->UsePriceEscalation_curEsc >= 1)) {
     928          191 :                         elcc->UsePriceEscalation(iInObj).Escalation(elcc->UsePriceEscalation_curEsc) = NumArray(elcc->UsePriceEscalation_curFld);
     929              :                     }
     930              :                 }
     931              :             }
     932              :         }
     933              :     }
     934         2396 : }
     935              : 
     936          800 : void GetInputLifeCycleCostUseAdjustment(EnergyPlusData &state)
     937              : {
     938              :     // SUBROUTINE INFORMATION:
     939              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
     940              :     //    DATE WRITTEN   May 2010
     941              : 
     942              :     // PURPOSE OF THIS SUBROUTINE:
     943              :     //    Read the input file for "LifeCycleCost:UseAdjustment" object.
     944              : 
     945              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     946              : 
     947              :     int iInObj;                      // loop index variable for reading in objects
     948              :     int NumFields;                   // Total number of elements
     949              :     int NumAlphas;                   // Number of elements in the alpha array
     950              :     int NumNums;                     // Number of elements in the numeric array
     951          800 :     Array1D_string AlphaArray;       // character string data
     952          800 :     Array1D<Real64> NumArray;        // numeric data
     953          800 :     std::string CurrentModuleObject; // for ease in renaming.
     954              : 
     955          800 :     auto &elcc(state.dataEconLifeCycleCost);
     956              : 
     957          800 :     if (!elcc->LCCparamPresent) {
     958          798 :         return;
     959              :     }
     960            2 :     CurrentModuleObject = "LifeCycleCost:UseAdjustment";
     961            2 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNums);
     962            2 :     NumArray.allocate(NumNums);
     963            2 :     AlphaArray.allocate(NumAlphas);
     964            2 :     elcc->numUseAdjustment = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     965            2 :     elcc->UseAdjustment.allocate(elcc->numUseAdjustment);
     966            3 :     for (iInObj = 1; iInObj <= elcc->numUseAdjustment; ++iInObj) {
     967            1 :         elcc->UseAdjustment(iInObj).Adjustment.allocate(elcc->lengthStudyYears);
     968              :     }
     969            2 :     if (elcc->numUseAdjustment > 0) {
     970              :         int IOStat; // IO Status when calling get input subroutine
     971            2 :         for (iInObj = 1; iInObj <= elcc->numUseAdjustment; ++iInObj) {
     972            2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     973              :                                                                      CurrentModuleObject,
     974              :                                                                      iInObj,
     975              :                                                                      AlphaArray,
     976              :                                                                      NumAlphas,
     977              :                                                                      NumArray,
     978              :                                                                      NumNums,
     979              :                                                                      IOStat,
     980            1 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     981            1 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     982            1 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     983            1 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     984              :             // check to make sure none of the values are another life cycle cost object
     985            3 :             for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
     986            2 :                 if (hasi(AlphaArray(jFld), "LifeCycleCost:")) {
     987            0 :                     ShowWarningError(state,
     988            0 :                                      format("In {} named {} a field was found containing LifeCycleCost: which may indicate a missing comma.",
     989              :                                             CurrentModuleObject,
     990              :                                             AlphaArray(1)));
     991              :                 }
     992              :             }
     993              :             // start to extract values from input array into appropriate fields
     994              :             //  A1,  \field Name
     995              :             //       \required-field
     996              :             //       \type alpha
     997            1 :             elcc->UseAdjustment(iInObj).name = AlphaArray(1);
     998              :             //  A2,  \field Resource
     999              :             //       \required-field
    1000              :             //       \type choice
    1001              :             //       \key Electricity
    1002              :             //       \key NaturalGas
    1003              :             //       \key Steam
    1004              :             //       \key Gasoline
    1005              :             //       \key Diesel
    1006              :             //       \key Coal
    1007              :             //       \key FuelOilNo1
    1008              :             //       \key FuelOilNo2
    1009              :             //       \key Propane
    1010              :             //       \key Water
    1011              :             //       \key OtherFuel1
    1012              :             //       \key OtherFuel2
    1013            1 :             elcc->UseAdjustment(iInObj).resource = static_cast<Constant::eResource>(getEnumValue(Constant::eResourceNamesUC, AlphaArray(2)));
    1014            1 :             if (NumAlphas > 2) {
    1015            0 :                 ShowWarningError(state, format("In {} contains more alpha fields than expected.", CurrentModuleObject));
    1016              :             }
    1017              :             //  N1,  \field Year 1 Multiplier
    1018              :             //       \type real
    1019              :             //       \begin-extensible
    1020              :             // Set the array to default to 1.0
    1021           23 :             for (int jYear = 1; jYear <= elcc->lengthStudyYears; ++jYear) {
    1022           22 :                 elcc->UseAdjustment(iInObj).Adjustment(jYear) = 1.0;
    1023              :             }
    1024            1 :             int numFldsToUse = min(NumNums, elcc->lengthStudyYears);
    1025            2 :             for (int jYear = 1; jYear <= numFldsToUse; ++jYear) {
    1026            1 :                 elcc->UseAdjustment(iInObj).Adjustment(jYear) = NumArray(jYear);
    1027              :             }
    1028              :         }
    1029              :     }
    1030         2396 : }
    1031              : 
    1032              : //======================================================================================================================
    1033              : //======================================================================================================================
    1034              : 
    1035              : //    COMPUTATION ROUTINES
    1036              : 
    1037              : //======================================================================================================================
    1038              : //======================================================================================================================
    1039              : 
    1040            2 : void ExpressAsCashFlows(EnergyPlusData &state)
    1041              : {
    1042              :     // SUBROUTINE INFORMATION:
    1043              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1044              :     //    DATE WRITTEN   July 2010
    1045              : 
    1046              :     // PURPOSE OF THIS SUBROUTINE:
    1047              :     //    Convert all recurring and nonrecurring costs into cash flows
    1048              :     //    used in calculations and reporting.
    1049              : 
    1050              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1051              :     int iCashFlow;
    1052              :     int jCost;
    1053              :     int jAdj;
    1054              :     int kYear;
    1055              :     int offset;
    1056              :     int month; // number of months since base date
    1057              :     int firstMonth;
    1058              :     int monthsBaseToService;
    1059              : 
    1060            2 :     std::map<int, std::array<Real64, static_cast<int>(Constant::eResource::Num)>> resourceCosts;
    1061           26 :     for (int jMonth = 1; jMonth <= 12; ++jMonth) {
    1062           24 :         resourceCosts[jMonth] = std::array<Real64, static_cast<int>(Constant::eResource::Num)>();
    1063           24 :         std::fill(resourceCosts[jMonth].begin(), resourceCosts[jMonth].end(), 0.0);
    1064              :     }
    1065              : 
    1066            2 :     Array1D<Real64> curResourceCosts(12);
    1067              : 
    1068            2 :     std::array<bool, static_cast<int>(Constant::eResource::Num)> resourceCostNotZero{};
    1069            2 :     std::fill(resourceCostNotZero.begin(), resourceCostNotZero.end(), false);
    1070              : 
    1071            2 :     std::array<Real64, static_cast<int>(Constant::eResource::Num)> resourceCostAnnual{};
    1072            2 :     std::fill(resourceCostAnnual.begin(), resourceCostAnnual.end(), 0.0);
    1073              : 
    1074              :     Real64 annualCost;
    1075              :     int found;
    1076              :     CostCategory curCategory;
    1077            2 :     Array1D<Real64> monthlyInflationFactor;
    1078              :     Real64 inflationPerMonth;
    1079              :     int iLoop;
    1080              : 
    1081            2 :     auto &elcc(state.dataEconLifeCycleCost);
    1082              : 
    1083              :     // compute months from 1900 for base and service period
    1084            4 :     elcc->ExpressAsCashFlows_baseMonths1900 =
    1085            2 :         (elcc->baseDateYear - 1900) * 12 + (elcc->baseDateMonth + 1); // elcc->baseDateMonth + 1 to account for baseDateMonth starting at 0
    1086            4 :     elcc->ExpressAsCashFlows_serviceMonths1900 =
    1087            2 :         (elcc->serviceDateYear - 1900) * 12 + elcc->serviceDateMonth + 1; // elcc->serviceDateMonth + 1 to account for serviceDateMonth starting at 0
    1088            2 :     monthsBaseToService = elcc->ExpressAsCashFlows_serviceMonths1900 - elcc->ExpressAsCashFlows_baseMonths1900;
    1089              :     // if ComponentCost:LineItem exist, the grand total of all costs are another non-recurring cost
    1090            2 :     if (state.dataCostEstimateManager->CurntBldg.GrandTotal >
    1091              :         0.0) { // from DataCostEstimate and computed in WriteCompCostTable within OutputReportTabular
    1092            0 :         ++elcc->numNonrecurringCost;
    1093            0 :         elcc->NonrecurringCost[elcc->numNonrecurringCost].name = "Total of ComponentCost:*";
    1094            0 :         elcc->NonrecurringCost[elcc->numNonrecurringCost].lineItem = "";
    1095            0 :         elcc->NonrecurringCost[elcc->numNonrecurringCost].category = CostCategory::Construction;
    1096            0 :         elcc->NonrecurringCost[elcc->numNonrecurringCost].cost = state.dataCostEstimateManager->CurntBldg.GrandTotal;
    1097            0 :         elcc->NonrecurringCost[elcc->numNonrecurringCost].startOfCosts = StartCosts::BasePeriod;
    1098            0 :         elcc->NonrecurringCost[elcc->numNonrecurringCost].yearsFromStart = 0;
    1099            0 :         elcc->NonrecurringCost[elcc->numNonrecurringCost].monthsFromStart = 0;
    1100            0 :         elcc->NonrecurringCost[elcc->numNonrecurringCost].totalMonthsFromStart = 0;
    1101              :     }
    1102              : 
    1103              :     // gather costs from EconomicTariff for each end use
    1104            2 :     elcc->numResourcesUsed = 0;
    1105           98 :     for (int iResource = 0; iResource < static_cast<int>(Constant::eResource::Num); ++iResource) {
    1106           96 :         EconomicTariff::GetMonthlyCostForResource(state, static_cast<Constant::eResource>(iResource), curResourceCosts);
    1107           96 :         annualCost = 0.0;
    1108         1248 :         for (int jMonth = 1; jMonth <= 12; ++jMonth) {
    1109         1152 :             resourceCosts[jMonth][iResource] = curResourceCosts(jMonth);
    1110         1152 :             annualCost += resourceCosts[jMonth][iResource];
    1111              :         }
    1112           96 :         if (annualCost != 0.0) {
    1113            1 :             ++elcc->numResourcesUsed;
    1114            1 :             resourceCostNotZero[iResource] = true;
    1115              :         } else {
    1116           95 :             resourceCostNotZero[iResource] = false;
    1117              :         }
    1118           96 :         resourceCostAnnual[iResource] = annualCost;
    1119              :     }
    1120              :     // allocate the escalated energy cost arrays
    1121           49 :     for (int year = 1; year <= elcc->lengthStudyYears; ++year) {
    1122           47 :         elcc->EscalatedEnergy[year] = std::array<Real64, static_cast<int>(Constant::eResource::Num)>();
    1123           47 :         std::fill(elcc->EscalatedEnergy[year].begin(), elcc->EscalatedEnergy[year].end(), 0.0);
    1124              :     }
    1125              : 
    1126            2 :     elcc->EscalatedTotEnergy.allocate(elcc->lengthStudyYears);
    1127            2 :     elcc->EscalatedTotEnergy = 0.0;
    1128              : 
    1129              :     // pre-compute the inflation factors for each year
    1130            2 :     monthlyInflationFactor.allocate(elcc->lengthStudyTotalMonths);
    1131            2 :     if (elcc->inflationApproach == InflAppr::ConstantDollar) {
    1132            2 :         monthlyInflationFactor = 1.0; // not really used but just in case
    1133            0 :     } else if (elcc->inflationApproach == InflAppr::CurrentDollar) {
    1134              :         // to allocate an interest rate (in this case inflation) cannot just use 1/12
    1135              :         // for the monthly value since it will be slightly wrong. Instead, use inverse of
    1136              :         // formula from Newnan (4-32) which is r = m x (ia + 1)^(1/m) - 1)
    1137            0 :         inflationPerMonth = std::pow(elcc->inflation + 1.0, 1.0 / 12.0) - 1;
    1138            0 :         for (int jMonth = 1; jMonth <= elcc->lengthStudyTotalMonths; ++jMonth) {
    1139            0 :             monthlyInflationFactor(jMonth) = std::pow(1.0 + inflationPerMonth, jMonth - 1);
    1140              :         }
    1141              :     }
    1142              : 
    1143            2 :     elcc->numCashFlow = CostCategory::Num + elcc->numRecurringCosts + elcc->numNonrecurringCost + elcc->numResourcesUsed;
    1144              :     // Cashflow array order:
    1145              :     //   1 cost categories
    1146              :     //   2 recurring costs
    1147              :     //   3 nonrecurring costs
    1148              :     //   4 resource costs
    1149            2 :     elcc->CashFlow.resize(elcc->numCashFlow);
    1150           42 :     for (iCashFlow = 0; iCashFlow < elcc->numCashFlow; ++iCashFlow) {
    1151           40 :         elcc->CashFlow[iCashFlow].mnAmount.allocate(elcc->lengthStudyTotalMonths);
    1152           40 :         elcc->CashFlow[iCashFlow].yrAmount.allocate(elcc->lengthStudyYears);
    1153           40 :         elcc->CashFlow[iCashFlow].yrPresVal.allocate(elcc->lengthStudyYears);
    1154           40 :         elcc->CashFlow[iCashFlow].mnAmount = 0.0;  // zero all cash flow values
    1155           40 :         elcc->CashFlow[iCashFlow].yrAmount = 0.0;  // zero all cash flow values
    1156           40 :         elcc->CashFlow[iCashFlow].yrPresVal = 0.0; // zero all present values
    1157              :     }
    1158              :     // Put nonrecurring costs into cashflows
    1159            2 :     offset = CostCategory::Num + elcc->numRecurringCosts;
    1160            8 :     for (jCost = 0; jCost < elcc->numNonrecurringCost; ++jCost) {
    1161            6 :         elcc->CashFlow[offset + jCost].name = elcc->NonrecurringCost[jCost].name;
    1162            6 :         elcc->CashFlow[offset + jCost].SourceKind = SourceKindType::Nonrecurring;
    1163            6 :         elcc->CashFlow[offset + jCost].Category = elcc->NonrecurringCost[jCost].category;
    1164            6 :         elcc->CashFlow[offset + jCost].orginalCost = elcc->NonrecurringCost[jCost].cost;
    1165            6 :         elcc->CashFlow[offset + jCost].mnAmount = 0.0;
    1166            6 :         if (elcc->NonrecurringCost[jCost].startOfCosts == StartCosts::ServicePeriod) {
    1167            1 :             month = elcc->NonrecurringCost[jCost].totalMonthsFromStart + monthsBaseToService + 1;
    1168            5 :         } else if (elcc->NonrecurringCost[jCost].startOfCosts == StartCosts::BasePeriod) {
    1169            5 :             month = elcc->NonrecurringCost[jCost].totalMonthsFromStart + 1;
    1170              :         }
    1171            6 :         if ((month >= 1) && (month <= elcc->lengthStudyTotalMonths)) {
    1172            6 :             elcc->CashFlow[offset + jCost].mnAmount(month) = elcc->NonrecurringCost[jCost].cost * monthlyInflationFactor(month);
    1173              :         } else {
    1174            0 :             ShowWarningError(state,
    1175            0 :                              format("For life cycle costing a nonrecurring cost named {} contains a cost which is not within the study period.",
    1176            0 :                                     elcc->NonrecurringCost[jCost].name));
    1177              :         }
    1178              :     }
    1179              :     // Put recurring costs into cashflows
    1180            2 :     offset = CostCategory::Num;
    1181            3 :     for (jCost = 0; jCost < elcc->numRecurringCosts; ++jCost) {
    1182            1 :         elcc->CashFlow[offset + jCost].name = elcc->RecurringCosts[jCost].name;
    1183            1 :         elcc->CashFlow[offset + jCost].SourceKind = SourceKindType::Recurring;
    1184            1 :         elcc->CashFlow[offset + jCost].Category = elcc->RecurringCosts[jCost].category;
    1185            1 :         elcc->CashFlow[offset + jCost].orginalCost = elcc->RecurringCosts[jCost].cost;
    1186            1 :         if (elcc->RecurringCosts[jCost].startOfCosts == StartCosts::ServicePeriod) {
    1187            1 :             firstMonth = elcc->RecurringCosts[jCost].totalMonthsFromStart + monthsBaseToService + 1;
    1188            0 :         } else if (elcc->RecurringCosts[jCost].startOfCosts == StartCosts::BasePeriod) {
    1189            0 :             firstMonth = elcc->RecurringCosts[jCost].totalMonthsFromStart + 1;
    1190              :         }
    1191            1 :         if ((firstMonth >= 1) && (firstMonth <= elcc->lengthStudyTotalMonths)) {
    1192            1 :             month = firstMonth;
    1193            1 :             if (elcc->RecurringCosts[jCost].totalRepeatPeriodMonths >= 1) {
    1194           20 :                 for (iLoop = 0; iLoop < 10000; ++iLoop) { // add a limit to the loop to prevent runaway condition
    1195           20 :                     elcc->CashFlow[offset + jCost].mnAmount(month) = elcc->RecurringCosts[jCost].cost * monthlyInflationFactor(month);
    1196           20 :                     month += elcc->RecurringCosts[jCost].totalRepeatPeriodMonths;
    1197           20 :                     if (month > elcc->lengthStudyTotalMonths) {
    1198            1 :                         break;
    1199              :                     }
    1200              :                 }
    1201              :             }
    1202              :         } else {
    1203            0 :             ShowWarningError(
    1204              :                 state,
    1205            0 :                 format("For life cycle costing the recurring cost named {} has the first year of the costs that is not within the study period.",
    1206            0 :                        elcc->RecurringCosts[jCost].name));
    1207              :         }
    1208              :     }
    1209              :     // Put resource costs into cashflows
    1210              :     // the first cash flow for resources should be after the categories, recurring and nonrecurring costs
    1211            2 :     int cashFlowCounter = CostCategory::Num + elcc->numRecurringCosts + elcc->numNonrecurringCost - 1; // Since CashFlow starts at 0
    1212           98 :     for (int iResource = 0; iResource < static_cast<int>(Constant::eResource::Num); ++iResource) {
    1213           96 :         if (resourceCostNotZero[iResource]) {
    1214            1 :             ++cashFlowCounter;
    1215              : 
    1216            1 :             switch (static_cast<Constant::eResource>(iResource)) {
    1217            0 :             case Constant::eResource::Water:
    1218              :             case Constant::eResource::OnSiteWater:
    1219              :             case Constant::eResource::MainsWater:
    1220              :             case Constant::eResource::RainWater:
    1221              :             case Constant::eResource::WellWater:
    1222              :             case Constant::eResource::Condensate:
    1223            0 :                 elcc->CashFlow[cashFlowCounter].Category = CostCategory::Water;
    1224            0 :                 break;
    1225            1 :             case Constant::eResource::Electricity:
    1226              :             case Constant::eResource::NaturalGas:
    1227              :             case Constant::eResource::Gasoline:
    1228              :             case Constant::eResource::Diesel:
    1229              :             case Constant::eResource::Coal:
    1230              :             case Constant::eResource::FuelOilNo1:
    1231              :             case Constant::eResource::FuelOilNo2:
    1232              :             case Constant::eResource::Propane:
    1233              :             case Constant::eResource::EnergyTransfer:
    1234              :             case Constant::eResource::DistrictCooling:
    1235              :             case Constant::eResource::DistrictHeatingWater:
    1236              :             case Constant::eResource::DistrictHeatingSteam:
    1237              :             case Constant::eResource::ElectricityProduced:
    1238              :             case Constant::eResource::ElectricityPurchased:
    1239              :             case Constant::eResource::ElectricityNet:
    1240              :             case Constant::eResource::SolarWater:
    1241              :             case Constant::eResource::SolarAir:
    1242            1 :                 elcc->CashFlow[cashFlowCounter].Category = CostCategory::Energy;
    1243            1 :                 break;
    1244            0 :             default:
    1245            0 :                 elcc->CashFlow[cashFlowCounter].Category = CostCategory::Operation;
    1246              :             }
    1247              : 
    1248            1 :             elcc->CashFlow[cashFlowCounter].Resource = static_cast<Constant::eResource>(iResource);
    1249            1 :             elcc->CashFlow[cashFlowCounter].SourceKind = SourceKindType::Resource;
    1250            1 :             elcc->CashFlow[cashFlowCounter].name = Constant::eResourceNames[static_cast<int>(iResource)];
    1251            1 :             if (cashFlowCounter <= elcc->numCashFlow) {
    1252              :                 // put the monthly energy costs into the cashflow prior to adjustments
    1253              :                 // energy costs (a.k.a. resource costs) start at the start of service and repeat
    1254              :                 // until the end of the study total
    1255           13 :                 for (int jMonth = 1; jMonth <= 12; ++jMonth) {
    1256           12 :                     elcc->CashFlow[cashFlowCounter].mnAmount(monthsBaseToService + jMonth) = resourceCosts[jMonth][iResource];
    1257              :                 }
    1258            1 :                 elcc->CashFlow[cashFlowCounter].orginalCost = resourceCostAnnual[iResource];
    1259          229 :                 for (int jMonth = monthsBaseToService + 13; jMonth <= elcc->lengthStudyTotalMonths; ++jMonth) {
    1260              :                     // use the cost from a year earlier
    1261          228 :                     elcc->CashFlow[cashFlowCounter].mnAmount(jMonth) = elcc->CashFlow[cashFlowCounter].mnAmount(jMonth - 12);
    1262              :                 }
    1263              :                 // add in the impact of inflation
    1264          265 :                 for (int jMonth = 1; jMonth <= elcc->lengthStudyTotalMonths; ++jMonth) {
    1265          264 :                     elcc->CashFlow[cashFlowCounter].mnAmount(jMonth) *= monthlyInflationFactor(jMonth);
    1266              :                 }
    1267              :                 // now factor in adjustments
    1268              :                 // need to find the correct adjustment to use for the current resource
    1269            1 :                 found = 0;
    1270            2 :                 for (jAdj = 1; jAdj <= elcc->numUseAdjustment; ++jAdj) {
    1271            1 :                     if (elcc->UseAdjustment(jAdj).resource == static_cast<Constant::eResource>(iResource)) {
    1272            0 :                         found = jAdj;
    1273            0 :                         break;
    1274              :                     }
    1275              :                 }
    1276              :                 // if any adjustments were found for that resource apply the multiplier
    1277            1 :                 if (found != 0) {
    1278            0 :                     for (kYear = 1; kYear <= elcc->lengthStudyYears;
    1279              :                          ++kYear) { // if service period is later than base period then this will go too far
    1280            0 :                         for (int jMonth = 1; jMonth <= 12; ++jMonth) {
    1281            0 :                             month = (kYear - 1) * 12 + jMonth;
    1282            0 :                             if (month > elcc->lengthStudyTotalMonths) {
    1283            0 :                                 break;
    1284              :                             }
    1285            0 :                             elcc->CashFlow[cashFlowCounter].mnAmount(month) *= elcc->UseAdjustment(found).Adjustment(kYear);
    1286              :                         }
    1287              :                     }
    1288              :                 }
    1289              :             }
    1290              :         }
    1291              :     }
    1292              :     // put cashflows into categories
    1293           34 :     for (jCost = 0; jCost < CostCategory::Num; ++jCost) {
    1294           32 :         elcc->CashFlow[jCost].Category = static_cast<CostCategory>(jCost); // make each category the type indicated
    1295           32 :         elcc->CashFlow[jCost].SourceKind = SourceKindType::Sum;
    1296              :     }
    1297              :     // add the cashflows by category
    1298           12 :     for (jCost = CostCategory::Num - 1; jCost < elcc->numCashFlow; ++jCost) {
    1299           10 :         curCategory = elcc->CashFlow[jCost].Category;
    1300           10 :         if ((curCategory < CostCategory::Num) && (curCategory >= 0)) {
    1301         2722 :             for (int jMonth = 1; jMonth <= elcc->lengthStudyTotalMonths; ++jMonth) {
    1302         2712 :                 elcc->CashFlow[curCategory].mnAmount(jMonth) += elcc->CashFlow[jCost].mnAmount(jMonth);
    1303              :             }
    1304              :         }
    1305              :     }
    1306              :     // create total categories
    1307          566 :     for (int jMonth = 1; jMonth <= elcc->lengthStudyTotalMonths; ++jMonth) {
    1308          564 :         elcc->CashFlow[CostCategory::TotEnergy].mnAmount(jMonth) = elcc->CashFlow[CostCategory::Energy].mnAmount(jMonth);
    1309          564 :         elcc->CashFlow[CostCategory::TotOper].mnAmount(jMonth) =
    1310          564 :             elcc->CashFlow[CostCategory::Maintenance].mnAmount(jMonth) + elcc->CashFlow[CostCategory::Repair].mnAmount(jMonth) +
    1311          564 :             elcc->CashFlow[CostCategory::Operation].mnAmount(jMonth) + elcc->CashFlow[CostCategory::Replacement].mnAmount(jMonth) +
    1312          564 :             elcc->CashFlow[CostCategory::MinorOverhaul].mnAmount(jMonth) + elcc->CashFlow[CostCategory::MajorOverhaul].mnAmount(jMonth) +
    1313          564 :             elcc->CashFlow[CostCategory::OtherOperational].mnAmount(jMonth) + elcc->CashFlow[CostCategory::Water].mnAmount(jMonth) +
    1314          564 :             elcc->CashFlow[CostCategory::Energy].mnAmount(jMonth);
    1315         1128 :         elcc->CashFlow[CostCategory::TotCaptl].mnAmount(jMonth) = elcc->CashFlow[CostCategory::Construction].mnAmount(jMonth) +
    1316          564 :                                                                   elcc->CashFlow[CostCategory::Salvage].mnAmount(jMonth) +
    1317          564 :                                                                   elcc->CashFlow[CostCategory::OtherCapital].mnAmount(jMonth);
    1318          564 :         elcc->CashFlow[CostCategory::TotGrand].mnAmount(jMonth) =
    1319          564 :             elcc->CashFlow[CostCategory::TotOper].mnAmount(jMonth) + elcc->CashFlow[CostCategory::TotCaptl].mnAmount(jMonth);
    1320              :     }
    1321              :     // convert all monthly cashflows into yearly cashflows
    1322           42 :     for (jCost = 0; jCost < elcc->numCashFlow; ++jCost) {
    1323          971 :         for (kYear = 1; kYear <= elcc->lengthStudyYears; ++kYear) {
    1324          931 :             annualCost = 0.0;
    1325        12103 :             for (int jMonth = 1; jMonth <= 12; ++jMonth) {
    1326        11172 :                 month = (kYear - 1) * 12 + jMonth;
    1327        11172 :                 if (month <= elcc->lengthStudyTotalMonths) {
    1328        11172 :                     annualCost += elcc->CashFlow[jCost].mnAmount(month);
    1329              :                 }
    1330              :             }
    1331          931 :             elcc->CashFlow[jCost].yrAmount(kYear) = annualCost;
    1332              :         }
    1333              :     }
    1334              :     // generate a warning if resource referenced was not used
    1335           10 :     for (int nUsePriceEsc = 1; nUsePriceEsc <= elcc->numUsePriceEscalation; ++nUsePriceEsc) {
    1336            8 :         Constant::eResource curResource = elcc->UsePriceEscalation(nUsePriceEsc).resource;
    1337            8 :         if (!resourceCostNotZero[static_cast<int>(curResource)] && state.dataGlobal->DoWeathSim) {
    1338            0 :             ShowWarningError(state,
    1339            0 :                              format("The resource referenced by LifeCycleCost:UsePriceEscalation= \"{}\" has no energy cost. ",
    1340            0 :                                     elcc->UsePriceEscalation(nUsePriceEsc).name));
    1341            0 :             ShowContinueError(state, "... It is likely that the wrong resource is used. The resource should match the meter used in Utility:Tariff.");
    1342              :         }
    1343              :     }
    1344            2 : }
    1345              : 
    1346            2 : void ComputeEscalatedEnergyCosts(EnergyPlusData &state)
    1347              : {
    1348              :     // J. Glazer - August 2019
    1349              :     int nUsePriceEsc;
    1350              : 
    1351            2 :     auto &elcc(state.dataEconLifeCycleCost);
    1352              : 
    1353           42 :     for (int iCashFlow = 0; iCashFlow < elcc->numCashFlow; ++iCashFlow) {
    1354           40 :         if (elcc->CashFlow[iCashFlow].pvKind == PrValKind::Energy) {
    1355              :             // make sure this is not water
    1356            1 :             Constant::eResource curResource = elcc->CashFlow[iCashFlow].Resource;
    1357            2 :             if (elcc->CashFlow[iCashFlow].Resource == Constant::eResource::Water ||
    1358            1 :                 (elcc->CashFlow[iCashFlow].Resource >= Constant::eResource::OnSiteWater &&
    1359            0 :                  elcc->CashFlow[iCashFlow].Resource <= Constant::eResource::Condensate)) {
    1360            0 :                 continue;
    1361              :             }
    1362            1 :             if ((curResource != Constant::eResource::Invalid)) {
    1363            1 :                 int found = 0;
    1364            3 :                 for (nUsePriceEsc = 1; nUsePriceEsc <= elcc->numUsePriceEscalation; ++nUsePriceEsc) {
    1365            3 :                     if (elcc->UsePriceEscalation(nUsePriceEsc).resource == curResource) {
    1366            1 :                         found = nUsePriceEsc;
    1367            1 :                         break;
    1368              :                     }
    1369              :                 }
    1370            1 :                 if (found > 0) {
    1371           23 :                     for (int jYear = 1; jYear <= elcc->lengthStudyYears; ++jYear) {
    1372           22 :                         elcc->EscalatedEnergy[jYear][static_cast<int>(curResource)] =
    1373           22 :                             elcc->CashFlow[iCashFlow].yrAmount(jYear) * elcc->UsePriceEscalation(found).Escalation(jYear);
    1374              :                     }
    1375              :                 } else { // if no escalation than just store the original energy cost
    1376            0 :                     for (int jYear = 1; jYear <= elcc->lengthStudyYears; ++jYear) {
    1377            0 :                         elcc->EscalatedEnergy[jYear][static_cast<int>(curResource)] = elcc->CashFlow[iCashFlow].yrAmount(jYear);
    1378              :                     }
    1379              :                 }
    1380              :             }
    1381              :         }
    1382              :     }
    1383           98 :     for (int kResource = 0; kResource < static_cast<int>(Constant::eResource::Num); ++kResource) {
    1384         2352 :         for (int jYear = 1; jYear <= elcc->lengthStudyYears; ++jYear) {
    1385         2256 :             elcc->EscalatedTotEnergy(jYear) += elcc->EscalatedEnergy[jYear][kResource];
    1386              :         }
    1387              :     }
    1388            2 : }
    1389              : 
    1390            2 : void ComputePresentValue(EnergyPlusData &state)
    1391              : {
    1392              :     // SUBROUTINE INFORMATION:
    1393              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1394              :     //    DATE WRITTEN   August 2010
    1395              :     //    MODIFIED       na
    1396              :     //    RE-ENGINEERED  na
    1397              : 
    1398              :     // PURPOSE OF THIS SUBROUTINE:
    1399              :     //    For each cashflow, compute the present value
    1400              : 
    1401              :     // METHODOLOGY EMPLOYED:
    1402              : 
    1403              :     // REFERENCES:
    1404              :     // na
    1405              : 
    1406              :     // USE STATEMENTS:
    1407              : 
    1408              :     // Locals
    1409              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1410              :     // na
    1411              : 
    1412              :     // SUBROUTINE PARAMETER DEFINITIONS:
    1413              :     // na
    1414              : 
    1415              :     // INTERFACE BLOCK SPECIFICATIONS
    1416              :     // na
    1417              : 
    1418              :     // DERIVED TYPE DEFINITIONS
    1419              :     // na
    1420              : 
    1421              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1422              :     Real64 totalPV;
    1423              :     Real64 curDiscountRate;
    1424              :     int iCashFlow;
    1425              :     int jYear;
    1426              :     int nUsePriceEsc;
    1427              :     Real64 effectiveYear;
    1428              : 
    1429            2 :     auto &elcc(state.dataEconLifeCycleCost);
    1430              : 
    1431              :     // identify how each cashflow should be treated
    1432           42 :     for (iCashFlow = 0; iCashFlow < elcc->numCashFlow; ++iCashFlow) {
    1433           40 :         switch (elcc->CashFlow[iCashFlow].SourceKind) {
    1434            1 :         case SourceKindType::Resource: {
    1435              :             // only for real fuels purchased such as electricity, natural gas, etc..
    1436            2 :             if ((elcc->CashFlow[iCashFlow].Resource >= Constant::eResource::Electricity) &&
    1437            1 :                 (elcc->CashFlow[iCashFlow].Resource <= Constant::eResource::ElectricitySurplusSold)) {
    1438            1 :                 elcc->CashFlow[iCashFlow].pvKind = PrValKind::Energy;
    1439              :             } else {
    1440            0 :                 elcc->CashFlow[iCashFlow].pvKind = PrValKind::NonEnergy;
    1441              :             }
    1442            1 :             break;
    1443              :         }
    1444            7 :         case SourceKindType::Recurring:
    1445              :         case SourceKindType::Nonrecurring: {
    1446            7 :             if (elcc->CashFlow[iCashFlow].Category == CostCategory::Energy) {
    1447            0 :                 elcc->CashFlow[iCashFlow].pvKind = PrValKind::Energy;
    1448              :             } else {
    1449            7 :                 elcc->CashFlow[iCashFlow].pvKind = PrValKind::NonEnergy;
    1450              :             }
    1451            7 :             break;
    1452              :         }
    1453           32 :         case SourceKindType::Sum:
    1454              :         default: {
    1455           32 :             elcc->CashFlow[iCashFlow].pvKind = PrValKind::NotComputed;
    1456           32 :             break;
    1457              :         }
    1458              :         }
    1459              :     }
    1460              :     // compute the Single Present Value factors based on the discount rate
    1461            2 :     elcc->SPV.allocate(elcc->lengthStudyYears); // Should this be energySPV?
    1462           49 :     for (int year = 1; year <= elcc->lengthStudyYears; ++year) {
    1463           47 :         elcc->energySPV[year] = std::array<Real64, static_cast<int>(Constant::eResource::Num)>();
    1464           47 :         std::fill(elcc->energySPV[year].begin(), elcc->energySPV[year].end(), 0.0);
    1465              :     }
    1466              : 
    1467              :     // Depending on if using Constant or Current Dollar analysis
    1468              :     // use the appropriate discount rate
    1469            2 :     if (elcc->inflationApproach == InflAppr::ConstantDollar) {
    1470            2 :         curDiscountRate = elcc->realDiscountRate;
    1471            0 :     } else if (elcc->inflationApproach == InflAppr::CurrentDollar) {
    1472            0 :         curDiscountRate = elcc->nominalDiscountRate;
    1473              :     }
    1474              :     // compute single present values based on real discount rates
    1475            2 :     constexpr std::array<Real64, static_cast<int>(DiscConv::Num)> DiscConv2EffectiveYearAdjustment = {1.0, 0.5, 0.0};
    1476           49 :     for (jYear = 1; jYear <= elcc->lengthStudyYears; ++jYear) {
    1477              :         // NIST 155 D.2.1.1 - Single Present Value (SPV) formula
    1478           47 :         effectiveYear = double(jYear) - DiscConv2EffectiveYearAdjustment[static_cast<int>(elcc->discountConvention)];
    1479           47 :         elcc->SPV(jYear) = 1.0 / std::pow(1.0 + curDiscountRate, effectiveYear);
    1480              :     }
    1481              :     // use SPV as default values for all energy types
    1482           49 :     for (jYear = 1; jYear <= elcc->lengthStudyYears; ++jYear) {
    1483         2303 :         for (int iResource = 0; iResource < static_cast<int>(Constant::eResource::Num); ++iResource) {
    1484         2256 :             elcc->energySPV[jYear][iResource] = elcc->SPV(jYear);
    1485              :         }
    1486              :     }
    1487              :     // loop through the resources and if they match a UseEscalation use those values instead
    1488           10 :     for (nUsePriceEsc = 1; nUsePriceEsc <= elcc->numUsePriceEscalation; ++nUsePriceEsc) {
    1489            8 :         Constant::eResource curResource = elcc->UsePriceEscalation(nUsePriceEsc).resource;
    1490            8 :         if (curResource != Constant::eResource::Invalid) {
    1491          199 :             for (jYear = 1; jYear <= elcc->lengthStudyYears; ++jYear) {
    1492              :                 // the following is based on UPV* formula from NIST 135 supplement but is for a single year
    1493          191 :                 effectiveYear = double(jYear) - DiscConv2EffectiveYearAdjustment[static_cast<int>(elcc->discountConvention)];
    1494          191 :                 elcc->energySPV[jYear][static_cast<int>(curResource)] =
    1495          191 :                     elcc->UsePriceEscalation(nUsePriceEsc).Escalation(jYear) / std::pow(1.0 + curDiscountRate, effectiveYear);
    1496              :             }
    1497              :         }
    1498              :     }
    1499           42 :     for (iCashFlow = 0; iCashFlow < elcc->numCashFlow; ++iCashFlow) {
    1500           40 :         switch (elcc->CashFlow[iCashFlow].pvKind) {
    1501            7 :         case PrValKind::NonEnergy: {
    1502            7 :             totalPV = 0.0;
    1503          164 :             for (jYear = 1; jYear <= elcc->lengthStudyYears; ++jYear) {
    1504          157 :                 elcc->CashFlow[iCashFlow].yrPresVal(jYear) = elcc->CashFlow[iCashFlow].yrAmount(jYear) * elcc->SPV(jYear);
    1505          157 :                 totalPV += elcc->CashFlow[iCashFlow].yrPresVal(jYear);
    1506              :             }
    1507            7 :             elcc->CashFlow[iCashFlow].presentValue = totalPV;
    1508            7 :             break;
    1509              :         }
    1510            1 :         case PrValKind::Energy: {
    1511            1 :             Constant::eResource curResource = elcc->CashFlow[iCashFlow].Resource;
    1512            1 :             if (curResource != Constant::eResource::Invalid) {
    1513            1 :                 totalPV = 0.0;
    1514           23 :                 for (jYear = 1; jYear <= elcc->lengthStudyYears; ++jYear) {
    1515           22 :                     elcc->CashFlow[iCashFlow].yrPresVal(jYear) =
    1516           22 :                         elcc->CashFlow[iCashFlow].yrAmount(jYear) * elcc->energySPV[jYear][static_cast<int>(curResource)];
    1517           22 :                     totalPV += elcc->CashFlow[iCashFlow].yrPresVal(jYear);
    1518              :                 }
    1519            1 :                 elcc->CashFlow[iCashFlow].presentValue = totalPV;
    1520              :             }
    1521            1 :             break;
    1522              :         }
    1523              :             //            case iPrValKind::NotComputed: included in default
    1524           32 :         default:
    1525           32 :             break; // do nothing
    1526              :         }
    1527              :     }
    1528              :     // sum by category
    1529           34 :     for (int i = 0; i < CostCategory::Num; ++i) {
    1530           32 :         elcc->CashFlow[i].presentValue = 0; // initialize value to zero before summing in next for loop
    1531              :     }
    1532           10 :     for (iCashFlow = CostCategory::Num; iCashFlow < elcc->numCashFlow; ++iCashFlow) {
    1533            8 :         int curCategory = elcc->CashFlow[iCashFlow].Category;
    1534            8 :         if ((curCategory < CostCategory::Num) && (curCategory >= 0)) {
    1535            8 :             elcc->CashFlow[curCategory].presentValue += elcc->CashFlow[iCashFlow].presentValue;
    1536          187 :             for (jYear = 1; jYear <= elcc->lengthStudyYears; ++jYear) {
    1537          179 :                 elcc->CashFlow[curCategory].yrPresVal(jYear) += elcc->CashFlow[iCashFlow].yrPresVal(jYear);
    1538              :             }
    1539              :         }
    1540              :     }
    1541              :     // create total categories
    1542            2 :     elcc->CashFlow[CostCategory::TotEnergy].presentValue = elcc->CashFlow[CostCategory::Energy].presentValue;
    1543            2 :     elcc->CashFlow[CostCategory::TotOper].presentValue =
    1544            2 :         elcc->CashFlow[CostCategory::Maintenance].presentValue + elcc->CashFlow[CostCategory::Repair].presentValue +
    1545            2 :         elcc->CashFlow[CostCategory::Operation].presentValue + elcc->CashFlow[CostCategory::Replacement].presentValue +
    1546            2 :         elcc->CashFlow[CostCategory::MinorOverhaul].presentValue + elcc->CashFlow[CostCategory::MajorOverhaul].presentValue +
    1547            2 :         elcc->CashFlow[CostCategory::OtherOperational].presentValue + elcc->CashFlow[CostCategory::Water].presentValue +
    1548            2 :         elcc->CashFlow[CostCategory::Energy].presentValue;
    1549            4 :     elcc->CashFlow[CostCategory::TotCaptl].presentValue = elcc->CashFlow[CostCategory::Construction].presentValue +
    1550            2 :                                                           elcc->CashFlow[CostCategory::Salvage].presentValue +
    1551            2 :                                                           elcc->CashFlow[CostCategory::OtherCapital].presentValue;
    1552            2 :     elcc->CashFlow[CostCategory::TotGrand].presentValue =
    1553            2 :         elcc->CashFlow[CostCategory::TotOper].presentValue + elcc->CashFlow[CostCategory::TotCaptl].presentValue;
    1554           49 :     for (jYear = 1; jYear <= elcc->lengthStudyYears; ++jYear) {
    1555           47 :         elcc->CashFlow[CostCategory::TotEnergy].yrPresVal(jYear) = elcc->CashFlow[CostCategory::Energy].yrPresVal(jYear);
    1556           47 :         elcc->CashFlow[CostCategory::TotOper].yrPresVal(jYear) =
    1557           47 :             elcc->CashFlow[CostCategory::Maintenance].yrPresVal(jYear) + elcc->CashFlow[CostCategory::Repair].yrPresVal(jYear) +
    1558           47 :             elcc->CashFlow[CostCategory::Operation].yrPresVal(jYear) + elcc->CashFlow[CostCategory::Replacement].yrPresVal(jYear) +
    1559           47 :             elcc->CashFlow[CostCategory::MinorOverhaul].yrPresVal(jYear) + elcc->CashFlow[CostCategory::MajorOverhaul].yrPresVal(jYear) +
    1560           47 :             elcc->CashFlow[CostCategory::OtherOperational].yrPresVal(jYear) + elcc->CashFlow[CostCategory::Water].yrPresVal(jYear) +
    1561           47 :             elcc->CashFlow[CostCategory::Energy].yrPresVal(jYear);
    1562           94 :         elcc->CashFlow[CostCategory::TotCaptl].yrPresVal(jYear) = elcc->CashFlow[CostCategory::Construction].yrPresVal(jYear) +
    1563           47 :                                                                   elcc->CashFlow[CostCategory::Salvage].yrPresVal(jYear) +
    1564           47 :                                                                   elcc->CashFlow[CostCategory::OtherCapital].yrPresVal(jYear);
    1565           47 :         elcc->CashFlow[CostCategory::TotGrand].yrPresVal(jYear) =
    1566           47 :             elcc->CashFlow[CostCategory::TotOper].yrPresVal(jYear) + elcc->CashFlow[CostCategory::TotCaptl].yrPresVal(jYear);
    1567              :     }
    1568            2 : }
    1569              : 
    1570            2 : void ComputeTaxAndDepreciation(EnergyPlusData &state)
    1571              : {
    1572              :     // SUBROUTINE INFORMATION:
    1573              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1574              :     //    DATE WRITTEN   August 2010
    1575              :     //    MODIFIED       na
    1576              :     //    RE-ENGINEERED  na
    1577              : 
    1578              :     // PURPOSE OF THIS SUBROUTINE:
    1579              :     //    Compute the present value after factoring in taxes
    1580              :     //    and depreciation.
    1581              : 
    1582              :     // METHODOLOGY EMPLOYED:
    1583              : 
    1584              :     // REFERENCES:
    1585              :     // na
    1586              : 
    1587              :     // USE STATEMENTS:
    1588              : 
    1589              :     // Locals
    1590              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1591              :     // na
    1592              : 
    1593              :     // SUBROUTINE PARAMETER DEFINITIONS:
    1594              : 
    1595              :     // INTERFACE BLOCK SPECIFICATIONS
    1596              :     // na
    1597              : 
    1598              :     // DERIVED TYPE DEFINITIONS
    1599              :     // na
    1600              : 
    1601              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1602              :     Real64 curCapital;
    1603              :     int curDepYear;
    1604              :     int iYear;
    1605              :     int jYear;
    1606              : 
    1607            2 :     auto &elcc(state.dataEconLifeCycleCost);
    1608              : 
    1609            2 :     elcc->DepreciatedCapital.allocate(elcc->lengthStudyYears);
    1610            2 :     elcc->TaxableIncome.allocate(elcc->lengthStudyYears);
    1611            2 :     elcc->Taxes.allocate(elcc->lengthStudyYears);
    1612            2 :     elcc->AfterTaxCashFlow.allocate(elcc->lengthStudyYears);
    1613            2 :     elcc->AfterTaxPresentValue.allocate(elcc->lengthStudyYears);
    1614              : 
    1615              :     // Depreciation factors are based on IRS Publication 946 for 2009 "How to Depreciate Property"
    1616              :     // The MACRS valus are based on Modified Accelerated Cost Recovery System GDS for 3, 5, 7, 10 year
    1617              :     // property are based on 200% depreciation method shown in Appendix A using half year. 15 and 20 are
    1618              :     // based on 150% (Chart 1). For Straight Line depreciation GDS is used for 27 years (actually 27.5)
    1619              :     // 31 years (actually 31.5 years) and 39 years using mid-month. For 40 years ADS is used (chart 2)
    1620              :     // Table A-1 is used for 3, 4, 5, 10, 15 and 20 years. Table A-6 is for 27 years. Table A-7 for 31 years.
    1621              :     // Table A-7a for 39 years. Table A-13 for 40 years. These years are a classification of property
    1622              :     // and should not be confused with the length of the study. For 27 years, 31 years, 39 years and 40 years
    1623              :     // the June value was used.
    1624              : 
    1625              :     // convert construction costs (not salvage) into depreciation
    1626            2 :     elcc->DepreciatedCapital = 0.0; // set all years to zero
    1627           49 :     for (iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1628           47 :         curCapital = elcc->CashFlow[CostCategory::Construction].yrAmount(iYear) + elcc->CashFlow[CostCategory::OtherCapital].yrAmount(iYear);
    1629         1974 :         for (jYear = 0; jYear < SizeDepr; ++jYear) {
    1630         1927 :             curDepYear = iYear + jYear; // start depreciating with the year that the capital was shown and go to years following
    1631         1927 :             if (curDepYear <= elcc->lengthStudyYears) {
    1632          578 :                 elcc->DepreciatedCapital(curDepYear) +=
    1633          578 :                     curCapital * (DepreciationPercentTable[static_cast<int>(elcc->depreciationMethod)][jYear] / 100);
    1634              :             }
    1635              :         }
    1636              :     }
    1637              :     // Using Newnan pg 3880
    1638              :     //   before-tax cash flow
    1639              :     //   depreciation
    1640              :     //   taxable income (before-tax cash flow - depreciation)
    1641              :     //   income taxes (taxable income x incremental tax rate)
    1642              :     //   after-tax cash flow (before-tax cash flow - income taxes)
    1643           49 :     for (iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1644           47 :         elcc->TaxableIncome(iYear) = elcc->CashFlow[CostCategory::TotGrand].yrAmount(iYear) - elcc->DepreciatedCapital(iYear);
    1645           47 :         elcc->Taxes(iYear) = elcc->TaxableIncome(iYear) * elcc->taxRate;
    1646           47 :         elcc->AfterTaxCashFlow(iYear) = elcc->CashFlow[CostCategory::TotGrand].yrAmount(iYear) - elcc->Taxes(iYear);
    1647              :         // the present value after taxes is pretax present value minus the present value of the taxes
    1648           47 :         elcc->AfterTaxPresentValue(iYear) = elcc->CashFlow[CostCategory::TotGrand].yrPresVal(iYear) - elcc->Taxes(iYear) * elcc->SPV(iYear);
    1649              :     }
    1650            2 : }
    1651              : 
    1652              : //======================================================================================================================
    1653              : //======================================================================================================================
    1654              : 
    1655              : //    OUTPUT ROUTINES
    1656              : 
    1657              : //======================================================================================================================
    1658              : //======================================================================================================================
    1659              : 
    1660            2 : void WriteTabularLifeCycleCostReport(EnergyPlusData &state)
    1661              : {
    1662              :     // SUBROUTINE INFORMATION:
    1663              :     //    AUTHOR         Jason Glazer of GARD Analytics, Inc.
    1664              :     //    DATE WRITTEN   June 2010
    1665              :     //    MODIFIED       na
    1666              :     //    RE-ENGINEERED  na
    1667              : 
    1668              :     // PURPOSE OF THIS SUBROUTINE:
    1669              :     //    Write the output report related to life-cycle costing
    1670              :     //    to the tabular output file.
    1671              : 
    1672              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1673              :     // all arrays are in the format: (row, column)
    1674            2 :     Array1D_string columnHead;
    1675            2 :     Array1D_int columnWidth;
    1676            2 :     Array1D_string rowHead;
    1677            2 :     Array2D_string tableBody;
    1678              : 
    1679            2 :     auto const &elcc = state.dataEconLifeCycleCost;
    1680              : 
    1681            2 :     if (elcc->LCCparamPresent && state.dataOutRptTab->displayLifeCycleCostReport) {
    1682              :         //---------------------------------
    1683              :         // Life-Cycle Cost Verification and Results Report
    1684              :         //---------------------------------
    1685            3 :         OutputReportTabular::WriteReportHeaders(state, "Life-Cycle Cost Report", "Entire Facility", OutputProcessor::StoreType::Average);
    1686              :         //---- Life-Cycle Cost Parameters
    1687            1 :         rowHead.allocate(11);
    1688            1 :         columnHead.allocate(1);
    1689            1 :         columnWidth.allocate(1);
    1690            1 :         tableBody.allocate(1, 11);
    1691            1 :         tableBody = "";
    1692            1 :         rowHead(1) = "Name";
    1693            1 :         rowHead(2) = "Discounting Convention";
    1694            1 :         rowHead(3) = "Inflation Approach";
    1695            1 :         rowHead(4) = "Real Discount Rate";
    1696            1 :         rowHead(5) = "Nominal Discount Rate";
    1697            1 :         rowHead(6) = "Inflation";
    1698            1 :         rowHead(7) = "Base Date";
    1699            1 :         rowHead(8) = "Service Date";
    1700            1 :         rowHead(9) = "Length of Study Period in Years";
    1701            1 :         rowHead(10) = "Tax rate";
    1702            1 :         rowHead(11) = "Depreciation Method";
    1703            1 :         columnHead(1) = "Value";
    1704              : 
    1705            1 :         tableBody(1, 1) = elcc->LCCname;
    1706            1 :         tableBody(1, 2) = DiscConvNames[static_cast<int>(elcc->discountConvention)];
    1707            1 :         tableBody(1, 3) = InflApprNames[static_cast<int>(elcc->inflationApproach)];
    1708            1 :         if (elcc->inflationApproach == InflAppr::ConstantDollar) {
    1709            1 :             tableBody(1, 4) = OutputReportTabular::RealToStr(elcc->realDiscountRate, 4);
    1710              :         } else {
    1711            0 :             tableBody(1, 4) = "-- N/A --";
    1712              :         }
    1713            1 :         if (elcc->inflationApproach == InflAppr::CurrentDollar) {
    1714            0 :             tableBody(1, 5) = OutputReportTabular::RealToStr(elcc->nominalDiscountRate, 4);
    1715              :         } else {
    1716            1 :             tableBody(1, 5) = "-- N/A --";
    1717              :         }
    1718            1 :         if (elcc->inflationApproach == InflAppr::CurrentDollar) {
    1719            0 :             tableBody(1, 6) = OutputReportTabular::RealToStr(elcc->inflation, 4);
    1720              :         } else {
    1721            1 :             tableBody(1, 6) = "-- N/A --";
    1722              :         }
    1723            1 :         tableBody(1, 7) = format("{} {}", Util::MonthNamesCC[static_cast<int>(elcc->baseDateMonth)], elcc->baseDateYear);
    1724            1 :         tableBody(1, 8) = format("{} {}", Util::MonthNamesCC[static_cast<int>(elcc->serviceDateMonth)], elcc->serviceDateYear);
    1725            1 :         tableBody(1, 9) = fmt::to_string(elcc->lengthStudyYears);
    1726            1 :         tableBody(1, 10) = OutputReportTabular::RealToStr(elcc->taxRate, 4);
    1727            1 :         tableBody(1, 11) = DeprMethodNames[static_cast<int>(elcc->depreciationMethod)];
    1728              : 
    1729            1 :         columnWidth = 14; // array assignment - same for all columns
    1730            1 :         OutputReportTabular::WriteSubtitle(state, "Life-Cycle Cost Parameters");
    1731            1 :         OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    1732            1 :         if (state.dataSQLiteProcedures->sqlite) {
    1733            0 :             state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    1734              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Life-Cycle Cost Parameters");
    1735              :         }
    1736            1 :         if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    1737            0 :             state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    1738              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Life-Cycle Cost Parameters");
    1739              :         }
    1740              : 
    1741            1 :         columnHead.deallocate();
    1742            1 :         rowHead.deallocate();
    1743            1 :         columnWidth.deallocate();
    1744            1 :         tableBody.deallocate();
    1745              :         //---- Use Price Escalation
    1746            1 :         int numColumns = max(1, elcc->numUsePriceEscalation);
    1747            1 :         rowHead.allocate(elcc->lengthStudyYears + 2);
    1748            1 :         columnHead.allocate(numColumns);
    1749            1 :         columnWidth.dimension(numColumns, 14); // array assignment - same for all columns
    1750            1 :         tableBody.allocate(numColumns, elcc->lengthStudyYears + 2);
    1751            2 :         tableBody = "";
    1752            1 :         columnHead = "none";
    1753            1 :         rowHead(1) = "Resource";
    1754            1 :         rowHead(2) = "Start Date";
    1755           23 :         for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1756           22 :             rowHead(iYear + 2) = fmt::to_string(iYear);
    1757              :         }
    1758            4 :         for (int jObj = 1; jObj <= elcc->numUsePriceEscalation; ++jObj) { // loop through objects not columns to add names
    1759            3 :             columnHead(jObj) = elcc->UsePriceEscalation(jObj).name;
    1760            3 :             tableBody(jObj, 1) = Constant::eResourceNames[static_cast<int>(elcc->UsePriceEscalation(jObj).resource)];
    1761            6 :             tableBody(jObj, 2) = format("{} {}",
    1762            3 :                                         Util::MonthNamesCC[static_cast<int>(elcc->UsePriceEscalation(jObj).escalationStartMonth)],
    1763            6 :                                         elcc->UsePriceEscalation(jObj).escalationStartYear);
    1764              :         }
    1765            4 :         for (int jObj = 1; jObj <= elcc->numUsePriceEscalation; ++jObj) {
    1766           69 :             for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1767           66 :                 tableBody(jObj, iYear + 2) = OutputReportTabular::RealToStr(elcc->UsePriceEscalation(jObj).Escalation(iYear), 6);
    1768              :             }
    1769              :         }
    1770            1 :         OutputReportTabular::WriteSubtitle(state, "Use Price Escalation");
    1771            1 :         OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    1772            1 :         if (state.dataSQLiteProcedures->sqlite) {
    1773            0 :             state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    1774              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Use Price Escalation");
    1775              :         }
    1776            1 :         if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    1777            0 :             state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    1778              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Use Price Escalation");
    1779              :         }
    1780            1 :         columnHead.deallocate();
    1781            1 :         rowHead.deallocate();
    1782            1 :         columnWidth.deallocate();
    1783            1 :         tableBody.deallocate();
    1784              :         //---- Use Adjustment
    1785            1 :         if (elcc->numUseAdjustment >= 1) { // only create table if objects used
    1786            1 :             numColumns = max(1, elcc->numUseAdjustment);
    1787            1 :             int numYears = elcc->lengthStudyYears - (elcc->serviceDateYear - elcc->baseDateYear);
    1788            1 :             rowHead.allocate(numYears + 1);
    1789            1 :             columnHead.allocate(numColumns);
    1790            1 :             columnWidth.dimension(numColumns, 14); // array assignment - same for all columns
    1791            1 :             tableBody.allocate(numColumns, numYears + 1);
    1792            2 :             tableBody = "";
    1793            1 :             columnHead = "none";
    1794            1 :             rowHead(1) = "";
    1795           21 :             for (int iYear = 1; iYear <= numYears; ++iYear) {
    1796           20 :                 rowHead(iYear + 1) = format("{} {}", Util::MonthNamesCC[static_cast<int>(elcc->serviceDateMonth)], elcc->serviceDateYear + iYear - 1);
    1797              :             }
    1798            2 :             for (int jObj = 1; jObj <= elcc->numUseAdjustment; ++jObj) { // loop through objects not columns to add names
    1799            1 :                 columnHead(jObj) = elcc->UseAdjustment(jObj).name;
    1800            1 :                 tableBody(jObj, 1) = Constant::eResourceNames[static_cast<int>(elcc->UseAdjustment(jObj).resource)];
    1801              :             }
    1802            2 :             for (int jObj = 1; jObj <= elcc->numUseAdjustment; ++jObj) {
    1803           21 :                 for (int iYear = 1; iYear <= numYears; ++iYear) {
    1804           20 :                     tableBody(jObj, iYear + 1) = OutputReportTabular::RealToStr(elcc->UseAdjustment(jObj).Adjustment(iYear), 6);
    1805              :                 }
    1806              :             }
    1807            1 :             OutputReportTabular::WriteSubtitle(state, "Use Adjustment");
    1808            1 :             OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    1809            1 :             if (state.dataSQLiteProcedures->sqlite) {
    1810            0 :                 state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    1811              :                     tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Use Adjustment");
    1812              :             }
    1813            1 :             if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    1814            0 :                 state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    1815              :                     tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Use Adjustment");
    1816              :             }
    1817            1 :             columnHead.deallocate();
    1818            1 :             rowHead.deallocate();
    1819            1 :             columnWidth.deallocate();
    1820            1 :             tableBody.deallocate();
    1821              :         }
    1822              :         //---- Cash Flow for Recurring and Nonrecurring Costs
    1823            1 :         numColumns = max(1, elcc->numRecurringCosts + elcc->numNonrecurringCost);
    1824            1 :         rowHead.allocate(elcc->lengthStudyYears + 1);
    1825            1 :         columnHead.allocate(numColumns);
    1826            1 :         columnWidth.dimension(numColumns, 14); // array assignment - same for all columns
    1827            1 :         tableBody.allocate(numColumns, elcc->lengthStudyYears + 1);
    1828            1 :         tableBody = "";
    1829            1 :         rowHead(1) = "";
    1830           23 :         for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1831           22 :             rowHead(iYear + 1) = format("{} {}", Util::MonthNamesCC[static_cast<int>(elcc->baseDateMonth)], elcc->baseDateYear + iYear - 1);
    1832              :         }
    1833            7 :         for (int jObj = 0; jObj < (elcc->numRecurringCosts + elcc->numNonrecurringCost); ++jObj) {
    1834            6 :             int curCashFlow = CostCategory::Num + jObj;
    1835            6 :             columnHead(jObj + 1) = elcc->CashFlow[curCashFlow].name;
    1836              : 
    1837            6 :             tableBody(jObj + 1, 1) = SourceKindTypeNames[static_cast<int>(elcc->CashFlow[curCashFlow].SourceKind)];
    1838              : 
    1839          138 :             for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1840          132 :                 tableBody(jObj + 1, iYear + 1) = OutputReportTabular::RealToStr(elcc->CashFlow[curCashFlow].yrAmount(iYear), 2);
    1841              :             }
    1842              :         }
    1843            1 :         OutputReportTabular::WriteSubtitle(state, "Cash Flow for Recurring and Nonrecurring Costs (Without Escalation)");
    1844            1 :         OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    1845            1 :         if (state.dataSQLiteProcedures->sqlite) {
    1846            0 :             state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(tableBody,
    1847              :                                                                                rowHead,
    1848              :                                                                                columnHead,
    1849              :                                                                                "Life-Cycle Cost Report",
    1850              :                                                                                "Entire Facility",
    1851              :                                                                                "Cash Flow for Recurring and Nonrecurring Costs (Without Escalation)");
    1852              :         }
    1853            1 :         if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    1854            0 :             state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    1855              :                 tableBody,
    1856              :                 rowHead,
    1857              :                 columnHead,
    1858              :                 "Life-Cycle Cost Report",
    1859              :                 "Entire Facility",
    1860              :                 "Cash Flow for Recurring and Nonrecurring Costs (Without Escalation)");
    1861              :         }
    1862            1 :         columnHead.deallocate();
    1863            1 :         rowHead.deallocate();
    1864            1 :         columnWidth.deallocate();
    1865            1 :         tableBody.deallocate();
    1866              :         //---- Energy and Water Cost Cash Flows (Without Escalation)
    1867            1 :         numColumns = max(1, elcc->numResourcesUsed + 1);
    1868            1 :         rowHead.allocate(elcc->lengthStudyYears);
    1869            1 :         columnHead.allocate(numColumns);
    1870            1 :         columnWidth.dimension(numColumns, 14); // array assignment - same for all columns
    1871            1 :         tableBody.allocate(numColumns, elcc->lengthStudyYears);
    1872            1 :         tableBody = "";
    1873           23 :         for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1874           22 :             rowHead(iYear) = format("{} {}", Util::MonthNamesCC[static_cast<int>(elcc->baseDateMonth)], elcc->baseDateYear + iYear - 1);
    1875              :         }
    1876            2 :         for (int jObj = 0; jObj < elcc->numResourcesUsed; ++jObj) {
    1877            1 :             int curCashFlow = CostCategory::Num + elcc->numRecurringCosts + elcc->numNonrecurringCost + jObj;
    1878            1 :             columnHead(jObj + 1) = elcc->CashFlow[curCashFlow].name;
    1879           23 :             for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1880           22 :                 tableBody(jObj + 1, iYear) = OutputReportTabular::RealToStr(elcc->CashFlow[curCashFlow].yrAmount(iYear), 2);
    1881              :             }
    1882              :         }
    1883            1 :         columnHead(numColumns) = Total;
    1884           23 :         for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1885           44 :             tableBody(elcc->numResourcesUsed + 1, iYear) = OutputReportTabular::RealToStr(
    1886           44 :                 elcc->CashFlow[CostCategory::TotEnergy].yrAmount(iYear) + elcc->CashFlow[CostCategory::Water].yrAmount(iYear), 2);
    1887              :         }
    1888            1 :         OutputReportTabular::WriteSubtitle(state, "Energy and Water Cost Cash Flows (Without Escalation)");
    1889            1 :         OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    1890            1 :         if (state.dataSQLiteProcedures->sqlite) {
    1891            0 :             state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    1892              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Energy and Water Cost Cash Flows (Without Escalation)");
    1893              :         }
    1894            1 :         if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    1895            0 :             state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    1896              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Energy and Water Cost Cash Flows (Without Escalation)");
    1897              :         }
    1898            1 :         columnHead.deallocate();
    1899            1 :         rowHead.deallocate();
    1900            1 :         columnWidth.deallocate();
    1901            1 :         tableBody.deallocate();
    1902              :         //---- Energy and Water Cost Cash Flows (With Escalation)
    1903            1 :         numColumns = max(1, elcc->numResourcesUsed + 1);
    1904            1 :         rowHead.allocate(elcc->lengthStudyYears);
    1905            1 :         columnHead.allocate(numColumns);
    1906            1 :         columnWidth.dimension(numColumns, 14); // array assignment - same for all columns
    1907            1 :         tableBody.allocate(numColumns, elcc->lengthStudyYears);
    1908            1 :         tableBody = "";
    1909           23 :         for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1910           22 :             rowHead(iYear) = format("{} {}", Util::MonthNamesCC[static_cast<int>(elcc->baseDateMonth)], elcc->baseDateYear + iYear - 1);
    1911              :         }
    1912            2 :         for (int jObj = 0; jObj < elcc->numResourcesUsed; ++jObj) {
    1913            1 :             int curCashFlow = CostCategory::Num + elcc->numRecurringCosts + elcc->numNonrecurringCost + jObj;
    1914            1 :             columnHead(jObj + 1) = elcc->CashFlow[curCashFlow].name;
    1915            1 :             Constant::eResource curResource = elcc->CashFlow[curCashFlow].Resource;
    1916            1 :             if (elcc->CashFlow[curCashFlow].Resource != Constant::eResource::Water) {
    1917           23 :                 for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1918           22 :                     tableBody(jObj + 1, iYear) = OutputReportTabular::RealToStr(elcc->EscalatedEnergy[iYear][static_cast<int>(curResource)], 2);
    1919              :                 }
    1920              :             } else { // for water just use the original cashflow since not involved in escalation
    1921            0 :                 for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1922            0 :                     tableBody(jObj + 1, iYear) = OutputReportTabular::RealToStr(elcc->CashFlow[curCashFlow].yrAmount(iYear), 2);
    1923              :                 }
    1924              :             }
    1925              :         }
    1926            1 :         columnHead(numColumns) = Total;
    1927           23 :         for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1928           22 :             tableBody(elcc->numResourcesUsed + 1, iYear) =
    1929           44 :                 OutputReportTabular::RealToStr(elcc->EscalatedTotEnergy(iYear) + elcc->CashFlow[CostCategory::Water].yrAmount(iYear), 2);
    1930              :         }
    1931            1 :         OutputReportTabular::WriteSubtitle(state, "Energy and Water Cost Cash Flows (With Escalation)");
    1932            1 :         OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    1933            1 :         if (state.dataSQLiteProcedures->sqlite) {
    1934            0 :             state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    1935              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Energy and Water Cost Cash Flows (With Escalation)");
    1936              :         }
    1937            1 :         if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    1938            0 :             state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    1939              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Energy and Water Cost Cash Flows (With Escalation)");
    1940              :         }
    1941            1 :         columnHead.deallocate();
    1942            1 :         rowHead.deallocate();
    1943            1 :         columnWidth.deallocate();
    1944            1 :         tableBody.deallocate();
    1945              : 
    1946              :         //---- Capital Cash Flow by Category
    1947            1 :         rowHead.allocate(elcc->lengthStudyYears);
    1948            1 :         columnHead.allocate(4);
    1949            1 :         columnWidth.allocate(4);
    1950            1 :         columnWidth = 14; // array assignment - same for all columns
    1951            1 :         tableBody.allocate(4, elcc->lengthStudyYears);
    1952            1 :         tableBody = "";
    1953            4 :         for (int CostCategory = CostCategory::Construction, tableColumnIndex = 1; CostCategory <= CostCategory::OtherCapital;
    1954            3 :              ++tableColumnIndex, ++CostCategory) {
    1955            3 :             columnHead(tableColumnIndex) = CostCategoryNamesNoSpace[static_cast<int>(CostCategory)];
    1956              :         }
    1957            1 :         columnHead(4) = Total;
    1958           23 :         for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1959           22 :             rowHead(iYear) = format("{} {}", Util::MonthNamesCC[static_cast<int>(elcc->baseDateMonth)], elcc->baseDateYear + iYear - 1);
    1960          110 :             for (int CostCategory = CostCategory::Construction, tableColumnIndex = 1; CostCategory <= CostCategory::TotCaptl;
    1961           88 :                  ++tableColumnIndex, ++CostCategory) {
    1962           88 :                 tableBody(tableColumnIndex, iYear) = OutputReportTabular::RealToStr(elcc->CashFlow[CostCategory].yrAmount(iYear), 2);
    1963              :             }
    1964              :         }
    1965            1 :         OutputReportTabular::WriteSubtitle(state, "Capital Cash Flow by Category (Without Escalation)");
    1966            1 :         OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    1967            1 :         if (state.dataSQLiteProcedures->sqlite) {
    1968            0 :             state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    1969              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Capital Cash Flow by Category (Without Escalation)");
    1970              :         }
    1971            1 :         if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    1972            0 :             state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    1973              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Capital Cash Flow by Category (Without Escalation)");
    1974              :         }
    1975            1 :         columnHead.deallocate();
    1976            1 :         rowHead.deallocate();
    1977            1 :         columnWidth.deallocate();
    1978            1 :         tableBody.deallocate();
    1979              :         //---- Operating Cash Flow by Category (Without Escalation)
    1980            1 :         rowHead.allocate(elcc->lengthStudyYears);
    1981            1 :         columnHead.allocate(10);
    1982            1 :         columnWidth.allocate(10);
    1983            1 :         columnWidth = 14; // array assignment - same for all columns
    1984            1 :         tableBody.allocate(10, elcc->lengthStudyYears);
    1985            1 :         tableBody = "";
    1986           10 :         for (int CostCategory = CostCategory::Maintenance, tableColumnIndex = 1; CostCategory <= CostCategory::Energy;
    1987            9 :              ++tableColumnIndex, ++CostCategory) {
    1988            9 :             columnHead(tableColumnIndex) = CostCategoryNamesNoSpace[CostCategory];
    1989              :         }
    1990            1 :         columnHead(10) = Total;
    1991              : 
    1992           23 :         for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    1993           22 :             rowHead(iYear) = format("{} {}", Util::MonthNamesCC[static_cast<int>(elcc->baseDateMonth)], elcc->baseDateYear + iYear - 1);
    1994          242 :             for (int CashFlowCostCategory = CostCategory::Maintenance; CashFlowCostCategory <= CostCategory::TotOper; ++CashFlowCostCategory) {
    1995          220 :                 tableBody(CashFlowCostCategory + 1, iYear) = OutputReportTabular::RealToStr(elcc->CashFlow[CashFlowCostCategory].yrAmount(iYear), 2);
    1996              :             }
    1997              :         }
    1998            1 :         OutputReportTabular::WriteSubtitle(state, "Operating Cash Flow by Category (Without Escalation)");
    1999            1 :         OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    2000            1 :         if (state.dataSQLiteProcedures->sqlite) {
    2001            0 :             state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    2002              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Operating Cash Flow by Category (Without Escalation)");
    2003              :         }
    2004            1 :         if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    2005            0 :             state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    2006              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Operating Cash Flow by Category (Without Escalation)");
    2007              :         }
    2008            1 :         columnHead.deallocate();
    2009            1 :         rowHead.deallocate();
    2010            1 :         columnWidth.deallocate();
    2011            1 :         tableBody.deallocate();
    2012              :         //---- Operating Cash Flow by Category (With Escalation)
    2013            1 :         rowHead.allocate(elcc->lengthStudyYears);
    2014            1 :         columnHead.allocate(10);
    2015            1 :         columnWidth.allocate(10);
    2016            1 :         columnWidth = 14; // array assignment - same for all columns
    2017            1 :         tableBody.allocate(10, elcc->lengthStudyYears);
    2018            1 :         tableBody = "";
    2019           10 :         for (int CostCategory = CostCategory::Maintenance, tableColumnIndex = 1; CostCategory <= CostCategory::Energy;
    2020            9 :              ++tableColumnIndex, ++CostCategory) {
    2021            9 :             columnHead(tableColumnIndex) = CostCategoryNamesNoSpace[CostCategory];
    2022              :         }
    2023            1 :         columnHead(10) = Total;
    2024              : 
    2025           23 :         for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    2026           22 :             rowHead(iYear) = format("{} {}", Util::MonthNamesCC[static_cast<int>(elcc->baseDateMonth)], elcc->baseDateYear + iYear - 1);
    2027          198 :             for (int CashFlowCostCategory = CostCategory::Maintenance; CashFlowCostCategory <= CostCategory::Water; ++CashFlowCostCategory) {
    2028          176 :                 tableBody(CashFlowCostCategory + 1, iYear) = OutputReportTabular::RealToStr(elcc->CashFlow[CashFlowCostCategory].yrAmount(iYear), 2);
    2029              :             }
    2030           22 :             tableBody(9, iYear) = OutputReportTabular::RealToStr(elcc->EscalatedTotEnergy(iYear), 2);
    2031           22 :             Real64 yearly_total_cost = elcc->CashFlow[CostCategory::TotOper].yrAmount(iYear) + elcc->EscalatedTotEnergy(iYear) -
    2032           22 :                                        elcc->CashFlow[CostCategory::TotEnergy].yrAmount(iYear);
    2033           22 :             tableBody(10, iYear) = OutputReportTabular::RealToStr(yearly_total_cost, 2);
    2034              :         }
    2035            1 :         OutputReportTabular::WriteSubtitle(state, "Operating Cash Flow by Category (With Escalation)");
    2036            1 :         OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    2037            1 :         if (state.dataSQLiteProcedures->sqlite) {
    2038            0 :             state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    2039              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Operating Cash Flow by Category (With Escalation)");
    2040              :         }
    2041            1 :         if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    2042            0 :             state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    2043              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Operating Cash Flow by Category (With Escalation)");
    2044              :         }
    2045            1 :         columnHead.deallocate();
    2046            1 :         rowHead.deallocate();
    2047            1 :         columnWidth.deallocate();
    2048            1 :         tableBody.deallocate();
    2049              :         //---- DEBUG ONLY - Monthly Cash Flows
    2050              :         // bool showMonthlyCashFlows = false;
    2051              :         // if (showMonthlyCashFlows) {
    2052              :         //    rowHead.allocate(elcc->lengthStudyTotalMonths);
    2053              :         //    columnHead.allocate(elcc->numCashFlow);
    2054              :         //    columnWidth.allocate(elcc->numCashFlow);
    2055              :         //    tableBody.allocate(elcc->numCashFlow, elcc->lengthStudyTotalMonths);
    2056              :         //    tableBody = "";
    2057              :         //    columnHead(1) = "mnt";
    2058              :         //    columnHead(2) = "rpr";
    2059              :         //    columnHead(3) = "opr";
    2060              :         //    columnHead(4) = "repl";
    2061              :         //    columnHead(5) = "mOvhl";
    2062              :         //    columnHead(6) = "MOvhl";
    2063              :         //    columnHead(7) = "oOpr";
    2064              :         //    columnHead(8) = "cons";
    2065              :         //    columnHead(9) = "slvg";
    2066              :         //    columnHead(10) = "oCap";
    2067              :         //    columnHead(11) = "H2O";
    2068              :         //    columnHead(12) = "ene";
    2069              :         //    columnHead(13) = "tEne";
    2070              :         //    columnHead(14) = "tOpr";
    2071              :         //    columnHead(15) = "tCap";
    2072              :         //    columnHead(16) = "Totl";
    2073              :         //    for (int jObj = CostCategory::Num; jObj < elcc->numCashFlow; ++jObj) {
    2074              :         //        columnHead(jObj + 1) = elcc->CashFlow[jObj].name;
    2075              :         //    }
    2076              :         //    for (int kMonth = 1; kMonth <= elcc->lengthStudyTotalMonths; ++kMonth) {
    2077              :         //        rowHead(kMonth) = format("{} {}",
    2078              :         //                                 Util::MonthNamesCC[static_cast<int>(1 + (kMonth + elcc->baseDateMonth - 2) % 12) - 1],
    2079              :         //                                 elcc->baseDateYear + int((kMonth - 1) / 12));
    2080              :         //        for (int jObj = 0; jObj < elcc->numCashFlow; ++jObj) {
    2081              :         //            tableBody(jObj + 1, kMonth) = OutputReportTabular::RealToStr(elcc->CashFlow[jObj].mnAmount(kMonth), 2);
    2082              :         //        }
    2083              :         //    }
    2084              :         //    OutputReportTabular::WriteSubtitle(state, "DEBUG ONLY - Monthly Cash Flows");
    2085              :         //    OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    2086              :         //    if (state.dataSQLiteProcedures->sqlite) {
    2087              :         //        state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    2088              :         //            tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "DEBUG ONLY - Monthly Cash Flows");
    2089              :         //    }
    2090              :         //    if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    2091              :         //        state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    2092              :         //            tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "DEBUG ONLY - Monthly Cash Flows");
    2093              :         //    }
    2094              :         //    columnHead.deallocate();
    2095              :         //    rowHead.deallocate();
    2096              :         //    columnWidth.deallocate();
    2097              :         //    tableBody.deallocate();
    2098              :         //}
    2099              :         //---- Monthly Total Cash Flow
    2100            1 :         rowHead.allocate(elcc->lengthStudyYears);
    2101            1 :         columnHead.allocate(12);
    2102            1 :         columnWidth.allocate(12);
    2103            1 :         columnWidth = 14; // array assignment - same for all columns
    2104            1 :         tableBody.allocate(12, elcc->lengthStudyYears);
    2105            1 :         tableBody = "";
    2106           13 :         for (int kMonth = 1; kMonth <= 12; ++kMonth) {
    2107           12 :             columnHead(kMonth) = Util::MonthNamesCC[static_cast<int>(kMonth - 1)];
    2108              :         }
    2109           23 :         for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    2110           22 :             rowHead(iYear) = fmt::to_string(elcc->baseDateYear + iYear - 1);
    2111          286 :             for (int kMonth = 1; kMonth <= 12; ++kMonth) {
    2112          264 :                 tableBody(kMonth, iYear) =
    2113          528 :                     OutputReportTabular::RealToStr(elcc->CashFlow[CostCategory::TotGrand].mnAmount((iYear - 1) * 12 + kMonth), 2);
    2114              :             }
    2115              :         }
    2116            1 :         OutputReportTabular::WriteSubtitle(state, "Monthly Total Cash Flow (Without Escalation)");
    2117            1 :         OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    2118            1 :         if (state.dataSQLiteProcedures->sqlite) {
    2119            0 :             state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    2120              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Monthly Total Cash Flow (Without Escalation)");
    2121              :         }
    2122            1 :         if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    2123            0 :             state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    2124              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Monthly Total Cash Flow (Without Escalation)");
    2125              :         }
    2126            1 :         columnHead.deallocate();
    2127            1 :         rowHead.deallocate();
    2128            1 :         columnWidth.deallocate();
    2129            1 :         tableBody.deallocate();
    2130              :         //---- Present Value for Recurring, Nonrecurring and Energy Costs
    2131            1 :         int numRows = max(1, elcc->numRecurringCosts + elcc->numNonrecurringCost + elcc->numResourcesUsed);
    2132            1 :         rowHead.allocate(numRows + 1);
    2133            1 :         columnHead.allocate(5);
    2134            1 :         columnWidth.allocate(5);
    2135            1 :         columnWidth = 14; // array assignment - same for all columns
    2136            1 :         tableBody.allocate(5, numRows + 1);
    2137            1 :         tableBody = "";
    2138            1 :         columnHead(1) = "Category";
    2139            1 :         columnHead(2) = "Kind";
    2140            1 :         columnHead(3) = "Cost";
    2141            1 :         columnHead(4) = "Present Value";
    2142            1 :         columnHead(5) = "Present Value Factor";
    2143            1 :         Real64 totalPV = 0.0;
    2144            1 :         rowHead(numRows + 1) = TotalUC;
    2145            8 :         for (int jObj = 0; jObj < (elcc->numRecurringCosts + elcc->numNonrecurringCost + elcc->numResourcesUsed); ++jObj) {
    2146            7 :             int offset = CostCategory::Num;
    2147            7 :             rowHead(jObj + 1) = elcc->CashFlow[offset + jObj].name;
    2148            7 :             switch (elcc->CashFlow[offset + jObj].Category) {
    2149            7 :             case CostCategory::Maintenance:
    2150              :             case CostCategory::Repair:
    2151              :             case CostCategory::Operation:
    2152              :             case CostCategory::Replacement:
    2153              :             case CostCategory::MinorOverhaul:
    2154              :             case CostCategory::MajorOverhaul:
    2155              :             case CostCategory::OtherOperational:
    2156              :             case CostCategory::Construction:
    2157              :             case CostCategory::Salvage:
    2158              :             case CostCategory::OtherCapital:
    2159              :             case CostCategory::Water:
    2160              :             case CostCategory::Energy: {
    2161            7 :                 tableBody(1, jObj + 1) = CostCategoryNames[static_cast<int>(elcc->CashFlow[offset + jObj].Category)];
    2162            7 :                 break;
    2163              :             }
    2164            0 :             default:
    2165            0 :                 tableBody(1, jObj + 1) = "-";
    2166            0 :                 break;
    2167              :             }
    2168            7 :             switch (elcc->CashFlow[offset + jObj].SourceKind) {
    2169            6 :             case SourceKindType::Nonrecurring:
    2170              :             case SourceKindType::Recurring: {
    2171            6 :                 tableBody(2, jObj + 1) = SourceKindTypeNames[static_cast<int>(elcc->CashFlow[offset + jObj].SourceKind)];
    2172            6 :                 break;
    2173              :             }
    2174            1 :             case SourceKindType::Resource: {
    2175            1 :                 if (elcc->CashFlow[offset + jObj].Category == CostCategory::Water) {
    2176            0 :                     tableBody(2, jObj + 1) = ResourceCostCategoryNames[static_cast<int>(ResourceCostCategory::Water)];
    2177              :                 } else {
    2178            1 :                     tableBody(2, jObj + 1) = ResourceCostCategoryNames[static_cast<int>(ResourceCostCategory::Energy)];
    2179              :                 }
    2180            1 :                 break;
    2181              :             }
    2182            0 :             default: {
    2183            0 :                 tableBody(2, jObj + 1) = "-";
    2184            0 :                 break;
    2185              :             }
    2186              :             }
    2187            7 :             tableBody(3, jObj + 1) = OutputReportTabular::RealToStr(elcc->CashFlow[offset + jObj].orginalCost, 2);
    2188            7 :             tableBody(4, jObj + 1) = OutputReportTabular::RealToStr(elcc->CashFlow[offset + jObj].presentValue, 2);
    2189            7 :             totalPV += elcc->CashFlow[offset + jObj].presentValue;
    2190            7 :             if (elcc->CashFlow[offset + jObj].orginalCost != 0.0) {
    2191            7 :                 tableBody(5, jObj + 1) =
    2192           14 :                     OutputReportTabular::RealToStr(elcc->CashFlow[offset + jObj].presentValue / elcc->CashFlow[offset + jObj].orginalCost, 4);
    2193              :             } else {
    2194            0 :                 tableBody(5, jObj + 1) = "-";
    2195              :             }
    2196              :         }
    2197            1 :         tableBody(4, numRows + 1) = OutputReportTabular::RealToStr(totalPV, 2);
    2198            1 :         OutputReportTabular::WriteSubtitle(state, "Present Value for Recurring, Nonrecurring and Energy Costs (Before Tax)");
    2199            1 :         OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    2200            1 :         if (state.dataSQLiteProcedures->sqlite) {
    2201            0 :             state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    2202              :                 tableBody,
    2203              :                 rowHead,
    2204              :                 columnHead,
    2205              :                 "Life-Cycle Cost Report",
    2206              :                 "Entire Facility",
    2207              :                 "Present Value for Recurring, Nonrecurring and Energy Costs (Before Tax)");
    2208              :         }
    2209            1 :         if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    2210            0 :             state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    2211              :                 tableBody,
    2212              :                 rowHead,
    2213              :                 columnHead,
    2214              :                 "Life-Cycle Cost Report",
    2215              :                 "Entire Facility",
    2216              :                 "Present Value for Recurring, Nonrecurring and Energy Costs (Before Tax)");
    2217              :         }
    2218            1 :         columnHead.deallocate();
    2219            1 :         rowHead.deallocate();
    2220            1 :         columnWidth.deallocate();
    2221            1 :         tableBody.deallocate();
    2222              :         //---- Present Value by Category
    2223            1 :         rowHead.allocate(16);
    2224            1 :         columnHead.allocate(1);
    2225            1 :         columnWidth.allocate(1);
    2226            1 :         columnWidth = 14; // array assignment - same for all columns
    2227            1 :         tableBody.allocate(1, 16);
    2228            1 :         tableBody = "";
    2229           17 :         for (int CashFlowCostCategory = CostCategory::Maintenance; CashFlowCostCategory <= CostCategory::TotGrand; ++CashFlowCostCategory) {
    2230           16 :             rowHead(CashFlowCostCategory + 1) = CostCategoryNames[CashFlowCostCategory];
    2231              :         }
    2232            1 :         columnHead(1) = "Present Value";
    2233              : 
    2234           17 :         for (int CashFlowCostCategory = CostCategory::Maintenance; CashFlowCostCategory <= CostCategory::TotGrand; ++CashFlowCostCategory) {
    2235           16 :             tableBody(1, CashFlowCostCategory + 1) = OutputReportTabular::RealToStr(elcc->CashFlow[CashFlowCostCategory].presentValue, 2);
    2236              :         }
    2237              : 
    2238            1 :         OutputReportTabular::WriteSubtitle(state, "Present Value by Category");
    2239            1 :         OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    2240            1 :         if (state.dataSQLiteProcedures->sqlite) {
    2241            0 :             state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    2242              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Present Value by Category");
    2243              :         }
    2244            1 :         if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    2245            0 :             state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    2246              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Present Value by Category");
    2247              :         }
    2248            1 :         columnHead.deallocate();
    2249            1 :         rowHead.deallocate();
    2250            1 :         columnWidth.deallocate();
    2251            1 :         tableBody.deallocate();
    2252              :         //---- Present Value by Year
    2253            1 :         rowHead.allocate(elcc->lengthStudyYears + 1);
    2254            1 :         columnHead.allocate(3);
    2255            1 :         columnWidth.allocate(3);
    2256            1 :         columnWidth = 14; // array assignment - same for all columns
    2257            1 :         tableBody.allocate(3, elcc->lengthStudyYears + 1);
    2258            1 :         tableBody = "";
    2259            1 :         columnHead(1) = "Total Cost (Without Escalation)";
    2260            1 :         columnHead(2) = "Total Cost (With Escalation)";
    2261            1 :         columnHead(3) = "Present Value of Costs";
    2262              : 
    2263            1 :         totalPV = 0.0;
    2264           23 :         for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    2265           22 :             rowHead(iYear) = format("{} {}", Util::MonthNamesCC[static_cast<int>(elcc->baseDateMonth)], elcc->baseDateYear + iYear - 1);
    2266           22 :             tableBody(1, iYear) = OutputReportTabular::RealToStr(elcc->CashFlow[CostCategory::TotGrand].yrAmount(iYear), 2);
    2267              :             // adjust for escalated energy costs
    2268           22 :             Real64 yearly_total_cost = elcc->CashFlow[CostCategory::TotGrand].yrAmount(iYear) + elcc->EscalatedTotEnergy(iYear) -
    2269           22 :                                        elcc->CashFlow[CostCategory::TotEnergy].yrAmount(iYear);
    2270           22 :             tableBody(2, iYear) = OutputReportTabular::RealToStr(yearly_total_cost, 2);
    2271           22 :             tableBody(3, iYear) = OutputReportTabular::RealToStr(elcc->CashFlow[CostCategory::TotGrand].yrPresVal(iYear), 2);
    2272           22 :             totalPV += elcc->CashFlow[CostCategory::TotGrand].yrPresVal(iYear);
    2273              :         }
    2274              : 
    2275            1 :         rowHead(elcc->lengthStudyYears + 1) = TotalUC;
    2276            1 :         tableBody(3, elcc->lengthStudyYears + 1) = OutputReportTabular::RealToStr(totalPV, 2);
    2277              : 
    2278            1 :         OutputReportTabular::WriteSubtitle(state, "Present Value by Year");
    2279            1 :         OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    2280            1 :         if (state.dataSQLiteProcedures->sqlite) {
    2281            0 :             state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    2282              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Present Value by Year");
    2283              :         }
    2284            1 :         if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    2285            0 :             state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    2286              :                 tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "Present Value by Year");
    2287              :         }
    2288            1 :         columnHead.deallocate();
    2289            1 :         rowHead.deallocate();
    2290            1 :         columnWidth.deallocate();
    2291            1 :         tableBody.deallocate();
    2292              :         //---- After Tax Estimate
    2293            1 :         if (elcc->taxRate != 0.0) {
    2294            0 :             rowHead.allocate(elcc->lengthStudyYears + 1);
    2295            0 :             columnHead.allocate(5);
    2296            0 :             columnWidth.allocate(5);
    2297            0 :             columnWidth = 14; // array assignment - same for all columns
    2298            0 :             tableBody.allocate(5, elcc->lengthStudyYears + 1);
    2299            0 :             tableBody = "";
    2300            0 :             columnHead(1) = "Depreciated Capital";
    2301            0 :             columnHead(2) = "Taxable Income";
    2302            0 :             columnHead(3) = "Income Taxes";
    2303            0 :             columnHead(4) = "After Tax Cash Flow";
    2304            0 :             columnHead(5) = "After Tax Present Value";
    2305              : 
    2306            0 :             totalPV = 0.0;
    2307            0 :             for (int iYear = 1; iYear <= elcc->lengthStudyYears; ++iYear) {
    2308            0 :                 rowHead(iYear) = format("{} {}", Util::MonthNamesCC[static_cast<int>(elcc->baseDateMonth)], elcc->baseDateYear + iYear - 1);
    2309            0 :                 tableBody(1, iYear) = OutputReportTabular::RealToStr(elcc->DepreciatedCapital(iYear), 2);
    2310            0 :                 tableBody(2, iYear) = OutputReportTabular::RealToStr(elcc->TaxableIncome(iYear), 2);
    2311            0 :                 tableBody(3, iYear) = OutputReportTabular::RealToStr(elcc->Taxes(iYear), 2);
    2312            0 :                 tableBody(4, iYear) = OutputReportTabular::RealToStr(elcc->AfterTaxCashFlow(iYear), 2);
    2313            0 :                 tableBody(5, iYear) = OutputReportTabular::RealToStr(elcc->AfterTaxPresentValue(iYear), 2);
    2314            0 :                 totalPV += elcc->AfterTaxPresentValue(iYear);
    2315              :             }
    2316              : 
    2317            0 :             rowHead(elcc->lengthStudyYears + 1) = TotalUC;
    2318            0 :             tableBody(5, elcc->lengthStudyYears + 1) = OutputReportTabular::RealToStr(totalPV, 2);
    2319              : 
    2320            0 :             OutputReportTabular::WriteSubtitle(state, "After Tax Estimate");
    2321            0 :             OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
    2322            0 :             if (state.dataSQLiteProcedures->sqlite) {
    2323            0 :                 state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
    2324              :                     tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "After Tax Estimate");
    2325              :             }
    2326            0 :             if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
    2327            0 :                 state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
    2328              :                     tableBody, rowHead, columnHead, "Life-Cycle Cost Report", "Entire Facility", "After Tax Estimate");
    2329              :             }
    2330            0 :             columnHead.deallocate();
    2331            0 :             rowHead.deallocate();
    2332            0 :             columnWidth.deallocate();
    2333            0 :             tableBody.deallocate();
    2334              :         }
    2335              :     }
    2336            2 : }
    2337              : 
    2338              : } // namespace EnergyPlus::EconomicLifeCycleCost
        

Generated by: LCOV version 2.0-1