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.
Files changed (83) hide show
  1. ams/__init__.py +0 -1
  2. ams/_version.py +3 -3
  3. ams/cases/5bus/pjm5bus_demo.json +1324 -0
  4. ams/core/__init__.py +1 -0
  5. ams/core/common.py +30 -0
  6. ams/core/model.py +1 -1
  7. ams/core/symprocessor.py +1 -1
  8. ams/extension/eva.py +1 -1
  9. ams/interface.py +40 -24
  10. ams/io/matpower.py +192 -26
  11. ams/io/psse.py +278 -1
  12. ams/io/pypower.py +14 -0
  13. ams/main.py +2 -2
  14. ams/models/group.py +2 -70
  15. ams/models/static/pq.py +7 -3
  16. ams/opt/param.py +1 -2
  17. ams/report.py +3 -4
  18. ams/routines/__init__.py +2 -3
  19. ams/routines/acopf.py +5 -108
  20. ams/routines/dcopf.py +8 -0
  21. ams/routines/dcpf.py +1 -1
  22. ams/routines/ed.py +4 -2
  23. ams/routines/grbopt.py +150 -0
  24. ams/routines/pflow.py +2 -2
  25. ams/routines/pypower.py +631 -0
  26. ams/routines/routine.py +4 -10
  27. ams/routines/uc.py +2 -2
  28. ams/shared.py +30 -44
  29. ams/system.py +118 -2
  30. docs/source/api.rst +2 -0
  31. docs/source/getting_started/formats/matpower.rst +135 -0
  32. docs/source/getting_started/formats/pypower.rst +1 -2
  33. docs/source/getting_started/install.rst +9 -6
  34. docs/source/images/dcopf_time.png +0 -0
  35. docs/source/images/educ_pie.png +0 -0
  36. docs/source/release-notes.rst +29 -47
  37. {ltbams-1.0.8.dist-info → ltbams-1.0.10.dist-info}/METADATA +87 -47
  38. {ltbams-1.0.8.dist-info → ltbams-1.0.10.dist-info}/RECORD +58 -75
  39. {ltbams-1.0.8.dist-info → ltbams-1.0.10.dist-info}/WHEEL +1 -1
  40. tests/test_1st_system.py +1 -1
  41. tests/test_case.py +14 -14
  42. tests/test_export_csv.py +1 -1
  43. tests/test_interface.py +24 -2
  44. tests/test_io.py +125 -1
  45. tests/test_omodel.py +1 -1
  46. tests/test_report.py +6 -6
  47. tests/test_routine.py +2 -2
  48. tests/test_rtn_acopf.py +75 -0
  49. tests/test_rtn_dcopf.py +1 -1
  50. tests/test_rtn_dcopf2.py +1 -1
  51. tests/test_rtn_ed.py +9 -9
  52. tests/test_rtn_opf.py +142 -0
  53. tests/test_rtn_pflow.py +0 -72
  54. tests/test_rtn_pypower.py +315 -0
  55. tests/test_rtn_rted.py +8 -8
  56. tests/test_rtn_uc.py +18 -18
  57. ams/pypower/__init__.py +0 -8
  58. ams/pypower/_compat.py +0 -9
  59. ams/pypower/core/__init__.py +0 -8
  60. ams/pypower/core/pips.py +0 -894
  61. ams/pypower/core/ppoption.py +0 -244
  62. ams/pypower/core/ppver.py +0 -18
  63. ams/pypower/core/solver.py +0 -2451
  64. ams/pypower/eps.py +0 -6
  65. ams/pypower/idx.py +0 -174
  66. ams/pypower/io.py +0 -604
  67. ams/pypower/make/__init__.py +0 -11
  68. ams/pypower/make/matrices.py +0 -665
  69. ams/pypower/make/pdv.py +0 -506
  70. ams/pypower/routines/__init__.py +0 -7
  71. ams/pypower/routines/cpf.py +0 -513
  72. ams/pypower/routines/cpf_callbacks.py +0 -114
  73. ams/pypower/routines/opf.py +0 -1803
  74. ams/pypower/routines/opffcns.py +0 -1946
  75. ams/pypower/routines/pflow.py +0 -852
  76. ams/pypower/toggle.py +0 -1098
  77. ams/pypower/utils.py +0 -293
  78. ams/routines/cpf.py +0 -65
  79. ams/routines/dcpf0.py +0 -196
  80. ams/routines/pflow0.py +0 -113
  81. tests/test_rtn_dcpf.py +0 -77
  82. {ltbams-1.0.8.dist-info → ltbams-1.0.10.dist-info}/entry_points.txt +0 -0
  83. {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.xlsx"),
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.xlsx"),
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.xlsx"),
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.xlsx"),
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,
@@ -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.xlsx"),
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.xlsx"),
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.xlsx"),
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.xlsx"),
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.xlsx"),
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!")