Repository: e2nIEE/pandapower

Issue:
Cannot use 'bfsw' algorithm with time series
I am trying to run the 'bfsw' algorithm with time series but an error occurs.

version: pandapower==2.4.0
os: #52-Ubuntu SMP Thu Sep 10 10:58:49 UTC 2020

What caused the error: 

I modifed this example: [Time series example](https://nbviewer.jupyter.org/github/e2nIEE/pandapower/blob/develop/tutorials/time_series.ipynb)

by changing:
```python
    # 1. create test net
    net = simple_test_net()

    # 2. create (random) data source
    n_timesteps = 24
    profiles, ds = create_data_source(n_timesteps)
    # 3. create controllers (to control P values of the load and the sgen)
    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=output_dir)

    # 5. the main time series function
    run_timeseries(net, time_steps)
```
into

```python
def timeseries_example(output_dir):
    # 1. create test net
    net = simple_test_net()

    # 2. create (random) data source
    n_timesteps = 24
    profiles, ds = create_data_source(n_timesteps)
    # 3. create controllers (to control P values of the load and the sgen)
    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=output_dir)

    # 5. the main time series function
    run_timeseries(net, time_steps, algorithm='bfsw')
```

Error:

```python
TypeError                                 Traceback (most recent call last)
<ipython-input-17-7ba382adfb8e> in <module>
      3 if not os.path.exists(output_dir):
      4     os.mkdir(output_dir)
----> 5 timeseries_example(output_dir)

<ipython-input-11-b8481a2a0e9c> in timeseries_example(output_dir)
     16 
     17     # 5. the main time series function
---> 18     run_timeseries(net, time_steps, algorithm='bfsw')

~/github/distflow/venv/lib/python3.8/site-packages/pandapower/timeseries/run_time_series.py in run_timeseries(net, time_steps, continue_on_divergence, verbose, **kwargs)
    336 
    337     control_diagnostic(net)
--> 338     run_loop(net, ts_variables, **kwargs)
    339 
    340     # cleanup functions after the last time step was calculated

~/github/distflow/venv/lib/python3.8/site-packages/pandapower/timeseries/run_time_series.py in run_loop(net, ts_variables, **kwargs)
    308     for i, time_step in enumerate(ts_variables["time_steps"]):
    309         print_progress(i, time_step, ts_variables["time_steps"], ts_variables["verbose"], **kwargs)
--> 310         run_time_step(net, time_step, ts_variables, **kwargs)
    311 
    312 

~/github/distflow/venv/lib/python3.8/site-packages/pandapower/timeseries/run_time_series.py in run_time_step(net, time_step, ts_variables, **kwargs)
    112     try:
    113         # calls controller init, control steps and run function (runpp usually is called in here)
--> 114         run_control(net, run_control=False, ctrl_variables=ts_variables, **kwargs)
    115     except ControllerNotConverged:
    116         ctrl_converged = False

~/github/distflow/venv/lib/python3.8/site-packages/pandapower/control/run_control.py in run_control(net, ctrl_variables, max_iter, continue_on_lf_divergence, **kwargs)
    232 
    233     # run each controller step in given controller order
--> 234     control_implementation(controller_order, net, run_funct, errors, max_iter, continue_on_lf_divergence, **kwargs)
    235 
    236     # call finalize function of each controller

~/github/distflow/venv/lib/python3.8/site-packages/pandapower/control/run_control.py in control_implementation(controller_order, net, run_funct, errors, max_iter, continue_on_lf_divergence, **kwargs)
    150             if not converged:
    151                 run_count += 1
--> 152                 _control_repair(net, run_funct, continue_on_lf_divergence, levelorder, errors, **kwargs)
    153         # raises controller not converged
    154         check_final_convergence(run_count, max_iter, errors, net['converged'])

~/github/distflow/venv/lib/python3.8/site-packages/pandapower/control/run_control.py in _control_repair(net, run_funct, continue_on_lf_divergence, levelorder, errors, **kwargs)
    170 def _control_repair(net, run_funct, continue_on_lf_divergence, levelorder, errors, **kwargs):
    171     try:
--> 172         run_funct(net, **kwargs)  # run can be runpp, runopf or whatever
    173     except errors:
    174         if continue_on_lf_divergence:

~/github/distflow/venv/lib/python3.8/site-packages/pandapower/run.py in runpp(net, algorithm, calculate_voltage_angles, init, max_iteration, tolerance_mva, trafo_model, trafo_loading, enforce_q_lims, check_connectivity, voltage_depend_loads, consider_line_temperature, run_control, **kwargs)
    223         _check_bus_index_and_print_warning_if_high(net)
    224         _check_gen_index_and_print_warning_if_high(net)
--> 225         _powerflow(net, **kwargs)
    226 
    227 

~/github/distflow/venv/lib/python3.8/site-packages/pandapower/powerflow.py in _powerflow(net, **kwargs)
     72 
     73     # ----- run the powerflow -----
---> 74     result = _run_pf_algorithm(ppci, net["_options"], **kwargs)
     75     # read the results (=ppci with results) to net
     76     _ppci_to_net(result, net)

~/github/distflow/venv/lib/python3.8/site-packages/pandapower/powerflow.py in _run_pf_algorithm(ppci, options, **kwargs)
    147             result = _pf_without_branches(ppci, options)
    148         elif algorithm == 'bfsw':  # forward/backward sweep power flow algorithm
--> 149             result = _run_bfswpf(ppci, options, **kwargs)[0]
    150         elif algorithm in ['nr', 'iwamoto_nr']:
    151             result = _run_newton_raphson_pf(ppci, options)

~/github/distflow/venv/lib/python3.8/site-packages/pandapower/pf/run_bfswpf.py in _run_bfswpf(ppci, options, **kwargs)
    406 
    407         # depth-first-search bus ordering and generating Direct Load Flow matrix DLF = BCBV * BIBC
--> 408         ppci, DLF, buses_ordered_bfs_nets = _get_bibc_bcbv(ppci, options, bus, branch, G)
    409 
    410     # if there are trafos with phase-shift calculate Ybus without phase-shift for bfswpf

~/github/distflow/venv/lib/python3.8/site-packages/pandapower/pf/run_bfswpf.py in _get_bibc_bcbv(ppci, options, bus, branch, graph)
    171     recycle = options["recycle"]
    172 
--> 173     if recycle is not None and recycle["bfsw"] and ppci["internal"]["DLF"].size:
    174         DLF, buses_ordered_bfs_nets = ppci["internal"]['DLF'], \
    175                                       ppci["internal"]['buses_ord_bfs_nets']

TypeError: 'bool' object is not subscriptable
```




Discussion:
I cannot reproduce the error, but I am getting a different error:

  File "C:\pandapower\pandapower\pf\run_bfswpf.py", line 173, in _get_bibc_bcbv
    if recycle is not None and recycle["bfsw"] and ppci["internal"]["DLF"].size:
KeyError: 'bfsw'


@FlorianShepherd , @jkrstulo , can you take a look at this error?

Resolving patch:
diff --git a/pandapower/pf/run_bfswpf.py b/pandapower/pf/run_bfswpf.py
--- a/pandapower/pf/run_bfswpf.py
+++ b/pandapower/pf/run_bfswpf.py
@@ -170,13 +170,13 @@ def _make_bibc_bcbv(bus, branch, graph):
 def _get_bibc_bcbv(ppci, options, bus, branch, graph):
     recycle = options["recycle"]
 
-    if recycle is not None and recycle["bfsw"] and ppci["internal"]["DLF"].size:
+    if isinstance(recycle, dict) and not recycle["trafo"] and ppci["internal"]["DLF"].size:
         DLF, buses_ordered_bfs_nets = ppci["internal"]['DLF'], \
                                       ppci["internal"]['buses_ord_bfs_nets']
     else:
         ## build matrices
         DLF, buses_ordered_bfs_nets = _make_bibc_bcbv(bus, branch, graph)
-        if recycle is not None and recycle["bfsw"]:
+        if isinstance(recycle, dict) and not recycle["trafo"]:
             ppci["internal"]['DLF'], \
             ppci["internal"]['buses_ord_bfs_nets'] = DLF, buses_ordered_bfs_nets
 


Test patch: