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

Revision history [back]

Here is the MIRR calculation in BEopt:

public double CalculateModifiedInternalRateOfReturn(OutputPoint outputPt, OutputPoint refOutputPt)
        {
            float[] NegativeCashFlows = new float[AnalysisPd + 1];
            float[] PositiveCashFlows = new float[AnalysisPd + 1];

            for (int year = 0; year <= AnalysisPd; year++)
            {
                float NetCashFlow = (float)(CalculateHomeownerCashFlowForYear(refOutputPt, year) - CalculateHomeownerCashFlowForYear(outputPt, year));
                if (NetCashFlow > 0)
                    PositiveCashFlows[year] = NetCashFlow;
                else
                    NegativeCashFlows[year] = NetCashFlow;
            }

            double PresentValue = CalculatePresentValueOfCosts(NegativeCashFlows, null);
            double FutureValue = CalculateFutureValueOfCosts(PositiveCashFlows, null);

            if (PresentValue == 0)
                return double.NaN; // Infinite MIRR
            double mirr = (Math.Pow(-FutureValue / PresentValue, (1.0 / AnalysisPd)) - 1) * 100;
            return mirr;
        }

CalculateHomeownerCashFlowForYear is simply:

private double CalculateHomeownerCashFlowForYear(OutputPoint outputPt, int year)
        {
            return outputPt.NominalCashFlow(year).Incentives +
                   outputPt.NominalCashFlow(year).LoanInterest +
                   outputPt.NominalCashFlow(year).LoanPrincipal +
                   outputPt.NominalCashFlow(year).LoanTaxDeduction +
                   outputPt.NominalCashFlow(year).ReplacementCost +
                   outputPt.NominalCashFlow(year).ResidualValue +
                   outputPt.NominalCashFlow(year).FederalTaxCredits +
                   outputPt.NominalCashFlow(year).NonFederalTaxCredits +
                   outputPt.NominalCashFlow(year).UtilityBill +
                   outputPt.NominalCashFlow(year).CashPayment;
        }

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

Here is the MIRR calculation in BEopt:modified payback calculation:

public double CalculateModifiedInternalRateOfReturn(OutputPoint 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[] NegativeCashFlows CumulativePositiveCashFlows = new float[AnalysisPd + 1];
            float[] PositiveCashFlows = new float[AnalysisPd + 1];

            for (int year = 0; year <= AnalysisPd; year++)
            {
                float NetCashFlow CumulativePositiveCashFlows[year] = (float)(CalculateHomeownerCashFlowForYear(refOutputPt, year) - CalculateHomeownerCashFlowForYear(outputPt, year));
-1 * (float)GetPresentValueGivenFutureCost(CalculateNetHomeownerCashFlowForYear(outputPt, refOutputPt, year, true), year, GetNominalDiscountRate());
                if (NetCashFlow (year > 0)
                    PositiveCashFlows[year] CumulativePositiveCashFlows[year] += CumulativePositiveCashFlows[year - 1];
            }

            // Find year where cumulative positive cash flow exceeds the total cash outflow
            for (int year = NetCashFlow;
                else
                    NegativeCashFlows[year] = NetCashFlow;
            }

            double PresentValue = CalculatePresentValueOfCosts(NegativeCashFlows, null);
            double FutureValue = CalculateFutureValueOfCosts(PositiveCashFlows, null);

0; year <= AnalysisPd; year++)
            {
                if (PresentValue (CumulativePositiveCashFlows[year] >= TotalCashOutflow)
                {
                    if (year == 0)
                 return double.NaN; 0;

                    // Infinite MIRR
            double mirr = (Math.Pow(-FutureValue Interpolate between previous year and this year to obtain
                    // a non-integer payback value
                    return year - 1 + (TotalCashOutflow - CumulativePositiveCashFlows[year - 1]) / PresentValue, (1.0 / AnalysisPd)) (CumulativePositiveCashFlows[year] - 1) * 100;
CumulativePositiveCashFlows[year - 1]);
                }
            }

            return mirr;
double.NaN;
        }

CalculateHomeownerCashFlowForYear is simply:

private double CalculateHomeownerCashFlowForYear(OutputPoint outputPt, int year)
        {
            return outputPt.NominalCashFlow(year).Incentives +
                   outputPt.NominalCashFlow(year).LoanInterest +
                   outputPt.NominalCashFlow(year).LoanPrincipal +
                   outputPt.NominalCashFlow(year).LoanTaxDeduction +
                   outputPt.NominalCashFlow(year).ReplacementCost +
                   outputPt.NominalCashFlow(year).ResidualValue +
                   outputPt.NominalCashFlow(year).FederalTaxCredits +
                   outputPt.NominalCashFlow(year).NonFederalTaxCredits +
                   outputPt.NominalCashFlow(year).UtilityBill +
                   outputPt.NominalCashFlow(year).CashPayment;
        }

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)));
        }