Skip to content

Commit

Permalink
Merge pull request #43 from jinningwang/doc
Browse files Browse the repository at this point in the history
Doc
  • Loading branch information
jinningwang authored Feb 21, 2024
2 parents 0e8ab69 + 3f69fc0 commit 85834f9
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 27 deletions.
2 changes: 2 additions & 0 deletions .codacy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ engines:
flake8:
enabled: true
exclude_paths:
- "setup.py"
- "versioneer.py"
- "ams/pypower/**"
- "ams/_version.py"
- ".github/**"
- "README.md"
- "tests/**"
7 changes: 6 additions & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,10 @@ cli:
report_type: "xml"

ignore:
- "setup.py"
- "versioneer.py"
- "ams/pypower/**"
- "ams/_version.py"
- "ams/pypower/**"
- ".github/**"
- "README.md"
- "tests/**"
2 changes: 1 addition & 1 deletion ams/routines/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from collections import OrderedDict
from andes.utils.func import list_flatten
from ams.routines.routine import RoutineModel # NOQA
from ams.routines.routine import RoutineBase # NOQA

all_routines = OrderedDict([
('dcpf', ['DCPF']),
Expand Down
8 changes: 4 additions & 4 deletions ams/routines/dcopf.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
from ams.core.param import RParam
from ams.core.service import NumOp, NumOpDual

from ams.routines.routine import RoutineModel
from ams.routines.routine import RoutineBase

from ams.opt.omodel import Var, Constraint, Objective


logger = logging.getLogger(__name__)


class DCOPF(RoutineModel):
class DCOPF(RoutineBase):
"""
DC optimal power flow (DCOPF).
Expand All @@ -24,7 +24,7 @@ class DCOPF(RoutineModel):
"""

def __init__(self, system, config):
RoutineModel.__init__(self, system, config)
RoutineBase.__init__(self, system, config)
self.info = 'DC Optimal Power Flow'
self.type = 'DCED'
# --- Data Section ---
Expand Down Expand Up @@ -224,7 +224,7 @@ def run(self, no_code=True, **kwargs):
kwargs : keywords, optional
Additional solver specific arguments. See CVXPY documentation for details.
"""
return RoutineModel.run(self, no_code=no_code, **kwargs)
return RoutineBase.run(self, no_code=no_code, **kwargs)

def _post_solve(self):
# --- post-solving calculations ---
Expand Down
6 changes: 3 additions & 3 deletions ams/routines/dcpf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from andes.shared import deg2rad
from andes.utils.misc import elapsed

from ams.routines.routine import RoutineModel
from ams.routines.routine import RoutineBase
from ams.opt.omodel import Var
from ams.pypower import runpf
from ams.pypower.core import ppoption
Expand All @@ -17,15 +17,15 @@
logger = logging.getLogger(__name__)


class DCPFlowBase(RoutineModel):
class DCPFlowBase(RoutineBase):
"""
Base class for power flow.
Overload the ``solve``, ``unpack``, and ``run`` methods.
"""

def __init__(self, system, config):
RoutineModel.__init__(self, system, config)
RoutineBase.__init__(self, system, config)
self.info = 'DC Power Flow'
self.type = 'PF'

Expand Down
4 changes: 2 additions & 2 deletions ams/routines/routine.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
logger = logging.getLogger(__name__)


class RoutineModel:
class RoutineBase:
"""
Class to hold descriptive routine models and data mapping.
"""
Expand Down Expand Up @@ -507,7 +507,7 @@ def __setattr__(self, key, value):
self._check_attribute(key, value)
self._register_attribute(key, value)

super(RoutineModel, self).__setattr__(key, value)
super(RoutineBase, self).__setattr__(key, value)

def _register_attribute(self, key, value):
"""
Expand Down
4 changes: 2 additions & 2 deletions examples/ex8.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In AMS, a `RoutineModel` collects the descriptive dispatch formulations.\n",
"`DCOPF`, `RTED`, etc, are the subclasses of `RoutineModel`."
"In AMS, a routine collects the descriptive dispatch formulations.\n",
"`DCOPF`, `RTED`, etc, are the subclasses of `RoutineBase`."
]
},
{
Expand Down
81 changes: 67 additions & 14 deletions tests/test_andes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@
import andes
import ams

from ams.interop.andes import build_group_table, to_andes, parse_addfile
from ams.interop.andes import build_group_table, make_link_table, to_andes, parse_addfile


class TestInteropBase(unittest.TestCase):
"""
Tests for basic function of ANDES interface.
# TODO: add case that involve PVD1 or REGCV1
"""
ad_cases = [
'ieee14/ieee14_full.xlsx',
Expand All @@ -31,12 +29,16 @@ def setUp(self) -> None:
Test setup.
"""

def test_build_group_table(self):
def test_basic_functions(self):
"""
Test basic functions defined in ANDES Interop.
"""
for ad_case in self.ad_cases:
sa = andes.load(andes.get_case(ad_case),
setup=True,
no_output=True,
default_config=True,)
# --- test build_group_table ---
ssa_stg = build_group_table(adsys=sa,
grp_name='StaticGen',
param_name=['u', 'name', 'idx', 'bus'],
Expand All @@ -49,8 +51,19 @@ def test_build_group_table(self):
mdl_name=[])
self.assertEqual(ssa_gov.shape,
(sa.TurbineGov.n, 2))
# --- test make_link_table ---
link_table = make_link_table(adsys=sa)
stg_idx = [str(i) for i in sa.PV.idx.v + sa.Slack.idx.v]
self.assertSetEqual(set(stg_idx),
set(link_table['stg_idx'].values))
bus_idx = [str(i) for i in sa.PV.bus.v + sa.Slack.bus.v]
self.assertSetEqual(set(bus_idx),
set(link_table['bus_idx'].values))

def test_convert(self):
"""
Test conversion from AMS case to ANDES case.
"""
for ad_case, am_case in zip(self.ad_cases, self.am_cases):
sp = ams.load(ams.get_case(am_case),
setup=True,
Expand All @@ -72,21 +85,61 @@ def test_convert(self):
# set2 includes set1, ensure GENROU.gen are all in StaticGen.idx
self.assertEqual(set1, set1 & set2)

def test_extra_dyn(self):
"""
Test conversion when extra dynamic models exist.
"""
sp = ams.load(ams.get_case('ieee14/ieee14_uced.xlsx'),
setup=True,
no_output=True,
default_config=True,)
sa = to_andes(sp, setup=True, addfile=andes.get_case('ieee14/ieee14_full.xlsx'))

self.assertGreaterEqual(sa.PVD1.n, 0)

class TestANDES(unittest.TestCase):
"""
Tests for ANDES interface.

# TODO: add tests for ANDES interface functions.
class TestDataExchange(unittest.TestCase):
"""
Tests for data exchange between AMS and ANDES.
"""
cases = [
'5bus/pjm5bus_demo.xlsx',
'ieee14/ieee14_uced.xlsx',
'ieee39/ieee39_uced_esd1.xlsx',
'matpower/case118.m',
]

def setUp(self) -> None:
"""
Test setup. This is executed before each test case.
"""
self.sp = ams.load(ams.get_case('ieee14/ieee14_uced.xlsx'),
setup=True,
no_output=True,
default_config=True,)
self.sp.RTED.run(solver='ECOS')
self.sp.RTED.dc2ac()
self.stg_idx = self.sp.RTED.pg.get_idx()

def test_data_exchange(self):
"""
Test data exchange between AMS and ANDES.
"""
sa = to_andes(self.sp, setup=True,
addfile=andes.get_case('ieee14/ieee14_full.xlsx'),
no_output=True,
default_config=True,)
# alleviate limiter
sa.TGOV1.set(src='VMAX', attr='v', idx=sa.TGOV1.idx.v, value=100*np.ones(sa.TGOV1.n))
sa.TGOV1.set(src='VMIN', attr='v', idx=sa.TGOV1.idx.v, value=np.zeros(sa.TGOV1.n))

# --- test before PFlow ---
self.sp.dyn.send(adsys=sa, routine='RTED')
p0 = sa.StaticGen.get(src='p0', attr='v', idx=self.stg_idx)
pg = self.sp.RTED.get(src='pg', attr='v', idx=self.stg_idx)
np.testing.assert_array_equal(p0, pg)

# --- test after TDS ---
self.assertFalse(self.sp.dyn.is_tds)
sa.PFlow.run()
sa.TDS.init()
self.assertTrue(self.sp.dyn.is_tds)

sa.TDS.config.tf = 1
sa.TDS.run()
self.sp.dyn.send(adsys=sa, routine='RTED')
self.sp.dyn.receive(adsys=sa, routine='RTED', no_update=False)
22 changes: 22 additions & 0 deletions tests/test_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,28 @@ def test_ieee14_raw_convert(self):
os.remove(ss.files.dump)
self.assertEqual(ss.exit_code, 0, "Exit code is not 0.")

def test_ieee14_raw2xlsx(self):
ss = ams.load(
get_case("ieee14/ieee14.raw"),
setup=True,
no_output=True,
default_config=True,
)
ams.io.xlsx.write(ss, "ieee14.xlsx")
self.assertTrue(os.path.exists("ieee14.xlsx"))
os.remove("ieee14.xlsx")

def test_ieee14_raw2json(self):
ss = ams.load(
get_case("ieee14/ieee14.raw"),
setup=True,
no_output=True,
default_config=True,
)
ams.io.json.write(ss, "ieee14.json")
self.assertTrue(os.path.exists("ieee14.json"))
os.remove("ieee14.json")

def test_ieee14_raw2json_convert(self):
ss = ams.run(
get_case("ieee14/ieee14.raw"),
Expand Down

0 comments on commit 85834f9

Please sign in to comment.