Design rule checking (DRC)#

Design Rule Check (DRC) engine for PyEDB.

This module provides a high-performance, multi-threaded design-rule checker that runs inside an open PyEDB session and validates industry-standard rules including geometry, spacing, manufacturing, high-speed, and test constraints.

The DRC engine features:

  • Multi-threaded rule checking using ThreadPoolExecutor

  • R-tree spatial indexing for fast geometry queries

  • Impedance checks via analytical formulas (Wheeler, Cohn, Hammerstad-Jensen)

  • Copper balance verification by layer or zone polygons

  • Back-drill stub and depth verification

  • IPC-D-356A netlist export with DRC annotations

Examples#

Basic DRC workflow:

>>> import pyedb
>>> from pyedb.workflows.drc.drc import Drc, Rules
>>> edb = pyedb.Edb(edbpath="my_board.aedb")
>>> rules = Rules.parse_file("rules.json")
>>> drc = Drc(edb)
>>> violations = drc.check(rules)
>>> print(f"Found {len(violations)} violations")

Build rules programmatically:

>>> rules = (
...     Rules()
...     .add_min_line_width("trace_width", "3.5mil")
...     .add_min_clearance("clk2data", "4mil", "CLK*", "DATA*")
...     .add_copper_balance("top_balance", max_percent=10, layers=["TOP"])
... )
>>> drc = Drc(edb)
>>> violations = drc.check(rules)

Export results for fabrication review:

>>> drc.to_ipc356a("fab_review.ipc")

The pyedb.workflows.drc sub-package exposes a lightweight, high-accuracy design-rule checker (DRC) that runs inside an open PyEDB session. It validates more than 50 industry-standard rules (geometry, spacing, manufacturing, high-speed, test) and exports an IPC-D-356A netlist annotated with violations for CAM hand-off.

Features#

  • Impedance checks via improved analytical formulas (Wheeler, Cohn, Hammerstad–Jensen).

  • Copper-balance by layer or by arbitrary zone polygons.

  • Back-drill stub/depth verification.

  • R-tree spatial index for fast geometry queries.

  • Thread-safe, multi-threaded rule execution (automatic core detection).

  • Fluent, type-safe API to build rule decks programmatically.

  • JSON/YAML round-trip serialization (via Pydantic).

Quick start#

import pyedb
from pyedb.workflows.drc.drc import Drc, Rules

edb = pyedb.Edb("my_board.aedb")
rules = (
    Rules()
    .add_min_line_width("pwr", "15 mil")
    .add_min_clearance("clk2data", "4 mil", "CLK*", "DATA*")
    .add_min_annular_ring("via5", "5 mil")
    .add_diff_pair_length_match("usb", tolerance="0.1 mm", pairs=[("USB_P", "USB_N")])
    .add_copper_balance("top_bal", max_percent=10, layers=["TOP"])
)

drc = Drc(edb)
violations = drc.check(rules)
drc.to_ipc356a("fab_review.ipc")

API reference#

Rules container#

Rules

Centralized container for all design rule categories.

Rules.from_dict

Create Rules instance from dictionary.

Rules.to_dict

Convert Rules to dictionary.

Rules.add_min_line_width

Append a minimum line width rule.

Rules.add_min_clearance

Append a minimum clearance rule between nets.

Rules.add_min_annular_ring

Append a minimum annular ring rule for drilled holes.

Rules.add_diff_pair_length_match

Append a differential pair length matching rule.

Rules.add_back_drill_stub_length

Append a maximum back-drill stub length rule.

Rules.add_copper_balance

Append a copper density balance rule.

Rule models#

MinLineWidth

Minimum trace width constraint rule.

MinClearance

Minimum spacing constraint between nets.

MinAnnularRing

Minimum annular ring constraint for drilled holes.

DiffPair

Differential pair net definition.

DiffPairLengthMatch

Length matching constraint for differential pairs.

BackDrillStubLength

Maximum back-drill stub length constraint.

CopperBalance

Copper density balance constraint.

DRC engine#

Drc

High-performance DRC engine for PyEDB.

Drc.check

Run all rules and return a list of violations.

Drc.to_ipc356a

Write a complete IPC-D-356A netlist with DRC annotations.

Implementation notes#

Thread safety#

All heavy geometry checks are embarrassingly parallel. The engine snapshots EDB data into plain Python objects before entering the worker pool, so the R-tree index is never accessed concurrently.

Extending the engine#

Add a new rule in three steps:

  1. Create a Pydantic model inheriting from Pydantic.BaseModel.

  2. Append the model to the Rules container and expose a fluent helper.

  3. Implement _rule_<field_name> inside Drc; accept the rule instance and append violations to self.violations.

Examples#

Load a rule deck from JSON#

import json
from pyedb.workflows.drc.drc import Rules

with open("my_rules.json") as f:
    rules = Rules.from_dict(json.load(f))

Export violations to CSV#

import csv

drc = Drc(edb)
drc.check(rules)

with open("violations.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=drc.violations[0].keys())
    writer.writeheader()
    writer.writerows(drc.violations)