Skip to content

Commit 5ab784b

Browse files
authored
Merge pull request #522 from CURENT/develop
Minor version bump.
2 parents 3adca81 + 7a87ad5 commit 5ab784b

File tree

21 files changed

+268
-39
lines changed

21 files changed

+268
-39
lines changed

CONTRIBUTING.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Types of Contributions
1313
Report Bugs
1414
~~~~~~~~~~~
1515

16-
Report bugs at https://github.com/cuihantao/andes/issues.
16+
Report bugs at https://github.com/curent/andes/issues.
1717

1818
If you are reporting a bug, please include:
1919

@@ -42,7 +42,7 @@ or even on the web in blog posts, articles, and such.
4242
Submit Feedback
4343
~~~~~~~~~~~~~~~
4444

45-
The best way to send feedback is to file an issue at https://github.com/cuihantao/andes/issues.
45+
The best way to send feedback is to file an issue at https://github.com/curent/andes/issues.
4646

4747
If you are proposing a feature:
4848

@@ -97,8 +97,8 @@ Before you submit a pull request, check that it meets these guidelines:
9797
2. If the pull request adds functionality, the docs should be updated. Put
9898
your new functionality into a function with a docstring, and add the
9999
feature to the list in README.rst.
100-
3. The pull request should work for Python 3.6 and up. Check
101-
https://github.com/cuihantao/andes/actions
100+
3. The pull request should work for Python 3.8 and up. Check
101+
https://github.com/curent/andes/actions
102102
and make sure that the tests pass for all supported Python versions.
103103

104104
============

andes/io/matpower.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -272,20 +272,20 @@ def mpc2system(mpc: dict, system) -> bool:
272272
if (data[8] == 0.0) or (data[8] == 1.0 and data[9] == 0.0):
273273
# not a transformer
274274
tf = False
275-
ratio = 1
276-
angle = 0
275+
tap_raio = 1
276+
phase_shift = 0
277277
else:
278278
tf = True
279-
ratio = data[8]
280-
angle = data[9] * deg2rad
279+
tap_raio = data[8]
280+
phase_shift = data[9] * deg2rad
281281

282282
vf = system.Bus.Vn.v[system.Bus.idx2uid(fbus)]
283283
vt = system.Bus.Vn.v[system.Bus.idx2uid(tbus)]
284284
system.add('Line', u=status, name=f'Line {fbus:.0f}-{tbus:.0f}',
285285
Vn1=vf, Vn2=vt,
286286
bus1=fbus, bus2=tbus,
287287
r=r, x=x, b=b,
288-
trans=tf, tap=ratio, phi=angle,
288+
trans=tf, tap=tap_raio, phi=phase_shift,
289289
rate_a=rate_a, rate_b=rate_b, rate_c=rate_c)
290290

291291
if ('bus_name' in mpc) and (len(mpc['bus_name']) == len(system.Bus.name.v)):

andes/io/psse.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,16 @@ def _parse_fshunt_v33(raw, system):
402402

403403

404404
def _parse_gen_v33(raw, system, sw):
405-
# 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11, 12, 13, 14, 15, 16,17,18,19
406-
# I,ID,PG,QG,QT,QB,VS,IREG,MBASE,ZR,ZX,RT,XT,GTAP,STAT,RMPCT,PT,PB,O1,F1
405+
"""
406+
Helper function for parsing static generator section.
407+
"""
408+
409+
# 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
410+
# I, ID, PG, QG, QT, QB, VS, IREG, MBASE, ZR, ZX, RT, XT, GTAP, STAT,
411+
# 15, 16, 17, 18, 19, ..., 26, 27
412+
# RMPCT, PT, PB, O1, F1, ..., O4, F4, WMOD, WPF
413+
# The columns above for v33 is different from the manual of v34.5, which includes two new columns:
414+
# `NREG`` at 8 and `BSLOD` before `O1`
407415

408416
mva = system.config.mva
409417
out = defaultdict(list)
@@ -417,6 +425,7 @@ def _parse_gen_v33(raw, system, sw):
417425
gen_mva = data[8]
418426
gen_idx += 1
419427
status = data[14]
428+
wmod = data[26] if len(data) >= 26 else 0
420429

