Ejemplo n.º 1
0
    def dummy():
        cmp = Component()
        xs = [0.0, 10.0, 25.0, 50.0]
        ys = [0.0, 10.0, 25.0, 50.0]
        a = 5
        xl = min(xs) - a
        xr = max(xs) + a
        yb = min(ys) - a
        yt = max(ys) + a

        cmp.add_polygon([(xl, yb), (xl, yt), (xr, yt), (xr, yb)], LAYER.WG)

        for i, y in enumerate(ys):
            p0 = (xl, y)
            p1 = (xr, y)
            cmp.add_port(name="W{}".format(i), midpoint=p0, orientation=180, width=0.5)
            cmp.add_port(name="E{}".format(i), midpoint=p1, orientation=0, width=0.5)

        for i, x in enumerate(xs):
            p0 = (x, yb)
            p1 = (x, yt)
            cmp.add_port(name="S{}".format(i), midpoint=p0, orientation=270, width=0.5)
            cmp.add_port(name="N{}".format(i), midpoint=p1, orientation=90, width=0.5)

        return cmp
Ejemplo n.º 2
0
def corner(width=WIRE_WIDTH, radius=None, layer=LAYER.M3):
    """ 90 degrees electrical bend

    Args:
        width: wire width
        radius ignore (passed for consistency with other types of bends)
        layer: layer

    .. plot::
      :include-source:

      import pp

      c = pp.c.corner(width=10., layer=pp.LAYER.M3)
      pp.plotgds(c)
    """
    c = Component()
    a = width / 2
    xpts = [-a, a, a, -a]
    ypts = [-a, -a, a, a]

    c.add_polygon([xpts, ypts], layer=layer)
    c.add_port(name="W0", midpoint=(-a, 0), width=width, orientation=180)
    c.add_port(name="N0", midpoint=(0, a), width=width, orientation=90)
    c.info["length"] = width
    return c
Ejemplo n.º 3
0
def L(
    width: Union[int, float] = 1,
    size: Tuple[int, int] = (10, 20),
    layer: Tuple[int, int] = LAYER.M3,
) -> Component:
    """Generates an 'L' geometry with ports on both ends. Based on phidl.

    Args:
        width: of the line
        size: length and height of the base
        layer:

    .. plot::
      :include-source:

      import pp

      c = pp.c.L(width1=1, size=(10, 20), layer=pp.LAYER.M3)
      pp.plotgds(c)

    """
    D = Component()
    w = width / 2
    s1, s2 = size
    points = [(-w, -w), (s1, -w), (s1, w), (w, w), (w, s2), (-w, s2), (-w, -w)]
    D.add_polygon(points, layer=layer)
    D.add_port(name=1, midpoint=(0, s2), width=width, orientation=90)
    D.add_port(name=2, midpoint=(s1, 0), width=width, orientation=0)
    return D
Ejemplo n.º 4
0
def add_keepout(component,
                target_layers,
                keepout_layers,
                margin=2.0) -> Component:
    """Adds keepout after Looking up all polygons in a cell.
    You can also use add_padding

    Args:
        component
        target_layers: list of layers to read
        keepout_layers: list of layers to add keepout
        margin: offset from tareget to keepout_layers
    """
    c = Component(f"{component.name}_ko")
    c << component
    for layer in target_layers:
        polygons = component.get_polygons(by_spec=layer)
        if polygons:
            for ko_layer in keepout_layers:
                ko_layer = _parse_layer(ko_layer)
                polygon_keepout = [
                    polygon_grow(polygon, margin) for polygon in polygons
                ]
                c.add_polygon(polygon_keepout, ko_layer)
    return c
