# -*- Mode: Python -*-

# updated may 2016.

import argparse

p = argparse.ArgumentParser (description="solar scenario calculator")
p.add_argument ('--roi',        help='return on investment (default 10%%/yr)', type=float, default=10)
p.add_argument ('--years',      help='years to simulate', type=int, default=10)
p.add_argument ('--nem',        help='NEM payment per kWh', type=float, default=0.035)
p.add_argument ('--cpw',        help='cost per watt installed', type=float, default=5.0)
p.add_argument ('--rate-rise',  help='rise in rates per year (default 6.7%%/yr)', type=float, default=6.7)
p.add_argument ('--base',       help='starting pool of money', type=float, default=100000)

args = p.parse_args()

# convert annual yield to monthly yield
def per_month (p):
    return ((1 + p)**(1/12.))-1

eq_per_year = args.roi / 100.0
eq_per_month = per_month (eq_per_year)

# according to this page: http://www.sungevity.com/solar-cost-savings
# california rates historically go up by 6.7% per year
#  [this jives with a rise from $0.18 in 2005 to $0.32 in 2014 in the middle tier]
rate_rise_per_year = args.rate_rise / 100.0
rate_rise_per_month = per_month (rate_rise_per_year)

# XXX model the winter/summer tiers exactly
tiers = [
    # 2016: baseline is 10.5kWh/day (winter 10.9, summer 10.1)
    # note: averaging the two tier rates seen on march bill.
    (10.5 * 1.0, (.18212 + .18212) / 2), # 100% baseline
    (10.5 * 0.3, (.25444 + .22481) / 2), # 101%-130%
    (10.5 * 0.7, (.25444 + .28578) / 2), # 130%-200%
    (1000.0    , (.37442 + .36389) / 2), # 200%+
    ]

class scenario:

    def __init__ (self, name, base, cost, size):
        # starting tiers
        self.tiers = tiers[:]
        # we start out with this amount of money
        self.base = base
        # cost of the solar system
        self.cost = cost
        # we're worth this much
        self.worth = base - cost
        # solar panel output
        self.size = size

    def tiers_month (self, kwh):
        # given current tiers, how much will <kwh> cost.
        # [XXX apply seasonal rate tiers]
        total = 0.0
        for diem, cost in self.tiers:
            chunk = min (diem * 30, kwh)
            total += cost * chunk
            kwh -= chunk
        return total

    def bump_tiers (self):
        for i in range (len (self.tiers)):
            baseline, rate = self.tiers[i]
            rate += rate * rate_rise_per_month
            self.tiers[i] = baseline, rate

    def one_month (self, month):
        # increase net worth by market rate
        self.worth += self.worth * eq_per_month
        # get usage for this month
        kwh = usage_2016[month]
        # subtract power generated by solar panels
        gen = estimate_output (month, self.size)
        if gen > kwh:
            #import pdb; pdb.set_trace()
            nem = gen - kwh
            ecost = - args.nem * nem
            #print 'NEM: %0.2f' % (-ecost,)
        else:
            net = kwh - gen
            assert (net > 0)
            ecost = self.tiers_month (net)
        # subtract(/add) the electric bill
        self.worth -= ecost
        # adjust bill for rate rises
        self.bump_tiers()

    def pprint (self):
        print '%10.2f' % (self.worth,)

    def go (self, years=10):
        r = []
        for i in range (years):
            for j in range (12):
                self.one_month (j)
            r.append (self.worth)
        return r

# from pge.com, my actual usage from apr 2015 - apr 2016.
usage_2016 = [682, 681, 1239, 1288, 1180, 1227, 947, 858, 954, 902, 795, 829, 828]

def rotate (x, n=1):
    return x[n:] + x[:n]

# rotate these to start in january.
usage_2016 = rotate (usage_2016, -3)

# from http://pvwatts.nrel.gov/, for my house: 9.2kW system.
pvwatts_data = [
    ("1","493.02386475","2.1583786","66.90973663","519.69580078","128.19"),
    ("2","600.4855957","2.91345429","81.57672119","631.1362915","156.13"),
    ("3","752.00354004","3.32714248","103.14141846","790.7008667","195.52"),
    ("4","1254.8762207","5.78721142","173.61634827","1310.40014648","326.27"),
    ("5","1503.25878906","6.86042976","212.67332458","1567.78503418","390.85"),
    ("6","1632.52246094","7.72504187","231.75125122","1701.86328125","424.46"),
    ("7","1558.41894531","7.18829393","222.83711243","1625.68762207","405.19"),
    ("8","1391.38745117","6.49911213","201.47247314","1451.62536621","361.76"),
    ("9","1113.03320313","5.31577206","159.47315979","1161.75146484","289.39"),
    ("10","841.21911621","3.86629081","119.85501862","880.38519287","218.72"),
    ("11","564.35845947","2.6162765","78.48829651","593.22485352","146.73"),
    ("12","464.67822266","2.09182525","64.84658051","491.63354492","120.82"),
]

def estimate_output (month, size):
    watts = float (pvwatts_data[month][1])
    # adjust watts per system size
    ratio = size / 9200.0
    return watts * ratio

# base is a made-up number to reflect a pool of money
#  that is either used to pay electric bills, pay
#  for a solar installation, or earn money invested
#  in markets/bonds/etc at the --roi value.

cpw = args.cpw

scenarios = [
    # name         base       cost      size
    ('none',     args.base,    0,       0),
    ('SP 9.2K',  args.base, 9200 * cpw, 9200),
    ('SP 5K',    args.base, 5000 * cpw, 5000),
    ('SP 3K',    args.base, 3000 * cpw, 3000),
    ('SP 2K',    args.base, 2000 * cpw, 2000),
    ]

def go():
    import sys

    results = []
    for s in scenarios:
        x = scenario (*s)
        results.append (x.go (args.years))

    sys.stdout.write ('yr ')
    for j in range (len (scenarios)):
        sys.stdout.write ('%11s ' % (scenarios[j][0]))
    sys.stdout.write ('\n')
    for i in range (len (results[0])):
        sys.stdout.write ('%2d ' % (i+1,))
        for j in range (len (scenarios)):
            sys.stdout.write ('%10.0f ' % (results[j][i]))
            if results[j][i] >= results[0][i]:
                sys.stdout.write ('+')
            else:
                sys.stdout.write ('-')
        sys.stdout.write ('\n')

go()
