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
from omegaconf import OmegaConf
c = gf.components.mzi()
c.plot()
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f6b5358ef90>
c = gf.components.ring_single()
c.plot()
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f6b4e4e5110>
n = c.get_netlist()
c.write_netlist("ring.yml")
n = OmegaConf.load("ring.yml")
i = list(n["instances"].keys())
i
['bend_euler_1',
'bend_euler_2',
'coupler_ring_1',
'straight_1',
'straight_2',
'straight_3']
instance_name0 = i[0]
n["instances"][instance_name0]["settings"]
{'angle': 90.0, 'cross_section': {'bbox_layers': None, 'bbox_offsets': None, 'components_along_path': [], 'radius': 10.0, 'radius_min': 5.0, 'sections': [{'hidden': False, 'insets': None, 'layer': 'WG', 'name': '_default', 'offset': 0.0, 'offset_function': None, 'port_names': ['o1', 'o2'], 'port_types': ['optical', 'optical'], 'simplify': None, 'width': 0.5, 'width_function': None}]}, 'direction': 'ccw', 'npoints': None, 'p': 0.5, 'radius': 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 0x7f6b4e57a790>
@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()
<networkx.classes.graph.Graph at 0x7f6b53599390>
c = gf.components.mzi()
c.plot()
c = gf.components.mzi()
n = c.get_netlist()
print(c.get_netlist().keys())
dict_keys(['connections', 'instances', 'placements', 'ports', 'name'])
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f6b4e4e8a50>
n.keys()
dict_keys(['connections', '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()
gf.remove_from_cache(c)
c.plot()
n = c.get_netlist()
print(n["warnings"])
{'optical': {'unconnected_ports': [{'ports': ['mmi,o1', 'mmi,o3', 'bend,o2'], 'values': [[-10.0, 0.0], [15.5, -0.625], [25.5, 10.625]], 'message': '3 unconnected optical ports!'}]}}
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f6b4e5c7090>
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()
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f6b535645d0>
c = gf.components.ring_double()
c.plot()
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f6b4e2eb950>
c = gf.components.mzit()
c.plot()
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f6b5bcf66d0>
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()
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f6b4e5d3450>
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()
n = c.get_netlist()
c.plot_netlist()
<networkx.classes.graph.Graph at 0x7f6b4deb08d0>
n_recursive = c.get_netlist_recursive()
n_recursive.keys()
dict_keys(['mzi_lattice_d52c1fad', 'mzi_d52b8f87', 'mzi_cd076e56', 'mzi_48422baa'])
get_netlist_flat#
You can also flatten the recursive netlist
flat_netlist = c.get_netlist_flat()
The flat netlist contains the same keys as a regular netlist:
flat_netlist.keys()
dict_keys(['connections', 'placements', 'instances', 'ports', 'name'])
However, its instances are flattened and uniquely renamed according to hierarchy:
flat_netlist["instances"].keys()
dict_keys(['mzi_lattice_d52c1fad~mzi_1~bend_euler_1', 'mzi_lattice_d52c1fad~mzi_1~bend_euler_2', 'mzi_lattice_d52c1fad~mzi_1~bend_euler_3', 'mzi_lattice_d52c1fad~mzi_1~bend_euler_4', 'mzi_lattice_d52c1fad~mzi_1~bend_euler_5', 'mzi_lattice_d52c1fad~mzi_1~bend_euler_6', 'mzi_lattice_d52c1fad~mzi_1~bend_euler_7', 'mzi_lattice_d52c1fad~mzi_1~bend_euler_8', 'mzi_lattice_d52c1fad~mzi_1~cp1', 'mzi_lattice_d52c1fad~mzi_1~cp2', 'mzi_lattice_d52c1fad~mzi_1~straight_10', 'mzi_lattice_d52c1fad~mzi_1~straight_5', 'mzi_lattice_d52c1fad~mzi_1~straight_6', 'mzi_lattice_d52c1fad~mzi_1~straight_7', 'mzi_lattice_d52c1fad~mzi_1~straight_8', 'mzi_lattice_d52c1fad~mzi_1~straight_9', 'mzi_lattice_d52c1fad~mzi_1~sxb', 'mzi_lattice_d52c1fad~mzi_1~sxt', 'mzi_lattice_d52c1fad~mzi_1~syl', 'mzi_lattice_d52c1fad~mzi_1~sytl', 'mzi_lattice_d52c1fad~mzi_2~bend_euler_1', 'mzi_lattice_d52c1fad~mzi_2~bend_euler_2', 'mzi_lattice_d52c1fad~mzi_2~bend_euler_3', 'mzi_lattice_d52c1fad~mzi_2~bend_euler_4', 'mzi_lattice_d52c1fad~mzi_2~bend_euler_5', 'mzi_lattice_d52c1fad~mzi_2~bend_euler_6', 'mzi_lattice_d52c1fad~mzi_2~bend_euler_7', 'mzi_lattice_d52c1fad~mzi_2~bend_euler_8', 'mzi_lattice_d52c1fad~mzi_2~cp2', 'mzi_lattice_d52c1fad~mzi_2~straight_10', 'mzi_lattice_d52c1fad~mzi_2~straight_5', 'mzi_lattice_d52c1fad~mzi_2~straight_6', 'mzi_lattice_d52c1fad~mzi_2~straight_7', 'mzi_lattice_d52c1fad~mzi_2~straight_8', 'mzi_lattice_d52c1fad~mzi_2~straight_9', 'mzi_lattice_d52c1fad~mzi_2~sxb', 'mzi_lattice_d52c1fad~mzi_2~sxt', 'mzi_lattice_d52c1fad~mzi_2~syl', 'mzi_lattice_d52c1fad~mzi_2~sytl', 'mzi_lattice_d52c1fad~mzi_3~bend_euler_1', 'mzi_lattice_d52c1fad~mzi_3~bend_euler_2', 'mzi_lattice_d52c1fad~mzi_3~bend_euler_3', 'mzi_lattice_d52c1fad~mzi_3~bend_euler_4', 'mzi_lattice_d52c1fad~mzi_3~bend_euler_5', 'mzi_lattice_d52c1fad~mzi_3~bend_euler_6', 'mzi_lattice_d52c1fad~mzi_3~bend_euler_7', 'mzi_lattice_d52c1fad~mzi_3~bend_euler_8', 'mzi_lattice_d52c1fad~mzi_3~cp2', 'mzi_lattice_d52c1fad~mzi_3~straight_10', 'mzi_lattice_d52c1fad~mzi_3~straight_5', 'mzi_lattice_d52c1fad~mzi_3~straight_6', 'mzi_lattice_d52c1fad~mzi_3~straight_7', 'mzi_lattice_d52c1fad~mzi_3~straight_8', 'mzi_lattice_d52c1fad~mzi_3~straight_9', 'mzi_lattice_d52c1fad~mzi_3~sxb', 'mzi_lattice_d52c1fad~mzi_3~sxt', 'mzi_lattice_d52c1fad~mzi_3~syl', 'mzi_lattice_d52c1fad~mzi_3~sytl'])
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_flat(with_labels=False) # labels get cluttered
<networkx.classes.graph.Graph at 0x7f6b4e600610>
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:
vdiv = gf.Component("voltageDivider")
r1 = vdiv << gf.components.resistance_sheet()
r2 = vdiv << gf.components.resistance_sheet()
r3 = vdiv << gf.get_component(gf.components.resistance_sheet).rotate()
r4 = vdiv << gf.get_component(gf.components.resistance_sheet).rotate()
r1.connect("pad2", r2.ports["pad1"])
r3.connect("pad1", r2.ports["pad1"], preserve_orientation=True)
r4.connect("pad2", r2.ports["pad1"], preserve_orientation=True)
vdiv.plot()
try:
vdiv.get_netlist_flat()
except Exception as exc:
print(exc)
Found multiple connections at (-50.0, 0.0):['resistance_sheet_1,pad2', 'resistance_sheet_2,pad1', 'rotate_1,pad1', 'rotate_2,pad2']
vdiv.get_netlist_flat(allow_multiple=True)
{'connections': {'voltageDivider~resistance_sheet_1,pad2': ['voltageDivider~resistance_sheet_2,pad1'],
'voltageDivider~resistance_sheet_2,pad1': ['voltageDivider~resistance_sheet_1,pad2',
'voltageDivider~rotate_1~resistance_sheet_1,pad1'],
'voltageDivider~rotate_1~resistance_sheet_1,pad1': ['voltageDivider~resistance_sheet_2,pad1',
'voltageDivider~rotate_2~resistance_sheet_1,pad2'],
'voltageDivider~rotate_2~resistance_sheet_1,pad2': ['voltageDivider~rotate_1~resistance_sheet_1,pad1']},
'placements': {'voltageDivider~resistance_sheet_1': {'x': -100.0,
'y': 0.0,
'mirror': 0,
'rotation': 0},
'voltageDivider~resistance_sheet_2': {'x': 0.0,
'y': 0.0,
'mirror': 0,
'rotation': 0},
'voltageDivider~rotate_1~resistance_sheet_1': {'x': -50.0,
'y': 50.0,
'mirror': 0,
'rotation': 90},
'voltageDivider~rotate_2~resistance_sheet_1': {'x': -50.0,
'y': -50.0,
'mirror': 0,
'rotation': 90}},
'instances': {'voltageDivider~resistance_sheet_1': {'component': 'resistance_sheet',
'info': {'resistance': 0},
'settings': {'width': 10,
'layers': ['SLAB90', 'NPP'],
'layer_offsets': [0, 0.2],
'pad': {'function': 'via_stack',
'settings': {'layers': ['SLAB90', 'NPP', 'M1'],
'vias': [None,
None,
{'function': 'via',
'settings': {'layer': 'VIAC'},
'module': 'gdsfactory.components.via'}],
'size': [80, 80]},
'module': 'gdsfactory.components.via_stack'},
'pad_pitch': 100.0,
'ohms_per_square': None,
'port_orientation1': 180,
'port_orientation2': 0}},
'voltageDivider~resistance_sheet_2': {'component': 'resistance_sheet',
'info': {'resistance': 0},
'settings': {'width': 10,
'layers': ['SLAB90', 'NPP'],
'layer_offsets': [0, 0.2],
'pad': {'function': 'via_stack',
'settings': {'layers': ['SLAB90', 'NPP', 'M1'],
'vias': [None,
None,
{'function': 'via',
'settings': {'layer': 'VIAC'},
'module': 'gdsfactory.components.via'}],
'size': [80, 80]},
'module': 'gdsfactory.components.via_stack'},
'pad_pitch': 100.0,
'ohms_per_square': None,
'port_orientation1': 180,
'port_orientation2': 0}},
'voltageDivider~rotate_1~resistance_sheet_1': {'component': 'resistance_sheet',
'info': {'resistance': 0},
'settings': {'width': 10,
'layers': ['SLAB90', 'NPP'],
'layer_offsets': [0, 0.2],
'pad': {'function': 'via_stack',
'settings': {'layers': ['SLAB90', 'NPP', 'M1'],
'vias': [None,
None,
{'function': 'via',
'settings': {'layer': 'VIAC'},
'module': 'gdsfactory.components.via'}],
'size': [80, 80]},
'module': 'gdsfactory.components.via_stack'},
'pad_pitch': 100.0,
'ohms_per_square': None,
'port_orientation1': 180,
'port_orientation2': 0}},
'voltageDivider~rotate_2~resistance_sheet_1': {'component': 'resistance_sheet',
'info': {'resistance': 0},
'settings': {'width': 10,
'layers': ['SLAB90', 'NPP'],
'layer_offsets': [0, 0.2],
'pad': {'function': 'via_stack',
'settings': {'layers': ['SLAB90', 'NPP', 'M1'],
'vias': [None,
None,
{'function': 'via',
'settings': {'layer': 'VIAC'},
'module': 'gdsfactory.components.via'}],
'size': [80, 80]},
'module': 'gdsfactory.components.via_stack'},
'pad_pitch': 100.0,
'ohms_per_square': None,
'port_orientation1': 180,
'port_orientation2': 0}}},
'ports': {},
'name': 'voltageDivider'}
from gplugins.gfviz import show
import gdsfactory as gf
show(gf.components.mzi())
show(gf.components.ring_single())