Question-and-Answer Resource for the Building Energy Modeling Community
Get started with the Help page
Ask Your Question
1

Clarifications regarding BEopt modified payback period

asked 2023-03-07 16:32:43 -0500

jpierce's avatar

updated 2023-03-08 09:56:46 -0500

Hello,

I am seeking clarification on how BEopt's modified payback period is calculated. The help in v2.8 and v3.0 include a general description, but there are some ambiguities, and unlike the other financial metrics there is no equation to parse. Below is some pseudo-code indicating my understanding of the description (for a thirty year analysis period), but we are not able to faithfully recreate BEopt's values.

IF SUM(PACKAGE UTILITIES[1-30]) <= SUM(REFERENCE UTILITIES[1-30])
    EXPENSE=PACKAGE INITIAL COST - REFERENCE INITIAL COST
    SAVED=0

    FOR YR IN 1 TO 30
        EXPENSE+=PACKAGE REPLACEMENT[YR] - REFERENCE PACKAGE REPLACEMENT[YR]
        SAVED+=PACKAGE UTILITY[YR] - REFERENCE UTILITY[YR]

        IF SAVED>=EXPENSE
            PAYBACK=YR-1 + (SAVED-EXPENSE)/PACKAGE UTILITY[YR]
            BREAK
        END
    END
ELSE
    PAYBACK = NaN
END

P.S. We need to calculate our own modified payback periods, because we want to produce payback periods for heat pump packages that use a furnace home as the point of comparison, since they are still the most prevalent equipment in our market.

edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
2

answered 2023-03-08 09:32:48 -0500

updated 2023-03-08 10:18:17 -0500

Edit: Sorry, you wanted modified payback and not modified internal rate of return.

Here is the modified payback calculation:

public double CalculateModifiedPayback(OutputPoint outputPt, OutputPoint refOutputPt)
        {
            // Calculate total of cash outflows
            float TotalCashOutflow = 0;
            for (int year = 0; year <= AnalysisPd; year++)
            {
                TotalCashOutflow += (float)GetPresentValueGivenFutureCost(CalculateNetHomeownerCashFlowForYear(outputPt, refOutputPt, year, false), year, GetNominalDiscountRate());
            }

            // Calculate cumulative positive cash flows
            float[] CumulativePositiveCashFlows = new float[AnalysisPd + 1];
            for (int year = 0; year <= AnalysisPd; year++)
            {
                CumulativePositiveCashFlows[year] = -1 * (float)GetPresentValueGivenFutureCost(CalculateNetHomeownerCashFlowForYear(outputPt, refOutputPt, year, true), year, GetNominalDiscountRate());
                if (year > 0)
                    CumulativePositiveCashFlows[year] += CumulativePositiveCashFlows[year - 1];
            }

            // Find year where cumulative positive cash flow exceeds the total cash outflow
            for (int year = 0; year <= AnalysisPd; year++)
            {
                if (CumulativePositiveCashFlows[year] >= TotalCashOutflow)
                {
                    if (year == 0)
                        return 0;

                    // Interpolate between previous year and this year to obtain
                    // a non-integer payback value
                    return year - 1 + (TotalCashOutflow - CumulativePositiveCashFlows[year - 1]) / (CumulativePositiveCashFlows[year] - CumulativePositiveCashFlows[year - 1]);
                }
            }

            return double.NaN;
        }

CalculateNetHomeownerCashFlowForYear method:

private double CalculateNetHomeownerCashFlowForYear(OutputPoint outputPt, OutputPoint refOutputPt, int year, bool PositiveOnly)
        {
            double retval = 0;
            retval += CalculateNetCashFlowForYear(outputPt.NominalCashFlow(year).Incentives, refOutputPt.NominalCashFlow(year).Incentives, PositiveOnly);
            retval += CalculateNetCashFlowForYear(outputPt.NominalCashFlow(year).LoanInterest, refOutputPt.NominalCashFlow(year).LoanInterest, PositiveOnly);
            retval += CalculateNetCashFlowForYear(outputPt.NominalCashFlow(year).LoanPrincipal, refOutputPt.NominalCashFlow(year).LoanPrincipal, PositiveOnly);
            retval += CalculateNetCashFlowForYear(outputPt.NominalCashFlow(year).LoanTaxDeduction, refOutputPt.NominalCashFlow(year).LoanTaxDeduction, PositiveOnly);
            retval += CalculateNetCashFlowForYear(outputPt.NominalCashFlow(year).ReplacementCost, refOutputPt.NominalCashFlow(year).ReplacementCost, PositiveOnly);
            retval += CalculateNetCashFlowForYear(outputPt.NominalCashFlow(year).ResidualValue, refOutputPt.NominalCashFlow(year).ResidualValue, PositiveOnly);
            retval += CalculateNetCashFlowForYear(outputPt.NominalCashFlow(year).FederalTaxCredits, refOutputPt.NominalCashFlow(year).FederalTaxCredits, PositiveOnly);
            retval += CalculateNetCashFlowForYear(outputPt.NominalCashFlow(year).NonFederalTaxCredits, refOutputPt.NominalCashFlow(year).NonFederalTaxCredits, PositiveOnly);
            retval += CalculateNetCashFlowForYear(outputPt.NominalCashFlow(year).UtilityBill, refOutputPt.NominalCashFlow(year).UtilityBill, PositiveOnly);
            retval += CalculateNetCashFlowForYear(outputPt.NominalCashFlow(year).CashPayment, refOutputPt.NominalCashFlow(year).CashPayment, PositiveOnly);
            return retval;
        }

CalculateNetCashFlowForYear method:

private double CalculateNetCashFlowForYear(float outputPtVal, float refOutputPtVal, bool PositiveOnly)
        {
            double diff = outputPtVal - refOutputPtVal;
            if ((diff < 0 && PositiveOnly) || (diff > 0 && !PositiveOnly))
                return diff;
            return 0;
        }

GetPresentValueGivenFutureCost method:

public static double GetPresentValueGivenFutureCost(double Cost, double YearOfCost, double DiscountRate)
        {
            return (Cost / (Math.Pow((1 + DiscountRate), YearOfCost)));
        }
edit flag offensive delete link more

Comments

Thanks, but that's modified internal rate of return, not modified payback. The general flow looks similar to what I hypothesized, but since some of the trappings are different due to it having a different purpose it's a little difficult to be certain how to adapt this. In particular, there's nothing that relates to the least clear portion of the help file's description of modified payback, "The modified payback is the moment in time where the cumulative positive cash flow exceeds the total cash outflow". For example, is residual value really part of payback period?

jpierce's avatar jpierce  ( 2023-03-08 09:56:16 -0500 )edit

Sorry, I updated it to show the modified payback calculation.

shorowit's avatar shorowit  ( 2023-03-08 10:00:43 -0500 )edit

Thanks. CalculateNetHomeownerCashFlowForYeart got wiped in the update. What's the difference between true and false for the fourth argument? And I assume GetPresentValueGivenFutureCost is standard NPV?

jpierce's avatar jpierce  ( 2023-03-08 10:12:45 -0500 )edit
1

I added the additional methods above.

shorowit's avatar shorowit  ( 2023-03-08 10:18:32 -0500 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Careers

Question Tools

1 follower

Stats

Asked: 2023-03-07 16:32:43 -0500

Seen: 106 times

Last updated: Mar 08 '23