Skip to content

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.

schematic = elvis.load_schematics(PIC)
schematic
{'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])
GDS Layout Preview

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])
GDS Layout Preview

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:

  1. Chain building — instances are grouped into chains:
  2. 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".
  3. Each multi-port reference component (splitter, combiner, pad, …) is its own single-instance chain.
  4. Bare polygons drawn directly in the top cell are collected into a single top-cell polygons chain.
  5. 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.
  6. 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.
  7. 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])
GDS Layout Preview

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])
GDS Layout Preview

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,e3pad2,e1
route pad3 -> pad4 pad3,e3pad4,e3
new net pad1,e3pad3,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.