def connect_electrical_shortest_path(port1, port2):
    """connects two ports with a polygon that takes the shortest path"""
    points = [port1.midpoint, port2.midpoint]
    name = f"zz_conn_{hash_points(points)}"
    c = Component(name=name)
    layer = port1.layer
    p1x0 = port1.endpoints[0][0]
    p1y0 = port1.endpoints[0][1]
    p1x1 = port1.endpoints[1][0]
    p1y1 = port1.endpoints[1][1]

    p2x0 = port2.endpoints[0][0]
    p2y0 = port2.endpoints[0][1]
    p2x1 = port2.endpoints[1][0]
    p2y1 = port2.endpoints[1][1]

    if port1.orientation in [90, 270]:
        c.add_polygon(
            ([(p1x1, p1y0), (p1x0, p1y1), (p2x1, p2y1), (p2x0, p2y0)]), layer=layer
        )
    else:
        c.add_polygon(
            ([(p1x0, p1y1), (p1x1, p1y0), (p2x1, p2y1), (p2x0, p2y0)]), layer=layer
        )
    return c.ref()
Ejemplo n.º 6
0
def _add_pin_square(
    component: Component,
    port: Port,
    pin_length: float = 0.1,
    layer: Tuple[int, int] = LAYER.PORT,
    label_layer: Optional[Tuple[int, int]] = LAYER.PORT,
    port_margin: float = 0.0,
) -> None:
    """Add half out pin to a component.

    Args:
        component:
        port: Port
        pin_length: length of the pin marker for the port
        layer: for the pin marker
        label_layer: for the label
        port_margin: margin to port edge


    .. code::

           _______________
          |               |
          |               |
          |               |
         |||              |
         |||              |
          |               |
          |      __       |
          |_______________|
                 __

    """
    p = port
    a = p.orientation
    ca = np.cos(a * np.pi / 180)
    sa = np.sin(a * np.pi / 180)
    rot_mat = np.array([[ca, -sa], [sa, ca]])

    d = p.width / 2 + port_margin

    dbot = np.array([pin_length / 2, -d])
    dtop = np.array([pin_length / 2, d])
    dbotin = np.array([-pin_length / 2, -d])
    dtopin = np.array([-pin_length / 2, +d])

    p0 = p.position + _rotate(dbot, rot_mat)
    p1 = p.position + _rotate(dtop, rot_mat)
    ptopin = p.position + _rotate(dtopin, rot_mat)
    pbotin = p.position + _rotate(dbotin, rot_mat)
    polygon = [p0, p1, ptopin, pbotin]
    component.add_polygon(polygon, layer=layer)

    if label_layer:
        component.add_label(
            text=str(p.name),
            position=p.midpoint,
            layer=label_layer,
        )
Ejemplo n.º 7
0
def tlm(
    width: float = 11.0,
    height: float = 11.0,
    layers: List[Tuple[int, int]] = [LAYER.M1, LAYER.M2, LAYER.M3],
    vias: List[Any] = [via2, via3],
) -> Component:
    """
    Rectangular transition thru metal layers

    Args:
        name: component name
        width, height: rectangle parameters
        layers: layers on which to draw rectangles
        vias: vias to use to fill the rectangles

    Returns
        <Component>
    """

    # assert len(layers) - 1 == len(vias), "tlm: There should be N layers for N-1 vias"

    a = width / 2
    b = height / 2
    rect_pts = [(-a, -b), (a, -b), (a, b), (-a, b)]

    c = Component()
    # Add metal rectangles
    for layer in layers:
        c.add_polygon(rect_pts, layer=layer)

    # Add vias
    for via in vias:
        via = via() if callable(via) else via

        w = via.info["width"]
        h = via.info["height"]
        g = via.info["clearance"]
        period = via.info["period"]

        nb_vias_x = (width - w - 2 * g) / period + 1
        nb_vias_y = (height - h - 2 * g) / period + 1

        nb_vias_x = int(floor(nb_vias_x))
        nb_vias_y = int(floor(nb_vias_y))

        cw = (width - (nb_vias_x - 1) * period - w) / 2
        ch = (height - (nb_vias_y - 1) * period - h) / 2

        x0 = -a + cw + w / 2
        y0 = -b + ch + h / 2

        for i in range(nb_vias_x):
            for j in range(nb_vias_y):
                c.add(via.ref(position=(x0 + i * period, y0 + j * period)))

    return c
Ejemplo n.º 8
0
def wg3(length=3, width=0.5):
    from pp.component import Component

    c = Component("waveguide")
    w = width / 2
    layer = (1, 0)
    c.add_polygon([(0, -w), (length, -w), (length, w), (0, w)], layer=layer)
    c.add_port(name="W0", midpoint=[0, 0], width=width, orientation=180, layer=layer)
    c.add_port(name="E0", midpoint=[length, 0], width=width, orientation=0, layer=layer)
    return c