421430
param = {'Sn': gen_mva, 'Vn': vn, 'u': status,
422431
'bus': bus, 'subidx': subidx,
@@ -428,6 +437,7 @@ def _parse_gen_v33(raw, system, sw):
428437
'v0': data[6],
429438
'ra': data[9], # ra - armature resistance
430439
'xs': data[10], # xs - synchronous reactance
440+
'wmod': wmod, # generator control mode
431441
}
432442

433443
if data[0] in sw.keys():
@@ -443,12 +453,14 @@ def _parse_gen_v33(raw, system, sw):
443453

444454
def _parse_line_v33(raw, system):
445455
#
456+
# 0,1, 2,3,4,5, 6, 7, 8, 9,10,11,12,13, 14,15,16
446457
# I,J,CKT,R,X,B,RATEA,RATEB,RATEC,GI,BI,GJ,BJ,ST,LEN,O1,F1,...,O4,F4
447458
#
448459

449460
out = defaultdict(list)
450461
for data in raw['branch']:
451462
param = {
463+
'u': data[13],
452464
'bus1': data[0], 'bus2': data[1],
453465
'r': data[3], 'x': data[4], 'b': data[5],
454466
'rate_a': data[6], 'rate_b': data[7], 'rate_c': data[8],

andes/models/line/line.py

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
"""
44

55
import numpy as np
6+
67
from andes.core import (ModelData, IdxParam, NumParam, DataParam,
78
Model, ExtAlgeb, ConstService)
9+
from andes.shared import spmatrix
810

911

1012
class LineData(ModelData):
@@ -241,3 +243,168 @@ def get_tf_idx(self):
241243
"""
242244

243245
return np.array(self.idx.v)[self.istf]
246+
247+
def build_y(self):
248+
"""
249+
Build bus admittance matrix. Store the matrix in ``self.Y``.
250+
251+
Returns
252+
-------
253+
Y : spmatrix
254+
Bus admittance matrix.
255+
"""
256+
257+
nb = self.system.Bus.n
258+
259+
y1 = self.u.v * (self.g1.v + self.b1.v * 1j)
260+
y2 = self.u.v * (self.g2.v + self.b2.v * 1j)
261+
y12 = self.u.v / (self.r.v + self.x.v * 1j)
262+
m = self.tap.v * np.exp(1j * self.phi.v)
263+
m2 = self.tap.v**2
264+
mconj = np.conj(m)
265+
266+
# build self and mutual admittances into Y
267+
self.Y = spmatrix((y12 + y1 / m2), self.a1.a, self.a1.a, (nb, nb), 'z')
268+
self.Y -= spmatrix(y12 / mconj, self.a1.a, self.a2.a, (nb, nb), 'z')
269+
self.Y -= spmatrix(y12 / m, self.a2.a, self.a1.a, (nb, nb), 'z')
270+
self.Y += spmatrix(y12 + y2, self.a2.a, self.a2.a, (nb, nb), 'z')
271+
272+
return self.Y
273+
274+
def build_b(self, method='fdpf'):
275+
"""
276+
build Bp and Bpp matrices for fast decoupled power flow and DC power flow.
277+
278+
Results are saved to ``self.Bp`` and ``self.Bpp`` without return.
279+
"""
280+
self.build_Bp(method)
281+
self.build_Bpp(method)
282+
283+
def build_Bp(self, method='fdpf'):
284+
"""
285+
Function for building B' matrix.
286+
287+
The result is saved to ``self.Bp`` and returned
288+
289+
Parameters
290+
----------
291+
method : str
292+
Method for building B' matrix. Choose from 'fdpf', 'fdbx', 'dcpf'.
293+
Returns
294+
-------
295+
Bp : spmatrix
296+
B' matrix.
297+
298+
"""
299+
nb = self.system.Bus.n
300+
301+
if method not in ("fdpf", "fdbx", "dcpf"):
302+
raise ValueError(f"Invalid method {method}; choose from 'fdpf', 'fdbx', 'dcpf'")
303+
304+
# Build B prime matrix -- FDPF
305+
# `y1`` neglects line charging shunt, and g1 is usually 0 in HV lines
306+
# `y2`` neglects line charging shunt, and g2 is usually 0 in HV lines
307+
y1 = self.u.v * self.g1.v
308+
y2 = self.u.v * self.g2.v
309+
310+
# `m` neglected tap ratio
311+
m = np.exp(self.phi.v * 1j)
312+
mconj = np.conj(m)
313+
m2 = np.ones(self.n)
314+
315+
if method in ('fdxb', 'dcpf'):
316+
# neglect line resistance in Bp in XB method
317+
y12 = self.u.v / (self.x.v * 1j)
318+
else:
319+
y12 = self.u.v / (self.r.v + self.x.v * 1j)
320+
321+
self.Bdc = spmatrix((y12 + y1) / m2, self.a1.a, self.a1.a, (nb, nb), 'z')
322+
self.Bdc -= spmatrix(y12 / mconj, self.a1.a, self.a2.a, (nb, nb), 'z')
323+
self.Bdc -= spmatrix(y12 / m, self.a2.a, self.a1.a, (nb, nb), 'z')
324+
self.Bdc += spmatrix(y12 + y2, self.a2.a, self.a2.a, (nb, nb), 'z')
325+
self.Bdc = self.Bdc.imag()
326+
327+
for item in range(nb):
328+
if abs(self.Bdc[item, item]) == 0:
329+
self.Bdc[item, item] = 1e-6 + 0j
330+
331+
return self.Bdc
332+
333+
def build_Bpp(self, method='fdpf'):
334+
"""
335+
Function for building B'' matrix.
336+
337+
The result is saved to ``self.Bpp`` and returned
338+
339+
Parameters
340+
----------
341+
method : str
342+
Method for building B'' matrix. Choose from 'fdpf', 'fdbx', 'dcpf'.
343+
344+
Returns
345+
-------
346+
Bpp : spmatrix
347+
B'' matrix.
348+
"""
349+
350+
nb = self.system.Bus.n
351+
352+
if method not in ("fdpf", "fdbx", "dcpf"):
353+
raise ValueError(f"Invalid method {method}; choose from 'fdpf', 'fdbx', 'dcpf'")
354+
355+
# Build B double prime matrix
356+
# y1 neglected line charging shunt, and g1 is usually 0 in HV lines
357+
# y2 neglected line charging shunt, and g2 is usually 0 in HV lines
358+
# m neglected phase shifter
359+
y1 = self.u.v * (self.g1.v + self.b1.v * 1j)
360+
y2 = self.u.v * (self.g2.v + self.b2.v * 1j)
361+
362+
m = self.tap.v
363+
m2 = abs(m)**2
364+
365+
if method in ('fdbx', 'fdpf', 'dcpf'):
366+
# neglect line resistance in Bpp in BX method
367+
y12 = self.u.v / (self.x.v * 1j)
368+
else:
369+
y12 = self.u.v / (self.r.v + self.x.v * 1j)
370+
371+
self.Bpp = spmatrix((y12 + y1) / m2, self.a1.a, self.a1.a, (nb, nb), 'z')
372+
self.Bpp -= spmatrix(y12 / np.conj(m), self.a1.a, self.a2.a, (nb, nb), 'z')
373+
self.Bpp -= spmatrix(y12 / m, self.a2.a, self.a1.a, (nb, nb), 'z')
374+
self.Bpp += spmatrix(y12 + y2, self.a2.a, self.a2.a, (nb, nb), 'z')
375+
self.Bpp = self.Bpp.imag()
376+
377+
for item in range(nb):
378+
if abs(self.Bpp[item, item]) == 0:
379+
self.Bpp[item, item] = 1e-6 + 0j
380+
381+
return self.Bpp
382+
383+
def build_Bdc(self):
384+
"""
385+
The MATPOWER-flavor Bdc matrix for DC power flow. Saves results to `self.Bdc`.
386+
387+
The method neglects line charging and line resistance. It retains tap ratio.
388+
389+
Returns
390+
-------
391+
Bdc : spmatrix
392+
Bdc matrix.
393+
"""
394+
395+
nb = self.system.Bus.n
396+
397+
y12 = self.u.v / (self.x.v * 1j)
398+
y12 = y12 / self.tap.v
399+
400+
self.Bdc = spmatrix(y12, self.a1.a, self.a1.a, (nb, nb), 'z')
401+
self.Bdc -= spmatrix(y12, self.a1.a, self.a2.a, (nb, nb), 'z')
402+
self.Bdc -= spmatrix(y12, self.a2.a, self.a1.a, (nb, nb), 'z')
403+
self.Bdc += spmatrix(y12, self.a2.a, self.a2.a, (nb, nb), 'z')
404+
self.Bdc = self.Bdc.imag()
405+
406+
for item in range(nb):
407+
if abs(self.Bdc[item, item]) == 0:
408+
self.Bdc[item, item] = 1e-6
409+
410+
return self.Bdc

andes/models/static/pv.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,19 @@ def __init__(self):
3636
self.ra = NumParam(default=0.0, info='armature resistance', tex_name='r_a')
3737
self.xs = NumParam(default=0.3, info='armature reactance', tex_name='x_s')
3838

39+
# `wmod`: generator model included in PSS/E file; not yet used in ANDES
40+
# 0: conventional
41+
# 1: renewable standard QT/ QB limits
42+
# 2: renewable +, - Qlimits based on WPF
43+
# 3: renewable, fixed Qlimit based on WPF
44+
# 4: Infeed machine
45+
self.wmod = NumParam(default=0,
46+
info='Machine ctrl. mode [PSS/E]',
47+
tex_name=r'w_{mod}',
48+
unit='int',
49+
export=False,
50+
)
51+
3952

4053
class PVModel(Model):
4154
"""

andes/routines/eig.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,16 +103,18 @@ def _reduce(self, fx, fy, gx, gy, Tf, dense=True):
103103
spmatrix
104104
The reduced state matrix
105105
"""
106-
gyx = matrix(gx)
107-
self.solver.linsolve(gy, gyx)
106+
self.gyx = matrix(gx)
107+
self.solver.linsolve(gy, self.gyx)
108108

109109
Tfnz = Tf + np.ones_like(Tf) * np.equal(Tf, 0.0)
110110
iTf = spdiag((1 / Tfnz).tolist())
111111

112+
self.fxy = (fx - fy * self.gyx)
113+
112114
if dense:
113-
return iTf * (fx - fy * gyx)
115+
return iTf * self.fxy
114116
else:
115-
return sparse(iTf * (fx - fy * gyx))
117+
return sparse(iTf * self.fxy)
116118

117119
def _reorder(self):
118120
"""

andes/system.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""
2-
System class for power system data and methods
2+
System class for power system data and methods.
33
"""
44

5-
# [ANDES] (C)2015-2022 Hantao Cui
5+
# [ANDES] (C)2015-2024 Hantao Cui
66
#
77
# This program is free software; you can redistribute it and/or modify
88
# it under the terms of the GNU General Public License as published by

andes/variables/dae.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ class DAE:
282282
+===========+=============================================+
283283
| m | The number of algebraic variables/equations |
284284
+-----------+---------------------------------------------+
285-
| n | The number of algebraic variables/equations |
285+
| n | The number of state variables/equations |
286286
+-----------+---------------------------------------------+
287287
| o | The number of limiter state flags |
288288
+-----------+---------------------------------------------+

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@
125125

126126
html_context = {
127127
"github_url": "https://github.com",
128-
"github_user": "cuihantao",
128+
"github_user": "curent",
129129
"github_repo": "andes",
130130
"github_version": "master",
131131
"doc_path": "docs/source",

docs/source/examples/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ Examples
66
A collection of examples are presented to supplement the tutorial. The
77
examples below are identical to the Jupyter Notebook in the ``examples``
88
folder of the repository
9-
`here <https://github.com/cuihantao/andes/tree/master/examples>`__. You
9+
`here <https://github.com/curent/andes/tree/master/examples>`__. You
1010
can run the examples in a live Jupyter Notebook online using
11-
`Binder <https://mybinder.org/v2/gh/cuihantao/andes/master>`__.
11+
`Binder <https://mybinder.org/v2/gh/curent/andes/master>`__.
1212

1313
.. toctree::
1414
:maxdepth: 2

0 commit comments

Comments
 (0)