Skip to content

Instantly share code, notes, and snippets.

@brianbruggeman
Created March 6, 2015 01:43
Show Gist options
  • Save brianbruggeman/797f18fecf021b7414d9 to your computer and use it in GitHub Desktop.
Save brianbruggeman/797f18fecf021b7414d9 to your computer and use it in GitHub Desktop.
solar energy roi
#!/usr/bin/env python
"""
Calculates return on investment over time.
Usage:
calc_roi [options]
Options:
-h, --help This message
-u, --unit-cost <uc> Cost per panel (USD) [Default: 750]
-i, --initial <ic> Initial investment cost (USD) [Default: 9000]
-i, --units <units> Initial units purchased [Default: 15]
-d, --degradation <deg> Efficiency degradation per year % [Default: 0.007]
-y, --years <years> Years to calculate [Default: 25]
-r, --return <return> Annual return per unit (USD) [Default: 90]
-p, --purchase Purchase new units with profit [Default: True]
-s, --sunset <year> When to sunset a panel [Default: 100]
-m, --margin <margin> Percentage of revenue kept [Default: 80%]
-c, --cease <year> Year to cease purchasing new units [Default: 100]
"""
class Panel(object):
"""
Solar Panel used for calculating roi per unit
"""
@property
def break_even(self):
""" Year when this panel will break even """
investment_return = 0
for year in xrange(100):
coeff = 1.0 - (self.degradation)
margin = self.profit_margin
revenue = self.annual_revenue
investment_return += coeff * revenue * margin
if investment_return >= self.investment:
return year
@property
def age(self):
""" age of panel """
return self.start + self.year
@property
def roi(self):
""" return on investment (%) """
return self.investment / self.generated_revenue
@property
def degraded_revenue(self):
""" degradation of panel in revenue """
value = 0
if self.age < self.sunset:
coefficient = (1.0 - self.degradation * self.age)
value = coefficient * self.annual_revenue * self.profit_margin
return value
def __init__(self, cost=750, year=0, revenue=2250 / 25, degradation=0.007, margin=0.8, sunset=100):
""" Creates a unit which can be updated """
self.investment = cost
self.start = year
self.year = 0
self.profit_margin = 0.8
self.degradation = degradation
self.annual_revenue = revenue
self.generated_revenue = 0
self.sunset = sunset
def update(self):
""" Increments unit for this year """
self.generated_revenue += self.degraded_revenue
self.year += 1
def __repr__(self):
""" Panel at any point in time """
args = {
"years": self.years,
"capital": self.investment,
"return": self.generated_revenue,
"roi": self.roi,
}
string = "<Panel age:{years}, capital:{investment}, "\
"return:{revenue}, roi:{roi}>"
return string.format(args)
def calculate(args):
unit_cost = args.get("--unit-cost")
initial_cost = args.get("--initial")
units_purchased = args.get("--units")
degradation = args.get("--degradation")
years = args.get("--years")
annual_return = args.get("--return")
purchase_new_units = args.get("--purchase", False)
sunset = args.get("--sunset")
margin = args.get("--margin")
cease = args.get("--cease")
cpu = initial_cost / units_purchased
units = [Panel(cost=cpu,
revenue=annual_return,
degradation=degradation,
margin=margin,
sunset=sunset)
for unit in xrange(units_purchased)]
titles = ["year", "units", "monthly", "roi", "investment", "return"]
print "{0:>4}: {1:>10} | {2:>16} | {3:<15} | ({4:>19}/{5:>19})".format(*titles)
cumulative = 0
for year in xrange(years):
profit = sum(u.degraded_revenue for u in units)
cumulative += profit
if purchase_new_units and year < cease:
while cumulative > unit_cost:
panel = Panel(cost=unit_cost,
year=year,
revenue=annual_return,
degradation=degradation,
margin=margin,
sunset=sunset)
units.append(panel)
cumulative = cumulative - unit_cost
data = {
"units": sum(1 for u in units),
"year": year,
"cost": sum(u.investment for u in units),
"profit": sum(u.generated_revenue for u in units),
"monthly": sum(u.degraded_revenue/12.0 for u in units),
}
data["roi"] = data["profit"] / data["cost"]
print("{year:>4}: {units:>10} | ${monthly:>15,} | {roi:<15} | (${cost:>18,}/${profit:>18,})".format(**data))
for unit in units:
unit.update()
if __name__ == "__main__":
import docopt
args = docopt.docopt(__doc__)
for k, v in args.iteritems():
try:
if "." not in v:
v = int(v)
args[k] = v
else:
v = float(v)
args[k] = v
except:
pass
calculate(args)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment