예제 #1
0
class __ConnectLayer__(__ProcessLayer__):

    midpoint = param.MidPointField()

    layer1 = param.LayerField()
    layer2 = param.LayerField()

    port1 = param.DataField(fdef_name='create_port1')
    port2 = param.DataField(fdef_name='create_port2')

    def create_port1(self):
        port = Port(name='P1', midpoint=self.midpoint, gdslayer=self.layer1)
        return port

    def create_port2(self):
        port = Port(name='P2', midpoint=self.midpoint, gdslayer=self.layer2)
        return port

    def create_ports(self, ports):
        ports += self.port1
        ports += self.port2
        return ports

    def create_elementals(self, elems):
        super().create_elementals(elems)
        return elems
예제 #2
0
파일: basic.py 프로젝트: cloudcalvin/spira
class Route(spira.Cell):

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

    def validate_parameters(self):
        if self.port1.width < self.player.data.WIDTH:
            return False
        if self.port2.width < self.player.data.WIDTH:
            return False
        return True

    def create_elementals(self, elems):

        route = RouteShape(port1=self.port1,
                           port2=self.port2,
                           path_type='straight',
                           width_type='straight')

        R1 = RouteBasic(route=route, connect_layer=self.player.layer)
        r1 = spira.SRef(R1)
        r1.rotate(angle=self.port2.orientation - 180, center=R1.port1.midpoint)
        r1.move(midpoint=(0, 0), destination=self.port1.midpoint)

        elems += r1

        return elems
예제 #3
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()
예제 #4
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
예제 #5
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
예제 #6
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
예제 #7
0
파일: basic.py 프로젝트: cloudcalvin/spira
class RouteBasic(spira.Cell):

    route = param.ShapeField()
    connect_layer = param.LayerField(
        doc='GDSII layer to which the route connects.')

    port1 = param.DataField(fdef_name='create_port1')
    port2 = param.DataField(fdef_name='create_port2')
    llayer = param.DataField(fdef_name='create_layer')

    def create_layer(self):
        ll = spira.Layer(number=self.connect_layer.number,
                         datatype=RDD.PURPOSE.TERM.datatype)
        return ll

    def create_elementals(self, elems):
        ply = spira.Polygons(shape=self.route, gdslayer=self.connect_layer)
        ply.rotate(angle=-90)
        elems += ply
        return elems

    def create_port1(self):
        term = spira.Term(name='TERM1',
                          midpoint=(0, 0),
                          width=self.route.width1,
                          length=0.2,
                          orientation=180,
                          gdslayer=self.llayer)
        term.rotate(angle=-90)
        return term

    def create_port2(self):
        term = spira.Term(name='TERM2',
                          midpoint=[self.route.x_dist, self.route.y_dist],
                          width=self.route.width2,
                          length=0.2,
                          orientation=0,
                          gdslayer=self.llayer)
        term.rotate(angle=-90)
        return term

    def create_ports(self, ports):

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

        return ports
예제 #8
0
class DLayer(__DeviceLayer__):

    blayer = param.PolygonField()
    device_elems = param.ElementListField()
    box = param.DataField(fdef_name='create_box_layer')
    terms = param.DataField(fdef_name='create_labels')

    color = param.ColorField(default='#e54e7f')

    def create_labels(self):
        elems = ElementList()
        for p in self.device_elems.polygons:
            layer = p.gdslayer.number
            players = RDD.PLAYER.get_physical_layers(purposes='METAL')
            if layer in players:
                l2 = Layer(name='BoundingBox', number=layer, datatype=8)
                # FIXME: Ports with the same name overrides eachother.
                elems += Port(name='P{}'.format(layer), midpoint=self.blayer.center, gdslayer=l2)
        return elems

    def create_box_layer(self):
        elems = ElementList()
        setter = {}

        for p in self.device_elems.polygons:
            layer = p.gdslayer.number
            setter[layer] = 'not_set'

        for p in self.device_elems.polygons:
            layer = p.gdslayer.number
            players = RDD.PLAYER.get_physical_layers(purposes=['METAL'])
            if layer in players and setter[layer] == 'not_set':
                l1 = Layer(name='BoundingBox', number=layer, datatype=8)
                elems += Polygons(polygons=self.blayer.polygons, gdslayer=l1)
                setter[layer] = 'already_set'
        return elems

    def create_elementals(self, elems):

        elems += self.box
        elems += self.terms

        elems = elems.flatten()

        return elems
