In [15]:
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 ...
In [16]:
from pydgrid.pydgrid import grid

CIGRE LV European System

Contour plot for voltages using Bokeh

In [21]:
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

In [68]:
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

In [66]:
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)

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

Analysis using Pandas

In [71]:
import pandas as pd
In [72]:
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
Out[72]:
nodes I_node_m V_node_m p_kW q_kVA
0 R0.1 2.354273 11547.000000 2.577389e+01 8.644055e+00
1 R0.2 2.351745 11547.000000 2.574330e+01 8.643441e+00
2 R0.3 2.352324 11547.000000 2.575912e+01 8.617257e+00
3 R1.1 57.943781 230.052034 -1.266243e+01 -4.165818e+00
4 R1.2 57.943879 230.080687 -1.266663e+01 -4.158419e+00
5 R1.3 57.943609 230.191895 -1.267094e+01 -4.165759e+00
6 R1.4 0.000762 0.084786 -1.701185e-08 -6.235960e-08
7 R11.1 4.365162 229.094059 -9.500425e-01 -3.122253e-01
8 R11.2 4.362702 229.219290 -9.500000e-01 -3.122990e-01
9 R11.3 4.359101 229.394089 -9.499575e-01 -3.122254e-01
10 R11.4 0.003668 0.011247 3.948453e-08 -1.195482e-08
11 R15.1 15.271672 227.066591 -3.294657e+00 -1.081706e+00
12 R15.2 15.254887 227.280502 -3.293328e+00 -1.083991e+00
13 R15.3 15.230552 227.514912 -3.292017e+00 -1.081702e+00
14 R15.4 0.024910 0.099937 2.380792e-06 -7.273643e-07
15 R16.1 16.096357 227.876964 -3.485057e+00 -1.143906e+00
16 R16.2 16.076458 228.116149 -3.483343e+00 -1.146911e+00
17 R16.3 16.047569 228.365740 -3.481603e+00 -1.143930e+00
18 R16.4 0.029558 0.124104 3.496682e-06 -1.108729e-06
19 R17.1 10.260767 227.519635 -2.218223e+00 -7.276670e-01
20 R17.2 10.244894 227.811876 -2.216679e+00 -7.303860e-01
21 R17.3 10.221897 228.095607 -2.215102e+00 -7.276951e-01
22 R17.4 0.023554 0.175980 3.946777e-06 -1.266426e-06
23 R18.1 13.790405 227.336119 -2.978916e+00 -9.770599e-01
24 R18.2 13.767967 227.641712 -2.976683e+00 -9.809879e-01
25 R18.3 13.735478 227.934247 -2.974407e+00 -9.770993e-01
26 R18.4 0.033283 0.189204 5.996453e-06 -1.923019e-06
27 R2.1 0.000000 229.636211 0.000000e+00 -0.000000e+00
28 R2.2 0.000000 229.711450 -0.000000e+00 0.000000e+00
29 R2.3 0.000000 229.853290 0.000000e+00 0.000000e+00
... ... ... ... ... ...
45 R6.3 0.000000 228.746354 0.000000e+00 0.000000e+00
46 R6.4 0.000000 0.112901 0.000000e+00 -0.000000e+00
47 R7.1 0.000000 228.108910 0.000000e+00 -0.000000e+00
48 R7.2 0.000000 228.356044 -0.000000e+00 0.000000e+00
49 R7.3 0.000000 228.610245 0.000000e+00 0.000000e+00
50 R7.4 0.000000 0.131524 0.000000e+00 -0.000000e+00
51 R8.1 0.000000 227.941534 0.000000e+00 -0.000000e+00
52 R8.2 0.000000 228.207678 -0.000000e+00 0.000000e+00
53 R8.3 0.000000 228.474140 0.000000e+00 0.000000e+00
54 R8.4 0.000000 0.150147 0.000000e+00 -0.000000e+00
55 R9.1 0.000000 227.774231 0.000000e+00 -0.000000e+00
56 R9.2 0.000000 228.059234 -0.000000e+00 0.000000e+00
57 R9.3 0.000000 228.338050 0.000000e+00 0.000000e+00
58 R9.4 0.000000 0.168797 0.000000e+00 -0.000000e+00
59 R10.1 0.000000 227.678278 0.000000e+00 -0.000000e+00
60 R10.2 0.000000 227.974154 -0.000000e+00 0.000000e+00
61 R10.3 0.000000 228.260024 0.000000e+00 0.000000e+00
62 R10.4 0.000000 0.179484 0.000000e+00 -0.000000e+00
63 R12.1 0.000000 228.392741 0.000000e+00 -0.000000e+00
64 R12.2 0.000000 228.570126 -0.000000e+00 0.000000e+00
65 R12.3 0.000000 228.779357 0.000000e+00 0.000000e+00
66 R12.4 0.000000 0.062989 0.000000e+00 -0.000000e+00
67 R13.1 0.000000 227.950627 0.000000e+00 -0.000000e+00
68 R13.2 0.000000 228.140238 -0.000000e+00 0.000000e+00
69 R13.3 0.000000 228.357837 0.000000e+00 0.000000e+00
70 R13.4 0.000000 0.075266 0.000000e+00 -0.000000e+00
71 R14.1 0.000000 227.508589 0.000000e+00 -0.000000e+00
72 R14.2 0.000000 227.710350 -0.000000e+00 0.000000e+00
73 R14.3 0.000000 227.936357 0.000000e+00 0.000000e+00
74 R14.4 0.000000 0.087601 0.000000e+00 -0.000000e+00

75 rows × 5 columns

Visualizing Pandas dataframe with qgrid

In [75]:
import qgrid

qgrid.show_grid(df)
In [ ]: