示例#1
0
def test_pad_pcell(top_cell):
    pad = DCPad(name="testname")
    pad.params.layer_metal = kdb.LayerInfo(1, 0)
    pad.params.layer_opening = kdb.LayerInfo(2, 0)

    # This will get automatically converted to LayerInfo
    # No Error
    pad.params.layer_metal = "1/0"

    # TODO set defaults here
    TOP, layout = top_cell()
    cell, ports = pad.new_cell(layout)
    assert "el0" in ports
    origin, angle = kdb.DPoint(0, 0), 0
    TOP.insert_cell(cell, origin, angle)
    TOP.write("tests/tmp/pad.gds")
示例#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
示例#3
0
    def add_layer(self, layer_name, layer_def):
        """Adds a layer to the technology file.
        layer_name: str: name of layer. (Useless in GDS, useful in OASIS)
        layer_def: str: 10/0, 10 = layer index, 0, datatype
        """

        layer_idx, datatype = layer_def.split("/")
        layer_idx = int(layer_idx)
        datatype = int(datatype)
        self.layers[layer_name] = kdb.LayerInfo(layer_idx, datatype, layer_name)
    def __init__(self):

        # Important: initialize the super class
        super(TLM, self).__init__()
        #  self.param("lay", self.TypeLayer, "Layer", default = pya.LayerInfo(2, 0))
        self.param("ito",
                   self.TypeLayer,
                   "Conductor Layer",
                   default=pya.LayerInfo(1, 0, "ITO Opening 1/0"))
        self.param("nno",
                   self.TypeLayer,
                   "Pad Layer",
                   default=pya.LayerInfo(2, 0, "NNO Pad 2/0"))
        self.param("fox",
                   self.TypeLayer,
                   "Isolation Layer",
                   default=pya.LayerInfo(3, 0, "Field Oxide 3/0"))
        self.param("hfoetch",
                   self.TypeLayer,
                   "Isolation Layer",
                   default=pya.LayerInfo(4, 0, "HfO2 Etch 4/0"))
        # self.param("l", self.TypeList, "Length (Squares)", default= [2, 5, 10, 20])
        self.param("w", self.TypeDouble, "Width (um)", default=40)
示例#5
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")
示例#6
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
示例#7
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")
示例#8
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
示例#9
0
def test_layers():
    t = ExampleTech()
    assert t.layers["layer_metal"] == kdb.LayerInfo(1, 0, "layer_metal")
示例#10
0
import os
import klayout.db as pya

path = os.path.dirname(os.path.abspath(__file__))
print(path)
layout = pya.Layout()

# create layers to use in our layout. LayerInfo takes layer#, datatype, text label as inputs
ito = pya.LayerInfo(1, 0, "ITO Opening 1/0")
nno = pya.LayerInfo(2, 0, "NNO Pad 2/0")
fox = pya.LayerInfo(3, 0, "Field Oxide 3/0")
hfoetch = pya.LayerInfo(4, 0, "HfO2 Etch 4/0")

# assign layers to layout
for l in [ito, nno, fox, hfoetch]:
    layout.layer(l)

top = layout.create_cell("TOP")
top.shapes(ito.layer).insert(pya.Box([0, 0], [1000,1000]))

layout.write(os.path.join(path, 'test.gds'))
示例#11
0
def test_load_from_xml():
    filepath = Path(os.path.dirname(__file__)).resolve() / "EBeam.lyp"
    ebeam = Tech.load_from_xml(filepath)
    assert ebeam.layers["M1"] == kdb.LayerInfo(41, 0, "M1")