예제 #9
0
class CircuitGenerator(GateGenerator):

    structure_circuit = param.DataField(fdef_name='create_structure_circuit')

    def create_structure_circuit(self):
        self.structure_gate

        mask = Circuit(cell=self.cell, cell_elems=self.cell.elementals)
        return SRef(mask)
예제 #10
0
class ComposeMLayers(__CellContainer__):
    """
    Decorates all elementals with purpose metal with
    LCells and add them as elementals to the new class.
    """

    cell_elems = param.ElementListField()

    mlayers = param.DataField(fdef_name='create_mlayers')

    def _merge_layers(self, flat_metals):
        points = []
        elems = spira.ElementList()
        for p in flat_metals:
            for pp in p.polygons:
                points.append(pp)
        if points:
            from spira.gdsii.utils import scale_polygon_down as spd
            points = spd(points)
            shape = shapes.Shape(points=points)
            shape.apply_merge
            for pts in shape.points:
                pts = spd([pts])
                elems += spira.Polygons(shape=pts)
        return elems

    def create_mlayers(self):
        elems = spira.ElementList()
        # players = RDD.PLAYER.get_physical_layers(purpose_symbol=['METAL', 'GROUND', 'MOAT'])
        flat_elems = self.cell_elems.flat_copy()
        for pl in RDD.PLAYER.get_physical_layers(purposes='METAL'):

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

            if metal_elems:
                c_mlayer = CMLayers(layer=pl.layer)
                for i, ply in enumerate(self._merge_layers(metal_elems)):
                    ml = MLayer(name='MLayer_{}_{}_{}_{}'.format(
                        pl.layer.number, self.cell.name, self.cell.id, i),
                                points=ply.polygons,
                                number=pl.layer.number)
                    c_mlayer += spira.SRef(ml)
                elems += spira.SRef(c_mlayer)
        return elems

    def create_elementals(self, elems):

        # TODO: Apply DRC checking between metals, before being placed.

        for lcell in self.mlayers:
            elems += lcell

        # FIXME: Allow this operation.
        # elems += self.mlayers

        return elems
예제 #11
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
예제 #12
0
class Route(__Path__):

    ports = param.ElementListField(fdef_name='create_ports')
    # ports = param.PortListField(fdef_name='create_ports')

    input_term = param.DataField(fdef_name='create_port_input')
    output_term = param.DataField(fdef_name='create_port_output')

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

    def create_port_input(self):
        return None

    def create_port_output(self):
        return None

    def create_ports(self, ports):
        return ports
예제 #13
0
class Junction(spira.Cell):
    """ Josephson Junction component for the AIST process. """

    metals = param.DataField(fdef_name='create_metal_layers')
    contacts = param.DataField(fdef_name='create_contact_layers')

    def create_metal_layers(self):
        metals = spira.ElementList()
        metals += ply.Box(player=RDD.PLAYER.COU, center=(1.95, 5.76), w=1.9, h=6.7)
        metals += ply.Box(player=RDD.PLAYER.BAS, center=(1.95, 2.6), w=3.9, h=5.2)
        metals += ply.Box(player=RDD.PLAYER.BAS, center=(1.95, 7.7), w=1.9, h=2.8)
        metals += ply.Box(player=RDD.PLAYER.RES, center=(1.95, 7.2), w=1.5, h=1.5)
        metals += ply.Box(player=RDD.PLAYER.RES, center=(1.95, 5.76), w=1.5, h=2.0)
        metals += ply.Box(player=RDD.PLAYER.RES, center=(1.95, 3.55), w=3.4, h=2.8)
        return metals

    def create_contact_layers(self):
        elems = spira.ElementList()
        elems += ply.Box(player=RDD.PLAYER.GC, center=(1.95, 1.1), w=2.9, h=1.2)
        elems += ply.Box(player=RDD.PLAYER.BC, center=(1.95, 8.5), w=1.4, h=1.0)
        elems += ply.Box(player=RDD.PLAYER.RC, center=(1.95, 7.2), w=0.9, h=1.0)
        elems += ply.Box(player=RDD.PLAYER.RC, center=(1.95, 3.55), w=2.9, h=2.3)
        elems += ply.Box(player=RDD.PLAYER.JC, center=(1.95, 3.55), w=1.4, h=1.0)
        elems += ply.Box(player=RDD.PLAYER.JJ, center=(1.95, 3.55), w=1.9, h=1.3)
        return elems

    def create_elementals(self, elems):
        for e in self.metals:
            elems += e
        for e in self.contacts:
            elems += e

        for key in RDD.VIAS.keys:
            RDD.VIAS[key].PCELL.create_elementals(elems)

        return elems

    def create_ports(self, ports):
        ports += spira.Term(name='Input', midpoint=(0.25, 3.5), orientation=90, width=2)
        ports += spira.Term(name='Output', midpoint=(3.6, 3.5), orientation=-90)
        return ports