Ejemplo n.º 9
0
def bbox(bbox=[(-1, -1), (3, 4)], layer=(1, 0)):
    """ Creates a bounding box rectangle from coordinates, to allow
    creation of a rectangle bounding box directly form another shape.

    Args:
        bbox: Coordinates of the box [(x1, y1), (x2, y2)].
        layer:

    """
    D = Component(name="bbox")
    (a, b), (c, d) = bbox
    points = ((a, b), (c, b), (c, d), (a, d))
    D.add_polygon(points, layer=layer)
    return D
Ejemplo n.º 10
0
def waveguide(
    length: float = 10.0,
    width: float = 0.5,
    layer: Tuple[int, int] = pp.LAYER.WG,
    layers_cladding: Optional[Iterable[Tuple[int, int]]] = None,
    cladding_offset: float = pp.conf.tech.cladding_offset,
) -> Component:
    """Straight waveguide

    Args:
        length: in X direction
        width: in Y direction
        layer
        layers_cladding
        cladding_offset

    .. plot::
      :include-source:

      import pp

      c = pp.c.waveguide(length=10, width=0.5)
      pp.plotgds(c)

    """
    c = Component()
    w = width / 2
    c.add_polygon([(0, -w), (length, -w), (length, w), (0, w)], layer=layer)

    wc = w + cladding_offset

    if layers_cladding:
        for layer_cladding in layers_cladding:
            c.add_polygon([(0, -wc), (length, -wc), (length, wc), (0, wc)],
                          layer=layer_cladding)

    c.add_port(name="W0",
               midpoint=[0, 0],
               width=width,
               orientation=180,
               layer=layer)
    c.add_port(name="E0",
               midpoint=[length, 0],
               width=width,
               orientation=0,
               layer=layer)

    c.width = width
    c.length = length
    return c
Ejemplo n.º 11
0
def via(width=0.7, height=0.7, period=2.0, clearance=1.0, layer=LAYER.VIA1):
    """Rectangular via"""
    c = Component()
    c.info["period"] = period
    c.info["clearance"] = clearance
    c.info["width"] = width
    c.info["height"] = height

    a = width / 2
    b = height / 2

    c.add_polygon([(-a, -b), (a, -b), (a, b), (-a, b)], layer=layer)

    return c
Ejemplo n.º 12
0
def _add_pin_square_inside(
    component: Component,
    port: Port,
    pin_length: float = 0.1,
    layer: Tuple[int, int] = LAYER.PORT,
    label_layer: Tuple[int, int] = LAYER.TEXT,
) -> None:
    """Add square pin towards the inside of the port

    Args:
        component:
        port: Port
        pin_length: length of the pin marker for the port
        layer: for the pin marker
        label_layer: for the label
        port_margin: margin to port edge

    .. code::

           _______________
          |               |
          |               |
          |               |
          ||              |
          ||              |
          |               |
          |      __       |
          |_______________|


    """
    p = port
    a = p.orientation
    ca = np.cos(a * np.pi / 180)
    sa = np.sin(a * np.pi / 180)
    rot_mat = np.array([[ca, -sa], [sa, ca]])

    d = p.width / 2

    dbot = np.array([0, -d])
    dtop = np.array([0, d])
    dbotin = np.array([-pin_length, -d])
    dtopin = np.array([-pin_length, +d])

    p0 = p.position + _rotate(dbot, rot_mat)
    p1 = p.position + _rotate(dtop, rot_mat)
    ptopin = p.position + _rotate(dtopin, rot_mat)
    pbotin = p.position + _rotate(dbotin, rot_mat)
    polygon = [p0, p1, ptopin, pbotin]
    component.add_polygon(polygon, layer=layer)
