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
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
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
def flip(port: Port) -> Port: """Flip Port orientation.""" return Port(port.name, port.midpoint, port.width, port.orientation + 180)
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