[1]:
import numpy as np
from bokeh.io import output_notebook, show
from bokeh.plotting import figure
from bokeh.layouts import gridplot
from bokeh.models import ColumnDataSource, HoverTool, CustomJS
from bokeh.io import push_notebook
from ipywidgets import interact
from scipy.interpolate import Rbf
output_notebook()
Loading BokehJS ...
[2]:
from pydgrid.pydgrid import grid

CIGRE LV European System

Contour plot for voltages using Bokeh

[3]:
sys1 = grid()
sys1.read('cigre_europe_residential.json')  # Load data
sys1.pf()
sys1.get_v()      # post process voltages
sys1.get_i()      # post process currents

V_an  = np.array([item['v_an']/item['U_kV']/1000*np.sqrt(3) for item in sys1.buses])
V_bn  = np.array([item['v_bn']/item['U_kV']/1000*np.sqrt(3) for item in sys1.buses])
V_cn  = np.array([item['v_cn']/item['U_kV']/1000*np.sqrt(3) for item in sys1.buses])
Pos_x = np.array([item['pos_x'] for item in sys1.buses])
Pos_y = np.array([item['pos_y'] for item in sys1.buses])
x_min = np.min(Pos_x)
x_max = np.max(Pos_x)
y_min = np.min(Pos_y)
y_max = np.max(Pos_y)

x_margin = 150
y_margin = 100

x_min2 = x_min-x_margin
x_max2 = x_max+x_margin
y_min2 = y_min-y_margin
y_max2 = y_max+y_margin

Pos_x_e = np.hstack((x_min2, x_min2, Pos_x, x_max2, x_max2))
Pos_y_e = np.hstack((y_min2, y_max2, Pos_y, y_max2, y_min2))
V_an_e  = np.hstack((1,1, V_an, 1,1))
V_bn_e  = np.hstack((1,1, V_bn, 1,1))
V_cn_e  = np.hstack((1,1, V_cn, 1,1))
rbfi_a = Rbf(Pos_x_e, Pos_y_e, V_an_e, function='linear')
rbfi_b = Rbf(Pos_x_e, Pos_y_e, V_bn_e)
rbfi_c = Rbf(Pos_x_e, Pos_y_e, V_cn_e)

x =  np.linspace(x_min2,x_max2, 500)
y =  np.linspace(y_min2,y_max2, 500)
X, Y = np.meshgrid(x, y)
Z_a = rbfi_a(X, Y)
Z_b = rbfi_b(X, Y)
Z_c = rbfi_c(X, Y)

Graph with obtained results

[4]:
sys1.s_radio_scale = 0.1
sys1.s_radio_min = 5.0

sys1.bokeh_tools()

p = figure(width=600, height=800,
           title='European LV Network (CIGRE)', x_range=[-150,150], y_range=[-350, 50])

p.image(image=[Z_a], x=x_min2, y=y_min2, dw=(x_max2-x_min2), dh=(y_max2-y_min2), palette="Spectral11")


# lines:
source = ColumnDataSource(sys1.line_data)
lin = p.multi_line(source=source, xs='x_s', ys='y_s', color="red", alpha=1, line_width=5)

# buses:
source = ColumnDataSource(sys1.bus_data)
cr = p.circle(source=source, x='x', y='y', size='s_radio', color='s_color', alpha=1)

p.add_tools(HoverTool(renderers=[lin], tooltips=sys1.line_tooltip))
p.add_tools(HoverTool(renderers=[cr], tooltips=sys1.bus_tooltip))
show(p)

Interaction with powers

[5]:
sys1.read('cigre_europe_residential.json')  # Load data
sys1.pf()
sys1.get_v()      # post process voltages
sys1.get_i()      # post process currents

s_0_3pn = np.copy(sys1.pq_3pn) #
s_0_1p  = np.copy(sys1.pq_1p)  #
sys1.bokeh_tools()
p = figure(width=800, height=400,
           title='Voltage vs load powers',
           x_range = [40,-350], y_range = [180,250],
           x_axis_label='Distance (m)',
           y_axis_label='Voltage (V)')
source = ColumnDataSource(sys1.bus_data)
cr = p.circle(source=source, x='y', y='v_an', size=15, color="red", alpha=0.5)
p.circle(source=source, x='y', y='v_bn', size=15, color="green", alpha=0.5)
p.circle(source=source, x='y', y='v_cn', size=15, color="blue", alpha=0.5)
p.line([-400,300],[231*1.05,231*1.05], color='red', line_width=5)
p.line([-400,300],[231*0.90,231*0.90], color='blue', line_width=5)
#p.add_tools(HoverTool(renderers=[cr], tooltips=sys1.bus_tooltip))


def update_loads(load_factor=1.0):

    sys1.pq_1p = load_factor*s_0_1p
    sys1.pq_3pn = np.copy(load_factor*s_0_3pn)
    sys1.set_pf()
    sys1.pf()
    sys1.get_v()
    sys1.get_i()
    #sys1.bokeh_tools()
    v_an_m = np.abs(sys1.V_node[sys1.node_1_sorter])
    v_bn_m = np.abs(sys1.V_node[sys1.node_2_sorter])
    v_cn_m = np.abs(sys1.V_node[sys1.node_3_sorter])
    sys1.bus_data['v_an'] = v_an_m
    sys1.bus_data['v_bn'] = v_bn_m
    sys1.bus_data['v_cn'] = v_cn_m
    source.data = sys1.bus_data

    push_notebook()