Ejemplo n.º 13
0
def _add_padding(component, x=50, y=50, layers=(LAYER.PADDING), suffix="p"):
    """Adds padding layers to component.
    This is just an example. For the real function see pp.add_padding.
    """
    c = Component(name=f"{component.name}_{suffix}")
    c << component
    points = [
        [c.xmin - x, c.ymin - y],
        [c.xmax + x, c.ymin - y],
        [c.xmax + x, c.ymax + y],
        [c.xmin - x, c.ymax + y],
    ]
    for layer in layers:
        c.add_polygon(points, layer=layer)
    return c
Ejemplo n.º 14
0
def coupler_straight(
    length: float = 10.0,
    width: float = 0.5,
    gap: float = 0.27,
    layer: Tuple[int, int] = pp.LAYER.WG,
    layers_cladding: List[Tuple[int, int]] = [pp.LAYER.WGCLAD],
    cladding_offset: float = 3.0,
) -> Component:
    """ straight coupled waveguides. Two multimode ports

    .. plot::
      :include-source:

      import pp

      c = pp.c.coupler_straight()
      pp.plotgds(c)

    """

    c = Component()

    # Top path
    c.add_polygon([(0, 0), (length, 0), (length, width), (0, width)],
                  layer=layer)
    y = width + gap

    # Bottom path
    c.add_polygon([(0, y), (length, y), (length, width + y), (0, width + y)],
                  layer=layer)

    # One multimode port on each side
    port_w = width * 2 + gap

    c.add_port(name="W0",
               midpoint=[0, port_w / 2],
               width=port_w,
               orientation=180)
    c.add_port(name="E0",
               midpoint=[length, port_w / 2],
               width=port_w,
               orientation=0)

    c.width = width
    c.length = length

    # cladding
    ymax = 2 * width + gap + cladding_offset
    for layer_cladding in layers_cladding:
        c.add_polygon(
            [
                (0, -cladding_offset),
                (length, -cladding_offset),
                (length, ymax),
                (0, ymax),
            ],
            layer=layer_cladding,
        )

    return c
Ejemplo n.º 15
0
def import_phidl_component(component: Device, **kwargs) -> Component:
    """ returns a gdsfactory Component from a phidl Device or function
    """
    D = call_if_func(component, **kwargs)
    D_copy = Component(name=D._internal_name)
    D_copy.info = copy.deepcopy(D.info)
    for ref in D.references:
        new_ref = ComponentReference(
            device=ref.parent,
            origin=ref.origin,
            rotation=ref.rotation,
            magnification=ref.magnification,
            x_reflection=ref.x_reflection,
        )
        new_ref.owner = D_copy
        D_copy.add(new_ref)
        for alias_name, alias_ref in D.aliases.items():
            if alias_ref == ref:
                D_copy.aliases[alias_name] = new_ref

    for p in D.ports.values():
        D_copy.add_port(
            port=Port(
                name=p.name,
                midpoint=p.midpoint,
                width=p.width,
                orientation=p.orientation,
                parent=p.parent,
            )
        )
    for poly in D.polygons:
        D_copy.add_polygon(poly)
    for label in D.labels:
        D_copy.add_label(
            text=label.text,
            position=label.position,
            layer=(label.layer, label.texttype),
        )
    return D_copy
Ejemplo n.º 16
0
def _add_pin_triangle(
    component: Component,
    port: Port,
    layer: Tuple[int, int] = LAYER.PORT,
    label_layer: Tuple[int, int] = LAYER.TEXT,
) -> None:
    """Add triangle pin with a right angle, pointing out of the port

    Args:
        component:
        port: Port
        layer: for the pin marker
        label_layer: for the label
    """
    p = port

    a = p.orientation
    ca = np.cos(a * np.pi / 180)
    sa = np.sin(a * np.pi / 180)
    rot_mat = np.array([[ca, -sa], [sa, ca]])

    d = p.width / 2

    dbot = np.array([0, -d])
    dtop = np.array([0, d])
    dtip = np.array([d, 0])

    p0 = p.position + _rotate(dbot, rot_mat)
    p1 = p.position + _rotate(dtop, rot_mat)
    ptip = p.position + _rotate(dtip, rot_mat)
    polygon = [p0, p1, ptip]

    component.add_label(
        text=p.name,
        position=p.midpoint,
        layer=label_layer,
    )

    component.add_polygon(polygon, layer=layer)
