Skip to content

Commit

Permalink
Merge pull request #141 from cuihantao/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
cuihantao authored Jun 2, 2021
2 parents d34ce8e + 710839d commit 90f8ee8
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 25 deletions.
17 changes: 17 additions & 0 deletions andes/core/npfunc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import numpy as np


def safe_div(a, b, out=None):
"""
Safe division for numpy. Division by zero yields zero.
`safe_div` cannot be used in `e_str` due to unsupported Derivative.
Parameters
----------
out : None or array-like
If not None, out contains the default values for where b==0.
"""
if out is None:
out = np.zeros_like(a)

return np.divide(a, b, out=np.zeros_like(a), where=(b != 0))
7 changes: 6 additions & 1 deletion andes/core/symprocessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from sympy import sympify, lambdify, latex, SympifyError
from sympy import SparseMatrix

from andes.core.npfunc import safe_div
from andes.shared import dilled_vars
from andes.utils.paths import get_pycode_path

Expand Down Expand Up @@ -135,6 +136,7 @@ def generate_symbols(self):
self.lambdify_func[0]['real'] = np.real
self.lambdify_func[0]['im'] = np.imag
self.lambdify_func[0]['re'] = np.real
self.lambdify_func[0]['safe_div'] = safe_div

self.vars_list = list(self.vars_dict.values()) # useful for ``.jacobian()``

