Ejemplo n.º 1
0
def test_cache_metadata():
    save_options = kdb.SaveLayoutOptions()
    save_options.gds2_write_file_properties = True
    layout = kdb.Layout()
    layout.set_property(CACHE_PROP_ID, "test1")
    layout.write("tests/tmp/test_cache_metadata.gds", save_options)
    layout2 = kdb.Layout()
    assert layout2.property(CACHE_PROP_ID) is None
    layout2.set_property(CACHE_PROP_ID, "test2")
    assert layout2.property(CACHE_PROP_ID) == "test2"
    layout2.read("tests/tmp/test_cache_metadata.gds")
    assert layout2.property(CACHE_PROP_ID) == "test1"
Ejemplo n.º 2
0
def find_labels(gdspath: Path,
                label_layer: Tuple[int, int] = LAYER.LABEL,
                prefix: str = "opt_") -> Iterator[Tuple[str, float, float]]:
    """finds labels and locations from a GDS file"""
    # Load the layout
    gdspath = str(gdspath)
    layout = pya.Layout()
    layout.read(gdspath)

    # Get the top cell and the units, and find out the index of the layer
    topcell = layout.top_cell()
    dbu = layout.dbu
    layer = pya.LayerInfo(label_layer[0], label_layer[1])
    layer_index = layout.layer(layer)

    # Extract locations
    iterator = topcell.begin_shapes_rec(layer_index)

    while not (iterator.at_end()):
        shape, trans = iterator.shape(), iterator.trans()
        iterator.next()
        if shape.is_text():
            text = shape.text
            if text.string.startswith(prefix):
                transformed = text.transformed(trans)
                yield text.string, transformed.x * dbu, transformed.y * dbu
Ejemplo n.º 3
0
def assemble_subdies(
    mask_name,
    dict_subdies,
    subdies_directory,
    mask_directory=None,
    um_to_grid=UM_TO_GRID,
):
    """
    Args:
        dict_subdies: {subdie_name: (x, y, rotation) in (um, um, deg)}
        subdies_directory: directory where the subdies should be looked for
    """
    top_level_layout = pya.Layout()
    top_level = top_level_layout.create_cell(mask_name)
    if mask_directory is None:
        mask_directory = subdies_directory

    for subdie_name, (x_um, y_um, R) in dict_subdies.items():
        gdspath = os.path.join(subdies_directory, subdie_name + ".gds")
        subdie = load_gds(gdspath).top_cell()

        _subdie = import_cell(top_level_layout, subdie)

        t = pya.Trans(R / 2, 0, int(x_um * um_to_grid), int(y_um * um_to_grid))
        # t = pya.Trans(0, 0)
        subdie_instance = pya.CellInstArray(_subdie.cell_index(), t)
        top_level.insert(subdie_instance)

    top_level.write(os.path.join(mask_directory, mask_name + ".gds"))
    return top_level
Ejemplo n.º 4
0
def import_oas(filename, cellname = None, flatten = False):
    if filename.lower().endswith('.gds'):
        # you are looking for import_gds
        retval = pg.import_gds(filename, cellname = cellname, flatten = flatten)
        return retval
    try:
        import klayout.db as pya
    except ImportError as err:
        err.args = ('[PHIDL] klayout package needed to import OASIS. pip install klayout\n' + err.args[0], ) + err.args[1:]
        raise
    if not filename.lower().endswith('.oas'): filename += '.oas'
    fileroot = os.path.splitext(filename)[0]
    tempfilename = fileroot + '-tmp.gds'

    layout = pya.Layout()
    layout.read(filename)
    # We want to end up with one Device. If the imported layout has multiple top cells,
    # a new toplevel is created, and they go into the second level
    if len(layout.top_cells()) > 1:
        topcell = layout.create_cell('toplevel')
        rot_DTrans = pya.DTrans.R0
        origin = pya.DPoint(0, 0)
        for childcell in layout.top_cells():
            if childcell == topcell: continue
            topcell.insert(pya.DCellInstArray(childcell.cell_index(), pya.DTrans(rot_DTrans, origin)))
    else:
        topcell = layout.top_cell()
    topcell.write(tempfilename)

    retval = pg.import_gds(tempfilename, cellname = cellname, flatten = flatten)
    os.remove(tempfilename)
    return retval
Ejemplo n.º 5
0
def test_metadata():
    save_options = kdb.SaveLayoutOptions()
    save_options.gds2_write_file_properties = True
    save_options.gds2_write_cell_properties = True
    load_options = kdb.LoadLayoutOptions()
    load_options.properties_enabled = True
    layout = kdb.Layout()
    TOP = layout.create_cell("TOP")
    TOP.set_property("key", "test1")
    TOP.set_property(123, "test2")
    layout.write("tests/tmp/test_metadata.gds", save_options)
    layout2 = kdb.Layout()
    layout2.read("tests/tmp/test_metadata.gds", load_options)
    TOP = layout2.top_cell()
    assert TOP.property(123) == "test2"
    assert TOP.property("key") == "test1"
Ejemplo n.º 6
0
 def load_gds(self, filename):
     """ Load a GDS and append it into self.cells """
     layout = pya.Layout()
     WORKING_MEMORY[filename] = layout
     layout.read(str(filename))
     self.cells[layout.top_cell().name] = layout.top_cell()
     self.cells[layout.top_cell().name].metadata = {}
Ejemplo n.º 7
0
def check_width(gdspath,
                layer: Tuple[int, int] = (1, 0),
                min_width: float = 0.150,
                dbu: float = 1e3):
    """Reads layer from top cell and returns a number of edges violating min width

    Args:
        gdspath: path to GDS or Component
        layer: tuple (int, int)
        min_width: in um
        dbu: database units (1000 um/nm)
    """
    from pp.component import Component
    from pp.write_component import write_gds

    if isinstance(gdspath, Component):
        gdspath.flatten()
        gdspath = write_gds(gdspath)
    layout = pya.Layout()
    layout.read(str(gdspath))
    cell = layout.top_cell()
    region = pya.Region(cell.begin_shapes_rec(layout.layer(layer[0],
                                                           layer[1])))
    # print(region)
    # print(min_width*1e3)
    return len(region.width_check(min_width * dbu))
Ejemplo n.º 8
0
def test_alphabet() -> None:
    ly = pya.Layout()
    top_cell = ly.create_cell("TOP")
    add_text(top_cell, "HELLO-WORLD_0123456789+_-")
    # add_text(top_cell, "HELLO - WORLD 0123456789 +_-") # Need to add spaces
    # to the font
    top_cell.write("hello_world.gds")
Ejemplo n.º 9
0
def change_grid_klayout(
    gdspath,
    gdspathout=None,
    precision_in=1e-9,
    precision_out=1e-9,
):
    """ This script allows you to change the design grid by reading a layout written with different precission (DBU database units)
    and scaling to for example 1nm grid

    Using this script here is a bit of a hack to ensure that this gdsfactory layout works with Calibre.
    Calibre has some issue when there are 2 cells defined in the GDS with the same name
    This script reads a GDS in klayout and writes it again.
    """
    assert precision_in >= precision_out

    gdspathout = gdspathout or gdspath
    gdspath = str(gdspath)
    gdspathout = str(gdspathout)

    layout = kl.Layout()
    layout.read(gdspath)
    layout.top_cell()

    scale = int(precision_in / precision_out)

    layout.dbu = precision_out / 1e-6
    if scale > 1:
        layout.scale_and_snap(layout.top_cell(), 1, scale, 1)
    layout.write(gdspathout)
    return gdspathout
Ejemplo n.º 10
0
def check_inclusion(
    gdspath: ComponentOrPath,
    layer_in: Tuple[int, int] = (1, 0),
    layer_out: Tuple[int, int] = (2, 0),
    min_inclusion: float = 0.150,
    dbu: float = 1e3,
    ignore_angle_deg: int = 80,
    whole_edges: bool = False,
    metrics: str = "Square",
    min_projection: None = None,
    max_projection: None = None,
) -> int:
    """reads layer from top cell and returns a the area that violates min inclusion
    if 0 no area violates exclusion

    Args:
        gdspath: path to GDS
        layer_in: tuple
        layer_out: tuple
        min_inclusion: in um
        dbu: database units (1000 um/nm)
        ignore_angle_deg: The angle above which no check is performed
        whole_edges: If true, deliver the whole edges
        metrics: Specify the metrics type
        min_projection: lower threshold of the projected length of one edge onto another
        max_projection: upper limit of the projected length of one edge onto another
    """
    import klayout.db as pya

    from gdsfactory.component import Component

    if isinstance(gdspath, Component):
        gdspath.flatten()
        gdspath = gdspath.write_gds()
    layout = pya.Layout()
    layout.read(str(gdspath))
    cell = layout.top_cell()
    a = pya.Region(
        cell.begin_shapes_rec(layout.layer(layer_in[0], layer_in[1])))
    b = pya.Region(
        cell.begin_shapes_rec(layout.layer(layer_out[0], layer_out[1])))

    valid_metrics = ["Square", "Euclidian"]
    if metrics not in valid_metrics:
        raise ValueError("metrics = {metrics!r} not in {valid_metrics}")
    metrics = getattr(pya.Region, metrics)

    d = b.inside_check(
        a,
        min_inclusion * dbu,
        whole_edges,
        metrics,
        ignore_angle_deg,
        min_projection,
        max_projection,
    )
    return d.polygons().area()
def check_inclusion(
    gdspath,
    layer_in=(1, 0),
    layer_out=(2, 0),
    min_inclusion=0.150,
    dbu=1e3,
    ignore_angle_deg=80,
    whole_edges=False,
    metrics=None,
    min_projection=None,
    max_projection=None,
):
    """reads layer from top cell and returns a the area that violates min inclusion
    if 0 no area violates exclusion

    Args:
        gdspath: path to GDS
        layer_in: tuple
        layer_out: tuple
        min_inclusion: in um
        dbu: database units (1000 um/nm)
        ignore_angle_deg: The angle above which no check is performed
        other: The other region against which to check
        whole_edges: If true, deliver the whole edges
        metrics: Specify the metrics type
        min_projection The lower threshold of the projected length of one edge onto another
        max_projection The upper limit of the projected length of one edge onto another
    """
    from pp.component import Component
    from pp.write_component import write_gds

    if isinstance(gdspath, Component):
        gdspath.flatten()
        gdspath = write_gds(gdspath)
    layout = pya.Layout()
    layout.read(str(gdspath))
    cell = layout.top_cell()
    a = pya.Region(
        cell.begin_shapes_rec(layout.layer(layer_in[0], layer_in[1])))
    b = pya.Region(
        cell.begin_shapes_rec(layout.layer(layer_out[0], layer_out[1])))

    d = b.inside_check(
        a,
        min_inclusion * dbu,
        whole_edges,
        metrics,
        ignore_angle_deg,
        min_projection,
        max_projection,
    )
    return d.polygons().area()
Ejemplo n.º 12
0
def layout_pgtext(cell, layer, x, y, text, mag, inv=False, angle=0):
    layout = kdb.Layout()
    lylayer = layout.layer(layer)
    for i, line in enumerate(text.splitlines()):
        pcell = layout.create_cell("TEXT", "Basic", {
            "text": line,
            "layer": layer,
            "mag": mag,
            "inverse": inv
        })
        pcell.transform_into(
            kdb.DCplxTrans(1, angle, False, x, y - i * mag * 5 / 4))
        lylayer_new = cell.layout().layer(layer)
        cell.shapes(lylayer_new).insert(pcell.shapes(lylayer))
Ejemplo n.º 13
0
def _demo():
    import pp
    c = pp.c.waveguide()
    gdspath = pp.write_component(c)

    layout1 = load_gds(gdspath)
    cell1 = layout1.top_cell()
    cell1_instance1 = pya.CellInstArray(cell1.cell_index(), pya.Trans(10, 0))

    layout2 = pya.Layout()
    cell2 = layout2.create_cell("TOP_LEVEL")

    layout2.cell("TOP_LEVEL").insert(cell1_instance1)
    layout2.write("test.gds")
Ejemplo n.º 14
0
def load_gds(filepath):
    filepath = str(filepath)
    layout = pya.Layout()
    try:
        layout.read(filepath)
    except:
        print(filepath)
        raise
    cell = layout.top_cell()
    cell.metadata = {}

    # To make sure the cell does not get destroyed
    global CELLS
    CELLS[cell.name] = layout
    return layout
Ejemplo n.º 15
0
def load_gds(filepath: Union[Path, str]) -> Layout:
    filepath = str(filepath)
    layout = pya.Layout()
    try:
        layout.read(filepath)
    except RuntimeError as e:
        print(f"Error reading {filepath}")
        raise e
    cell = layout.top_cell()
    cell.metadata = {}

    # To make sure the cell does not get destroyed
    global CELLS
    CELLS[cell.name] = layout
    return layout
Ejemplo n.º 16
0
def _demo():
    import gdsfactory as gf

    c = gf.components.straight()
    gdspath = c.write_gds_with_metadata()

    layout1 = load_gds(gdspath)
    cell1 = layout1.top_cell()
    cell1_instance1 = pya.CellInstArray(cell1.cell_index(), pya.Trans(10, 0))

    layout2 = pya.Layout()
    layout2.create_cell("TOP_LEVEL")

    layout2.cell("TOP_LEVEL").insert(cell1_instance1)
    layout2.write("test.gds")
Ejemplo n.º 17
0
def check_duplicated_cells(gdspath: Union[Path, str]):
    """Reads cell and checks for duplicated cells

    Args:
        gdspath: path to GDS or Component
    """
    import klayout.db as pya

    from gdsfactory.component import Component

    if isinstance(gdspath, Component):
        gdspath.flatten()
        gdspath = gdspath.write_gds()
    layout = pya.Layout()
    layout.read(str(gdspath))
    cell = layout.top_cell()
    return cell
Ejemplo n.º 18
0
def main():
    layout = pya.Layout()
    TOP = layout.create_cell("TOP")

    layer = pya.LayerInfo(1, 0)  # First layer

    origin = pya.DPoint(0, 0)
    ex = pya.DVector(1, 0)
    ey = pya.DVector(0, 1)

    angles = np.linspace(-170, 170, 13)

    for i, angle_0 in enumerate(angles):
        for j, angle_3 in enumerate(angles):
            curve = bezier_curve(origin + ey * i * 150 + ex * j * 150, angle_0,
                                 angle_3, ex, ey)
            layout_waveguide(TOP, layer, curve, width=0.5)

    layout.write("bezier_waveguides.gds")