Ejemplo n.º 17
0
def connect_electrical_shortest_path(port1, port2):
    """connects two ports with a polygon that takes the shortest path"""
    c = Component(name="zz_conn_{}".format(uuid.uuid4()))
    layer = port1.layer
    p1x0 = port1.endpoints[0][0]
    p1y0 = port1.endpoints[0][1]
    p1x1 = port1.endpoints[1][0]
    p1y1 = port1.endpoints[1][1]

    p2x0 = port2.endpoints[0][0]
    p2y0 = port2.endpoints[0][1]
    p2x1 = port2.endpoints[1][0]
    p2y1 = port2.endpoints[1][1]

    if port1.orientation in [90, 270]:
        c.add_polygon(([(p1x1, p1y0), (p1x0, p1y1), (p2x1, p2y1),
                        (p2x0, p2y0)]),
                      layer=layer)
    else:
        c.add_polygon(([(p1x0, p1y1), (p1x1, p1y0), (p2x1, p2y1),
                        (p2x0, p2y0)]),
                      layer=layer)
    return c.ref()
Ejemplo n.º 18
0
def _add_outline(
    component: Component,
    reference: Optional[ComponentReference] = None,
    layer: Tuple[int, int] = LAYER.DEVREC,
    **kwargs,
) -> None:
    """Adds devices outline bounding box in layer.

    Args:
        component: where to add the markers
        reference: to read outline from
        layer: to add padding
        default: default padding
        top: North padding
        bottom
        right
        left
    """
    c = reference or component
    if hasattr(component, "parent"):
        component = component.parent
    points = get_padding_points(component=c, default=0, **kwargs)
    component.add_polygon(points, layer=layer)
Ejemplo n.º 19
0
def waveguide_pin(
    length: float = 10.0,
    width: float = 0.5,
    width_i: float = 0.0,
    width_p: float = 1.0,
    width_n: float = 1.0,
    width_pp: float = 1.0,
    width_np: float = 1.0,
    width_ppp: float = 1.0,
    width_npp: float = 1.0,
    layer_p: Tuple[int, int] = LAYER.P,
    layer_n: Tuple[int, int] = LAYER.N,
    layer_pp: Tuple[int, int] = LAYER.Pp,
    layer_np: Tuple[int, int] = LAYER.Np,
    layer_ppp: Tuple[int, int] = LAYER.Ppp,
    layer_npp: Tuple[int, int] = LAYER.Npp,
    waveguide_factory: Callable = waveguide,
) -> Component:
    """PN doped waveguide

        .. code::


                               |<------width------>|
                                ____________________
                               |     |       |     |
            ___________________|     |       |     |__________________________|
                                     |       |                                |
                P++     P+     P     |   I   |     N        N+         N++    |
            __________________________________________________________________|
                                                                              |
                                     |width_i| width_n | width_np | width_npp |
                                        0    oi        on        onp         onpp

    .. plot::
      :include-source:

      import pp

      c = pp.c.waveguide_pin(length=10)
      pp.plotgds(c)

    """
    c = Component()
    w = c << waveguide_factory(length=length, width=width)
    c.absorb(w)

    oi = width_i / 2
    on = oi + width_n
    onp = oi + width_n + width_np
    onpp = oi + width_n + width_np + width_npp

    # N doping
    c.add_polygon([(0, oi), (length, oi), (length, onpp), (0, onpp)],
                  layer=layer_n)

    if layer_np:
        c.add_polygon([(0, on), (length, on), (length, onpp), (0, onpp)],
                      layer=layer_np)
    if layer_npp:
        c.add_polygon([(0, onp), (length, onp), (length, onpp), (0, onpp)],
                      layer=layer_npp)

    oi = -width_i / 2
    op = oi - width_p
    opp = oi - width_p - width_pp
    oppp = oi - width_p - width_pp - width_ppp

    # P doping
    c.add_polygon([(0, oi), (length, oi), (length, oppp), (0, oppp)],
                  layer=layer_p)
    if layer_pp:
        c.add_polygon([(0, op), (length, op), (length, oppp), (0, oppp)],
                      layer=layer_pp)
    if layer_ppp:
        c.add_polygon([(0, opp), (length, opp), (length, oppp), (0, oppp)],
                      layer=layer_ppp)

    return c
