Skip to content

Commit

Permalink
feat: add group parameter in System, allowing grouping of components
Browse files Browse the repository at this point in the history
  • Loading branch information
geddy11 committed Oct 29, 2024
1 parent 8fb1728 commit 83d9965
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ build:
jobs:
post_create_environment:
# install graphviz
- apt-get install graphviz
- apt-get install graphviz -y
# Install poetry et.al.
# https://python-poetry.org/docs/#installing-manually
- pip install poetry jupyter-book sphinx-autoapi toml numpy pandas rustworkx scipy rich matplotlib tqdm ipywidgets graphviz packaging
Expand Down
45 changes: 36 additions & 9 deletions src/sysloss/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ class System:
System name.
source : Source
Source component.
group : str, optional
Group name, for grouping components together.
Raises
------
Expand All @@ -79,7 +81,7 @@ class System:
"""

def __init__(self, name: str, source: Source):
def __init__(self, name: str, source: Source, *, group: str = ""):
"""Class constructor"""
self._g = None
if not isinstance(source, Source):
Expand All @@ -93,6 +95,8 @@ def __init__(self, name: str, source: Source):
self._g.attrs["phase_conf"][source._params["name"]] = {}
self._g.attrs["nodes"] = {}
self._g.attrs["nodes"][source._params["name"]] = pidx
self._g.attrs["groups"] = {}
self._g.attrs["groups"][source._params["name"]] = group

@classmethod
def from_file(cls, fname: str):
Expand Down Expand Up @@ -238,6 +242,11 @@ def from_file(cls, fname: str):
self._g.attrs["phases"] = phases
phase_conf = _get_mand(sysparams, "phase_conf")
self._g.attrs["phase_conf"] = phase_conf
groups = _get_opt(sysparams, "groups", {})
if groups == {}:
for key in phase_conf:
groups[key] = ""
self._g.attrs["groups"] = groups

return self

Expand Down Expand Up @@ -330,7 +339,7 @@ def _make_rtree(self, adj, node):
tree.add(self._make_rtree(adj, child))
return tree

def add_comp(self, parent: str, *, comp):
def add_comp(self, parent: str, *, comp, group: str = ""):
"""Add component to system.
Parameters
Expand All @@ -339,6 +348,8 @@ def add_comp(self, parent: str, *, comp):
Name of parent component.
comp : component
Component (from :py:mod:`~sysloss.components`).
group : str, optional
Group name, for grouping components together.
Raises
------
Expand All @@ -348,7 +359,7 @@ def add_comp(self, parent: str, *, comp):
Examples
--------
>>> sys.add_comp("Vin", comp=Converter("Buck", vo=1.8, eff=0.87))
>>> sys.add_comp("Buck", comp=PLoad("MCU", pwr=0.015))
>>> sys.add_comp("Buck", comp=PLoad("MCU", pwr=0.015), group="Main")
"""
# check that parent exists
Expand All @@ -365,17 +376,18 @@ def add_comp(self, parent: str, *, comp):
)
cidx = self._g.add_child(pidx, comp, None)
self._g.attrs["nodes"][comp._params["name"]] = cidx
# if not isinstance(phase_config, dict) and not isinstance(phase_config, list):
# raise ValueError("phase_config must be dict or list")
self._g.attrs["phase_conf"][comp._params["name"]] = {}
self._g.attrs["groups"][comp._params["name"]] = group

def add_source(self, source: Source):
def add_source(self, source: Source, *, group: str = ""):
"""Add an additional Source to the system.
Parameters
----------
source : Source
Source component.
group : str, optional
Group name, for grouping components together.
Raises
------
Expand All @@ -394,8 +406,9 @@ def add_source(self, source: Source):
pidx = self._g.add_node(source)
self._g.attrs["nodes"][source._params["name"]] = pidx
self._g.attrs["phase_conf"][source._params["name"]] = {}
self._g.attrs["groups"][source._params["name"]] = group

