Skip to content

API Verification

KLayout DRC

gplugins.klayout.drc.write_drc.write_drc_deck_macro(rules, layers=None, name='generic', filepath=None, shortcut='Ctrl+Shift+D', mode='tiled', threads=4, tile_size=500, tile_borders=None)

Write KLayout DRC macro.

You can customize the shortcut to run the DRC macro from the Klayout GUI.

Parameters:

Name Type Description Default
rules list[str]

list of rules.

required
layers dict[str, Layer] | None

layer definitions can be dict or dataclass.

None
name str

drc rule deck name.

'generic'
filepath PathType | None

Optional macro path (defaults to .klayout/drc/name.lydrc).

None
shortcut str

to run macro from KLayout GUI.

'Ctrl+Shift+D'
mode str

tiled, default or deep (hierarchical).

'tiled'
threads int

number of threads.

4
tile_size int

in um for tile mode.

500
tile_borders int | None

sides for each. Defaults None to automatic.

None

.. code::

import gdsfactory as gf
from gplugins.klayout.drc.write_drc import (
    write_drc_deck_macro,
    check_enclosing,
    check_width,
    check_space,
    check_separation,
    check_area,
    check_density,
)
from gdsfactory.gpdk import LAYER
rules = [
    check_width(layer="WG", value=0.2),
    check_space(layer="WG", value=0.2),
    check_separation(layer1="HEATER", layer2="M1", value=1.0),
    check_enclosing(layer1="VIAC", layer2="M1", value=0.2),
    check_area(layer="WG", min_area_um2=0.05),
    check_density(
        layer="WG", layer_floorplan="FLOORPLAN", min_density=0.5, max_density=0.6
    ),
    check_not_inside(layer="VIAC", not_inside="NPP"),
]

drc_check_deck = write_drc_deck_macro(rules=rules, layers=LAYER, mode="tiled")
print(drc_check_deck)
Source code in gplugins/klayout/drc/write_drc.py
def write_drc_deck_macro(
    rules: list[str],
    layers: dict[str, Layer] | None = None,
    name: str = "generic",
    filepath: PathType | None = None,
    shortcut: str = "Ctrl+Shift+D",
    mode: str = "tiled",
    threads: int = 4,
    tile_size: int = 500,
    tile_borders: int | None = None,
) -> str:
    """Write KLayout DRC macro.

    You can customize the shortcut to run the DRC macro from the Klayout GUI.

    Args:
        rules: list of rules.
        layers: layer definitions can be dict or dataclass.
        name: drc rule deck name.
        filepath: Optional macro path (defaults to .klayout/drc/name.lydrc).
        shortcut: to run macro from KLayout GUI.
        mode: tiled, default or deep (hierarchical).
        threads: number of threads.
        tile_size: in um for tile mode.
        tile_borders: sides for each. Defaults None to automatic.

    .. code::

        import gdsfactory as gf
        from gplugins.klayout.drc.write_drc import (
            write_drc_deck_macro,
            check_enclosing,
            check_width,
            check_space,
            check_separation,
            check_area,
            check_density,
        )
        from gdsfactory.gpdk import LAYER
        rules = [
            check_width(layer="WG", value=0.2),
            check_space(layer="WG", value=0.2),
            check_separation(layer1="HEATER", layer2="M1", value=1.0),
            check_enclosing(layer1="VIAC", layer2="M1", value=0.2),
            check_area(layer="WG", min_area_um2=0.05),
            check_density(
                layer="WG", layer_floorplan="FLOORPLAN", min_density=0.5, max_density=0.6
            ),
            check_not_inside(layer="VIAC", not_inside="NPP"),
        ]

        drc_check_deck = write_drc_deck_macro(rules=rules, layers=LAYER, mode="tiled")
        print(drc_check_deck)

    """
    if mode not in modes:
        raise ValueError(f"{mode!r} not in {modes}")

    script = get_drc_script_start(name=name, shortcut=shortcut)

    script += get_drc_script(
        rules=rules,
        layers=layers,
        threads=threads,
        tile_size=tile_size,
        tile_borders=tile_borders,
        mode=mode,
    )

    script += drc_script_end
    filepath = filepath or get_klayout_path() / "drc" / f"{name}.lydrc"
    filepath = pathlib.Path(filepath)
    dirpath = filepath.parent
    dirpath.mkdir(parents=True, exist_ok=True)
    filepath = pathlib.Path(filepath)
    filepath.write_text(script, encoding="UTF-8")
    print(f"Wrote DRC deck to {str(filepath)!r} with shortcut {shortcut!r}")
    return script

gplugins.klayout.drc.write_drc.check_width(value, layer, angle_limit=90.0)

Min feature size.

Parameters:

Name Type Description Default
value float | int

width in um if float, dbu if int (nm).

required
layer str

layer name.

required
angle_limit float

angle limit in degrees.

90.0
Source code in gplugins/klayout/drc/write_drc.py
def check_width(value: float | int, layer: str, angle_limit: float = 90.0) -> str:
    """Min feature size.

    Args:
        value: width in um if float, dbu if int (nm).
        layer: layer name.
        angle_limit: angle limit in degrees.
    """
    category = "width"
    error = f"{layer} {category} {value}um"
    return (
        f"{layer}.{category}({value}, angle_limit({angle_limit}))"
        f".output({error!r}, {error!r})"
    )

gplugins.klayout.drc.write_drc.check_space(value, layer, angle_limit=90.0)

Min Space between shapes of layer.

Parameters:

Name Type Description Default
value float | int

width in um if float, dbu if int (nm).

required
layer str

layer name.

required
angle_limit float

angle limit in degrees.

90.0
Source code in gplugins/klayout/drc/write_drc.py
def check_space(value: float | int, layer: str, angle_limit: float = 90.0) -> str:
    """Min Space between shapes of layer.

    Args:
        value: width in um if float, dbu if int (nm).
        layer: layer name.
        angle_limit: angle limit in degrees.
    """
    category = "space"
    error = f"{layer} {category} {value}um"
    return (
        f"{layer}.{category}({value}, angle_limit({angle_limit}))"
        f".output({error!r}, {error!r})"
    )

gplugins.klayout.drc.write_drc.check_separation(value, layer1, layer2)

Min space between different layers.

Parameters:

Name Type Description Default
value float | int

width in um if float, dbu if int (nm).

required
layer1 str

layer name.

required
layer2 str

layer name.

required
Source code in gplugins/klayout/drc/write_drc.py
def check_separation(value: float | int, layer1: str, layer2: str) -> str:
    """Min space between different layers.

    Args:
        value: width in um if float, dbu if int (nm).
        layer1: layer name.
        layer2: layer name.
    """
    error = f"min {layer1} {layer2} separation {value}um"
    return f"{layer1}.separation({layer2}, {value}).output({error!r}, {error!r})"

gplugins.klayout.drc.write_drc.check_enclosing(value, layer1, layer2, angle_limit=90.0)

Checks if layer1 encloses (is bigger than) layer2 by value.

Parameters:

Name Type Description Default
value float | int

width in um if float, dbu if int (nm).

required
layer1 str

layer name.

required
layer2 str

layer name.

required
angle_limit float

angle limit in degrees.

90.0
Source code in gplugins/klayout/drc/write_drc.py
def check_enclosing(
    value: float | int, layer1: str, layer2: str, angle_limit: float = 90.0
) -> str:
    """Checks if layer1 encloses (is bigger than) layer2 by value.

    Args:
        value: width in um if float, dbu if int (nm).
        layer1: layer name.
        layer2: layer name.
        angle_limit: angle limit in degrees.

    """
    error = f"{layer1} enclosing {layer2} by {value}um"
    return (
        f"{layer1}.enclosing({layer2}, angle_limit({angle_limit}), {value})"
        f".output({error!r}, {error!r})"
    )

gplugins.klayout.drc.write_drc.check_area(layer, min_area_um2=2.0)

Return script for min area checking.

Parameters:

Name Type Description Default
layer str

layer name.

required
min_area_um2 float | int

min area in um2. int if dbu, float if um.

2.0
Source code in gplugins/klayout/drc/write_drc.py
def check_area(layer: str, min_area_um2: float | int = 2.0) -> str:
    """Return script for min area checking.

    Args:
        layer: layer name.
        min_area_um2: min area in um2. int if dbu, float if um.

    """
    return f"""

min_{layer}_a = {min_area_um2}.um2
r_{layer}_a = {layer}.with_area(0, min_{layer}_a)
r_{layer}_a.output("{layer.upper()}_A: {layer} area < min_{layer}_a um2")
"""

gplugins.klayout.drc.write_drc.check_density(layer='metal1', layer_floorplan='FLOORPLAN', min_density=0.2, max_density=0.8)

Return script to ensure density of layer is within min and max.

based on https://github.com/klayoutmatthias/si4all

Source code in gplugins/klayout/drc/write_drc.py
def check_density(
    layer: str = "metal1",
    layer_floorplan: str = "FLOORPLAN",
    min_density: float = 0.2,
    max_density: float = 0.8,
) -> str:
    """Return script to ensure density of layer is within min and max.

    based on https://github.com/klayoutmatthias/si4all

    """
    return f"""
min_density = {min_density}
max_density = {max_density}

area = {layer}.area
border_area = {layer_floorplan}.area
if border_area >= 1.dbu * 1.dbu

  r_min_dens = polygon_layer
  r_max_dens = polygon_layer

  dens = area / border_area

  if dens < min_density
    # copy border as min density marker
    r_min_dens = {layer_floorplan}
  end

  if dens > max_density
    # copy border as max density marker
    r_max_dens = {layer_floorplan}
  end

  r_min_dens.output("{layer}_Xa: {layer} density below threshold of {min_density}")
  r_max_dens.output("{layer}: {layer} density above threshold of {max_density}")

end

"""

gplugins.klayout.drc.write_drc.check_not_inside(layer, not_inside, size=None)

Checks for that a layer is not inside another layer.

Parameters:

Name Type Description Default
layer str

layer name.

required
not_inside str

layer name.

required
size int | float | None

optional layer size in um if float, dbu if int (nm).

None
Source code in gplugins/klayout/drc/write_drc.py
def check_not_inside(
    layer: str, not_inside: str, size: int | float | None = None
) -> str:
    """Checks for that a layer is not inside another layer.

    Args:
        layer: layer name.
        not_inside: layer name.
        size: optional layer size in um if float, dbu if int (nm).
    """
    if size is None:
        error = f"{layer} not inside {not_inside}"
        return f"{layer}.not_inside({not_inside}).output({error!r}, {error!r})"
    else:
        error = f"{layer} sized by {size} not inside {not_inside}"
        script = f"{layer}_sized = {layer}.size({size})\n "
        script += f"{layer}.not_inside({not_inside}).output({error!r}, {error!r})"
        return script

KLayout Dataprep

gplugins.klayout.dataprep.regions.RegionCollection

A RegionCollection can load a GDS file and make layer operations on it.

It is a dictionary of layers with Region objects.

Parameters:

Name Type Description Default
gdspath PathType

to read GDS from.

required
cell_name str | None

optional top cell name to edit (defaults to the top cell of the layout if None).

None

.. code::

