Skip to content

tscircuit/high-density-repair03

Repository files navigation

high-density-repair03

This package contains a GlobalDrcForceImproveSolver for improving high-density PCB routes against DRC-style errors.

Install

bun install 

Develop

Run the solver debugger page:

bun run start

Run tests:

bun test

Run typecheck:

bun run typecheck

Benchmark

Run the DRC14 benchmark locally:

bun run benchmark:drc14

You can also use the shell wrapper, which is the entrypoint used by CI:

./benchmark.sh
./benchmark.sh 10
./benchmark.sh --limit all --concurrency 4
./benchmark.sh --scenario-limit 20 --effort 2 --max-iterations 100

The benchmark runs the pinned dataset-drc14 samples through GlobalDrcForceImproveSolver. It prints each sample's initial-to-final DRC count, then prints a summary table. By default it writes benchmark-result.json; this is generated output and is ignored by git.

Useful options:

  • --limit / --scenario-limit: run the first N samples, or all
  • --concurrency N|auto: number of Bun workers
  • --effort: solver effort value
  • --max-iterations: solver max iteration override
  • --out: output path for the JSON benchmark report
  • --no-out: skip writing the JSON report
  • --json: print the JSON report to stdout
  • --fail-on-drc: exit non-zero if final DRC issues remain

Benchmark CI

Benchmark CI can be triggered by commenting on a PR:

/benchmark [benchmark.sh args...]

Examples:

/benchmark
/benchmark 10
/benchmark all --concurrency 4
/benchmark --scenario-limit all --effort 2
/benchmark --scenario-limit 20 --max-iterations 100

PRs with [BENCHMARK TEST] in the title run the benchmark workflow automatically on PR updates. The workflow can also be run manually with workflow_dispatch, including scenario limit, concurrency, effort, max iterations, and ref inputs.

For PR comment runs, CI posts Markdown tables for the PR benchmark and the latest successful main benchmark artifact when available. The PR table includes deltas versus main for DRC counts and timing metrics.

Usage

The main export is GlobalDrcForceImproveSolver:

import { GlobalDrcForceImproveSolver } from "high-density-repair03"

const solver = new GlobalDrcForceImproveSolver({
  srj: {
    bounds: { minX: 0, minY: 0, maxX: 10, maxY: 10 },
    connections: [{ name: "A" }, { name: "B" }],
    obstacles: [],
    layerCount: 2,
    minTraceWidth: 0.1,
    minViaDiameter: 0.3,
    defaultObstacleMargin: 0.1,
  },
  hdRoutes: [
    {
      connectionName: "A",
      route: [
        { x: 1, y: 5, z: 0 },
        { x: 5, y: 5, z: 0 },
        { x: 9, y: 5, z: 0 },
      ],
      vias: [],
      traceThickness: 0.1,
      viaDiameter: 0.3,
    },
    {
      connectionName: "B",
      route: [
        { x: 5, y: 1, z: 0 },
        { x: 5, y: 5, z: 0 },
        { x: 5, y: 9, z: 0 },
      ],
      vias: [],
      traceThickness: 0.1,
      viaDiameter: 0.3,
    },
  ],
  drcEvaluator: ({ traces }) => {
    const horizontal = traces.find((trace) => trace.connection_name === "A")
    const vertical = traces.find((trace) => trace.connection_name === "B")
    const hMid = horizontal?.route[1]
    const vMid = vertical?.route[1]
    if (!hMid || !vMid) return []

    const distance = Math.hypot(hMid.x - vMid.x, hMid.y - vMid.y)
    return distance < 0.15
      ? [
          {
            message: `trace clearance gap: ${distance.toFixed(3)}mm required: 0.150mm`,
            center: { x: (hMid.x + vMid.x) / 2, y: (hMid.y + vMid.y) / 2 },
            pcb_trace_id: "A_0",
          },
        ]
      : []
  },
})

solver.solve()

const output = solver.getOutput()
console.log(output.drc.count)
console.log(output.hdRoutes)

Algorithm

The solver follows the same high-level approach as the GlobalDrcForceImproveSolver in tscircuit-autorouter:

  1. Score the current routed solution with relaxed DRC.
  2. Try one broad repulsion pass across vias, traces, and obstacles.
  3. If that helps, keep it.
  4. Run targeted error-centered force passes using the current DRC error centers.
  5. Accept a candidate only when it improves the upstream objective: lower DRC count, or for equal count, lower issue score, or for equal count, fewer via DRC issues.

That means this repo is intended to mirror the same repair concept and selection criteria used in the autorouter repo, while exposing a friendlier standalone package API and debugger visualization.

Input shape

srj expects:

  • bounds: routing area { minX, minY, maxX, maxY }
  • connections: logical connection list, each with at least name
  • obstacles: rectangular keepouts or copper obstacles
  • layerCount: board layer count
  • minTraceWidth: minimum allowed trace width
  • minViaDiameter: optional via diameter default
  • defaultObstacleMargin: optional obstacle margin default

hdRoutes expects one or more routes shaped like:

{
  connectionName: "A",
  route: [
    { x: 1, y: 5, z: 0 },
    { x: 5, y: 5, z: 0 },
    { x: 9, y: 5, z: 0 },
  ],
  vias: [],
  traceThickness: 0.1,
  viaDiameter: 0.3,
}

DRC Evaluator

This repo does not bundle a full PCB DRC engine. Instead, you provide drcEvaluator, which receives:

  • srj
  • routes
  • traces

It should return either:

  • an array of error objects, or
  • an object with errors and optional errorsWithCenters

For best results, each error should include:

  • message: used to estimate severity
  • center or pcb_center: the location of the violation
  • pcb_trace_id for trace-related violations
  • pcb_via_ids for via-related violations

Output

solver.getOutput() returns:

{
  hdRoutes: HighDensityRoute[],
  drc: {
    errors: DrcError[],
    count: number,
    issueScore: number,
    traceRouteIndexById: Map<string, number>
  }
}

Using This In tscircuit-autorouter

Inside tscircuit-autorouter, the solver is typically used as an internal pipeline step after trace widths are assigned:

import { GlobalDrcForceImproveSolver } from "../../solvers/GlobalDrcForceImproveSolver/GlobalDrcForceImproveSolver"

const solver = new GlobalDrcForceImproveSolver({
  srj: cms.srjWithPointPairs!,
  hdRoutes: cms.traceWidthSolver!.getHdRoutesWithWidths(),
  effort: cms.effort,
})

solver.solve()

const repairedRoutes = solver.getOutput()

That is the same pattern used in AutoroutingPipelineSolver4_TinyHypergraph in your local tscircuit-autorouter checkout.

For direct tests in tscircuit-autorouter, usage looks like:

import { GlobalDrcForceImproveSolver } from "lib/solvers/GlobalDrcForceImproveSolver/GlobalDrcForceImproveSolver"

const solver = new GlobalDrcForceImproveSolver({
  srj,
  hdRoutes: inputRoutes,
  effort: 1,
})

solver.solve()

const outputRoutes = solver.getOutput()

One API difference to keep in mind:

  • In tscircuit-autorouter, getOutput() returns HighDensityRoute[].
  • In this standalone repo, getOutput() returns { hdRoutes, drc } so you can inspect the resulting DRC snapshot directly.

Compatibility Export

MySolver is still exported as a thin wrapper around GlobalDrcForceImproveSolver with empty defaults, mainly for the existing debugger page and smoke tests.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors