#!/usr/bin/env python # coding: utf-8 # # Distribution Generation Curtailment with OPF # This is an introduction on how to use the pandapower optimal power flow for calculation optimal distributed generation curtailment. # # ## Example Network # # We use the four bus example network from the basic OPF tutorial: # # # # We first create this network in pandapower: # In[100]: import pandapower as pp net = pp.create_empty_network() #create buses bus1 = pp.create_bus(net, vn_kv=220., min_vm_pu=1.0, max_vm_pu=1.02) bus2 = pp.create_bus(net, vn_kv=110., min_vm_pu=1.0, max_vm_pu=1.02) bus3 = pp.create_bus(net, vn_kv=110., min_vm_pu=1.0, max_vm_pu=1.02) bus4 = pp.create_bus(net, vn_kv=110., min_vm_pu=1.0, max_vm_pu=1.02) #create 220/110 kV transformer pp.create_transformer(net, bus1, bus2, std_type="100 MVA 220/110 kV", max_loading_percent=100) #create 110 kV lines pp.create_line(net, bus2, bus3, length_km=70., std_type='149-AL1/24-ST1A 110.0', max_loading_percent=100) pp.create_line(net, bus3, bus4, length_km=50., std_type='149-AL1/24-ST1A 110.0', max_loading_percent=100) pp.create_line(net, bus4, bus2, length_km=40., std_type='149-AL1/24-ST1A 110.0', max_loading_percent=100) #create loads pp.create_load(net, bus2, p_mw=60, controllable=False) pp.create_load(net, bus3, p_mw=70, controllable=False) pp.create_load(net, bus4, p_mw=10, controllable=False) #create generators eg = pp.create_ext_grid(net, bus1) g0 = pp.create_gen(net, bus3, p_mw=80, min_p_mw=0, max_p_mw=80, vm_pu=1.01, controllable=True) g1 = pp.create_gen(net, bus4, p_mw=100, min_p_mw=0, max_p_mw=100, vm_pu=1.01, controllable=True) # In[102]: pp.create_poly_cost(net, 0, 'gen', cp1_eur_per_mw=-1) pp.create_poly_cost(net, 1, 'gen', cp1_eur_per_mw=-1) pp.create_poly_cost(net, 0, 'ext_grid', cp1_eur_per_mw=0) pp.runopp(net, verbose=True) # Because of the negative costs, the OPF now maximizes power generation at the generators, which is constrained by their maximum power: # In[103]: pd.concat([net.res_gen.p_mw, net.gen.min_p_mw, net.gen.max_p_mw], axis=1) # While gen 1 is operating at the limit, gen 0 is below the maximum output. Apparently the generator can not reach its maximum output without violating at least one power flow constraint. Let's check on the constraints. # # The line and transformer constraints are not reached: # In[104]: pd.concat([net.line.max_loading_percent, net.res_line.loading_percent], axis=1) # In[105]: pd.concat([net.trafo.max_loading_percent, net.res_trafo.loading_percent], axis=1) # But the voltage constraints are: # In[106]: import pandas as pd pd.concat([net.res_bus.vm_pu, net.bus.min_vm_pu, net.bus.max_vm_pu], axis=1) # Obviously the voltage profile was the limiting factor for the generator feed-in. If we relax this constraint a little bit: # In[107]: net.bus["max_vm_pu"] = 1.05 pp.runopp(net) # We see an increased feed-in of the generators: # In[108]: pd.concat([net.res_gen.p_mw, net.gen.min_p_mw, net.gen.max_p_mw], axis=1) # In[109]: net.res_bus