LCOV - code coverage report
Current view: top level - EnergyPlus - EconomicLifeCycleCost.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 865 1134 76.3 %
Date: 2024-08-23 23:50:59 Functions: 12 12 100.0 %

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

Generated by: LCOV version 1.14