Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 48 additions & 4 deletions pygridsim/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,23 @@ def __init__(self):
self.num_transformers = 0
self.num_pv = 0
self.num_generators = 0
self.nickname_to_name = {}
Comment thread
amzhao16 marked this conversation as resolved.
Comment thread
amzhao16 marked this conversation as resolved.
altdss.ClearAll()
altdss('new circuit.MyCircuit')

def _check_naming(self, name):
if name in self.nickname_to_name:
raise NameError("Provided name already assigned to a node")
Comment thread
amzhao16 marked this conversation as resolved.
Outdated
if name.startswith("load") or name.startswith(
Comment thread
amzhao16 marked this conversation as resolved.
Outdated
"generator") or name == "source" or name.startswith("pv"):
raise NameError(
"Cannot name nodes of the format 'component + __', ambiguity with internal names")
Comment thread
amzhao16 marked this conversation as resolved.
Outdated

def add_load_nodes(self,
load_type: str = "house",
params: dict[str, int] = None,
num: int = 1):
num: int = 1,
names: list[str] = None):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add explicit typing:

params: Optional[dict[str, int]] = None,
names: Optional[list[str]] = None

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you recommend doing this with the "from typing import Optional" class? I'm not used to declaring typing with optional, and am getting "Call expression not allowed in type expressionPylancereportInvalidTypeForm" when doing it naively.

"""Adds Load Node(s) to circuit.

Allows the user to add num load nodes,
Expand All @@ -47,14 +57,24 @@ def add_load_nodes(self,
Load parameters for these manual additions. Defaults to empty dictionary.
num (int, optional):
The number of loads to create with these parameters. Defaults to 1.
names (list(str), optional):
Up to num names to assign as shortcuts to the loads

Returns:
list[OpenDSS object]:
A list of OpenDSS objects representing the load nodes created.
"""
params = params or dict()
names = names or list()
if len(names) > num:
raise ValueError("Specified more names of loads than number of nodes")

load_nodes = []
for _ in range(num):
for i in range(num):
if (len(names) > i):
self._check_naming(names[i])
self.nickname_to_name[names[i]] = "load" + str(self.num_loads)

_make_load_node(params, load_type, self.num_loads)
self.num_loads += 1

Expand Down Expand Up @@ -106,12 +126,19 @@ def add_PVSystems(self, load_nodes: list[str],

PV_nodes = []
for load in load_nodes:
if (load in self.nickname_to_name):
self.nickname_to_name[load]
Comment thread
amzhao16 marked this conversation as resolved.
Outdated

PV_nodes.append(_make_pv(load, params, num_panels, self.num_pv))
self.num_pv += 1

return PV_nodes

def add_generators(self, num: int = 1, gen_type: str = "small", params: dict[str, int] = None):
def add_generators(self,
num: int = 1,
gen_type: str = "small",
params: dict[str, int] = None,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit add typing same as above

names: list[str] = None):
"""Adds generator(s) to the system.

Args:
Expand All @@ -121,14 +148,24 @@ def add_generators(self, num: int = 1, gen_type: str = "small", params: dict[str
The type of generator (one of "small", "large", "industrial"). Defaults to "small".
params (dict[str, int], optional):
A dictionary of parameters to configure the generator. Defaults to None.
names (list(str), optional):
Up to num names to assign as shortcuts to the generators

Returns:
list[DSS objects]:
A list of OpenDSS objects representing the generators created.
"""
params = params or dict()
names = names or list()
if len(names) > num:
raise ValueError("Specified more names of generators than number of nodes")

generators = []
for _ in range(num):
for i in range(num):
if (len(names) > i):
self._check_naming(names[i])
self.nickname_to_name[names[i]] = "generator" + str(self.num_generators)

generators.append(_make_generator(params, gen_type, count=self.num_generators))
self.num_generators += 1

Expand Down Expand Up @@ -159,6 +196,13 @@ def add_lines(self,
"""
params = params or dict()
for src, dst in connections:
if (src in self.nickname_to_name):
src = self.nickname_to_name[src]
if (dst in self.nickname_to_name):
dst = self.nickname_to_name[dst]
if (src == dst):
raise ValueError("Tried to make a line between equivalent src and dst")

_make_line(src, dst, line_type, self.num_lines, params, transformer)
self.num_lines += 1

Expand Down
31 changes: 31 additions & 0 deletions tests/test_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,37 @@ def test_011_configs(self):
with self.assertRaises(Exception):
circuit.update_source(source_type=SourceType.TURBINE)

def test_012_node_naming(self):
circuit = PyGridSim()
circuit.update_source()
# Create 4 nodes, only name 2 of them
circuit.add_load_nodes(num=4, load_type="house", names=["0", "1"])
circuit.add_generators(num=2, gen_type="small", names=["G0", "G1"])

# Add PVSystems to one of the nodes with shortcut
circuit.add_PVSystems(load_nodes=["load2", "0"])
# Can use original or abbreviated name
circuit.add_lines(connections=[("G0", "0"), ("generator1", "load1")])

with self.assertRaises(NameError):
# Tries to assign an already assigned name
circuit.add_load_nodes(num=1, names=["G1"])

with self.assertRaises(NameError):
# Tries to assign name to internal name load1, errors because adds ambiguity
circuit.add_load_nodes(num=1, names=["load1"])

with self.assertRaises(ValueError):
# Attempt to name 2 load nodes, but only initiating 1
circuit.add_load_nodes(names=["640", "641"])

with self.assertRaises(ValueError):
# Trying to create a line between a node and itself (nickname)
circuit.add_lines(connections=[("load0", "0")])

circuit.solve()
print(circuit.results(["Voltages", "Losses"]))


class TestCustomizedCircuit(unittest.TestCase):
"""
Expand Down