Esempio n. 1
0
class BasicSpline(shapes.Shape):
    """  """

    radius = param.FloatField(default=5)
    angle = param.FloatField(default=10)
    angle_step = param.FloatField(default=2)

    def create_points(self, pts):
        DEG2RAD = np.pi / 180.0
        alpha = self.angle * DEG2RAD
        c = math.sin(alpha)
        if self.angle == 45.0:
            t = 0.5
        else:
            c2 = c**2
            t = math.sin(math.atan(((1.0 - c2) / c2)**0.125))**2

        L = self.radius * 2 * t * (1 - t) / (3 * (t**4 + (1 - t)**4)**1.5)

        q0_0 = np.array([-L, 0])
        q0_1 = np.array([0, 0])
        q0_2 = np.array([0, 0])
        q0_3 = np.array([0, L])

        q1_0 = t * q0_0 + (1 - t) * q0_1
        q2_0 = t**2 * q0_0 + 2 * t * (1 - t) * q0_1 + (1 - t)**2 * q0_2
        q3_0 = t**3 * q0_0 + 3 * t**2 * (1 - t) * q0_1 + 3 * t * (
            1 - t)**2 * q0_2 + (1 - t)**3 * q0_3

        S = shapes.Shape(points=[[q0_0, q1_0, q2_0, q3_0]])

        steps = int(math.ceil(2.0 * self.angle / self.angle_step))
        return BezierCurve(midpointal_shape=S, steps=steps).points
Esempio n. 2
0
class ArcRoute(spira.Route):

    gdslayer = param.LayerField(name='ArcLayer', number=91)
    radius = param.FloatField(default=5)
    width = param.FloatField(default=1)
    theta = param.FloatField(default=45)
    start_angle = param.FloatField(default=0)
    angle_resolution = param.FloatField(default=1)
    angle1 = param.DataField(fdef_name='create_angle1')
    angle2 = param.DataField(fdef_name='create_angle2')

    def create_angle1(self):
        angle1 = (self.start_angle + 0) * np.pi / 180
        return angle1

    def create_angle2(self):
        angle2 = (self.start_angle + self.theta + 0) * np.pi / 180
        return angle2

    def create_port_input(self):
        midpoint = self.radius * np.cos(self.angle1), self.radius * np.sin(
            self.angle1)
        orientation = self.start_angle - 0 + 180 * (self.theta < 0)
        port = spira.Term(name='P1',
                          midpoint=midpoint,
                          width=self.width,
                          length=0.2,
                          orientation=orientation + 180)
        return port

    def create_port_output(self):
        midpoint = self.radius * np.cos(self.angle2), self.radius * np.sin(
            self.angle2)
        orientation = self.start_angle + self.theta + 180 - 180 * (self.theta <
                                                                   0)
        port = spira.Term(name='P2',
                          midpoint=midpoint,
                          width=self.width,
                          length=0.2,
                          orientation=orientation + 180)
        return port

    def create_points(self, points):

        inner_radius = self.radius - self.width / 2.0
        outer_radius = self.radius + self.width / 2.0
        z = int(np.ceil(abs(self.theta) / self.angle_resolution))
        t = np.linspace(self.angle1, self.angle2, z)

        inner_points_x = (inner_radius * np.cos(t)).tolist()
        inner_points_y = (inner_radius * np.sin(t)).tolist()
        outer_points_x = (outer_radius * np.cos(t)).tolist()
        outer_points_y = (outer_radius * np.sin(t)).tolist()
        xpts = np.array(inner_points_x + outer_points_x[::-1])
        ypts = np.array(inner_points_y + outer_points_y[::-1])

        points = [[list(p) for p in list(zip(xpts, ypts))]]

        return points
Esempio n. 3
0
    class TerminalExample(spira.Cell):
        width = param.FloatField(default=10)
        height = param.FloatField(default=1)

        def create_ports(self, ports):
            ports += spira.Term(name='P1',
                                midpoint=(10, 0),
                                width=self.height,
                                orientation=180)
            return ports
Esempio n. 4
0
class ArcSeries(spira.Cell):

    gdslayer = param.LayerField(number=91)
    radius = param.FloatField(default=20)
    #     radius = param.FloatField(default=20 * 1e6)
    width = param.FloatField(default=1.0)
    #     width = param.FloatField(default=1.0 * 1e6)
    angular_coverage = param.FloatField(default=30)
    num_steps = param.IntegerField(default=1)
    angle_resolution = param.FloatField(default=0.1)
    start_angle = param.IntegerField(default=0)
    direction = param.StringField(default='ccw')

    port1 = param.DataField()
    port2 = param.DataField()

    subarc = SubArcSeries

    def get_subarc_routes(self):
        D = SubArcSeries(gdslayer=self.gdslayer,
                         radius=self.radius,
                         width=self.width,
                         angular_coverage=self.angular_coverage,
                         num_steps=self.num_steps,
                         angle_resolution=self.angle_resolution,
                         start_angle=self.start_angle)

        s1 = spira.SRef(D)
        s2 = spira.SRef(D)

        s2.reflect(p1=[0, 0], p2=[1, 1])
        s2.connect(port='P2', destination=s1.ports['P2'])

        return s1, s2

    def create_elementals(self, elems):

        s1, s2 = self.get_subarc_routes()

        elems += s1
        elems += s2

        return elems

    def create_ports(self, ports):

        s1, s2 = self.get_subarc_routes()

        #         ports += s1.ports['P1'].modified_copy(name='Port_1')
        #         ports += s2.ports['P1'].modified_copy(name='Port_2')

        return ports
