-
Notifications
You must be signed in to change notification settings - Fork 466
/
optimal_powerflow.py
130 lines (101 loc) · 4.35 KB
/
optimal_powerflow.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# -*- coding: utf-8 -*-
# Copyright (c) 2016-2024 by University of Kassel and Fraunhofer Institute for Energy Economics
# and Energy System Technology (IEE), Kassel. All rights reserved.
import warnings
from sys import stdout
from numpy import allclose
from pandapower.pypower.add_userfcn import add_userfcn
from pandapower.pypower.ppoption import ppoption
from scipy.sparse import csr_matrix as sparse
from pandapower.auxiliary import ppException, _clean_up, _add_auxiliary_elements
from pandapower.pypower.idx_bus import VM
from pandapower.pypower.opf import opf
from pandapower.pypower.printpf import printpf
from pandapower.pd2ppc import _pd2ppc
from pandapower.pf.run_newton_raphson_pf import _run_newton_raphson_pf
from pandapower.results import _copy_results_ppci_to_ppc, init_results, verify_results, \
_extract_results
try:
import pandaplan.core.pplog as logging
except ImportError:
import logging
logger = logging.getLogger(__name__)
class OPFNotConverged(ppException):
"""
Exception being raised in case optimal powerflow did not converge.
"""
pass
def _optimal_powerflow(net, verbose, suppress_warnings, **kwargs):
ac = net["_options"]["ac"]
init = net["_options"]["init"]
if "OPF_FLOW_LIM" not in kwargs:
kwargs["OPF_FLOW_LIM"] = 2
if net["_options"]["voltage_depend_loads"] and not (
allclose(net.load.const_z_percent.values, 0) and
allclose(net.load.const_i_percent.values, 0)):
logger.error("pandapower optimal_powerflow does not support voltage depend loads.")
ppopt = ppoption(VERBOSE=verbose, PF_DC=not ac, INIT=init, **kwargs)
net["OPF_converged"] = False
net["converged"] = False
_add_auxiliary_elements(net)
if not ac or net["_options"]["init_results"]:
verify_results(net)
else:
init_results(net, "opf")
ppc, ppci = _pd2ppc(net)
if not ac:
ppci["bus"][:, VM] = 1.0
net["_ppc_opf"] = ppci
if len(net.dcline) > 0:
ppci = add_userfcn(ppci, 'formulation', _add_dcline_constraints, args=net)
if init == "pf":
ppci = _run_pf_before_opf(net, ppci)
if suppress_warnings:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
result = opf(ppci, ppopt)
else:
result = opf(ppci, ppopt)
# net["_ppc_opf"] = result
if verbose:
ppopt['OUT_ALL'] = 1
printpf(baseMVA=result["baseMVA"], bus=result["bus"], gen=result["gen"],
branch=result["branch"], f=result["f"], success=result["success"],
et=result["et"], fd=stdout, ppopt=ppopt)
if not result["success"]:
raise OPFNotConverged("Optimal Power Flow did not converge!")
# ppci doesn't contain out of service elements, but ppc does -> copy results accordingly
mode = net["_options"]["mode"]
result = _copy_results_ppci_to_ppc(result, ppc, mode=mode)
# net["_ppc_opf"] = result
net["OPF_converged"] = True
_extract_results(net, result)
_clean_up(net)
def _add_dcline_constraints(om, net):
# from numpy import hstack, diag, eye, zeros
ppc = om.get_ppc()
ndc = net.dcline.in_service.sum() # number of in-service DC lines
if ndc > 0:
ng = ppc['gen'].shape[0] # number of total gens
Adc = sparse((ndc, ng))
gen_lookup = net._pd2ppc_lookups["gen"]
dcline_gens_from = net.gen.index[-2 * ndc::2]
dcline_gens_to = net.gen.index[-2 * ndc + 1::2]
for i, (f, t, loss, active) in enumerate(zip(dcline_gens_from, dcline_gens_to,
net.dcline.loss_percent.values,
net.dcline.in_service.values)):
if active:
Adc[i, gen_lookup[f]] = 1. + loss / 100
Adc[i, gen_lookup[t]] = 1.
# constraints
nL0 = -net.dcline.loss_mw.values # absolute losses
# L1 = -net.dcline.loss_percent.values * 1e-2 #relative losses
# Adc = sparse(hstack([zeros((ndc, ng)), diag(1-L1), eye(ndc)]))
# add them to the model
om = om.add_constraints('dcline', Adc, nL0, nL0, ['Pg'])
def _run_pf_before_opf(net, ppci):
# net._options["numba"] = True
net._options["tolerance_mva"] = 1e-8
net._options["max_iteration"] = 10
net._options["algorithm"] = "nr"
return _run_newton_raphson_pf(ppci, net["_options"])