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