Esempio n. 5
0
class BasicTriangle(Shape):

    a = param.FloatField(default=2)
    b = param.FloatField(default=0.5)
    c = param.FloatField(default=1)

    def create_points(self, points):
        p1 = [0, 0]
        p2 = [p1[0] + self.b, p1[1]]
        p3 = [p1[0], p1[1] + self.a]
        pts = np.array([p1, p2, p3])
        points = [pts]
        return points
Esempio n. 6
0
class Width(__SingleLayerDesignRule__):
    minimum = param.FloatField()
    maximum = param.FloatField()
    error = param.IntegerField(default=RDD.PURPOSE.ERROR.MIN_WIDTH.datatype)

    def __repr__(self):
        return 'Rule width: min={} max={}'.format(self.minimum, self.maximum)

    def apply(self, elems):
        fails = False
        if self.violate:
            fails = True
        return fails
Esempio n. 7
0
class JunctionSquid(spira.Cell):

    width = param.FloatField()
    height = param.FloatField()
    midpoint = param.FloatField()
    w = param.FloatField()
    h = param.FloatField()

    top_routing = param.DataField(fdef_name='create_top_routing')
    bot_routing = param.DataField(fdef_name='create_bot_routing')

    def create_top_routing(self):
        p1 = [self.midpoint, self.h / 2]
        p2 = [self.midpoint, self.h / 2 + self.height]
        p3 = [self.width, self.h / 2 + self.height]
        p4 = [self.width, self.h / 2]

        points = [p1, p2, p3, p4]

        return spira.Path(points, width=1, gdslayer=RDD.M5, distance=3)

    def create_bot_routing(self):
        p1 = [self.midpoint, -self.h / 2]
        p2 = [self.midpoint, -self.height]
        p3 = [self.width, -self.height]
        p4 = [self.width, -self.h / 2]

        points = [p1, p2, p3, p4]

        return spira.Path(points, width=1, gdslayer=RDD.M6, distance=3)

    def create_elementals(self, elems):

        jj = Junction()

        # FIXME: Automate this movement.
        jj.move(origin=jj.center, destination=(0, 0))

        # FIXME: Rotation applies to parent cell.
        j1 = spira.SRef(jj, origin=(-1, 0), rotation=90)
        # j1.move(origin=j1.ref.center, destination=(0,0))
        j2 = spira.SRef(jj, origin=(10.5, 0), rotation=180)

        elems += j1
        elems += j2

        elems += self.top_routing
        elems += self.bot_routing

        return elems
Esempio n. 8
0
class BoxShape(Shape):

    width = param.FloatField(default=1)
    height = param.FloatField(default=1)

    def create_points(self, points):
        cx = self.center[0]
        cy = self.center[1]
        dx = 0.5 * self.width
        dy = 0.5 * self.height
        pts = [(cx + dx, cy + dy), (cx - dx, cy + dy), (cx - dx, cy - dy),
               (cx + dx, cy - dy)]
        points = np.array([pts])
        return points
Esempio n. 9
0
class CircleShape(Shape):

    box_size = param.PointField(default=(1.0, 1.0))
    start_angle = param.FloatField(default=0.0)
    end_angle = param.FloatField(default=360.0)
    angle_step = param.FloatField(default=3)

    def create_points(self, points):
        sa = self.start_angle * DEG2RAD
        ea = self.end_angle * DEG2RAD
        h_radius = self.box_size[0] / 2.0
        v_radius = self.box_size[1] / 2.0
        n_s = float(self.end_angle - self.start_angle) / self.angle_step
        n_steps = int(math.ceil(abs(n_s))) * np.sign(n_s)
        if n_steps == 0:
            if sa == ea:
                pts = np.array([[
                    math.cos(sa) * h_radius + self.center[0],
                    math.sin(sa) * v_radius + self.center[1]
                ]])
            else:
                pts = np.array([[
                    math.cos(sa) * h_radius + self.center[0],
                    math.sin(sa) * v_radius + self.center[1]
                ],
                                [
                                    math.cos(ea) * h_radius + self.center[0],
                                    math.sin(ea) * v_radius + self.center[1]
                                ]])
            return pts

        angle_step = float(ea - sa) / n_steps
        if self.clockwise:
            angle_step = -angle_step
            sign = -1
        else:
            sign = +1
        while sign * sa > sign * ea:
            ea += sign * 2 * math.pi

        angles = np.arange(sa, ea + 0.5 * angle_step, angle_step)
        pts = np.column_stack((np.cos(angles), np.sin(angles))) \
                               * np.array([(h_radius, v_radius)]) \
                               + np.array([(self.center[0], self.center[1])])

        points = np.array([pts])

        return points
Esempio n. 10
0
class LibraryAbstract(__Library__):

    grid = param.FloatField(default=RDD.GDSII.GRID)
    grids_per_unit = param.DataField(fdef_name='create_grids_per_unit')
    units_per_grid = param.DataField(fdef_name='create_units_per_grid')

    def create_grids_per_unit(self):
        return self.unit / self.grid

    def create_units_per_grid(self):
        return self.grid / self.unit

    def validate_parameters(self):
        if self.grid > self.unit:
            raise Exception('The grid should be smaller than the unit.')
        return True

    def referenced_structures(self):
        referred_to_list = list()
        for s in self.cells:
            referred_to_list.append(s.dependencies())
        return referred_to_list

    def get_cell(self, cell_name):
        for C in self.cells:
            if C.name == cell_name:
                return C
        return None

    def is_empty(self):
        return len(self.cells) == 0

    def clear(self):
        self.cells.clear()