d = RegionCollection(gdspath)
d[LAYER.SLAB90] += 2 # grow slab by 2um
d[LAYER.SLAB90] -= 2 # shrink slab by 2um
d[LAYER.SLAB90].smooth(1000) # smooth slab by 1um points
d[LAYER.DEEP_ETCH] = d[LAYER.SLAB90] # copy layer
d[LAYER.SLAB90].clear() # clear slab150
d.write_gds("out.gds", keep_original=True)
Source code in gplugins/klayout/dataprep/regions.py
class RegionCollection:
    """A RegionCollection can load a GDS file and make layer operations on it.

    It is a dictionary of layers with Region objects.

    Args:
        gdspath: to read GDS from.
        cell_name: optional top cell name to edit (defaults to the top cell of the layout if None).

    .. code::

        d = RegionCollection(gdspath)
        d[LAYER.SLAB90] += 2 # grow slab by 2um
        d[LAYER.SLAB90] -= 2 # shrink slab by 2um
        d[LAYER.SLAB90].smooth(1000) # smooth slab by 1um points
        d[LAYER.DEEP_ETCH] = d[LAYER.SLAB90] # copy layer
        d[LAYER.SLAB90].clear() # clear slab150
        d.write_gds("out.gds", keep_original=True)

    """

    def __init__(self, gdspath: PathType, cell_name: str | None = None) -> None:
        """Initializes the RegionCollection."""
        lib = kf.KCLayout(str(gdspath))
        lib.read(filename=str(gdspath))
        self.layout = lib.cell_by_name(cell_name) if cell_name else lib.top_cell()
        self.lib = lib
        self.regions: dict[tuple[int, int], Region] = {}
        self.cell = lib[lib.top_cell().cell_index()]

    def __getitem__(self, layer: tuple[int, int]) -> Region:
        """Gets a layer from the collection."""
        _assert_is_layer(layer)

        if layer in self.regions:
            return self.regions[layer]
        region = Region()
        layer_index = self.lib.layer(layer[0], layer[1])
        region.insert(self.layout.begin_shapes_rec(layer_index))
        region.merge()
        self.regions[layer] = region
        return region

    def __setitem__(self, layer: tuple[int, int], region: Region) -> None:
        """Sets a layer in the collection."""
        _assert_is_layer(layer)
        self.regions[layer] = region

    def __contains__(self, item: tuple[int, int]) -> bool:
        """Checks if the layout contains the given layer."""
        _assert_is_layer(item)
        layer, datatype = item
        return self.lib.find_layer(layer, datatype) is not None

    def write_gds(
        self,
        gdspath: PathType = GDSDIR_TEMP / "out.gds",
        top_cell_name: str | None = None,
        keep_original: bool = True,
        save_options: kdb.SaveLayoutOptions | None = None,
    ) -> None:
        """Write gds.

        Args:
            gdspath: output gds path.
            top_cell_name: name to use for the top cell of the output library.
            keep_original: if True, keeps all original cells (and hierarchy, to the extent possible) in the output. If false, only explicitly defined layers are output.
            save_options: if provided, specified KLayout SaveLayoutOptions are used when writing the GDS.
        """
        # use the working top cell name if not provided
        if top_cell_name is None:
            top_cell_name = self.layout.name
        c = self.get_kcell(cellname=top_cell_name, keep_original=keep_original)
        if save_options:
            c.write(gdspath, save_options=save_options)
        else:
            c.write(gdspath)

    def plot(self) -> kf.KCell:
        """Plot regions."""
        return self.cell

    def get_kcell(
        self, keep_original: bool = True, cellname: str = "Unnamed"
    ) -> kf.KCell:
        """Returns kfactory cell.

        Args:
            keep_original: keep original cell.
            cellname: for top cell.
        """
        if cellname == "Unnamed":
            uid = str(uuid.uuid4())[:8]
            cellname += f"_{uid}"

        output_lib = kf.KCLayout("output")
        c = kf.KCell(cellname, output_lib)
        if keep_original:
            c.copy_tree(self.layout)
            for layer in self.regions:
                layer_id = output_lib.layer(layer[0], layer[1])
                output_lib.layout.clear_layer(layer_id)

        for layer, region in self.regions.items():
            c.shapes(output_lib.layer(layer[0], layer[1])).insert(region)
        return c

    def show(self, gdspath: PathType = GDSDIR_TEMP / "out.gds", **kwargs: Any) -> None:
        """Show gds in klayout.

        Args:
            gdspath: gdspath.
            kwargs: keyword arguments.

        Keyword Args:
            keep_original: keep original cell.
            cellname: for top cell.
        """
        self.write_gds(**kwargs)
        gf.show(gdspath)

    def __delattr__(self, element) -> None:
        """Deletes a layer from the collection."""
        setattr(self, element, Region())

__init__(gdspath, cell_name=None)

Initializes the RegionCollection.

Source code in gplugins/klayout/dataprep/regions.py
def __init__(self, gdspath: PathType, cell_name: str | None = None) -> None:
    """Initializes the RegionCollection."""
    lib = kf.KCLayout(str(gdspath))
    lib.read(filename=str(gdspath))
    self.layout = lib.cell_by_name(cell_name) if cell_name else lib.top_cell()
    self.lib = lib
    self.regions: dict[tuple[int, int], Region] = {}
    self.cell = lib[lib.top_cell().cell_index()]

__getitem__(layer)

Gets a layer from the collection.

Source code in gplugins/klayout/dataprep/regions.py
def __getitem__(self, layer: tuple[int, int]) -> Region:
    """Gets a layer from the collection."""
    _assert_is_layer(layer)

    if layer in self.regions:
        return self.regions[layer]
    region = Region()
    layer_index = self.lib.layer(layer[0], layer[1])
    region.insert(self.layout.begin_shapes_rec(layer_index))
    region.merge()
    self.regions[layer] = region
    return region

__setitem__(layer, region)

Sets a layer in the collection.