Ejemplo n.º 20
0
def wg_heater_connector(
    heater_ports: List[Port],
    metal_width: float = 10.0,
    tlm_layers: List[Tuple[int, int]] = [
        LAYER.VIA1,
        LAYER.M1,
        LAYER.VIA2,
        LAYER.M2,
        LAYER.VIA3,
        LAYER.M3,
    ],
) -> Component:
    """
    Connects together a pair of wg heaters and connect to a M3 port
    """

    cmp = Component()
    assert len(heater_ports) == 2
    assert (heater_ports[0].orientation == heater_ports[1].orientation
            ), "both ports should be facing in the same direction"
    angle = heater_ports[0].orientation
    angle = angle % 360
    assert angle in [0, 180], "angle should be 0 or 180, got {}".format(angle)

    dx = 0.0
    dy = 0.0

    angle_to_dps = {0: [(-dx, -dy), (-dx, dy)], 180: [(dx, -dy), (dx, dy)]}
    ports = heater_ports
    hw = heater_ports[0].width

    if angle in [0, 180]:
        ports.sort(key=lambda p: p.y)
    else:
        ports.sort(key=lambda p: p.x)

    _heater_to_metal = tlm(width=0.5, height=0.5, layers=tlm_layers, vias=[])

    tlm_positions = []
    for port, dp in zip(ports, angle_to_dps[angle]):
        # Extend heater
        p = port.midpoint

        # Add via/metal transitions
        tlm_pos = p + dp
        hm = _heater_to_metal.ref(position=tlm_pos)
        tlm_positions += [tlm_pos]
        cmp.add(hm)

    ss = 1 if angle == 0 else -1

    # Connect both sides with top metal
    edge_metal_piece_width = 7.0
    x = ss * edge_metal_piece_width / 2
    top_metal_layer = tlm_layers[-1]
    cmp.add_polygon(
        line(
            tlm_positions[0] + (x, -hw / 2),
            tlm_positions[1] + (x, hw / 2),
            edge_metal_piece_width,
        ),
        layer=top_metal_layer,
    )

    # Add metal port
    cmp.add_port(
        name="0",
        midpoint=0.5 * sum(tlm_positions) +
        (ss * edge_metal_piece_width / 2, 0),
        orientation=angle,
        width=metal_width,
        layer=top_metal_layer,
        port_type="dc",
    )

    return cmp