def change_comp(self, name: str, *, comp):
def change_comp(self, name: str, *, comp, group: str = ""):
"""Replace component.
The new component can be of same type (parameter change), or a new type
Expand All @@ -407,6 +420,8 @@ def change_comp(self, name: str, *, comp):
Name of component to be changed.
comp : component
Component (from :py:mod:`~sysloss.components`).
group : str, optional
Group name, for grouping components together.
Raises
------
Expand Down Expand Up @@ -448,6 +463,9 @@ def change_comp(self, name: str, *, comp):
# delete old phase config and set new default
del [self._g.attrs["phase_conf"][name]]
self._g.attrs["phase_conf"][comp._params["name"]] = {}
# delete old group and set new
del [self._g.attrs["groups"][name]]
self._g.attrs["groups"][comp._params["name"]] = group

def del_comp(self, name: str, *, del_childs: bool = True):
"""Delete component.
Expand Down Expand Up @@ -496,11 +514,13 @@ def del_comp(self, name: str, *, del_childs: bool = True):
for c in rx.descendants(self._g, eidx):
del [self._g.attrs["nodes"][self._g[c]._params["name"]]]
del [self._g.attrs["phase_conf"][self._g[c]._params["name"]]]
del [self._g.attrs["groups"][self._g[c]._params["name"]]]
self._g.remove_node(c)
# delete node
self._g.remove_node(eidx)
del [self._g.attrs["nodes"][name]]
del [self._g.attrs["phase_conf"][name]]
del [self._g.attrs["groups"][name]]
# restore links between new parent and childs, unless deleted
if not del_childs:
if childs[eidx] != -1:
Expand Down Expand Up @@ -726,16 +746,18 @@ def solve(
# calculate results for each node
names, parent, typ, pwr, loss, trise, tpeak = [], [], [], [], [], [], []
eff, warn, vsi, iso, vso, isi = [], [], [], [], [], []
domain, phases, ener, dname = [], [], [], "none"
domain, phases, ener, dname, group = [], [], [], "none", []
sources, dwarns = {}, {}
show_trise = False
for n in self._topo_nodes: # [vi, vo, ii, io]
phase_config = self._phase_lkup[n]
names += [self._g[n]._params["name"]]
name = self._g[n]._params["name"]
names += [name]
if self._g[n]._component_type.name == "SOURCE":
dname = self._g[n]._params["name"]
domain += [dname]
phases += [ph]
group += [self._g.attrs["groups"][name]]
vi = v[n]
vo = v[n]
ii = i[n]
Expand Down Expand Up @@ -788,6 +810,7 @@ def solve(
parent += [""]
domain += [""]
phases += [ph]
group += [""]
vsi += [sources[list(sources.keys())[d]]]
vso += [""]
isi += [""]
Expand All @@ -809,6 +832,7 @@ def solve(
parent += [""]
domain += [""]
phases += [ph]
group += [""]
vsi += [""]
vso += [""]
isi += [""]
Expand All @@ -830,6 +854,8 @@ def solve(
res["Type"] = typ
res["Parent"] = parent
res["Domain"] = domain
if any(["" != x for x in group]):
res["Group"] = group
if tags != {}:
for key in tags.keys():
res[key] = [tags[key]] * len(names)
Expand Down Expand Up @@ -1257,6 +1283,7 @@ def save(self, fname: str, *, indent: int = 4):
"version": sysloss.__version__,
"phases": self._g.attrs["phases"],
"phase_conf": self._g.attrs["phase_conf"],
"groups": self._g.attrs["groups"],
}
}
ridx = self._get_sources()
Expand Down
11 changes: 7 additions & 4 deletions tests/unit/test_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

def test_case1():
"""Check system consisting of all component types"""
case1 = System("Case1 system", Source("3V coin", vo=3, rs=13e-3))
case1 = System("Case1 system", Source("3V coin", vo=3, rs=13e-3), group="42")
case1.add_comp("3V coin", comp=Converter("1.8V buck", vo=1.8, eff=0.87, iq=12e-6))
case1.add_comp("1.8V buck", comp=PLoad("MCU", pwr=27e-3))
case1.add_comp("3V coin", comp=Converter("5V boost", vo=5, eff=0.91, iq=42e-6))
Expand All @@ -42,7 +42,7 @@ def test_case1():
)
case1.add_comp(parent="RC filter", comp=VLoss("Diode", vdrop=0.17))
case1.add_comp("Diode", comp=LinReg("LDO 2.5V", vo=2.5, vdrop=0.27, ig=150e-6))
case1.add_comp("LDO 2.5V", comp=PLoad("ADC", pwr=15e-3))
case1.add_comp("LDO 2.5V", comp=PLoad("ADC", pwr=15e-3), group="AFE")
case1.add_comp("5V boost", comp=RLoad("Res divider", rs=200e3))
case1.add_comp("5V boost", comp=PSwitch("Load switch", rs=150e-3))
case1.add_comp("Load switch", comp=PLoad("MCU 2", pwr=0.12))
Expand All @@ -51,10 +51,10 @@ def test_case1():
df = case1.solve(quiet=False)
rows = 13
assert df.shape[0] == rows, "Case1 solution row count"
assert df.shape[1] == 11, "Case1 solution column count"
assert df.shape[1] == 12, "Case1 solution column count"
df = case1.solve(tags={"Battery": "small", "Interval": "fast"})
assert df.shape[0] == rows, "Case1 solution row count"
assert df.shape[1] == 13, "Case1 solution column count"
assert df.shape[1] == 14, "Case1 solution column count"
assert np.allclose(
df[df["Component"] == "System total"]["Efficiency (%)"][rows - 1],
84.8522,
Expand Down Expand Up @@ -97,6 +97,9 @@ def test_case1():
df[df["Component"] == "System total"]["Power (W)"][rows - 1],
rtol=1e-6,
), "Case1 vs case1b power"
assert df2.shape[1] == 12, "Case1b solution column count"
assert case1b._g.attrs["groups"]["3V coin"] == "42", "Case1 source group name"
assert case1b._g.attrs["groups"]["ADC"] == "AFE", "Case1 ADC group name"


def test_case2():
Expand Down

0 comments on commit 83d9965

Please sign in to comment.