Skip to content

Commit

Permalink
fixed recycle stuff and test
Browse files Browse the repository at this point in the history
  • Loading branch information
Florian Schaefer committed Jul 30, 2019
1 parent 1463fe9 commit d5c6c1e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 94 deletions.
91 changes: 13 additions & 78 deletions pandapower/test/timeseries/test_timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
# Copyright (c) 2016-2019 by University of Kassel and Fraunhofer Institute for Energy Economics
# and Energy System Technology (IEE), Kassel. All rights reserved.

import copy
import os
import tempfile

import numpy as np
Expand All @@ -13,11 +11,9 @@

import pandapower.control.util.diagnostic
import pandapower as pp
import pandapower.toolbox as tb
import logging
from pandapower.control import DiscreteTapControl, ContinuousTapControl, ConstControl
from pandapower.control import ContinuousTapControl, ConstControl

from pandapower import networks as nw
from pandapower.timeseries import DFData
from pandapower.timeseries import OutputWriter
from pandapower.timeseries.run_time_series import run_timeseries, control_diagnostic
Expand Down Expand Up @@ -148,11 +144,11 @@ def test_timeseries_results():

n_timesteps = 5
profiles, ds = create_data_source(n_timesteps)
recycle = False

# 1load
ConstControl(net, element='load', variable='p_mw', element_index=[0, 1, 2],
data_source=ds, profile_name=["load1", "load2_mv_p", "load3_hv_p"],
scale_factor=0.5, recycle=recycle)
scale_factor=0.5)

time_steps = range(0, n_timesteps)
ow = OutputWriter(net, time_steps, output_path=tempfile.gettempdir(), output_file_type=".json")
Expand All @@ -161,18 +157,17 @@ def test_timeseries_results():

ow.log_variable('res_line', 'loading_percent')
ow.log_variable('res_line', 'i_ka')
run_timeseries(net, time_steps, output_writer=ow, recycle=recycle)
run_timeseries(net, time_steps, output_writer=ow)
assert np.allclose(ow.output['res_load.p_mw'].sum().values * 2,
profiles[["load1", "load2_mv_p", "load3_hv_p"]].sum().values)

# 3load - @Rieke What is this test for compared to the first one?
# @Flo in / out of service testen ...
ow.log_variable('res_load', 'p_mw')
net.controller.in_service = False # set the first controller out of service
ConstControl(net, 'load', 'p_mw', element_index=0, data_source=ds, profile_name='load1',
recycle=recycle)
ConstControl(net, 'load', 'p_mw', element_index=0, data_source=ds, profile_name='load1')

run_timeseries(net, time_steps, output_writer=ow, recycle=recycle)
run_timeseries(net, time_steps, output_writer=ow)
assert np.allclose(ow.output['res_load.p_mw'][0].sum(), profiles["load1"].sum())


Expand All @@ -184,19 +179,19 @@ def test_timeseries_var_func():

n_timesteps = 5
profiles, ds = create_data_source(n_timesteps)
recycle = False

# 1load
ConstControl(net, element='load', variable='p_mw', element_index=[0, 1, 2],
data_source=ds, profile_name=["load1", "load2_mv_p", "load3_hv_p"],
scale_factor=0.5, recycle=recycle)
scale_factor=0.5)

time_steps = range(0, n_timesteps)
ow = OutputWriter(net, time_steps, output_path=tempfile.gettempdir(), output_file_type=".json")
ow.log_variable('res_load', 'p_mw', eval_function=np.max)
ow.log_variable('res_bus', 'vm_pu', eval_function=np.min)
ow.log_variable('res_bus', 'q_mvar', eval_function=np.sum)

run_timeseries(net, time_steps, output_writer=ow, recycle=recycle)
run_timeseries(net, time_steps, output_writer=ow)
# asserts if last value of output_writers output is the minimum value
assert net["res_load"]["p_mw"].max() == ow.output["res_load.p_mw"].iloc[-1].values
assert net["res_bus"]["vm_pu"].min() == ow.output["res_bus.vm_pu"].iloc[-1].values
Expand All @@ -211,72 +206,13 @@ def test_timeseries_var_func():
eval_name="hv_bus_min")
ow.log_variable('res_bus', 'vm_pu', index=mv_busses_index, eval_function=np.min,
eval_name="mv_bus_min")
run_timeseries(net, time_steps, output_writer=ow, recycle=recycle)
run_timeseries(net, time_steps, output_writer=ow)
assert net["res_bus"].loc[hv_busses_index, "vm_pu"].min() == ow.output["res_bus.vm_pu"].loc[
time_steps[-1], "hv_bus_min"]
assert net["res_bus"].loc[mv_busses_index, "vm_pu"].min() == ow.output["res_bus.vm_pu"].loc[
time_steps[-1], "mv_bus_min"]