예제 #14
0
class MaskGenerator(CircuitGenerator):

    structure_mask = param.DataField(fdef_name='create_structure_mask')

    def create_structure_mask(self):
        self.structure_circuit

        mask = Mask(cell=self.cell, cell_elems=self.cell.elementals)
        return SRef(mask)

    def create_elementals(self, elems):
        return elems
예제 #15
0
class GLayer(__ProcessLayer__):
    """ Ground Plane layer. """

    blayer = param.PolygonField()
    device_elems = param.ElementListField()
    box = param.DataField(fdef_name='create_box_layer')
    terms = param.DataField(fdef_name='create_labels')

    def create_labels(self):
        elems = ElementList()
        for p in self.device_elems.polygons:
            layer = p.gdslayer.number
            # if layer in RDD.GROUND.layers:
            if layer == RDD.GDSII.GPLAYER:
                l2 = Layer(name='BoundingBox', number=layer, datatype=5)
                elems += Port(name='P{}'.format(layer), midpoint=self.blayer.center, gdslayer=l2)
        return elems

    def create_box_layer(self):
        elems = ElementList()
        for p in self.device_elems.polygons:
            layer = p.gdslayer.number
            # if layer in RDD.GROUND.layers:
            if layer == RDD.GDSII.GPLAYER:
                l1 = Layer(name='BoundingBox', number=layer, datatype=5)
                elems += Polygons(polygons=self.blayer.polygons, gdslayer=l1)
        return elems

    def create_elementals(self, elems):

        super().create_elementals(elems)

        # elems += self.box
        # elems += self.terms
        #
        # elems = elems.flatten()

        return elems
예제 #16
0
class GateGenerator(__Generator__):
    """
    Connect to the current library and get the
    primitive metadata from the Rule Deck.
    The pcell device is updated after parsing the
    elementals in the via pcell class.
    """

    structure_gate = param.DataField(fdef_name='create_structure_gate')

    def create_structure_gate(self):
        self.generate_devices

        self.cell.name += 'gate'

        mask = Gate(cell=self.cell, cell_elems=self.cell.elementals)
        return SRef(mask)
예제 #17
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
예제 #18
0
class ComposeGLayer(ComposeNLayer):

    plane_elems = param.ElementListField(
    )  # Elementals like skyplanes and groundplanes.
    ground_layer = param.DataField(fdef_name='create_merged_ground_layers')

    def create_merged_ground_layers(self):
        points = []
        for p in self.plane_elems.flat_copy():
            for pp in p.polygons:
                points.append(pp)
        if points:
            ll = Layer(number=RDD.GDSII.GPLAYER, datatype=6)
            merged_ply = UnionPolygons(polygons=points, gdslayer=ll)
            return merged_ply
        return None

    def create_elementals(self, elems):

        super().create_elementals(elems)

        if self.level == 1:
            if self.ground_layer:
                box = self.cell.bbox
                # box.move(midpoint=box.center, destination=(0,0))

                gnd = self.ground_layer | box
                if gnd:
                    c_glayer = CGLayers(layer=gnd.gdslayer)
                    name = 'GLayer_{}_{}'.format(self.cell.name,
                                                 gnd.gdslayer.number)
                    gnd_layer = GLayer(name=name,
                                       layer=gnd.gdslayer,
                                       player=gnd)
                    c_glayer += spira.SRef(gnd_layer)
                    elems += spira.SRef(c_glayer)

        return elems
예제 #19
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)
예제 #20
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
예제 #21
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
예제 #22
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
예제 #23
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
예제 #24
0
파일: port.py 프로젝트: cloudcalvin/spira
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
예제 #25
0
class __Shape__(FieldInitializer):

    center = param.PointField()
    gdslayer = param.LayerField()
    clockwise = param.BoolField(default=False)
    points = param.PointArrayField(fdef_name='create_points')
    apply_merge = param.DataField(fdef_name='create_merged_points')
    simplify = param.DataField(fdef_name='create_simplified_points')
    edges = param.DataField(fdef_name='create_edge_lines')

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

    def create_points(self, points):
        return points

    def create_merged_points(self):
        """  """
        from spira.gdsii.utils import scale_polygon_up as spu
        from spira.gdsii.utils import scale_polygon_down as spd
        polygons = spu(self.points)
        self.points = []
        for poly in polygons:
            if pyclipper.Orientation(poly) is False:
                reverse_poly = pyclipper.ReversePath(poly)
                solution = pyclipper.SimplifyPolygon(reverse_poly)
            else:
                solution = pyclipper.SimplifyPolygon(poly)
            for sol in solution:
                self.points.append(sol)
        self.points = bool_operation(subj=self.points, method='union')
        self.points = spd(self.points)
        return self

    def create_simplified_points(self):
        """  """
        from shapely.geometry import Polygon as ShapelyPolygon
        value = 1
        polygons = self.points
        self.points = []
        for points in polygons:
            factor = (len(points) / 100) * 1e5 * value
            sp = ShapelyPolygon(points).simplify(factor)
            pp = [[p[0], p[1]] for p in sp.exterior.coords]
            self.points.append(pp)
        return self

    def reflect(self, p1=(0, 1), p2=(0, 0)):
        """ Reflect across a line. """
        points = np.array(self.points[0])
        p1 = np.array(p1)
        p2 = np.array(p2)
        if np.asarray(points).ndim == 1:
            t = np.dot((p2 - p1), (points - p1)) / norm(p2 - p1)**2
            pts = 2 * (p1 + (p2 - p1) * t) - points
        if np.asarray(points).ndim == 2:
            pts = np.array([0, 0])
            for p in points:
                t = np.dot((p2 - p1), (p - p1)) / norm(p2 - p1)**2
                r = np.array(2 * (p1 + (p2 - p1) * t) - p)
                pts = np.vstack((pts, r))
        self.points = [pts]
        return self

    def rotate(self, angle=45, center=(0, 0)):
        """ Rotate points with an angle around a center. """
        points = np.array(self.points[0])
        angle = angle * np.pi / 180
        ca = np.cos(angle)
        sa = np.sin(angle)
        sa = np.array((-sa, sa))
        c0 = np.array(center)
        if np.asarray(points).ndim == 2:
            pts = (points - c0) * ca + (points - c0)[:, ::-1] * sa + c0
            pts = np.round(pts, 6)
        if np.asarray(points).ndim == 1:
            pts = (points - c0) * ca + (points - c0)[::-1] * sa + c0
            pts = np.round(pts, 6)
        self.points = [pts]
        return self

    @property
    def orientation(self):
        """ Returns the orientation of the shape: 
        +1(counterclock) or -1(clock) """
        # FIXME: Error with multiple shapes: [[[s1], [s2]]]
        pts = self.points[0]
        T = np.roll(np.roll(pts, 1, 1), 1, 0)
        return -np.sign(sum(np.diff(pts * T, 1, 1)))

    @property
    def area(self):
        """ Returns the area of the shape. """
        pts = self.points[0]
        T = np.roll(np.roll(pts, 1, 1), 1, 0)
        return sum(abs(np.diff(pts * T, 1, 1))) * 0.5

    @property
    def count(self):
        """ number of points in the shape """
        return self.__len__()

    @property
    def reverse(self):
        pass

    def move(self, pos):
        p = np.array([pos[0], pos[1]])
        self.points += p
        return self

    def transform(self):
        pass

    def point_inside(self):
        pass

    def index(self, item):
        pass
예제 #26
0
파일: basic.py 프로젝트: cloudcalvin/spira
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
예제 #27
0
class PhysicalLayer(__Layer__):
    """

    """

    doc = param.StringField()
    layer = param.LayerField()
    purpose = PurposeLayerField()
    data = param.DataField(default=ProcessTree())

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

    def __repr__(self):
        string = '[SPiRA: PhysicalLayer] (layer \'{}\', symbol \'{}\')'
        return string.format(self.layer.name, self.purpose.symbol)

    def __str__(self):
        return self.__repr__()

    def __eq__(self, other):
        if isinstance(other, PhysicalLayer):
            return other.key == self.key
        # elif isinstance(other, Layer):
        #     return other.number == self.layer.number
        elif isinstance(other, int):
            return other == self.layer.number
        else:
            raise ValueError('Not Implemented!')

    def __neq__(self, other):
        if isinstance(other, PhysicalLayer):
            return other.key != self.key
        # elif isinstance(other, Layer):
        #     return other.number != self.layer.number
        elif isinstance(other, int):
            return other != self.layer.number
        else:
            raise ValueError('Not Implemented!')
    
    # def __add__(self, other):
    #     if isinstance(other, PhysicalLayer):
    #         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, PhysicalLayer):
    #         self.datatype += other.datatype
    #     elif isinstance(other, int):
    #         self.datatype += other
    #     else:
    #         raise ValueError('Not Implemented')
    #     return self

    @property
    def key(self):
        return (self.layer.number, self.purpose.symbol)
예제 #28
0
class PolygonAbstract(__Polygon__):

    gdslayer = param.LayerField()
    gdspy_commit = param.BoolField()
    clockwise = param.BoolField(default=True)

    nodes = param.DataField(fdef_name='create_nodes')
    edges = param.DataField(fdef_name='create_edges')

    def __init__(self, shape, **kwargs):
        from spira.lgm.shapes.shape import __Shape__
        from spira.lgm.shapes.shape import Shape

        if issubclass(type(shape), __Shape__):
            self.shape = shape
        elif isinstance(shape, (list, set, np.ndarray)):
            self.shape = Shape(points=shape)
        else:
            raise ValueError('Shape type not supported!')

        ElementalInitializer.__init__(self, **kwargs)
        gdspy.PolygonSet.__init__(self,
                                  self.shape.points,
                                  layer=self.gdslayer.number,
                                  datatype=self.gdslayer.datatype,
                                  verbose=False)

    def create_nodes(self):
        """ Created nodes of each point in the polygon array.
        Converting a point to a node allows us to bind
        other objects to that specific node or point. """
        pass

    def create_edges(self):
        """ A list of tuples containing two nodes. """
        pass

    def move_edge(self):
        pass

    def commit_to_gdspy(self, cell):
        if self.__repr__() not in list(PolygonAbstract.__committed__.keys()):
            ply = deepcopy(self.shape.points)
            P = gdspy.PolygonSet(ply, self.gdslayer.number,
                                 self.gdslayer.datatype)
            cell.add(P)
            PolygonAbstract.__committed__.update({self.__repr__(): P})
        else:
            cell.add(PolygonAbstract.__committed__[self.__repr__()])

    def flat_copy(self, level=-1, commit_to_gdspy=False):
        elems = []
        for points in self.shape.points:
            c_poly = self.modified_copy(shape=deepcopy([points]),
                                        gdspy_commit=self.gdspy_commit)
            elems.append(c_poly)
            if commit_to_gdspy:
                self.gdspy_commit = True
        return elems

    def merge(self, other):
        if isinstance(other, (list, set)):
            pass
        elif isinstance(other, Polygons):
            pass
        else:
            raise ValueError('Type is not supported for Polygon merging.')

    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])
        self.shape.points = self.polygons
        return self

    def reflect(self, p1=(0, 1), p2=(0, 0)):
        for n, points in enumerate(self.shape.points):
            self.shape.points[n] = self.__reflect__(points, p1, p2)
        self.shape.points = self.polygons
        return self

    def rotate(self, angle=45, center=(0, 0)):
        super().rotate(angle=angle * np.pi / 180, center=center)
        self.shape.points = self.polygons
        return self

    def translate(self, dx, dy):
        super().translate(dx=dx, dy=dy)
        self.shape.points = self.polygons
        return self

    def stretch(self, stretch_class):
        p = stretch_class.apply_to_polygon(self.points[0])
        self.shape.points = [np.array(p)]
        return self

    def move(self, midpoint=(0, 0), destination=None, axis=None):
        from spira.gdsii.elemental.port import __Port__
        """ Moves elements of the Device 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 """

        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)

        return self

    def fast_boolean(self, other, operation):
        mm = gdspy.fast_boolean(self.shape.points,
                                other.shape.points,
                                operation=operation)
        return Polygons(shape=mm.points, gdslayer=self.gdslayer)
예제 #29
0
class MeshAbstract(__Mesh__):
    """ Class that connects a meshio generated mesh with
    a networkx generated graph of the set of polygons. """

    name = param.StringField()
    layer = param.LayerField()
    point_data = param.ElementListField()
    cell_data = param.ElementListField()
    field_data = param.ElementListField()
    node_sets = param.ElementListField()
    gmsh_periodic = param.ElementListField()

    mesh_graph = param.DataField(fdef_name='create_mesh_graph')

    def __init__(self, polygons, points, cells, **kwargs):
        super().__init__(polygons, points, cells, **kwargs)

    def create_mesh_graph(self):
        """ Create a graph from the meshed geometry. """

        ll = len(self.points)
        A = np.zeros((ll, ll), dtype=np.int64)

        for n, triangle in enumerate(self.__triangles__()):
            self.add_edges(n, triangle, A)

        for n, triangle in enumerate(self.__triangles__()):
            self.add_positions(n, triangle)

    def add_edges(self, n, tri, A):
        def update_adj(self, t1, adj_mat, v_pair):
            if (adj_mat[v_pair[0]][v_pair[1]] != 0):
                t2 = adj_mat[v_pair[0]][v_pair[1]] - 1
                self.g.add_edge(t1, t2, label=None)
            else:
                adj_mat[v_pair[0]][v_pair[1]] = t1 + 1
                adj_mat[v_pair[1]][v_pair[0]] = t1 + 1

        v1 = [tri[0], tri[1], tri[2]]
        v2 = [tri[1], tri[2], tri[0]]

        for v_pair in list(zip(v1, v2)):
            update_adj(self, n, A, v_pair)

    def add_positions(self, n, tri):
        pp = self.points
        n1, n2, n3 = pp[tri[0]], pp[tri[1]], pp[tri[2]]

        sum_x = 1e+8 * (n1[0] + n2[0] + n3[0]) / 3.0
        sum_y = 1e+8 * (n1[1] + n2[1] + n3[1]) / 3.0

        self.g.node[n]['vertex'] = tri
        self.g.node[n]['pos'] = [sum_x, sum_y]

    def __triangles__(self):
        if 'triangle' not in self.cells:
            raise ValueError('Triangle not found in cells')
        return self.cells['triangle']

    def __physical_triangles__(self):
        if 'triangle' not in self.cell_data[0]:
            raise ValueError('Triangle not in meshio cell_data')
        if 'gmsh:physical' not in self.cell_data[0]['triangle']:
            raise ValueError('Physical not found ing meshio triangle')
        return self.cell_data[0]['triangle']['gmsh:physical'].tolist()

    def __layer_triangles_dict__(self):
        """
        Arguments
        ---------
        tri : list
            The surface_id of the triangle
            corresponding to the index value.
        key -> 5_0_1 (layer_datatype_polyid)
        value -> [1 2] (1=surface_id 2=triangle)
        """

        triangles = {}
        for name, value in self.field_data[0].items():
            for n in self.g.nodes():
                surface_id = value[0]
                ptriangles = self.__physical_triangles__()
                if ptriangles[n] == surface_id:
                    layer = int(name.split('_')[0])
                    datatype = int(name.split('_')[1])
                    key = (layer, datatype)
                    if key in triangles:
                        triangles[key].append(n)
                    else:
                        triangles[key] = [n]
        return triangles

    def __triangle_nodes__(self):
        """ Get triangle field_data in list form. """

        nodes = []
        for v in self.__layer_triangles_dict__().values():
            nodes.extend(v)

        triangles = {}
        for n in nodes:
            for node, triangle in enumerate(self.__triangles__()):
                if n == node:
                    triangles[n] = triangle
        return triangles

    def __point_data__(self):
        pass

    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
예제 #30
0
class MeshLabeled(MeshAbstract):

    RDD = spira.get_rule_deck()

    primitives = param.ElementListField()

    surface_nodes = param.DataField(fdef_name='create_surface_nodes')
    pinlabel_nodes = param.DataField(fdef_name='create_pinlabel_nodes')

    def __init__(self, polygons, points, cells, **kwargs):
        print('\nPinLabels object')

        super().__init__(polygons, points, cells, **kwargs)

        self.points = points
        self.cells = cells

        self.surface_nodes
        self.pinlabel_nodes

    def create_surface_nodes(self):

        LOG.header('Adding surface labels')

        node_count = 0

        triangles = self.__layer_triangles_dict__()
        for key, nodes in triangles.items():
            for n in nodes:
                position = self.g.node[n]['pos']

                pid = utils.labeled_polygon_id(position, self.polygons)

                if pid is not None:
                    params = {}
                    params['text'] = self.name
                    params['gdslayer'] = self.layer
                    params['color'] = RDD.METALS.get_key_by_layer(
                        self.layer)['COLOR']

                    label = spira.Label(position=position, **params)
                    label.id = '{}_{}'.format(key[0], pid)

                    self.g.node[n]['surface'] = label

            node_count += 1

        print('# surface nodes added: {}'.format(node_count))

    def create_pinlabel_nodes(self):

        LOG.header('Adding pin labels')

        for node, triangle in self.__triangle_nodes__().items():
            points = [utils.c2d(self.points[i]) for i in triangle]
            for S in self.primitives:
                if isinstance(S, spira.Port):
                    self.add_port_label(node, S, points)
                else:
                    self.add_device_label(node, S, points)

    def add_new_node(self, n, D, pos):
        params = {}
        params['text'] = 'new'
        l1 = spira.Layer(name='Label', number=104)
        params['gdslayer'] = l1
        # params['color'] = RDD.METALS.get_key_by_layer(self.layer)['COLOR']

        label = spira.Label(position=pos, **params)
        label.id = '{}_{}'.format(n, n)

        num = self.g.number_of_nodes()

        self.g.add_node(num + 1, pos=pos, pin=D, surface=label)
        self.g.add_edge(n, num + 1)

    def add_port_label(self, n, D, points):
        if D.point_inside(points):
            P = spira.PortNode(name=D.name, elementals=D)
            self.g.node[n]['pin'] = P

    def add_device_label(self, n, S, points):
        for name, p in S.ports.items():
            if p.gdslayer.name == 'GROUND':
                pass
                # if lbl.layer == self.layer.number:
                #     params = {}
                #     params['text'] = 'GROUND'
                #     l1 = spira.Layer(name='GND', number=104)
                #     params['gdslayer'] = l1
                #
                #     label = spira.Label(position=lbl.position, **params)
                #     label.id = '{}_{}'.format(n, n)
                #
                #     ply = spira.Polygons(gdslayer=l1)
                #
                #     D_gnd = BaseVia(name='BaseVIA_GND',
                #                     ply=ply,
                #                     m2=l1, m1=l1)
                #
                #     num = self.g.number_of_nodes()
                #
                #     self.g.add_node(num+1, pos=lbl.position, pin=D_gnd, surface=label)
                #     self.g.add_edge(n, num+1)
            else:
                # print(S.flat_copy())
                # print(p.gdslayer.number)
                # print(self.layer.number)
                # print('')
                if p.gdslayer.number == self.layer.number:
                    if p.point_inside(points):
                        self.g.node[n]['pin'] = S