#p_grid = gridplot([[p], [p_2]])
show(p, notebook_handle=True)

[5]:

<Bokeh Notebook handle for In[5]>

[6]:
from ipywidgets import interact
interact(update_loads, load_factor=(-1,1.2, 0.1))
[6]:
<function __main__.update_loads(load_factor=1.0)>

Analysis using Pandas

[7]:
import pandas as pd
[8]:
df = pd.DataFrame()
df['nodes'] = sys1.nodes
df['I_node_m'] = np.abs(sys1.I_node)
df['V_node_m'] = np.abs(sys1.V_node)
#df['phi'] = np.angle(sys1.I_node, deg=True) - np.angle(sys1.V_node, deg=True)
s  = np.conjugate(sys1.I_node)*sys1.V_node
df['p_kW']  = s.real/1000
df['q_kVA'] = s.imag/1000

df
[8]:
nodes I_node_m V_node_m p_kW q_kVA
0 R0.1 12.279686 11547.000000 133.228235 48.534983
1 R0.2 12.194776 11547.000000 132.224879 48.424213
2 R0.3 12.219433 11547.000000 132.822486 47.610666
3 R1.1 294.305597 226.183736 -63.206394 -20.883865
4 R1.2 294.318022 226.377454 -63.338571 -20.673117
5 R1.3 294.268246 227.024469 -63.455017 -20.892937
6 R1.4 0.129777 0.488038 -0.000018 -0.000061
7 R11.1 22.619924 221.082177 -4.751117 -1.560611
8 R11.2 22.542696 221.818706 -4.749990 -1.562532
9 R11.3 22.431808 222.842141 -4.748898 -1.560605
10 R11.4 0.111885 0.056907 0.000006 -0.000001
11 R15.1 82.678522 210.089330 -16.512848 -5.388732
12 R15.2 82.063130 211.381109 -16.463661 -5.463720
13 R15.3 81.216693 212.814945 -16.424028 -5.384451
14 R15.4 0.869274 0.627272 0.000537 -0.000093
15 R16.1 85.643246 214.560691 -17.470587 -5.695963
16 R16.2 84.972116 215.951166 -17.414043 -5.785090
17 R16.3 84.050216 217.432385 -17.366033 -5.692562
18 R16.4 0.947507 0.712773 0.000663 -0.000129
19 R17.1 55.050752 212.626217 -11.132419 -3.616867
20 R17.2 54.506010 214.317220 -11.080836 -3.697878
21 R17.3 53.767616 216.004660 -11.037499 -3.613848
22 R17.4 0.762900 1.009420 0.000755 -0.000153
23 R18.1 74.293759 211.633036 -14.954995 -4.853998
24 R18.2 73.514087 213.405120 -14.879548 -4.972049
25 R18.3 72.461012 215.150835 -14.816623 -4.849461
26 R18.4 1.089448 1.091264 0.001165 -0.000237
27 R2.1 0.000000 223.960103 0.000000 -0.000000
28 R2.2 0.000000 224.415535 -0.000000 0.000000
29 R2.3 0.000000 225.243290 0.000000 0.000000
... ... ... ... ... ...
45 R6.3 0.000000 219.425766 0.000000 0.000000
46 R6.4 0.000000 0.634712 0.000000 -0.000000
47 R7.1 0.000000 215.787875 0.000000 -0.000000
48 R7.2 0.000000 217.212013 -0.000000 0.000000
49 R7.3 0.000000 218.710282 0.000000 0.000000
50 R7.4 0.000000 0.741778 0.000000 -0.000000
51 R8.1 0.000000 214.889967 0.000000 -0.000000
52 R8.2 0.000000 216.422120 -0.000000 0.000000
53 R8.3 0.000000 217.994913 0.000000 0.000000
54 R8.4 0.000000 0.848844 0.000000 -0.000000
55 R9.1 0.000000 213.992505 0.000000 -0.000000
56 R9.2 0.000000 215.631806 -0.000000 0.000000
57 R9.3 0.000000 217.279749 0.000000 0.000000
58 R9.4 0.000000 0.956068 0.000000 -0.000000
59 R10.1 0.000000 213.476942 0.000000 -0.000000
60 R10.2 0.000000 215.178180 -0.000000 0.000000
61 R10.3 0.000000 216.869265 0.000000 0.000000
62 R10.4 0.000000 1.017707 0.000000 -0.000000
63 R12.1 0.000000 217.273533 0.000000 -0.000000
64 R12.2 0.000000 218.317615 -0.000000 0.000000
65 R12.3 0.000000 219.559931 0.000000 0.000000
66 R12.4 0.000000 0.367154 0.000000 -0.000000
67 R13.1 0.000000 214.877482 0.000000 -0.000000
68 R13.2 0.000000 216.004358 -0.000000 0.000000
69 R13.3 0.000000 217.310579 0.000000 0.000000
70 R13.4 0.000000 0.453609 0.000000 -0.000000
71 R14.1 0.000000 212.482806 0.000000 -0.000000
72 R14.2 0.000000 213.692088 -0.000000 0.000000
73 R14.3 0.000000 215.062258 0.000000 0.000000
74 R14.4 0.000000 0.540432 0.000000 -0.000000

75 rows × 5 columns