Skip to content

Commit

Permalink
Merge pull request #224 from nikosavola/223-plotted-spice-unique-elem…
Browse files Browse the repository at this point in the history
…ents

Ensure unique SPICE netlist elements with a counter
  • Loading branch information
joamatab authored Nov 10, 2023
2 parents 5ae9e60 + 7887619 commit bbee620
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 24 deletions.
9 changes: 7 additions & 2 deletions gplugins/klayout/netlist_spice_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@


class NoCommentReader(kdb.NetlistSpiceReaderDelegate):
"""KLayout Spice reader without comments after $. This allows checking the netlist for HSPICE"""
"""KLayout Spice reader without comments after $. This allows checking the netlist for HSPICE."""

n_nodes: int = 0

def parse_element(self, s: str, element: str) -> kdb.ParseElementData:
if "$" in s:
s = s.split("$")[0] # Don't take comments into account
s, *_ = s.split("$") # Don't take comments into account
parsed = super().parse_element(s, element)
# ensure uniqueness
parsed.model_name = parsed.model_name + f"_{self.n_nodes}"
self.n_nodes += 1
return parsed
26 changes: 22 additions & 4 deletions gplugins/klayout/plot_nets.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,33 @@ def _get_subcircuit_name(subcircuit: kdb.SubCircuit) -> str:


def netlist_to_networkx(
netlist: kdb.Netlist, fully_connected: bool = False, include_labels: bool = True
netlist: kdb.Netlist,
fully_connected: bool = False,
include_labels: bool = True,
only_most_complex: bool = False,
) -> nx.Graph:
"""Convert a KLayout DB `Netlist` to a networkx graph.
Args:
kdbnet: The KLayout DB `Netlist` to convert to a networkx `Graph`.
netlist: The KLayout DB `Netlist` to convert to a networkx `Graph`.
fully_connected: Whether to plot the graph as elements fully connected to all other ones (True) or
going through other elements (False).
include_labels: Whether to include labels in the graph connected to corresponding cells.
only_most_complex: Whether to plot only the circuit with most connections or not.
Helpful for not plotting subcircuits separately.
Returns:
A networkx `Graph` representing the connectivity of the `Netlist`.
"""
G = nx.Graph()

top_circuits = list(
itertools.islice(netlist.each_circuit_top_down(), netlist.top_circuit_count())
)

if only_most_complex:
top_circuits = (max(top_circuits, key=lambda x: x.pin_count()),)

for circuit in top_circuits:
# first flatten components that won't be kept
for subcircuit in circuit.each_subcircuit():
Expand Down Expand Up @@ -65,17 +78,19 @@ def plot_nets(
fully_connected: bool = False,
interactive: bool = False,
include_labels: bool = True,
only_most_complex: bool = False,
) -> None:
"""Plots the connectivity between the components in the KLayout LayoutToNetlist file from :func:`~get_l2n`.
Args:
filepath: Path to the KLayout LayoutToNetlist file or a SPICE netlist.
File extensions should be `.l2n` and `.spice`, respectively.
fully_connected: Whether to plot the graph as elements fully connected to all other ones (True) or
going through other elements (False).
interactive: Whether to plot an interactive graph with `pyvis` or not.
include_labels: Whether to include labels in the graph connected to corresponding cells.
only_most_complex: Whether to plot only the circuit with most connections or not.
Helpful for not plotting subcircuits separately.
"""
match Path(filepath).suffix:
case ".l2n" | ".txt":
Expand All @@ -94,7 +109,10 @@ def plot_nets(

# Creating a graph for the connectivity
G_connectivity = netlist_to_networkx(
netlist, fully_connected=fully_connected, include_labels=include_labels
netlist,
fully_connected=fully_connected,
include_labels=include_labels,
only_most_complex=only_most_complex,
)

# Plotting the graph
Expand Down
6 changes: 3 additions & 3 deletions gplugins/klayout/tests/test_netlist_spice_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
@pytest.mark.parametrize(
"s,element,expected_name,expected_nets",
[
("1 2 POS", "X", "POS", {"1", "2"}),
("2 3 NEG $ This is a comment", "X", "NEG", {"2", "3"}),
("1 2 POS", "X", "POS_0", {"1", "2"}),
("2 3 NEG $ This is a comment", "X", "NEG_0", {"2", "3"}),
(
"5 4 some_elem some_variable=1 $ This is a comment",
"X",
"some_elem",
"some_elem_0",
{"5", "4"},
),
],
Expand Down
31 changes: 16 additions & 15 deletions gplugins/klayout/tests/test_plot_nets.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,22 @@ def spice_netlist(tmpdir_factory) -> str:
return netlist_path


def test_plot_nets(klayout_netlist):
plot_nets(klayout_netlist)


def test_plot_nets_interactive(klayout_netlist):
plot_nets(klayout_netlist, interactive=True)
assert Path("connectivity.html").exists()


def test_plot_nets_not_fully_connected(klayout_netlist):
plot_nets(klayout_netlist, fully_connected=False)


def test_plot_nets_no_labels(klayout_netlist):
plot_nets(klayout_netlist, include_labels=False)
@pytest.mark.parametrize("fully_connected", [True, False])
@pytest.mark.parametrize("interactive", [True, False])
@pytest.mark.parametrize("include_labels", [True, False])
@pytest.mark.parametrize("only_most_complex", [True, False])
def test_plot_nets(
klayout_netlist, fully_connected, interactive, include_labels, only_most_complex
):
plot_nets(
klayout_netlist,
fully_connected=fully_connected,
interactive=interactive,
include_labels=include_labels,
only_most_complex=only_most_complex,
)
if interactive:
assert Path("connectivity.html").exists()


def test_plot_nets_spice(spice_netlist):
Expand Down

0 comments on commit bbee620

Please sign in to comment.