Beispiel #1
0
    def add_port(
        self,
        name: Optional[Union[str, int, object]] = None,
        midpoint: Tuple[float, float] = (
            0.0,
            0.0,
        ),
        width: float = 1.0,
        orientation: int = 45,
        port: Optional[Port] = None,
        layer: Tuple[int, int] = (1, 0),
        port_type: str = "optical",
        cross_section: Optional[CrossSection] = None,
    ) -> Port:
        """Can be called to copy an existing port like add_port(port = existing_port) or
        to create a new port add_port(myname, mymidpoint, mywidth, myorientation).
        Can also be called to copy an existing port
        with a new name add_port(port = existing_port, name = new_name)"""

        if port:
            if not isinstance(port, Port):
                raise ValueError(f"add_port() needs a Port, got {type(port)}")
            p = port.copy(new_uid=True)
            if name is not None:
                p.name = name
            p.parent = self

        elif isinstance(name, Port):
            p = name.copy(new_uid=True)
            p.parent = self
            name = p.name
        else:
            half_width = width / 2
            half_width_correct = snap_to_grid(half_width, nm=1)
            if not np.isclose(half_width, half_width_correct):
                warnings.warn(
                    f"port width = {width} will create off-grid points.\n"
                    f"You can fix it by changing width to {2*half_width_correct}\n"
                    f"port {name}, {midpoint}  {orientation} deg",
                    stacklevel=3,
                )
            p = Port(
                name=name,
                midpoint=(snap_to_grid(midpoint[0]),
                          snap_to_grid(midpoint[1])),
                width=snap_to_grid(width),
                orientation=orientation,
                parent=self,
                layer=layer,
                port_type=port_type,
                cross_section=cross_section,
            )
        if name is not None:
            p.name = name
        if p.name in self.ports:
            raise ValueError(
                f"add_port() Port name {p.name} exists in {self.name}")

        self.ports[p.name] = p
        return p
Beispiel #2
0
def test_manhattan() -> Component:
    top_cell = Component()

    inputs = [
        Port("in1", (10, 5), 0.5, 90),
        # Port("in2", (-10, 20), 0.5, 0),
        # Port("in3", (10, 30), 0.5, 0),
        # Port("in4", (-10, -5), 0.5, 90),
        # Port("in5", (0, 0), 0.5, 0),
        # Port("in6", (0, 0), 0.5, 0),
    ]

    outputs = [
        Port("in1", (290, -60), 0.5, 180),
        # Port("in2", (-100, 20), 0.5, 0),
        # Port("in3", (100, -25), 0.5, 0),
        # Port("in4", (-150, -65), 0.5, 270),
        # Port("in5", (25, 3), 0.5, 180),
        # Port("in6", (0, 10), 0.5, 0),
    ]

    lengths = [349.974]

    for input_port, output_port, length in zip(inputs, outputs, lengths):

        # input_port = Port("input_port", (10,5), 0.5, 90)
        # output_port = Port("output_port", (90,-60), 0.5, 180)
        # bend = bend_circular(radius=5.0)

        route = route_manhattan(
            input_port=input_port,
            output_port=output_port,
            straight=straight_function,
            radius=5.0,
            auto_widen=True,
            width_wide=2,
            # layer=(2, 0),
            # width=0.2,
        )

        top_cell.add(route.references)
        assert np.isclose(route.length, length), route.length
    return top_cell
def test_get_bundle_from_waypointsB(
    data_regression: DataRegressionFixture,
    check: bool = True,
) -> Component:

    ys1 = np.array([0, 5, 10, 15, 30, 40, 50, 60]) + 0.0
    ys2 = np.array([0, 10, 20, 30, 70, 90, 110, 120]) + 500.0
    N = ys1.size

    ports1 = [
        Port(name=f"A_{i}", midpoint=(0, ys1[i]), width=0.5, orientation=0)
        for i in range(N)
    ]
    ports2 = [
        Port(
            name=f"B_{i}",
            midpoint=(500, ys2[i]),
            width=0.5,
            orientation=180,
        ) for i in range(N)
    ]

    p0 = ports1[0].position

    c = gf.Component("B")
    c.add_ports(ports1)
    c.add_ports(ports2)
    waypoints = [
        p0 + (200, 0),
        p0 + (200, -200),
        p0 + (400, -200),
        (p0[0] + 400, ports2[0].y),
    ]

    routes = get_bundle_from_waypoints(ports1, ports2, waypoints)
    lengths = {}
    for i, route in enumerate(routes):
        c.add(route.references)
        lengths[i] = route.length

    if check:
        data_regression.check(lengths)
    return c