Esempio n. 11
0
class Squid(spira.Cell):

    m1 = param.MidPointField(default=(0, 0))
    m2 = param.MidPointField(default=(0, 0))
    rotation = param.FloatField(default=0)

    def create_elementals(self, elems):

        jj = Junction()

        jj.center = (0, 0)

        s1 = spira.SRef(jj, midpoint=self.m1, rotation=self.rotation)
        s2 = spira.SRef(jj, midpoint=self.m2, rotation=-self.rotation)

        r1 = RouteManhattan(port1=s1.ports['Output'],
                            port2=s2.ports['Output'],
                            radius=1,
                            length=1)
        r2 = RouteManhattan(port1=s1.ports['Input'],
                            port2=s2.ports['Input'],
                            radius=1,
                            length=1)

        s3 = spira.SRef(r1)
        elems += s3

        s4 = spira.SRef(r2)
        elems += s4

        elems += [s1, s2]

        return elems
Esempio n. 12
0
    class Triangle(shapes.Shape):
        """ Right triangle """

        a = param.FloatField(default=1)
        b = param.FloatField(default=1)
        c = param.FloatField(default=1)

        def create_points(self, points):

            p1 = [0, 0]
            p2 = [p1[0]+self.b, p1[1]]
            p3 = [p1[0], p1[1]+self.a]

            points = [[p1, p2, p3]]

            return points
Esempio n. 13
0
class GradualFractal(spira.Cell):
    """
    Creates a 90-degree bent waveguide the bending radius is
    gradually increased until it reaches the minimum
    value of the radius at the "angular coverage" angle.
    It essentially creates a smooth transition to a bent waveguide
    mode. User can control number of steps provided. Direction
    determined by start angle and cw or ccw switch with the
    default 10 "num_steps" and 15 degree coverage,
    effective radius is about 1.5*radius.
    """

    gdslayer = param.LayerField(number=91)
    radius = param.FloatField(default=20)
    #     radius = param.FloatField(default=20 * 1e6)
    width = param.FloatField(default=1.0)
    #     width = param.FloatField(default=1.0 * 1e6)
    angular_coverage = param.FloatField(default=20)
    num_steps = param.IntegerField(default=5)
    angle_resolution = param.FloatField(default=0.01)
    start_angle = param.IntegerField(default=0)
    direction = param.StringField(default='ccw')

    def create_elementals(self, elems):

        D = ArcSeries(gdslayer=self.gdslayer,
                      radius=self.radius,
                      width=self.width,
                      angular_coverage=self.angular_coverage,
                      num_steps=self.num_steps,
                      angle_resolution=self.angle_resolution,
                      start_angle=self.start_angle)

        # D.xmin, D.ymin = 0, 0

        # Orient to default settings...
        # D.reflect(p1=[0,0], p2=[1,1])
        # D.reflect(p1=[0,0], p2=[1,0])

        # D.rotate(angle=self.start_angle, center=D.center)
        # D.center = [0, 0]

        s1 = spira.SRef(D)
        elems += s1

        return elems
Esempio n. 14
0
class Box(Base):

    w = param.FloatField(default=1)
    h = param.FloatField(default=1)
    center = param.PointField()

    def validate_parameters(self):
        if self.w < self.player.data.WIDTH:
            return False
        if self.h < self.player.data.WIDTH:
            return False
        return True

    def create_polygon(self):
        shape = shapes.BoxShape(center=self.center, width=self.w, height=self.h)
        ply = spira.Polygons(shape=shape, gdslayer=self.player.layer)
        return ply
Esempio n. 15
0
class YtronShape(shapes.Shape):
    """  """

    rho = param.IntegerField(default=1)
    arm_lengths = param.PointField(default=(500, 300))
    source_length = param.IntegerField(default=500)
    arm_widths = param.PointField(default=(200, 200))
    theta = param.FloatField(default=2.5)
    theta_resolution = param.FloatField(default=10)

    def create_points(self, points):

        theta = self.theta * np.pi / 180
        theta_resolution = self.theta_resolution * np.pi / 180
        thetalist = np.linspace(
            -(np.pi - theta), -theta,
            int((np.pi - 2 * theta) / theta_resolution) + 2)
        semicircle_x = self.rho * np.cos(thetalist)
        semicircle_y = self.rho * np.sin(thetalist) + self.rho

        xc = self.rho * np.cos(theta)
        yc = self.rho * np.sin(theta)
        arm_x_left = self.arm_lengths[0] * np.sin(theta)
        arm_y_left = self.arm_lengths[0] * np.cos(theta)
        arm_x_right = self.arm_lengths[1] * np.sin(theta)
        arm_y_right = self.arm_lengths[1] * np.cos(theta)

        xpts = semicircle_x.tolist() + [
            xc + arm_x_right, xc + arm_x_right + self.arm_widths[1],
            xc + self.arm_widths[1], xc + self.arm_widths[1], 0,
            -(xc + self.arm_widths[0]), -(xc + self.arm_widths[0]),
            -(xc + arm_x_left + self.arm_widths[0]), -(xc + arm_x_left)
        ]
        ypts = semicircle_y.tolist() + [
            yc + arm_y_right, yc + arm_y_right, yc, yc - self.source_length,
            yc - self.source_length, yc - self.source_length, yc,
            yc + arm_y_left, yc + arm_y_left
        ]

        points = np.array([list(zip(xpts, ypts))])

        return points
Esempio n. 16
0
class __Path__(gdspy.Path, Shape):

    width = param.FloatField(default=1)
    initial_point = param.PointField()
    number_of_paths = param.IntegerField(default=1)
    distance = param.FloatField(default=0)

    def __init__(self, **kwargs):

        Shape.__init__(self, **kwargs)
        gdspy.Path.__init__(self,
            width=self.width,
            initial_point=self.initial_point,
            number_of_paths=self.number_of_paths,
            distance=self.distance
        )

    def __repr__(self):
        if self is None:
            return 'Path is None!'
        return ("[SPiRA: Path] (width {}, distance {})").format(self.width, self.distance)

    def __str__(self):
        return self.__repr__()
Esempio n. 17
0
class ConvexPolygon(Shape):

    radius = param.FloatField(default=1.0)
    num_sides = param.IntegerField(default=6)

    def create_points(self, pts):
        if self.radius == 0.0:
            pts.append(self.center)
            return pts
        angle_step = 2 * math.pi / self.num_sides
        for i in range(0, self.num_sides):
            x0 = self.radius * np.cos((i + 0.5) * angle_step + math.pi / 2)
            y0 = self.radius * np.sin((i + 0.5) * angle_step + math.pi / 2)
            pts.append((self.center[0] + x0, self.center[1] + y0))
        points = np.array([pts])
        return points
Esempio n. 18
0
class Port(PortAbstract):
    """ Ports are objects that connect different polygons
    or references in a layout. Ports represent vertical
    connection such as vias or junctions.

    Examples
    --------
    >>> port = spira.Port()
    """

    edge_width = param.FloatField(default=0.25)

    def __init__(self, port=None, polygon=None, **kwargs):
        super().__init__(port=port, polygon=polygon, **kwargs)

        if polygon is None:
            from spira import shapes
            shape = shapes.CircleShape(
                center=self.midpoint,
                box_size=[self.edge_width, self.edge_width])
            pp = spira.Polygons(shape=shape, gdslayer=self.gdslayer)
            pp.move(midpoint=pp.center, destination=self.midpoint)
            self.polygon = pp
        else:
            self.polygon = polygon

    def __repr__(self):
        return ("[SPiRA: Port] (name {}, number {}, midpoint {}, " +
                "radius {}, orientation {})").format(self.name,
                                                     self.gdslayer.number,
                                                     self.midpoint,
                                                     self.edge_width,
                                                     self.orientation)

    def _copy(self):
        new_port = Port(parent=self.parent,
                        polygon=deepcopy(self.polygon),
                        name=self.name,
                        midpoint=deepcopy(self.midpoint),
                        edge_width=self.edge_width,
                        gdslayer=deepcopy(self.gdslayer),
                        poly_layer=deepcopy(self.poly_layer),
                        text_layer=deepcopy(self.text_layer),
                        orientation=deepcopy(self.orientation))
        return new_port
Esempio n. 19
0
class BezierCurve(__ShapeContainer__):
    """ polynomial bezier curve based on a shape with control points """
    steps = param.FloatField(default=100)

    def __init__(self, midpointal_shape, **kwargs):
        super().__init__(midpointal_shape=midpointal_shape, **kwargs)

    def create_points(self, pts):
        step = 1.0 / self.steps
        t = np.arange(0.0, 1.0 + 0.5 * step, step)
        P = np.array(self.midpointal_shape.points[0])
        Px = np.outer(P[:, 0], np.ones(np.size(t)))
        Py = np.outer(P[:, 1], np.ones(np.size(t)))

        for j in range(len(self.midpointal_shape.points[0]) - 1, 0, -1):
            Px = Px[0:j, :] + np.diff(Px, 1, 0) * t
            Py = Py[0:j, :] + np.diff(Py, 1, 0) * t

        pts = np.transpose(np.row_stack((Px, Py)))
        points = np.array([pts])

        return points
