Commit eb384b14 authored by vs2788's avatar vs2788

adding tutorial 6

parent a138a87e
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
\documentclass[11pt,a4paper,fleqn]{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[colorlinks=true, citecolor=blue, linkcolor=blue, filecolor=blue,urlcolor=blue]{hyperref}
\hypersetup{
colorlinks = true,
citecolor = gray
}
\usepackage{wrapfig}
\usepackage{caption}
\captionsetup{format=plain, indent=5pt, font=footnotesize, labelfont=bf}
\setkomafont{disposition}{\scshape\bfseries}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsfonts}
%\usepackage{bbm}
%\usepackage{mathtools}
% \usepackage{epsfig}
% \usepackage{grffile}
%\usepackage{times}
%\usepackage{babel}
\usepackage{tikz}
\usepackage{paralist}
\usepackage{color}
\usepackage[top=3cm, bottom=2.5cm, left=2.5cm, right=3cm]{geometry}
%\setlength{\mathindent}{1ex}
% PGF
\usepackage{pgfplots}
\usepackage{pgf}
%\usepackage{siunitx}
%\usepackage{xfrac}
%\usepackage{calculator}
%\usepackage{calculus}
%\usepackage{eurosym}
%\usepackage{booktabs}
%\sisetup{per-mode=fraction,%
% fraction-function=\sfrac}
%\newcommand{\eur}[1]{\EUR{#1}\si{\per\kilo\meter}}
\pgfplotsset{
compat=newest,
every axis/.append style={small, minor tick num=3}
}
%\usepackage[backend=biber,style=alphabetic,url=false,doi=false]{biblatex}
%\addbibresource{sheet01_biber.bib}
% \addbibresource{/home/coroa/papers/refs.bib}
\newcommand{\id}{\mathbbm{1}}
\newcommand{\NN}{{\mathbbm{N}}}
\newcommand{\ZZ}{{\mathbbm{Z}}}
\newcommand{\RR}{{\mathbbm{R}}}
\newcommand{\CC}{{\mathbbm{C}}}
\renewcommand{\vec}[1]{{\boldsymbol{#1}}}
\renewcommand{\i}{\mathrm{i}}
\newcommand{\expect}[1]{\langle\,#1\,\rangle}
\newcommand{\e}[1]{\ensuremath{\,\mathrm{#1}}}
\renewcommand{\O}{\mc{O}}
\newcommand{\veps}{\varepsilon}
\newcommand{\ud}[1]{\textup{d}#1\,}
\newcommand{\unclear}[1]{\color{green}#1}
\newcommand{\problem}[1]{\color{red}#1}
\newcommand{\rd}[1]{\num[round-mode=places,round-precision=1]{#1}}
%\DeclareSIUnit{\euro}{\EUR}
%\DeclareSIUnit{\dollar}{\$}
%\newcommand{\eur}{\text{\EUR{}}}
\usepackage{palatino}
\usepackage{mathpazo}
\setlength\parindent{0pt}
\usepackage{xcolor}
\usepackage{framed}
\definecolor{shadecolor}{rgb}{.9,.9,.9}
%=====================================================================
%=====================================================================
\begin{document}
\begin{center}
\textbf{\Large Energy System Modelling }\\
{SS 2018, Karlsruhe Institute of Technology}\\
{Institute for Automation and Applied Informatics}\\ [1em]
\textbf{\textsc{\Large Tutorial VI: Clustering of Large Power Systems\\}}
\small Will be worked on in the exercise session on Wednesday, 18 July 2018.\\[1.5em]
\end{center}
\vspace{1em}
%=============== ======================================================
\paragraph{Clustering the European Grid}~\\
%=====================================================================
As seen previously, the integration of renewable energy is cheaper at a large geographical scale and its variability requires a good temporal resolution. Therefore the computational power needed for the optimization of the whole energy system could be too high for servers or super computer.
\\
\\
In this tutorial, we will first compare 2 basic clustering solutions to reduce the grid model size. Then we will observe the impact of clustering on the lowest installed capacity required to feed the demand.
%=============== ======================================================
\paragraph{Installation.}~\\
%=====================================================================
The jupyter notebook of this tutorial requires to install the library sklearn to perform the clustering
%=============== ======================================================
\paragraph{Introduction – the European grid.}~\\
%=====================================================================
the file \textit{base.nc} contains a good representation of the European grid, with the various high voltage AC lines and the DC links.
\\
\\
You could load this file in PyPSA and plot it, the colors of the lines represent the voltage type and level, the width of the lines are proportional to their transmission capacity.
\\
\\
\textbf{Task:} Calculate the order and the size of this graph (you will need to include AC lines and DC links).
\\
\\
To cluster this network, we will use a simplify version of this grid, by considering all AC lines to have the same voltage. It will also group very close buses. Import the simplified version (\textit{elec\char`_s.nc}).\textbf{Task:} Calculate the resulting size and order.
%=============== ======================================================
\paragraph{Clustering with sklearn.}~\\
%=====================================================================
Sklearn is a library which allows to cluster data. Due to its simplicity and to the limited goal of this tutorial, we will cluster the simplified network by grouping the buses according to their geographical locations.
\\
\\
\textbf{Task:}Perform various clustering of the simplified network by changing clustering algorithms (Kmeans, SpectralClustering, …) and the number of clusters k.\\
{\url{http://scikit-learn.org/stable/modules/clustering.html}}
\\
\\
\textbf{Task:}Use the \textit{plot\char`_clusters} function of tutorial.py to observe the outcome of the clustering.
\\
\\
\textbf{Questions:}
Are the buses adequately clustered?\\
Which algorithm is giving the best outcome?\\
What are the limits of using geographically based data clustering on the electrical grid?
%=============== ======================================================
\paragraph{Clustering and minimum installed capacity.}~\\
%=====================================================================
The file \textit{elec\char`_s.nc} provides solar and wind energy hourly profile per bus for year 2013 and an hourly load profile per bus. The Run of River Hydropower is also fixed.
\\
\\
We will now use the functions :\\
\textit{tutorial.find\char`_kmeans\char`_busmap} and \textit{pypsa.networkclustering.get\char`_clustering\char`_from\char`_busmap} \\
to cluster the European Grid according to the Kmeans algorithm with weighted values (corresponding here to the maximum load at the bus). These functions aggregate the bus data (load, renewable potential...) to the cluster node and group lines from the initial network to form the edges of the clustered graph.\\
Our clustered network is still missing some installed capacities for renewable at each bus to be able to run a simulation such as a Linear Optimal Power Flow (LOPF): LOPF could say if our installed capacity of renewable could supply the loads according to the available line transfer capacity.
\\
\\
In order to give a capacity of solar, onshore wind and\char`/or offshore wind to each bus in a simple way, I created a small function \textit{P\char`_nom\char`_re} attributing an installed capacity proportional to load at each bus (the proportionality coefficients for solar w\char`_s, onshore wind w\char`_on and offshore wind w\char`_of could be changed independently). The goal here is not to simulate a real or ideal energy system, but to be more familiar with the tools and to observe if different clustering sizes or clustering groups are having an impact on results.
\\
\\
\textbf{Task:}For a graph with a small number of cluster (10-25), determine minimum proportionality coefficients w\char`_s, w\char`_on and w\char`_of to have a successful LOPF at a specific day and hour (observe the message \textit{INFO:pypsa.opf:Optimization successful} or \textit{ERROR:pypsa.opf:Optimisation failed}).
\\
\\
\textbf{Questions:}If you try the same coefficients with a higher number of cluster (100-200), is the LOPF still successful. If not, could you find an explanation?
\end{document}
import yaml
import pypsa
import numpy as np
import xarray as xr
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.lines as mlines
from sklearn.cluster import KMeans, SpectralClustering
### FUNCTIONS
def plot_clusters(network, y_pred,X,lim_fig="None"):
colors_choice=['b', 'g', 'r', 'c', 'y', 'violet','purple','k','chartreuse','indianred','pink','orange','gray','yellow','springgreen','indigo','brown','silver','aqua']*(int(max(y_pred)/19)+1)
colors_list = [ colors_choice[x] for x in y_pred]
fig, ax = plt.subplots()
fig.set_size_inches(15,15)
if lim_fig!= "None":
ax.set_xlim(lim_fig[0])
ax.set_ylim(lim_fig[1])
network.plot(bus_sizes=0.01,
line_colors=pd.concat(dict(Line=pd.Series('red', index=network.lines.index),
Link=pd.Series('violet', index=network.links.index))),
line_widths=pd.concat(dict(Line=network.lines['s_nom']/1000,Link=network.links['p_nom']/1000)))
plt.scatter(X[:, 0], X[:, 1], c=colors_list,s=100)
plt.show()
def plot_network(network,option="AC_DC",basemap="no"):
fig, ax = plt.subplots()
fig.set_size_inches(15,15)
if basemap=="yes":
long_min=-10
long_max=30
lat_min=35
lat_max=72
map = Basemap(llcrnrlon=long_min,
llcrnrlat=lat_min,
urcrnrlon=long_max,
urcrnrlat=lat_max,resolution='l')
map.drawcoastlines(linewidth=0.25)
map.drawcountries(linewidth=0.25)
else:
ax.set_ylim([35,72])
if option=="AC_DC":
network.plot(bus_sizes=5,
line_colors=pd.concat(dict(Line=pd.Series('red', index=network.lines.index),
Link=pd.Series('violet', index=network.links.index))),
line_widths=pd.concat(dict(Line=network.lines['s_nom']/1500,Link=network.links['p_nom']/1500)))
red_line = mlines.Line2D([], [], color='red',label='AC')
violet_line=mlines.Line2D([], [], color='violet',label='DC')
plt.legend(handles=[red_line,violet_line])
else:
voltage_colors = {132.0: 'blue', 220.0: 'green', 300.0: 'orange', 380.0: 'red'}
network.plot(bus_sizes=5,
line_colors=pd.concat(dict(Line=network.lines['v_nom'].map(voltage_colors),
Link=pd.Series('violet', index=network.links.index))),
line_widths=pd.concat(dict(Line=network.lines['s_nom']/1000,Link=network.links['p_nom']/1000)))
blue_line = mlines.Line2D([], [], color='blue',label='132 kV')
green_line = mlines.Line2D([], [], color='green',label='220 kV')
orange_line = mlines.Line2D([], [], color='orange',label='300 kV')
red_line = mlines.Line2D([], [], color='red',label='380 kV')
violet_line=mlines.Line2D([], [], color='violet',label='DC')
plt.legend(handles=[blue_line,green_line,orange_line,red_line,violet_line])
def find_kmeans_busmap(n_clusters, n, n_weightings, **kwargs):
kmeans = KMeans(init='k-means++', n_clusters=n_clusters, ** kwargs)
kmeans.fit(n[["x","y"]].values)
return pd.Series(data=kmeans.predict(n[["x","y"]]),
index=n.index).astype(str)
def weighting(network):
load = (network.loads_t.p_set.mean()
.groupby(network.loads.bus).sum()
.reindex(network.buses.index, fill_value=0.))
return load
def P_nom_re(network,w_s=2.5,w_onw=0.2,w_ofw=0.1):
network.generators.loc[network.generators['carrier'] == 'solar',"p_nom_max"]=network.generators.loc[network.generators['carrier'] == 'solar',"weight"]*w_s
network.generators.loc[network.generators['carrier'] == 'onwind',"p_nom_max"]=network.generators.loc[network.generators['carrier'] == 'onwind',"weight"]*w_onw
network.generators.loc[network.generators['carrier'] == 'offwind',"p_nom_max"]=network.generators.loc[network.generators['carrier'] == 'offwind',"weight"]*w_ofw
network.generators.loc[network.generators['carrier'] == 'solar',"p_nom"]=network.generators.loc[network.generators['carrier'] == 'solar',"weight"]*w_s
network.generators.loc[network.generators['carrier'] == 'onwind',"p_nom"]=network.generators.loc[network.generators['carrier'] == 'onwind',"weight"]*w_onw
network.generators.loc[network.generators['carrier'] == 'offwind',"p_nom"]=network.generators.loc[network.generators['carrier'] == 'offwind',"weight"]*w_ofw
def lopf_d_h(network,day,hour):
network.set_snapshots(pd.DatetimeIndex(start=hour.format(day), end=hour.format(day), freq='H'))
# solve linear optimal power flow
network.lopf(network.snapshots[0],
solver_name='glpk')
def plot_line_loading(network):
fig, ax = plt.subplots()
ax.set_ylim([35,72])
fig.set_size_inches(15,15)
loading = network.lines_t.p0.loc[network.snapshots[0]]/network.lines.s_nom/0.7
loading=loading.fillna(0)
loading=loading.append(pd.Series(1))
loading_dc = network.links_t.p0.loc[network.snapshots[0]]/network.links.p_nom/0.7
loading_dc=loading_dc.fillna(0)
loading_dc=loading_dc.append(pd.Series(1))
#print(loading_dc)
#print(pd.concat(dict(Line=abs(loading),Link=abs(loading_dc))))
#network.plot(line_colors=abs(loading),line_cmap=plt.cm.jet,title="Line loading",
# line_widths=pd.concat(dict(Line=network.lines['s_nom']/1500,Link=network.links['p_nom']/1500)))
network.plot(line_colors=pd.concat(dict(Line=abs(loading),Link=abs(loading_dc))),
line_cmap= dict(Line=plt.cm.jet,Link=plt.cm.jet),
line_widths=pd.concat(dict(Line=network.lines['s_nom']/1500,Link=network.links['p_nom']/1500)))
Z = [[0,0],[max(abs(loading)),0]]
CS3 = plt.contourf(Z, cmap=plt.cm.jet)
plt.colorbar(fraction=0.01, pad=0.01)
def plot_bus_status(network):
fig, ax = plt.subplots()
ax.set_ylim([35,72])
fig.set_size_inches(15,15)
bus_status= pd.DataFrame({'status': network.loads_t.p_set.values[0]*-1,
'pmax':network.loads_t.p_set.values[0]*0,
'p':network.loads_t.p_set.values[0]*0,
'ponpmax':network.loads_t.p_set.values[0]*0})
for i in bus_status.index:
#print(bus_status.loc[i].values[0],p_nc.generators.loc[p_nc.generators["bus"]==i].index)
#print(i)
try:
for j in network.generators.loc[network.generators["bus"]==str(i)].index:
#bus_status.loc[i].values[0]+=p_nc.generators.loc[j].p_nom*p_nc.generators_t.p_max_pu[j].values[0]
bus_status.status.loc[i]+=network.generators_t.p[j].values[0]
bus_status.p.loc[i]+=network.generators_t.p[j].values[0]
bus_status.pmax.loc[i]+=network.generators.p_nom[j]
bus_status.ponpmax.loc[i]=bus_status.p.loc[i]/bus_status.pmax.loc[i]
except:
print(i)
bus_color=(bus_status.status/p_nc_25.loads_t.p_set.values[0]).values
#print(loading_dc)
#print(pd.concat(dict(Line=abs(loading),Link=abs(loading_dc))))
#network.plot(line_colors=abs(loading),line_cmap=plt.cm.jet,title="Line loading",
# line_widths=pd.concat(dict(Line=network.lines['s_nom']/1500,Link=network.links['p_nom']/1500)))
network.plot(bus_colors=bus_color,
bus_sizes=400,
bus_cmap= plt.cm.jet,
line_widths=pd.concat(dict(Line=network.lines['s_nom']/1500,Link=network.links['p_nom']/1500)))
Z = [[min(bus_color),0],[max(bus_color),0]]
CS3 = plt.contourf(Z, cmap=plt.cm.jet)
plt.colorbar(fraction=0.01, pad=0.01)
def plot_line_loading_bus_status(network):
fig, ax = plt.subplots()
ax.set_ylim([35,72])
fig.set_size_inches(15,15)
loading = network.lines_t.p0.loc[network.snapshots[0]]/network.lines.s_nom/0.7
loading=loading.fillna(0)
loading=loading.append(pd.Series(1))
loading_dc = network.links_t.p0.loc[network.snapshots[0]]/network.links.p_nom/0.7
loading_dc=loading_dc.fillna(0)
loading_dc=loading_dc.append(pd.Series(1))
bus_status= pd.DataFrame({'status': network.loads_t.p_set.values[0]*-1,
'pmax':network.loads_t.p_set.values[0]*0,
'p':network.loads_t.p_set.values[0]*0,
'ponpmax':network.loads_t.p_set.values[0]*0})
for i in bus_status.index:
#print(bus_status.loc[i].values[0],p_nc.generators.loc[p_nc.generators["bus"]==i].index)
#print(i)
try:
for j in network.generators.loc[network.generators["bus"]==str(i)].index:
#bus_status.loc[i].values[0]+=p_nc.generators.loc[j].p_nom*p_nc.generators_t.p_max_pu[j].values[0]
bus_status.status.loc[i]+=network.generators_t.p[j].values[0]
bus_status.p.loc[i]+=network.generators_t.p[j].values[0]
bus_status.pmax.loc[i]+=network.generators.p_nom[j]
bus_status.ponpmax.loc[i]=bus_status.p.loc[i]/bus_status.pmax.loc[i]
except:
print(i)
bus_color=(bus_status.status/network.loads_t.p_set.values[0]).values
bus_color[bus_color>1.5]=1.5
#print(loading_dc)
#print(pd.concat(dict(Line=abs(loading),Link=abs(loading_dc))))
#network.plot(line_colors=abs(loading),line_cmap=plt.cm.jet,title="Line loading",
# line_widths=pd.concat(dict(Line=network.lines['s_nom']/1500,Link=network.links['p_nom']/1500)))
network.plot(bus_colors=bus_color,
#bus_sizes=400,
bus_sizes=network.loads_t.p_set.values[0]/500**(0.5),
bus_cmap= plt.cm.jet,
line_colors=pd.concat(dict(Line=abs(loading),Link=abs(loading_dc))),
line_cmap= dict(Line=plt.cm.jet,Link=plt.cm.jet),
line_widths=pd.concat(dict(Line=network.lines['s_nom']/500,Link=network.links['p_nom']/500)))
Z = [[0,0],[max(abs(loading)),0]]
CS3 = plt.contourf(Z, cmap=plt.cm.jet)
plt.colorbar(fraction=0.01, pad=0.06)
Z2 = [[min(bus_color),0],[max(bus_color),0]]
CS4 = plt.contourf(Z2, cmap=plt.cm.jet)
plt.colorbar(fraction=0.01, pad=0.01)
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment