In [1]:
# Import the necessary libraries
import numpy as np
import math as math
In [2]:
import csv

with open('gridwatch_2018_overq.csv','r') as f:
    readerk = csv.reader(f)
    listk = list(readerk)
In [3]:
d1 = listk[2][1]
list2 = [*zip(*listk)]
dates = list2[1]

dates[1]
Out[3]:
' 2017-10-13 22:35:34'
In [4]:
from datetime import datetime, timedelta
datetime.strptime(d1," %Y-%m-%d  %H:%M:%S")

datel = []
secs = []
firstdate = datetime.strptime(dates[1]," %Y-%m-%d  %H:%M:%S")

#Reference date, first second of 2018
refdate = datetime(2018,1,1,0,0,0)

for x in dates:
    try:
        dn = datetime.strptime(x," %Y-%m-%d  %H:%M:%S")
    except:
        print(x)
    else:
        datel.append(dn)
        secs.append((dn-refdate).total_seconds())
In [5]:
import plotly.plotly as py

from plotly.graph_objs import scatter
import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot
init_notebook_mode(connected=True)
In [6]:
layoutsk = go.Layout(yaxis=dict(automargin=True,title='Power, MW'),xaxis=dict(title='day number of 2018'))
#iplot(go.Figure(data=[{"x":np.array(secs)/86400,"y": list2[2]}],layout=layoutsk))
In [7]:
wind_raw   = np.array(list2[7]).astype(float);
solar_raw  = np.array(list2[12]).astype(float);
demand_raw = np.array(list2[2]).astype(float);
timestamp = np.array(list2[0]).astype(float)
In [8]:
secsa = np.array(secs)

numsecs_year = (365*86400);
numpers = math.floor(numsecs_year/300);
#Include a week before and after the year as a buffer to allow 
#valid 2-week long moving averages.
buffer_pers = math.floor(7*24*3600/300);
numpers = numpers + 2*buffer_pers

secs_ev = (np.linspace(0,numpers,numpers+1)-buffer_pers)*300

#trace1 = go.Scatter(y=secsa/300)
#trace2 = go.Scatter(y=secs_ev/300)
#iplot(go.Figure(data=[trace1,trace2],layout=layoutsk))

wind = np.interp(secs_ev,secsa,wind_raw)
solar = np.interp(secs_ev,secsa,solar_raw)
demand = np.interp(secs_ev,secsa,demand_raw)
In [9]:
dt = 5*60
dayno = np.array(secs_ev)/86400;

firstper_val = math.floor(2*86400/300)
lastper_val =  math.floor((365+7+5)*86400/300)

N_hr=math.floor(3600/dt)
wind_sm = np.convolve(wind,np.ones((N_hr,))/N_hr,mode='same')
solar_sm = np.convolve(solar,np.ones((N_hr,))/N_hr,mode='same')

times_hr = dayno[firstper_val:lastper_val:12]
solar_hr = solar_sm[firstper_val:lastper_val:12]
wind_hr = wind_sm[firstper_val:lastper_val:12]

N_day=math.floor(86400/dt)
wind_sm = np.convolve(wind,np.ones((N_day,))/N_day,mode='same')
solar_sm = np.convolve(solar,np.ones((N_day,))/N_day,mode='same')
demand_sm = np.convolve(demand,np.ones((N_day,))/N_day,mode='same')

times_day = dayno[firstper_val:lastper_val:12*24]
solar_day = solar_sm[firstper_val:lastper_val:12*24]
wind_day = wind_sm[firstper_val:lastper_val:12*24]
demand_day = demand_sm[firstper_val:lastper_val:12*24]


firstper_val = math.floor(7*86400/300)
lastper_val =  math.floor((365+7)*86400/300)

N_wk=math.floor(7*86400/dt)
wind_sm = np.convolve(wind,np.ones((N_wk,))/N_wk,mode='same')
solar_sm = np.convolve(solar,np.ones((N_wk,))/N_wk,mode='same')

times_wk = dayno[firstper_val:lastper_val:12*24]
solar_wk = solar_sm[firstper_val:lastper_val:12*24]
wind_wk = wind_sm[firstper_val:lastper_val:12*24]

trace1 = go.Scatter(x=times_hr,y=wind_hr,name="wind, hourly")
trace2 = go.Scatter(x=times_hr,y=solar_hr,name="solar, hourly")
iplot(go.Figure(data=[trace1,trace2],layout=layoutsk))

trace1 = go.Scatter(x=times_day,y=wind_day,name="wind, daily")
trace2 = go.Scatter(x=times_day,y=solar_day,name="solar, daily")
iplot(go.Figure(data=[trace1,trace2],layout=layoutsk))


trace1 = go.Scatter(x=times_wk,y=wind_wk,name="wind, 7-day running mean")
trace2 = go.Scatter(x=times_wk,y=solar_wk,name="solar, 7-day running mean")
iplot(go.Figure(data=[trace1,trace2],layout=layoutsk))
In [10]:
solar_norm = solar_day/np.mean(solar_day)
wind_norm = wind_day/np.mean(wind_day)
demand_norm = demand_day/np.mean(demand_day)

trace1 = go.Scatter(x=times_day,y=wind_norm,name="wind, daily")
trace2 = go.Scatter(x=times_day,y=solar_norm,name="solar, daily")
trace3 = go.Scatter(x=times_day,y=0.5*(wind_norm+solar_norm),name="50/50 wind/solar, daily")
trace4 = go.Scatter(x=times_day,y=demand_norm,name="demand, daily")
iplot(go.Figure(data=[trace1,trace2,trace3,trace4],layout=layoutsk))
In [11]:
#Storage calculation: set up on a 'daily' basis here, so it is 
#effectively assumed that there is some other short-term storage or
#demand management smoothing out demand and output on the hours-to-day scale.

#Ratio of annual renewable energy output (before curtailment) to annual demand
proportion = 1.0
#Proportion of the renewable output from wind
wind_frac  = 0.7
#Proportion of the renewable output from solar
solar_frac = 1 - wind_frac

#Mean demand, daily basis
demand_mean = np.mean(demand_day)

solar_scale = proportion*demand_mean*solar_frac*solar_norm
wind_scale  = proportion*demand_mean* wind_frac* wind_norm

renewmix = solar_scale + wind_scale

#Storage: 100% round-trip efficiency assumed.

#Maximum power of storage power stations in MW (for both charge and discharge) 
store_maxpow = 13e3
#Number of hours of storage at full power
store_nhours = 10*24
#Amount of storage
store_MWh = store_nhours*store_maxpow

#Timestep in hours
dt = 24

#Offset to first day of 2018: data includes a 'buffer'
#of a week at each end of 2018 to allow moving averages.
firstday = 5
ndays = 365

dayssim = range(firstday,ndays+firstday-1)

store_out = renewmix*0
store_ene = renewmix*0
#Assume storage half full at start of year
store_ene[firstday] = 0.5*store_MWh

for dayno in dayssim:
    rem = demand_day[dayno] - renewmix[dayno]
    srem= max(min(rem,store_maxpow),-store_maxpow)
    store_next = store_ene[dayno] - srem*dt
    store_next = max(min(store_next,store_MWh),0)
    store_out[dayno] = (store_ene[dayno] - store_next)/dt
    if (dayno<ndays+firstday-1):
        store_ene[dayno+1] = store_next
        
In [12]:
trace1 = go.Scatter(x=times_day[dayssim],y=renewmix[dayssim],name="70/30 wind/solar, daily")
trace2 = go.Scatter(x=times_day[dayssim],y=renewmix[dayssim]+store_out[dayssim],name="70/30 wind/solar+storage, daily")
trace3 = go.Scatter(x=times_day[dayssim],y=demand_day[dayssim],name="demand, daily")
trace4 = go.Scatter(x=times_day[dayssim],y=store_out[dayssim],name="storage output, daily")

#trace1 = go.Scatter(x=times_day,y=renewmix,name="70/30 wind/solar, daily")
iplot(go.Figure(data=[trace1,trace2,trace3,trace4],layout=layoutsk))

layoutene = go.Layout(yaxis=dict(automargin=True,title='Energy, MWh'),xaxis=dict(title='day number of 2018'))
trace4 = go.Scatter(x=times_day[dayssim],y=store_ene[dayssim],name="storage energy, daily")
iplot(go.Figure(data=[trace4],layout=layoutene))
In [13]:
#Proportion of total energy (daily basis) met by renewables+storage
np.mean(np.minimum(renewmix[dayssim],demand_day[dayssim]))/np.mean(demand_day[dayssim])
Out[13]:
0.8440616580428347
In [14]:
#Proportion of total energy (daily basis) met by renewables+storage
np.mean(np.minimum(renewmix[dayssim]+store_out[dayssim],demand_day[dayssim]))/np.mean(demand_day[dayssim])
Out[14]:
0.950013652525948
In [ ]: