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.
20 #------------------------------------------------------------------------------
22 #------------------------------------------------------------------------------
25 from os
.path
import join
, dirname
, exists
, getsize
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 #-------------------------------------------------------------------------------
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.
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"
64 """ The test runner will execute this method prior to each test.
66 path
= join(DATA_DIR
, self
.case_name
, self
.case_name
+ ".pkl")
67 self
.case
= PickleReader().read(path
)
71 """ Test the vector of bus power injections.
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
)
82 """ Test bus and branch admittance matrices.
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
)
97 """ Test FDPF B matrices.
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
)
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),
150 self
.assertTrue(mfeq2(dSbus_dVa
, mp_dSbus_dVa
.tocsr(), 1e-12),
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 #------------------------------------------------------------------------------
177 #------------------------------------------------------------------------------
179 class CaseTest(unittest
.TestCase
):
180 """ Defines a test case for the Pylon case.
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.
194 case
.buses
[5].p_lmbda
= 1.1
195 case
.generators
[2].mu_pmax
= 1.1
196 case
.branches
[10].p_from
= 1.1
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")
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 #------------------------------------------------------------------------------
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.
268 bus
.v_magnitude
= 0.95
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.
296 bus1
= Bus(name
="Bus 1")
297 bus2
= Bus(name
="Bus 2")
298 bus3
= Bus(name
="Bus 3")
299 c
.buses
= [bus1
, bus2
, bus3
]
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)
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)
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())
330 branch
.mu_s_from
= 90.0
332 branch
.mu_angmin
= 60.0
333 branch
.mu_angmax
= 0.0
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.
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
)
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__":
420 # EOF -------------------------------------------------------------------------