Commit 5ab28a43 authored by sp2668's avatar sp2668
Browse files

minor

parent e40ad58a
This diff is collapsed.
%% Cell type:markdown id: tags:
# Energy System Modelling - Solutions to Tutorial II
%% Cell type:markdown id: tags:
**Imports**
%% Cell type:code id: tags:
``` python
import numpy as np
import numpy.linalg
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
```
%% Cell type:markdown id: tags:
***
## Problem II.1
%% Cell type:markdown id: tags:
***
**(a) Compile the nodes list and the edge list.**
> **Remark:** While graph-theoretically both lists are unordered sets, let's agree on an ordering now which can serve as basis for the matrices in the following exercises: we sort everything in ascending numerical order, i.e. node 1 before node 2 and edge (1,2) before (1,4) before (2,3).
%% Cell type:code id: tags:
``` python
nodes = [0, 1, 2, 3, 4, 5]
edges = [(0, 1), (1, 2), (1, 4),
(1, 5), (2, 3), (2, 4),
(3, 4), (4, 5)]
```
%% Cell type:markdown id: tags:
***
**(b) Determine the order and the size of the network.**
%% Cell type:code id: tags:
``` python
N = len(nodes)
E = len(edges)
```
%% Cell type:code id: tags:
``` python
print("Order: {}\nSize: {}".format(N, E))
```
%% Output
Order: 6
Size: 8
%% Cell type:markdown id: tags:
***
**(c) Compute the adjacency matrix $A$ and check that it is symmetric.**
> In graph theory and computer science, an adjacency matrix is a square matrix used to represent a finite graph. The elements of the matrix indicate whether pairs of vertices are adjacent or not in the graph.
%% Cell type:code id: tags:
``` python
A = np.zeros((N, N))
for u, v in edges:
A[u, v] += 1
A[v, u] += 1
A
```
%% Output
array([[0., 1., 0., 0., 0., 0.],
[1., 0., 1., 0., 1., 1.],
[0., 1., 0., 1., 1., 0.],
[0., 0., 1., 0., 1., 0.],
[0., 1., 1., 1., 0., 1.],
[0., 1., 0., 0., 1., 0.]])
array([[ 0., 1., 0., 0., 0., 0.],
[ 1., 0., 1., 0., 1., 1.],
[ 0., 1., 0., 1., 1., 0.],
[ 0., 0., 1., 0., 1., 0.],
[ 0., 1., 1., 1., 0., 1.],
[ 0., 1., 0., 0., 1., 0.]])
%% Cell type:code id: tags:
``` python
(A == A.T).all()
```
%% Output
True
%% Cell type:markdown id: tags:
***
**(d) Find the degree $k_n$ of each node $n$ and compute the average degree of the network.**
> In graph theory, the degree (or valency) of a vertex of a graph is the number of edges incident to the vertex, with loops counted twice.
%% Cell type:code id: tags:
``` python
k = A.sum(axis=1)
k
```
%% Output
array([1., 4., 3., 2., 4., 2.])
array([ 1., 4., 3., 2., 4., 2.])
%% Cell type:code id: tags:
``` python
k.mean()
```
%% Output
2.6666666666666665
%% Cell type:markdown id: tags:
***
**(e) Determine the incidence matrix $K$ by assuming the links are always directed from smaller-numbered node to larger-numbered node, i.e. from node 2 to node 3, instead of from 3 to 2.**
> The unoriented incidence matrix (or simply incidence matrix) of an undirected graph is a $n \times m$ matrix $B$, where n and m are the numbers of vertices and edges respectively, such that $B_{i,j} = 1$ if the vertex $v_i$ and edge $e_j$ are incident and 0 otherwise.
%% Cell type:code id: tags:
``` python
K = np.zeros((N,E))
for i, (u, v) in enumerate(edges):
K[u,i] = 1
K[v,i] = -1
K
```
%% Output
array([[ 1., 0., 0., 0., 0., 0., 0., 0.],
[-1., 1., 1., 1., 0., 0., 0., 0.],
[ 0., -1., 0., 0., 1., 1., 0., 0.],
[ 0., 0., 0., 0., -1., 0., 1., 0.],
[ 0., 0., -1., 0., 0., -1., -1., 1.],
[ 0., 0., 0., -1., 0., 0., 0., -1.]])
%% Cell type:markdown id: tags:
***
**(f) Compute the Laplacian $L$ of the network using $k_n$ and $A$. Remember that the Laplacian can also be computed as $L=KK^T$ and check that the two definitions agree.**
> The **Laplacian** (also: admittance matrix, Kirchhoff matrix, discrete Laplacian) is a matrix representation of a graph. It is defined as the difference of degree matrix and adjacency matrix. The **degree matrix** is a diagonal matrix which contains information about the degree of each vertex.
%% Cell type:code id: tags:
``` python
D = np.diag(A.sum(axis=1))
```
%% Cell type:code id: tags:
``` python
L = D - A
L
```
%% Output
array([[ 1., -1., 0., 0., 0., 0.],
[-1., 4., -1., 0., -1., -1.],
[ 0., -1., 3., -1., -1., 0.],
[ 0., 0., -1., 2., -1., 0.],
[ 0., -1., -1., -1., 4., -1.],
[ 0., -1., 0., 0., -1., 2.]])
%% Cell type:code id: tags:
``` python
np.array_equal(L, K.dot(K.T))
```
%% Output
True
%% Cell type:markdown id: tags:
***
**(g) Find the diameter of the network by looking at the graph.**
> The diameter of a network is the longest of all the calculated shortest paths in a network. It is the shortest distance between the two most distant nodes in the network. In other words, once the shortest path length from every node to all other nodes is calculated, the diameter is the longest of all the calculated path lengths. The diameter is representative of the linear size of a network.
%% Cell type:markdown id: tags:
By looking: Between nodes $0$ and $3$, f.ex. $0 \to 1 \to 2 \to 3$
%% Cell type:markdown id: tags:
***
## Problem II.2
If you map the nodes to `0=DK, 1=DE, 2=CH, 3=IT, 4=AT,5=CZ` the network represents a small part of the European electricity network (albeit very simplified). In the repository, you can find the power imbalance time series for the six countries for January 2017 in hourly MW in the file `imbalance.csv`. They have been derived from physical flows as published by [ENTSO-E](https://transparency.entsoe.eu/transmission-domain/physicalFlow/show)
%% Cell type:markdown id: tags:
The linear power flow is given by
$$p_i = \sum_j \tilde{L}_{i,j}\theta_j \qquad \text{and} \qquad f_l = \frac{1}{x_l} \sum_i K_{i,l}\theta_i, \qquad \text{where} \qquad \tilde{L}_{i,j}= \sum_l K_{i,l}\frac{1}{x_l} K_{j,l}$$
is the weighted Laplacian. For simplicity, we assume identity reactance on all links $x_l = 1$.
%% Cell type:markdown id: tags:
***
**Read data**
%% Cell type:code id: tags:
``` python
imbalance = pd.read_csv('imbalance.csv', index_col=0, parse_dates=True)
imbalance.head()
```
%% Output
DK DE CH IT AT CZ
DateTime
2017-01-01 00:00:00 -79.73 3486.25 -3403.37 -97.5 -2867.33 2961.68
2017-01-01 01:00:00 -109.14 4248.17 -3829.59 -105.9 -3149.98 2946.44
2017-01-01 02:00:00 -101.49 5314.56 -4131.66 -199.2 -3646.87 2764.66
2017-01-01 03:00:00 -197.96 5450.71 -4009.61 -656.0 -3345.56 2758.42
2017-01-01 04:00:00 -526.15 5695.72 -3924.43 -646.2 -3393.12 2794.18
%% Cell type:markdown id: tags:
\begin{equation}
p_u = \sum_v L_{u,v} \theta_v
\end{equation}
%% Cell type:markdown id: tags:
***
**(a) Compute the voltage angles $\theta_j$ and flows $f_l$ for the first hour in the dataset with the convention of $\theta_0 = 0$; i.e. the slack bus is at node 0.**
> **Remark:** Linear equation systems are solved efficiently using [`numpy.linalg.solve`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.solve.html).
%% Cell type:markdown id: tags:
Calculate the *voltage angles* first.
> Note, that we define the node for Denmark as slack and therefore force $\theta_{DK}=0$.
%% Cell type:code id: tags:
``` python
imbalance.iloc[0].values[1:]
```
%% Output
array([ 3486.25, -3403.37, -97.5 , -2867.33, 2961.68])
%% Cell type:code id: tags:
``` python
theta = np.r_[0, np.linalg.solve(L[1:,1:], imbalance.iloc[0].values[1:])]
theta
```
%% Output
array([ 0. , 79.73 , -2302.97857143, -1995.25809524,
-1590.03761905, 725.68619048])
%% Cell type:markdown id: tags:
Then, calculate the *flows*:
%% Cell type:code id: tags:
``` python
flows = K.T.dot(theta)
flows
```
%% Output
array([ -79.73 , 2382.70857143, 1669.76761905, -645.95619048,
-307.72047619, -712.94095238, -405.22047619, -2315.72380952])
%% Cell type:markdown id: tags:
***
**(b) Determine the average flow on each link for January 2017 and draw it as a directed network**
%% Cell type:code id: tags:
``` python
flows = K.T.dot(np.vstack([np.zeros((1, len(imbalance))), np.linalg.solve(L[1:,1:], imbalance.values[:,1:].T)]))
```
%% Cell type:code id: tags:
``` python
flows.shape
```
%% Output
(8, 744)
%% Cell type:code id: tags:
``` python
avg_flows = flows.mean(axis=1)
avg_flows
```
%% Output
array([ 451.02294355, 2402.42223502, 2124.94871608, 426.46578277,
421.1171115 , -277.47351895, -698.59063044, -1698.48293331])
......
Supports Markdown
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