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/a68fc757ae1cd98e077bfe7e6bb1731c55692b5a19aa564327e87968f698e92c.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f56f4073f10>
../_images/36d059361537cce933c4b6220091d7436ab6b17ffaecc6705bb257f4ecb3b302.png
c = gf.components.ring_single()
c.plot()
../_images/0cc2fcbe24c935123408fe08dd7bb96293353af4565fad8d2311f86f6dcc7a56.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f574c0722d0>
../_images/a70442c2166061712dcd1ea69e0ae886cde5c626076336551607decc296d0821.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_gdsfactorypcomponentspbendspbend_euler_RNone_387600b2_10000_11300_A90',
 'bend_euler_gdsfactorypcomponentspbendspbend_euler_RNone_387600b2_m4000_21300_A180',
 'coupler_ring_gdsfactorypcomponentspcouplerspcoupler_rin_9cdfdde6_0_0',
 'straight_gdsfactorypcomponentspwaveguidespstraight_L0p6_058e2168_10000_11300_A270',
 'straight_gdsfactorypcomponentspwaveguidespstraight_L0p6_058e2168_m14000_10700_A90',
 'straight_gdsfactorypcomponentspwaveguidespstraight_L4_N_a6eac62c_0_21300_A180']
instance_name0 = i[0]
n["instances"][instance_name0]["settings"]
{'allow_min_radius_violation': False,
 'angle': 90,
 'angular_step': None,
 'cross_section': 'strip',
 'layer': None,
 'npoints': None,
 'p': 0.5,
 'radius': None,
 'width': None,
 '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 0x7f574c11f050>
../_images/de5c34f4138b61a7d9f184c85ad8554e7e89b632712d9ec8a5540a9cb71343b7.png
@gf.cell
def mzi_with_bend_deterministic_names_using_alias():
    c = gf.Component()
    mzi = c.add_ref(gf.components.mzi(), name="my_mzi")
    bend = c.add_ref(gf.components.bend_euler(), name="my_bend")
    bend.connect("o1", mzi.ports["o2"])
    return c


c = mzi_with_bend_deterministic_names_using_alias()
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f56f3bb25d0>
../_images/60c06ca71c8fb10d65c27b8674f808c40c4c8d0e44b326a03b5a51ad72965343.png
c = gf.components.mzi()
c.plot()
../_images/a68fc757ae1cd98e077bfe7e6bb1731c55692b5a19aa564327e87968f698e92c.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 0x7f56f389a450>
../_images/36d059361537cce933c4b6220091d7436ab6b17ffaecc6705bb257f4ecb3b302.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(), name="mmi")
    bend = c.add_ref(gf.components.bend_euler(layer=(2, 0)), name="bend")
    bend.connect("o1", mmi.ports["o2"], allow_layer_mismatch=True)
    return c


c = mmi_with_bend()
c.plot()
../_images/c14c392cec4da580f97ff459cb1619019cbe02df9c6bdd10a386b2d0a4182b5d.png
n = c.get_netlist()
print(n["warnings"])
{'optical': {'unconnected_ports': ({'ports': ('mmi,o1', 'mmi,o3', 'bend,o2'), 'values': ((-10, 0), (15.5, -0.625), (25.5, 10.625)), 'message': '3 unconnected optical ports!'},)}}
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f56f3789a90>
../_images/0b5e90f68ea3c457c9159b4330965e67ab2dd84bc7d65f44aadc1fc74987658e.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/0cc2fcbe24c935123408fe08dd7bb96293353af4565fad8d2311f86f6dcc7a56.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f56f395c6d0>
../_images/a70442c2166061712dcd1ea69e0ae886cde5c626076336551607decc296d0821.png
c = gf.components.ring_double()
c.plot()
../_images/75909c3d434b5f187d48d0988bc1e27c9ef543fb6a3c6548ca00c1f358ce2fb4.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f56f38ed110>
../_images/1a5e39b4c155609247e0985950827b83c356c82aca13e20a575526362ee28e8e.png
c = gf.components.mzit()
c.plot()
../_images/b70343486b17f4747b4de10278e81c5aa8b32969f82af4d88ccade967c46b51e.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f56f34d0b10>
../_images/6a4ffbfe3506fdffaf9b4f8e0fdd897a25702821dee3854a94532c2a5e3e29c6.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/c106dbad7563bda265fa369e180265650393d5af9e59cbcd494b5bbb80939da0.png
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f56f34c8050>
../_images/e1941f1f37bf41eb7602477fceb1c076ccd65a757e9c7524d5bceea48b73bfa5.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/f7f0a1f65958ba4a9128ecc66af961c467475c0f16497384771a2d99da0377b7.png
n = c.get_netlist()
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f56f3940ed0>
../_images/b6f39decdc1e2e2a20d6127fad829d629ece580976309705035331d00a93415c.png
n_recursive = c.get_netlist(recursive=True)
n_recursive.keys()
dict_keys(['mzi_lattice_gdsfactorypcomponentspmzispmzi_lattice_CL10_1ef6aef7', 'mzi_gdsfactorypcomponentspmzispmzi_DL10_LY2_LXNone_Bben_a745c7f1', 'mzi_gdsfactorypcomponentspmzispmzi_DL100_LY2_LXNone_Bbe_21f47d0c', 'mzi_gdsfactorypcomponentspmzispmzi_DL200_LY2_LXNone_Bbe_745dab54'])

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 0x7f56f31ea250>
../_images/0f8261da4b0140157780bf6db81e29f80d9023c89f05cedf0022247b5b688e33.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.rotate(90)