@pytest.mark.xfail(
reason="@author: please rework this test in cooporation with steffen, after publication of simbench within pandapower")
def test_timeseries_recycle_simbench():
# Todo: Get simbench net and test trafo controllers with recycle functions
# test net
# net = sb.get_simbench_net("1-HV-mixed--0-sw")
net = nw.create_cigre_network_hv() # fixing the import error bug
# random datasource --> will be memmaps
tb.drop_inactive_elements(net)
n_timesteps = 3
profiles = create_rand_data_source(net, n_timesteps)

# 1load
ds = DFData(profiles["load"])
ConstControl(net, element='load', variable='p_mw', element_index=net.load.index,
data_source=ds, profile_name=profiles["load"].keys(),
scale_factor=0.5, recycle=True)
# sgen
ds = DFData(profiles["sgen"])
ConstControl(net, element='sgen', variable='p_mw', element_index=net.sgen.index,
data_source=ds, profile_name=profiles["sgen"].keys(),
scale_factor=0.5, recycle=True)

# tc = ContinuousTapControl(net, tid=6, u_set=1.04, side='lv', tol=1e-6, trafotype="3W", recycle=True)
# tc = ContinuousTapControl(net, tid=5, u_set=.98, side='lv', tol=1e-6, trafotype="3W", recycle=True)
tc = DiscreteTapControl(net, tid=0, u_lower=1.04, u_upper=1.044, side='lv', recycle=True)
tc = DiscreteTapControl(net, tid=1, u_lower=.98, u_upper=.984, side='lv', recycle=True)
# ds = DFData(profiles["trafo3w"])
# ConstControl(net, element='trafo3w', variable='tap_pos', element_index=net.trafo3w.index,
# data_source=ds, profile_name=profiles["trafo3w"].keys(), scale_factor=1, recycle=True)
net.trafo.loc[0, "tap_pos"] = -10
net.trafo.loc[1, "tap_pos"] = 2
time_steps = range(0, n_timesteps)
ow = OutputWriter(net, time_steps, output_path=tempfile.gettempdir())
ow.log_variable('trafo', 'tap_pos')
ow.log_variable('res_load', 'p_mw')
ow.log_variable('res_bus', 'vm_pu')
ow.log_variable('res_line', 'loading_percent')
ow.log_variable('res_trafo', 'loading_percent')
ow.log_variable('res_line', 'i_ka')

run_timeseries(net, time_steps, output_writer=ow, recycle=False)
res_normal = copy.deepcopy(ow.output)

net.trafo.loc[0, "tap_pos"] = -10
net.trafo.loc[1, "tap_pos"] = 2
run_timeseries(net, time_steps, output_writer=ow, recycle=True)
res_recycle = copy.deepcopy(ow.output)

for key, val in res_normal.items():
val_recycle = res_recycle[key]
if key == "Parameters":
# Parameters is complex datatype compared to others
np.testing.assert_array_equal(val_recycle.values, val.values)
else:
mask = ~(np.isnan(val)).values
assert np.allclose(val_recycle.values[mask], val.values[mask])


def test_time_steps():
net = simple_test_net()
n_timesteps = 11
Expand All @@ -300,11 +236,10 @@ def test_output_dump_after_time():

n_timesteps = 100
profiles, ds = create_data_source(n_timesteps)
recycle = False

# 1load
ConstControl(net, element='load', variable='p_mw', element_index=[0, 1, 2],
data_source=ds, profile_name=["load1", "load2_mv_p", "load3_hv_p"],
recycle=recycle)
data_source=ds, profile_name=["load1", "load2_mv_p", "load3_hv_p"])

time_steps = range(0, n_timesteps)
# write output after 0.1 minutes to disk
Expand All @@ -315,7 +250,7 @@ def test_output_dump_after_time():

ow.log_variable('res_line', 'loading_percent')
ow.log_variable('res_line', 'i_ka')
run_timeseries(net, time_steps, output_writer=ow, recycle=recycle)
run_timeseries(net, time_steps, output_writer=ow)
# ToDo: read partially dumped results and compare with all stored results


Expand Down
41 changes: 25 additions & 16 deletions pandapower/timeseries/run_time_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,22 +140,34 @@ def run_time_step(net, time_step, ts_variables, **kwargs):


def all_controllers_recycleable(net):
# checks if controller are recycleable
recycleable = np.alltrue(net["controller"]["recycle"].values)
if not recycleable:
logger.warning("recycle feature not supported by some controllers in net. I have to deactive recycle")
return recycleable