Esempio n. 20
0
class SRefAbstract(__SRef__):

    midpoint = param.MidPointField()
    rotation = param.FloatField(default=0)
    reflection = param.BoolField(default=False)
    magnification = param.FloatField(default=1)

    def dependencies(self):
        """  """
        from spira.gdsii.lists.cell_list import CellList
        d = CellList()
        d.add(self.ref)
        d.add(self.ref.dependencies())
        return d

    def _copy(self, level=0):
        S = SRef(structure=self.ref,
                 midpoint=self.midpoint,
                 rotation=self.rotation,
                 magnification=self.magnification,
                 reflection=self.reflection)
        return S

    def flat_copy(self, level=-1, commit_to_gdspy=False):
        """  """

        if level == 0:
            el = spira.ElementList()
            el += self
            return el

        transform = {
            'midpoint': self.midpoint,
            'rotation': self.rotation,
            'magnification': self.magnification,
            'reflection': self.reflection
        }

        el = self.ref.elementals.flat_copy(level - 1)
        el.transform(transform)
        return el

    def transform(self, transform):
        if transform['reflection']:
            self.reflect(p1=[0, 0], p2=[1, 0])
        if transform['rotation']:
            self.rotate(angle=transform['rotation'])
        if transform['midpoint']:
            self.translate(dx=transform['midpoint'][0],
                           dy=transform['midpoint'][1])
        return self

    def flatten(self):
        return self.ref.flatten()

    @property
    def ports(self):
        """
        This property allows you to access
        my_device_reference.ports, and receive a
        copy of the ports dict which is correctly
        rotated and translated
        """
        for port in self._parent_ports:

            tf = {
                'midpoint': self.midpoint,
                'rotation': self.rotation,
                'magnification': self.magnification,
                'reflection': self.reflection
            }

            # print(tf['rotation'])

            new_port = port._copy()
            self._local_ports[port.name] = new_port.transform(tf)
        return self._local_ports

    def move(self, midpoint=(0, 0), destination=None, axis=None):
        """
        Moves the DeviceReference from the midpoint point to the destination. Both
        midpoint and destination can be 1x2 array-like, Port, or a key
        corresponding to one of the Ports in this device_ref
        """

        if destination is None:
            destination = midpoint
            midpoint = (0, 0)

        if issubclass(type(midpoint), __Port__):
            o = midpoint.midpoint
        elif np.array(midpoint).size == 2:
            o = midpoint
        elif midpoint in self.ports:
            o = self.ports[midpoint].midpoint
        else:
            raise ValueError("[DeviceReference.move()] ``midpoint`` " +
                             "not array-like, a port, or port name")

        if issubclass(type(destination), __Port__):
            d = destination.midpoint
        elif np.array(destination).size == 2:
            d = destination
        elif destination in self.ports:
            d = self.ports[destination].midpoint
        else:
            raise ValueError("[DeviceReference.move()] ``destination`` " +
                             "not array-like, a port, or port name")

        if axis == 'x':
            d = (d[0], o[1])
        if axis == 'y':
            d = (o[0], d[1])

        dxdy = np.array(d) - np.array(o)
        self.midpoint = np.array(self.midpoint) + dxdy
        return self

    def translate(self, dx=0, dy=0):
        """ Translate port by dx and dy. """
        super().translate(dx=dx, dy=dy)
        self.midpoint = self.midpoint
        return self

    def rotate(self, angle=45, center=(0, 0)):
        """  """
        if angle == 0:
            return self

        if issubclass(type(center), __Port__):
            center = center.midpoint

        self.rotation += angle
        self.midpoint = self.__rotate__(self.midpoint, angle, center)

        return self

    def reflect(self, p1=(0, 1), p2=(0, 0)):
        """  """
        if issubclass(type(p1), __Port__):
            p1 = p1.midpoint
        if issubclass(type(p2), __Port__):
            p2 = p2.midpoint

        p1 = np.array(p1)
        p2 = np.array(p2)

        # Translate so reflection axis passes through midpoint
        self.midpoint = self.midpoint - p1

        # Rotate so reflection axis aligns with x-axis
        angle = np.arctan2((p2[1] - p1[1]), (p2[0] - p1[0])) * 180 / np.pi
        self.midpoint = self.__rotate__(self.midpoint,
                                        angle=-angle,
                                        center=[0, 0])
        self.rotation -= angle

        # Reflect across x-axis
        self.reflection = not self.reflection
        self.midpoint = [self.midpoint[0], -self.midpoint[1]]
        self.rotation = -self.rotation

        # Un-rotate and un-translate
        self.midpoint = self.__rotate__(self.midpoint,
                                        angle=angle,
                                        center=[0, 0])
        self.rotation += angle
        self.midpoint = self.midpoint + p1

        return self

    def connect(self, port, destination, overlap=0):
        """  """
        if port in self.ports.keys():
            p = self.ports[port]
        elif issubclass(type(port), __Port__):
            p = port
        else:
            raise ValueError(
                "[SPiRA] connect() did not receive a Port or " +
                "valid port name - received ({}), ports available " +
                "are ({})").format(port, self.ports.keys())

        angle = 180 + destination.orientation - p.orientation
        self.rotate(angle=angle, center=p.midpoint)
        self.move(midpoint=p, destination=destination)

        return self

    def stretch(self, port, center=[0, 0], vector=[1, 1]):
        """  """
        from spira.lgm.shape.stretch import Stretch
        self.stretching[port] = Stretch(center=center, vector=vector)
        return self
Esempio n. 21
0
class SubArcSeries(spira.Cell):

    gdslayer = param.LayerField(number=99)
    radius = param.FloatField(default=20)
    #     radius = param.FloatField(default=20 * 1e6)
    width = param.FloatField(default=1.0)
    #     width = param.FloatField(default=1.0 * 1e6)
    angular_coverage = param.FloatField(default=30)
    num_steps = param.IntegerField(default=1)
    angle_resolution = param.FloatField(default=0.1)
    start_angle = param.IntegerField(default=0)

    port1 = param.DataField()
    port2 = param.DataField()

    def _regular_bend(self, prev_port):
        """ Now connect a regular bend for
        the normal curved portion. """
        B = Arc(shape=ArcRoute(radius=self.radius,
                               width=self.width,
                               theta=45 - np.rad2deg(self.angular_coverage),
                               start_angle=self.angular_coverage,
                               angle_resolution=self.angle_resolution,
                               gdslayer=spira.Layer(number=88)))

        b = spira.SRef(B)

        b.connect(port='P1', destination=prev_port)

        p0 = b.ports['P2']

        self.port2 = spira.Term(
            name='P2',
            midpoint=p0.midpoint,
            #             midpoint=scu(p0.midpoint),
            width=p0.width,
            orientation=p0.orientation)

        return b

    def create_elementals(self, elems):

        self.angular_coverage = np.deg2rad(self.angular_coverage)
        inc_rad = (self.radius**-1) / self.num_steps
        angle_step = self.angular_coverage / self.num_steps

        print('inc_rad: {}'.format(inc_rad))
        print('angle_step: {}'.format(angle_step))

        arcs = []
        for x in range(self.num_steps):
            A = Arc(shape=ArcRoute(radius=1 / ((x + 1) * inc_rad),
                                   width=self.width,
                                   theta=np.rad2deg(angle_step),
                                   start_angle=x * np.rad2deg(angle_step),
                                   angle_resolution=self.angle_resolution,
                                   gdslayer=self.gdslayer))

            a = spira.SRef(A)
            elems += a
            arcs.append(a)
            if x > 0:
                a.connect(port='P1', destination=prevPort)
            prevPort = a.ports['P2']

        self.port1 = arcs[0].ports['P1']

        elems += self._regular_bend(prevPort)

        return elems

    def create_ports(self, ports):

        ports += self.port1
        ports += self.port2

        return ports
Esempio n. 22
0
class RouteShape(shapes.Shape):

    port1 = param.DataField()
    port2 = param.DataField()

    num_path_pts = param.IntegerField(default=99)

    path_type = param.StringField(default='sine')
    width_type = param.StringField(default='straight')
    width1 = param.FloatField(default=None)
    width2 = param.FloatField(default=None)

    x_dist = param.FloatField()
    y_dist = param.FloatField()

    def create_points(self, points):

        point_a = np.array(self.port1.midpoint)
        if self.width1 is None:
            self.width1 = self.port1.width
        point_b = np.array(self.port2.midpoint)
        if self.width2 is None:
            self.width2 = self.port2.width
        if round(
                abs(mod(self.port1.orientation - self.port2.orientation, 360)),
                3) != 180:
            raise ValueError('Ports do not face eachother.')
        orientation = self.port1.orientation - 90

        separation = point_b - point_a
        distance = norm(separation)
        rotation = np.arctan2(separation[1], separation[0]) * 180 / pi
        angle = rotation - orientation
        forward_distance = distance * cos(angle * pi / 180)
        lateral_distance = distance * sin(angle * pi / 180)

        xf = forward_distance
        yf = lateral_distance

        self.x_dist = xf
        self.y_dist = yf

        if self.path_type == 'straight':
            curve_fun = lambda t: [xf * t, yf * t]
            curve_deriv_fun = lambda t: [xf + t * 0, 0 + t * 0]
        if self.path_type == 'sine':
            curve_fun = lambda t: [xf * t, yf * (1 - cos(t * pi)) / 2]
            curve_deriv_fun = lambda t: [
                xf + t * 0, yf * (sin(t * pi) * pi) / 2
            ]

        if self.width_type == 'straight':
            width_fun = lambda t: (self.width2 - self.width1) * t + self.width1
        if self.width_type == 'sine':
            width_fun = lambda t: (self.width2 - self.width1) * (1 - cos(
                t * pi)) / 2 + self.width1

        route_path = gdspy.Path(width=self.width1, initial_point=(0, 0))

        route_path.parametric(curve_fun,
                              curve_deriv_fun,
                              number_of_evaluations=self.num_path_pts,
                              max_points=199,
                              final_width=width_fun,
                              final_distance=None)

        points = route_path.polygons

        return points
Esempio n. 23
0
class LabelAbstract(__Label__):

    gdslayer = param.LayerField()
    text = param.StringField()
    str_anchor = param.StringField(default='o')
    rotation = param.FloatField(default=0)
    magnification = param.FloatField(default=1)
    reflection = param.BoolField(default=False)
    texttype = param.IntegerField()
    gdspy_commit = param.BoolField()

    def __init__(self, position, **kwargs):
        super().__init__(position, **kwargs)

    def commit_to_gdspy(self, cell):
        if self.__repr__() not in list(LabelAbstract.__committed__.keys()):
            L = gdspy.Label(self.text,
                deepcopy(self.position),
                anchor='o',
                rotation=self.rotation,
                magnification=self.magnification,
                x_reflection=self.reflection,
                layer=self.gdslayer.number,
                texttype=self.texttype
            )
            cell.add(L)
            LabelAbstract.__committed__.update({self.__repr__():L})
        else:
            cell.add(LabelAbstract.__committed__[self.__repr__()])

    def reflect(self, p1=(0,1), p2=(0,0)):
        self.position = [self.position[0], -self.position[1]]
        self.rotation = self.rotation * (-1)
        self.rotation = np.mod(self.rotation, 360)
        return self

    def rotate(self, angle=45, center=(0,0)):
        self.position = self.__rotate__(self.position, angle=angle, center=[0, 0])
        self.rotation += angle
        self.rotation = np.mod(self.rotation, 360)
        return self

    def point_inside(self, polygon):
        return pyclipper.PointInPolygon(self.position, polygon) != 0

    def transform(self, transform):
        if transform['reflection']:
            self.reflect(p1=[0,0], p2=[1,0])
        if transform['rotation']:
            self.rotate(angle=transform['rotation'])
        if transform['midpoint']:
            self.translate(dx=transform['midpoint'][0], dy=transform['midpoint'][1])
        return self

    def flat_copy(self, level=-1, commit_to_gdspy=False):
        c_label = self.modified_copy(position=self.position)
        if commit_to_gdspy:
            self.gdspy_commit = True
        return c_label

    def move(self, midpoint=(0,0), destination=None, axis=None):
        from spira.gdsii.elemental.port import __Port__

        if destination is None:
            destination = midpoint
            midpoint = [0,0]

        if issubclass(type(midpoint), __Port__):
            o = midpoint.midpoint
        elif np.array(midpoint).size == 2:
            o = midpoint
        elif midpoint in self.ports:
            o = self.ports[midpoint].midpoint
        else:
            raise ValueError("[PHIDL] [DeviceReference.move()] ``midpoint`` " +
                             "not array-like, a port, or port name")

        if issubclass(type(destination), __Port__):
            d = destination.midpoint
        elif np.array(destination).size == 2:
            d = destination
        elif destination in self.ports:
            d = self.ports[destination].midpoint
        else:
            raise ValueError("[PHIDL] [DeviceReference.move()] ``destination`` " +
                             "not array-like, a port, or port name")

        if axis == 'x':
            d = (d[0], o[1])
        if axis == 'y':
            d = (o[0], d[1])

        dx, dy = np.array(d) - o

        super().translate(dx, dy)

        return self
