---
title: "DrcRules"
description: "Builder for design rule checking rule sets."
canonical_url: "https://www.rosette.dev/docs/api-reference/DrcRules"
markdown_url: "https://www.rosette.dev/docs/api-reference/DrcRules.md"
source_url: "https://github.com/PreFab-Photonics/rosette/blob/f086d7670645fd36c05362d696d442a2b2e74850/www/content/docs/api-reference/DrcRules.mdx"
docs_channel: "main"
docs_revision: "f086d7670645fd36c05362d696d442a2b2e74850"
---

# DrcRules

Builder for DRC rule sets.

Import with `from rosette.drc import DrcRules`.

DrcRules uses a fluent builder pattern. Each method returns a new `DrcRules`
with the rule added, so you can chain calls together. Start with an empty
`DrcRules()` and add rules for minimum width, spacing, area, enclosure,
overlap, angles, and more.

```python
rules = (
    DrcRules()
    .min_width(Layer(1), 0.12, name="WG.W.1")
    .min_spacing(Layer(1), Layer(1), 0.15, name="WG.S.1")
    .min_area(Layer(1), 0.01)
    .min_enclosure(Layer(11), Layer(10), 0.10, name="VIA_ENC")
    .allowed_angles(Layer(1), [0, 90], name="WG.ANG")
)

result = run_drc(cell, rules)
```

## Methods



### `__init__`

```python
__init__() -> None
```

Create an empty DRC rule set.



**Returns:** `None`





### `min_width`

```python
min_width(layer, width, name=None) -> DrcRules
```

Add a minimum width rule for a layer.



- **`layer`** (`Layer | int | tuple[int, int]`)

  Target layer. Accepts a `Layer` object, a single int (datatype defaults to 0),
  or a `(number, datatype)` tuple.





- **`width`** (`float`)

  Minimum allowed width in design units.





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `min_spacing`

```python
min_spacing(layer1, layer2, spacing, name=None) -> DrcRules
```

Add a minimum spacing rule between two layers.

Use the same layer for both arguments to check intra-layer spacing.



- **`layer1`** (`Layer | int | tuple[int, int]`)

  First layer.





- **`layer2`** (`Layer | int | tuple[int, int]`)

  Second layer.





- **`spacing`** (`float`)

  Minimum allowed spacing in design units.





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `min_area`

```python
min_area(layer, area, name=None) -> DrcRules
```

Add a minimum area rule for a layer.



- **`layer`** (`Layer | int | tuple[int, int]`)

  Target layer.





- **`area`** (`float`)

  Minimum allowed polygon area in design units squared.





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `min_enclosure`

```python
min_enclosure(inner, outer, enclosure, name=None) -> DrcRules
```

Add an enclosure rule (inner layer must be enclosed by outer layer).



- **`inner`** (`Layer | int | tuple[int, int]`)

  Inner layer that must be enclosed.





- **`outer`** (`Layer | int | tuple[int, int]`)

  Outer layer that must enclose the inner layer.





- **`enclosure`** (`float`)

  Minimum enclosure distance in design units.





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `require_overlap`

```python
require_overlap(layer1, layer2, name=None) -> DrcRules
```

Add a rule requiring overlap between two layers.



- **`layer1`** (`Layer | int | tuple[int, int]`)

  First layer.





- **`layer2`** (`Layer | int | tuple[int, int]`)

  Second layer.





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `forbid_overlap`

```python
forbid_overlap(layer1, layer2, name=None) -> DrcRules
```

Add a rule forbidding overlap between two layers. Can also be used with the
same layer for both arguments to detect overlapping polygons within a single
layer. In TOML config, use `no_overlap = true` in a per-layer section as a
shorthand for `forbid_overlap(layer, layer)`.



- **`layer1`** (`Layer | int | tuple[int, int]`)

  First layer (can equal `layer2` for same-layer overlap detection).





- **`layer2`** (`Layer | int | tuple[int, int]`)

  Second layer (can equal `layer1` for same-layer overlap detection).





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `allowed_angles`

```python
allowed_angles(layer, angles, name=None) -> DrcRules
```

Add a rule restricting polygon edge angles to specified values (in degrees).



- **`layer`** (`Layer | int | tuple[int, int]`)

  Target layer.





- **`angles`** (`list[float]`)

  List of allowed edge angles in degrees (e.g., `[0, 90]` for Manhattan geometry).





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `min_edge_length`

```python
min_edge_length(layer, length, name=None) -> DrcRules
```

Add a minimum edge length rule for a layer. Catches tiny jogs and notches.



- **`layer`** (`Layer | int | tuple[int, int]`)

  Target layer.





- **`length`** (`float`)

  Minimum allowed edge length in design units.





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `no_self_intersection`

```python
no_self_intersection(layer, name=None) -> DrcRules
```

Add a self-intersection check for a layer. Detects invalid (self-crossing) geometry.



- **`layer`** (`Layer | int | tuple[int, int]`)

  Target layer.





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `max_width`

```python
max_width(layer, width, name=None) -> DrcRules
```

Add a maximum width rule for a layer. Useful for enforcing single-mode waveguide constraints.



- **`layer`** (`Layer | int | tuple[int, int]`)

  Target layer.





- **`width`** (`float`)

  Maximum allowed width in design units.





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `snap_to_grid`

```python
snap_to_grid(layer, grid_pitch, name=None) -> DrcRules
```

Add a snap-to-grid check for a layer. Verifies all polygon vertex coordinates are
multiples of the manufacturing grid pitch. Off-grid geometry causes mask fracturing
errors and is rejected by most foundries.

Unlike other per-polygon rules, snap-to-grid checks run on fully-transformed (world)
coordinates so that off-grid translations of cell instances are caught.

