ltbams 0.9.9__py3-none-any.whl → 1.0.2a1__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 +4 -11
- ams/_version.py +3 -3
- ams/cases/5bus/pjm5bus_demo.xlsx +0 -0
- ams/cases/5bus/pjm5bus_jumper.xlsx +0 -0
- ams/cases/5bus/pjm5bus_uced.json +1062 -0
- ams/cases/5bus/pjm5bus_uced.xlsx +0 -0
- ams/cases/5bus/pjm5bus_uced_esd1.xlsx +0 -0
- ams/cases/5bus/pjm5bus_uced_ev.xlsx +0 -0
- ams/cases/ieee123/ieee123.xlsx +0 -0
- ams/cases/ieee123/ieee123_regcv1.xlsx +0 -0
- ams/cases/ieee14/ieee14.json +1166 -0
- ams/cases/ieee14/ieee14.raw +92 -0
- ams/cases/ieee14/ieee14_conn.xlsx +0 -0
- ams/cases/ieee14/ieee14_uced.xlsx +0 -0
- ams/cases/ieee39/ieee39.xlsx +0 -0
- ams/cases/ieee39/ieee39_uced.xlsx +0 -0
- ams/cases/ieee39/ieee39_uced_esd1.xlsx +0 -0
- ams/cases/ieee39/ieee39_uced_pvd1.xlsx +0 -0
- ams/cases/ieee39/ieee39_uced_vis.xlsx +0 -0
- ams/cases/matpower/benchmark.json +1594 -0
- ams/cases/matpower/case118.m +787 -0
- ams/cases/matpower/case14.m +129 -0
- ams/cases/matpower/case300.m +1315 -0
- ams/cases/matpower/case39.m +205 -0
- ams/cases/matpower/case5.m +62 -0
- ams/cases/matpower/case_ACTIVSg2000.m +9460 -0
- ams/cases/npcc/npcc.m +644 -0
- ams/cases/npcc/npcc_uced.xlsx +0 -0
- ams/cases/pglib/pglib_opf_case39_epri__api.m +243 -0
- ams/cases/wecc/wecc.m +714 -0
- ams/cases/wecc/wecc_uced.xlsx +0 -0
- ams/cli.py +6 -0
- ams/core/__init__.py +2 -0
- ams/core/documenter.py +652 -0
- ams/core/matprocessor.py +782 -0
- ams/core/model.py +330 -0
- ams/core/param.py +322 -0
- ams/core/service.py +918 -0
- ams/core/symprocessor.py +224 -0
- ams/core/var.py +59 -0
- ams/extension/__init__.py +5 -0
- ams/extension/eva.py +401 -0
- ams/interface.py +1085 -0
- ams/io/__init__.py +133 -0
- ams/io/json.py +82 -0
- ams/io/matpower.py +406 -0
- ams/io/psse.py +6 -0
- ams/io/pypower.py +103 -0
- ams/io/xlsx.py +80 -0
- ams/main.py +81 -4
- ams/models/__init__.py +24 -0
- ams/models/area.py +40 -0
- ams/models/bus.py +52 -0
- ams/models/cost.py +169 -0
- ams/models/distributed/__init__.py +3 -0
- ams/models/distributed/esd1.py +71 -0
- ams/models/distributed/ev.py +60 -0
- ams/models/distributed/pvd1.py +67 -0
- ams/models/group.py +231 -0
- ams/models/info.py +26 -0
- ams/models/line.py +238 -0
- ams/models/renewable/__init__.py +5 -0
- ams/models/renewable/regc.py +119 -0
- ams/models/reserve.py +94 -0
- ams/models/shunt.py +14 -0
- ams/models/static/__init__.py +2 -0
- ams/models/static/gen.py +165 -0
- ams/models/static/pq.py +61 -0
- ams/models/timeslot.py +69 -0
- ams/models/zone.py +49 -0
- ams/opt/__init__.py +12 -0
- ams/opt/constraint.py +175 -0
- ams/opt/exprcalc.py +127 -0
- ams/opt/expression.py +188 -0
- ams/opt/objective.py +174 -0
- ams/opt/omodel.py +432 -0
- ams/opt/optzbase.py +192 -0
- ams/opt/param.py +156 -0
- ams/opt/var.py +233 -0
- ams/pypower/__init__.py +8 -0
- ams/pypower/_compat.py +9 -0
- ams/pypower/core/__init__.py +8 -0
- ams/pypower/core/pips.py +894 -0
- ams/pypower/core/ppoption.py +244 -0
- ams/pypower/core/ppver.py +18 -0
- ams/pypower/core/solver.py +2451 -0
- ams/pypower/eps.py +6 -0
- ams/pypower/idx.py +174 -0
- ams/pypower/io.py +604 -0
- ams/pypower/make/__init__.py +11 -0
- ams/pypower/make/matrices.py +665 -0
- ams/pypower/make/pdv.py +506 -0
- ams/pypower/routines/__init__.py +7 -0
- ams/pypower/routines/cpf.py +513 -0
- ams/pypower/routines/cpf_callbacks.py +114 -0
- ams/pypower/routines/opf.py +1803 -0
- ams/pypower/routines/opffcns.py +1946 -0
- ams/pypower/routines/pflow.py +852 -0
- ams/pypower/toggle.py +1098 -0
- ams/pypower/utils.py +293 -0
- ams/report.py +212 -50
- ams/routines/__init__.py +23 -0
- ams/routines/acopf.py +117 -0
- ams/routines/cpf.py +65 -0
- ams/routines/dcopf.py +241 -0
- ams/routines/dcpf.py +209 -0
- ams/routines/dcpf0.py +196 -0
- ams/routines/dopf.py +150 -0
- ams/routines/ed.py +312 -0
- ams/routines/pflow.py +255 -0
- ams/routines/pflow0.py +113 -0
- ams/routines/routine.py +1033 -0
- ams/routines/rted.py +519 -0
- ams/routines/type.py +160 -0
- ams/routines/uc.py +376 -0
- ams/shared.py +63 -9
- ams/system.py +61 -22
- ams/utils/__init__.py +3 -0
- ams/utils/misc.py +77 -0
- ams/utils/paths.py +257 -0
- docs/Makefile +21 -0
- docs/make.bat +35 -0
- docs/source/_templates/autosummary/base.rst +5 -0
- docs/source/_templates/autosummary/class.rst +35 -0
- docs/source/_templates/autosummary/module.rst +65 -0
- docs/source/_templates/autosummary/module_toctree.rst +66 -0
- docs/source/api.rst +102 -0
- docs/source/conf.py +203 -0
- docs/source/examples/index.rst +34 -0
- docs/source/genmodelref.py +61 -0
- docs/source/genroutineref.py +47 -0
- docs/source/getting_started/copyright.rst +20 -0
- docs/source/getting_started/formats/index.rst +20 -0
- docs/source/getting_started/formats/matpower.rst +183 -0
- docs/source/getting_started/formats/psse.rst +46 -0
- docs/source/getting_started/formats/pypower.rst +223 -0
- docs/source/getting_started/formats/xlsx.png +0 -0
- docs/source/getting_started/formats/xlsx.rst +23 -0
- docs/source/getting_started/index.rst +76 -0
- docs/source/getting_started/install.rst +234 -0
- docs/source/getting_started/overview.rst +26 -0
- docs/source/getting_started/testcase.rst +45 -0
- docs/source/getting_started/verification.rst +13 -0
- docs/source/images/curent.ico +0 -0
- docs/source/images/dcopf_time.png +0 -0
- docs/source/images/sponsors/CURENT_Logo_NameOnTrans.png +0 -0
- docs/source/images/sponsors/CURENT_Logo_Transparent.png +0 -0
- docs/source/images/sponsors/CURENT_Logo_Transparent_Name.png +0 -0
- docs/source/images/sponsors/doe.png +0 -0
- docs/source/index.rst +108 -0
- docs/source/modeling/example.rst +159 -0
- docs/source/modeling/index.rst +17 -0
- docs/source/modeling/model.rst +210 -0
- docs/source/modeling/routine.rst +122 -0
- docs/source/modeling/system.rst +51 -0
- docs/source/release-notes.rst +398 -0
- ltbams-1.0.2a1.dist-info/METADATA +210 -0
- ltbams-1.0.2a1.dist-info/RECORD +188 -0
- {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/WHEEL +1 -1
- ltbams-1.0.2a1.dist-info/top_level.txt +3 -0
- tests/__init__.py +0 -0
- tests/test_1st_system.py +33 -0
- tests/test_addressing.py +40 -0
- tests/test_andes_mats.py +61 -0
- tests/test_case.py +266 -0
- tests/test_cli.py +34 -0
- tests/test_export_csv.py +89 -0
- tests/test_group.py +83 -0
- tests/test_interface.py +216 -0
- tests/test_io.py +32 -0
- tests/test_jumper.py +27 -0
- tests/test_known_good.py +267 -0
- tests/test_matp.py +437 -0
- tests/test_model.py +54 -0
- tests/test_omodel.py +119 -0
- tests/test_paths.py +22 -0
- tests/test_report.py +251 -0
- tests/test_repr.py +21 -0
- tests/test_routine.py +178 -0
- tests/test_rtn_dcopf.py +101 -0
- tests/test_rtn_dcpf.py +77 -0
- tests/test_rtn_ed.py +279 -0
- tests/test_rtn_pflow.py +219 -0
- tests/test_rtn_rted.py +273 -0
- tests/test_rtn_uc.py +248 -0
- tests/test_service.py +73 -0
- ltbams-0.9.9.dist-info/LICENSE +0 -692
- ltbams-0.9.9.dist-info/METADATA +0 -859
- ltbams-0.9.9.dist-info/RECORD +0 -14
- ltbams-0.9.9.dist-info/top_level.txt +0 -1
- {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/entry_points.txt +0 -0
tests/test_model.py
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
import unittest
|
2
|
+
import numpy as np
|
3
|
+
|
4
|
+
import ams
|
5
|
+
|
6
|
+
|
7
|
+
class TestModelMethods(unittest.TestCase):
|
8
|
+
"""
|
9
|
+
Test methods of Model.
|
10
|
+
"""
|
11
|
+
|
12
|
+
def setUp(self):
|
13
|
+
self.ss = ams.run(
|
14
|
+
ams.get_case("ieee14/ieee14.json"),
|
15
|
+
default_config=True,
|
16
|
+
no_output=True,
|
17
|
+
)
|
18
|
+
|
19
|
+
def test_model_set(self):
|
20
|
+
"""
|
21
|
+
Test `Model.set()` method.
|
22
|
+
"""
|
23
|
+
|
24
|
+
# set a single value
|
25
|
+
self.ss.PQ.set("p0", "PQ_1", "v", 0.25)
|
26
|
+
self.assertEqual(self.ss.PQ.p0.v[0], 0.25)
|
27
|
+
|
28
|
+
# set a list of values
|
29
|
+
self.ss.PQ.set("p0", ["PQ_1", "PQ_2"], "v", [0.26, 0.51])
|
30
|
+
np.testing.assert_equal(self.ss.PQ.p0.v[[0, 1]], [0.26, 0.51])
|
31
|
+
|
32
|
+
# set a list of values
|
33
|
+
self.ss.PQ.set("p0", ["PQ_3", "PQ_5"], "v", [0.52, 0.16])
|
34
|
+
np.testing.assert_equal(self.ss.PQ.p0.v[[2, 4]], [0.52, 0.16])
|
35
|
+
|
36
|
+
# set a list of idxes with a single element to an array of values
|
37
|
+
self.ss.PQ.set("p0", ["PQ_4"], "v", np.array([0.086]))
|
38
|
+
np.testing.assert_equal(self.ss.PQ.p0.v[3], 0.086)
|
39
|
+
|
40
|
+
# set an array of idxes with a single element to an array of values
|
41
|
+
self.ss.PQ.set("p0", np.array(["PQ_4"]), "v", np.array([0.096]))
|
42
|
+
np.testing.assert_equal(self.ss.PQ.p0.v[3], 0.096)
|
43
|
+
|
44
|
+
# set an array of idxes with a list of single value
|
45
|
+
self.ss.PQ.set("p0", np.array(["PQ_4"]), "v", 0.097)
|
46
|
+
np.testing.assert_equal(self.ss.PQ.p0.v[3], 0.097)
|
47
|
+
|
48
|
+
def test_model_repr(self):
|
49
|
+
"""
|
50
|
+
Test `Model.__repr__()` method.
|
51
|
+
"""
|
52
|
+
|
53
|
+
for mdl in self.ss.models.items():
|
54
|
+
print(mdl.__repr__())
|
tests/test_omodel.py
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
import unittest
|
2
|
+
|
3
|
+
import ams
|
4
|
+
|
5
|
+
|
6
|
+
class TestOModelWrappers(unittest.TestCase):
|
7
|
+
"""
|
8
|
+
Test wrappers in module `omodel`.
|
9
|
+
"""
|
10
|
+
|
11
|
+
def setUp(self) -> None:
|
12
|
+
self.ss = ams.load(ams.get_case("matpower/case5.m"),
|
13
|
+
setup=True,
|
14
|
+
default_config=True,
|
15
|
+
no_output=True,
|
16
|
+
)
|
17
|
+
|
18
|
+
def test_ensure_symbols(self):
|
19
|
+
"""
|
20
|
+
Test `ensure_symbols` wrapper.
|
21
|
+
"""
|
22
|
+
self.assertFalse(self.ss.DCOPF._syms, "Symbols should not be ready before generation!")
|
23
|
+
self.ss.DCOPF.pd.parse()
|
24
|
+
self.assertTrue(self.ss.DCOPF._syms, "Symbols should be ready after generation!")
|
25
|
+
|
26
|
+
def test_ensure_mats_and_parsed(self):
|
27
|
+
"""
|
28
|
+
Test `ensure_mats_and_parsed` wrapper.
|
29
|
+
"""
|
30
|
+
self.assertFalse(self.ss.mats.initialized, "MatProcessor should not be initialized before initialization!")
|
31
|
+
self.assertFalse(self.ss.DCOPF.om.parsed, "OModel should be parsed after parsing!")
|
32
|
+
self.ss.DCOPF.pd.evaluate()
|
33
|
+
self.assertTrue(self.ss.mats.initialized, "MatProcessor should be initialized after parsing!")
|
34
|
+
self.assertTrue(self.ss.DCOPF.om.parsed, "OModle should be parsed after parsing!")
|
35
|
+
|
36
|
+
|
37
|
+
class TestOModel(unittest.TestCase):
|
38
|
+
"""
|
39
|
+
Test class `OModel`.
|
40
|
+
"""
|
41
|
+
|
42
|
+
def setUp(self) -> None:
|
43
|
+
self.ss = ams.load(ams.get_case("matpower/case5.m"),
|
44
|
+
setup=True,
|
45
|
+
default_config=True,
|
46
|
+
no_output=True,
|
47
|
+
)
|
48
|
+
|
49
|
+
def test_initialized(self):
|
50
|
+
"""
|
51
|
+
Test `OModel` initialization.
|
52
|
+
"""
|
53
|
+
self.assertFalse(self.ss.DCOPF.om.initialized, "OModel shoud not be initialized before initialziation!")
|
54
|
+
self.ss.DCOPF.om.init()
|
55
|
+
self.assertTrue(self.ss.DCOPF.om.initialized, "OModel should be initialized!")
|
56
|
+
|
57
|
+
def test_uninitialized_after_nonparametric_update(self):
|
58
|
+
"""
|
59
|
+
Test `OModel` initialization after nonparametric update.
|
60
|
+
"""
|
61
|
+
self.ss.DCOPF.om.init()
|
62
|
+
self.assertTrue(self.ss.DCOPF.om.initialized, "OModel should be initialized after initialization!")
|
63
|
+
self.ss.DCOPF.update('ug')
|
64
|
+
self.assertTrue(self.ss.DCOPF.om.initialized, "OModel should be initialized after nonparametric update!")
|
65
|
+
|
66
|
+
|
67
|
+
class TestOModelrepr(unittest.TestCase):
|
68
|
+
"""
|
69
|
+
Test __repr__ in module `omodel`.
|
70
|
+
"""
|
71
|
+
|
72
|
+
def setUp(self) -> None:
|
73
|
+
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.xlsx"),
|
74
|
+
setup=True,
|
75
|
+
default_config=True,
|
76
|
+
no_output=True,
|
77
|
+
)
|
78
|
+
|
79
|
+
def test_dcopf(self):
|
80
|
+
"""
|
81
|
+
Test `DCOPF.om` __repr__().
|
82
|
+
"""
|
83
|
+
self.ss.DCOPF.om.parse()
|
84
|
+
self.assertIsInstance(self.ss.DCOPF.pg.__repr__(), str)
|
85
|
+
self.assertIsInstance(self.ss.DCOPF.pmax.__repr__(), str)
|
86
|
+
self.assertIsInstance(self.ss.DCOPF.pb.__repr__(), str)
|
87
|
+
self.assertIsInstance(self.ss.DCOPF.plflb.__repr__(), str)
|
88
|
+
self.assertIsInstance(self.ss.DCOPF.obj.__repr__(), str)
|
89
|
+
|
90
|
+
def test_rted(self):
|
91
|
+
"""
|
92
|
+
Test `RTED.om` __repr__().
|
93
|
+
"""
|
94
|
+
self.ss.RTED.om.parse()
|
95
|
+
self.assertIsInstance(self.ss.RTED.pru.__repr__(), str)
|
96
|
+
self.assertIsInstance(self.ss.RTED.R10.__repr__(), str)
|
97
|
+
self.assertIsInstance(self.ss.RTED.pru.__repr__(), str)
|
98
|
+
self.assertIsInstance(self.ss.RTED.rru.__repr__(), str)
|
99
|
+
self.assertIsInstance(self.ss.RTED.obj.__repr__(), str)
|
100
|
+
|
101
|
+
def test_ed(self):
|
102
|
+
"""
|
103
|
+
Test `ED.om` __repr__().
|
104
|
+
"""
|
105
|
+
self.ss.ED.om.parse()
|
106
|
+
self.assertIsInstance(self.ss.ED.prs.__repr__(), str)
|
107
|
+
self.assertIsInstance(self.ss.ED.R30.__repr__(), str)
|
108
|
+
self.assertIsInstance(self.ss.ED.prsb.__repr__(), str)
|
109
|
+
self.assertIsInstance(self.ss.ED.obj.__repr__(), str)
|
110
|
+
|
111
|
+
def test_uc(self):
|
112
|
+
"""
|
113
|
+
Test `UC.om` __repr__().
|
114
|
+
"""
|
115
|
+
self.ss.UC.om.parse()
|
116
|
+
self.assertIsInstance(self.ss.UC.prns.__repr__(), str)
|
117
|
+
self.assertIsInstance(self.ss.UC.cdp.__repr__(), str)
|
118
|
+
self.assertIsInstance(self.ss.UC.prnsb.__repr__(), str)
|
119
|
+
self.assertIsInstance(self.ss.UC.obj.__repr__(), str)
|
tests/test_paths.py
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
import unittest
|
2
|
+
|
3
|
+
import ams
|
4
|
+
from ams.utils.paths import list_cases
|
5
|
+
|
6
|
+
|
7
|
+
class TestPaths(unittest.TestCase):
|
8
|
+
def setUp(self) -> None:
|
9
|
+
self.npcc = 'npcc/'
|
10
|
+
self.matpower = 'matpower/'
|
11
|
+
self.ieee14 = ams.get_case("ieee14/ieee14.raw")
|
12
|
+
|
13
|
+
def test_tree(self):
|
14
|
+
list_cases(self.npcc, no_print=True)
|
15
|
+
list_cases(self.matpower, no_print=True)
|
16
|
+
|
17
|
+
def test_relative_path(self):
|
18
|
+
ss = ams.run('ieee14.raw',
|
19
|
+
input_path=ams.get_case('ieee14/', check=False),
|
20
|
+
no_output=True, default_config=True,
|
21
|
+
)
|
22
|
+
self.assertNotEqual(ss, None)
|
tests/test_report.py
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
"""
|
2
|
+
Test system report.
|
3
|
+
"""
|
4
|
+
import unittest
|
5
|
+
import os
|
6
|
+
|
7
|
+
import ams
|
8
|
+
from ams.shared import skip_unittest_without_MISOCP
|
9
|
+
|
10
|
+
|
11
|
+
import logging
|
12
|
+
|
13
|
+
logger = logging.getLogger(__name__)
|
14
|
+
|
15
|
+
|
16
|
+
class TestReport(unittest.TestCase):
|
17
|
+
"""
|
18
|
+
Tests for Report class.
|
19
|
+
"""
|
20
|
+
|
21
|
+
def setUp(self) -> None:
|
22
|
+
self.ss = ams.main.load(
|
23
|
+
ams.get_case("5bus/pjm5bus_demo.xlsx"),
|
24
|
+
default_config=True,
|
25
|
+
no_output=True,
|
26
|
+
)
|
27
|
+
self.expected_report = 'pjm5bus_demo_out.txt'
|
28
|
+
|
29
|
+
def test_no_output(self):
|
30
|
+
"""
|
31
|
+
Test no output.
|
32
|
+
"""
|
33
|
+
self.assertTrue(self.ss.files.no_output)
|
34
|
+
self.assertFalse(self.ss.report())
|
35
|
+
|
36
|
+
def test_no_report(self):
|
37
|
+
"""
|
38
|
+
Test report with no solved routine.
|
39
|
+
"""
|
40
|
+
self.ss.files.no_output = False
|
41
|
+
self.assertTrue(self.ss.report())
|
42
|
+
self.assertTrue(os.path.exists(self.expected_report))
|
43
|
+
|
44
|
+
with open(self.expected_report, "r") as report_file:
|
45
|
+
file_contents = report_file.read()
|
46
|
+
self.assertNotIn("DCOPF", file_contents)
|
47
|
+
|
48
|
+
os.remove(self.expected_report)
|
49
|
+
|
50
|
+
def test_DCOPF_report(self):
|
51
|
+
"""
|
52
|
+
Test report with DCOPF solved.
|
53
|
+
"""
|
54
|
+
self.ss.files.no_output = False
|
55
|
+
self.ss.DCOPF.run(solver='CLARABEL')
|
56
|
+
self.assertTrue(self.ss.report())
|
57
|
+
self.assertTrue(os.path.exists(self.expected_report))
|
58
|
+
|
59
|
+
with open(self.expected_report, "r") as report_file:
|
60
|
+
file_contents = report_file.read()
|
61
|
+
self.assertIn("DCOPF", file_contents)
|
62
|
+
os.remove(self.expected_report)
|
63
|
+
|
64
|
+
self.ss.DCOPF.export_csv()
|
65
|
+
self.assertTrue(os.path.exists('pjm5bus_demo_DCOPF.csv'))
|
66
|
+
os.remove('pjm5bus_demo_DCOPF.csv')
|
67
|
+
|
68
|
+
def test_DCPF_report(self):
|
69
|
+
"""
|
70
|
+
Test report with DCPF solved.
|
71
|
+
"""
|
72
|
+
self.ss.files.no_output = False
|
73
|
+
self.ss.DCPF.run(solver='CLARABEL')
|
74
|
+
self.assertTrue(self.ss.report())
|
75
|
+
self.assertTrue(os.path.exists(self.expected_report))
|
76
|
+
|
77
|
+
with open(self.expected_report, "r") as report_file:
|
78
|
+
file_contents = report_file.read()
|
79
|
+
self.assertIn("DCPF", file_contents)
|
80
|
+
os.remove(self.expected_report)
|
81
|
+
|
82
|
+
self.ss.DCPF.export_csv()
|
83
|
+
self.assertTrue(os.path.exists('pjm5bus_demo_DCPF.csv'))
|
84
|
+
os.remove('pjm5bus_demo_DCPF.csv')
|
85
|
+
|
86
|
+
def test_RTED_report(self):
|
87
|
+
"""
|
88
|
+
Test report with RTED solved.
|
89
|
+
"""
|
90
|
+
self.ss.files.no_output = False
|
91
|
+
self.ss.RTED.run(solver='CLARABEL')
|
92
|
+
self.assertTrue(self.ss.report())
|
93
|
+
self.assertTrue(os.path.exists(self.expected_report))
|
94
|
+
|
95
|
+
with open(self.expected_report, "r") as report_file:
|
96
|
+
file_contents = report_file.read()
|
97
|
+
self.assertIn("RTED", file_contents)
|
98
|
+
os.remove(self.expected_report)
|
99
|
+
|
100
|
+
self.ss.RTED.export_csv()
|
101
|
+
self.assertTrue(os.path.exists('pjm5bus_demo_RTED.csv'))
|
102
|
+
os.remove('pjm5bus_demo_RTED.csv')
|
103
|
+
|
104
|
+
def test_RTEDDG_report(self):
|
105
|
+
"""
|
106
|
+
Test report with RTEDDG solved.
|
107
|
+
"""
|
108
|
+
self.ss.files.no_output = False
|
109
|
+
self.ss.RTEDDG.run(solver='CLARABEL')
|
110
|
+
self.assertTrue(self.ss.report())
|
111
|
+
self.assertTrue(os.path.exists(self.expected_report))
|
112
|
+
|
113
|
+
with open(self.expected_report, "r") as report_file:
|
114
|
+
file_contents = report_file.read()
|
115
|
+
self.assertIn("RTEDDG", file_contents)
|
116
|
+
os.remove(self.expected_report)
|
117
|
+
|
118
|
+
self.ss.RTEDDG.export_csv()
|
119
|
+
self.assertTrue(os.path.exists('pjm5bus_demo_RTEDDG.csv'))
|
120
|
+
os.remove('pjm5bus_demo_RTEDDG.csv')
|
121
|
+
|
122
|
+
@skip_unittest_without_MISOCP
|
123
|
+
def test_RTEDES_report(self):
|
124
|
+
"""
|
125
|
+
Test report with RTEDES solved.
|
126
|
+
"""
|
127
|
+
self.ss.files.no_output = False
|
128
|
+
self.ss.RTEDES.run()
|
129
|
+
self.assertTrue(self.ss.report())
|
130
|
+
self.assertTrue(os.path.exists(self.expected_report))
|
131
|
+
|
132
|
+
with open(self.expected_report, "r") as report_file:
|
133
|
+
file_contents = report_file.read()
|
134
|
+
self.assertIn("RTEDES", file_contents)
|
135
|
+
os.remove(self.expected_report)
|
136
|
+
|
137
|
+
self.ss.RTEDES.export_csv()
|
138
|
+
self.assertTrue(os.path.exists('pjm5bus_demo_RTEDES.csv'))
|
139
|
+
os.remove('pjm5bus_demo_RTEDES.csv')
|
140
|
+
|
141
|
+
def test_ED_report(self):
|
142
|
+
"""
|
143
|
+
Test report with ED solved.
|
144
|
+
"""
|
145
|
+
self.ss.files.no_output = False
|
146
|
+
self.ss.ED.run(solver='CLARABEL')
|
147
|
+
self.assertTrue(self.ss.report())
|
148
|
+
self.assertTrue(os.path.exists(self.expected_report))
|
149
|
+
|
150
|
+
with open(self.expected_report, "r") as report_file:
|
151
|
+
file_contents = report_file.read()
|
152
|
+
self.assertIn("ED", file_contents)
|
153
|
+
os.remove(self.expected_report)
|
154
|
+
|
155
|
+
self.ss.ED.export_csv()
|
156
|
+
self.assertTrue(os.path.exists('pjm5bus_demo_ED.csv'))
|
157
|
+
os.remove('pjm5bus_demo_ED.csv')
|
158
|
+
|
159
|
+
def test_EDDG_report(self):
|
160
|
+
"""
|
161
|
+
Test report with EDDG solved.
|
162
|
+
"""
|
163
|
+
self.ss.files.no_output = False
|
164
|
+
self.ss.EDDG.run(solver='CLARABEL')
|
165
|
+
self.assertTrue(self.ss.report())
|
166
|
+
self.assertTrue(os.path.exists(self.expected_report))
|
167
|
+
|
168
|
+
with open(self.expected_report, "r") as report_file:
|
169
|
+
file_contents = report_file.read()
|
170
|
+
self.assertIn("EDDG", file_contents)
|
171
|
+
os.remove(self.expected_report)
|
172
|
+
|
173
|
+
self.ss.EDDG.export_csv()
|
174
|
+
self.assertTrue(os.path.exists('pjm5bus_demo_EDDG.csv'))
|
175
|
+
os.remove('pjm5bus_demo_EDDG.csv')
|
176
|
+
|
177
|
+
@skip_unittest_without_MISOCP
|
178
|
+
def test_EDES_report(self):
|
179
|
+
"""
|
180
|
+
Test report with EDES solved.
|
181
|
+
"""
|
182
|
+
self.ss.files.no_output = False
|
183
|
+
self.ss.EDES.run()
|
184
|
+
self.assertTrue(self.ss.report())
|
185
|
+
self.assertTrue(os.path.exists(self.expected_report))
|
186
|
+
|
187
|
+
with open(self.expected_report, "r") as report_file:
|
188
|
+
file_contents = report_file.read()
|
189
|
+
self.assertIn("EDES", file_contents)
|
190
|
+
os.remove(self.expected_report)
|
191
|
+
|
192
|
+
self.ss.EDES.export_csv()
|
193
|
+
self.assertTrue(os.path.exists('pjm5bus_demo_EDES.csv'))
|
194
|
+
os.remove('pjm5bus_demo_EDES.csv')
|
195
|
+
|
196
|
+
@skip_unittest_without_MISOCP
|
197
|
+
def test_UC_report(self):
|
198
|
+
"""
|
199
|
+
Test report with UC solved.
|
200
|
+
"""
|
201
|
+
self.ss.files.no_output = False
|
202
|
+
self.ss.UC.run()
|
203
|
+
self.assertTrue(self.ss.report())
|
204
|
+
self.assertTrue(os.path.exists(self.expected_report))
|
205
|
+
|
206
|
+
with open(self.expected_report, "r") as report_file:
|
207
|
+
file_contents = report_file.read()
|
208
|
+
self.assertIn("UC", file_contents)
|
209
|
+
os.remove(self.expected_report)
|
210
|
+
|
211
|
+
self.ss.UC.export_csv()
|
212
|
+
self.assertTrue(os.path.exists('pjm5bus_demo_UC.csv'))
|
213
|
+
os.remove('pjm5bus_demo_UC.csv')
|
214
|
+
|
215
|
+
@skip_unittest_without_MISOCP
|
216
|
+
def test_UCDG_report(self):
|
217
|
+
"""
|
218
|
+
Test report with UCDG solved.
|
219
|
+
"""
|
220
|
+
self.ss.files.no_output = False
|
221
|
+
self.ss.UCDG.run()
|
222
|
+
self.assertTrue(self.ss.report())
|
223
|
+
self.assertTrue(os.path.exists(self.expected_report))
|
224
|
+
|
225
|
+
with open(self.expected_report, "r") as report_file:
|
226
|
+
file_contents = report_file.read()
|
227
|
+
self.assertIn("UCDG", file_contents)
|
228
|
+
os.remove(self.expected_report)
|
229
|
+
|
230
|
+
self.ss.UCDG.export_csv()
|
231
|
+
self.assertTrue(os.path.exists('pjm5bus_demo_UCDG.csv'))
|
232
|
+
os.remove('pjm5bus_demo_UCDG.csv')
|
233
|
+
|
234
|
+
@skip_unittest_without_MISOCP
|
235
|
+
def test_UCES_report(self):
|
236
|
+
"""
|
237
|
+
Test report with UCES solved.
|
238
|
+
"""
|
239
|
+
self.ss.files.no_output = False
|
240
|
+
self.ss.UCES.run()
|
241
|
+
self.assertTrue(self.ss.report())
|
242
|
+
self.assertTrue(os.path.exists(self.expected_report))
|
243
|
+
|
244
|
+
with open(self.expected_report, "r") as report_file:
|
245
|
+
file_contents = report_file.read()
|
246
|
+
self.assertIn("UCES", file_contents)
|
247
|
+
os.remove(self.expected_report)
|
248
|
+
|
249
|
+
self.ss.UCES.export_csv()
|
250
|
+
self.assertTrue(os.path.exists('pjm5bus_demo_UCES.csv'))
|
251
|
+
os.remove('pjm5bus_demo_UCES.csv')
|
tests/test_repr.py
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
import contextlib
|
2
|
+
import unittest
|
3
|
+
|
4
|
+
import ams
|
5
|
+
|
6
|
+
|
7
|
+
class TestRepr(unittest.TestCase):
|
8
|
+
"""Test __repr__"""
|
9
|
+
def setUp(self):
|
10
|
+
self.ss = ams.run(ams.get_case("ieee39/ieee39_uced.xlsx"),
|
11
|
+
no_output=True,
|
12
|
+
default_config=True,
|
13
|
+
)
|
14
|
+
|
15
|
+
def test_print_model_repr(self):
|
16
|
+
"""
|
17
|
+
Print out Model ``cache``'s fields and values.
|
18
|
+
"""
|
19
|
+
with contextlib.redirect_stdout(None):
|
20
|
+
for model in self.ss.models.values():
|
21
|
+
print(model.cache.__dict__)
|
tests/test_routine.py
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
import unittest
|
2
|
+
import numpy as np
|
3
|
+
|
4
|
+
|
5
|
+
import ams
|
6
|
+
from ams.shared import pd
|
7
|
+
|
8
|
+
|
9
|
+
class TestRoutineMethods(unittest.TestCase):
|
10
|
+
"""
|
11
|
+
Test methods of `Routine`.
|
12
|
+
"""
|
13
|
+
|
14
|
+
def setUp(self) -> None:
|
15
|
+
self.ss = ams.load(ams.get_case("ieee39/ieee39_uced.xlsx"),
|
16
|
+
default_config=True,
|
17
|
+
no_output=True,
|
18
|
+
)
|
19
|
+
|
20
|
+
def test_data_check(self):
|
21
|
+
"""
|
22
|
+
Test `Routine._data_check()` method.
|
23
|
+
"""
|
24
|
+
|
25
|
+
self.assertTrue(self.ss.DCOPF._data_check())
|
26
|
+
self.assertFalse(self.ss.RTEDES._data_check())
|
27
|
+
|
28
|
+
def test_get_off_constrs(self):
|
29
|
+
"""
|
30
|
+
Test `Routine._get_off_constrs()` method.
|
31
|
+
"""
|
32
|
+
|
33
|
+
self.assertIsInstance(self.ss.DCOPF._get_off_constrs(), list)
|
34
|
+
|
35
|
+
def test_routine_set(self):
|
36
|
+
"""
|
37
|
+
Test `Routine.set()` method.
|
38
|
+
"""
|
39
|
+
|
40
|
+
self.ss.DCOPF.set('c2', 'GCost_1', 'v', 10)
|
41
|
+
np.testing.assert_equal(self.ss.GCost.get('c2', 'GCost_1', 'v'), 10)
|
42
|
+
|
43
|
+
def test_routine_get(self):
|
44
|
+
"""
|
45
|
+
Test `Routine.get()` method.
|
46
|
+
"""
|
47
|
+
# --- single period routine ---
|
48
|
+
# get an rparam value
|
49
|
+
np.testing.assert_equal(self.ss.DCOPF.get('ug', 'PV_30'), 1)
|
50
|
+
|
51
|
+
# get an unpacked var value
|
52
|
+
self.ss.DCOPF.run(solver='CLARABEL')
|
53
|
+
self.assertEqual(self.ss.DCOPF.exit_code, 0, "Exit code is not 0.")
|
54
|
+
np.testing.assert_equal(self.ss.DCOPF.get('pg', 'PV_30', 'v'),
|
55
|
+
self.ss.StaticGen.get('p', 'PV_30', 'v'))
|
56
|
+
|
57
|
+
# test input type
|
58
|
+
self.assertIsInstance(self.ss.DCOPF.get('pg', pd.Series(['PV_30']), 'v'), np.ndarray)
|
59
|
+
|
60
|
+
# test return type
|
61
|
+
self.assertIsInstance(self.ss.DCOPF.get('pg', 'PV_30', 'v'), float)
|
62
|
+
self.assertIsInstance(self.ss.DCOPF.get('pg', ['PV_30'], 'v'), np.ndarray)
|
63
|
+
|
64
|
+
# --- multi period routine ---
|
65
|
+
self.ss.ED.run(solver='CLARABEL')
|
66
|
+
self.assertEqual(self.ss.ED.exit_code, 0, "Exit code is not 0.")
|
67
|
+
np.testing.assert_equal(self.ss.ED.get('pg', 'PV_30', 'v').ndim, 1)
|
68
|
+
np.testing.assert_equal(self.ss.ED.get('pg', ['PV_30'], 'v').ndim, 2)
|
69
|
+
|
70
|
+
def test_rouine_init(self):
|
71
|
+
"""
|
72
|
+
Test `Routine.init()` method.
|
73
|
+
"""
|
74
|
+
|
75
|
+
self.assertTrue(self.ss.DCOPF.init(), "DCOPF initialization failed!")
|
76
|
+
|
77
|
+
def test_generate_symbols(self):
|
78
|
+
"""
|
79
|
+
Test symbol generation.
|
80
|
+
"""
|
81
|
+
|
82
|
+
self.ss.DCOPF.syms.generate_symbols()
|
83
|
+
self.assertTrue(self.ss.DCOPF._syms, "Symbol generation failed!")
|
84
|
+
|
85
|
+
def test_value_method(self):
|
86
|
+
"""
|
87
|
+
Test Contraint and Objective values.
|
88
|
+
"""
|
89
|
+
|
90
|
+
self.ss.DCOPF.run(solver='CLARABEL')
|
91
|
+
self.assertTrue(self.ss.DCOPF.converged, "DCOPF did not converge!")
|
92
|
+
|
93
|
+
# --- constraint values ---
|
94
|
+
for constr in self.ss.DCOPF.constrs.values():
|
95
|
+
np.testing.assert_almost_equal(constr.v, constr.e, decimal=6)
|
96
|
+
|
97
|
+
# --- objective value ---
|
98
|
+
self.assertAlmostEqual(self.ss.DCOPF.obj.v, self.ss.DCOPF.obj.e, places=6)
|
99
|
+
|
100
|
+
|
101
|
+
class TestSetOptzValueACOPF(unittest.TestCase):
|
102
|
+
"""
|
103
|
+
Test value settings of `OptzBase` series in `ACOPF`.
|
104
|
+
"""
|
105
|
+
|
106
|
+
def setUp(self) -> None:
|
107
|
+
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.xlsx"),
|
108
|
+
setup=True,
|
109
|
+
default_config=True,
|
110
|
+
no_output=True,
|
111
|
+
)
|
112
|
+
|
113
|
+
def test_vset_before_init(self):
|
114
|
+
"""
|
115
|
+
Test value setting before routine initialization.
|
116
|
+
"""
|
117
|
+
# set values to `Var` before initialization is not doable
|
118
|
+
v_ext = np.ones(self.ss.ACOPF.pg.n)
|
119
|
+
self.ss.ACOPF.pg.v = v_ext
|
120
|
+
self.assertIsNone(self.ss.ACOPF.pg.v)
|
121
|
+
# set values to `Constraint` is not allowed
|
122
|
+
self.assertRaises(AttributeError, lambda: setattr(self.ss.ACOPF.plfub, 'v', 1))
|
123
|
+
# set values to `Objective` is not allowed
|
124
|
+
self.assertRaises(AttributeError, lambda: setattr(self.ss.ACOPF.obj, 'v', 1))
|
125
|
+
|
126
|
+
def test_vset_after_init(self):
|
127
|
+
"""
|
128
|
+
Test value setting after routine initialization.
|
129
|
+
"""
|
130
|
+
self.ss.ACOPF.init()
|
131
|
+
# set values to `Var` after initialization is allowed
|
132
|
+
v_ext = np.ones(self.ss.ACOPF.pg.n)
|
133
|
+
self.ss.ACOPF.pg.v = v_ext
|
134
|
+
np.testing.assert_equal(self.ss.ACOPF.pg.v, v_ext)
|
135
|
+
# set values to `Constraint` is not allowed
|
136
|
+
self.assertRaises(AttributeError, lambda: setattr(self.ss.ACOPF.plfub, 'v', 1))
|
137
|
+
# set values to `Objective` is not allowed
|
138
|
+
self.assertRaises(AttributeError, lambda: setattr(self.ss.ACOPF.obj, 'v', 1))
|
139
|
+
|
140
|
+
|
141
|
+
class TestSetOptzValueDCOPF(unittest.TestCase):
|
142
|
+
"""
|
143
|
+
Test value settings of `OptzBase` series in `DCOPF`.
|
144
|
+
"""
|
145
|
+
|
146
|
+
def setUp(self) -> None:
|
147
|
+
self.ss = ams.load(ams.get_case("5bus/pjm5bus_demo.xlsx"),
|
148
|
+
setup=True,
|
149
|
+
default_config=True,
|
150
|
+
no_output=True,
|
151
|
+
)
|
152
|
+
|
153
|
+
def test_vset_before_init(self):
|
154
|
+
"""
|
155
|
+
Test value setting before routine initialization.
|
156
|
+
"""
|
157
|
+
# set values to `Var` before initialization is not doable
|
158
|
+
v_ext = np.ones(self.ss.DCOPF.pg.n)
|
159
|
+
self.ss.DCOPF.pg.v = v_ext
|
160
|
+
self.assertIsNone(self.ss.DCOPF.pg.v)
|
161
|
+
# set values to `Constraint` is not allowed
|
162
|
+
self.assertRaises(AttributeError, lambda: setattr(self.ss.DCOPF.plfub, 'v', 1))
|
163
|
+
# set values to `Objective` is not allowed
|
164
|
+
self.assertRaises(AttributeError, lambda: setattr(self.ss.DCOPF.obj, 'v', 1))
|
165
|
+
|
166
|
+
def test_vset_after_init(self):
|
167
|
+
"""
|
168
|
+
Test value setting after routine initialization.
|
169
|
+
"""
|
170
|
+
self.ss.DCOPF.init()
|
171
|
+
# set values to `Var` after initialization is allowed
|
172
|
+
v_ext = np.ones(self.ss.DCOPF.pg.n)
|
173
|
+
self.ss.DCOPF.pg.v = v_ext
|
174
|
+
np.testing.assert_equal(self.ss.DCOPF.pg.v, v_ext)
|
175
|
+
# set values to `Constraint` is not allowed
|
176
|
+
self.assertRaises(AttributeError, lambda: setattr(self.ss.DCOPF.plfub, 'v', 1))
|
177
|
+
# set values to `Objective` is not allowed
|
178
|
+
self.assertRaises(AttributeError, lambda: setattr(self.ss.DCOPF.obj, 'v', 1))
|