Exemplo n.º 1
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
Exemplo n.º 2
0
def add_text(
    cell: Cell,
    text: str,
    position: Tuple[int, int] = (0, 0),
    align_x: str = "center",
    align_y: str = "top",
    fontpath: Path = FONT_PATH,
) -> Cell:
    """add text label"""
    text = text.upper()
    alphabet = load_alphabet(filepath=fontpath)
    idbu = 1 / cell.layout().dbu
    si = alphabet["A"].dbbox()
    x, y = position
    w = si.width()
    h = si.height()
    c = cell.layout().create_cell("TEXT_{}".format(text))
    n = len(text)

    if align_x == "center":
        dx = -(n + 0.5) * w / 2
    elif align_x == "right":
        dx = -n * w
    else:
        dx = 0

    if align_y == "top":
        dy = -h
    elif align_y == "center":
        dy = -h / 2
    else:
        dy = 0

    for i, char in enumerate(text):
        _l = import_cell(cell.layout(), alphabet[char])
        _transform = pya.DTrans((i * w + dx) * idbu, dy * idbu)
        label = pya.CellInstArray(_l.cell_index(), _transform)
        c.insert(label)

    cell.insert(pya.CellInstArray(c.cell_index(), pya.DTrans(x, y)))
    return c
Exemplo n.º 3
0
    def draw(self, cell, layer):
        """ Draws this port on cell's layer using klayout.db"""
        if self.name.startswith("el"):
            pin_length = self.width
        else:
            # port is optical
            pin_length = max(2, self.width / 10)

        ex = self.direction

        # Place a Path around the port pointing towards its exit
        port_path = kdb.DPath(
            [
                self.position - 0.5 * pin_length * ex,
                self.position + 0.5 * pin_length * ex,
            ],
            self.width,
        )
        cell.shapes(layer).insert(port_path)

        # Place a small arrow around the tip of the port
        from zeropdk.layout.geometry import rotate90

        ey = rotate90(ex)
        port_tip = kdb.DSimplePolygon(
            [
                self.position + 0.5 * pin_length * ex,
                self.position + 0.4 * pin_length * ex + 0.1 * pin_length * ey,
                self.position + 0.4 * pin_length * ex - 0.1 * pin_length * ey,
            ]
        )
        cell.shapes(layer).insert(port_tip)
        # pin_rectangle = rectangle(self.position, self.width,
        #                           pin_length, ex, ey)
        # cell.shapes(layer).insert(pin_rectangle)

        # Place a text object annotating the name of the port
        cell.shapes(layer).insert(
            kdb.DText(
                self.name,
                kdb.DTrans(kdb.DTrans.R0, self.position.x, self.position.y),
                min(pin_length, 20),
                0,
            )
        )

        return self
Exemplo n.º 4
0
def place_cell(
    parent_cell,
    pcell,
    ports_dict,
    placement_origin,
    relative_to=None,
    transform_into=False,
):
    """ Places an pya cell and return ports with updated positions
    Args:
        parent_cell: cell to place into
        pcell, ports_dict: result of KLayoutPCell.pcell call
        placement_origin: pya.Point object to be used as origin
        relative_to: port name
            the cell is placed so that the port is located at placement_origin
        transform_into:
            if used with relative_into, transform the cell's coordinate system
            so that its origin is in the given port.

    Returns:
        ports(dict): key:port.name, value: geometry.Port with positions relative to parent_cell's origin
    """

    ports = ports_dict
    cell = pcell

    port_offset = placement_origin
    if relative_to is not None:
        offset = ports[relative_to].position
        port_offset = placement_origin - offset
        if transform_into:
            # print(type(pcell))
            offset_transform = kdb.DTrans(kdb.DTrans.R0, -offset)
            for instance in cell.each_inst():
                instance.transform(offset_transform)
            cell.transform_into(offset_transform)
        else:
            placement_origin = placement_origin - offset
    parent_cell.insert_cell(cell, placement_origin, 0)

    new_ports = deepcopy(ports)
    for port in new_ports.values():
        port.position += port_offset

    return new_ports
Exemplo n.º 5
0
def rodGetObj(i):
    print "rodGetObject: " + str(i)
    if i in rodsByName:
        return rodsByName[i]
    s = i.split("/")
    if len(s) > 1:
        tx = []
        print "rod subobject query: " + str(s)
        cmap = rodsByName
        inst = rodsByName[s[0]]
        dbox = None
        got_shape = False
        for e in s:
            e = cmap[e]
            cell = e['_shapes'][0]
            if isinstance(cell, db.Instance):
                cmap = rod_map[cell.cell.basic_name()]
                tx.append(cell.dtrans)
            else:
                got_shape = True
            dbox = e['_shapes'][0].dbbox()
        #accumulate the transforms
        if not got_shape:
            print dbox
            dbox.p1 = db.DPoint.new(
                0, 0)  #If only have a cell, then all stuff relative to origin
            dbox.p2 = dbox.p1
        total = db.DTrans()
        for t in tx:
            total = total * t
        if not dbox:
            write()
            exit()
        dbox = total.trans(dbox)
        obj = createObj(dbox=dbox)
        obj['_slaves'].append(inst)
        inst['_masters'].append(obj)
        obj['_transform'] = total
        rodsByName[i] = obj
        return obj
    write()
    assert (False)
    exit(0)
    print "****************getObject failed"
    return None
Exemplo n.º 6
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
Exemplo n.º 7
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