Ejemplo n.º 21
0
def import_gds(
    gdspath: Union[str, Path],
    cellname: None = None,
    flatten: bool = False,
    snap_to_grid_nm: Optional[int] = None,
) -> Component:
    """Returns a Componenent from a GDS file.

    Adapted from phidl/geometry.py

    Args:
        gdspath: path of GDS file
        cellname: cell of the name to import (None) imports top cell
        flatten: if True returns flattened (no hierarchy)
        snap_to_grid_nm: snap to different nm grid (does not snap if False)

    """
    gdsii_lib = gdspy.GdsLibrary()
    gdsii_lib.read_gds(gdspath)
    top_level_cells = gdsii_lib.top_level()
    cellnames = [c.name for c in top_level_cells]

    if cellname is not None:
        if cellname not in gdsii_lib.cells:
            raise ValueError(
                f"cell {cellname} is not in file {gdspath} with cells {cellnames}"
            )
        topcell = gdsii_lib.cells[cellname]
    elif cellname is None and len(top_level_cells) == 1:
        topcell = top_level_cells[0]
    elif cellname is None and len(top_level_cells) > 1:
        raise ValueError(
            f"import_gds() There are multiple top-level cells in {gdspath}, "
            f"you must specify `cellname` to select of one of them among {cellnames}"
        )

    if not flatten:
        D_list = []
        c2dmap = {}
        for cell in gdsii_lib.cells.values():
            D = Component(name=cell.name)
            D.polygons = cell.polygons
            D.references = cell.references
            D.name = cell.name
            for label in cell.labels:
                rotation = label.rotation
                if rotation is None:
                    rotation = 0
                label_ref = D.add_label(
                    text=label.text,
                    position=np.asfarray(label.position),
                    magnification=label.magnification,
                    rotation=rotation * 180 / np.pi,
                    layer=(label.layer, label.texttype),
                )
                label_ref.anchor = label.anchor
            c2dmap.update({cell: D})
            D_list += [D]

        for D in D_list:
            # First convert each reference so it points to the right Device
            converted_references = []
            for e in D.references:
                ref_device = c2dmap[e.ref_cell]
                if isinstance(e, gdspy.CellReference):
                    dr = DeviceReference(
                        device=ref_device,
                        origin=e.origin,
                        rotation=e.rotation,
                        magnification=e.magnification,
                        x_reflection=e.x_reflection,
                    )
                    dr.owner = D
                    converted_references.append(dr)
                elif isinstance(e, gdspy.CellArray):
                    dr = CellArray(
                        device=ref_device,
                        columns=e.columns,
                        rows=e.rows,
                        spacing=e.spacing,
                        origin=e.origin,
                        rotation=e.rotation,
                        magnification=e.magnification,
                        x_reflection=e.x_reflection,
                    )
                    dr.owner = D
                    converted_references.append(dr)
            D.references = converted_references

            # Next convert each Polygon
            # temp_polygons = list(D.polygons)
            # D.polygons = []
            # for p in temp_polygons:
            #     D.add_polygon(p)

            # Next convert each Polygon
            temp_polygons = list(D.polygons)
            D.polygons = []
            for p in temp_polygons:
                if snap_to_grid_nm:
                    points_on_grid = pp.drc.snap_to_grid(
                        p.polygons[0], nm=snap_to_grid_nm
                    )
                    p = gdspy.Polygon(
                        points_on_grid, layer=p.layers[0], datatype=p.datatypes[0]
                    )
                D.add_polygon(p)
        topdevice = c2dmap[topcell]
        return topdevice
    if flatten:
        D = pp.Component()
        polygons = topcell.get_polygons(by_spec=True)

        for layer_in_gds, polys in polygons.items():
            D.add_polygon(polys, layer=layer_in_gds)
        return D
Ejemplo n.º 22
0
def gdsdiff(cellA, cellB):
    """Compare two Components.

    Args:
        CellA: Component or path to gds file
        CellB: Component or path to gds file

    Returns:
        Component with both cells (xor, common and diffs)
    """
    if isinstance(cellA, pathlib.PosixPath):
        cellA = str(cellA)
    if isinstance(cellB, pathlib.PosixPath):
        cellB = str(cellB)
    if isinstance(cellA, str):
        cellA = import_gds(cellA, flatten=True)
    if isinstance(cellB, str):
        cellB = import_gds(cellB, flatten=True)

    layers = set()
    layers.update(cellA.get_layers())
    layers.update(cellB.get_layers())

    top = Component(name="TOP")
    diff = Component(name="xor")
    common = Component(name="common")
    old_only = Component(name="only_in_old")
    new_only = Component(name="only_in_new")

    cellA.name = "old"
    cellB.name = "new"
    top << cellA
    top << cellB

    for layer in layers:
        A = get_polygons_on_layer(cellA, layer)
        B = get_polygons_on_layer(cellB, layer)

        if A is None and B is None:
            continue
        elif B is None:
            diff.add_polygon(A, layer)
            continue
        elif A is None:
            diff.add_polygon(B, layer)
            continue

        # Common bits
        common_AB = boolean(A, B, operation="and", precision=0.001)

        # Bits in either A or B
        either_AB = boolean(A, B, operation="xor", precision=0.001)

        # Bits only in A
        only_in_A = boolean(A, either_AB, operation="and", precision=0.001)

        # Bits only in B
        only_in_B = boolean(B, either_AB, operation="and", precision=0.001)

        if common_AB is not None:
            common.add_polygon(common_AB, layer)
        if only_in_A is not None:
            old_only.add_polygon(only_in_A, layer)
        if only_in_B is not None:
            new_only.add_polygon(only_in_B, layer)

    top << diff
    top << common
    top << old_only
    top << new_only
    return top