Merge pull request #5 from cuihantao/master
[pylon.git] / pylon / test / case_test.py
blob52e540481cee865d8402803d081a577317996921
1 #------------------------------------------------------------------------------
2 # Copyright (C) 2007-2010 Richard Lincoln
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #------------------------------------------------------------------------------
17 """ Defines the case test case.
18 """
20 #------------------------------------------------------------------------------
21 # Imports:
22 #------------------------------------------------------------------------------
24 import os
25 from os.path import join, dirname, exists, getsize
26 import unittest
27 import tempfile
28 from numpy import complex128
30 from scipy import alltrue
31 from scipy.io.mmio import mmread
33 from pylon import Case, Bus, Branch, Generator, NewtonPF, XB, BX
34 from pylon.io import PickleReader
35 from pylon.util import CaseReport, mfeq2
37 #-------------------------------------------------------------------------------
38 # Constants:
39 #-------------------------------------------------------------------------------
41 MP_DATA_FILE = join(dirname(__file__), "data", "case6ww.m")
42 DATA_FILE = join(dirname(__file__), "data", "case6ww","case6ww.pkl")
43 PWL_FILE = join(dirname(__file__), "data", "case30pwl", "case30pwl.pkl")
44 DATA_DIR = join(dirname(__file__), "data")
46 #------------------------------------------------------------------------------
47 # "CaseMatrixTest" class:
48 #------------------------------------------------------------------------------
50 class CaseMatrixTest(unittest.TestCase):
51 """ Defines a test case for the Pylon case.
52 """
54 def __init__(self, methodName='runTest'):
55 super(CaseMatrixTest, self).__init__(methodName)
57 #: Name of the folder in which the MatrixMarket data exists.
58 self.case_name = "case6ww"
60 self.case = None
63 def setUp(self):
64 """ The test runner will execute this method prior to each test.
65 """
66 path = join(DATA_DIR, self.case_name, self.case_name + ".pkl")
67 self.case = PickleReader().read(path)
70 def testSbus(self):
71 """ Test the vector of bus power injections.
72 """
73 Sbus = self.case.Sbus
74 mpSbus = mmread(join(DATA_DIR, self.case_name, "Sbus.mtx")).flatten()
76 # self.assertTrue(alltrue(Sbus == mpSbus))
77 # FIXME: Improve accuracy.
78 self.assertTrue(abs(max(Sbus - mpSbus)) < 1e-06, msg=self.case_name)
81 def testYbus(self):
82 """ Test bus and branch admittance matrices.
83 """
84 self.case.index_buses()
85 Ybus, Yf, Yt = self.case.Y
87 mpYbus = mmread(join(DATA_DIR, self.case_name, "Ybus.mtx")).tocsr()
88 mpYf = mmread(join(DATA_DIR, self.case_name, "Yf.mtx")).tocsr()
89 mpYt = mmread(join(DATA_DIR, self.case_name, "Yt.mtx")).tocsr()
91 self.assertTrue(mfeq2(Ybus, mpYbus, diff=1e-12), self.case_name)
92 self.assertTrue(mfeq2(Yf, mpYf, diff=1e-12), self.case_name)
93 self.assertTrue(mfeq2(Yt, mpYt, diff=1e-12), self.case_name)
96 def testB(self):
97 """ Test FDPF B matrices.
98 """
99 self.case.index_buses()
100 xbBp, xbBpp = self.case.makeB(method=XB)
102 mpxbBp = mmread(join(DATA_DIR, self.case_name, "Bp_XB.mtx")).tocsr()
103 mpxbBpp = mmread(join(DATA_DIR, self.case_name, "Bpp_XB.mtx")).tocsr()
105 self.assertTrue(mfeq2(xbBp, mpxbBp, diff=1e-12), self.case_name)
106 self.assertTrue(mfeq2(xbBpp, mpxbBpp, diff=1e-12), self.case_name)
108 bxBp, bxBpp = self.case.makeB(method=BX)
110 mpbxBp = mmread(join(DATA_DIR, self.case_name, "Bp_BX.mtx")).tocsr()
111 mpbxBpp = mmread(join(DATA_DIR, self.case_name, "Bpp_BX.mtx")).tocsr()
113 self.assertTrue(mfeq2(bxBp, mpbxBp, diff=1e-12), self.case_name)
114 self.assertTrue(mfeq2(bxBpp, mpbxBpp, diff=1e-12), self.case_name)
117 def testBdc(self):
118 """ Test DCPF B matrices and phase shift injection vectors.
120 self.case.index_buses()
121 B, Bf, Pbusinj, Pfinj = self.case.Bdc
123 mpB = mmread(join(DATA_DIR, self.case_name, "B.mtx")).tocsr()
124 self.assertTrue(mfeq2(B, mpB, diff=1e-12), self.case_name)
126 mpBf = mmread(join(DATA_DIR, self.case_name, "Bf.mtx")).tocsr()
127 self.assertTrue(mfeq2(Bf, mpBf, diff=1e-12), self.case_name)
129 mpPbusinj = mmread(join(DATA_DIR, self.case_name,
130 "Pbusinj.mtx")).flatten()
131 self.assertTrue(abs(max(Pbusinj - mpPbusinj)) < 1e-14, self.case_name)
133 mpPfinj = mmread(join(DATA_DIR, self.case_name, "Pfinj.mtx")).flatten()
134 self.assertTrue(abs(max(Pfinj - mpPfinj)) < 1e-14, self.case_name)
137 def test_dSbus_dV(self):
138 """ Test partial derivative of power injection w.r.t. voltage.
140 mpYbus = mmread(join(DATA_DIR, self.case_name, "Ybus.mtx")).tocsr()
141 mpV0 = mmread(join(DATA_DIR, self.case_name, "V0.mtx")).flatten()
143 dSbus_dVm, dSbus_dVa = self.case.dSbus_dV(mpYbus, mpV0)
145 mp_dSbus_dVm = mmread(join(DATA_DIR, self.case_name, "dSbus_dVm0.mtx"))
146 mp_dSbus_dVa = mmread(join(DATA_DIR, self.case_name, "dSbus_dVa0.mtx"))
148 self.assertTrue(mfeq2(dSbus_dVm, mp_dSbus_dVm.tocsr(), 1e-12),
149 self.case_name)
150 self.assertTrue(mfeq2(dSbus_dVa, mp_dSbus_dVa.tocsr(), 1e-12),
151 self.case_name)
153 #------------------------------------------------------------------------------
154 # "CaseMatrix24RTSTest" class:
155 #------------------------------------------------------------------------------
157 class CaseMatrix24RTSTest(CaseMatrixTest):
159 def __init__(self, methodName='runTest'):
160 super(CaseMatrix24RTSTest, self).__init__(methodName)
162 self.case_name = "case24_ieee_rts"
164 #------------------------------------------------------------------------------
165 # "CaseMatrixIEEE30Test" class:
166 #------------------------------------------------------------------------------
168 class CaseMatrixIEEE30Test(CaseMatrixTest):
170 def __init__(self, methodName='runTest'):
171 super(CaseMatrixIEEE30Test, self).__init__(methodName)
173 self.case_name = "case_ieee30"
175 #------------------------------------------------------------------------------
176 # "CaseTest" class:
177 #------------------------------------------------------------------------------
179 class CaseTest(unittest.TestCase):
180 """ Defines a test case for the Pylon case.
183 def setUp(self):
184 """ The test runner will execute this method prior to each test.
186 self.case = PickleReader().read(DATA_FILE)
189 def test_reset(self):
190 """ Test zeroing of result attributes.
192 case = self.case
194 case.buses[5].p_lmbda = 1.1
195 case.generators[2].mu_pmax = 1.1
196 case.branches[10].p_from = 1.1
198 case.reset()
200 self.assertEqual(case.buses[5].p_lmbda, 0.0)
201 self.assertEqual(case.generators[2].mu_pmax, 0.0)
202 self.assertEqual(case.branches[10].p_from, 0.0)
205 def test_sort_generators(self):
206 """ Test ordering of generators according to bus index.
208 case = PickleReader().read(PWL_FILE)
210 self.assertEqual(case.buses.index(case.generators[2].bus), 21)
211 self.assertEqual(case.buses.index(case.generators[5].bus), 12)
213 case.sort_generators()
215 self.assertEqual(case.buses.index(case.generators[2].bus), 12)
216 self.assertEqual(case.buses.index(case.generators[5].bus), 26)
218 #--------------------------------------------------------------------------
219 # Serialisation tests.
220 #--------------------------------------------------------------------------
222 def test_load_matpower(self):
223 """ Test loading a MATPOWER data file.
225 case = Case.load(MP_DATA_FILE, "matpower")
227 self.assertEqual(len(case.generators), 3)
228 self.assertTrue(isinstance(case, Case))
231 def test_infer_matpower_format(self):
232 """ Test inference of MATPOWER format from file extension.
234 case = Case.load(MP_DATA_FILE) # Format not specified.
236 self.assertEqual(len(case.generators), 3)
237 self.assertTrue(isinstance(case, Case))
240 def test_save_matpower(self):
241 """ Test saving a case in MATPOWER format.
243 tmp_fd, tmp_name = tempfile.mkstemp(".m")
244 os.close(tmp_fd)
245 os.remove(tmp_name)
246 # os.unlink(tmp_name)
248 self.assertFalse(exists(tmp_name))
250 self.case.save(tmp_name)
252 self.assertTrue(exists(tmp_name))
253 self.assertTrue(getsize(tmp_name) > 0)
256 #------------------------------------------------------------------------------
257 # "BusTest" class:
258 #------------------------------------------------------------------------------
260 class BusTest(unittest.TestCase):
261 """ Test case for the Bus class.
264 def test_reset(self):
265 """ Test initialisation of bus result attributes.
267 bus = Bus()
268 bus.v_magnitude = 0.95
269 bus.v_angle = 15.0
270 bus.p_lmbda = 50.0
271 bus.q_lmbda = 20.0
272 bus.mu_vmin = 10.0
273 bus.mu_vmax = 10.0
275 bus.reset()
277 self.assertEqual(bus.v_magnitude, 0.95)
278 self.assertEqual(bus.v_angle, 15.0)
279 self.assertEqual(bus.p_lmbda, 0.0)
280 self.assertEqual(bus.q_lmbda, 0.0)
281 self.assertEqual(bus.mu_vmin, 0.0)
282 self.assertEqual(bus.mu_vmax, 0.0)
284 #------------------------------------------------------------------------------
285 # "BranchTest" class:
286 #------------------------------------------------------------------------------
288 class BranchTest(unittest.TestCase):
289 """ Test case for the Branch class.
292 def test_bus_indexes(self):
293 """ Test the from/to bus index property.
295 c = Case(name="c")
296 bus1 = Bus(name="Bus 1")
297 bus2 = Bus(name="Bus 2")
298 bus3 = Bus(name="Bus 3")
299 c.buses = [bus1, bus2, bus3]
301 # Append to list.
302 branch1 = Branch(bus3, bus1)
303 c.branches.append(branch1)
305 self.assertEqual(c.buses.index(branch1.from_bus), 2)
306 self.assertEqual(c.buses.index(branch1.to_bus), 0)
308 # Set list.
309 branch2 = Branch(bus2, bus3)
310 branch3 = Branch(bus2, bus1)
311 c.branches = [branch2, branch3]
313 self.assertEqual(c.buses.index(branch2.from_bus), 1)
314 self.assertEqual(c.buses.index(branch2.to_bus), 2)
316 # Move branch.
317 branch2.from_bus = bus1
318 self.assertEqual(c.buses.index(branch2.from_bus), 0)
321 def test_reset(self):
322 """ Test initialisation of bus result attributes.
324 branch = Branch(Bus(), Bus())
326 branch.p_from = 25.0
327 branch.p_to = -25.0
328 branch.q_from = -9.0
329 branch.q_to = 9.0
330 branch.mu_s_from = 90.0
331 branch.mu_s_to = 0.0
332 branch.mu_angmin = 60.0
333 branch.mu_angmax = 0.0
335 branch.reset()
337 self.assertEqual(branch.p_from, 0.0)
338 self.assertEqual(branch.p_to, 0.0)
339 self.assertEqual(branch.q_from, 0.0)
340 self.assertEqual(branch.q_to, 0.0)
341 self.assertEqual(branch.mu_s_from, 0.0)
342 self.assertEqual(branch.mu_s_to, 0.0)
343 self.assertEqual(branch.mu_angmin, 0.0)
344 self.assertEqual(branch.mu_angmax, 0.0)
346 #------------------------------------------------------------------------------
347 # "CaseReportTest" class:
348 #------------------------------------------------------------------------------
350 class CaseReportTest(unittest.TestCase):
351 """ Defines a test case for the Pylon case report.
354 def setUp(self):
355 """ The test runner will execute this method prior to each test.
357 self.case = PickleReader().read(PWL_FILE)
360 def test_report(self):
361 """ Test case report property values.
363 NewtonPF(self.case).solve()
364 report = CaseReport(self.case)
365 pl = 3
367 self.assertEqual(report.n_buses, 30)
368 self.assertEqual(report.n_connected_buses, 30)
369 self.assertEqual(report.n_generators, 6)
370 self.assertEqual(report.n_online_generators, 6)
371 self.assertEqual(report.n_loads, 20)
372 self.assertEqual(report.n_fixed_loads, 20)
373 self.assertEqual(report.n_online_vloads, 0)
374 self.assertEqual(report.n_shunts, 2)
375 self.assertEqual(report.n_branches, 41)
376 self.assertEqual(report.n_transformers, 0)
377 self.assertEqual(report.n_interties, 7)
378 self.assertEqual(report.n_areas, 3)
380 self.assertAlmostEqual(report.total_pgen_capacity, 335.0, pl)
381 self.assertAlmostEqual(report.total_qgen_capacity[0], -95.0, pl)
382 self.assertAlmostEqual(report.total_qgen_capacity[1], 405.9, pl)
383 self.assertAlmostEqual(report.online_pgen_capacity, 335.0, pl)
384 self.assertAlmostEqual(report.online_qgen_capacity[0], -95.0, pl)
385 self.assertAlmostEqual(report.online_qgen_capacity[1], 405.9, pl)
386 self.assertAlmostEqual(report.actual_pgen, 191.644, pl)
387 self.assertAlmostEqual(report.actual_qgen, 100.415, pl)
388 self.assertAlmostEqual(report.fixed_p_demand, 189.2, pl)
389 self.assertAlmostEqual(report.fixed_q_demand, 107.2, pl)
390 self.assertAlmostEqual(report.vload_p_demand[0], 0.0, pl)
391 self.assertAlmostEqual(report.vload_p_demand[1], 0.0, pl)
392 self.assertAlmostEqual(report.p_demand, 189.2, pl)
393 self.assertAlmostEqual(report.q_demand, 107.2, pl)
394 self.assertAlmostEqual(report.shunt_pinj, 0.0, pl)
395 self.assertAlmostEqual(report.shunt_qinj, 0.222, pl)
396 self.assertAlmostEqual(report.losses[0], 2.4438, pl)
397 self.assertAlmostEqual(report.losses[1], 8.9899, pl)
398 self.assertAlmostEqual(report.branch_qinj, 15.553, pl)
399 self.assertAlmostEqual(report.total_tie_pflow, 33.181, pl)
400 self.assertAlmostEqual(report.total_tie_qflow, 27.076, pl)
401 self.assertAlmostEqual(report.min_v_magnitude[0], 0.961, pl)
402 self.assertEqual(report.min_v_magnitude[1], 7)
403 self.assertAlmostEqual(report.max_v_magnitude[0], 1.000, pl)
404 # self.assertEqual(report.max_v_magnitude[1], 0)
405 self.assertAlmostEqual(report.min_v_angle[0], -3.9582, pl)
406 self.assertEqual(report.min_v_angle[1], 18)
407 self.assertAlmostEqual(report.max_v_angle[0], 1.4762, pl)
408 self.assertEqual(report.max_v_angle[1], 12)
409 self.assertAlmostEqual(report.max_p_losses[0], 0.2892, pl)
410 self.assertEqual(report.max_p_losses[1], 1)
411 self.assertEqual(report.max_p_losses[2], 5)
412 self.assertAlmostEqual(report.max_q_losses[0], 2.0970, pl)
413 self.assertEqual(report.max_q_losses[1], 11)
414 self.assertEqual(report.max_q_losses[2], 12)
417 if __name__ == "__main__":
418 unittest.main()
420 # EOF -------------------------------------------------------------------------