Source code in gplugins/klayout/dataprep/regions.py
def __setitem__(self, layer: tuple[int, int], region: Region) -> None:
    """Sets a layer in the collection."""
    _assert_is_layer(layer)
    self.regions[layer] = region

__contains__(item)

Checks if the layout contains the given layer.

Source code in gplugins/klayout/dataprep/regions.py
def __contains__(self, item: tuple[int, int]) -> bool:
    """Checks if the layout contains the given layer."""
    _assert_is_layer(item)
    layer, datatype = item
    return self.lib.find_layer(layer, datatype) is not None

write_gds(gdspath=GDSDIR_TEMP / 'out.gds', top_cell_name=None, keep_original=True, save_options=None)

Write gds.

Parameters:

Name Type Description Default
gdspath PathType

output gds path.

GDSDIR_TEMP / 'out.gds'
top_cell_name str | None

name to use for the top cell of the output library.

None
keep_original bool

if True, keeps all original cells (and hierarchy, to the extent possible) in the output. If false, only explicitly defined layers are output.

True
save_options SaveLayoutOptions | None

if provided, specified KLayout SaveLayoutOptions are used when writing the GDS.

None
Source code in gplugins/klayout/dataprep/regions.py
def write_gds(
    self,
    gdspath: PathType = GDSDIR_TEMP / "out.gds",
    top_cell_name: str | None = None,
    keep_original: bool = True,
    save_options: kdb.SaveLayoutOptions | None = None,
) -> None:
    """Write gds.

    Args:
        gdspath: output gds path.
        top_cell_name: name to use for the top cell of the output library.
        keep_original: if True, keeps all original cells (and hierarchy, to the extent possible) in the output. If false, only explicitly defined layers are output.
        save_options: if provided, specified KLayout SaveLayoutOptions are used when writing the GDS.
    """
    # use the working top cell name if not provided
    if top_cell_name is None:
        top_cell_name = self.layout.name
    c = self.get_kcell(cellname=top_cell_name, keep_original=keep_original)
    if save_options:
        c.write(gdspath, save_options=save_options)
    else:
        c.write(gdspath)

plot()

Plot regions.

Source code in gplugins/klayout/dataprep/regions.py
def plot(self) -> kf.KCell:
    """Plot regions."""
    return self.cell

get_kcell(keep_original=True, cellname='Unnamed')

Returns kfactory cell.

Parameters:

Name Type Description Default
keep_original bool

keep original cell.

True
cellname str

for top cell.

'Unnamed'
Source code in gplugins/klayout/dataprep/regions.py
def get_kcell(
    self, keep_original: bool = True, cellname: str = "Unnamed"
) -> kf.KCell:
    """Returns kfactory cell.

    Args:
        keep_original: keep original cell.
        cellname: for top cell.
    """
    if cellname == "Unnamed":
        uid = str(uuid.uuid4())[:8]
        cellname += f"_{uid}"

    output_lib = kf.KCLayout("output")
    c = kf.KCell(cellname, output_lib)
    if keep_original:
        c.copy_tree(self.layout)
        for layer in self.regions:
            layer_id = output_lib.layer(layer[0], layer[1])
            output_lib.layout.clear_layer(layer_id)

    for layer, region in self.regions.items():
        c.shapes(output_lib.layer(layer[0], layer[1])).insert(region)
    return c

show(gdspath=GDSDIR_TEMP / 'out.gds', **kwargs)

Show gds in klayout.

Parameters:

Name Type Description Default
gdspath PathType

gdspath.

GDSDIR_TEMP / 'out.gds'
kwargs Any

keyword arguments.

{}

Other Parameters:

Name Type Description
keep_original

keep original cell.

cellname

for top cell.

Source code in gplugins/klayout/dataprep/regions.py
def show(self, gdspath: PathType = GDSDIR_TEMP / "out.gds", **kwargs: Any) -> None:
    """Show gds in klayout.

    Args:
        gdspath: gdspath.
        kwargs: keyword arguments.

    Keyword Args:
        keep_original: keep original cell.
        cellname: for top cell.
    """
    self.write_gds(**kwargs)
    gf.show(gdspath)

__delattr__(element)

Deletes a layer from the collection.

Source code in gplugins/klayout/dataprep/regions.py
def __delattr__(self, element) -> None:
    """Deletes a layer from the collection."""
    setattr(self, element, Region())