Beispiel #4
0
def add_ports_from_markers_center(
    component: Component,
    pin_layer: Layer = (1, 10),
    port_layer: Optional[Layer] = None,
    inside: bool = False,
    tol: float = 0.1,
    pin_extra_width: float = 0.0,
    min_pin_area_um2: Optional[float] = None,
    max_pin_area_um2: float = 150.0 * 150.0,
    skip_square_ports: bool = True,
    xcenter: Optional[float] = None,
    ycenter: Optional[float] = None,
    port_name_prefix: str = "",
    port_type: str = "optical",
) -> Component:
    """Add ports from rectangular pin markers.

    markers at port center, so half of the marker goes inside and half ouside the port.

    guess port orientation from the component center

    Args:
        component: to read polygons from and to write ports to
        pin_layer: GDS layer for maker [int, int]
        port_layer: for the new created port
        inside: True-> markers  inside. False-> markers at center
        tol: tolerance for comparing how rectangular is the pin
        pin_extra_width: 2*offset from pin to straight
        min_pin_area_um2: ignores pins with area smaller than min_pin_area_um2
        max_pin_area_um2: ignore pins for area above certain size
        skip_square_ports: skips square ports (hard to guess orientation)
        xcenter: for guessing orientation of rectangular ports
        ycenter: for guessing orientation of rectangular ports
        port_name_prefix: o for optical ports (o1, o2, o3)

    For the default center case (inside=False)

    .. code::
           _______________
          |               |
          |               |
         |||             |||____  | pin_extra_width/2 > 0
         |||             |||
         |||             |||____
         |||             |||
          |      __       |
          |_______________|
                 __


    For the inside case (inside=True)

    .. code::
           _______________
          |               |
          |               |
          |               |
          | |             |
          | |             |
          |      __       |
          |               |
          |_______________|



    dx < dy: port is east or west
        x > xc: east
        x < xc: west

    dx > dy: port is north or south
        y > yc: north
        y < yc: south

    dx = dy
        x > xc: east
        x < xc: west

    """
    xc = xcenter or component.x
    yc = ycenter or component.y
    xmax = component.xmax
    xmin = component.xmin
    ymax = component.ymax
    ymin = component.ymin

    port_markers = read_port_markers(component, layers=(pin_layer,))
    layer = port_layer or pin_layer
    port_locations = []

    ports = {}

    for i, p in enumerate(port_markers.polygons):
        port_name = f"{port_name_prefix}{i+1}" if port_name_prefix else i
        dy = p.ymax - p.ymin
        dx = p.xmax - p.xmin
        x = p.x
        y = p.y
        if min_pin_area_um2 and dx * dy <= min_pin_area_um2:
            continue

        if max_pin_area_um2 and dx * dy > max_pin_area_um2:
            continue

        # skip square ports as they have no clear orientation
        if skip_square_ports and snap_to_grid(dx) == snap_to_grid(dy):
            continue
        pxmax = p.xmax
        pxmin = p.xmin
        pymax = p.ymax
        pymin = p.ymin

        if dx < dy and x > xc:  # east
            orientation = 0
            width = dy
            if inside:
                x = p.xmax
        elif dx < dy and x < xc:  # west
            orientation = 180
            width = dy
            if inside:
                x = p.xmin
        elif dx > dy and y > yc:  # north
            orientation = 90
            width = dx
            if inside:
                y = p.ymax
        elif dx > dy and y < yc:  # south
            orientation = 270
            width = dx
            if inside:
                y = p.ymin

        # port markers have same width and height
        # check which edge (E, W, N, S) they are closer to
        elif pxmax > xmax - tol:  # east
            orientation = 0
            width = dy
            x = p.xmax
        elif pxmin < xmin + tol:  # west
            orientation = 180
            width = dy
            x = p.xmin
        elif pymax > ymax - tol:  # north
            orientation = 90
            width = dx
            y = p.ymax
        elif pymin < ymin + tol:  # south
            orientation = 270
            width = dx
            y = p.ymin

        x = snap_to_grid(x)
        y = snap_to_grid(y)
        width = np.round(width - pin_extra_width, 3)

        if (x, y) not in port_locations:
            port_locations.append((x, y))
            ports[port_name] = Port(
                name=port_name,
                midpoint=(x, y),
                width=width,
                orientation=orientation,
                layer=layer,
                port_type=port_type,
            )

    ports = sort_ports_clockwise(ports)

    for port_name, port in ports.items():
        component.add_port(name=port_name, port=port)
    return component
Beispiel #5
0
def flip(port: Port) -> Port:
    """Flip Port orientation."""
    return Port(port.name, port.midpoint, port.width, port.orientation + 180)
Beispiel #6
0
    def demo_connect_corner(N=6, config="A"):

        d = 10.0
        sep = 5.0
        top_cell = gf.Component(name="connect_corner")

        if config in ["A", "B"]:
            a = 100.0
            ports_A_TR = [
                Port("A_TR_{}".format(i), (d, a / 2 + i * sep), 0.5, 0)
                for i in range(N)
            ]
            ports_A_TL = [
                Port("A_TL_{}".format(i), (-d, a / 2 + i * sep), 0.5, 180)
                for i in range(N)
            ]
            ports_A_BR = [
                Port("A_BR_{}".format(i), (d, -a / 2 - i * sep), 0.5, 0)
                for i in range(N)
            ]
            ports_A_BL = [
                Port("A_BL_{}".format(i), (-d, -a / 2 - i * sep), 0.5, 180)
                for i in range(N)
            ]

            ports_A = [ports_A_TR, ports_A_TL, ports_A_BR, ports_A_BL]

            ports_B_TR = [
                Port("B_TR_{}".format(i), (a / 2 + i * sep, d), 0.5, 90)
                for i in range(N)
            ]
            ports_B_TL = [
                Port("B_TL_{}".format(i), (-a / 2 - i * sep, d), 0.5, 90)
                for i in range(N)
            ]
            ports_B_BR = [
                Port("B_BR_{}".format(i), (a / 2 + i * sep, -d), 0.5, 270)
                for i in range(N)
            ]
            ports_B_BL = [
                Port("B_BL_{}".format(i), (-a / 2 - i * sep, -d), 0.5, 270)
                for i in range(N)
            ]

            ports_B = [ports_B_TR, ports_B_TL, ports_B_BR, ports_B_BL]

        elif config in ["C", "D"]:
            a = N * sep + 2 * d
            ports_A_TR = [
                Port("A_TR_{}".format(i), (a, d + i * sep), 0.5, 0) for i in range(N)
            ]
            ports_A_TL = [
                Port("A_TL_{}".format(i), (-a, d + i * sep), 0.5, 180) for i in range(N)
            ]
            ports_A_BR = [
                Port("A_BR_{}".format(i), (a, -d - i * sep), 0.5, 0) for i in range(N)
            ]
            ports_A_BL = [
                Port("A_BL_{}".format(i), (-a, -d - i * sep), 0.5, 180)
                for i in range(N)
            ]

            ports_A = [ports_A_TR, ports_A_TL, ports_A_BR, ports_A_BL]

            ports_B_TR = [
                Port("B_TR_{}".format(i), (d + i * sep, a), 0.5, 90) for i in range(N)
            ]
            ports_B_TL = [
                Port("B_TL_{}".format(i), (-d - i * sep, a), 0.5, 90) for i in range(N)
            ]
            ports_B_BR = [
                Port("B_BR_{}".format(i), (d + i * sep, -a), 0.5, 270) for i in range(N)
            ]
            ports_B_BL = [
                Port("B_BL_{}".format(i), (-d - i * sep, -a), 0.5, 270)
                for i in range(N)
            ]

            ports_B = [ports_B_TR, ports_B_TL, ports_B_BR, ports_B_BL]

        if config in ["A", "C"]:
            for ports1, ports2 in zip(ports_A, ports_B):
                routes = gf.routing.get_bundle(ports1, ports2, radius=8)
                for route in routes:
                    top_cell.add(route.references)

        elif config in ["B", "D"]:
            for ports1, ports2 in zip(ports_A, ports_B):
                routes = gf.routing.get_bundle(ports2, ports1, radius=8)
                for route in routes:
                    top_cell.add(route.references)

        return top_cell