Skip to content

Commit

Permalink
Merge branch 'meta_control' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
rbolgaryn committed May 19, 2021
2 parents 4b9f36b + e067741 commit cfb5dfa
Show file tree
Hide file tree
Showing 8 changed files with 500 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Change Log
- [ADDED] OR-Tools implementation of linprog solver
- [ADDED] Efficient PTDF calculation on large grid
- [ADDED] toolbox function replace_pq_elmtype()
- [CHANGED] ConstControl can now also change attributes of other controllers, if the parameter "variable" is defined in the format "object.attribute" (e.g. "object.vm_set_pu")

[2.6.0]- 2021-03-09
----------------------
Expand Down
3 changes: 3 additions & 0 deletions doc/control/controller.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ ConstControl
==============
.. _ConstControl:
This controller is made for the use with the time series module to read data from a DataSource and write it to the net.
The controller can write the values either to a column of an element table (e.g. net.load.p_mw) or an attribute of another object that is
stored in an element table (e.g. another controller, net.controller.object). To change a controller attribute, the variable must be defined
in the format "object.attribute" (e.g. "object.set_vm_pu").

.. autoclass:: pandapower.control.controller.const_control.ConstControl
:members:
Expand Down
24 changes: 23 additions & 1 deletion pandapower/control/controller/const_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ class ConstControl(Controller):
"""
Class representing a generic time series controller for a specified element and variable
Control strategy: "No Control" -> just updates timeseries
It is possible to set attributes of objects that are contained in a net table, e.g. attributes of other controllers. This can be helpful
e.g. if a voltage setpoint of a transformer tap changer depends on the time step.
An attribute of an object in the "object" column of a table (e.g. net.controller["object"] -> net.controller.object.at[0, "vm_set_pu"]
can be set if the attribute is specified as "object.attribute" (e.g. "object.vm_set_pu").
INPUT:
Expand Down Expand Up @@ -76,8 +80,13 @@ def __init__(self, net, element, variable, element_index, profile_name=None, dat
self.profile_name = profile_name
self.scale_factor = scale_factor
self.applied = False
self.object_attribute = None
# write functions faster, depending on type of self.element_index
if isinstance(self.element_index, int):
if self.variable.startswith('object'):
# write to object attribute
self.write = "object"
self.object_attribute = self.variable.split(".")[1]
elif isinstance(self.element_index, int):
# use .at if element_index is integer for speedup
self.write = "single_index"
# commenting this out for now, see issue 609
Expand Down Expand Up @@ -123,6 +132,8 @@ def write_to_net(self, net):
self._write_to_all_index(net)
elif self.write == "loc":
self._write_with_loc(net)
elif self.write == "object":
self._write_to_object_attribute(net)
else:
raise NotImplementedError("ConstControl: self.write must be one of "
"['single_index', 'all_index', 'loc']")
Expand Down Expand Up @@ -167,3 +178,14 @@ def _write_to_all_index(self, net):

def _write_with_loc(self, net):
net[self.element].loc[self.element_index, self.variable] = self.values

def _write_to_object_attribute(self, net):
if hasattr(self.element_index, '__iter__') and len(self.element_index) > 1:
for idx, val in zip(self.element_index, self.values):
setattr(net[self.element]["object"].at[idx], self.object_attribute, val)
else:
setattr(net[self.element]["object"].at[self.element_index], self.object_attribute, self.values)

def __str__(self):
return super().__str__() + " [%s.%s]" % (self.element, self.variable)

21 changes: 21 additions & 0 deletions pandapower/control/controller/trafo/DiscreteTapControl.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,27 @@ def __init__(self, net, tid, vm_lower_pu, vm_upper_pu, side="lv", trafotype="2W"
self.vm_upper_pu = vm_upper_pu

self.tap_pos = net[self.trafotable].at[tid, "tap_pos"]
if "vm_set_pu" in kwargs:
self.vm_set_pu = kwargs["vm_set_pu"]
self.vm_delta_pu = self.net[self.trafotable].at[tid, "tap_step_percent"] / 100. * .5
else:
self.vm_set_pu = None
self.vm_delta_pu = None

@classmethod
def from_tap_step_percent(cls, net, tid, vm_set_pu, side="lv", trafotype="2W", tol=1e-3, in_service=True, order=0,
drop_same_existing_ctrl=False, matching_params=None, **kwargs):
self = DiscreteTapControl(net, tid=tid, vm_lower_pu=None, vm_upper_pu=None, side=side, trafotype=trafotype, tol=tol,
in_service=in_service, order=order, drop_same_existing_ctrl=drop_same_existing_ctrl,
matching_params=matching_params, vm_set_pu=vm_set_pu, **kwargs)
self.vm_lower_pu = self.vm_set_pu - self.vm_delta_pu
self.vm_upper_pu = self.vm_set_pu + self.vm_delta_pu

def initialize_control(self, net):
if hasattr(self, 'vm_set_pu') and self.vm_set_pu is not None:
self.vm_delta_pu = self.net[self.trafotable].at[tid, "tap_step_percent"] / 100. * .5
self.vm_lower_pu = self.vm_set_pu - self.vm_delta_pu
self.vm_upper_pu = self.vm_set_pu + self.vm_delta_pu

def control_step(self, net):
"""
Expand Down
2 changes: 1 addition & 1 deletion pandapower/control/util/auxiliary.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def get_controller_index(net, ctrl_type=None, parameters=None, idx=[]):
# query of parameters in net.controller dataframe
idx = Int64Index(idx)
for df_key in df_keys:
idx &= net.controller.index[net.controller[df_key] == parameters[df_key]]
idx.intersection(net.controller.index[net.controller[df_key] == parameters[df_key]])
# query of parameters in controller object attributes
idx = [i for i in idx if _controller_attributes_query(
net.controller.object.loc[i], attributes_dict)]
Expand Down
11 changes: 11 additions & 0 deletions pandapower/test/control/test_const_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,16 @@ def test_write():
assert np.all(net.sgen.p_mw.values == ds.df.loc[t].values * np.array([1, 1, 0.5]))