Ejemplo n.º 19
0
def write_oas(device, filename, **write_kwargs):
    if filename.lower().endswith('.gds'):
        # you are looking for write_gds
        device.write_gds(filename, **write_kwargs)
        return
    try:
        import klayout.db as pya
    except ImportError as err:
        err.args = ('[PHIDL] klayout package needed to write OASIS. pip install klayout\n' + err.args[0], ) + err.args[1:]
        raise
    if not filename.lower().endswith('.oas'): filename += '.oas'
    fileroot = os.path.splitext(filename)[0]
    tempfilename = fileroot + '-tmp.gds'

    device.write_gds(tempfilename, **write_kwargs)
    layout = pya.Layout()
    layout.read(tempfilename)
    # there can only be one top_cell because we only wrote one device
    topcell = layout.top_cell()
    topcell.write(filename)
    os.remove(tempfilename)
    return filename
Ejemplo n.º 20
0
def find_labels(gdspath, label_layer=201, label_purpose=0):
    """ finds labels and locations from a GDS file """
    # Load the layout
    gdspath = str(gdspath)
    layout = pya.Layout()
    layout.read(gdspath)

    # Get the top cell and the units, and find out the index of the layer
    topcell = layout.top_cell()
    dbu = layout.dbu
    layer = pya.LayerInfo(label_layer, label_purpose)
    layer_index = layout.layer(layer)

    # Extract locations
    iterator = topcell.begin_shapes_rec(layer_index)

    while not (iterator.at_end()):
        shape, trans = iterator.shape(), iterator.trans()
        iterator.next()
        if shape.is_text():
            text = shape.text
            transformed = text.transformed(trans)
            yield text.string, transformed.x * dbu, transformed.y * dbu
Ejemplo n.º 21
0
 def test_3(self):
   # db plugins loaded?
   v = db.Layout()
   v.read(os.path.join(os.path.dirname(__file__), "..", "gds", "t10.gds"))
   self.assertEqual(v.top_cell().name, "RINGO")
Ejemplo n.º 22
0
def check_space(
    gdspath: ComponentOrPath,
    layer: Tuple[int, int] = (1, 0),
    min_space: float = 0.150,
    dbu: float = 1e3,
    ignore_angle_deg: int = 80,
    whole_edges: bool = False,
    metrics: str = "Square",
    min_projection: None = None,
    max_projection: None = None,
) -> int:
    """Reads layer from top cell and returns a the area that violates min space.

    If "whole_edges" is true, the resulting EdgePairs collection will receive the whole edges which contribute in the space check.

    "metrics" can be one of the constants Euclidian, Square or Projection. See there for a description of these constants.
    Use nil for this value to select the default (Euclidian metrics).

    "ignore_angle" specifies the angle limit of two edges. If two edges form an angle equal or above the given value, they will not contribute in
    the check. Setting this value to 90 (the default) will exclude edges with an angle of 90 degree or more from the check.
    Use nil for this value to select the default.

    "min_projection" and "max_projection" allow selecting edges by their projected value upon each other. It is sufficient if the projection of on
    e edge on the other matches the specified condition. The projected length must be larger or equal to "min_projection" and less than "max_proje
    ction". If you don't want to specify one limit, pass nil to the respective value.

    Args:
        gdspath: path to GDS or Component
        layer: tuple
        min_space: in um
        dbu: database units (1000 um/nm)
        ignore_angle_deg: The angle above which no check is performed
        other: The other region against which to check
        whole_edges: If true, deliver the whole edges
        metrics: Specify the metrics type 'Euclidian, square'
        min_projection The lower threshold of the projected length of one edge onto another
        max_projection The upper limit of the projected length of one edge onto another

    """

    if isinstance(gdspath, Component):
        gdspath.flatten()
        gdspath = gdspath.write_gds()
    layout = pya.Layout()
    layout.read(str(gdspath))
    cell = layout.top_cell()
    region = pya.Region(cell.begin_shapes_rec(layout.layer(layer[0],
                                                           layer[1])))

    valid_metrics = ["Square", "Euclidian"]

    if metrics not in valid_metrics:
        raise ValueError("metrics = {metrics} not in {valid_metrics}")
    metrics = getattr(pya.Region, metrics)

    d = region.space_check(
        min_space * dbu,
        whole_edges,
        metrics,
        ignore_angle_deg,
        min_projection,
        max_projection,
    )
    # print(d.polygons().area())
    return d.polygons().area()
Ejemplo n.º 23
0
import inspect
import sys
import os
import re
import props
from tools import Lazy

import klayout.db as db
import klayout.lib
import tools
import math
import context
import geom
import uuid

layout = db.Layout()
layout.dbu = .001


######## These are implementations of Skill standard library functions
def stringp(s):
    return isinstance(s, basestring)


def floatp(s):
    return isinstance(s, float)


def fixp(s):
    return isinstance(s, int)
Ejemplo n.º 24
0
        def wrapper_draw(self, cell):
            layout = cell.layout()
            try:
                layer_map_dict[layout]
            except KeyError:
                layer_map_dict[layout] = pya.LayerMap()

            # Adding the dbu of the layout in the hash (bit us in the butt last time)
            short_hash_pcell = produce_hash(self,
                                            extra=(layout.dbu, extra_hash))

            # cache paths
            cache_fname = f"cache_{self.__class__.__qualname__}_{short_hash_pcell}"
            cache_fname_gds = cache_fname + ".gds"
            cache_fname_pkl = cache_fname + ".klayout.pkl"

            os.makedirs(cache_dir, mode=0o775, exist_ok=True)

            cache_fpath_gds = os.path.join(cache_dir, cache_fname_gds)
            cache_fpath_pkl = os.path.join(cache_dir, cache_fname_pkl)

            if os.path.isfile(cache_fpath_gds) and os.path.isfile(
                    cache_fpath_pkl):
                with open(cache_fpath_pkl, "rb") as file:
                    ports, read_short_hash_pcell, cellname = pickle.load(file)  # pylint: disable=unused-variable

                logger.debug(
                    f"Reading from cache: {cache_fname}: {cellname}, {ports}")
                print("r", end="", flush=True)
                if not layout.has_cell(cache_fname):
                    read_layout(layout,
                                cache_fpath_gds,
                                disambiguation_name=cellname)
                retrieved_cell = layout.cell(cache_fname)
                cell.insert(
                    pya.DCellInstArray(
                        retrieved_cell.cell_index(),
                        pya.DTrans(pya.DTrans.R0, pya.DPoint(0, 0)),
                    ))
                # cell.move_tree(retrieved_cell)
            else:
                if layout.has_cell(cache_fname):
                    logger.warning(
                        f"WARNING: {cache_fname_gds} does not exist but {cache_fname} is in layout."
                    )

                # populating .gds and .pkl
                empty_layout = pya.Layout()
                empty_layout.dbu = layout.dbu
                empty_cell = empty_layout.create_cell(cell.name)
                filled_cell, ports = draw(self, empty_cell)

                logger.debug(
                    f"Writing to cache: {cache_fname}: {filled_cell.name}, {ports}"
                )
                print("w", end="", flush=True)

                cellname, filled_cell.name = filled_cell.name, cache_fname
                # There can be duplicate cell names in subcells here.
                # We are saving a list of them inside a property named CACHE_PROP_ID
                # So we need to allow the properties to be saved inside the gds file (incompatible with the GDS2 standard)
                save_options = pya.SaveLayoutOptions()
                save_options.gds2_write_file_properties = True
                empty_layout.write(cache_fpath_gds, save_options)
                with open(cache_fpath_pkl, "wb") as file:
                    pickle.dump((ports, short_hash_pcell, cellname), file)

                # Make sure we delete the empty_layout to not grow
                # helps debug
                layer_map_dict.pop(empty_layout, None)
                del empty_layout
                assert not layout.has_cell(cache_fname)

                read_layout(layout,
                            cache_fpath_gds,
                            disambiguation_name=cellname)
                retrieved_cell = layout.cell(cache_fname)
                cell.insert(
                    pya.DCellInstArray(
                        retrieved_cell.cell_index(),
                        pya.DTrans(pya.DTrans.R0, pya.DPoint(0, 0)),
                    ))

            return cell, ports
Ejemplo n.º 25
0
 def _top_cell():
     layout = kdb.Layout()
     layout.dbu = 0.001
     TOP = layout.create_cell("TOP")
     return TOP, layout
Ejemplo n.º 26
0
        def wrapper_draw(self, cell):
            global layer_map_dict
            layout = cell.layout()
            try:
                layer_map_dict[layout]
            except KeyError:
                layer_map_dict[layout] = pya.LayerMap()

            # Adding the dbu of the layout in the hash (bit us in the butt last time)
            short_hash_pcell = produce_hash(self, extra=(layout.dbu, extra_hash))

            # cache paths
            cache_fname = f"cache_{self.__class__.__qualname__}_{short_hash_pcell}"
            cache_fname_gds = cache_fname + ".gds"
            cache_fname_pkl = cache_fname + ".klayout.pkl"

            os.makedirs(cache_dir, mode=0o775, exist_ok=True)

            cache_fpath_gds = os.path.join(cache_dir, cache_fname_gds)
            cache_fpath_pkl = os.path.join(cache_dir, cache_fname_pkl)

            if os.path.isfile(cache_fpath_gds) and os.path.isfile(cache_fpath_pkl):
                with open(cache_fpath_pkl, "rb") as file:
                    ports, read_short_hash_pcell, cellname = pickle.load(file)
                if debug:
                    print(f"Reading from cache: {cache_fname}: {cellname}, {ports}")
                else:
                    print("r", end="", flush=True)
                if not layout.has_cell(cache_fname):
                    read_layout(layout, cache_fpath_gds)
                retrieved_cell = layout.cell(cache_fname)
                cell.insert(
                    pya.DCellInstArray(
                        retrieved_cell.cell_index(),
                        pya.DTrans(pya.DTrans.R0, pya.DPoint(0, 0)),
                    )
                )
                # cell.move_tree(retrieved_cell)
            else:
                if layout.has_cell(cache_fname):
                    print(
                        f"WARNING: {cache_fname_gds} does not exist but {cache_fname} is in layout."
                    )

                # populating .gds and .pkl
                empty_layout = pya.Layout()
                empty_layout.dbu = layout.dbu
                empty_cell = empty_layout.create_cell(cell.name)
                filled_cell, ports = draw(self, empty_cell)

                if debug:
                    print(
                        f"Writing to cache: {cache_fname}: {filled_cell.name}, {ports}"
                    )
                else:
                    print("w", end="", flush=True)

                cellname, filled_cell.name = filled_cell.name, cache_fname
                filled_cell.write(cache_fpath_gds)
                with open(cache_fpath_pkl, "wb") as file:
                    pickle.dump((ports, short_hash_pcell, cellname), file)

                # Make sure we delete the empty_layout to not grow
                # helps debug
                layer_map_dict.pop(empty_layout, None)
                del empty_layout
                assert not layout.has_cell(cache_fname)

                read_layout(layout, cache_fpath_gds)
                retrieved_cell = layout.cell(cache_fname)
                cell.insert(
                    pya.DCellInstArray(
                        retrieved_cell.cell_index(),
                        pya.DTrans(pya.DTrans.R0, pya.DPoint(0, 0)),
                    )
                )

            return cell, ports
Ejemplo n.º 27
0
def main():
    def trace_rounded_path(cell, layer, rounded_path, width):
        points = []
        for item in rounded_path:
            points.extend(item.get_points())

        dpath = kdb.DPath(points, width, 0, 0)

        cell.shapes(layer).insert(dpath)

    def trace_reference_path(cell, layer, points, width):
        dpath = kdb.DPath(points, width, 0, 0)
        cell.shapes(layer).insert(dpath)

    layout = kdb.Layout()
    TOP = layout.create_cell("TOP")
    layer = kdb.LayerInfo(10, 0)
    layerRec = kdb.LayerInfo(1001, 0)

    ex, ey = kdb.DPoint(1, 0), kdb.DPoint(0, 1)

    points = [0 * ex, 10 * ex, 10 * (ex + ey), 30 * ex]
    origin = 0 * ey
    points = [origin + point for point in points]
    x = compute_rounded_path(points, 3)
    trace_rounded_path(TOP, layer, x, 0.5)
    trace_reference_path(TOP, layerRec, points, 0.5)

    points = [0 * ex, 10 * ex, 5 * (ex - ey), 17 * ex, 30 * ex]
    origin = 30 * ey
    points = [origin + point for point in points]
    x = compute_rounded_path(points, 3)
    trace_rounded_path(TOP, layer, x, 0.5)
    trace_reference_path(TOP, layerRec, points, 0.5)

    radius = 3
    for ex2 in (ex, -ex):
        points = [2 * ex2]
        for d in np.arange(1, 10, 2.5):
            origin = points[-1]
            displacements = [
                4 * radius * ex2,
                4 * radius * ex2 + d * ey - 1 * d * ex2,
                d * ey,
                (d + 2 * radius) * ey,
            ]
            points += [origin + displacement for displacement in displacements]
        origin = 15 * ex + 40 * ey
        points = [origin + point for point in points]
        x = compute_rounded_path(points, radius)
        trace_rounded_path(TOP, layer, x, 0.5)
        trace_reference_path(TOP, layerRec, points, 0.5)

    # Layout tapered waveguide
    points = [
        0 * ex,
        100 * ex,
        100 * ex + 20 * ey,
        10 * ex + 5 * ey,
        10 * ex + 25 * ey,
        100 * ex + 30 * ey,
    ]

    # Untapered
    origin = 40 * ex
    points_ = [origin + point for point in points]
    layout_waveguide_from_points(TOP, layer, points_, 0.5, 5)

    # Tapered
    origin = 40 * ex + 40 * ey
    points_ = [origin + point for point in points]
    layout_waveguide_from_points(
        TOP, layer, points_, 0.5, 5, taper_width=3, taper_length=10
    )

    print("Wrote waveguide_rounding.gds")
    TOP.write("waveguide_rounding.gds")
Ejemplo n.º 28
0
#!/usr/bin/python3

import klayout.db as db
import klayout.lib

layout = db.Layout()
layout.dbu = .001

layers = {
    "m1": layout.layer(68, 20),
    "m1.con": layout.layer(67, 44),
    "m1.pin": layout.layer(68, 16),
    "m1.label": layout.layer(68, 5),
    "m2": layout.layer(69, 20),
    "m2.con": layout.layer(68, 44),
    "m2.pin": layout.layer(69, 16),
    "m2.label": layout.layer(69, 5),
    "li": layout.layer(67, 20),
    "li.pin": layout.layer(67, 16),
    "li.label": layout.layer(67, 5),
    "li.con": layout.layer(66, 44),
    "poly": layout.layer(66, 20),
    "npc": layout.layer(95, 20)
}


def make_rect(cell, org, sz, layer):
    if isinstance(layer, list):
        for l in layer:
            make_rect(cell, org, sz, l)
        return
Ejemplo n.º 29
0
import klayout.db as pya
from zeropdk.layout.polygons import layout_path
from zeropdk.layout import layout_box
import numpy as np
from functions import *

layout = pya.Layout()
layout.dbu = 0.001
TOP = layout.create_cell("TOP")

workingLayer = layout.layer(4, 0)
chipBorder = layout.layer(7, 0)  #computational layer
maskBorder = layout.layer(10, 0)  #nbtin layer
outputLayer = layout.layer(1, 0)
sourceLayer = layout.layer(3, 0)
port1Layer = layout.layer(2, 0)
port2Layer = layout.layer(5, 0)

ex = pya.DVector(1, 0)
ey = pya.DVector(0, 1)

upperRegion = pya.Region()
lowerRegion = pya.Region()
feedlineRegion = pya.Region()
lowZRegion = pya.Region()
highZRegion = pya.Region()

#insert chip/mask border
chipWidth = 11000
chipLength = 19000
#layout_box(TOP, chipBorder, -chipWidth*ex-50000*ey, chipWidth*ex + 50000*ey, ex)
Ejemplo n.º 30
0
def place_from_yaml(
    filepath_yaml: Path,
    root_does: Path = CONFIG["cache_doe_directory"],
    precision: float = 1e-9,
    fontpath: Path = text.FONT_PATH,
    default_align_x: NSEW = "W",
    default_align_y: NSEW = "S",
    default_margin: int = 10,
    default_x0: NSEW = "E",
    default_y0: NSEW = "S",
) -> Cell:
    """Returns a gds cell composed of DOEs/components given in a yaml file
    allows for each DOE to have its own x and y spacing (more flexible than method1)

    Args:
        filepath_yaml:
        root_does: used for cache, requires content.txt
    """
    transform_identity = pya.Trans(0, 0)
    dicts, mask_settings = load_yaml(filepath_yaml)

    does, templates = separate_does_from_templates(dicts)

    placed_doe = None
    placed_does = {}
    top_level_name = mask_settings.get("name", "TOP_LEVEL")
    layer_doe_label = mask_settings["layer_doe_label"]
    top_level_layout = pya.Layout()

    # Set database units according to precision
    top_level_layout.dbu = precision / 1e-6
    dbu = top_level_layout.dbu
    um_to_grid = int(1 / dbu)

    top_level = top_level_layout.create_cell(top_level_name)
    global CELLS
    CELLS[top_level_name] = top_level_layout

    default_doe_settings = {
        "add_doe_label": False,
        "add_doe_visual_label": False,
        "dx_visual_label": 0,
        "dy_visual_label": 0,
    }

    for doe_name, doe in does.items():

        # If a template is specified, apply it
        if "template" in doe:
            doe_templates = doe["template"]
            if type(doe_templates) != list:
                doe_templates = [doe_templates]
            for doe_template in doe_templates:
                try:
                    doe = update_dicts_recurse(doe, templates[doe_template])

                except BaseException:
                    print(doe_template, "does not exist")
                    raise
        doe = update_dicts_recurse(doe, default_doe_settings)

        # Get all the components
        components = load_doe(doe_name, root_does)

        # Check that the high level components are all unique
        # For now this is mostly to circumvent a bug
        # But the design manual also specifies that DOE components should have
        # unique names. So one instance per cell

        if components:
            if len(components) != len(
                    set([_c.top_cell().name for _c in components])):
                __dict_component_debug = {}
                for _c in components:
                    _name = _c.top_cell().name
                    if _name not in __dict_component_debug:
                        __dict_component_debug[_name] = 0
                    __dict_component_debug[_name] += 1
                duplicates_components = [
                    _name for _name, _count in __dict_component_debug.items()
                    if _count > 1
                ]
                print(
                    "Please remove duplicate components at DOE entry level: ")
                print(duplicates_components)

            components = [
                import_cell(top_level_layout, _c.top_cell())
                for _c in components
            ]

        default_placer_settings = {
            "align_x": default_align_x,
            "align_y": default_align_y,
            "margin": default_margin,
            "x0": default_x0,
            "y0": default_y0,
        }
        settings = default_placer_settings.copy()
        placer = doe.get("placer")

        if placer:
            placer_type = placer.pop("type", "pack_col")
            settings.update(doe["placer"])
        else:
            placer_type = "pack_col"

        if placer_type not in PLACER_NAME2FUNC:
            raise ValueError(
                f"{placer_type} is not an available placer, Choose:"
                f" {list(PLACER_NAME2FUNC.keys())}")
        _placer = PLACER_NAME2FUNC[placer_type]

        # All other attributes are assumed to be settings for the placer

        # Check if the cell should be attached to a specific parent cell
        if "parent" in settings:
            parent_name = settings.pop("parent")
            if parent_name not in CELLS:
                # Create parent cell in layout and insert it under top level
                parent_cell = top_level_layout.create_cell(parent_name)
                CELLS[parent_name] = parent_cell
                parent_cell_instance = pya.CellInstArray(
                    parent_cell.cell_index(), transform_identity)
                top_level.insert(parent_cell_instance)
            doe_parent_cell = CELLS[parent_name]
        else:
            # If no parent specified, insert the DOE at top level
            doe_parent_cell = top_level

        # Check if we should create a DOE cell which regroups the DOEs
        if "with_doe_cell" in settings:
            with_doe_cell = settings.pop("with_doe_cell")
        else:
            with_doe_cell = True

        # x0, y0 can either be float or string
        x0 = settings.pop("x0")
        y0 = settings.pop("y0")

        # Check whether we are doing relative or absolute placement
        # if (x0 in ["E", "W"] or y0 in ["N", "S"]) and not placed_doe:
        #     raise ValueError(
        #         "At least one DOE must be placed to use relative placement"
        #     )

        # For relative placement (to previous DOE)
        if "margin_x" not in settings:
            settings["margin_x"] = settings["margin"]
        if "margin_y" not in settings:
            settings["margin_y"] = settings["margin"]

        if "inter_margin_x" not in settings:
            inter_margin_x = settings["margin_x"]
        else:
            inter_margin_x = settings.pop("inter_margin_x")

        if "inter_margin_y" not in settings:
            inter_margin_y = settings["margin_y"]
        else:
            inter_margin_y = settings.pop("inter_margin_y")

        align_x = settings["align_x"]
        align_y = settings["align_y"]

        # Make sure that the alignment is sensible depending on how we stack

        # If we specify a DOE to place next to, use it
        if "next_to" in settings:
            placed_doe = placed_does[settings.pop("next_to")]

        # print(placed_doe)
        # print(placed_does)

        # Otherwise, use previously placed DOE as starting point
        doe_si = (SizeInfo(placed_doe, top_level_layout, um_to_grid=um_to_grid)
                  if placed_doe is not None else None)
        if x0 == "E":
            x0 = doe_si.east
            if align_x == "W":
                x0 += inter_margin_x

        if x0 == "W":
            x0 = doe_si.west
            if align_x == "E":
                x0 -= inter_margin_x

        if y0 == "N":
            y0 = doe_si.north
            if align_y == "S":
                y0 += inter_margin_y

        if y0 == "S":
            y0 = doe_si.south
            if align_y == "N":
                y0 -= inter_margin_y

        # Add x0, y0 in settings as float
        settings["x0"] = x0
        settings["y0"] = y0

        settings["um_to_grid"] = um_to_grid

        placed_components = _placer(components, **settings)

        # Place components within a cell having the DOE name

        if with_doe_cell or len(placed_components) > 1:
            doe_cell = top_level_layout.create_cell(doe_name)
            CELLS[doe_name] = doe_cell
            for instance in placed_components:
                doe_cell.insert(instance)
            placed_does[doe_name] = doe_cell
            placed_doe = doe_cell
            doe_instance = pya.CellInstArray(doe_cell.cell_index(),
                                             transform_identity)
        else:
            # If only single cell and we want to skip the sweep cell
            doe_instance = placed_components[0]
            placed_does[doe_name] = doe_instance
            placed_doe = doe_instance

        add_doe_label = doe["add_doe_label"]
        add_doe_visual_label = doe["add_doe_visual_label"]

        if add_doe_label:
            layer_label_index, layer_label_datatype = layer_doe_label
            layer_index = top_level.layout().insert_layer(
                pya.LayerInfo(layer_label_index, layer_label_datatype))
            # Add the name of the DOE at the center of the cell
            _p = doe_instance.bbox(top_level_layout).center()
            _text = pya.Text(doe_name, _p.x, _p.y)
            top_level.shapes(layer_index).insert(_text)

        if add_doe_visual_label:
            _bbox = doe_instance.bbox(top_level_layout)

            idbu = 1 / top_level.layout().dbu
            x_text = _bbox.center().x + doe["dx_visual_label"] * idbu
            y_text = _bbox.bottom + (15.0 + doe["dy_visual_label"]) * idbu
            _text = text.add_text(top_level,
                                  doe_name,
                                  position=(x_text, y_text),
                                  fontpath=fontpath)
            # _transform = pya.DTrans(x_text, y_text)
            # top_level.insert(pya.CellInstArray(_text.cell_index(), _transform))

        doe_parent_cell.insert(doe_instance)

    return top_level