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.
Files changed (191) hide show
  1. ams/__init__.py +4 -11
  2. ams/_version.py +3 -3
  3. ams/cases/5bus/pjm5bus_demo.xlsx +0 -0
  4. ams/cases/5bus/pjm5bus_jumper.xlsx +0 -0
  5. ams/cases/5bus/pjm5bus_uced.json +1062 -0
  6. ams/cases/5bus/pjm5bus_uced.xlsx +0 -0
  7. ams/cases/5bus/pjm5bus_uced_esd1.xlsx +0 -0
  8. ams/cases/5bus/pjm5bus_uced_ev.xlsx +0 -0
  9. ams/cases/ieee123/ieee123.xlsx +0 -0
  10. ams/cases/ieee123/ieee123_regcv1.xlsx +0 -0
  11. ams/cases/ieee14/ieee14.json +1166 -0
  12. ams/cases/ieee14/ieee14.raw +92 -0
  13. ams/cases/ieee14/ieee14_conn.xlsx +0 -0
  14. ams/cases/ieee14/ieee14_uced.xlsx +0 -0
  15. ams/cases/ieee39/ieee39.xlsx +0 -0
  16. ams/cases/ieee39/ieee39_uced.xlsx +0 -0
  17. ams/cases/ieee39/ieee39_uced_esd1.xlsx +0 -0
  18. ams/cases/ieee39/ieee39_uced_pvd1.xlsx +0 -0
  19. ams/cases/ieee39/ieee39_uced_vis.xlsx +0 -0
  20. ams/cases/matpower/benchmark.json +1594 -0
  21. ams/cases/matpower/case118.m +787 -0
  22. ams/cases/matpower/case14.m +129 -0
  23. ams/cases/matpower/case300.m +1315 -0
  24. ams/cases/matpower/case39.m +205 -0
  25. ams/cases/matpower/case5.m +62 -0
  26. ams/cases/matpower/case_ACTIVSg2000.m +9460 -0
  27. ams/cases/npcc/npcc.m +644 -0
  28. ams/cases/npcc/npcc_uced.xlsx +0 -0
  29. ams/cases/pglib/pglib_opf_case39_epri__api.m +243 -0
  30. ams/cases/wecc/wecc.m +714 -0
  31. ams/cases/wecc/wecc_uced.xlsx +0 -0
  32. ams/cli.py +6 -0
  33. ams/core/__init__.py +2 -0
  34. ams/core/documenter.py +652 -0
  35. ams/core/matprocessor.py +782 -0
  36. ams/core/model.py +330 -0
  37. ams/core/param.py +322 -0
  38. ams/core/service.py +918 -0
  39. ams/core/symprocessor.py +224 -0
  40. ams/core/var.py +59 -0
  41. ams/extension/__init__.py +5 -0
  42. ams/extension/eva.py +401 -0
  43. ams/interface.py +1085 -0
  44. ams/io/__init__.py +133 -0
  45. ams/io/json.py +82 -0
  46. ams/io/matpower.py +406 -0
  47. ams/io/psse.py +6 -0
  48. ams/io/pypower.py +103 -0
  49. ams/io/xlsx.py +80 -0
  50. ams/main.py +81 -4
  51. ams/models/__init__.py +24 -0
  52. ams/models/area.py +40 -0
  53. ams/models/bus.py +52 -0
  54. ams/models/cost.py +169 -0
  55. ams/models/distributed/__init__.py +3 -0
  56. ams/models/distributed/esd1.py +71 -0
  57. ams/models/distributed/ev.py +60 -0
  58. ams/models/distributed/pvd1.py +67 -0
  59. ams/models/group.py +231 -0
  60. ams/models/info.py +26 -0
  61. ams/models/line.py +238 -0
  62. ams/models/renewable/__init__.py +5 -0
  63. ams/models/renewable/regc.py +119 -0
  64. ams/models/reserve.py +94 -0
  65. ams/models/shunt.py +14 -0
  66. ams/models/static/__init__.py +2 -0
  67. ams/models/static/gen.py +165 -0
  68. ams/models/static/pq.py +61 -0
  69. ams/models/timeslot.py +69 -0
  70. ams/models/zone.py +49 -0
  71. ams/opt/__init__.py +12 -0
  72. ams/opt/constraint.py +175 -0
  73. ams/opt/exprcalc.py +127 -0
  74. ams/opt/expression.py +188 -0
  75. ams/opt/objective.py +174 -0
  76. ams/opt/omodel.py +432 -0
  77. ams/opt/optzbase.py +192 -0
  78. ams/opt/param.py +156 -0
  79. ams/opt/var.py +233 -0
  80. ams/pypower/__init__.py +8 -0
  81. ams/pypower/_compat.py +9 -0
  82. ams/pypower/core/__init__.py +8 -0
  83. ams/pypower/core/pips.py +894 -0
  84. ams/pypower/core/ppoption.py +244 -0
  85. ams/pypower/core/ppver.py +18 -0
  86. ams/pypower/core/solver.py +2451 -0
  87. ams/pypower/eps.py +6 -0
  88. ams/pypower/idx.py +174 -0
  89. ams/pypower/io.py +604 -0
  90. ams/pypower/make/__init__.py +11 -0
  91. ams/pypower/make/matrices.py +665 -0
  92. ams/pypower/make/pdv.py +506 -0
  93. ams/pypower/routines/__init__.py +7 -0
  94. ams/pypower/routines/cpf.py +513 -0
  95. ams/pypower/routines/cpf_callbacks.py +114 -0
  96. ams/pypower/routines/opf.py +1803 -0
  97. ams/pypower/routines/opffcns.py +1946 -0
  98. ams/pypower/routines/pflow.py +852 -0
  99. ams/pypower/toggle.py +1098 -0
  100. ams/pypower/utils.py +293 -0
  101. ams/report.py +212 -50
  102. ams/routines/__init__.py +23 -0
  103. ams/routines/acopf.py +117 -0
  104. ams/routines/cpf.py +65 -0
  105. ams/routines/dcopf.py +241 -0
  106. ams/routines/dcpf.py +209 -0
  107. ams/routines/dcpf0.py +196 -0
  108. ams/routines/dopf.py +150 -0
  109. ams/routines/ed.py +312 -0
  110. ams/routines/pflow.py +255 -0
  111. ams/routines/pflow0.py +113 -0
  112. ams/routines/routine.py +1033 -0
  113. ams/routines/rted.py +519 -0
  114. ams/routines/type.py +160 -0
  115. ams/routines/uc.py +376 -0
  116. ams/shared.py +63 -9
  117. ams/system.py +61 -22
  118. ams/utils/__init__.py +3 -0
  119. ams/utils/misc.py +77 -0
  120. ams/utils/paths.py +257 -0
  121. docs/Makefile +21 -0
  122. docs/make.bat +35 -0
  123. docs/source/_templates/autosummary/base.rst +5 -0
  124. docs/source/_templates/autosummary/class.rst +35 -0
  125. docs/source/_templates/autosummary/module.rst +65 -0
  126. docs/source/_templates/autosummary/module_toctree.rst +66 -0
  127. docs/source/api.rst +102 -0
  128. docs/source/conf.py +203 -0
  129. docs/source/examples/index.rst +34 -0
  130. docs/source/genmodelref.py +61 -0
  131. docs/source/genroutineref.py +47 -0
  132. docs/source/getting_started/copyright.rst +20 -0
  133. docs/source/getting_started/formats/index.rst +20 -0
  134. docs/source/getting_started/formats/matpower.rst +183 -0
  135. docs/source/getting_started/formats/psse.rst +46 -0
  136. docs/source/getting_started/formats/pypower.rst +223 -0
  137. docs/source/getting_started/formats/xlsx.png +0 -0
  138. docs/source/getting_started/formats/xlsx.rst +23 -0
  139. docs/source/getting_started/index.rst +76 -0
  140. docs/source/getting_started/install.rst +234 -0
  141. docs/source/getting_started/overview.rst +26 -0
  142. docs/source/getting_started/testcase.rst +45 -0
  143. docs/source/getting_started/verification.rst +13 -0
  144. docs/source/images/curent.ico +0 -0
  145. docs/source/images/dcopf_time.png +0 -0
  146. docs/source/images/sponsors/CURENT_Logo_NameOnTrans.png +0 -0
  147. docs/source/images/sponsors/CURENT_Logo_Transparent.png +0 -0
  148. docs/source/images/sponsors/CURENT_Logo_Transparent_Name.png +0 -0
  149. docs/source/images/sponsors/doe.png +0 -0
  150. docs/source/index.rst +108 -0
  151. docs/source/modeling/example.rst +159 -0
  152. docs/source/modeling/index.rst +17 -0
  153. docs/source/modeling/model.rst +210 -0
  154. docs/source/modeling/routine.rst +122 -0
  155. docs/source/modeling/system.rst +51 -0
  156. docs/source/release-notes.rst +398 -0
  157. ltbams-1.0.2a1.dist-info/METADATA +210 -0
  158. ltbams-1.0.2a1.dist-info/RECORD +188 -0
  159. {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/WHEEL +1 -1
  160. ltbams-1.0.2a1.dist-info/top_level.txt +3 -0
  161. tests/__init__.py +0 -0
  162. tests/test_1st_system.py +33 -0
  163. tests/test_addressing.py +40 -0
  164. tests/test_andes_mats.py +61 -0
  165. tests/test_case.py +266 -0
  166. tests/test_cli.py +34 -0
  167. tests/test_export_csv.py +89 -0
  168. tests/test_group.py +83 -0
  169. tests/test_interface.py +216 -0
  170. tests/test_io.py +32 -0
  171. tests/test_jumper.py +27 -0
  172. tests/test_known_good.py +267 -0
  173. tests/test_matp.py +437 -0
  174. tests/test_model.py +54 -0
  175. tests/test_omodel.py +119 -0
  176. tests/test_paths.py +22 -0
  177. tests/test_report.py +251 -0
  178. tests/test_repr.py +21 -0
  179. tests/test_routine.py +178 -0
  180. tests/test_rtn_dcopf.py +101 -0
  181. tests/test_rtn_dcpf.py +77 -0
  182. tests/test_rtn_ed.py +279 -0
  183. tests/test_rtn_pflow.py +219 -0
  184. tests/test_rtn_rted.py +273 -0
  185. tests/test_rtn_uc.py +248 -0
  186. tests/test_service.py +73 -0
  187. ltbams-0.9.9.dist-info/LICENSE +0 -692
  188. ltbams-0.9.9.dist-info/METADATA +0 -859
  189. ltbams-0.9.9.dist-info/RECORD +0 -14
  190. ltbams-0.9.9.dist-info/top_level.txt +0 -1
  191. {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,267 @@
1
+ import logging
2
+ import unittest
3
+
4
+ import json
5
+
6
+ import numpy as np
7
+
8
+ from andes.shared import rad2deg
9
+ import ams
10
+ from ams.shared import nan
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class TestKnownResults(unittest.TestCase):
16
+
17
+ def setUp(self) -> None:
18
+ with open(ams.get_case('matpower/benchmark.json'), 'r') as file:
19
+ self.mpres = json.load(file)
20
+
21
+ self.sp = ams.load(ams.get_case('matpower/case14.m'),
22
+ setup=True, no_output=True, default_config=True)
23
+
24
+ def test_DCPF_case14(self):
25
+ """
26
+ Test DC power flow for case14.
27
+ """
28
+ self.sp.DCPF.run()
29
+ np.testing.assert_allclose(self.sp.DCPF.aBus.v * rad2deg,
30
+ np.array(self.mpres['case14']['DCPF']['aBus']).reshape(-1),
31
+ rtol=1e-2, atol=1e-2)
32
+
33
+ np.testing.assert_allclose(self.sp.DCPF.pg.v * self.sp.config.mva,
34
+ np.array(self.mpres['case14']['DCPF']['pg']).reshape(-1),
35
+ rtol=1e-2, atol=1e-2)
36
+
37
+ def test_PFlow_case14(self):
38
+ """
39
+ Test power flow for case14.
40
+ """
41
+ self.sp.PFlow.run()
42
+ np.testing.assert_allclose(self.sp.PFlow.aBus.v * rad2deg,
43
+ np.array(self.mpres['case14']['PFlow']['aBus']).reshape(-1),
44
+ rtol=1e-2, atol=1e-2)
45
+ np.testing.assert_allclose(self.sp.PFlow.vBus.v,
46
+ np.array(self.mpres['case14']['PFlow']['vBus']).reshape(-1),
47
+ rtol=1e-2, atol=1e-2)
48
+ np.testing.assert_allclose(self.sp.PFlow.pg.v.sum() * self.sp.config.mva,
49
+ np.array(self.mpres['case14']['PFlow']['pg']).sum(),
50
+ rtol=1e-2, atol=1e-2)
51
+
52
+ def test_DCOPF_case14(self):
53
+ """
54
+ Test DCOPF for case14.
55
+ """
56
+ self.sp.DCOPF.run(solver='CLARABEL')
57
+ self.assertAlmostEqual(self.sp.DCOPF.obj.v,
58
+ self.mpres['case14']['DCOPF']['obj'],
59
+ places=4)
60
+ np.testing.assert_allclose(self.sp.DCOPF.pi.v / self.sp.config.mva,
61
+ np.array(self.mpres['case14']['DCOPF']['pi']).reshape(-1),
62
+ rtol=1e-2, atol=1e-2)
63
+
64
+ def test_Matrices_case14(self):
65
+ """
66
+ Test matrices for case14.
67
+ """
68
+ ptdf = self.sp.mats.build_ptdf()
69
+ lodf = self.sp.mats.build_lodf()
70
+
71
+ ptdf_mp = load_ptdf(self.mpres, 'case14')
72
+ lodf_mp = load_lodf(self.mpres, 'case14')
73
+
74
+ ptdf[np.isnan(ptdf_mp)] = nan
75
+ lodf[np.isnan(lodf_mp)] = nan
76
+
77
+ np.testing.assert_allclose(ptdf, ptdf_mp,
78
+ equal_nan=True, rtol=1e-2, atol=1e-2)
79
+
80
+ np.testing.assert_allclose(lodf, lodf_mp,
81
+ equal_nan=True, rtol=1e-2, atol=1e-2)
82
+
83
+
84
+ class TestKnownResultsIEEE39(unittest.TestCase):
85
+
86
+ def setUp(self) -> None:
87
+ with open(ams.get_case('matpower/benchmark.json'), 'r') as file:
88
+ self.mpres = json.load(file)
89
+
90
+ self.sp = ams.load(ams.get_case('matpower/case39.m'),
91
+ setup=True, no_output=True, default_config=True)
92
+
93
+ def test_DCPF_case39(self):
94
+ """
95
+ Test DC power flow for case39.
96
+ """
97
+ self.sp.DCPF.run()
98
+ np.testing.assert_allclose(self.sp.DCPF.aBus.v * rad2deg,
99
+ np.array(self.mpres['case39']['DCPF']['aBus']).reshape(-1),
100
+ rtol=1e-2, atol=1e-2)
101
+
102
+ np.testing.assert_allclose(self.sp.DCPF.pg.v.sum() * self.sp.config.mva,
103
+ np.array(self.mpres['case39']['DCPF']['pg']).sum(),
104
+ rtol=1e-2, atol=1e-2)
105
+
106
+ def test_PFlow_case39(self):
107
+ """
108
+ Test power flow for case39.
109
+ """
110
+ self.sp.PFlow.run()
111
+ np.testing.assert_allclose(self.sp.PFlow.aBus.v * rad2deg,
112
+ np.array(self.mpres['case39']['PFlow']['aBus']).reshape(-1),
113
+ rtol=1e-2, atol=1e-2)
114
+ np.testing.assert_allclose(self.sp.PFlow.vBus.v,
115
+ np.array(self.mpres['case39']['PFlow']['vBus']).reshape(-1),
116
+ rtol=1e-2, atol=1e-2)
117
+ np.testing.assert_allclose(self.sp.PFlow.pg.v.sum() * self.sp.config.mva,
118
+ np.array(self.mpres['case39']['PFlow']['pg']).sum(),
119
+ rtol=1e-2, atol=1e-2)
120
+
121
+ def test_DCOPF_case39(self):
122
+ """
123
+ Test DCOPF for case39.
124
+ """
125
+ self.sp.DCOPF.run(solver='CLARABEL')
126
+ self.assertAlmostEqual(self.sp.DCOPF.obj.v,
127
+ self.mpres['case39']['DCOPF']['obj'],
128
+ places=2)
129
+ np.testing.assert_allclose(self.sp.DCOPF.pi.v / self.sp.config.mva,
130
+ np.array(self.mpres['case39']['DCOPF']['pi']).reshape(-1),
131
+ rtol=1e-2, atol=1e-2)
132
+
133
+ def test_Matrices_case39(self):
134
+ """
135
+ Test matrices for case39.
136
+ """
137
+ ptdf = self.sp.mats.build_ptdf()
138
+ lodf = self.sp.mats.build_lodf()
139
+
140
+ ptdf_mp = load_ptdf(self.mpres, 'case39')
141
+ lodf_mp = load_lodf(self.mpres, 'case39')
142
+
143
+ ptdf[np.isnan(ptdf_mp)] = nan
144
+ lodf[np.isnan(lodf_mp)] = nan
145
+
146
+ np.testing.assert_allclose(ptdf, ptdf_mp,
147
+ equal_nan=True, rtol=1e-2, atol=1e-2)
148
+
149
+ np.testing.assert_allclose(lodf, lodf_mp,
150
+ equal_nan=True, rtol=1e-2, atol=10)
151
+
152
+
153
+ class TestKnownResultsIEEE118(unittest.TestCase):
154
+
155
+ def setUp(self) -> None:
156
+ with open(ams.get_case('matpower/benchmark.json'), 'r') as file:
157
+ self.mpres = json.load(file)
158
+
159
+ self.sp = ams.load(ams.get_case('matpower/case118.m'),
160
+ setup=True, no_output=True, default_config=True)
161
+
162
+ def test_DCPF_case118(self):
163
+ """
164
+ Test DC power flow for case118.
165
+ """
166
+ self.sp.DCPF.run()
167
+ aBus_mp = np.array(self.mpres['case118']['DCPF']['aBus']).reshape(-1)
168
+ aBus_mp -= aBus_mp[0]
169
+ np.testing.assert_allclose((self.sp.DCPF.aBus.v - self.sp.DCPF.aBus.v[0]) * rad2deg,
170
+ aBus_mp,
171
+ rtol=1e-2, atol=1e-2)
172
+
173
+ np.testing.assert_allclose(self.sp.DCPF.pg.v.sum() * self.sp.config.mva,
174
+ np.array(self.mpres['case118']['DCPF']['pg']).sum(),
175
+ rtol=1e-2, atol=1e-2)
176
+
177
+ def test_PFlow_case118(self):
178
+ """
179
+ Test power flow for case118.
180
+ """
181
+ self.sp.PFlow.run()
182
+ np.testing.assert_allclose(self.sp.PFlow.aBus.v * rad2deg,
183
+ np.array(self.mpres['case118']['PFlow']['aBus']).reshape(-1),
184
+ rtol=1e-2, atol=1e-2)
185
+ np.testing.assert_allclose(self.sp.PFlow.vBus.v,
186
+ np.array(self.mpres['case118']['PFlow']['vBus']).reshape(-1),
187
+ rtol=1e-2, atol=1e-2)
188
+ np.testing.assert_allclose(self.sp.PFlow.pg.v.sum() * self.sp.config.mva,
189
+ np.array(self.mpres['case118']['PFlow']['pg']).sum(),
190
+ rtol=1e-2, atol=1e-2)
191
+
192
+ def test_DCOPF_case118(self):
193
+ """
194
+ Test DCOPF for case118.
195
+ """
196
+ self.sp.DCOPF.run(solver='CLARABEL')
197
+ self.assertAlmostEqual(self.sp.DCOPF.obj.v,
198
+ self.mpres['case118']['DCOPF']['obj'],
199
+ places=2)
200
+ np.testing.assert_allclose(self.sp.DCOPF.pi.v / self.sp.config.mva,
201
+ np.array(self.mpres['case118']['DCOPF']['pi']).reshape(-1),
202
+ rtol=1e-2, atol=1e-2)
203
+
204
+ def test_Matrices_case118(self):
205
+ """
206
+ Test matrices for case118.
207
+ """
208
+ ptdf = self.sp.mats.build_ptdf()
209
+ lodf = self.sp.mats.build_lodf()
210
+
211
+ ptdf_mp = load_ptdf(self.mpres, 'case118')
212
+ lodf_mp = load_lodf(self.mpres, 'case118')
213
+
214
+ ptdf[np.isnan(ptdf_mp)] = nan
215
+ lodf[np.isnan(lodf_mp)] = nan
216
+
217
+ np.testing.assert_allclose(ptdf, ptdf_mp,
218
+ equal_nan=True, rtol=1e-2, atol=1e-2)
219
+
220
+ np.testing.assert_allclose(lodf, lodf_mp,
221
+ equal_nan=True, rtol=1e-2, atol=10)
222
+
223
+
224
+ def load_ptdf(mpres, case):
225
+ """
226
+ Load PTDF from mpres.
227
+
228
+ Parameters
229
+ ----------
230
+ mpres : dict
231
+ The result dictionary.
232
+ case : str
233
+ The case name.
234
+
235
+ Returns
236
+ -------
237
+ ptdf : np.ndarray
238
+ The PTDF matrix.
239
+ """
240
+ ptdf_data = np.array(mpres[case]['PTDF'])
241
+ ptdf = np.array([[0 if val == "_NaN_" else val for val in row] for row in ptdf_data],
242
+ dtype=float)
243
+ return ptdf
244
+
245
+
246
+ def load_lodf(mpres, case):
247
+ """
248
+ Load LODF from mpres.
249
+
250
+ Parameters
251
+ ----------
252
+ mpres : dict
253
+ The result dictionary.
254
+ case : str
255
+ The case name.
256
+
257
+ Returns
258
+ -------
259
+ lodf : np.ndarray
260
+ The LODF matrix.
261
+ """
262
+ lodf_data = np.array(mpres[case]['LODF'])
263
+ lodf = np.array([[nan if val in ["_NaN_", "-_Inf_", "_Inf_"] else val for val in row] for row in lodf_data],
264
+ dtype=float)
265
+ # NOTE: force the diagonal to be -1
266
+ np.fill_diagonal(lodf, -1)
267
+ return lodf
tests/test_matp.py ADDED
@@ -0,0 +1,437 @@
1
+ """
2
+ Test module MatProcessor.
3
+ """
4
+
5
+ import unittest
6
+ import os
7
+
8
+ import numpy as np
9
+
10
+ import ams
11
+ from ams.core.matprocessor import MatProcessor, MParam
12
+ from ams.shared import sps
13
+
14
+
15
+ class TestMatProcessorBasic(unittest.TestCase):
16
+ """
17
+ Test basic functionality of MatProcessor.
18
+ """
19
+
20
+ def setUp(self) -> None:
21
+ self.ss = ams.load(ams.get_case("matpower/case300.m"),
22
+ default_config=True, no_output=True)
23
+ self.nR = self.ss.Zone.n
24
+ self.nb = self.ss.Bus.n
25
+ self.nl = self.ss.Line.n
26
+ self.ng = self.ss.StaticGen.n
27
+ self.nsh = self.ss.Shunt.n
28
+ self.nD = self.ss.StaticLoad.n
29
+
30
+ self.mats = MatProcessor(self.ss)
31
+ self.mats.build()
32
+
33
+ def test_MParams_owner(self):
34
+ """
35
+ Tesst MParams owner before system initialization.
36
+ """
37
+ self.assertIs(self.mats.Cft.owner, self.mats)
38
+ self.assertIs(self.mats.CftT.owner, self.mats)
39
+ self.assertIs(self.mats.Cg.owner, self.mats)
40
+ self.assertIs(self.mats.Cl.owner, self.mats)
41
+ self.assertIs(self.mats.Csh.owner, self.mats)
42
+ self.assertIs(self.mats.Bbus.owner, self.mats)
43
+ self.assertIs(self.mats.Bf.owner, self.mats)
44
+ self.assertIs(self.mats.Pbusinj.owner, self.mats)
45
+ self.assertIs(self.mats.Pfinj.owner, self.mats)
46
+ self.assertIs(self.mats.PTDF.owner, self.mats)
47
+ self.assertIs(self.mats.LODF.owner, self.mats)
48
+
49
+ def test_MParam_export_csv(self):
50
+ """
51
+ Test MParams export.
52
+ """
53
+ # --- path is not given ---
54
+ exported_csv = self.mats.Cft.export_csv()
55
+ self.assertTrue(os.path.exists(exported_csv))
56
+ os.remove(exported_csv)
57
+
58
+ # --- path is given ---
59
+ path = 'CASE300_Cft.csv'
60
+ exported_csv = self.mats.Cft.export_csv(path)
61
+ self.assertTrue(os.path.exists(path))
62
+ os.remove(path)
63
+
64
+ def test_MParams_export(self) -> None:
65
+ """
66
+ Test MParams export.
67
+ """
68
+ cft = self.mats.Cft.export_csv()
69
+ self.assertTrue(os.path.exists(cft))
70
+ os.remove(cft)
71
+
72
+ cftt = self.mats.CftT.export_csv()
73
+ self.assertTrue(os.path.exists(cftt))
74
+ os.remove(cftt)
75
+
76
+ cg = self.mats.Cg.export_csv()
77
+ self.assertTrue(os.path.exists(cg))
78
+ os.remove(cg)
79
+
80
+ cl = self.mats.Cl.export_csv()
81
+ self.assertTrue(os.path.exists(cl))
82
+ os.remove(cl)
83
+
84
+ csh = self.mats.Csh.export_csv()
85
+ self.assertTrue(os.path.exists(csh))
86
+ os.remove(csh)
87
+
88
+ bbus = self.mats.Bbus.export_csv()
89
+ self.assertTrue(os.path.exists(bbus))
90
+ os.remove(bbus)
91
+
92
+ bf = self.mats.Bf.export_csv()
93
+ self.assertTrue(os.path.exists(bf))
94
+ os.remove(bf)
95
+
96
+ ptdf = self.mats.PTDF.export_csv()
97
+ self.assertTrue(os.path.exists(ptdf))
98
+ os.remove(ptdf)
99
+
100
+ lodf = self.mats.LODF.export_csv()
101
+ self.assertTrue(os.path.exists(lodf))
102
+ os.remove(lodf)
103
+
104
+ def test_MParam_instance(self):
105
+ """
106
+ Test `MParam` instantiate.
107
+ """
108
+ one_vec = MParam(v=sps.csr_matrix(np.ones(self.ss.Bus.n)))
109
+ # check if `_v` is `sps.csr_matrix` instance
110
+ self.assertIsInstance(one_vec._v, sps.csr_matrix)
111
+ # check if `v` is 1D-array
112
+ self.assertEqual(one_vec.v.shape, (self.ss.Bus.n,))
113
+
114
+ def test_c(self):
115
+ """
116
+ Test connectivity matrices.
117
+ """
118
+ # Test `Cg`
119
+ self.assertIsInstance(self.mats.Cg._v, (sps.csr_matrix, sps.lil_matrix))
120
+ self.assertIsInstance(self.mats.Cg.v, np.ndarray)
121
+ self.assertEqual(self.mats.Cg._v.max(), 1)
122
+ np.testing.assert_equal(self.mats.Cg._v.sum(axis=0), np.ones((1, self.ng)))
123
+
124
+ # Test `Cl`
125
+ self.assertIsInstance(self.mats.Cl._v, (sps.csr_matrix, sps.lil_matrix))
126
+ self.assertIsInstance(self.mats.Cl.v, np.ndarray)
127
+ self.assertEqual(self.mats.Cl._v.max(), 1)
128
+ np.testing.assert_equal(self.mats.Cl._v.sum(axis=0), np.ones((1, self.nD)))
129
+
130
+ # Test `Csh`
131
+ self.assertIsInstance(self.mats.Csh._v, (sps.csr_matrix, sps.lil_matrix))
132
+ self.assertIsInstance(self.mats.Csh.v, np.ndarray)
133
+ self.assertEqual(self.mats.Csh._v.max(), 1)
134
+ np.testing.assert_equal(self.mats.Csh._v.sum(axis=0), np.ones((1, self.nsh)))
135
+
136
+ # Test `Cft`
137
+ self.assertIsInstance(self.mats.Cft._v, (sps.csr_matrix, sps.lil_matrix))
138
+ self.assertIsInstance(self.mats.Cft.v, np.ndarray)
139
+ self.assertEqual(self.mats.Cft._v.max(), 1)
140
+ np.testing.assert_equal(self.mats.Cft._v.sum(axis=0), np.zeros((1, self.nl)))
141
+
142
+ def test_b_calc(self):
143
+ """
144
+ Test `b_calc`.
145
+ """
146
+ b = self.mats._calc_b()
147
+ self.assertIsInstance(b, np.ndarray)
148
+ self.assertEqual(b.shape, (self.nl,))
149
+
150
+ def test_bf(self):
151
+ """
152
+ Test `Bf`.
153
+ """
154
+ self.assertIsInstance(self.mats.Bf._v, (sps.csr_matrix, sps.lil_matrix))
155
+ np.testing.assert_equal(self.mats.Bf._v.shape, (self.nl, self.nb))
156
+
157
+ def test_bbus(self):
158
+ """
159
+ Test `Bbus`.
160
+ """
161
+ self.assertIsInstance(self.mats.Bbus._v, (sps.csr_matrix, sps.lil_matrix))
162
+ np.testing.assert_equal(self.mats.Bbus._v.shape, (self.nb, self.nb))
163
+
164
+ def test_pfinj(self):
165
+ """
166
+ Test `Pfinj`.
167
+ """
168
+ self.assertIsInstance(self.mats.Pfinj._v, np.ndarray)
169
+ np.testing.assert_equal(self.mats.Pfinj._v.shape, (self.nl,))
170
+
171
+ def test_pbusinj(self):
172
+ """
173
+ Test `Pbusinj`.
174
+ """
175
+ self.assertIsInstance(self.mats.Pbusinj._v, np.ndarray)
176
+ np.testing.assert_equal(self.mats.Pbusinj._v.shape, (self.nb,))
177
+
178
+
179
+ class TestBuildPTDF(unittest.TestCase):
180
+ """
181
+ Test build PTDF.
182
+ """
183
+
184
+ def setUp(self) -> None:
185
+ self.ss = ams.load(ams.get_case('matpower/case14.m'),
186
+ setup=True, default_config=True, no_output=True)
187
+ self.nl = self.ss.Line.n
188
+ self.nb = self.ss.Bus.n
189
+
190
+ self.assertFalse(self.ss.mats.initialized)
191
+ # NOTE: here we test `no_store=True` option
192
+ self.ptdf_full = self.ss.mats.build_ptdf(no_store=True)
193
+ self.assertTrue(self.ss.mats.initialized)
194
+
195
+ def test_ptdf_before_mat_init(self):
196
+ """
197
+ Test PTDF before MatProcessor initialization `mats.init()`.
198
+ """
199
+ self.assertIsNone(self.ss.mats.PTDF._v)
200
+ _ = self.ss.mats.build_ptdf(no_store=False)
201
+ self.assertEqual(self.ss.mats.PTDF._v.shape, (self.nl, self.nb))
202
+
203
+ def test_ptdf_lines(self):
204
+ """
205
+ Test PTDF with `line` inputs.
206
+ """
207
+ # NOTE: when `line` is given, `PTDF` should not be stored even with `no_store=False`
208
+
209
+ # input str
210
+ ptdf_l2 = self.ss.mats.build_ptdf(line=self.ss.Line.idx.v[2], no_store=False)
211
+ self.assertIsNone(self.ss.mats.PTDF._v)
212
+ np.testing.assert_array_almost_equal(ptdf_l2, self.ptdf_full[2, :])
213
+
214
+ # input list with single element
215
+ ptdf_l2p = self.ss.mats.build_ptdf(line=[self.ss.Line.idx.v[2]], no_store=False)
216
+ self.assertIsNone(self.ss.mats.PTDF._v)
217
+ np.testing.assert_array_almost_equal(ptdf_l2p, self.ptdf_full[[2], :])
218
+
219
+ # input list with multiple elements
220
+ ptdf_l23 = self.ss.mats.build_ptdf(line=self.ss.Line.idx.v[2:4], no_store=False)
221
+ self.assertIsNone(self.ss.mats.PTDF._v)
222
+ np.testing.assert_array_almost_equal(ptdf_l23, self.ptdf_full[2:4, :])
223
+
224
+ def test_ptdf_incremental_lines(self):
225
+ """
226
+ Test PTDF incremental build with `line` inputs.
227
+ """
228
+ # input str
229
+ ptdf_l2 = self.ss.mats.build_ptdf(line=self.ss.Line.idx.v[2], incremental=True, no_store=False,
230
+ no_tqdm=True)
231
+ np.testing.assert_array_almost_equal(ptdf_l2.todense(),
232
+ self.ptdf_full[[2], :])
233
+ self.assertTrue(sps.isspmatrix_lil(ptdf_l2))
234
+ self.assertIsNone(self.ss.mats.PTDF._v)
235
+
236
+ # input list with single element
237
+ ptdf_l2p = self.ss.mats.build_ptdf(line=[self.ss.Line.idx.v[2]], incremental=True, no_store=False,
238
+ no_tqdm=False)
239
+ np.testing.assert_array_almost_equal(ptdf_l2p.todense(),
240
+ self.ptdf_full[[2], :])
241
+ self.assertTrue(sps.isspmatrix_lil(ptdf_l2p))
242
+ self.assertIsNone(self.ss.mats.PTDF._v)
243
+
244
+ # input list with multiple elements
245
+ ptdf_l23 = self.ss.mats.build_ptdf(line=self.ss.Line.idx.v[2:4], incremental=True, no_store=False)
246
+ np.testing.assert_array_almost_equal(ptdf_l23.todense(),
247
+ self.ptdf_full[2:4, :])
248
+
249
+ def test_ptdf_incremental_step(self):
250
+ """
251
+ Test PTDF incremental build with step.
252
+ """
253
+ # step < line length
254
+ ptdf_c1 = self.ss.mats.build_ptdf(line=self.ss.Line.idx.v[2:4], incremental=True,
255
+ no_store=False, step=1)
256
+ self.assertTrue(sps.isspmatrix_lil(ptdf_c1))
257
+ self.assertIsNone(self.ss.mats.PTDF._v)
258
+ np.testing.assert_array_almost_equal(ptdf_c1.todense(),
259
+ self.ptdf_full[2:4, :],)
260
+
261
+ # step = line length
262
+ ptdf_c2 = self.ss.mats.build_ptdf(line=self.ss.Line.idx.v[2:4], incremental=True,
263
+ no_store=False, step=2)
264
+ self.assertTrue(sps.isspmatrix_lil(ptdf_c2))
265
+ self.assertIsNone(self.ss.mats.PTDF._v)
266
+ np.testing.assert_array_almost_equal(ptdf_c2.todense(),
267
+ self.ptdf_full[2:4, :],)
268
+
269
+ # step > line length
270
+ ptdf_c5 = self.ss.mats.build_ptdf(line=self.ss.Line.idx.v[2:4], incremental=True,
271
+ no_store=False, step=5)
272
+ self.assertTrue(sps.isspmatrix_lil(ptdf_c5))
273
+ self.assertIsNone(self.ss.mats.PTDF._v)
274
+ np.testing.assert_array_almost_equal(ptdf_c5.todense(),
275
+ self.ptdf_full[2:4, :],)
276
+
277
+
278
+ class TestBuildLODF(unittest.TestCase):
279
+ """
280
+ Test build LODF.
281
+ """
282
+
283
+ def setUp(self) -> None:
284
+ self.ss = ams.load(ams.get_case('matpower/case14.m'),
285
+ setup=True, default_config=True, no_output=True)
286
+ self.nl = self.ss.Line.n
287
+ self.nb = self.ss.Bus.n
288
+ self.dec = 4
289
+
290
+ self.assertFalse(self.ss.mats.initialized)
291
+ self.lodf_full = self.ss.mats.build_lodf(no_store=True)
292
+ self.assertTrue(self.ss.mats.initialized)
293
+
294
+ def test_lodf_before_ptdf(self):
295
+ """
296
+ Test LODF before PTDF.
297
+ """
298
+ self.assertIsNone(self.ss.mats.PTDF._v)
299
+ self.assertIsNone(self.ss.mats.LODF._v)
300
+ _ = self.ss.mats.build_lodf(no_store=False)
301
+ self.assertEqual(self.ss.mats.LODF._v.shape, (self.nl, self.nl))
302
+ # PTDF should not be stored for requested building
303
+ self.assertIsNone(self.ss.mats.PTDF._v)
304
+
305
+ def test_lodf_lines(self):
306
+ """
307
+ Test LODF with `line` inputs.
308
+ """
309
+ # input str
310
+ lodf_l2 = self.ss.mats.build_lodf(line=self.ss.Line.idx.v[2], no_store=False)
311
+ np.testing.assert_array_almost_equal(lodf_l2, self.lodf_full[:, 2], decimal=self.dec)
312
+
313
+ # input list with single element
314
+ lodf_l2p = self.ss.mats.build_lodf(line=[self.ss.Line.idx.v[2]], no_store=False)
315
+ np.testing.assert_array_almost_equal(lodf_l2p, self.lodf_full[:, [2]], decimal=self.dec)
316
+
317
+ # input list with multiple elements
318
+ lodf_l23 = self.ss.mats.build_lodf(line=self.ss.Line.idx.v[2:4], no_store=False)
319
+ np.testing.assert_array_almost_equal(lodf_l23, self.lodf_full[:, 2:4], decimal=self.dec)
320
+
321
+ def test_lodf_incremental_lines(self):
322
+ """
323
+ Test LODF incremental build with `line` inputs.
324
+ """
325
+ # input str
326
+ lodf_l2 = self.ss.mats.build_lodf(line=self.ss.Line.idx.v[2], incremental=True, no_store=False)
327
+ np.testing.assert_array_almost_equal(lodf_l2.todense(),
328
+ self.lodf_full[:, [2]],
329
+ decimal=self.dec)
330
+ self.assertTrue(sps.isspmatrix_lil(lodf_l2))
331
+
332
+ # input list with single element
333
+ lodf_l2p = self.ss.mats.build_lodf(line=[self.ss.Line.idx.v[2]], incremental=True, no_store=False)
334
+ np.testing.assert_array_almost_equal(lodf_l2p.todense(),
335
+ self.lodf_full[:, [2]],
336
+ decimal=self.dec)
337
+ self.assertTrue(sps.isspmatrix_lil(lodf_l2p))
338
+
339
+ # input list with multiple elements
340
+ lodf_l23 = self.ss.mats.build_lodf(line=self.ss.Line.idx.v[2:4], incremental=True, no_store=False)
341
+ np.testing.assert_array_almost_equal(lodf_l23.todense(),
342
+ self.lodf_full[:, 2:4],
343
+ decimal=self.dec)
344
+
345
+ def test_lodf_incremental_step(self):
346
+ """
347
+ Test LODF incremental build with step.
348
+ """
349
+ # step < line length
350
+ lodf_c1 = self.ss.mats.build_lodf(line=self.ss.Line.idx.v[2:4], incremental=True,
351
+ no_store=False, step=1)
352
+ self.assertTrue(sps.isspmatrix_lil(lodf_c1))
353
+ np.testing.assert_array_almost_equal(lodf_c1.todense(),
354
+ self.lodf_full[:, 2:4],
355
+ decimal=self.dec)
356
+
357
+ # step = line length
358
+ lodf_c2 = self.ss.mats.build_lodf(line=self.ss.Line.idx.v[2:4], incremental=True,
359
+ no_store=False, step=2)
360
+ self.assertTrue(sps.isspmatrix_lil(lodf_c2))
361
+ np.testing.assert_array_almost_equal(lodf_c2.todense(),
362
+ self.lodf_full[:, 2:4],
363
+ decimal=self.dec)
364
+
365
+ # step > line length
366
+ lodf_c5 = self.ss.mats.build_lodf(line=self.ss.Line.idx.v[2:4], incremental=True,
367
+ no_store=False, step=5)
368
+ self.assertTrue(sps.isspmatrix_lil(lodf_c5))
369
+ np.testing.assert_array_almost_equal(lodf_c5.todense(),
370
+ self.lodf_full[:, 2:4],
371
+ decimal=self.dec)
372
+
373
+
374
+ class TestBuildOTDF(unittest.TestCase):
375
+ """
376
+ Test build OTDF.
377
+ """
378
+
379
+ def setUp(self) -> None:
380
+ self.ss = ams.load(ams.get_case('matpower/case14.m'),
381
+ setup=True, default_config=True, no_output=True)
382
+ self.nl = self.ss.Line.n
383
+ self.nb = self.ss.Bus.n
384
+ self.dec = 4
385
+ _ = self.ss.mats.build()
386
+
387
+ def test_otdf_dense_build(self):
388
+ _ = self.ss.mats.build_ptdf(no_store=False, incremental=False)
389
+ _ = self.ss.mats.build_lodf(no_store=False, incremental=False)
390
+ self.otdf_full = self.ss.mats.build_otdf()
391
+ self.assertEqual(self.otdf_full.shape, (self.nl, self.nb))
392
+
393
+ def test_otdf_sparse_build(self):
394
+ # --- both PTDF and LODF are dense ---
395
+ _ = self.ss.mats.build_ptdf(no_store=False, incremental=False)
396
+ _ = self.ss.mats.build_lodf(no_store=False, incremental=False)
397
+ otdf_dense = self.ss.mats.build_otdf()
398
+
399
+ _ = self.ss.mats.build_ptdf(no_store=False, incremental=True)
400
+ _ = self.ss.mats.build_lodf(no_store=False, incremental=True)
401
+ otdf_sparse = self.ss.mats.build_otdf()
402
+ np.testing.assert_array_almost_equal(otdf_sparse.todense(), otdf_dense,
403
+ decimal=self.dec)
404
+
405
+ # --- PTDF is dense and LODF is sparse ---
406
+ _ = self.ss.mats.build_ptdf(no_store=False, incremental=False)
407
+ _ = self.ss.mats.build_lodf(no_store=False, incremental=True)
408
+ otdf_sps1 = self.ss.mats.build_otdf()
409
+ np.testing.assert_array_almost_equal(otdf_sps1, otdf_dense,
410
+ decimal=self.dec)
411
+
412
+ # --- PTDF is sparse and LODF is dense ---
413
+ _ = self.ss.mats.build_ptdf(no_store=False, incremental=True)
414
+ _ = self.ss.mats.build_lodf(no_store=False, incremental=False)
415
+ otdf_sps2 = self.ss.mats.build_otdf()
416
+ np.testing.assert_array_almost_equal(otdf_sps2.todense(), otdf_dense,
417
+ decimal=self.dec)
418
+
419
+ def test_otdf_lines(self):
420
+ """
421
+ Test OTDF with `line` inputs.
422
+ """
423
+ # --- both PTDF and LODF are dense ---
424
+ _ = self.ss.mats.build_ptdf(no_store=False, incremental=False)
425
+ _ = self.ss.mats.build_lodf(no_store=False, incremental=False)
426
+
427
+ # input str
428
+ otdf_l2 = self.ss.mats.build_otdf(line=self.ss.Line.idx.v[2])
429
+ self.assertEqual(otdf_l2.shape, (self.nl, self.nb))
430
+
431
+ # input list with single element
432
+ otdf_l2p = self.ss.mats.build_otdf(line=[self.ss.Line.idx.v[2]])
433
+ self.assertEqual(otdf_l2p.shape, (self.nl, self.nb))
434
+
435
+ # input list with multiple elements
436
+ otdf_l23 = self.ss.mats.build_otdf(line=self.ss.Line.idx.v[2:4])
437
+ self.assertEqual(otdf_l23.shape, (self.nl, self.nb))