Common grid pitches: `0.001` (1 nm) or `0.005` (5 nm).

In TOML config, use `snap_to_grid = 0.001` in a per-layer section.



- **`layer`** (`Layer | int | tuple[int, int]`)

  Target layer.





- **`grid_pitch`** (`float`)

  Grid pitch in design units (e.g., `0.001` for 1 nm, `0.005` for 5 nm). Must be positive.





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `acute_angle`

```python
acute_angle(layer, threshold_deg, name=None) -> DrcRules
```

Add an acute interior angle check for a layer. Flags convex polygon vertices
whose interior angle is strictly less than `threshold_deg`.

Reflex (concave, > 180°) vertices are ignored because they represent the polygon turning
outward and are not a lithography risk. Only inward-pointing sharp corners, which
round off during lithography and can cause fracturing issues, are reported.

A common threshold in photonic PDKs is `60.0` degrees.

In TOML config, use `acute_angle = 60.0` in a per-layer section.



- **`layer`** (`Layer | int | tuple[int, int]`)

  Target layer.





- **`threshold_deg`** (`float`)

  Minimum allowed convex interior angle in degrees. Vertices with an interior angle
  strictly less than this are reported.





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `not_inside`

```python
not_inside(inner, outer, name=None) -> DrcRules
```

Add a not-inside / exclusion-zone rule. Flags polygons on `inner` that are fully
contained inside the union of polygons on `outer`.

Partial crossings, where an inner polygon crosses an outer boundary, are not
violations. The inner polygon must sit wholly inside an outer region for the rule
to trigger. Use this for keep-out zones, such as no-fly regions for a routing
layer.

Distinct from `forbid_overlap`, which flags any overlap at all.

In TOML config, add to the `[[drc.rules]]` array:

```toml
[[drc.rules]]
type = "not_inside"
inner = "silicon"
outer = "keepout"
name = "KEEPOUT.SI"
```



- **`inner`** (`Layer | int | tuple[int, int]`)

  Layer whose polygons are being checked for containment.





- **`outer`** (`Layer | int | tuple[int, int]`)

  Layer defining the exclusion / keep-out region. Polygons on this layer are unioned
  before the containment test, so adjacent outer polygons collectively count as a
  single exclusion zone.





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `density`

```python
density(layer, window, step, min=None, max=None, region_layer=None, name=None) -> DrcRules
```

Add a layer density (CMP uniformity) check.

Tiles a region with a sliding `window` × `window` square, stepping by `step`,
and flags every window position where the area fraction covered by `layer`
falls outside `[min, max]`.

Foundries require density within a band for CMP (chemical-mechanical
planarization) uniformity, a likely tape-out blocker if omitted. Typical
photonic-PDK values: silicon device layer `min=0.20, max=0.80` over a 100 µm
window with 50 µm step.

At least one of `min` or `max` must be provided. If `region_layer` is set, the
union of polygons on that layer defines the region over which density is
measured; otherwise the bounding box of all placed geometry in the design is
used (equivalent to `Library.cell_bbox` on the top cell). Designs with no
geometry at all skip the check silently.

In TOML config, use the grouped `[drc.layers.<layer>.density]` subtable:

```toml
[drc.layers.silicon.density]
min = 0.20
max = 0.80
window = 100.0
step = 50.0         # optional; defaults to window / 2
# region_layer = "prbnd"   # optional; defaults to placed-geometry bbox
```



- **`layer`** (`Layer | int | tuple[int, int]`)

  Target layer whose area fraction is measured.





- **`window`** (`float`)

  Window side length in design units.





- **`step`** (`float`)

  Stride between window positions in design units. Typically `window / 2` for
  sliding-window hot-spot detection.





- **`min`** (`float | None`, default `None`)

  Minimum required density fraction in `[0, 1]`, or `None` for no lower bound.





- **`max`** (`float | None`, default `None`)

  Maximum allowed density fraction in `[0, 1]`, or `None` for no upper bound.





- **`region_layer`** (`Layer | int | tuple[int, int] | None`, default `None`)

  Optional marker layer whose union defines the region over which density is
  measured. If omitted, the bounding box of all placed geometry in the design
  is used.





- **`name`** (`str | None`, default `None`)

  Optional rule name for violation reporting.





**Returns:** `DrcRules`

A new DrcRules with the rule added.





### `warning_margin`

```python
warning_margin(margin) -> DrcRules
```

Set a global warning margin (in design units, typically µm). Near-threshold
violations on length-based numeric rules whose measured value is within
`margin` of the required threshold are reported as `severity == "warning"`
instead of `"error"`. Warnings do not cause [`DrcResult.passed`](/docs/api-reference/DrcResult#passed)
to be `False` and do not fail `rosette check` / `rosette drc`.

For example, with `min_width = 0.12` and `warning_margin = 0.01`:

* width `< 0.11` → error
* width in `[0.11, 0.12)` → warning
* width `≥ 0.12` → no violation

Applies to `min_width`, `min_spacing`, `min_enclosure`, `min_edge_length`,
and `max_width`, all of which compare in length units.

**Excluded:** `min_area` thresholds are in *squared* units and `density`
values are dimensionless fractions, so neither is commensurate with a
length-unit margin; both remain strict errors. Categorical / binary checks
(`allowed_angles`, `require_overlap`, `forbid_overlap`,
`no_self_intersection`, `snap_to_grid`, `acute_angle`, `not_inside`) are also
unaffected.

Pass `0.0` (or any non-positive value) to disable. The default behavior,
where every violation is an error, is preserved until you opt in.

In TOML config:

```toml
[drc]
warning_margin = 0.01
```



- **`margin`** (`float`)

  Margin in design units (typically µm). Pass `0.0` to disable.





**Returns:** `DrcRules`

A new DrcRules with the margin set.