ltbams 1.0.8__py3-none-any.whl → 1.0.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ams/__init__.py +0 -1
- ams/_version.py +3 -3
- ams/cases/5bus/pjm5bus_demo.json +1324 -0
- ams/core/__init__.py +1 -0
- ams/core/common.py +30 -0
- ams/core/model.py +1 -1
- ams/core/symprocessor.py +1 -1
- ams/extension/eva.py +1 -1
- ams/interface.py +40 -24
- ams/io/matpower.py +192 -26
- ams/io/psse.py +278 -1
- ams/io/pypower.py +14 -0
- ams/main.py +2 -2
- ams/models/group.py +2 -70
- ams/models/static/pq.py +7 -3
- ams/opt/param.py +1 -2
- ams/report.py +3 -4
- ams/routines/__init__.py +2 -3
- ams/routines/acopf.py +5 -108
- ams/routines/dcopf.py +8 -0
- ams/routines/dcpf.py +1 -1
- ams/routines/ed.py +4 -2
- ams/routines/grbopt.py +150 -0
- ams/routines/pflow.py +2 -2
- ams/routines/pypower.py +631 -0
- ams/routines/routine.py +4 -10
- ams/routines/uc.py +2 -2
- ams/shared.py +30 -44
- ams/system.py +118 -2
- docs/source/api.rst +2 -0
- docs/source/getting_started/formats/matpower.rst +135 -0
- docs/source/getting_started/formats/pypower.rst +1 -2
- docs/source/getting_started/install.rst +9 -6
- docs/source/images/dcopf_time.png +0 -0
- docs/source/images/educ_pie.png +0 -0
- docs/source/release-notes.rst +29 -47
- {ltbams-1.0.8.dist-info → ltbams-1.0.10.dist-info}/METADATA +87 -47
- {ltbams-1.0.8.dist-info → ltbams-1.0.10.dist-info}/RECORD +58 -75
- {ltbams-1.0.8.dist-info → ltbams-1.0.10.dist-info}/WHEEL +1 -1
- tests/test_1st_system.py +1 -1
- tests/test_case.py +14 -14
- tests/test_export_csv.py +1 -1
- tests/test_interface.py +24 -2
- tests/test_io.py +125 -1
- tests/test_omodel.py +1 -1
- tests/test_report.py +6 -6
- tests/test_routine.py +2 -2
- tests/test_rtn_acopf.py +75 -0
- tests/test_rtn_dcopf.py +1 -1
- tests/test_rtn_dcopf2.py +1 -1
- tests/test_rtn_ed.py +9 -9
- tests/test_rtn_opf.py +142 -0
- tests/test_rtn_pflow.py +0 -72
- tests/test_rtn_pypower.py +315 -0
- tests/test_rtn_rted.py +8 -8
- tests/test_rtn_uc.py +18 -18
- ams/pypower/__init__.py +0 -8
- ams/pypower/_compat.py +0 -9
- ams/pypower/core/__init__.py +0 -8
- ams/pypower/core/pips.py +0 -894
- ams/pypower/core/ppoption.py +0 -244
- ams/pypower/core/ppver.py +0 -18
- ams/pypower/core/solver.py +0 -2451
- ams/pypower/eps.py +0 -6
- ams/pypower/idx.py +0 -174
- ams/pypower/io.py +0 -604
- ams/pypower/make/__init__.py +0 -11
- ams/pypower/make/matrices.py +0 -665
- ams/pypower/make/pdv.py +0 -506
- ams/pypower/routines/__init__.py +0 -7
- ams/pypower/routines/cpf.py +0 -513
- ams/pypower/routines/cpf_callbacks.py +0 -114
- ams/pypower/routines/opf.py +0 -1803
- ams/pypower/routines/opffcns.py +0 -1946
- ams/pypower/routines/pflow.py +0 -852
- ams/pypower/toggle.py +0 -1098
- ams/pypower/utils.py +0 -293
- ams/routines/cpf.py +0 -65
- ams/routines/dcpf0.py +0 -196
- ams/routines/pflow0.py +0 -113
- tests/test_rtn_dcpf.py +0 -77
- {ltbams-1.0.8.dist-info → ltbams-1.0.10.dist-info}/entry_points.txt +0 -0
- {ltbams-1.0.8.dist-info → ltbams-1.0.10.dist-info}/top_level.txt +0 -0
tests/test_io.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
"""
|
2
2
|
Test file input/output.
|
3
3
|
"""
|
4
|
-
|
4
|
+
import os
|
5
5
|
import unittest
|
6
6
|
import numpy as np
|
7
7
|
|
@@ -9,6 +9,9 @@ import ams
|
|
9
9
|
|
10
10
|
|
11
11
|
class TestMATPOWER(unittest.TestCase):
|
12
|
+
"""
|
13
|
+
Test IO functions for MATPOWER and PYPOWER.
|
14
|
+
"""
|
12
15
|
|
13
16
|
def setUp(self):
|
14
17
|
self.mpc5 = ams.io.matpower.m2mpc(ams.get_case('matpower/case5.m'))
|
@@ -34,6 +37,12 @@ class TestMATPOWER(unittest.TestCase):
|
|
34
37
|
np.testing.assert_array_equal(system5.GCost.c2.v,
|
35
38
|
np.zeros(system5.StaticGen.n))
|
36
39
|
|
40
|
+
# Check if Area is added
|
41
|
+
self.assertGreater(system5.Area.n, 0)
|
42
|
+
|
43
|
+
# Check if Zone is added
|
44
|
+
self.assertGreater(system5.Zone.n, 0)
|
45
|
+
|
37
46
|
system14 = ams.system.System()
|
38
47
|
# Test gentype length check
|
39
48
|
mpc14 = self.mpc14.copy()
|
@@ -41,11 +50,41 @@ class TestMATPOWER(unittest.TestCase):
|
|
41
50
|
with self.assertRaises(ValueError, msg='gentype length check failed!'):
|
42
51
|
ams.io.matpower.mpc2system(mpc14, system14)
|
43
52
|
|
53
|
+
system14 = ams.system.System()
|
44
54
|
ams.io.matpower.mpc2system(self.mpc14, system14)
|
45
55
|
# In case14.m, the gencost has type 2 cost model, with 3 parameters.
|
46
56
|
np.testing.assert_array_less(np.zeros(system14.StaticGen.n),
|
47
57
|
system14.GCost.c2.v,)
|
48
58
|
|
59
|
+
def test_system2mpc(self):
|
60
|
+
"""Test conversion from AMS System to MPC."""
|
61
|
+
system5 = ams.system.System()
|
62
|
+
ams.io.matpower.mpc2system(self.mpc5, system5)
|
63
|
+
mpc5 = ams.io.matpower.system2mpc(system5)
|
64
|
+
|
65
|
+
self.assertEqual(mpc5['baseMVA'], self.mpc5['baseMVA'])
|
66
|
+
|
67
|
+
# Bus
|
68
|
+
# type, PD, QD, GS,BS, VM, VA. BASE_KV, VMAX, VMIN
|
69
|
+
bus_cols = [1, 2, 3, 4, 5, 7, 8, 9, 11, 12]
|
70
|
+
np.testing.assert_array_equal(mpc5['bus'][:, bus_cols],
|
71
|
+
self.mpc5['bus'][:, bus_cols])
|
72
|
+
|
73
|
+
# Branch, Gen, Gencost, can have minor differences but is okay
|
74
|
+
|
75
|
+
# String type data
|
76
|
+
np.testing.assert_array_equal(mpc5['gentype'], self.mpc5['gentype'])
|
77
|
+
np.testing.assert_array_equal(mpc5['genfuel'], self.mpc5['genfuel'])
|
78
|
+
np.testing.assert_array_equal(mpc5['bus_name'], self.mpc5['bus_name'])
|
79
|
+
|
80
|
+
# Area quantity
|
81
|
+
self.assertEqual(np.unique(mpc5['bus'][:, 6]).shape[0],
|
82
|
+
np.unique(self.mpc5['bus'][:, 6]).shape[0])
|
83
|
+
|
84
|
+
# Zone quantity
|
85
|
+
self.assertEqual(np.unique(mpc5['bus'][:, 10]).shape[0],
|
86
|
+
np.unique(self.mpc5['bus'][:, 10]).shape[0])
|
87
|
+
|
49
88
|
def test_gencost1(self):
|
50
89
|
"""Test when gencost is type 1."""
|
51
90
|
mpcgc1 = self.mpc14.copy()
|
@@ -54,3 +93,88 @@ class TestMATPOWER(unittest.TestCase):
|
|
54
93
|
system = ams.system.System()
|
55
94
|
ams.io.matpower.mpc2system(mpcgc1, system)
|
56
95
|
self.assertEqual(system.GCost.n, 5)
|
96
|
+
|
97
|
+
def test_mpc2m(self):
|
98
|
+
"""Test conversion from MPC to M file."""
|
99
|
+
mpc5 = ams.io.matpower.m2mpc(ams.get_case('matpower/case5.m'))
|
100
|
+
mpc14 = ams.io.matpower.m2mpc(ams.get_case('matpower/case14.m'))
|
101
|
+
|
102
|
+
# Test conversion to M file
|
103
|
+
mfile5 = ams.io.matpower.mpc2m(mpc5, './case5out.m')
|
104
|
+
mfile14 = ams.io.matpower.mpc2m(mpc14, './case14out.m')
|
105
|
+
|
106
|
+
# Check if the files exist
|
107
|
+
self.assertTrue(os.path.exists(mfile5))
|
108
|
+
self.assertTrue(os.path.exists(mfile14))
|
109
|
+
|
110
|
+
mpc5read = ams.io.matpower.m2mpc(mfile5)
|
111
|
+
mpc14read = ams.io.matpower.m2mpc(mfile14)
|
112
|
+
|
113
|
+
# Check if the numerical values are the same
|
114
|
+
for key in mpc5:
|
115
|
+
if key in ['bus_name', 'gentype', 'genfuel']:
|
116
|
+
continue
|
117
|
+
np.testing.assert_array_almost_equal(
|
118
|
+
mpc5[key], mpc5read[key], decimal=5,
|
119
|
+
err_msg=f"Mismatch in {key} when converting case5.m"
|
120
|
+
)
|
121
|
+
for key in mpc14:
|
122
|
+
if key in ['bus_name', 'gentype', 'genfuel']:
|
123
|
+
continue
|
124
|
+
np.testing.assert_array_almost_equal(
|
125
|
+
mpc14[key], mpc14read[key], decimal=5,
|
126
|
+
err_msg=f"Mismatch in {key} when converting case14.m"
|
127
|
+
)
|
128
|
+
|
129
|
+
# Clean up the generated files
|
130
|
+
os.remove(mfile5)
|
131
|
+
os.remove(mfile14)
|
132
|
+
|
133
|
+
def test_system2m(self):
|
134
|
+
"""Test conversion from AMS System to M file."""
|
135
|
+
s5 = ams.load(ams.get_case('matpower/case5.m'),
|
136
|
+
no_output=True)
|
137
|
+
mfile5 = './case5out.m'
|
138
|
+
ams.io.matpower.write(s5, mfile5)
|
139
|
+
|
140
|
+
# Clean up the generated file
|
141
|
+
os.remove(mfile5)
|
142
|
+
|
143
|
+
|
144
|
+
class TestSystemExport(unittest.TestCase):
|
145
|
+
"""
|
146
|
+
Test system export functions.
|
147
|
+
"""
|
148
|
+
|
149
|
+
def test_system_to(self):
|
150
|
+
"""Test conversion from AMS System to several formats."""
|
151
|
+
ss = ams.load(ams.get_case('matpower/case5.m'),
|
152
|
+
no_output=True)
|
153
|
+
|
154
|
+
mpc = ss.to_mpc()
|
155
|
+
|
156
|
+
self.assertIsInstance(mpc, dict)
|
157
|
+
self.assertIn('bus', mpc)
|
158
|
+
self.assertIn('branch', mpc)
|
159
|
+
self.assertIn('gen', mpc)
|
160
|
+
self.assertIn('gencost', mpc)
|
161
|
+
self.assertIn('baseMVA', mpc)
|
162
|
+
self.assertIn('bus_name', mpc)
|
163
|
+
self.assertIn('gentype', mpc)
|
164
|
+
self.assertIn('genfuel', mpc)
|
165
|
+
|
166
|
+
ss.to_m("./case5_out.m")
|
167
|
+
self.assertTrue(os.path.exists("./case5_out.m"))
|
168
|
+
os.remove("./case5_out.m")
|
169
|
+
|
170
|
+
ss.to_json("./case5_out.json")
|
171
|
+
self.assertTrue(os.path.exists("./case5_out.json"))
|
172
|
+
os.remove("./case5_out.json")
|
173
|
+
|
174
|
+
ss.to_xlsx("./case5_out.xlsx")
|
175
|
+
self.assertTrue(os.path.exists("./case5_out.xlsx"))
|
176
|
+
os.remove("./case5_out.xlsx")
|
177
|
+
|
178
|
+
ss.to_raw("./case5_out.raw", overwrite=True)
|
179
|
+
self.assertTrue(os.path.exists("./case5_out.raw"))
|
180
|
+
os.remove("./case5_out.raw")
|
tests/test_omodel.py
CHANGED
@@ -70,7 +70,7 @@ class TestOModelrepr(unittest.TestCase):
|
|
70
70
|
"""
|
71
71
|
|
72
72
|
def setUp(self) -> None:
|
73
|
-
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.
|
73
|
+
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.json"),
|
74
74
|
setup=True,
|
75
75
|
default_config=True,
|
76
76
|
no_output=True,
|
tests/test_report.py
CHANGED
@@ -20,7 +20,7 @@ class TestReport(unittest.TestCase):
|
|
20
20
|
|
21
21
|
def setUp(self) -> None:
|
22
22
|
self.ss = ams.main.load(
|
23
|
-
ams.get_case("5bus/pjm5bus_demo.
|
23
|
+
ams.get_case("5bus/pjm5bus_demo.json"),
|
24
24
|
default_config=True,
|
25
25
|
no_output=True,
|
26
26
|
)
|
@@ -125,7 +125,7 @@ class TestReport(unittest.TestCase):
|
|
125
125
|
Test report with RTEDES solved.
|
126
126
|
"""
|
127
127
|
self.ss.files.no_output = False
|
128
|
-
self.ss.RTEDES.run()
|
128
|
+
self.ss.RTEDES.run(solver='SCIP')
|
129
129
|
self.assertTrue(self.ss.report())
|
130
130
|
self.assertTrue(os.path.exists(self.expected_report))
|
131
131
|
|
@@ -180,7 +180,7 @@ class TestReport(unittest.TestCase):
|
|
180
180
|
Test report with EDES solved.
|
181
181
|
"""
|
182
182
|
self.ss.files.no_output = False
|
183
|
-
self.ss.EDES.run()
|
183
|
+
self.ss.EDES.run(solver='SCIP')
|
184
184
|
self.assertTrue(self.ss.report())
|
185
185
|
self.assertTrue(os.path.exists(self.expected_report))
|
186
186
|
|
@@ -199,7 +199,7 @@ class TestReport(unittest.TestCase):
|
|
199
199
|
Test report with UC solved.
|
200
200
|
"""
|
201
201
|
self.ss.files.no_output = False
|
202
|
-
self.ss.UC.run()
|
202
|
+
self.ss.UC.run(solver='SCIP')
|
203
203
|
self.assertTrue(self.ss.report())
|
204
204
|
self.assertTrue(os.path.exists(self.expected_report))
|
205
205
|
|
@@ -218,7 +218,7 @@ class TestReport(unittest.TestCase):
|
|
218
218
|
Test report with UCDG solved.
|
219
219
|
"""
|
220
220
|
self.ss.files.no_output = False
|
221
|
-
self.ss.UCDG.run()
|
221
|
+
self.ss.UCDG.run(solver='SCIP')
|
222
222
|
self.assertTrue(self.ss.report())
|
223
223
|
self.assertTrue(os.path.exists(self.expected_report))
|
224
224
|
|
@@ -237,7 +237,7 @@ class TestReport(unittest.TestCase):
|
|
237
237
|
Test report with UCES solved.
|
238
238
|
"""
|
239
239
|
self.ss.files.no_output = False
|
240
|
-
self.ss.UCES.run()
|
240
|
+
self.ss.UCES.run(solver='SCIP')
|
241
241
|
self.assertTrue(self.ss.report())
|
242
242
|
self.assertTrue(os.path.exists(self.expected_report))
|
243
243
|
|
tests/test_routine.py
CHANGED
@@ -104,7 +104,7 @@ class TestSetOptzValueACOPF(unittest.TestCase):
|
|
104
104
|
"""
|
105
105
|
|
106
106
|
def setUp(self) -> None:
|
107
|
-
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.
|
107
|
+
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.json"),
|
108
108
|
setup=True,
|
109
109
|
default_config=True,
|
110
110
|
no_output=True,
|
@@ -144,7 +144,7 @@ class TestSetOptzValueDCOPF(unittest.TestCase):
|
|
144
144
|
"""
|
145
145
|
|
146
146
|
def setUp(self) -> None:
|
147
|
-
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.
|
147
|
+
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.json"),
|
148
148
|
setup=True,
|
149
149
|
default_config=True,
|
150
150
|
no_output=True,
|
tests/test_rtn_acopf.py
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
import unittest
|
2
|
+
|
3
|
+
import ams
|
4
|
+
|
5
|
+
|
6
|
+
class TestACOPF(unittest.TestCase):
|
7
|
+
"""
|
8
|
+
Test routine `ACOPF`.
|
9
|
+
"""
|
10
|
+
|
11
|
+
def setUp(self) -> None:
|
12
|
+
self.ss = ams.load(ams.get_case('matpower/case14.m'),
|
13
|
+
setup=True, no_output=True, default_config=True)
|
14
|
+
|
15
|
+
def test_init(self):
|
16
|
+
"""
|
17
|
+
Test initialization.
|
18
|
+
"""
|
19
|
+
self.ss.ACOPF.init()
|
20
|
+
self.assertTrue(self.ss.ACOPF.initialized, "ACOPF initialization failed!")
|
21
|
+
|
22
|
+
def test_trip_gen(self):
|
23
|
+
"""
|
24
|
+
Test generator tripping.
|
25
|
+
"""
|
26
|
+
stg = 2
|
27
|
+
self.ss.StaticGen.set(src='u', idx=stg, attr='v', value=0)
|
28
|
+
|
29
|
+
self.ss.ACOPF.update()
|
30
|
+
self.ss.ACOPF.run()
|
31
|
+
self.assertTrue(self.ss.ACOPF.converged, "ACOPF did not converge under generator trip!")
|
32
|
+
self.assertAlmostEqual(self.ss.ACOPF.get(src='pg', attr='v', idx=stg),
|
33
|
+
0, places=6,
|
34
|
+
msg="Generator trip does not take effect!")
|
35
|
+
|
36
|
+
self.ss.StaticGen.set(src='u', idx=stg, attr='v', value=1)
|
37
|
+
|
38
|
+
def test_trip_line(self):
|
39
|
+
"""
|
40
|
+
Test line tripping.
|
41
|
+
"""
|
42
|
+
self.ss.Line.set(src='u', attr='v', idx='Line_3', value=0)
|
43
|
+
|
44
|
+
self.ss.ACOPF.update()
|
45
|
+
self.ss.ACOPF.run()
|
46
|
+
self.assertTrue(self.ss.ACOPF.converged, "ACOPF did not converge under line trip!")
|
47
|
+
self.assertAlmostEqual(self.ss.ACOPF.get(src='plf', attr='v', idx='Line_3'),
|
48
|
+
0, places=6,
|
49
|
+
msg="Line trip does not take effect!")
|
50
|
+
|
51
|
+
self.ss.Line.alter(src='u', idx='Line_3', value=1)
|
52
|
+
|
53
|
+
def test_set_load(self):
|
54
|
+
"""
|
55
|
+
Test setting and tripping load.
|
56
|
+
"""
|
57
|
+
# --- run ACOPF ---
|
58
|
+
self.ss.ACOPF.run()
|
59
|
+
pgs = self.ss.ACOPF.pg.v.sum()
|
60
|
+
|
61
|
+
# --- set load ---
|
62
|
+
self.ss.PQ.set(src='p0', attr='v', idx='PQ_1', value=0.1)
|
63
|
+
self.ss.ACOPF.update()
|
64
|
+
|
65
|
+
self.ss.ACOPF.run()
|
66
|
+
pgs_pqt = self.ss.ACOPF.pg.v.sum()
|
67
|
+
self.assertLess(pgs_pqt, pgs, "Load set does not take effect!")
|
68
|
+
|
69
|
+
# --- trip load ---
|
70
|
+
self.ss.PQ.set(src='p0', attr='v', idx='PQ_1', value=0)
|
71
|
+
self.ss.ACOPF.update()
|
72
|
+
|
73
|
+
self.ss.ACOPF.run()
|
74
|
+
pgs_pqt2 = self.ss.ACOPF.pg.v.sum()
|
75
|
+
self.assertLess(pgs_pqt2, pgs_pqt, "Load trip does not take effect!")
|
tests/test_rtn_dcopf.py
CHANGED
@@ -10,7 +10,7 @@ class TestDCOPF(unittest.TestCase):
|
|
10
10
|
"""
|
11
11
|
|
12
12
|
def setUp(self) -> None:
|
13
|
-
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.
|
13
|
+
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.json"),
|
14
14
|
setup=True, default_config=True, no_output=True)
|
15
15
|
# decrease load first
|
16
16
|
self.ss.PQ.set(src='p0', attr='v', idx=['PQ_1', 'PQ_2'], value=[0.3, 0.3])
|
tests/test_rtn_dcopf2.py
CHANGED
@@ -10,7 +10,7 @@ class TestDCOPF2(unittest.TestCase):
|
|
10
10
|
"""
|
11
11
|
|
12
12
|
def setUp(self) -> None:
|
13
|
-
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.
|
13
|
+
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.json"),
|
14
14
|
setup=True, default_config=True, no_output=True)
|
15
15
|
# decrease load first
|
16
16
|
self.ss.PQ.set(src='p0', attr='v', idx=['PQ_1', 'PQ_2'], value=[0.3, 0.3])
|
tests/test_rtn_ed.py
CHANGED
@@ -11,7 +11,7 @@ class TestED(unittest.TestCase):
|
|
11
11
|
"""
|
12
12
|
|
13
13
|
def setUp(self) -> None:
|
14
|
-
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.
|
14
|
+
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.json"),
|
15
15
|
setup=True, default_config=True, no_output=True)
|
16
16
|
# decrease load first
|
17
17
|
self.ss.PQ.set(src='p0', attr='v', idx=['PQ_1', 'PQ_2'], value=[0.3, 0.3])
|
@@ -102,7 +102,7 @@ class TestEDDG(unittest.TestCase):
|
|
102
102
|
"""
|
103
103
|
|
104
104
|
def setUp(self) -> None:
|
105
|
-
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.
|
105
|
+
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.json"),
|
106
106
|
setup=True, default_config=True, no_output=True)
|
107
107
|
# decrease load first
|
108
108
|
self.ss.PQ.set(src='p0', attr='v', idx=['PQ_1', 'PQ_2'], value=[0.3, 0.3])
|
@@ -193,7 +193,7 @@ class TestEDES(unittest.TestCase):
|
|
193
193
|
"""
|
194
194
|
|
195
195
|
def setUp(self) -> None:
|
196
|
-
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.
|
196
|
+
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.json"),
|
197
197
|
setup=True, default_config=True, no_output=True)
|
198
198
|
# decrease load first
|
199
199
|
self.ss.PQ.set(src='p0', attr='v', idx=['PQ_1', 'PQ_2'], value=[0.3, 0.3])
|
@@ -217,7 +217,7 @@ class TestEDES(unittest.TestCase):
|
|
217
217
|
loc_offtime = np.array([0, 2])
|
218
218
|
self.ss.EDTSlot.ug.v[loc_offtime, stg_uid] = 0
|
219
219
|
|
220
|
-
self.ss.EDES.run()
|
220
|
+
self.ss.EDES.run(solver='SCIP')
|
221
221
|
self.assertTrue(self.ss.EDES.converged, "ED did not converge under generator trip!")
|
222
222
|
pg_pv1 = self.ss.EDES.get(src='pg', attr='v', idx=stg)
|
223
223
|
np.testing.assert_almost_equal(np.zeros_like(loc_offtime),
|
@@ -232,7 +232,7 @@ class TestEDES(unittest.TestCase):
|
|
232
232
|
self.ss.StaticGen.set(src='u', idx=stg, attr='v', value=0)
|
233
233
|
self.ss.EDES.update()
|
234
234
|
|
235
|
-
self.ss.EDES.run()
|
235
|
+
self.ss.EDES.run(solver='SCIP')
|
236
236
|
self.assertTrue(self.ss.EDES.converged, "ED did not converge under generator trip!")
|
237
237
|
pg_pv1 = self.ss.EDES.get(src='pg', attr='v', idx=stg)
|
238
238
|
np.testing.assert_array_less(np.zeros_like(pg_pv1), pg_pv1,
|
@@ -246,7 +246,7 @@ class TestEDES(unittest.TestCase):
|
|
246
246
|
Test line tripping.
|
247
247
|
"""
|
248
248
|
self.ss.Line.set(src='u', attr='v', idx='Line_3', value=0)
|
249
|
-
self.ss.EDES.run()
|
249
|
+
self.ss.EDES.run(solver='SCIP')
|
250
250
|
self.assertTrue(self.ss.EDES.converged, "EDES did not converge!")
|
251
251
|
plf_l3 = self.ss.EDES.get(src='plf', attr='v', idx='Line_3')
|
252
252
|
np.testing.assert_almost_equal(np.zeros_like(plf_l3),
|
@@ -259,14 +259,14 @@ class TestEDES(unittest.TestCase):
|
|
259
259
|
"""
|
260
260
|
Test setting and tripping load.
|
261
261
|
"""
|
262
|
-
self.ss.EDES.run()
|
262
|
+
self.ss.EDES.run(solver='SCIP')
|
263
263
|
pgs = self.ss.EDES.pg.v.sum()
|
264
264
|
|
265
265
|
# --- set load ---
|
266
266
|
self.ss.PQ.set(src='p0', attr='v', idx='PQ_1', value=0.1)
|
267
267
|
self.ss.EDES.update()
|
268
268
|
|
269
|
-
self.ss.EDES.run()
|
269
|
+
self.ss.EDES.run(solver='SCIP')
|
270
270
|
pgs_pqt = self.ss.EDES.pg.v.sum()
|
271
271
|
self.assertLess(pgs_pqt, pgs, "Load set does not take effect!")
|
272
272
|
|
@@ -274,6 +274,6 @@ class TestEDES(unittest.TestCase):
|
|
274
274
|
self.ss.PQ.alter(src='u', idx='PQ_2', value=0)
|
275
275
|
self.ss.EDES.update()
|
276
276
|
|
277
|
-
self.ss.EDES.run()
|
277
|
+
self.ss.EDES.run(solver='SCIP')
|
278
278
|
pgs_pqt2 = self.ss.EDES.pg.v.sum()
|
279
279
|
self.assertLess(pgs_pqt2, pgs_pqt, "Load trip does not take effect!")
|
tests/test_rtn_opf.py
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
"""
|
2
|
+
Test wrapper routines of gurobi_optimodes.
|
3
|
+
"""
|
4
|
+
import unittest
|
5
|
+
|
6
|
+
import ams
|
7
|
+
from ams.shared import skip_unittest_without_gurobi_optimods
|
8
|
+
|
9
|
+
|
10
|
+
class TestOPF(unittest.TestCase):
|
11
|
+
"""
|
12
|
+
Test routine `OPF` in DC.
|
13
|
+
"""
|
14
|
+
|
15
|
+
def setUp(self) -> None:
|
16
|
+
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.json"),
|
17
|
+
setup=True, default_config=True, no_output=True)
|
18
|
+
# decrease load first
|
19
|
+
self.ss.PQ.set(src='p0', attr='v', idx=['PQ_1', 'PQ_2'], value=[0.3, 0.3])
|
20
|
+
|
21
|
+
def test_init(self):
|
22
|
+
"""
|
23
|
+
Test initialization.
|
24
|
+
"""
|
25
|
+
self.ss.OPF.init()
|
26
|
+
self.assertTrue(self.ss.OPF.initialized, "OPF initialization failed!")
|
27
|
+
|
28
|
+
@skip_unittest_without_gurobi_optimods
|
29
|
+
def test_trip_gen(self):
|
30
|
+
"""
|
31
|
+
Test generator tripping.
|
32
|
+
"""
|
33
|
+
stg = 'PV_1'
|
34
|
+
self.ss.StaticGen.set(src='u', idx=stg, attr='v', value=0)
|
35
|
+
|
36
|
+
self.ss.OPF.update()
|
37
|
+
self.ss.OPF.run(opftype='DC')
|
38
|
+
self.assertTrue(self.ss.OPF.converged, "OPF in DC did not converge under generator trip!")
|
39
|
+
self.assertAlmostEqual(self.ss.OPF.get(src='pg', attr='v', idx=stg),
|
40
|
+
0, places=6,
|
41
|
+
msg="Generator trip does not take effect!")
|
42
|
+
|
43
|
+
self.ss.StaticGen.set(src='u', idx=stg, attr='v', value=1) # reset
|
44
|
+
|
45
|
+
@skip_unittest_without_gurobi_optimods
|
46
|
+
def test_trip_gen_ac(self):
|
47
|
+
"""
|
48
|
+
Test generator tripping.
|
49
|
+
"""
|
50
|
+
stg = 'PV_1'
|
51
|
+
self.ss.StaticGen.set(src='u', idx=stg, attr='v', value=0)
|
52
|
+
|
53
|
+
self.ss.OPF.update()
|
54
|
+
self.ss.OPF.run(opftype='AC')
|
55
|
+
self.assertTrue(self.ss.OPF.converged, "OPF in AC did not converge under generator trip!")
|
56
|
+
self.assertAlmostEqual(self.ss.OPF.get(src='pg', attr='v', idx=stg),
|
57
|
+
0, places=6,
|
58
|
+
msg="Generator trip does not take effect!")
|
59
|
+
|
60
|
+
self.ss.StaticGen.set(src='u', idx=stg, attr='v', value=1) # reset
|
61
|
+
|
62
|
+
@skip_unittest_without_gurobi_optimods
|
63
|
+
def test_trip_line(self):
|
64
|
+
"""
|
65
|
+
Test line tripping.
|
66
|
+
"""
|
67
|
+
self.ss.Line.set(src='u', attr='v', idx='Line_3', value=0)
|
68
|
+
|
69
|
+
self.ss.OPF.update()
|
70
|
+
self.ss.OPF.run(opftype='DC')
|
71
|
+
self.assertTrue(self.ss.OPF.converged, "OPF in DC did not converge under line trip!")
|
72
|
+
self.assertAlmostEqual(self.ss.OPF.get(src='plf', attr='v', idx='Line_3'),
|
73
|
+
0, places=6,
|
74
|
+
msg="Line trip does not take effect!")
|
75
|
+
|
76
|
+
self.ss.Line.alter(src='u', idx='Line_3', value=1) # reset
|
77
|
+
|
78
|
+
@skip_unittest_without_gurobi_optimods
|
79
|
+
def test_trip_line_ac(self):
|
80
|
+
"""
|
81
|
+
Test line tripping.
|
82
|
+
"""
|
83
|
+
self.ss.Line.set(src='u', attr='v', idx='Line_3', value=0)
|
84
|
+
|
85
|
+
self.ss.OPF.update()
|
86
|
+
self.ss.OPF.run(opftype='AC')
|
87
|
+
self.assertTrue(self.ss.OPF.converged, "OPF in AC did not converge under line trip!")
|
88
|
+
self.assertAlmostEqual(self.ss.OPF.get(src='plf', attr='v', idx='Line_3'),
|
89
|
+
0, places=6,
|
90
|
+
msg="Line trip does not take effect!")
|
91
|
+
|
92
|
+
self.ss.Line.alter(src='u', idx='Line_3', value=1) # reset
|
93
|
+
|
94
|
+
@skip_unittest_without_gurobi_optimods
|
95
|
+
def test_set_load(self):
|
96
|
+
"""
|
97
|
+
Test setting and tripping load.
|
98
|
+
"""
|
99
|
+
# --- run OPF ---
|
100
|
+
self.ss.OPF.run(opftype='DC')
|
101
|
+
pgs = self.ss.OPF.pg.v.sum()
|
102
|
+
|
103
|
+
# --- set load ---
|
104
|
+
self.ss.PQ.set(src='p0', attr='v', idx='PQ_1', value=0.1)
|
105
|
+
self.ss.OPF.update()
|
106
|
+
|
107
|
+
self.ss.OPF.run(opftype='DC')
|
108
|
+
pgs_pqt = self.ss.OPF.pg.v.sum()
|
109
|
+
self.assertLess(pgs_pqt, pgs, "Load set does not take effect!")
|
110
|
+
|
111
|
+
# --- trip load ---
|
112
|
+
self.ss.PQ.set(src='u', attr='v', idx='PQ_2', value=0)
|
113
|
+
self.ss.OPF.update()
|
114
|
+
|
115
|
+
self.ss.OPF.run(opftype='DC')
|
116
|
+
pgs_pqt2 = self.ss.OPF.pg.v.sum()
|
117
|
+
self.assertLess(pgs_pqt2, pgs_pqt, "Load trip does not take effect!")
|
118
|
+
|
119
|
+
@skip_unittest_without_gurobi_optimods
|
120
|
+
def test_set_load_ac(self):
|
121
|
+
"""
|
122
|
+
Test setting and tripping load.
|
123
|
+
"""
|
124
|
+
# --- run OPF ---
|
125
|
+
self.ss.OPF.run(opftype='AC')
|
126
|
+
pgs = self.ss.OPF.pg.v.sum()
|
127
|
+
|
128
|
+
# --- set load ---
|
129
|
+
self.ss.PQ.set(src='p0', attr='v', idx='PQ_1', value=0.1)
|
130
|
+
self.ss.OPF.update()
|
131
|
+
|
132
|
+
self.ss.OPF.run(opftype='AC')
|
133
|
+
pgs_pqt = self.ss.OPF.pg.v.sum()
|
134
|
+
self.assertLess(pgs_pqt, pgs, "Load set does not take effect!")
|
135
|
+
|
136
|
+
# --- trip load ---
|
137
|
+
self.ss.PQ.set(src='u', attr='v', idx='PQ_2', value=0)
|
138
|
+
self.ss.OPF.update()
|
139
|
+
|
140
|
+
self.ss.OPF.run(opftype='AC')
|
141
|
+
pgs_pqt2 = self.ss.OPF.pg.v.sum()
|
142
|
+
self.assertLess(pgs_pqt2, pgs_pqt, "Load trip does not take effect!")
|
tests/test_rtn_pflow.py
CHANGED
@@ -145,75 +145,3 @@ class TestPFlow(unittest.TestCase):
|
|
145
145
|
self.ss.PFlow.run()
|
146
146
|
pgs_pqt2 = self.ss.PFlow.pg.v.sum()
|
147
147
|
self.assertLess(pgs_pqt2, pgs_pqt, "Load trip does not take effect!")
|
148
|
-
|
149
|
-
|
150
|
-
class TestACOPF(unittest.TestCase):
|
151
|
-
"""
|
152
|
-
Test routine `ACOPF`.
|
153
|
-
"""
|
154
|
-
|
155
|
-
def setUp(self) -> None:
|
156
|
-
self.ss = ams.load(ams.get_case('matpower/case14.m'),
|
157
|
-
setup=True, no_output=True, default_config=True)
|
158
|
-
|
159
|
-
def test_init(self):
|
160
|
-
"""
|
161
|
-
Test initialization.
|
162
|
-
"""
|
163
|
-
self.ss.ACOPF.init()
|
164
|
-
self.assertTrue(self.ss.ACOPF.initialized, "ACOPF initialization failed!")
|
165
|
-
|
166
|
-
def test_trip_gen(self):
|
167
|
-
"""
|
168
|
-
Test generator tripping.
|
169
|
-
"""
|
170
|
-
stg = 2
|
171
|
-
self.ss.StaticGen.set(src='u', idx=stg, attr='v', value=0)
|
172
|
-
|
173
|
-
self.ss.ACOPF.update()
|
174
|
-
self.ss.ACOPF.run()
|
175
|
-
self.assertTrue(self.ss.ACOPF.converged, "ACOPF did not converge under generator trip!")
|
176
|
-
self.assertAlmostEqual(self.ss.ACOPF.get(src='pg', attr='v', idx=stg),
|
177
|
-
0, places=6,
|
178
|
-
msg="Generator trip does not take effect!")
|
179
|
-
|
180
|
-
self.ss.StaticGen.set(src='u', idx=stg, attr='v', value=1)
|
181
|
-
|
182
|
-
def test_trip_line(self):
|
183
|
-
"""
|
184
|
-
Test line tripping.
|
185
|
-
"""
|
186
|
-
self.ss.Line.set(src='u', attr='v', idx='Line_3', value=0)
|
187
|
-
|
188
|
-
self.ss.ACOPF.update()
|
189
|
-
self.ss.ACOPF.run()
|
190
|
-
self.assertTrue(self.ss.ACOPF.converged, "ACOPF did not converge under line trip!")
|
191
|
-
self.assertAlmostEqual(self.ss.ACOPF.get(src='plf', attr='v', idx='Line_3'),
|
192
|
-
0, places=6,
|
193
|
-
msg="Line trip does not take effect!")
|
194
|
-
|
195
|
-
self.ss.Line.alter(src='u', idx='Line_3', value=1)
|
196
|
-
|
197
|
-
def test_set_load(self):
|
198
|
-
"""
|
199
|
-
Test setting and tripping load.
|
200
|
-
"""
|
201
|
-
# --- run ACOPF ---
|
202
|
-
self.ss.ACOPF.run()
|
203
|
-
pgs = self.ss.ACOPF.pg.v.sum()
|
204
|
-
|
205
|
-
# --- set load ---
|
206
|
-
self.ss.PQ.set(src='p0', attr='v', idx='PQ_1', value=0.1)
|
207
|
-
self.ss.ACOPF.update()
|
208
|
-
|
209
|
-
self.ss.ACOPF.run()
|
210
|
-
pgs_pqt = self.ss.ACOPF.pg.v.sum()
|
211
|
-
self.assertLess(pgs_pqt, pgs, "Load set does not take effect!")
|
212
|
-
|
213
|
-
# --- trip load ---
|
214
|
-
self.ss.PQ.set(src='p0', attr='v', idx='PQ_1', value=0)
|
215
|
-
self.ss.ACOPF.update()
|
216
|
-
|
217
|
-
self.ss.ACOPF.run()
|
218
|
-
pgs_pqt2 = self.ss.ACOPF.pg.v.sum()
|
219
|
-
self.assertLess(pgs_pqt2, pgs_pqt, "Load trip does not take effect!")
|