Netlist extractor YAML#

Any component can extract its netlist with get_netlist

While gf.read.from_yaml converts a YAML Dict into a Component

get_netlist converts Component into a YAML Dict

import gdsfactory as gf
import yaml
c = gf.components.mzi()
c.plot()
../_images/83deb8feb3e0bdc9ed7e42acacf73ccf6141a108ffc4d423ff7304a3c64db2e4.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f2905878a10>
../_images/d9c31ea753a927f9c23d101753ad84fbf5d0144a0099eec8843eec2606efcb13.png
c = gf.components.ring_single()
c.plot()
../_images/9b994c2ab91aadbd19ce18d4707ee56f6702de7d7cc7a6d8cd2626435e44980c.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f29056f97d0>
../_images/5bddbf40437d45c40e42ecf4f63ab22edcc4281b7b608e6c1a69d14a0166b687.png
n = c.get_netlist()
netlist_string = c.write_netlist(n)
n = yaml.safe_load(netlist_string)
i = list(n["instances"].keys())
i
['bend_euler_R10_A90_P0p5_2f1f5c6d_5125_16425',
 'bend_euler_R10_A90_P0p5_2f1f5c6d_m9125_16425',
 'coupler_ring_G0p2_R10_L_9871ac59_m2000_5225',
 'straight_L0p6_N2_CSstrip_10000_11000',
 'straight_L0p6_N2_CSstrip_m14000_11000',
 'straight_L4_N2_CSstrip_m2000_21300']
instance_name0 = i[0]
n["instances"][instance_name0]["settings"]
{'allow_min_radius_violation': False,
 'angle': 90,
 'cross_section': 'strip',
 'p': 0.5,
 'radius': 10,
 'with_arc_floorplan': True}

Instance names#

By default get netlist names each instance with the name of the reference

@gf.cell
def mzi_with_bend_automatic_naming():
    c = gf.Component()
    mzi = c.add_ref(gf.components.mzi())
    bend = c.add_ref(gf.components.bend_euler())
    bend.connect("o1", mzi.ports["o2"])
    return c


c = mzi_with_bend_automatic_naming()
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f2905609690>
../_images/cc47c9511eb36d07ad3e90e141dcda9c47d023853d7dc68ed9a9bd7397da20e6.png
@gf.cell
def mzi_with_bend_deterministic_names_using_alias():
    c = gf.Component()
    mzi = c.add_ref(gf.components.mzi(), alias="my_mzi")
    bend = c.add_ref(gf.components.bend_euler(), alias="my_bend")
    bend.connect("o1", mzi.ports["o2"])
    return c


c = mzi_with_bend_deterministic_names_using_alias()
c.plot_netlist()
/home/runner/micromamba/lib/python3.11/site-packages/gdsfactory/component.py:667: UserWarning: alias is deprecated, use name instead
  warnings.warn("alias is deprecated, use name instead")
<networkx.classes.graph.Graph at 0x7f29381bce10>
../_images/e059f51258c586daa27b800b8833614509da3f715990a307e425bd47fec324c3.png
c = gf.components.mzi()
c.plot()
../_images/83deb8feb3e0bdc9ed7e42acacf73ccf6141a108ffc4d423ff7304a3c64db2e4.png
c = gf.components.mzi()
n = c.get_netlist()
print(c.get_netlist().keys())
dict_keys(['nets', 'instances', 'placements', 'ports', 'name'])
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f2938177890>
../_images/d9c31ea753a927f9c23d101753ad84fbf5d0144a0099eec8843eec2606efcb13.png
n.keys()
dict_keys(['nets', 'instances', 'placements', 'ports', 'name'])

warnings#

Lets make a connectivity error, for example connecting ports on the wrong layer

@gf.cell
def mmi_with_bend():
    c = gf.Component()
    mmi = c.add_ref(gf.components.mmi1x2(), alias="mmi")
    bend = c.add_ref(gf.components.bend_euler(layer=(2, 0)), alias="bend")
    bend.connect("o1", mmi.ports["o2"], allow_layer_mismatch=True)
    return c


c = mmi_with_bend()
c.plot()
../_images/b20e44ba497a1b8bc5cc430c5d41dc1ae0548a913b916b3348c79db21b62a3c2.png
n = c.get_netlist()
print(n["warnings"])
{'optical': {'unconnected_ports': ({'ports': ('mmi,o1', 'mmi,o3', 'bend,o2'), 'values': ((-10000, 0), (15500, -625), (25500, 10625)), 'message': '3 unconnected optical ports!'},)}}
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f290556f950>
../_images/46852e982f28c29dd63ef3a0bcad8ff0fb9135b837adfa7a1f4f7e05b5aac2d4.png

get_netlist_recursive#

When you do get_netlist() for a component it will only show connections for the instances that belong to that component. So despite having a lot of connections, it will show only the meaningful connections for that component. For example, a ring has a ring_coupler. If you want to dig deeper, the connections that made that ring coupler are still available.

get_netlist_recursive() returns a recursive netlist.

c = gf.components.ring_single()
c.plot()
../_images/9b994c2ab91aadbd19ce18d4707ee56f6702de7d7cc7a6d8cd2626435e44980c.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f290556f890>
../_images/5bddbf40437d45c40e42ecf4f63ab22edcc4281b7b608e6c1a69d14a0166b687.png
c = gf.components.ring_double()
c.plot()
../_images/251950cbcb9f8bd105a4158fd93a11c7b9ce40e9afb1e003a9e1a1fc7aabbbe5.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f290533a2d0>
../_images/0cb9c03921ecd82320bc601d4988a794304fbfc3f80158d93099234b389638ed.png
c = gf.components.mzit()
c.plot()
../_images/0a70f45097e1886e78360baa31a1bd771f5a859c38f660a0d9a8fa6d317c2d6b.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f2905372dd0>
../_images/5f60dd39d76d6ec6c66212133a8acf5569e6125a880bc6d9212d761d2b5079ce.png
coupler_lengths = (10, 20, 30)
coupler_gaps = (0.1, 0.2, 0.3)
delta_lengths = (10, 100)

c = gf.components.mzi_lattice(
    coupler_lengths=coupler_lengths,
    coupler_gaps=coupler_gaps,
    delta_lengths=delta_lengths,
)
c.plot()
../_images/2e2d1ab47c54c847ae8df062be9ea327939b69c2d8c4f17d6e419bfbc81d3eed.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f29381bd6d0>
../_images/46e21dedd4f10cc70624b93fb4235b22eb2f0d932c7c7ad3a0cb98f54b76e044.png
coupler_lengths = (10, 20, 30, 40)
coupler_gaps = (0.1, 0.2, 0.4, 0.5)
delta_lengths = (10, 100, 200)

c = gf.components.mzi_lattice(
    coupler_lengths=coupler_lengths,
    coupler_gaps=coupler_gaps,
    delta_lengths=delta_lengths,
)
c.plot()
../_images/580d8ad7a160fc608b095a57415ed9be3558ca296571207f7316b3e336a90de7.png
n = c.get_netlist()
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f29055a9950>
../_images/e160c3f96df5bd48dbaf75a68fdd5af8d9e3a2ca2471680083c8ed47c5a4c3c4.png
n_recursive = c.get_netlist(recursive=True)
n_recursive.keys()
dict_keys(['mzi_lattice_CL10_20_30__8514709c', 'mzi_DL10_LY2_LXNone_Bbe_bd58332b', 'mzi_DL100_LY2_LXNone_Bb_bc9d44ae', 'mzi_DL200_LY2_LXNone_Bb_57f5eb49'])

Placement information is accumulated, and connections and ports are mapped, respectively, to the ports of the unique instances or the component top level ports. This can be plotted:

c.plot_netlist(with_labels=False)  # labels get cluttered
<networkx.classes.graph.Graph at 0x7f290487a550>
../_images/96a85d8fc0ff50af069f1c20850de515b39fb6fba61dc95ef9948060f41008dd.png

allow_multiple_connections#

The default get_netlist function (also used by default by get_netlist_recurse and get_netlist_flat) can identify more than two ports sharing the same connection through the allow_multiple flag.

For instance, consider a resistor network with one shared node:

import gdsfactory as gf

vdiv = gf.Component()
r1 = vdiv << gf.components.resistance_sheet()
r2 = vdiv << gf.components.resistance_sheet()
r3 = vdiv << gf.get_component(gf.components.resistance_sheet)
r4 = vdiv << gf.get_component(gf.components.resistance_sheet)

r1.connect("pad2", r2.ports["pad1"])
r3.connect("pad1", r2.ports["pad1"])
r4.connect("pad2", r2.ports["pad1"])

r4.drotate(90)

vdiv.plot()
../_images/46d097c8508b7946663f2214625a9b7ea99b64777450a101bd2ce684d5a948ad.png
try:
    vdiv.get_netlist()
except Exception as exc:
    print(exc)
/home/runner/micromamba/lib/python3.11/site-packages/gdsfactory/get_netlist.py:352: UserWarning: Found multiple connections at (-50000, -25000):['resistance_sheet_W10_LH_1b3e3b4b_0_m50000,pad2', 'resistance_sheet_W10_LH_1b3e3b4b_0_0,pad1', 'resistance_sheet_W10_LH_1b3e3b4b_m100000_m50000,pad1']
  warn(f"Found multiple connections at {xy}:{ports_at_xy}")
vdiv.get_netlist(allow_multiple=True)
{'nets': ({'p1': 'resistance_sheet_W10_LH_1b3e3b4b_0_0,pad1',
   'p2': 'resistance_sheet_W10_LH_1b3e3b4b_0_m50000,pad2'},
  {'p1': 'resistance_sheet_W10_LH_1b3e3b4b_0_0,pad1',
   'p2': 'resistance_sheet_W10_LH_1b3e3b4b_m100000_m50000,pad1'},
  {'p1': 'resistance_sheet_W10_LH_1b3e3b4b_0_0,pad2',
   'p2': 'resistance_sheet_W10_LH_1b3e3b4b_0_m50000,pad1'},
  {'p1': 'resistance_sheet_W10_LH_1b3e3b4b_0_m50000,pad2',
   'p2': 'resistance_sheet_W10_LH_1b3e3b4b_m100000_m50000,pad1'}),
 'instances': {'resistance_sheet_W10_LH_1b3e3b4b_0_0': {'component': 'resistance_sheet',
   'info': {'resistance': 0},
   'settings': {'width': 10,
    'layers': ('HEATER',),
    'layer_offsets': (0, 0.2),
    'pad': 'via_stack_heater_mtop',
    'pad_size': (50, 50),
    'pad_pitch': 100,
    'pad_port_name': 'e4'}},
  'resistance_sheet_W10_LH_1b3e3b4b_0_m50000': {'component': 'resistance_sheet',
   'info': {'resistance': 0},
   'settings': {'width': 10,
    'layers': ('HEATER',),
    'layer_offsets': (0, 0.2),
    'pad': 'via_stack_heater_mtop',
    'pad_size': (50, 50),
    'pad_pitch': 100,
    'pad_port_name': 'e4'}},
  'resistance_sheet_W10_LH_1b3e3b4b_50000_0': {'component': 'resistance_sheet',
   'info': {'resistance': 0},
   'settings': {'width': 10,
    'layers': ('HEATER',),
    'layer_offsets': (0, 0.2),
    'pad': 'via_stack_heater_mtop',
    'pad_size': (50, 50),
    'pad_pitch': 100,
    'pad_port_name': 'e4'}},
  'resistance_sheet_W10_LH_1b3e3b4b_m100000_m50000': {'component': 'resistance_sheet',
   'info': {'resistance': 0},
   'settings': {'width': 10,
    'layers': ('HEATER',),
    'layer_offsets': (0, 0.2),
    'pad': 'via_stack_heater_mtop',
    'pad_size': (50, 50),
    'pad_pitch': 100,
    'pad_port_name': 'e4'}}},
 'placements': {'resistance_sheet_W10_LH_1b3e3b4b_0_0': {'x': 0,
   'y': 0,
   'rotation': 0,
   'mirror': False},
  'resistance_sheet_W10_LH_1b3e3b4b_0_m50000': {'x': 0,
   'y': -50,
   'rotation': 180,
   'mirror': False},
  'resistance_sheet_W10_LH_1b3e3b4b_50000_0': {'x': 50,
   'y': 0,
   'rotation': 270,
   'mirror': False},
  'resistance_sheet_W10_LH_1b3e3b4b_m100000_m50000': {'x': -100,
   'y': -50,
   'rotation': 180,
   'mirror': False}},
 'ports': {},
 'name': 'Unnamed_85',
 'warnings': {'electrical': {'unconnected_ports': ({'ports': ('resistance_sheet_W10_LH_1b3e3b4b_m100000_m50000,pad2',
      'resistance_sheet_W10_LH_1b3e3b4b_50000_0,pad1',
      'resistance_sheet_W10_LH_1b3e3b4b_50000_0,pad2'),
     'values': ((-150000, -25000), (25000, 50000), (25000, -50000)),
     'message': '3 unconnected electrical ports!'},)}}}