Esempio n. 24
0
 class CellA(spira.Cell):
     layer = param.LayerField(number=18, datatype=1)
     boolean = param.BoolField(default=False)
     fvalue = param.FloatField(default=0.0)
Esempio n. 25
0
class Jtl(spira.Cell):

    m1 = param.MidPointField(default=(0, 0))
    m2 = param.MidPointField(default=(0, 0))
    rotation = param.FloatField(default=0)

    jj1 = param.DataField(fdef_name='create_junction_one')
    jj2 = param.DataField(fdef_name='create_junction_two')
    quadrant = param.DataField(fdef_name='create_quadrant')

    def create_quadrant(self):
        quadrant = None
        if (self.m2[1] > self.m1[1]) and (self.m2[0] > self.m1[0]):
            quadrant = 'Q1'
        if (self.m2[1] > self.m1[1]) and (self.m2[0] < self.m1[0]):
            quadrant = 'Q2'
        if (self.m2[1] < self.m1[1]) and (self.m2[0] < self.m1[0]):
            quadrant = 'Q3'
        if (self.m2[1] < self.m1[1]) and (self.m2[0] > self.m1[0]):
            quadrant = 'Q4'
        return quadrant

    def create_junction_one(self):
        jj = Junction()
        jj.center = (0, 0)
        return spira.SRef(jj, midpoint=self.m1, rotation=self.rotation)

    def create_junction_two(self):
        jj = Junction()
        jj.center = (0, 0)
        return spira.SRef(jj, midpoint=self.m2, rotation=-self.rotation)

    def create_elementals(self, elems):

        s1 = self.jj1
        s2 = self.jj2

        if self.quadrant in ['Q1', 'Q4']:
            route = RouteManhattan(port1=s1.ports['Output'],
                                   port2=s2.ports['Input'],
                                   radius=3,
                                   length=1,
                                   gdslayer=RDD.COU.LAYER)
        if self.quadrant in ['Q2', 'Q3']:
            route = RouteManhattan(port1=s2.ports['Output'],
                                   port2=s1.ports['Input'],
                                   radius=3,
                                   length=1,
                                   gdslayer=RDD.COU.LAYER)

        s3 = spira.SRef(route)
        s3.move(midpoint=s3.ports['T1'], destination=route.port1)

        r1 = Route(port1=self.term_ports['T1'],
                   port2=s1.ports['Input'],
                   player=RDD.PLAYER.COU)
        elems += spira.SRef(r1)

        r2 = Route(port1=self.term_ports['T2'],
                   port2=s2.ports['Output'],
                   player=RDD.PLAYER.COU)
        elems += spira.SRef(r2)

        elems += [s1, s2, s3]

        return elems

    def create_ports(self, ports):

        if self.quadrant in ['Q1', 'Q4']:
            ports += spira.Term(name='T1',
                                midpoint=self.jj1.ports['Input'] + [-10, 0],
                                orientation=-90)
            ports += spira.Term(name='T2',
                                midpoint=self.jj2.ports['Output'] + [10, 0],
                                orientation=90)

        if self.quadrant in ['Q2', 'Q3']:
            ports += spira.Term(name='T1',
                                midpoint=self.jj1.ports['Input'] + [10, 0],
                                orientation=-90)
            ports += spira.Term(name='T2',
                                midpoint=self.jj2.ports['Output'] + [-10, 0],
                                orientation=90)

        return ports
Esempio n. 26
0
class Term(PortAbstract):
    """
    Terminals are horizontal ports that connect SRef instances
    in the horizontal plane. They typically represents the
    i/o ports of a components.

    Examples
    --------
    >>> term = spira.Term()
    """

    width = param.FloatField(default=2)
    length = param.FloatField(default=0.1)

    def __init__(self, port=None, polygon=None, **kwargs):
        super().__init__(port=port, polygon=polygon, **kwargs)

        from spira import shapes
        if polygon is None:
            rect_shape = shapes.RectangleShape(p1=[0, 0],
                                               p2=[self.width, self.length])
            pp = spira.Polygons(shape=rect_shape,
                                gdslayer=spira.Layer(number=65))
            pp.rotate(angle=self.orientation, center=self.midpoint)
            # pp.rotate(angle=90-self.orientation, center=self.midpoint)
            pp.move(midpoint=pp.center, destination=self.midpoint)
            self.polygon = pp
        else:
            self.polygon = polygon

        arrow_shape = shapes.ArrowShape(a=self.width / 10,
                                        b=self.width / 20,
                                        c=self.width / 5)

        arrow_shape.apply_merge
        # arrow_shape.rotate(angle=self.orientation)

        self.arrow = spira.Polygons(shape=arrow_shape,
                                    gdslayer=spira.Layer(number=77))

        self.arrow.rotate(angle=self.orientation)
        # self.arrow.rotate(angle=90-self.orientation)

    def __repr__(self):
        return ("[SPiRA: Term] (name {}, number {}, midpoint {}, " +
                "width {}, orientation {})").format(self.name,
                                                    self.gdslayer.number,
                                                    self.midpoint, self.width,
                                                    self.orientation)

    def _copy(self):
        new_port = Term(parent=self.parent,
                        name=self.name,
                        midpoint=self.midpoint,
                        width=self.width,
                        length=self.length,
                        gdslayer=deepcopy(self.gdslayer),
                        poly_layer=deepcopy(self.poly_layer),
                        text_layer=deepcopy(self.text_layer),
                        orientation=self.orientation)
        return new_port
