LCOV - code coverage report
Current view: top level - EnergyPlus - EconomicLifeCycleCost.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 32.7 % 1140 373
Test Date: 2025-06-02 12:03:30 Functions: 75.0 % 12 9

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

Generated by: LCOV version 2.0-1