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
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
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()
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
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
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
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
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
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)
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
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
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
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
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
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
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)
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
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
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)
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
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
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
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
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
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
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
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)
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)
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
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