Esempio n. 27
0
class __Manhattan__(spira.Cell):

    port1 = param.DataField()
    port2 = param.DataField()

    length = param.FloatField(default=20)
    gdslayer = param.LayerField(number=13)
    radius = param.IntegerField(default=1)
    bend_type = param.StringField(default='circular')

    b1 = param.DataField(fdef_name='create_arc_bend_1')
    b2 = param.DataField(fdef_name='create_arc_bend_2')

    p1 = param.DataField(fdef_name='create_port1_position')
    p2 = param.DataField(fdef_name='create_port2_position')

    quadrant_one = param.DataField(fdef_name='create_quadrant_one')
    quadrant_two = param.DataField(fdef_name='create_quadrant_two')
    quadrant_three = param.DataField(fdef_name='create_quadrant_three')
    quadrant_four = param.DataField(fdef_name='create_quadrant_four')

    def _generate_route(self, p1, p2):
        route = RouteShape(port1=p1,
                           port2=p2,
                           path_type='straight',
                           width_type='straight')
        R1 = RouteBasic(route=route, connect_layer=self.gdslayer)
        r1 = spira.SRef(R1)
        r1.rotate(angle=p2.orientation - 180, center=R1.port1.midpoint)
        r1.move(midpoint=(0, 0), destination=p1.midpoint)
        return r1

    def create_port1_position(self):
        p1 = [self.port1.midpoint[0], self.port1.midpoint[1]]
        if self.port1.orientation == 90:
            p1 = [self.port1.midpoint[1], -self.port1.midpoint[0]]
        if self.port1.orientation == 180:
            p1 = [-self.port1.midpoint[0], -self.port1.midpoint[1]]
        if self.port1.orientation == 270:
            p1 = [-self.port1.midpoint[1], self.port1.midpoint[0]]
        return p1

    def create_port2_position(self):
        p2 = [self.port2.midpoint[0], self.port2.midpoint[1]]
        if self.port1.orientation == 90:
            p2 = [self.port2.midpoint[1], -self.port2.midpoint[0]]
        if self.port1.orientation == 180:
            p2 = [-self.port2.midpoint[0], -self.port2.midpoint[1]]
        if self.port1.orientation == 270:
            p2 = [-self.port2.midpoint[1], self.port2.midpoint[0]]
        return p2

    def create_arc_bend_1(self):
        if self.bend_type == 'circular':
            B1 = Arc(shape=ArcRoute(
                radius=self.radius,
                width=self.port1.width,
                gdslayer=self.gdslayer,
                # gdslayer=spira.Layer(number=18),
                start_angle=0,
                theta=90))
            return spira.SRef(B1)

    def create_arc_bend_2(self):
        if self.bend_type == 'circular':
            B2 = Arc(shape=ArcRoute(
                radius=self.radius,
                width=self.port1.width,
                gdslayer=self.gdslayer,
                # gdslayer=spira.Layer(number=18),
                start_angle=0,
                theta=-90))
            return spira.SRef(B2)
Esempio n. 28
0
class Surround(__DoubleLayerDesignRule__):
    minimum = param.FloatField()
    error = param.IntegerField(default=RDD.PURPOSE.ERROR.SPACING.datatype)

    def __repr__(self):
        return 'Rule surround: min={}'.format(self.minimum)

    def apply(self, elems):

        pos_elems = spira.ElementList()
        neg_elems = spira.ElementList()

        # print(elems)

        for C in elems.dependencies():
            for S in C.elementals.sref:
                if S.ref.layer.number == self.layer1.number:
                    pos_elems = S.ref.elementals
                    C1 = S.ref

                    for C in elems.dependencies():
                        for S in C.elementals.sref:
                            if S.ref.layer.number == self.layer2.number:
                                neg_elems = S.ref.elementals
                                C2 = S.ref

                                fails = False

                                if pos_elems and neg_elems:
                                    P = pos_elems[0]
                                    M = neg_elems[0]

                                    space = self.minimum * 1.0e+6

                                    x1 = abs(P.xmax - P.center[0])
                                    sx = (x1 + space) / x1

                                    p_copy = deepcopy(P)

                                    p_scale = p_copy.scale(scalex=sx,
                                                           scaley=sx,
                                                           center=P.center)

                                    p_overlap = p_scale | M
                                    # print(M)

                                    if p_overlap:
                                        a1 = round(p_scale.ply_area * 10e-9)
                                        a2 = round(p_overlap.ply_area * 10e-9)

                                        if abs(a1 - a2) > 1e-9:
                                            fails = True

                                            P_error = ELayer(
                                                points=P.polygons,
                                                number=C1.layer.number,
                                                error_type=self.error)
                                            C1 += SRef(P_error)

                                            M_error = ELayer(
                                                points=M.polygons,
                                                number=C2.layer.number,
                                                error_type=self.error)
                                            C2 += SRef(M_error)

                                            print(
                                                '\n ------ Surround Rules ------'
                                            )
                                            print(self.layer1)
                                            print('Surround ({}): {}'.format(
                                                'fail', self.minimum))
                                        else:
                                            fails = False
                                            print(
                                                '\n ------ Surround Rules ------'
                                            )
                                            print(self.layer1)
                                            print('Surround ({}): {}'.format(
                                                'pass', self.minimum))

                                return fails