vdiv.plot()
../_images/ffd7b7b5d8dd466ab851ab2ced64ce398fccd0633e754969a69ee18f675e72bd.png
try:
    vdiv.get_netlist()
except Exception as exc:
    print(exc)
vdiv.get_netlist(allow_multiple=True)
{'nets': ({'p1': 'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_0_0,pad1',
   'p2': 'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_0_m50000_A180,pad2'},
  {'p1': 'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_0_0,pad1',
   'p2': 'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_m100000_m50000_A180,pad1'},
  {'p1': 'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_0_0,pad2',
   'p2': 'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_0_m50000_A180,pad1'},
  {'p1': 'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_0_m50000_A180,pad2',
   'p2': 'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_m100000_m50000_A180,pad1'}),
 'instances': {'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_0_0': {'component': 'resistance_sheet',
   'info': {'resistance': 0, 'length': 50, 'width': 10},
   'settings': {'width': 10,
    'layers': ('HEATER',),
    'layer_offsets': (0, 0.2),
    'pad': 'via_stack_heater_mtop',
    'pad_size': (50, 50),
    'pad_pitch': 100,
    'ohms_per_square': None,
    'pad_port_name': 'e4'}},
  'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_0_m50000_A180': {'component': 'resistance_sheet',
   'info': {'resistance': 0, 'length': 50, 'width': 10},
   'settings': {'width': 10,
    'layers': ('HEATER',),
    'layer_offsets': (0, 0.2),
    'pad': 'via_stack_heater_mtop',
    'pad_size': (50, 50),
    'pad_pitch': 100,
    'ohms_per_square': None,
    'pad_port_name': 'e4'}},
  'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_50000_0_A270': {'component': 'resistance_sheet',
   'info': {'resistance': 0, 'length': 50, 'width': 10},
   'settings': {'width': 10,
    'layers': ('HEATER',),
    'layer_offsets': (0, 0.2),
    'pad': 'via_stack_heater_mtop',
    'pad_size': (50, 50),
    'pad_pitch': 100,
    'ohms_per_square': None,
    'pad_port_name': 'e4'}},
  'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_m100000_m50000_A180': {'component': 'resistance_sheet',
   'info': {'resistance': 0, 'length': 50, 'width': 10},
   'settings': {'width': 10,
    'layers': ('HEATER',),
    'layer_offsets': (0, 0.2),
    'pad': 'via_stack_heater_mtop',
    'pad_size': (50, 50),
    'pad_pitch': 100,
    'ohms_per_square': None,
    'pad_port_name': 'e4'}}},
 'placements': {'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_0_0': {'x': 0,
   'y': 0,
   'rotation': 0,
   'mirror': False},
  'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_0_m50000_A180': {'x': 0,
   'y': -50,
   'rotation': 180,
   'mirror': False},
  'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_50000_0_A270': {'x': 50,
   'y': 0,
   'rotation': 270,
   'mirror': False},
  'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_m100000_m50000_A180': {'x': -100,
   'y': -50,
   'rotation': 180,
   'mirror': False}},
 'ports': {},
 'name': 'Unnamed_86',
 'warnings': {'electrical': {'unconnected_ports': ({'ports': ('resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_m100000_m50000_A180,pad2',
      'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_50000_0_A270,pad1',
      'resistance_sheet_gdsfactorypcomponentsppcmspresistance__cb73a501_50000_0_A270,pad2'),
     'values': ((-150, -25), (25, 50), (25, -50)),
     'message': '3 unconnected electrical ports!'},)}}}