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

Generated by: LCOV version 2.0-1