This tutorial shows how specific results are extracted with the time series module in pandapower.
In this example we define the output writer to log the following:
This time series calculation requires the minimum following inputs:
If you have just read the simple time_series jupyter notebook example. You can directly proceed to the section of create_output_writer()
First we need some imports. Specific for this example are:
import os
import numpy as np
import pandas as pd
import tempfile
import random
import pandapower as pp
from pandapower.control import ConstControl
from pandapower.timeseries import DFData
from pandapower.timeseries import OutputWriter
from pandapower.timeseries.run_time_series import run_timeseries
random.seed(10)
First we look at the time series example function. It follows these steps:
def timeseries_example(output_dir):
# 1. create test net
net = simple_test_net()
# 2. create (random) data source
n_timesteps = 10
profiles, ds = create_data_source(n_timesteps)
# 3. create controllers (to control P values of the load and the sgen)
net = create_controllers(net, ds)
# time steps to be calculated. Could also be a list with non-consecutive time steps
time_steps = range(0, n_timesteps)
# 4. the output writer with the desired results to be stored to files.
ow = create_output_writer(net, time_steps, output_dir)
# 5. the main time series function
run_timeseries(net, time_steps)
We start by creating a simple example pandapower net consisting of five buses, a transformer, three lines, a load and a sgen.
def simple_test_net():
"""
simple net that looks like:
ext_grid b0---b1 trafo(110/20) b2----b3 load
|
|
b4 sgen
"""
net = pp.create_empty_network()
pp.set_user_pf_options(net, init_vm_pu = "flat", init_va_degree = "dc", calculate_voltage_angles=True)
b0 = pp.create_bus(net, 110)
b1 = pp.create_bus(net, 110)
b2 = pp.create_bus(net, 20)
b3 = pp.create_bus(net, 20)
b4 = pp.create_bus(net, 20)
pp.create_ext_grid(net, b0)
pp.create_line(net, b0, b1, 10, "149-AL1/24-ST1A 110.0")
pp.create_transformer(net, b1, b2, "25 MVA 110/20 kV", name='tr1')
pp.create_line(net, b2, b3, 10, "184-AL1/30-ST1A 20.0")
pp.create_line(net, b2, b4, 10, "184-AL1/30-ST1A 20.0")
pp.create_load(net, b2, p_mw=15., q_mvar=10., name='load1')
pp.create_sgen(net, b4, p_mw=20., q_mvar=0.15, name='sgen1')
return net
The data source is a simple pandas DataFrame. It contains random values for the load and the sgen P values ("profiles"). Of course your time series values should be loaded from a file later on. Note that the profiles are identified by their column name ("load1_p", "sgen1_p"). You can choose here whatever you prefer. The DFData(profiles) converts the Dataframe to the required format for the controllers. Note that the controller
def create_data_source(n_timesteps=10):
profiles = pd.DataFrame()
profiles['load1_p'] = np.random.random(n_timesteps) * 15.
profiles['sgen1_p'] = np.random.random(n_timesteps) * 20.
ds = DFData(profiles)
return profiles, ds
create the controllers by telling the function which element_index belongs to which profile. In this case we map:
def create_controllers(net, ds):
ConstControl(net, element='load', variable='p_mw', element_index=[0],
data_source=ds, profile_name=["load1_p"])
ConstControl(net, element='sgen', variable='p_mw', element_index=[0],
data_source=ds, profile_name=["sgen1_p"])
return net
create the output writer. Instead of saving the whole net (which takes a lot of time), we extract only pre defined outputs. In this case we:
def create_output_writer(net, time_steps, output_dir):
ow = OutputWriter(net, time_steps, output_path=output_dir, output_file_type=".xlsx", log_variables=list())
# create a mask to get the indices of all the hv buses in the grid
mask_hv_buses = (net.bus.vn_kv > 70.0) & (net.bus.vn_kv < 380.0)
hv_busses_index = net.bus.loc[mask_hv_buses].index
# create a mask to get the indices of all the mv buses in the grid
mask_mv_buses = (net.bus.vn_kv > 1.0) & (net.bus.vn_kv < 70.0)
mv_busses_index = net.bus.loc[mask_mv_buses].index
# now define the output writer, so that it gets the indices and specify the evaluation functions
# since we want the maximum voltage of all mv buses, we provide the indices of the mv buses and the maximum
# function np.max. The variable "eval_name" is free to chose and contains the name of the column in
# which the results are saved.
ow.log_variable('res_bus', 'p_mw', index=hv_busses_index, eval_function=np.sum, eval_name="hv_bus_sum_p")
ow.log_variable('res_bus', 'vm_pu', index=mv_busses_index, eval_function=np.max, eval_name="mv_bus_max")
return ow
Now lets execute the code.
output_dir = os.path.join(tempfile.gettempdir(), "time_series_example")
print("Results can be found in your local temp folder: {}".format(output_dir))
if not os.path.exists(output_dir):
os.mkdir(output_dir)
timeseries_example(output_dir)
Results can be found in your local temp folder: C:\Users\mmilovic\AppData\Local\Temp\time_series_example
100%|██████████████████████████████████████████████████████████████████████████████████| 10/10 [00:03<00:00, 2.83it/s]
If everything works you should have the desired results the temporary folder of your os (see print statement above). In this folder two excel files should have appeared containing the desired output for each of the ten time steps
Now let us plot the results
import matplotlib.pyplot as plt
%matplotlib inline
# voltage results
vm_pu_file = os.path.join(output_dir, "res_bus", "vm_pu.xlsx")
vm_pu = pd.read_excel(vm_pu_file, index_col=0)
vm_pu.plot(label="vm_pu")
plt.xlabel("time step")
plt.ylabel("voltage mag. [p.u.]")
plt.title("Voltage Magnitude")
plt.grid()
plt.show()
# p_mw results
p_mw_file = os.path.join(output_dir, "res_bus", "p_mw.xlsx")
p_mw = pd.read_excel(p_mw_file, index_col=0)
p_mw.plot(label="p_mw")
plt.xlabel("time step")
plt.ylabel("P [MW]")
plt.title("Real Power at Buses")
plt.grid()
plt.show()