Beispiel #1
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
Beispiel #2
0
class Density(__DoubleLayerDesignRule__):
    minimum = param.IntegerField()
    error = param.IntegerField(default=RDD.PURPOSE.ERROR.DENSITY.datatype)

    # TODO: Detect holes in die polygon

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

    def get_layer_area(self, elems):
        area = 0.0
        for e in elems:
            area += e.ply_area
        return area

    def apply(self, elems):

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

        for C in elems.dependencies():
            if C.layer.number == self.layer1.number:
                pos_elems = C.elementals
            elif C.layer.number == self.layer2.number:
                neg_elems = C.elementals

        fails = False

        Ap = self.get_layer_area(pos_elems)
        An = self.get_layer_area(neg_elems)

        if (Ap > 0) and (An > 0):
            presentage = 100 - (An / Ap) * 100

            if presentage < self.minimum:
                fails = True
                print('\n ------ Design Rules ------')
                print(self.layer1)
                message = '[DRC: Density ({})]: (layer1 {}, layer2 {}, extracted_value {}%, rule_value {}%)'.format(
                    'fail', self.layer1.number, self.layer2.number,
                    int(round(presentage)), self.min)
                raise ValueError(message)
            else:
                fails = False
                print('\n ------ Design Rules ------')
                print(self.layer1)
                print('Density ({}): {}%'.format('pass',
                                                 int(round(presentage))))

        return fails
Beispiel #3
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
Beispiel #4
0
class __ProcessLayer__(Cell):
    doc = param.StringField()
    points = param.ElementListField()
    # points = param.PointArrayField()
    number = param.IntegerField()
    error_type = param.IntegerField()

    layer = param.DataField(fdef_name='create_layer')
    player = param.DataField(fdef_name='create_polygon_layer')

    def create_polygon_layer(self):
        return Polygons(shape=self.points, gdslayer=self.layer)

    def create_layer(self):
        return Layer(name=self.name, number=self.number, datatype=self.error_type)

    def create_elementals(self, elems):
        elems += self.player
        return elems
Beispiel #5
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
Beispiel #6
0
class PurposeLayer(__Layer__):

    doc = param.StringField()
    name = param.StringField()
    datatype = param.IntegerField()
    symbol = param.StringField()

    def __init__(self, **kwargs):
        ElementalInitializer.__init__(self, **kwargs)

    # def __repr__(self):
    #     string = '[SPiRA: PurposeLayer] (\'{}\', datatype {}, symbol \'{}\')'
    #     return string.format(self.name, self.datatype, self.symbol)

    def __eq__(self, other):
        if isinstance(other, PurposeLayer):
            return self.key == other.key
        else:
            raise ValueError('Not Implemented!')

    def __ne__(self, other):
        if isinstance(other, PurposeLayer):
            return self.key != other.key
        else:
            raise ValueError('Not Implemented!')

    def __add__(self, other):
        if isinstance(other, PurposeLayer):
            d = self.datatype + other.datatype
        elif isinstance(other, int):
            d = self.datatype + other
        else:
            raise ValueError('Not Implemented')
        return PurposeLayer(datatype=d)

    def __iadd__(self, other):
        if isinstance(other, PurposeLayer):
            self.datatype += other.datatype
        elif isinstance(other, int):
            self.datatype += other
        else:
            raise ValueError('Not Implemented')
        return self

    def __deepcopy__(self, memo):
        return PurposeLayer(
            name=self.name,
            datatype=self.datatype,
            symbol=self.symbol
        )

    @property
    def key(self):
        return (self.datatype, self.symbol)
Beispiel #7
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
Beispiel #8
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
Beispiel #9
0
class ComposeNLayer(ComposeMLayers):
    """
    Decorates all elementas with purpose via with
    LCells and add them as elementals to the new class.
    """

    cell_elems = param.ElementListField()

    level = param.IntegerField(default=1)

    nlayers = param.DataField(fdef_name='create_nlayers')

    def create_nlayers(self):
        elems = ElementList()
        flat_elems = self.cell_elems.flat_copy()
        for pl in RDD.PLAYER.get_physical_layers(purposes='VIA'):

            via_elems = flat_elems.get_polygons(layer=pl.layer)

            if via_elems:
                c_nlayer = CNLayers(layer=pl.layer)
                for i, ply in enumerate(via_elems):
                    ml = NLayer(name='Via_NLayer_{}_{}_{}'.format(
                        pl.layer.number, self.cell.name, i),
                                points=ply.polygons,
                                midpoint=ply.center,
                                number=pl.layer.number)
                    c_nlayer += spira.SRef(ml)
                elems += SRef(c_nlayer)

        return elems

    def create_elementals(self, elems):

        super().create_elementals(elems)

        # Only add it if its a Device.
        if self.level == 1:
            for lcell in self.nlayers:
                elems += lcell

        return elems
Beispiel #10
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__()
Beispiel #11
0
class GeometryAbstract(__Geometry__):

    _ID = 0

    name = param.StringField()
    layer = param.IntegerField()
    dimension = param.IntegerField(default=2)
    algorithm = param.IntegerField(default=6)
    polygons = param.ElementListField()
    # gmsh_elements = param.ElementListField()

    create_mesh = param.DataField(fdef_name='create_meshio')
    elements = param.DataField(fdef_name='create_pygmsh_elements')

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

    def create_meshio(self):
        """
        Generates a GMSH mesh, which is saved in the `debug` folder.

        Arguments
        ---------
        mesh : dict
            Dictionary containing all the necessary mesh information.
        """

        if len(self.__surfaces__()) > 1:
            self.geom.boolean_union(self.__surfaces__())

        directory = os.getcwd() + '/debug/gmsh/'
        mesh_file = '{}{}.msh'.format(directory, self.name)
        geo_file = '{}{}.geo'.format(directory, self.name)
        vtk_file = '{}{}.vtu'.format(directory, self.name)

        if not os.path.exists(directory):
            os.makedirs(directory)

        mesh_data = pygmsh.generate_mesh(self.geom,
                                         verbose=False,
                                         dim=self.dimension,
                                         prune_vertices=False,
                                         remove_faces=False,
                                         geo_filename=geo_file)

        mm = meshio.Mesh(*mesh_data)

        meshio.write(mesh_file, mm)
        meshio.write(vtk_file, mm)

        # params = {
        #     'name': self.name,
        #     'layer': spira.Layer(number=self.layer),
        #     'points': [mesh_data[0]],
        #     'cells': [mesh_data[1]],
        #     'point_data': [mesh_data[2]],
        #     'cell_data': [mesh_data[3]],
        #     'field_data': [mesh_data[4]]
        # }

        # return params

        return mesh_data

    def create_pygmsh_elements(self):
        print('number of polygons {}'.format(len(self.polygons)))

        height = 0.0
        holes = None

        elems = ElementList()
        for ply in self.polygons:
            for i, points in enumerate(ply.polygons):
                pp = numpy_to_list(points, height, unit=10e-9)
                surface_label = '{}_{}_{}_{}'.format(ply.gdslayer.number,
                                                     ply.gdslayer.datatype,
                                                     GeometryAbstract._ID, i)
                gp = self.geom.add_polygon(pp,
                                           lcar=1.0,
                                           make_surface=True,
                                           holes=holes)
                self.geom.add_physical_surface(gp.surface, label=surface_label)
                elems += [gp.surface, gp.line_loop]
                GeometryAbstract._ID += 1

        return elems

    def extrude_surfaces(self, geom, surfaces):
        """ This extrudes the surface to a 3d volume element. """

        for i, surface in enumerate(surfaces):
            width = float(self.width) * scale

            ex = self.geom.extrude(surface, [0, 0, width])

            unique_id = '{}_{}'.format(polygons._id, i)

            volume = self.geom.add_physical_volume(ex[1], unique_id)

            self.extrude.append(ex[1])
            self.volume.append(volume)

    def geom_holes(self):
        """
        Create a list of gmsh surfaces from the mask polygons
        generated by the gdsii package.

        Arguments
        ---------
        surfaces : list
            list of pygmsh surface objects.
        """

        print('number of polygons {}'.format(len(self.e.polygons)))

        dim = 2
        height = 0.0
        material_stack = None

        for i, points in enumerate(self.e.polygons):
            if dim == 3:
                height = self.vertical_position(material_stack)

            pp = numpy_to_list(points, height, unit=self.e.unit)

            gp = geom.add_polygon(pp, lcar=1.0, make_surface=true)

            line_loops.append(gp.line_loop)

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

    def flatten(self):
        return [self]

    def commit_to_gdspy(self, cell):
        pass

    def transform(self, transform):
        return self
Beispiel #12
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
Beispiel #13
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
Beispiel #14
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
Beispiel #15
0
class PortAbstract(__Port__):

    name = param.StringField()
    midpoint = param.MidPointField()
    orientation = param.IntegerField()
    parent = param.DataField()
    gdslayer = param.LayerField(name='PortLayer', number=64)
    poly_layer = param.LayerField(name='PortLayer', number=64)
    text_layer = param.LayerField(name='PortLayer', number=63)

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

        self.orientation = np.mod(self.orientation, 360)

        L = spira.Label(position=self.midpoint,
                        text=self.name,
                        gdslayer=self.gdslayer,
                        texttype=self.text_layer.number)
        self.label = L
        self.arrow = None

    @property
    def endpoints(self):
        dx = self.width / 2 * np.cos((self.orientation - 90) * np.pi / 180)
        dy = self.width / 2 * np.sin((self.orientation - 90) * np.pi / 180)
        left_point = self.midpoint - np.array([dx, dy])
        right_point = self.midpoint + np.array([dx, dy])
        return np.array([left_point, right_point])

    @endpoints.setter
    def endpoints(self, points):
        p1, p2 = np.array(points[0]), np.array(points[1])
        self.midpoint = (p1 + p2) / 2
        dx, dy = p2 - p1
        self.orientation = np.arctan2(dx, dy) * 180 / np.pi
        self.width = np.sqrt(dx**2 + dy**2)

    @property
    def normal(self):
        dx = np.cos((self.orientation) * np.pi / 180)
        dy = np.sin((self.orientation) * np.pi / 180)
        return np.array([self.midpoint, self.midpoint + np.array([dx, dy])])

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

    def flat_copy(self, level=-1, commit_to_gdspy=False):
        c_port = self.modified_copy(midpoint=self.midpoint)
        if commit_to_gdspy:
            self.gdspy_write = True
        return c_port

    def commit_to_gdspy(self, cell):
        if self.__repr__() not in list(__Port__.__committed__.keys()):
            # self.polygon.rotate(angle=self.orientation)
            # self.polygon.move(midpoint=self.polygon.center, destination=self.midpoint)
            self.polygon.commit_to_gdspy(cell)
            self.label.commit_to_gdspy(cell)
            if self.arrow:
                # print(self.orientation)
                # self.arrow.rotate(angle=45)
                # self.arrow.rotate(angle=90)
                # self.arrow.rotate(angle=90-self.orientation)
                self.arrow.move(midpoint=self.arrow.center,
                                destination=self.midpoint)
                self.arrow.commit_to_gdspy(cell)
            __Port__.__committed__.update({self.__repr__(): self})

    def reflect(self):
        """ Reflect around the x-axis. """
        self.midpoint = [self.midpoint[0], -self.midpoint[1]]
        self.orientation = -self.orientation
        self.orientation = np.mod(self.orientation, 360)

        self.polygon.reflect()

        if self.arrow:
            self.arrow.reflect()

        return self

    def rotate(self, angle=45, center=(0, 0)):
        """ Rotate port around the center with angle. """
        self.midpoint = self.__rotate__(self.midpoint,
                                        angle=angle,
                                        center=center)
        self.orientation += angle
        self.orientation = np.mod(self.orientation, 360)

        self.polygon.rotate(angle=self.orientation)

        if self.arrow:
            # self.arrow.rotate(angle=angle)
            self.arrow.rotate(angle=np.mod(angle, 90))

        return self

    def translate(self, dx, dy):
        """ Translate port by dx and dy. """
        self.midpoint = self.midpoint + np.array([dx, dy])
        return self

    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

        self.translate(dx, dy)

        self.label.move(midpoint=self.label.position,
                        destination=self.midpoint)
        self.polygon.move(midpoint=self.polygon.center,
                          destination=self.midpoint)
        if self.arrow:
            self.arrow.move(midpoint=self.polygon.center,
                            destination=self.midpoint)

        return self

    def stretch(self, stretch_class):
        """ Stretch port by with the given stretch class. """
        p = stretch_class.apply(self.midpoint)
        self.midpoint = p
        return self

    def transform(self, T):
        """ Transform port with the given transform class. """
        if T['reflection']:
            self.reflect()
            self.label.reflect()
            self.polygon.reflect()
            if self.arrow:
                self.arrow.reflect()
        if T['rotation']:
            self.rotate(angle=T['rotation'], center=(0, 0))
            self.label.rotate(angle=T['rotation'])
            self.polygon.rotate(angle=T['rotation'])
            if self.arrow:
                self.arrow.rotate(angle=T['rotation'])
        if T['midpoint']:
            self.translate(dx=T['midpoint'][0], dy=T['midpoint'][1])
            self.label.move(midpoint=self.label.position,
                            destination=self.midpoint)
            self.polygon.move(midpoint=self.polygon.center,
                              destination=self.midpoint)
            if self.arrow:
                self.arrow.move(midpoint=self.polygon.center,
                                destination=self.midpoint)

        return self

    def _update(self, name, layer):
        ll = deepcopy(layer)
        ll.datatype = 65
        self.polygon.gdslayer = ll
        self.label.gdslayer = ll
Beispiel #16
0
class __StructureCell__(ConnectDesignRules):
    """
    Add a GROUND bbox to Device for primitive and
    DRC detection, since GROUND is only in Mask Cell.
    """

    level = param.IntegerField(default=1)

    device_elems = param.ElementListField()

    devices = param.DataField(fdef_name='create_device_layers')
    terminals = param.DataField(fdef_name='create_terminal_layers')

    def create_device_layers(self):
        box = self.cell.bbox
        box.move(midpoint=box.center, destination=(0, 0))

        B = DLayer(blayer=box, device_elems=self.cell.elementals)
        Bs = SRef(B)
        Bs.move(midpoint=(0, 0), destination=self.cell.bbox.center)

        return Bs

    def create_terminal_layers(self):
        #         flat_elems = self.cell_elems.flat_copy()
        #         port_elems = flat_elems.get_polygons(layer=RDD.PURPOSE.TERM)
        #         label_elems = flat_elems.labels
        #
        #         elems = ElementList()
        #         for port in port_elems:
        #             for label in label_elems:
        #
        #                 lbls = label.text.split(' ')
        #                 s_p1, s_p2 = lbls[1], lbls[2]
        #                 p1, p2 = None, None
        #
        #                 if s_p1 in RDD.METALS.keys:
        #                     layer = RDD.METALS[s_p1].LAYER
        #                     p1 = spira.Layer(name=lbls[0], number=layer, datatype=RDD.GDSII.TEXT)
        #
        #                 if s_p2 in RDD.METALS.keys:
        #                     layer = RDD.METALS[s_p2].LAYER
        #                     p2 = spira.Layer(name=lbls[0], number=layer, datatype=RDD.GDSII.TEXT)
        #
        #                 if p1 and p2:
        #                     if label.point_inside(polygon=port.polygons[0]):
        #                         term = TLayer(points=port.polygons,
        #                                     layer1=p1,
        #                                     layer2=p2,
        #                                     number=RDD.GDSII.TERM,
        #                                     midpoint=label.position)
        #
        #                         term.ports[0].name = 'P1_{}'.format(label.text)
        #                         term.ports[1].name = 'P2_{}'.format(label.text)
        #
        #                         elems += SRef(term)

        elems = ElementList()

        for p in self.cell.ports:
            if isinstance(p, spira.Term):
                term = TLayer(
                    points=p.polygon.polygons,
                    #                               layer1=p1,
                    #                               layer2=p2,
                    number=RDD.PURPOSE.TERM.datatype,
                    midpoint=p.label.position)

                term.ports[0].name = 'P1_{}'.format(1)
                term.ports[1].name = 'P2_{}'.format(2)

                elems += SRef(term)
        return elems

    def create_elementals(self, elems):

        super().create_elementals(elems)

        #         elems += self.devices

        # for term in self.terminals:
        #     elems += term

        return elems

    def create_ports(self, ports):

        #         for t in self.cell.terms:
        #             ports += t

        return ports
Beispiel #17
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
Beispiel #18
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)
Beispiel #19
0
class __Generator__(__CellContainer__):

    level = param.IntegerField(default=1)
    lcar = param.IntegerField(default=0.01)
    algorithm = param.IntegerField(default=6)

    generate_devices = param.DataField(fdef_name='create_devices')

    def create_graph(self, elems):

        prim_elems = ElementList()
        for S in elems.sref:
            if isinstance(S.ref, (NLayer, TLayer, DLayer)):
                prim_elems += S

        for layer in RDD.METALS.layers:
            L = Cell(name='{}'.format(layer))

            # ply_elems = D.get_mlayers(layer=layer)

            ply_elems = ElementList()
            for S in elems.sref:
                if isinstance(S.ref, CMLayers):
                    # print(S.ref.layer)
                    if S.ref.layer.number == layer:
                        # print(S)
                        for p in S.ref.elementals:
                            # print(p.ref.player)
                            # FIXME!!!
                            # if isinstance(p, ELayers):
                            # raise Errors
                            if isinstance(p.ref.player, Polygons):
                                ply_elems += p.ref.player

            if ply_elems:
                geom = Geometry(name='{}'.format(layer),
                                lcar=self.lcar,
                                algorithm=self.algorithm,
                                layer=layer,
                                polygons=ply_elems)

                mesh_data = geom.create_mesh

                params = {
                    'name': '{}'.format(layer),
                    'layer': Layer(number=layer),
                    'point_data': [mesh_data[2]],
                    'cell_data': [mesh_data[3]],
                    'field_data': [mesh_data[4]]
                }

                mesh = Mesh(polygons=ply_elems,
                            primitives=prim_elems,
                            points=mesh_data[0],
                            cells=mesh_data[1],
                            **params)

                L += mesh
                elems += SRef(L)

                sg = {}
                subgraphs = elems.subgraphs
                for name, g in subgraphs.items():
                    graph = Graph(subgraphs={name: g})
                    sg[name] = graph.g
                ng = Graph(subgraphs=sg)
                ng.write_graph(graphname='{}'.format(layer))
                elems += ng

    def wrap_references(self, c, c2dmap):
        from spira.gdsii.utils import scale_coord_down as scd
        for e in c.elementals:
            if isinstance(e, SRef):
                if e.ref in c2dmap:
                    e.ref = c2dmap[e.ref]

    def create_devices(self):
        deps = self.cell.dependencies()
        c2dmap = {}
        # for DeviceTCell in self.library.pcells:
        # print(RDD.DEVICES.JJ.PCELL)
        # for DeviceTCell in RDD.DEVICES.JJ.PCELL:
        #     print(type(DeviceTCell))
        #     for C in deps:

        #         plane_elems = ElementList()
        #         plane_elems += self.cell.get_purpose_layers(purpose_symbol='GROUND')
        #         # plane_elems += self.cell.elementals[(RDD.GDSII.GPLAYER, 0)]

        #         D = Device(cell=C, cell_elems=C.elementals, plane_elems=plane_elems)

        #         for PrimTCell in DeviceTCell.elementals.sref:
        #             PrimTCell.ref.create_elementals(D.elementals)
        #         c2dmap.update({C: D})

        for key in RDD.DEVICES.keys:
            DeviceTCell = RDD.DEVICES[key].PCELL
            for C in deps:

                plane_elems = ElementList()
                # from spira.gdsii import utils
                # players = RDD.PLAYER.get_physical_layers(purposes='GROUND')
                # plane_elems += utils.get_purpose_layers(self.cell, players)
                # # plane_elems += self.cell.elementals[(RDD.GDSII.GPLAYER, 0)]

                D = Device(cell=C,
                           cell_elems=C.elementals,
                           plane_elems=plane_elems)

                for PrimTCell in DeviceTCell.elementals.sref:
                    PrimTCell.ref.create_elementals(D.elementals)
                c2dmap.update({C: D})

        for c in self.cell.dependencies():
            self.wrap_references(c, c2dmap)

        return SRef(self.cell)