Electrical Short¶
File: pics/elec.pic.yml
Error caught: short — two routes on the metal layer overlap, shorting two independent nets.
Error type: LVS.short
Expected: ok=False, error_count=2 (1 short + 1 missing_in_schematic net group derived from the short)
import tempfile
from copy import deepcopy
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 / "elec.pic.yml"
Schematic¶
Pads connected by route_bundle_electrical routes. Two of the routes overlap on the metal layer, creating a short between nets that should be independent.
{'elec': {'instances': {'pad1': {'component': 'pad', 'settings': {}},
'pad2': {'component': 'pad', 'settings': {}},
'pad3': {'component': 'pad', 'settings': {}},
'pad4': {'component': 'pad', 'settings': {}}},
'routes': {'electrical': {'links': {'pad1,e3': 'pad2,e1'},
'routing_strategy': 'route_bundle_electrical',
'settings': {'allow_layer_mismatch': False,
'allow_type_mismatch': False,
'allow_width_mismatch': False}},
'electrical2': {'links': {'pad3,e3': 'pad4,e3'},
'routing_strategy': 'route_bundle_electrical',
'settings': {'allow_layer_mismatch': False,
'allow_type_mismatch': False,
'allow_width_mismatch': False,
'radius': 10}}},
'ports': {},
'placements': {'pad1': {'x': 0, 'y': 0, 'dx': -98.125, 'dy': -19.273},
'pad2': {'x': 0,
'y': 0,
'dx': 349.71,
'dy': -394.94,
'rotation': 0,
'mirror': False},
'pad3': {'x': -98.125,
'y': -19.273,
'dx': -97.005,
'dy': -423.277,
'rotation': 0,
'mirror': False},
'pad4': {'x': 0,
'y': 0,
'dx': 137.75,
'dy': -124.39,
'rotation': 0,
'mirror': False}}}}
Build from schematic¶
gds_path = BUILD_GDS / "elec.gds"
c = gf.read.from_yaml(schematic["elec"])
c.write_gds(gds_path)
show(gds_path, netlist=PIC, tools=[Tool.FIT_ALL, Tool.INSTANCE_PORTS])
LVS Results¶
rdb = elvis.lvs_rdb(
gds_path,
schematic,
short_layers=[(49, 0)],
equivalent_ports={"pad": ["pad", "e1", "e2", "e3", "e4"]},
)
lyrdb = Path(tempfile.gettempdir()) / "elec.lyrdb"
rdb.save(str(lyrdb))
show(gds_path, lyrdb=lyrdb, netlist=PIC, tools=[Tool.FIT_ALL, Tool.INSTANCE_PORTS])
flags used
The above LVS function call is called with the following flags
- short_layers=[(49, 0)]
- equivalent_ports={'pad': ["pad", "e1", "e2", "e3", "e4"]}
this can also be pre-configured.
Errors in detail:
print(f"ok={rdb.num_items() == 0}, error_count={rdb.num_items()}")
Markdown(elvis.error_summary(rdb))
ok=False, error_count=2
| cell | error type | description |
|---|---|---|
| elec | LVS.net.missing_in_schematic | Net {pad2,{pad,e1,e2,e3,e4}; pad4,{pad,e1,e2,e3,e4}; pad1,{pad,e1,e2,e3,e4}; pad3,{pad,e1,e2,e3,e4}} in layout but not in schematic |
| elec | LVS.short | Geometric short between 'pad3,e3 -> pad4,e3' and 'pad1,e3 -> pad2,e1' (1 location) |
Geometric short detection via short_layers keyword¶
Pass short_layers=[(layer, datatype)] to enable polygon-level short checking.
Elvis runs a four-step pipeline:
- Chain building — instances are grouped into chains:
- Each connected sequence of 2-port route instances (straights, bends, tapers) forms one chain,
named after its reference-component endpoints, e.g.
"pad1,e3 -> pad2,e2". - Each multi-port reference component (splitter, combiner, pad, …) is its own single-instance chain.
- Bare polygons drawn directly in the top cell are collected into a single
top-cell polygonschain. - Polygon extraction — GDS boundaries on the specified layer are extracted per instance and
grouped by chain. Each chain's polygons are unioned into a single
MultiPolygon. - Overlap detection — all pairs of chains are tested for polygon intersection. Overlaps that fall exactly at port locations (where chains legitimately share a boundary) are filtered out.
- Schematic-aware suppression — a detected short is suppressed if all cross-chain port pairs it implies are already declared in the schematic (see the Fix section below for details).
Layer (49,0) is the metal layer in GDSFactory's generic PDK.
Note
The short (last error) is clearly shown as the overlap of the two routed wires. Through that short, all four pad ports involved are physically tied to one electrical net in the layout, but the schematic declares them as two separate nets — Elvis collapses every cross-pair this implies into one group LVS.net.missing_in_schematic error using set notation {pad1,e3 -> pad2,e1; pad3,e3 -> pad4,e3; …}.
Fix¶
Route from pad1 to pad2 by going around pad4. The easiest way to achieve this is by adding a start_straight_length to the route leaving from pad:
schematic2 = deepcopy(schematic)
schematic2["elec"]["routes"]["electrical"]["settings"]["start_straight_length"] = 300
c2 = gf.read.from_yaml(schematic2["elec"])
c2.write_gds(gds_path)
rdb = elvis.lvs_rdb(
gds_path,
schematic2,
short_layers=[(49, 0)],
equivalent_ports={"pad": ["pad", "e1", "e2", "e3", "e4"]},
)
lyrdb = Path(tempfile.gettempdir()) / "elec.lyrdb"
rdb.save(str(lyrdb))
show(gds_path, lyrdb=lyrdb, netlist=PIC, tools=[Tool.FIT_ALL])
Another Fix¶
If the short is intentional one can add (often just one of) the missing nets to the schematic to fix it too.
schematic3 = deepcopy(schematic)
schematic3["elec"]["nets"] = [
# just one should be enough,
# because after adding it it makes the unconnected nets equivalent
{"p1": "pad1,e3", "p2": "pad3,e3"},
# {'p1': 'pad2,e1', 'p2': 'pad3,e3'},
# {'p1': 'pad1,e3', 'p2': 'pad4,e3'},
# {'p1': 'pad2,e1', 'p2': 'pad4,e3'},
]
c2 = gf.read.from_yaml(schematic3["elec"])
c2.write_gds(gds_path)
rdb = elvis.lvs_rdb(
gds_path,
schematic3,
short_layers=[(49, 0)],
equivalent_ports={
"pad": ["pad", "e1", "e2", "e3", "e4"],
},
)
lyrdb = Path(tempfile.gettempdir()) / "elec.lyrdb"
rdb.save(str(lyrdb))
show(gds_path, lyrdb=lyrdb, netlist=PIC, tools=[Tool.FIT_ALL])
Why it works — Transitive Net Closure¶
Adding all four reported nets is the clearest and most explicit approach. But even adding one of them is sufficient, because Elvis builds the transitive closure of all declared connections before checking cross-pairs.
Take pad1,e3 ↔ pad3,e3 as an example. This single net bridges the two otherwise
separate route groups.
| Declared connection | Ports joined |
|---|---|
| route pad1 -> pad2 | pad1,e3 ↔ pad2,e1 |
| route pad3 -> pad4 | pad3,e3 ↔ pad4,e3 |
| new net | pad1,e3 ↔ pad3,e3 ← bridges both groups |
After transitivity: {pad1,e3, pad2,e1, pad3,e3, pad4,e3, pad1,e3} — one equivalence class.
Every cross-pair is now "in the schematic", so the short is suppressed.
Why it matters¶
Electrical shorts on metal routing layers cause catastrophic failures: two independent nets merge into one, and both signals fight each other. Dense pad arrays are especially prone to routing shorts because routes are packed tightly and DRC rules alone may not catch a short that falls within design rules. Elvis's chain-based short detection finds overlaps that are electrically meaningful, not just geometrically close.