Expand Down Expand Up @@ -379,6 +381,8 @@ def generate_pycode(self, pycode_path):
from numpy import arcsin, arccos, arctan # NOQA
from numpy import log # NOQA
from andes.core.npfunc import * # NOQA
"""

Expand Down Expand Up @@ -524,7 +528,8 @@ def generate_init_eqn(self):
if instance.v_str is not None:
self.init_asn[item] = self.v_str_syms[item]
if instance.v_iter is not None:
self.init_itn[item] = self.v_iter_syms[item]
self.init_itn[item] = Matrix([self.v_iter_syms[item]])
self.init_itn_vars[item] = [item]

elif isinstance(item, list):
name_concat = '_'.join(item)
Expand Down
12 changes: 7 additions & 5 deletions andes/models/exciter/esdc2a.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,14 @@ def __init__(self, system, config):
info='Field voltage saturation',
)

# NOTE: Se0 below is not divided by `vf0` or `INT_y`
# `Se0` is the variable `Vx` in Powerworld's diagram
self.Se0 = ConstService(
tex_name='S_{e0}',
v_str='Indicator(vf0>SAT_A) * SAT_B*(SAT_A-vf0) ** 2 / vf0',
v_str='Indicator(vf0>SAT_A) * SAT_B*(SAT_A-vf0) ** 2',
)

self.vfe0 = ConstService(v_str='vf0 * (KE + Se0)',
self.vfe0 = ConstService(v_str='vf0*KE + Se0',
tex_name='V_{FE0}',
)
self.vref0 = ConstService(info='Initial reference voltage input',
Expand Down Expand Up @@ -182,16 +184,16 @@ def __init__(self, system, config):
cache=False,
)

self.Se = Algeb(tex_name=r"S_e(|V_{out}|)", info='saturation output',
self.Se = Algeb(tex_name=r"V_{out}*S_e(|V_{out}|)", info='saturation output',
v_str='Se0',
e_str='SL_z0 * (INT_y - SAT_A) ** 2 * SAT_B / INT_y - Se',
e_str='SL_z0 * (INT_y - SAT_A) ** 2 * SAT_B - Se',
)

self.VFE = Algeb(info='Combined saturation feedback',
tex_name='V_{FE}',
unit='p.u.',
v_str='vfe0',
e_str='INT_y * (KE + Se) - VFE'
e_str='(INT_y*KE + Se) - VFE'
)

self.INT = Integrator(u='ue * (LA_y - VFE)',
Expand Down
7 changes: 4 additions & 3 deletions andes/models/exciter/esst3a.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,9 @@ def __init__(self, system, config):

self.IN = Algeb(tex_name='I_N',
info='Input to FEX',
v_str='KC * XadIfd / VE',
e_str='KC * XadIfd / VE - IN',
v_str='safe_div(KC * XadIfd, VE)',
e_str='ue * (KC * XadIfd - VE * IN)',
diag_eps=True,
)

self.FEX = Piecewise(u=self.IN,
Expand Down Expand Up @@ -220,7 +221,7 @@ def __init__(self, system, config):

self.vrs = Algeb(tex_name='V_{RS}',
info='VR subtract feedback VG',
v_str='vf0 / VB_y / KM',
v_str='safe_div(vf0, VB_y) / KM',
e_str='LAW1_y - VG_y - vrs',
)

Expand Down
7 changes: 4 additions & 3 deletions andes/models/exciter/esst4b.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,9 @@ def __init__(self, system, config):

self.IN = Algeb(tex_name='I_N',
info='Input to FEX',
v_str='KC * XadIfd / VE',
e_str='KC * XadIfd / VE - IN',
v_str='safe_div(KC * XadIfd, VE)',
e_str='ue * (KC * XadIfd - VE * IN)',
diag_eps=True,
)

self.FEX = Piecewise(u=self.IN,
Expand Down Expand Up @@ -247,7 +248,7 @@ def __init__(self, system, config):
ks=self.config.ksm,
lower=self.VMMIN,
upper=self.VMMAX,
x0='vf0 / VB_y',
x0='safe_div(vf0, VB_y)',
)

# TODO: add back LV Gate
Expand Down
18 changes: 10 additions & 8 deletions andes/models/exciter/exac1.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,16 @@ def __init__(self, system, config):
info='Input to FEX',
v_str='1',
v_iter='KC * XadIfd - INT_y * IN',
e_str='KC * XadIfd - INT_y * IN',)
e_str='ue * (KC * XadIfd - INT_y * IN)',
diag_eps=True,
)

self.FEX = Piecewise(u=self.IN,
points=(0, 0.433, 0.75, 1),
funs=('1', '1 - 0.577*IN', 'sqrt(0.75 - IN ** 2)', '1.732*(1 - IN)', 0),
info='Piecewise function FEX',
)
self.FEX.y.v_iter = '1'
self.FEX.y.v_str = '1'
self.FEX.y.v_iter = self.FEX.y.e_str

self.LG = Lag(self.v, T=self.TR, K=1,
Expand Down Expand Up @@ -158,16 +160,16 @@ def __init__(self, system, config):

self.SL = LessThan(u=self.INT_y, bound=self.SAT_A, equal=False, enable=True, cache=False)

self.Se = Algeb(tex_name=r"S_e(|V_{out}|)", info='saturation output',
v_str='Indicator(INT_y > SAT_A) * SAT_B * (INT_y - SAT_A) ** 2 / INT_y',
e_str='SL_z0 * (INT_y - SAT_A) ** 2 * SAT_B / INT_y - Se',
self.Se = Algeb(tex_name=r"V_{out}*S_e(|V_{out}|)", info='saturation output',
v_str='Indicator(INT_y > SAT_A) * SAT_B * (INT_y - SAT_A) ** 2',
e_str='SL_z0 * (INT_y - SAT_A) ** 2 * SAT_B - Se',
)

self.VFE = Algeb(info='Combined saturation feedback',
tex_name='V_{FE}',
unit='p.u.',
v_str='INT_y * (KE + Se) + XadIfd * KD',
e_str='INT_y * (KE + Se) + XadIfd * KD - VFE'
v_str='INT_y * KE + Se + XadIfd * KD',
e_str='INT_y * KE + Se + XadIfd * KD - VFE'
)

self.vref = Algeb(info='Reference voltage input',
Expand All @@ -188,7 +190,7 @@ def __init__(self, system, config):
info='Stablizing circuit feedback',
)

self.vout.e_str = 'INT_y * FEX_y - vout'
self.vout.e_str = 'ue * INT_y * FEX_y - vout'


class EXAC1(EXAC1Data, EXAC1Model):
Expand Down
10 changes: 5 additions & 5 deletions andes/models/exciter/ieeet1.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,19 @@ def __init__(self, system, config):

self.Se0 = ConstService(info='Initial saturation output',
tex_name='S_{e0}',
v_str='Indicator(vf0>SAT_A) * SAT_B * (SAT_A - vf0) ** 2 / vf0',
v_str='Indicator(vf0>SAT_A) * SAT_B * (SAT_A - vf0) ** 2',
)
self.vr0 = ConstService(info='Initial vr',
tex_name='V_{r0}',
v_str='(KE + Se0) * vf0')
v_str='KE * vf0 + Se0')
self.vb0 = ConstService(info='Initial vb',
tex_name='V_{b0}',
v_str='vr0 / KA')
self.vref0 = ConstService(info='Initial reference voltage input',
tex_name='V_{ref0}',
v_str='v + vb0',
)
self.vfe0 = ConstService(v_str='vf0 * (KE + Se0)',
self.vfe0 = ConstService(v_str='vf0 * KE + Se0',
tex_name='V_{FE0}',
)

Expand Down Expand Up @@ -150,7 +150,7 @@ def __init__(self, system, config):
tex_name='V_{FE}',
unit='p.u.',
v_str='vfe0',
e_str='INT_y * (KE + Se) - VFE'
e_str='INT_y * KE + Se - VFE'
)

self.INT = Integrator(u='LA_y - VFE',
Expand All @@ -164,7 +164,7 @@ def __init__(self, system, config):

self.Se = Algeb(tex_name=r"S_e(|V_{out}|)", info='saturation output',
v_str='Se0',
e_str='SL_z0 * (INT_y - SAT_A) ** 2 * SAT_B / INT_y - Se',
e_str='SL_z0 * (INT_y - SAT_A) ** 2 * SAT_B - Se',
)

self.WF = Washout(u=self.vout, T=self.TF, K=self.KF, info='Stablizing circuit feedback')
Expand Down
5 changes: 5 additions & 0 deletions docs/source/release-notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ The APIs before v3.0.0 are in beta and may change without prior notice.

v1.3 Notes
----------
v1.3.9 (2021-06-02)
```````````````````
- Bug fixes in exciters when generators are offline.
- Added `safe_div` function for initialization equations.

v1.3.8 (2021-06-02)
```````````````````
- Added `REGCVSG` model for voltage-source controlled renewables.
Expand Down

0 comments on commit 90f8ee8

Please sign in to comment.