def get_run_function(net, output_writer, recycle, **kwargs):
def get_run_function(net, output_writer, **kwargs):
"""
checks if faster runpp function for time series is possible and activated or if another function is specified
in **kwargs
@param kwargs:
@return:
checks if "run" is specified in kwargs and calls this function in time series loop.
if "recycle" is in kwargs we use the TimeSeriesRunpp class
INPUT:
**net** - The pandapower format network
**output_writer** - The outputwriter class which stores results
RETURN:
**run** - the run function to be called (default is pp.runpp())
**recycle_class** - class to recycle implementation
"""

recycle = True if recycle and all_controllers_recycleable(net) else False
recycle = False
recycle_class = None

if "recycle" in kwargs:
recycle = kwargs.pop("recycle")
recycle = True if recycle and all_controllers_recycleable(net) else False

if recycle:
from timeseries.ts_runpp import TimeSeriesRunpp
recycle_class = TimeSeriesRunpp(net, output_writer)
Expand All @@ -168,6 +180,7 @@ def get_run_function(net, output_writer, recycle, **kwargs):


def init_time_steps(net, time_steps, **kwargs):
# initializes time steps if as a range
if not (isinstance(time_steps, list) or isinstance(time_steps, range)):
if time_steps is None and ("start_step" in kwargs and "stop_step" in kwargs):
logger.warning("start_step and stop_step are depricated. "
Expand All @@ -183,7 +196,7 @@ def init_time_steps(net, time_steps, **kwargs):
return time_steps


def init_time_series(net, time_steps, output_writer=None, recycle=False, continue_on_divergence=False, verbose=True,
def init_time_series(net, time_steps, output_writer=None, continue_on_divergence=False, verbose=True,
**kwargs):
"""
inits the time series calculation
Expand All @@ -196,7 +209,6 @@ def init_time_series(net, time_steps, output_writer=None, recycle=False, continu
OPTIONAL:
**output_writer** - A predefined output writer. If None the a default one is created with
get_default_output_writer()
**recycle** (bool, False) - If True faster runpp is used (rather experimental, use with caution)
**continue_on_divergence** (bool, False) - If True time series calculation continues in case of errors.
**verbose** (bool, True) - prints progess bar or logger debug messages
"""
Expand All @@ -208,7 +220,7 @@ def init_time_series(net, time_steps, output_writer=None, recycle=False, continu
output_writer = init_outputwriter(net, time_steps, output_writer)
level, order = get_controller_order(net)
# use faster runpp if timeseries possible
run, recycle_class = get_run_function(net, output_writer, recycle, **kwargs)
run, recycle_class = get_run_function(net, output_writer, **kwargs)

# True at default. Initial power flow is calculated before each control step (some controllers need inits)
ts_variables["initial_powerflow"] = check_for_initial_powerflow(order)
Expand Down Expand Up @@ -246,7 +258,7 @@ def print_progress(i, time_step, time_steps, verbose, **kwargs):
if logger.level == pplog.DEBUG and verbose:
logger.debug("run time step %i" % time_step)

# print luigi progress
# print luigi pipeline progress
if "luigi_progress" in kwargs:
if i % 365 == 0:
# print only every 365 time steps
Expand All @@ -258,12 +270,11 @@ def print_progress(i, time_step, time_steps, verbose, **kwargs):
progress(progress_percentage)


def run_timeseries(net, time_steps=None, output_writer=None, recycle=False,
continue_on_divergence=False, verbose=True, **kwargs):
def run_timeseries(net, time_steps=None, output_writer=None, continue_on_divergence=False, verbose=True, **kwargs):
"""
Time Series main function
Runs multiple PANDAPOWER AC power flows based on time series in controllers
Optionally other functions than the pp power flow can be called by setting the run function
Optionally other functions than the pp power flow can be called by setting the run function in kwargs
INPUT:
**net** - The pandapower format network
Expand All @@ -273,16 +284,14 @@ def run_timeseries(net, time_steps=None, output_writer=None, recycle=False,
if None, all time steps from provided data source are simulated
**output_writer** - A predefined output writer. If None the a default one is created with
get_default_output_writer()
**recycle** (bool, False) - If True faster runpp is used (rather experimental, use with caution)
**continue_on_divergence** (bool, False) - If True time series calculation continues in case of errors.
**verbose** (bool, True) - prints progress bar or if logger.level == Debug it prints debug messages
**kwargs** - Keyword arguments for run_control and runpp
"""

ts_variables = init_time_series(net, time_steps, output_writer, recycle, continue_on_divergence, verbose,
ts_variables = init_time_series(net, time_steps, output_writer, continue_on_divergence, verbose,
**kwargs)
control_diagnostic(net)

for i, time_step in enumerate(ts_variables["time_steps"]):
print_progress(i, time_step, ts_variables["time_steps"], verbose, **kwargs)
run_time_step(net, time_step, ts_variables, **kwargs)
Expand Down

0 comments on commit d5c6c1e

Please sign in to comment.