def test_write_to_object_attribute():
net = nw.simple_four_bus_system()
ds = pp.timeseries.DFData(pd.DataFrame(data=[1.01, 1.02, 1.03]))
c1 = pp.control.ContinuousTapControl(net, 0, 1.)
c2 = pp.control.ConstControl(net, 'controller', 'object.vm_set_pu', element_index=0, profile_name=0, data_source=ds)
for t in range(2):
c2.time_step(net, t)
c2.control_step(net)
assert net.controller.object.at[0].vm_set_pu == ds.df.at[t, 0]


if __name__ == '__main__':
pytest.main([__file__])
22 changes: 22 additions & 0 deletions pandapower/test/timeseries/test_timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,28 @@ def test_const_control(simple_test_net):
assert np.alltrue(profiles['slack_v'].values == ow.output['res_bus.vm_pu'][0].values)


def test_const_control_write_to_object_attribute(simple_test_net):
net = simple_test_net
profiles, ds = create_data_source()
time_steps = range(0, 10)
ow = setup_output_writer(net, time_steps)

ContinuousTapControl(net, 0, 1., level=1, check_tap_bounds=False)

ConstControl(net, 'load', 'p_mw', element_index=0, data_source=ds, profile_name='load1',
scale_factor=0.85)

ConstControl(net, 'ext_grid', 'vm_pu', element_index=0, data_source=ds, profile_name='slack_v')

ConstControl(net, 'controller', 'object.vm_set_pu', element_index=0, data_source=ds, profile_name='trafo_v')

run_timeseries(net, time_steps, output_writer=ow, verbose=False)

assert np.alltrue(profiles['load1'].values * 0.85 == ow.output['load.p_mw'][0].values)
assert np.alltrue(profiles['slack_v'].values == ow.output['res_bus.vm_pu'][0].values)
assert np.allclose(profiles['trafo_v'].values, ow.output['res_bus.vm_pu'][net.trafo.at[0, 'lv_bus']].values, atol=1e-3, rtol=0)


def test_false_alarm_trafos(simple_test_net):
net = simple_test_net

Expand Down
Loading

0 comments on commit cfb5dfa

Please sign in to comment.