Skip to content

Missing net in layout

File: pics/simple_splitter_with_error.pic.yml

Error caught: net — connection mmi,o3 ↔ wg_out2,o1 is declared in the schematic but the ports don't meet in the layout because wg_out2 is offset.

Error type: LVS.net.missing_in_layout

Expected: ok=False, error_count=3

import copy
import tempfile
from pathlib import Path

import elvis
import gdsfactory as gf
from IPython.display import Markdown
from kwasm import Tool, show

gf.gpdk.PDK.activate()

PICS = Path("../pics")
BUILD_GDS = Path("../build/gds")
BUILD_GDS.mkdir(parents=True, exist_ok=True)
PIC = PICS / "simple_splitter_with_error.pic.yml"

Schematic

The schematic places wg_out2 with an extra dx=2.247, dy=-10.826 offset — shifting it ~11 µm south of its nominal position and breaking the connection to mmi,o3.

schematic = elvis.load_schematics(PIC)
schematic
{'simple_splitter_with_error': {'instances': {'mmi': {'component': 'mmi1x2',
    'settings': {}},
   'wg_in': {'component': 'straight', 'settings': {'length': 10}},
   'wg_out1': {'component': 'straight', 'settings': {'length': 10}},
   'wg_out2': {'component': 'straight', 'settings': {'length': 10}}},
  'connections': {'mmi,o2': 'wg_out1,o1', 'wg_in,o2': 'mmi,o1'},
  'nets': [{'p1': 'mmi,o3', 'p2': 'wg_out2,o1'}],
  'ports': {'o1': 'wg_in,o1', 'o2': 'wg_out1,o2', 'o3': 'wg_out2,o2'},
  'placements': {'mmi': {'x': 0, 'y': 0},
   'wg_in': {'x': -20, 'y': 0},
   'wg_out1': {'x': 15.5, 'y': 0.625},
   'wg_out2': {'x': 15.5,
    'y': -0.625,
    'dx': 2.247,
    'dy': -10.826,
    'rotation': 0,
    'mirror': False}}}}

Note

note the explicitly added net:

'nets': [{'p1': 'mmi,o3', 'p2': 'wg_out2,o1'}],

Which is the promise we won't be keeping in this netlist.

Build from schematic

gds_path = BUILD_GDS / "simple_splitter_with_error.gds"
c = gf.read.from_yaml(schematic["simple_splitter_with_error"])
c.write_gds(gds_path)
show(gds_path, netlist=PIC, tools=[Tool.FIT_ALL, Tool.INSTANCE_PORTS])
GDS Layout Preview

The Bug: Placement Offset Breaks the Connection

wg_out2 is declared in the schematic with an explicit dx/dy offset:

placements:
  wg_out2:
    x: 15.5
    y: -0.625
    dx: 2.247
    dy: -10.826   # ← shifts wg_out2 ~11 µm off its nominal position

In GDSFactory placements, dx/dy adds to x/y, so wg_out2 ends up at (17.747, -11.451) instead of (15.5, -0.625). Its o1 port no longer aligns with mmi,o3 — Elvis cannot find the wire and reports the connection as missing in the layout.

LVS Results

rdb = elvis.lvs_rdb(gds_path, schematic)
lyrdb = Path(tempfile.gettempdir()) / "simple_splitter_with_error.lyrdb"
rdb.save(str(lyrdb))
show(gds_path, lyrdb=lyrdb, netlist=PIC, tools=[Tool.FIT_ALL])
GDS Layout Preview

Net errors in detail:

print(f"ok={rdb.num_items() == 0}, error_count={rdb.num_items()}")
Markdown(elvis.error_summary(rdb))
ok=False, error_count=3
cell error type description
simple_splitter_with_error LVS.net.missing_in_layout Net mmi,o3 <-> wg_out2,o1 in schematic but not in layout
simple_splitter_with_error LVS.open Open port: mmi,o3 is not connected
simple_splitter_with_error LVS.open Open port: wg_out2,o1 is not connected

Fix

Correct the placement in simple_splitter_with_error.pic.yml — remove or zero out the offset:

placements:
  wg_out2:
    x: mmi,o3
    y: mmi,o3
    port: o1
schematic_fixed = copy.deepcopy(schematic)
wg_out2_pl = schematic_fixed["simple_splitter_with_error"]["placements"]["wg_out2"]

# place port o1 of 'wg_out2' at the x and y position of port o3 of 'mmi'
wg_out2_pl["port"] = "o1"
wg_out2_pl["x"] = "mmi,o3"
wg_out2_pl["y"] = "mmi,o3"
wg_out2_pl["dx"] = 0.0
wg_out2_pl["dy"] = 0.0

# or alternatively connect wg_out2,o1 to mmi,o3
# note: the order when connecting is important:
# the first one gets moved (and possibly rotated) to the second one.
connections = schematic_fixed["simple_splitter_with_error"]["connections"]
connections["wg_out2,o1"] = "mmi,o3"

c_fixed = gf.read.from_yaml(schematic_fixed["simple_splitter_with_error"])
c_fixed.write_gds(gds_path)
rdb_fixed = elvis.lvs_rdb(gds_path, schematic_fixed)
rdb_fixed.save(str(lyrdb))
show(gds_path, lyrdb=lyrdb, netlist=PIC, tools=[Tool.FIT_ALL])
GDS Layout Preview

Why it matters

Unconnected instances can happen in many circumstances:

  • You forgot to connect them
  • You connected them but then moved them (the flexibility and dynamic nature of GDSFactory can be a blessing and a curse)
  • There is a small nanometer sized gap between two components that are supposed to be connected (the most devious of all the occurences)

Elvis catches all of these circumstances.