def test_1_Trans(self): a = pya.Trans() b = pya.Trans( pya.Trans.M135, pya.Point( 17, 5 )) c = pya.Trans( 3, True, pya.Point( 17, 5 )) d = pya.Trans( pya.Point( 17, 5 )) e = pya.Trans( pya.Trans.M135 ) e2 = pya.Trans.from_dtrans( pya.DTrans.M135 ) f = pya.Trans( pya.DTrans( pya.DTrans.M135, pya.DPoint( 17, 5 )) ) self.assertEqual( str(a), "r0 0,0" ) self.assertEqual( str(pya.Trans.from_s(str(a))), str(a) ) self.assertEqual( str(b), "m135 17,5" ) self.assertEqual( str(c), "m135 17,5" ) self.assertEqual( str(d), "r0 17,5" ) self.assertEqual( str(e), "m135 0,0" ) self.assertEqual( str(e2), "m135 0,0" ) self.assertEqual( str(f), "m135 17,5" ) self.assertEqual( str(pya.Trans.from_s(str(f))), str(f) ) self.assertEqual( str(b.trans( pya.Point( 1, 0 ))), "17,4" ) self.assertEqual( a == b, False ) self.assertEqual( a == a, True ) self.assertEqual( a != b, True ) self.assertEqual( a != a, False ) self.assertEqual( (d * e) == b, True ) self.assertEqual( (e * d) == b, False ) i = c.inverted() self.assertEqual( str(i), "m135 5,17" ) self.assertEqual( (i * b) == a, True ) self.assertEqual( (b * i) == a, True ) c = pya.Trans( 3, True, pya.Point( 17, 5 )) self.assertEqual( str(c), "m135 17,5" ) c.disp = pya.Point(1, 7) self.assertEqual( str(c), "m135 1,7" ) c.angle = 1 self.assertEqual( str(c), "m45 1,7" ) c.rot = 3 self.assertEqual( str(c), "r270 1,7" ) c.mirror = True self.assertEqual( str(c), "m135 1,7" ) self.assertEqual( str(e.trans( pya.Edge(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(( e * pya.Edge(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(e.trans( pya.Box(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(( e * pya.Box(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(e.trans( pya.Text("text", pya.Vector(0, 1)) )), "('text',m135 -1,0)" ) self.assertEqual( str(( e * pya.Text("text", pya.Vector(0, 1)) )), "('text',m135 -1,0)" ) self.assertEqual( str(e.trans( pya.Polygon( [ pya.Point(0, 1), pya.Point(2, -3), pya.Point(4, 5) ] ) )), "(-5,-4;-1,0;3,-2)" ) self.assertEqual( str(( e * pya.Polygon( [ pya.Point(0, 1), pya.Point(2, -3), pya.Point(4, 5) ] ) )), "(-5,-4;-1,0;3,-2)" ) self.assertEqual( str(e.trans( pya.Path( [ pya.Point(0, 1), pya.Point(2, 3) ], 10 ) )), "(-1,0;-3,-2) w=10 bx=0 ex=0 r=false" ) self.assertEqual( str(( e * pya.Path( [ pya.Point(0, 1), pya.Point(2, 3) ], 10 ) )), "(-1,0;-3,-2) w=10 bx=0 ex=0 r=false" )
def test_1a(self): # instantiate and register the library tl = PCellTestLib2() ly = pya.Layout(True) ly.dbu = 0.01 li1 = find_layer(ly, "1/0") self.assertEqual(li1 == None, True) ci1 = ly.add_cell("c1") c1 = ly.cell(ci1) lib = pya.Library.library_by_name("PCellTestLib2") self.assertEqual(lib != None, True) pcell_decl = lib.layout().pcell_declaration("Box2") param = [ pya.LayerInfo(1, 0) ] # rest is filled with defaults pcell_var_id = ly.add_pcell_variant(lib, pcell_decl.id(), param) pcell_var = ly.cell(pcell_var_id) pcell_inst = c1.insert(pya.CellInstArray(pcell_var_id, pya.Trans())) self.assertEqual(pcell_var.basic_name(), "Box2") self.assertEqual(pcell_var.pcell_parameters().__repr__(), "[<1/0>, 1.0, 1.0]") self.assertEqual(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)") self.assertEqual(nh(pcell_var.pcell_parameters_by_name()), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}") self.assertEqual(pcell_var.pcell_parameter("height").__repr__(), "1.0") self.assertEqual(c1.pcell_parameters(pcell_inst).__repr__(), "[<1/0>, 1.0, 1.0]") self.assertEqual(nh(c1.pcell_parameters_by_name(pcell_inst)), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}") self.assertEqual(c1.pcell_parameter(pcell_inst, "height").__repr__(), "1.0") self.assertEqual(nh(pcell_inst.pcell_parameters_by_name()), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}") self.assertEqual(pcell_inst["height"].__repr__(), "1.0") self.assertEqual(pcell_inst.pcell_parameter("height").__repr__(), "1.0") self.assertEqual(pcell_var.pcell_declaration().__repr__(), pcell_decl.__repr__()) self.assertEqual(c1.pcell_declaration(pcell_inst).__repr__(), pcell_decl.__repr__()) self.assertEqual(pcell_inst.pcell_declaration().__repr__(), pcell_decl.__repr__()) li1 = find_layer(ly, "1/0") self.assertEqual(li1 == None, False) pcell_inst.change_pcell_parameter("height", 2.0) self.assertEqual(nh(pcell_inst.pcell_parameters_by_name()), "{'height': 2.0, 'layer': <1/0>, 'width': 1.0}") self.assertEqual(ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-50,-100;50,100)") param = { "layer": pya.LayerInfo(2, 0), "width": 2, "height": 1 } li2 = ly.layer(2, 0) c1.change_pcell_parameters(pcell_inst, param) self.assertEqual(ly.begin_shapes(c1.cell_index(), li2).shape().__str__(), "box (-100,-50;100,50)") l10 = ly.layer(10, 0) c1.shapes(l10).insert(pya.Box(0, 10, 100, 210)) l11 = ly.layer(11, 0) c1.shapes(l11).insert(pya.Text("hello", pya.Trans())) self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), False) self.assertEqual(pcell_decl.can_create_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), True) self.assertEqual(repr(pcell_decl.parameters_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "[<10/0>, 1.0, 2.0]") self.assertEqual(str(pcell_decl.transformation_from_shape(ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "r0 50,110")
def port_to_pin_helper(ports_list, cell, layerPinRec): # Create the pins, as short paths: from siepic_tools.config import PIN_LENGTH dbu = cell.layout().dbu for port in ports_list: if port.name.startswith("el"): pin_length = port.width else: pin_length = PIN_LENGTH * dbu port_position_i = port.position.to_itype(dbu) cell.shapes(layerPinRec).insert( pya.DPath([port.position - 0.5 * pin_length * port.direction, port.position + 0.5 * pin_length * port.direction], port.width).to_itype(dbu)) cell.shapes(layerPinRec).insert(pya.Text(port.name, pya.Trans( pya.Trans.R0, port_position_i.x, port_position_i.y))).text_size = 2 / dbu
def produce_impl(self): # fetch the parameters dbu = self.layout.dbu ly = self.layout LayerSi = self.layer LayerSiN = ly.layer(self.layer) LayerPinRecN = ly.layer(self.pinrec) LayerDevRecN = ly.layer(self.devrec) LayerTextN = ly.layer(self.textl) # Fetch all the parameters: a = self.a / dbu r = self.r / dbu wg_dis = self.wg_dis + 1 n_vertices = self.n_vertices n_bus = self.n_bus n = int(math.ceil(self.n / 2)) Sx = [self.S1x, self.S2x, self.S3x, self.S4x, self.S5x] Sy = [self.S1y, 0, self.S2y] if n_bus == 1: Sx = [0, 0, 0, 0, 0] Sy = [0, 0, 0] if wg_dis % 2 == 0: length_slab_x = (2 * n - 1) * a else: length_slab_x = 2 * n * a length_slab_y = 2 * (wg_dis + 15) * a * math.sqrt(3) / 2 n_x = n n_y = wg_dis + 10 # Define Si slab and hole region for future subtraction Si_slab = pya.Region() Si_slab.insert( pya.Box(-length_slab_x / 2, -length_slab_y / 2, length_slab_x / 2, length_slab_y / 2)) hole = pya.Region() hole_r = r # function to generate points to create a circle def circle(x, y, r): npts = n_vertices theta = 2 * math.pi / npts # increment, in radians pts = [] for i in range(0, npts): pts.append( Point.from_dpoint( pya.DPoint((x + r * math.cos(i * theta)) / 1, (y + r * math.sin(i * theta)) / 1))) return pts # raster through all holes with shifts and waveguide hole_cell = circle(0, 0, hole_r) hole_poly = pya.Polygon(hole_cell) for j in range(-n_y, n_y + 1): if j % 2 == 0 and j != wg_dis: for i in range(-n_x, n_x + 1): if j == -wg_dis and i > 3 and n_bus == 2: None elif j == 0 and i in (1, -1, 2, -2, 3, -3, 4, -4, 5, -5): hole_x = abs(i) / i * (abs(i) - 0.5 + Sx[abs(i) - 1]) * a hole_y = 0 hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) hole_t = hole_poly.transformed(hole_trans) hole.insert(hole_t) elif i != 0: hole_x = abs(i) / i * (abs(i) - 0.5) * a hole_y = j * a * math.sqrt(3) / 2 hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) hole_t = hole_poly.transformed(hole_trans) hole.insert(hole_t) elif j % 2 == 1 and j != wg_dis: for i in range(-n_x, n_x + 1): if j == -wg_dis and i > 3 and n_bus == 2: None elif i == 0 and j in (1, -1, 3, -3): hole_x = 0 hole_y = j * a * (math.sqrt(3) / 2) + abs(j) / j * a * Sy[abs(j) - 1] hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) hole_t = hole_poly.transformed(hole_trans) hole.insert(hole_t) else: hole_x = i * a hole_y = j * a * math.sqrt(3) / 2 hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) hole_t = hole_poly.transformed(hole_trans) hole.insert(hole_t) phc = Si_slab - hole self.cell.shapes(LayerSiN).insert(phc) # Pins on the waveguide: pin_length = 200 pin_w = a wg_pos = a * math.sqrt(3) / 2 * wg_dis t = pya.Trans(Trans.R0, -length_slab_x / 2, wg_pos) pin = pya.Path( [pya.Point(pin_length / 2, 0), pya.Point(-pin_length / 2, 0)], pin_w) pin_t = pin.transformed(t) self.cell.shapes(LayerPinRecN).insert(pin_t) text = pya.Text("pin1", t) shape = self.cell.shapes(LayerPinRecN).insert(text) shape.text_size = 0.4 / dbu t = pya.Trans(Trans.R0, length_slab_x / 2, wg_pos) pin = pya.Path( [pya.Point(-pin_length / 2, 0), pya.Point(pin_length / 2, 0)], pin_w) pin_t = pin.transformed(t) self.cell.shapes(LayerPinRecN).insert(pin_t) text = pya.Text("pin2", t) shape = self.cell.shapes(LayerPinRecN).insert(text) shape.text_size = 0.4 / dbu #pin for drop waveguide if n_bus == 2: t = pya.Trans(Trans.R0, length_slab_x / 2, -wg_pos) pin_t = pin.transformed(t) self.cell.shapes(LayerPinRecN).insert(pin_t) text = pya.Text("pin3", t) shape = self.cell.shapes(LayerPinRecN).insert(text) shape.text_size = 0.4 / dbu # Create the device recognition layer -- make it 1 * wg_width away from the waveguides. points = [[-length_slab_x / 2, 0], [length_slab_x / 2, 0]] points = [Point(each[0], each[1]) for each in points] path = Path(points, length_slab_y) self.cell.shapes(LayerDevRecN).insert(path.simple_polygon())
def produce_impl(self): """Create the effective Klayout shapes. For this all the InstanceHolders are cycled through and all the child instances are created. Furthermore, if desired, dataprep is performed, which copies and sizes the shapes as desired. Dataprep will only create shapes on the topmost cell. Finally, if desired DR-cleaning is performed and in the process the shapes will be manhattanized. """ if self.layermap is None: raise NotImplementedError( 'self.layermap has to be defined by the PCell. You can either do this in the PCell initialization or ' 'in a Class that all PCells inherit from. See the documentation for more details' ) if self.dataprep_config is None: raise NotImplementedError( 'self.dataprep_config has to be defined by the PCell. You can either do this in the PCell initialization or ' 'in a Class that all PCells inherit from. See the documentation for more details' ) if self.clean_rules is None: raise NotImplementedError( 'self.clean_rules has to be defined by the PCell. You can either do this in the PCell initialization or ' 'in a Class that all PCells inherit from. See the documentation for more details' ) instances_and_ports = self.create_param_inst() id = 0 insts = [] # Because we cannot safe anything between coerce_parameters and here, we must calculate this again. if isnamedtupleinstance(instances_and_ports) or isinstance( instances_and_ports, InstanceHolder): instances_and_ports = [instances_and_ports] for inst_port in instances_and_ports: if isinstance(inst_port, InstanceHolder): inst_port.id = id id += 1 insts.append(inst_port) elif isnamedtupleinstance(inst_port): continue elif isinstance(inst_port, list): for iinst_port in inst_port: if isinstance(iinst_port, InstanceHolder): iinst_port.id = id id += 1 insts.append(iinst_port) elif isnamedtupleinstance(iinst_port): continue else: raise ValueError( "Expected type instances (InstanceHolder), ports (PortCreation) or a list of instances,ports. Instead got {}" .format(str(type(inst_port)))) # If we have child cells to create, create them now if insts: self.add_pcells(insts) # Create the shapes created in this PCell self.shapes() if self.top or not self.only_top_ports: # If this is a top cell or we want to draw all ports, draw the texts. # To make sure that texts of ports get drawn correctly set the boolean to true in File-> Setup -> Display -> Settings -> Cells -> 'Transform text with cell instance' # and make sure it's not set to Default font if self.portlist: for i, p in enumerate(self.portlist.split(';')): trans = pya.ICplxTrans.from_s(p.split(':')[0]).s_trans() trans.rot = (trans.rot + 1 % 4) if trans.is_mirror(): trans.rot = (trans.rot + 2 % 4) valign = halign = 1 if trans.rot % 2: valign = 2 else: halign = 2 text = pya.Text("Port {}".format(i), trans) text.halign = halign text.valign = valign self.cell.shapes(self._layers[0]).insert(text) # For the dataprep, do we want to keep the original shapes and child-cells? cl1 = clock() if self.keep: # Yes, so we create a new child cell called 'DataPrep' to create the dataprep shapes in if self.dataprep: prep_cell = self.layout.create_cell('DataPrep') prep_cell._create() kppc.photonics.dataprep.dataprep(self.cell, self.layout, prep_cell, config=self.dataprep_config, layers_org=self.layermap) self.cell.insert( pya.CellInstArray(prep_cell.cell_index(), pya.Trans.R0)) if self.drc_clean: rules = self.clean_rules # Convert Micrometers to database units for cr in rules: cr[1] = int(cr[1] / self.layout.dbu) cr[2] = int(cr[2] / self.layout.dbu) kppc.drc.clean(prep_cell, rules) else: # the dataprep will clean all children and shapes and then insert cleaned ones if self.dataprep: temp_cell = self.layout.create_cell('DataPrep_del') temp_cell._create() kppc.photonics.dataprep.dataprep(self.cell, self.layout, temp_cell, config=self.dataprep_config, layers_org=self.layermap) if self.drc_clean: rules = self.clean_rules # Convert Micrometers to database units for cr in rules: cr[1] = int(cr[1] / self.layout.dbu) cr[2] = int(cr[2] / self.layout.dbu) kppc.drc.clean(temp_cell, rules) # Delete all child cells self.cell.clear() self.cell.insert( pya.CellInstArray(temp_cell.cell_index(), pya.Trans.R0)) self.cell.flatten(True) print('Time for dataprep and DR-cleaning:') print(clock() - cl1)
def make_pin(cell, name, center, w, layer, direction): ''' Makes a pin that SiEPIC-Tools will recognize cell: which cell to draw it in name: text label for the pin center: location, int [x,y] w: pin width layer: layout.layer() type direction = 0: right 90: up 180: left 270: down Units: intput can be float for microns, or int for nm ''' from SiEPIC.extend import to_itype import numpy dbu = cell.layout().dbu if type(w) == type(float()): w = to_itype(w, dbu) print('SiEPIC.utils.layout.make_pin: w converted to %s' % w) else: print('SiEPIC.utils.layout.make_pin: w %s' % w) # print(type(center[0])) if type(center[0]) == type(float()) or type(center[0]) == type( numpy.float64()): center[0] = to_itype(center[0], dbu) center[1] = to_itype(center[1], dbu) print('SiEPIC.utils.layout.make_pin: center converted to %s' % (center)) else: print('SiEPIC.utils.layout.make_pin: center %s' % (center)) from SiEPIC._globals import PIN_LENGTH as pin_length if direction not in [0, 90, 180, 270]: raise ('error in make_pin: direction must be one of [0, 90, 180, 270]') # text label t = pya.Trans(pya.Trans.R0, center[0], center[1]) text = pya.Text(name, t) shape = cell.shapes(layer).insert(text) shape.text_dsize = float(w * dbu) shape.text_valign = 1 if direction == 0: p1 = pya.Point(center[0] - pin_length / 2, center[1]) p2 = pya.Point(center[0] + pin_length / 2, center[1]) shape.text_halign = 2 if direction == 90: p1 = pya.Point(center[0], center[1] - pin_length / 2) p2 = pya.Point(center[0], center[1] + pin_length / 2) shape.text_halign = 2 shape.text_rot = 1 if direction == 180: p1 = pya.Point(center[0] + pin_length / 2, center[1]) p2 = pya.Point(center[0] - pin_length / 2, center[1]) shape.text_halign = 3 if direction == 270: p1 = pya.Point(center[0], center[1] + pin_length / 2) p2 = pya.Point(center[0], center[1] - pin_length / 2) shape.text_halign = 3 shape.text_rot = 1 pin = pya.Path([p1, p2], w) cell.shapes(layer).insert(pin)
def produce_impl(self): # fetch the parameters dbu = self.layout.dbu ly = self.layout bus_n = self.bus_number LayerSi = self.layer LayerSiN = ly.layer(self.layer) LayerPinRecN = ly.layer(self.pinrec) LayerDevRecN = ly.layer(self.devrec) LayerTextN = ly.layer(self.textl) a = self.a / dbu r = self.r / dbu wg_dis = self.wg_dis + 1 n = int(math.ceil(self.n / 2)) Sx = [self.S1x, self.S2x, self.S3x, self.S4x, self.S5x] Sy = [self.S1y, 0, self.S2y] if wg_dis % 2 == 0: length_slab_x = 2 * n * a else: length_slab_x = (2 * n + 1) * a length_slab_y = 2 * (n - 2) * a if bus_n == 2: k = -1 else: k = 1 #function to creat polygon pts for right half of a hole in a hexagon unit cell def hexagon_hole_half(a, r): npts = 10 theta_div = math.pi / 3 theta_div_hole = math.pi / npts triangle_length = a / math.sqrt(3) pts = [] for i in range(0, 4): pts.append( Point.from_dpoint( pya.DPoint( triangle_length * math.cos(i * theta_div - math.pi / 2), triangle_length * math.sin(i * theta_div - math.pi / 2)))) for i in range(0, npts + 1): pts.append( Point.from_dpoint( pya.DPoint( r * math.cos(math.pi / 2 - i * theta_div_hole), r * math.sin(math.pi / 2 - i * theta_div_hole)))) return pts def hexagon_shifthole_half(a, r): npts = 10 theta_div = math.pi / 3 theta_div_hole = math.pi / npts triangle_length = a * 1.235 / math.sqrt(3) pts = [] for i in range(0, 4): pts.append( Point.from_dpoint( pya.DPoint( triangle_length * math.cos(i * theta_div - math.pi / 2), triangle_length * math.sin(i * theta_div - math.pi / 2)))) for i in range(0, npts + 1): pts.append( Point.from_dpoint( pya.DPoint( r * math.cos(math.pi / 2 - i * theta_div_hole), r * math.sin(math.pi / 2 - i * theta_div_hole)))) return pts #function to creat polygon pts for right half of a hexagon unit cell def hexagon_half(a): theta_div = math.pi / 3 triangle_length = a / math.sqrt(3) pts = [] for i in range(0, 4): pts.append( Point.from_dpoint( pya.DPoint( triangle_length * math.cos(i * theta_div - math.pi / 2), triangle_length * math.sin(i * theta_div - math.pi / 2)))) return pts #create the right and left half of the hole and hexagon cells #hole_cell = pya.Region() #hexagon_cell = pya.Region() hole = pya.Region() hole_cell_pts = hexagon_hole_half(a, r) hexagon_pts = hexagon_half(a) hole_shiftcell_pts = hexagon_shifthole_half(a, r) hole_cell_poly_0 = pya.Polygon(hole_cell_pts) hexagon_cell_poly_0 = pya.Polygon(hexagon_pts) hole_shiftcell_poly_0 = pya.Polygon(hole_shiftcell_pts) hole_trans = pya.Trans(pya.Trans.R180) hole_cell_poly_1 = hole_cell_poly_0.transformed(hole_trans) hexagon_cell_poly_1 = hexagon_cell_poly_0.transformed(hole_trans) hole_shiftcell_poly_1 = hole_shiftcell_poly_0.transformed(hole_trans) #create the photonic crystal with shifts and waveguides for j in range(-n + 1, n): if j % 2 == 0: for i in range(-n, n + 1): #waveguide if (j == k * wg_dis and i > 3) or (j == wg_dis and i != 0): hole_x = abs(i) / i * (abs(i) - 0.5) * a hole_y = j * a * math.sqrt(3) / 2 hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) hole_t_0 = hexagon_cell_poly_0.transformed(hole_trans) hole_t_1 = hexagon_cell_poly_1.transformed(hole_trans) hole.insert(hole_t_0) hole.insert(hole_t_1) #filling the edges with half cell elif i in (-n, n) and wg_dis % 2 == 1: hole_x = abs(i) / i * (abs(i) + 0.5) * a hole_y = j * a * math.sqrt(3) / 2 hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) if i == -n: hole_t = hole_cell_poly_0.transformed(hole_trans) else: hole_t = hole_cell_poly_1.transformed(hole_trans) hole.insert(hole_t) hole_x = abs(i) / i * (abs(i) - 0.5) * a hole_y = j * a * math.sqrt(3) / 2 hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) hole_t_0 = hole_cell_poly_0.transformed(hole_trans) hole_t_1 = hole_cell_poly_1.transformed(hole_trans) hole.insert(hole_t_0) hole.insert(hole_t_1) #x shifts elif j == 0 and i in (1, -1, 2, -2, 3, -3, 4, -4, 5, -5): hole_x = abs(i) / i * (abs(i) - 0.5 + Sx[abs(i) - 1]) * a hole_y = 0 hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) hole_t_0 = hole_shiftcell_poly_0.transformed( hole_trans) hole_t_1 = hole_shiftcell_poly_1.transformed( hole_trans) hole.insert(hole_t_0) hole.insert(hole_t_1) elif i != 0: hole_x = abs(i) / i * (abs(i) - 0.5) * a hole_y = j * a * math.sqrt(3) / 2 hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) hole_t_0 = hole_cell_poly_0.transformed(hole_trans) hole_t_1 = hole_cell_poly_1.transformed(hole_trans) hole.insert(hole_t_0) hole.insert(hole_t_1) elif j % 2 == 1: for i in range(-n, n + 1): #waveguide if (j == k * wg_dis and i > 3) or j == wg_dis: hole_x = i * a hole_y = j * a * math.sqrt(3) / 2 hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) hole_t_0 = hexagon_cell_poly_0.transformed(hole_trans) hole_t_1 = hexagon_cell_poly_1.transformed(hole_trans) hole.insert(hole_t_0) hole.insert(hole_t_1) #filling the edges with half cell elif wg_dis % 2 == 0 and i in (-n, n): hole_x = i * a hole_y = j * a * math.sqrt(3) / 2 hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) if i == -n: hole_t = hole_cell_poly_0.transformed(hole_trans) else: hole_t = hole_cell_poly_1.transformed(hole_trans) hole.insert(hole_t) #y shifts elif i == 0 and j in (1, -1, 3, -3): hole_x = 0 hole_y = j * a * (math.sqrt(3) / 2) + abs(j) / j * a * Sy[abs(j) - 1] hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) hole_t_0 = hole_shiftcell_poly_0.transformed( hole_trans) hole_t_1 = hole_shiftcell_poly_1.transformed( hole_trans) hole.insert(hole_t_0) hole.insert(hole_t_1) else: hole_x = i * a hole_y = j * a * math.sqrt(3) / 2 hole_trans = pya.Trans(Trans.R0, hole_x, hole_y) hole_t_0 = hole_cell_poly_0.transformed(hole_trans) hole_t_1 = hole_cell_poly_1.transformed(hole_trans) hole.insert(hole_t_0) hole.insert(hole_t_1) #print(hole_t_0) box_l = a / 2 hole.insert(pya.Box(-box_l, -box_l, box_l, box_l)) cover_box = pya.Box(-length_slab_x / 2, -a / 2, length_slab_x / 2, a / 2) box_y = n * a * math.sqrt(3) / 2 cover_box_trans_0 = pya.Trans(Trans.R0, 0, box_y) cover_box_trans_1 = pya.Trans(Trans.R0, 0, -box_y) cover_box_t_0 = cover_box.transformed(cover_box_trans_0) cover_box_t_1 = cover_box.transformed(cover_box_trans_1) #hole.insert(pya.Box()) self.cell.shapes(LayerSiN).insert(hole) self.cell.shapes(LayerSiN).insert(cover_box_t_0) self.cell.shapes(LayerSiN).insert(cover_box_t_1) # Pins on the waveguide: pin_length = 200 pin_w = a wg_pos = a * math.sqrt(3) / 2 * wg_dis t = pya.Trans(Trans.R0, -length_slab_x / 2, wg_pos) pin = pya.Path( [pya.Point(-pin_length / 2, 0), pya.Point(pin_length / 2, 0)], pin_w) pin_t = pin.transformed(t) self.cell.shapes(LayerPinRecN).insert(pin_t) text = pya.Text("pin1", t) shape = self.cell.shapes(LayerPinRecN).insert(text) shape.text_size = 0.4 / dbu t = pya.Trans(Trans.R0, length_slab_x / 2, wg_pos) pin_t = pin.transformed(t) self.cell.shapes(LayerPinRecN).insert(pin_t) text = pya.Text("pin2", t) shape = self.cell.shapes(LayerPinRecN).insert(text) shape.text_size = 0.4 / dbu #pin for drop waveguide t = pya.Trans(Trans.R0, length_slab_x / 2, -wg_pos) pin_t = pin.transformed(t) self.cell.shapes(LayerPinRecN).insert(pin_t) text = pya.Text("pin3", t) shape = self.cell.shapes(LayerPinRecN).insert(text) shape.text_size = 0.4 / dbu # Create the device recognition layer -- make it 1 * wg_width away from the waveguides. points = [[-length_slab_x / 2, 0], [length_slab_x / 2, 0]] points = [Point(each[0], each[1]) for each in points] path = Path(points, length_slab_y) self.cell.shapes(LayerDevRecN).insert(path.simple_polygon())
def test_1(self): # instantiate and register the library tl = PCellTestLib() ly = pya.Layout(True) ly.dbu = 0.01 li1 = find_layer(ly, "1/0") self.assertEqual(li1 == None, True) ci1 = ly.add_cell("c1") c1 = ly.cell(ci1) lib = pya.Library.library_by_name("NoLib") self.assertEqual(lib == None, True) lib = pya.Library.library_by_name("PCellTestLib") self.assertEqual(lib != None, True) pcell_decl = lib.layout().pcell_declaration("x") self.assertEqual(pcell_decl == None, True) pcell_decl = lib.layout().pcell_declaration("Box") self.assertEqual(pcell_decl != None, True) pcell_decl_id = lib.layout().pcell_id("Box") self.assertEqual(pcell_decl.id(), pcell_decl_id) self.assertEqual(":".join(lib.layout().pcell_names()), "Box") self.assertEqual(lib.layout().pcell_ids(), [pcell_decl_id]) self.assertEqual(lib.layout().pcell_declaration(pcell_decl_id).id(), pcell_decl_id) param = [pya.LayerInfo(1, 0)] # rest is filled with defaults pcell_var_id = ly.add_pcell_variant(lib, pcell_decl_id, param) pcell_var = ly.cell(pcell_var_id) pcell_inst = c1.insert(pya.CellInstArray(pcell_var_id, pya.Trans())) self.assertEqual(pcell_var.layout().__repr__(), ly.__repr__()) self.assertEqual(pcell_var.library().__repr__(), lib.__repr__()) self.assertEqual(pcell_var.is_pcell_variant(), True) self.assertEqual(pcell_var.display_title(), "PCellTestLib.Box(L=1/0,W=1.000,H=1.000)") self.assertEqual(pcell_var.basic_name(), "Box") self.assertEqual(c1.is_pcell_variant(), False) self.assertEqual(c1.is_pcell_variant(pcell_inst), True) self.assertEqual(pcell_var.pcell_id(), pcell_decl_id) self.assertEqual(pcell_var.pcell_library().__repr__(), lib.__repr__()) self.assertEqual(pcell_var.pcell_parameters().__repr__(), "[<1/0>, 1.0, 1.0]") self.assertEqual(nh(pcell_var.pcell_parameters_by_name()), "{'h': 1.0, 'l': <1/0>, 'w': 1.0}") self.assertEqual(pcell_var.pcell_parameter("h").__repr__(), "1.0") self.assertEqual( c1.pcell_parameters(pcell_inst).__repr__(), "[<1/0>, 1.0, 1.0]") self.assertEqual(nh(c1.pcell_parameters_by_name(pcell_inst)), "{'h': 1.0, 'l': <1/0>, 'w': 1.0}") self.assertEqual(c1.pcell_parameter(pcell_inst, "h").__repr__(), "1.0") self.assertEqual(nh(pcell_inst.pcell_parameters_by_name()), "{'h': 1.0, 'l': <1/0>, 'w': 1.0}") self.assertEqual(pcell_inst["h"].__repr__(), "1.0") self.assertEqual(pcell_inst["i"].__repr__(), "None") self.assertEqual(pcell_inst.pcell_parameter("h").__repr__(), "1.0") self.assertEqual(pcell_var.pcell_declaration().__repr__(), pcell_decl.__repr__()) self.assertEqual( c1.pcell_declaration(pcell_inst).__repr__(), pcell_decl.__repr__()) self.assertEqual(pcell_inst.pcell_declaration().__repr__(), pcell_decl.__repr__()) pcell_inst.change_pcell_parameter("h", 2.0) self.assertEqual(nh(pcell_inst.pcell_parameters_by_name()), "{'h': 2.0, 'l': <1/0>, 'w': 1.0}") pcell_inst.set_property("abc", "a property") self.assertEqual(pcell_inst.property("abc").__repr__(), "'a property'") c1.clear() param = [pya.LayerInfo(1, 0), 5.0, 10.0] pcell_var_id = ly.add_pcell_variant(lib, pcell_decl_id, param) pcell_var = ly.cell(pcell_var_id) pcell_inst = c1.insert(pya.CellInstArray(pcell_var_id, pya.Trans())) self.assertEqual(pcell_var.layout().__repr__(), ly.__repr__()) self.assertEqual(pcell_var.library().__repr__(), lib.__repr__()) self.assertEqual(pcell_var.is_pcell_variant(), True) self.assertEqual(pcell_var.display_title(), "PCellTestLib.Box(L=1/0,W=5.000,H=10.000)") self.assertEqual(pcell_var.basic_name(), "Box") self.assertEqual(c1.is_pcell_variant(), False) self.assertEqual(c1.is_pcell_variant(pcell_inst), True) self.assertEqual(pcell_var.pcell_id(), pcell_decl_id) self.assertEqual(pcell_var.pcell_library().__repr__(), lib.__repr__()) self.assertEqual(pcell_var.pcell_parameters().__repr__(), "[<1/0>, 5.0, 10.0]") self.assertEqual( c1.pcell_parameters(pcell_inst).__repr__(), "[<1/0>, 5.0, 10.0]") self.assertEqual(pcell_inst.pcell_parameters().__repr__(), "[<1/0>, 5.0, 10.0]") self.assertEqual(pcell_var.pcell_declaration().__repr__(), pcell_decl.__repr__()) self.assertEqual( c1.pcell_declaration(pcell_inst).__repr__(), pcell_decl.__repr__()) li1 = find_layer(ly, "1/0") self.assertEqual(li1 != None, True) self.assertEqual(ly.is_valid_layer(li1), True) self.assertEqual(str(ly.get_info(li1)), "1/0") lib_proxy_id = ly.add_lib_cell(lib, lib.layout().cell_by_name("StaticBox")) lib_proxy = ly.cell(lib_proxy_id) self.assertEqual(lib_proxy.display_title(), "PCellTestLib.StaticBox") self.assertEqual(lib_proxy.basic_name(), "StaticBox") self.assertEqual(lib_proxy.layout().__repr__(), ly.__repr__()) self.assertEqual(lib_proxy.library().__repr__(), lib.__repr__()) self.assertEqual(lib_proxy.is_pcell_variant(), False) self.assertEqual( lib.layout().cell( lib.layout().cell_by_name("StaticBox")).library().__repr__(), "None") li2 = find_layer(ly, "10/0") self.assertEqual(li2 != None, True) self.assertEqual( ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-250,-500;250,500)") self.assertEqual( ly.begin_shapes(lib_proxy.cell_index(), li2).shape().__str__(), "box (0,0;10,20)") param = {"w": 1, "h": 2} c1.change_pcell_parameters(pcell_inst, param) self.assertEqual( ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-50,-100;50,100)") param = [pya.LayerInfo(1, 0), 5.0, 5.0] c1.change_pcell_parameters(pcell_inst, param) self.assertEqual( ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-250,-250;250,250)") pcell_inst.change_pcell_parameters({"w": 2.0, "h": 10.0}) self.assertEqual( ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-100,-500;100,500)") pcell_inst.change_pcell_parameters([pya.LayerInfo(1, 0), 5.0, 5.0]) self.assertEqual( ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-250,-250;250,250)") pcell_inst.change_pcell_parameter("w", 5.0) pcell_inst.change_pcell_parameter("h", 1.0) self.assertEqual( ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-250,-50;250,50)") c1.change_pcell_parameter(pcell_inst, "w", 10.0) c1.change_pcell_parameter(pcell_inst, "h", 2.0) self.assertEqual( ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-500,-100;500,100)") self.assertEqual( ly.cell(pcell_inst.cell_index).is_pcell_variant(), True) self.assertEqual(pcell_inst.is_pcell(), True) new_id = ly.convert_cell_to_static(pcell_inst.cell_index) self.assertEqual(new_id == pcell_inst.cell_index, False) self.assertEqual(ly.cell(new_id).is_pcell_variant(), False) param = [pya.LayerInfo(1, 0), 5.0, 5.0] c1.change_pcell_parameters(pcell_inst, param) self.assertEqual( ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-250,-250;250,250)") pcell_inst.cell_index = new_id self.assertEqual( ly.begin_shapes(c1.cell_index(), li1).shape().__str__(), "box (-500,-100;500,100)") l10 = ly.layer(10, 0) c1.shapes(l10).insert(pya.Box(0, 10, 100, 210)) l11 = ly.layer(11, 0) c1.shapes(l11).insert(pya.Text("hello", pya.Trans())) self.assertEqual( pcell_decl.can_create_from_shape( ly, ly.begin_shapes(c1.cell_index(), l11).shape(), l10), False) self.assertEqual( pcell_decl.can_create_from_shape( ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10), True) self.assertEqual( repr( pcell_decl.parameters_from_shape( ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "[<10/0>, 1.0, 2.0]") self.assertEqual( str( pcell_decl.transformation_from_shape( ly, ly.begin_shapes(c1.cell_index(), l10).shape(), l10)), "r0 50,110")
def test_3_DTrans(self): c = pya.DCplxTrans( 5.0, -7.0 ) self.assertEqual( str(c), "r0 *1 5,-7" ) c = pya.DCplxTrans( pya.DCplxTrans.M135 ) self.assertEqual( str(c), "m135 *1 0,0" ) self.assertEqual( c.is_unity(), False ) self.assertEqual( c.is_ortho(), True ) self.assertEqual( c.is_mag(), False ) self.assertEqual( c.is_mirror(), True ) self.assertEqual( c.rot(), pya.DCplxTrans.M135.rot() ) self.assertEqual( str(c.s_trans()), "m135 0,0" ) self.assertAlmostEqual( c.angle, 270 ) self.assertEqual( str(c.trans( pya.Edge(0, 1, 2, 3) )), "(-1,0;-3,-2)" ) self.assertEqual( str(( c * pya.Edge(0, 1, 2, 3) )), "(-1,0;-3,-2)" ) self.assertEqual( str(c.trans( pya.Box(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(( c * pya.Box(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(c.trans( pya.Text("text", pya.Vector(0, 1)) )), "('text',m135 -1,0)" ) self.assertEqual( str(( c * pya.Text("text", pya.Vector(0, 1)) )), "('text',m135 -1,0)" ) self.assertEqual( str(c.trans( pya.Polygon( [ pya.Point(0, 1), pya.Point(2, -3), pya.Point(4, 5) ] ) )), "(-5,-4;-1,0;3,-2)" ) self.assertEqual( str(( c * pya.Polygon( [ pya.Point(0, 1), pya.Point(2, -3), pya.Point(4, 5) ] ) )), "(-5,-4;-1,0;3,-2)" ) self.assertEqual( str(c.trans( pya.Path( [ pya.Point(0, 1), pya.Point(2, 3) ], 10 ) )), "(-1,0;-3,-2) w=10 bx=0 ex=0 r=false" ) self.assertEqual( str(( c * pya.Path( [ pya.Point(0, 1), pya.Point(2, 3) ], 10 ) )), "(-1,0;-3,-2) w=10 bx=0 ex=0 r=false" ) c = pya.DCplxTrans.from_itrans( pya.CplxTrans.M135 ) self.assertEqual( str(c), "m135 *1 0,0" ) c = pya.DCplxTrans( 1.5 ) self.assertEqual( str(c), "r0 *1.5 0,0" ) self.assertEqual( c.is_unity(), False ) self.assertEqual( c.is_ortho(), True ) self.assertEqual( c.is_mag(), True ) self.assertEqual( c.is_mirror(), False ) self.assertEqual( c.rot(), pya.DCplxTrans.R0.rot() ) self.assertEqual( str(c.s_trans()), "r0 0,0" ) self.assertAlmostEqual( c.angle, 0 ) c = pya.DCplxTrans( 0.75, 45, True, 2.5, -12.5 ) self.assertEqual( str(c), "m22.5 *0.75 2.5,-12.5" ) c = pya.DCplxTrans( 0.75, 45, True, pya.DPoint( 2.5, -12.5 ) ) self.assertEqual( str(c), "m22.5 *0.75 2.5,-12.5" ) self.assertEqual( c.is_unity(), False ) self.assertEqual( c.is_ortho(), False ) self.assertEqual( c.is_mag(), True ) self.assertEqual( c.rot(), pya.DCplxTrans.M0.rot() ) self.assertEqual( str(c.s_trans()), "m0 2.5,-12.5" ) self.assertAlmostEqual( c.angle, 45 ) self.assertEqual( str(c.ctrans( 5 )), "3.75" ) self.assertEqual( str(c.trans( pya.DPoint( 12, 16 ) )), "17.3492424049,-14.6213203436" ) self.assertEqual( str(pya.DCplxTrans()), "r0 *1 0,0" ) self.assertEqual( pya.DCplxTrans().is_unity(), True ) self.assertEqual( (c * c.inverted()).is_unity(), True ) c.mirror = False self.assertEqual( str(c), "r45 *0.75 2.5,-12.5" ) c.mag = 1.5 self.assertEqual( str(c), "r45 *1.5 2.5,-12.5" ) c.disp = pya.DPoint( -1.0, 5.5 ) self.assertEqual( str(c), "r45 *1.5 -1,5.5" ) self.assertEqual( c.mag, 1.5 ) c.angle = 60 self.assertEqual( str(c), "r60 *1.5 -1,5.5" ) self.assertEqual( ("%g" % c.angle), "60" ) # Constructor variations self.assertEqual( str(pya.ICplxTrans()), "r0 *1 0,0" ) self.assertEqual( str(pya.ICplxTrans(1.5)), "r0 *1.5 0,0" ) self.assertEqual( str(pya.ICplxTrans(pya.Trans(1, False, 10, 20), 1.5)), "r90 *1.5 10,20" ) self.assertEqual( str(pya.ICplxTrans(pya.Trans(1, False, 10, 20))), "r90 *1 10,20" ) self.assertEqual( str(pya.ICplxTrans(1.5, 80, True, pya.Vector(100, 200))), "m40 *1.5 100,200" ) self.assertEqual( str(pya.ICplxTrans(1.5, 80, True, 100, 200)), "m40 *1.5 100,200" ) self.assertEqual( str(pya.ICplxTrans(pya.Vector(100, 200))), "r0 *1 100,200" ) self.assertEqual( str(pya.ICplxTrans(100, 200)), "r0 *1 100,200" ) self.assertEqual( str(pya.ICplxTrans(pya.ICplxTrans(100, 200))), "r0 *1 100,200" ) self.assertEqual( str(pya.ICplxTrans(pya.ICplxTrans(100, 200), 1.5)), "r0 *1.5 150,300" ) self.assertEqual( str(pya.ICplxTrans(pya.ICplxTrans(100, 200), 1.5, pya.Vector(10, 20))), "r0 *1.5 160,320" ) self.assertEqual( str(pya.ICplxTrans(pya.ICplxTrans(100, 200), 1.5, 10, 20)), "r0 *1.5 160,320" ) self.assertEqual( str(pya.DCplxTrans()), "r0 *1 0,0" ) self.assertEqual( str(pya.DCplxTrans(1.5)), "r0 *1.5 0,0" ) self.assertEqual( str(pya.DCplxTrans(pya.DTrans(1, False, 0.01, 0.02), 1.5)), "r90 *1.5 0.01,0.02" ) self.assertEqual( str(pya.DCplxTrans(pya.DTrans(1, False, 0.01, 0.02))), "r90 *1 0.01,0.02" ) self.assertEqual( str(pya.DCplxTrans(1.5, 80, True, pya.DVector(0.1, 0.2))), "m40 *1.5 0.1,0.2" ) self.assertEqual( str(pya.DCplxTrans(1.5, 80, True, 0.1, 0.2)), "m40 *1.5 0.1,0.2" ) self.assertEqual( str(pya.DCplxTrans(pya.DVector(0.1, 0.2))), "r0 *1 0.1,0.2" ) self.assertEqual( str(pya.DCplxTrans(0.1, 0.2)), "r0 *1 0.1,0.2" ) self.assertEqual( str(pya.DCplxTrans(pya.DCplxTrans(0.1, 0.2))), "r0 *1 0.1,0.2" ) self.assertEqual( str(pya.DCplxTrans(pya.DCplxTrans(0.1, 0.2), 1.5)), "r0 *1.5 0.15,0.3" ) self.assertEqual( str(pya.DCplxTrans(pya.DCplxTrans(0.1, 0.2), 1.5, pya.DVector(0.01, 0.02))), "r0 *1.5 0.16,0.32" ) self.assertEqual( str(pya.DCplxTrans(pya.DCplxTrans(0.1, 0.2), 1.5, 0.01, 0.02)), "r0 *1.5 0.16,0.32" )
def produce_impl(self): # fetch the parameters dbu = self.layout.dbu ly = self.layout LayerSi = self.layer LayerSiN = ly.layer(self.layer) LayerPinRecN = ly.layer(self.pinrec) LayerDevRecN = ly.layer(self.devrec) LayerTextN = ly.layer(self.textl) LayerInvert=ly.layer(self.invert) n_vertices = int(self.vertices) a = self.a/dbu r = self.r/dbu n_x = int(math.ceil(self.x/2)) n_y = int(math.ceil(self.y/2)) positive=bool(self.positive) minimum_feature=self.feature_size apodized=bool(self.apodized) length_slab_x = 2*n_x*a length_slab_y = 2*(n_y-2)*a k = 2 #function to creat polygon pts for right half of a hole in a hexagon unit cell def circle(x,y,r): npts = n_vertices theta = 2 * math.pi / npts # increment, in radians pts = [] for i in range(0, npts): pts.append(Point.from_dpoint(pya.DPoint((x+r*math.cos(i*theta))/1, (y+r*math.sin(i*theta))/1))) return pts def hexagon_hole_half(a,r): npts = 10 theta_div = math.pi/3 theta_div_hole = math.pi/npts triangle_length = a/math.sqrt(3) pts = [] for i in range(0,4): pts.append(Point.from_dpoint(pya.DPoint(triangle_length*math.cos(i*theta_div-math.pi/2), triangle_length*math.sin(i*theta_div-math.pi/2)))) for i in range(0, npts+1): pts.append(Point.from_dpoint(pya.DPoint(r*math.cos(math.pi/2-i*theta_div_hole), r*math.sin(math.pi/2-i*theta_div_hole)))) return pts def hexagon_shifthole_half(a,r): npts = 10 theta_div = math.pi/3 theta_div_hole = math.pi/npts triangle_length = a*1.235/math.sqrt(3) pts = [] for i in range(0,4): pts.append(Point.from_dpoint(pya.DPoint(triangle_length*math.cos(i*theta_div-math.pi/2), triangle_length*math.sin(i*theta_div-math.pi/2)))) for i in range(0, npts+1): pts.append(Point.from_dpoint(pya.DPoint(r*math.cos(math.pi/2-i*theta_div_hole), r*math.sin(math.pi/2-i*theta_div_hole)))) return pts #function to creat polygon pts for right half of a hexagon unit cell def hexagon_half(a): theta_div = math.pi/3 triangle_length = a/math.sqrt(3) pts = [] for i in range(0,4): pts.append(Point.from_dpoint(pya.DPoint(triangle_length*math.cos(i*theta_div-math.pi/2), triangle_length*math.sin(i*theta_div-math.pi/2)))) return pts #create the right and left half of the hole and hexagon cells #hole_cell = pya.Region() #hexagon_cell = pya.Region() # Define Si slab and hole region for future subtraction Si_slab = pya.Region() Si_slab.insert(pya.Box(-length_slab_x/2+a*2, -length_slab_y/2, length_slab_x/2-a, length_slab_y/2)) hole = pya.Region() hole_r = r # function to generate points to create a circle def circle(x,y,r): npts = n_vertices theta = 2 * math.pi / npts # increment, in radians pts = [] for i in range(0, npts): pts.append(Point.from_dpoint(pya.DPoint((x+r*math.cos(i*theta))/1, (y+r*math.sin(i*theta))/1))) return pts import numpy as np def gaussian(x, mu, sig): return 1./(np.sqrt(2.*np.pi)*sig)*np.exp(-np.power((x - mu)/sig, 2.)/2) # raster through all holes with shifts and waveguide for j in range(-n_y,n_y+1): if j%2 == 0: skip=0 apodization=0 for i in range(-n_x,n_x+1): if i==0: continue if skip==0: skip=1 continue elif skip==1: skip=2 continue elif skip==2: skip=3 apodization=apodization+1 continue elif skip==3: skip=1 #radius=r/gaussian(float(i)/(2*(n_x+1)),2*(n_x+1),10) location=float(i) location=abs(location) #radius=r/gaussian(location/(2*(n_x+1)),2*(n_x+1),0.02) #radius=(((2*n_x)-abs(i+n_x+3)*r)/(2*n_x)) radius=(float(apodization)/((n_x*2/3)-1))*r if radius<minimum_feature*500: radius=minimum_feature*500 if apodized==False: radius=r #radius=minimum_feature hole_cell = circle(0,0,radius) hole_poly = pya.Polygon(hole_cell) print("x1 "+str(apodization)) hole_x = abs(i)/i*(abs(i)-0.5)*a hole_y = j*a*math.sqrt(3)/2 hole_trans = pya.Trans(Trans.R0, hole_x,hole_y) hole_t = hole_poly.transformed(hole_trans) hole.insert(hole_t) elif j%2 == 1: skipodd=0 apodization=0 for i in range(-n_x,n_x+1): if i==-n_x: continue if i==n_x: continue if skipodd==0: skipodd=1 continue elif skipodd==1: skipodd=2 apodization=apodization+1 continue elif skipodd==2: skipodd=3 elif skipodd==3: skipodd=1 #radius=(((2*n_x)-abs(i+n_x+3)*r)/(2*n_x)) radius=(float(apodization)/((n_x*2/3)-1))*r if radius<minimum_feature*500: radius=minimum_feature*500 if apodized==False: radius=r #radius=minimum_feature #radius=r*(float(abs(i))/(2*(n_x+1))) hole_cell = circle(0,0,radius) hole_poly = pya.Polygon(hole_cell) print("x2 "+str(apodization)) print("p "+str(n_x)) hole_x = i*a hole_y = j*a*math.sqrt(3)/2 hole_trans = pya.Trans(Trans.R0, hole_x,hole_y) hole_t = hole_poly.transformed(hole_trans) hole.insert(hole_t) if positive==True: phc = hole else: phc = Si_slab - hole self.cell.shapes(LayerSiN).insert(phc) #print(hole_t_0) box_l = a/2 # Pins on the waveguide: pin_length = 200 pin_w = a t = pya.Trans(Trans.R0, -length_slab_x/2+a*2,0) pin = pya.Path([pya.Point(-pin_length/2, 0), pya.Point(pin_length/2, 0)], pin_w) pin_t = pin.transformed(t) self.cell.shapes(LayerPinRecN).insert(pin_t) text = pya.Text ("pin1", t) shape = self.cell.shapes(LayerPinRecN).insert(text) shape.text_size = 0.4/dbu # Create the device recognition layer -- make it 1 * wg_width away from the waveguides. points = [[-length_slab_x/2+a*2,0], [length_slab_x/2-a, 0]] points = [Point(each[0], each[1]) for each in points] path = Path(points, length_slab_y) self.cell.shapes(LayerDevRecN).insert(path.simple_polygon()) if positive==True: self.cell.shapes(LayerInvert).insert(path.simple_polygon()) return hole = pya.Region() hole_cell_pts = hexagon_hole_half(a,r) hexagon_pts = hexagon_half(a) hole_shiftcell_pts = hexagon_shifthole_half(a,r) hole_cell_poly_0 = pya.Polygon(hole_cell_pts) hexagon_cell_poly_0 = pya.Polygon(hexagon_pts) hole_shiftcell_poly_0 = pya.Polygon(hole_shiftcell_pts) hole_trans = pya.Trans(pya.Trans.R180) hole_cell_poly_1 = hole_cell_poly_0.transformed(hole_trans) hexagon_cell_poly_1 = hexagon_cell_poly_0.transformed(hole_trans) hole_shiftcell_poly_1 = hole_shiftcell_poly_0.transformed(hole_trans) skip=1 skip2=0 #create the photonic crystal with shifts and waveguides for j in range(-y+1,y): if j%2 == 0: for i in range(-x,x+1): #waveguide if (j == k and i > 3): hole_x = abs(i)/i*(abs(i)-0.5)*a hole_y = j*a*math.sqrt(3)/2 hole_trans = pya.Trans(Trans.R0, hole_x,hole_y) hole_t_0 = hole_cell_poly_0.transformed(hole_trans) hole_t_1 = hole_cell_poly_1.transformed(hole_trans) hole.insert(hole_t_0) hole.insert(hole_t_1) #filling the edges with half cell elif i!=0: hole_x = abs(i)/i*(abs(i)-0.5)*a hole_y = j*a*math.sqrt(3)/2 hole_trans = pya.Trans(Trans.R0, hole_x,hole_y) hole_t_0 = hole_cell_poly_0.transformed(hole_trans) hole_t_1 = hole_cell_poly_1.transformed(hole_trans) hole.insert(hole_t_0) hole.insert(hole_t_1) elif j%2 == 1: for i in range(-x,x+1): if skip==0 and i%3==0: skip=1 continue if skip==1: skip=2 continue if skip==2: skip=0 if i== -x: hole_x = abs(i)/i*(abs(i)-0.5)*a hole_y = j*a*math.sqrt(3)/2 hole_trans = pya.Trans(Trans.R0, hole_x,hole_y) hole_t_1 = hexagon_cell_poly_1.transformed(hole_trans) hole.insert(hole_t_1) if i== x: hole_x = abs(i)/i*(abs(i)-0.5)*a hole_y = j*a*math.sqrt(3)/2 hole_trans = pya.Trans(Trans.R0, hole_x,hole_y) hole_t_0 = hexagon_cell_poly_0.transformed(hole_trans) hole.insert(hole_t_0) #waveguide if (j == k and i > 3): hole_x =i*a hole_y =j*a*math.sqrt(3)/2 hole_trans = pya.Trans(Trans.R0, hole_x,hole_y) hole_t_0 = hexagon_cell_poly_0.transformed(hole_trans) hole_t_1 = hexagon_cell_poly_1.transformed(hole_trans) hole.insert(hole_t_0) hole.insert(hole_t_1) #filling the edges with half cell elif i in (-x,x): hole_x =i*a hole_y =j*a*math.sqrt(3)/2 hole_trans = pya.Trans(Trans.R0, hole_x,hole_y) if i == -x: hole_t = hole_cell_poly_0.transformed(hole_trans) else: hole_t = hole_cell_poly_1.transformed(hole_trans) hole.insert(hole_t) else: hole_x = i*a hole_y = j*a*math.sqrt(3)/2 hole_trans = pya.Trans(Trans.R0, hole_x,hole_y) hole_t_0 = hole_cell_poly_0.transformed(hole_trans) hole_t_1 = hole_cell_poly_1.transformed(hole_trans) hole.insert(hole_t_0) hole.insert(hole_t_1) #print(hole_t_0) box_l = a/2 cover_box = pya.Box(-length_slab_x/2, -a/2, length_slab_x/2, a/2) box_y = y*a*math.sqrt(3)/2 cover_box_trans_0 = pya.Trans(Trans.R0, 0,box_y) cover_box_trans_1 = pya.Trans(Trans.R0, 0,-box_y) cover_box_t_0 = cover_box.transformed(cover_box_trans_0) cover_box_t_1 = cover_box.transformed(cover_box_trans_1) #hole.insert(pya.Box()) self.cell.shapes(LayerSiN).insert(hole) self.cell.shapes(LayerSiN).insert(cover_box_t_0) self.cell.shapes(LayerSiN).insert(cover_box_t_1) # Pins on the waveguide: pin_length = 200 pin_w = a t = pya.Trans(Trans.R0, -length_slab_x/2,0) pin = pya.Path([pya.Point(-pin_length/2, 0), pya.Point(pin_length/2, 0)], pin_w) pin_t = pin.transformed(t) self.cell.shapes(LayerPinRecN).insert(pin_t) text = pya.Text ("pin1", t) shape = self.cell.shapes(LayerPinRecN).insert(text) shape.text_size = 0.4/dbu # Create the device recognition layer -- make it 1 * wg_width away from the waveguides. points = [[-length_slab_x/2,0], [length_slab_x/2, 0]] points = [Point(each[0], each[1]) for each in points] path = Path(points, length_slab_y) self.cell.shapes(LayerDevRecN).insert(path.simple_polygon())
def produce_impl(self): # This is the main part of the implementation: create the layout from math import pi, cos, sin from SiEPIC.extend import to_itype # fetch the parameters # TECHNOLOGY = get_technology_by_name('GSiP') dbu = self.layout.dbu ly = self.layout shapes = self.cell.shapes LayerSi3N = ly.layer(self.si3layer) LayerSiN = ly.layer(self.silayer) LayernN = ly.layer(self.nlayer) LayerpN = ly.layer(self.player) LayernpN = ly.layer(self.nplayer) LayerppN = ly.layer(self.pplayer) LayernppN = ly.layer(self.npplayer) LayerpppN = ly.layer(self.ppplayer) LayervcN = ly.layer(self.vclayer) Layerm1N = ly.layer(self.m1layer) LayervlN = ly.layer(self.vllayer) LayermlN = ly.layer(self.mllayer) LayermhN = ly.layer(self.mhlayer) TextLayerN = ly.layer(self.textl) LayerPinRecN = ly.layer(self.pinrec) LayerDevRecN = ly.layer(self.devrec) # Define variables for the Modulator # Variables for the Si waveguide w = to_itype(self.w,dbu) r = to_itype(self.r,dbu) g = to_itype(self.g,dbu) gmon = to_itype(self.gmon,dbu) #Variables for the N layer w_1 = 2.0/dbu #same for N, P, N+, P+ layer r_n = to_itype(self.r - 1.0,dbu) #Variables for the P layer r_p = to_itype(self.r + 1.0, dbu) #Variables for the N+layer r_np = to_itype(self.r - 1.5,dbu) #Variables for the P+layer r_pp = to_itype(self.r + 1.5,dbu) #Variables for the N++ layer w_2 = to_itype(5.5,dbu) #same for N++, P++ layer r_npp = to_itype(self.r - 3.75,dbu) #Variables for the P+layer r_ppp = to_itype(self.r + 3.75,dbu) #Variables for the VC layer w_vc = to_itype(4.0,dbu) r_vc1 = to_itype(self.r - 3.75,dbu) r_vc2 = to_itype(self.r + 3.75,dbu) #Variables for the M1 layer w_m1_in = r_vc1 + w_vc/2.0 + to_itype(0.5,dbu) r_m1_in = r_vc1 + w_vc/2.0 + to_itype(0.5,dbu) /2.0 w_m1_out = to_itype(6.0,dbu) r_m1_out = to_itype(self.r + 4.25,dbu) #Variables for the VL layer #r_vl = w_m1_in/2.0 - 2.1/dbu r_vl = r_vc1 - w_vc/2.0 - to_itype(2.01,dbu) if r_vl < to_itype(1.42,dbu): r_vl = to_itype(1.42,dbu) w_vc = r - to_itype(1.75,dbu) - (r_vl + 2.01) r_vc1 = r - to_itype(1.75,dbu) - w_vc/2.0 r_vc2 = r + to_itype(1.75,dbu) + w_vc/2.0 w_2 = (r-w/2.0 - to_itype(0.75,dbu)) - (r_vc1 - w_vc/2.0 - 0.75) # same for N++, P++ layer r_npp = ((r-w/2.0 - to_itype(0.75,dbu)) + (r_vc1 - w_vc/2.0 - 0.75))/2.0 r_ppp = 2*r - r_npp w_via = to_itype(5.0,dbu) h_via = to_itype(5.0,dbu) # Variables for the SiEtch2 layer (Slab) w_Si3 = round(w_m1_out + 2*(r_m1_out)+ 0/dbu) h_Si3 = w_Si3 taper_bigend = to_itype(2,dbu) taper_smallend = to_itype(0.3,dbu) taper_length = to_itype(5,dbu) #Variables for the MH layer w_mh = to_itype(2.0,dbu) r_mh = r r_mh_in = r_mh - w_mh/2.0 #Define Ring centre x0 = r + w/2 y0 = r + g + w ###################### # Generate the layout: # Create the ring resonator t = pya.Trans(pya.Trans.R0,x0, y0) pcell = ly.create_cell("Ring", "GSiP", { "layer": self.silayer, "radius": self.r, "width": self.w } ) self.cell.insert(pya.CellInstArray(pcell.cell_index(), t)) # Create the two waveguides wg1 = pya.Box(x0 - (w_Si3 / 2 + taper_length), -w/2, x0 + (w_Si3 / 2 + taper_length), w/2) shapes(LayerSiN).insert(wg1) y_offset = 2*r + g + gmon + 2*w wg2 = pya.Box(x0 - (w_Si3 / 2 + taper_length), y_offset-w/2, x0 + (w_Si3 / 2 + taper_length), y_offset+w/2) shapes(LayerSiN).insert(wg2) #Create the SiEtch2 (Slab) layer boxSi3 = pya.Box(x0-w_Si3/2.0, y0 - h_Si3/2.0, x0+w_Si3/2.0, y0 + h_Si3/2.0) shapes(LayerSi3N).insert(boxSi3) pin1pts = [pya.Point(x0-w_Si3/2.0, -taper_bigend/2.0), pya.Point(x0-w_Si3/2.0-taper_length,-taper_smallend/2.0), pya.Point(x0-w_Si3/2.0-taper_length,taper_smallend/2.0), pya.Point(x0-w_Si3/2.0, taper_bigend/2.0)] pin2pts = [pya.Point(x0+w_Si3/2.0,-taper_bigend/2.0), pya.Point(x0+w_Si3/2.0+taper_length,-taper_smallend/2.0), pya.Point(x0+w_Si3/2.0+taper_length,taper_smallend/2.0), pya.Point(x0+w_Si3/2.0,+taper_bigend/2.0)] pin3pts = [pya.Point(x0-w_Si3/2.0,y_offset-taper_bigend/2.0), pya.Point(x0-w_Si3/2.0-taper_length,y_offset-taper_smallend/2.0), pya.Point(x0-w_Si3/2.0-taper_length,y_offset+taper_smallend/2.0), pya.Point(x0-w_Si3/2.0,y_offset+ taper_bigend/2.0)] pin4pts = [pya.Point(x0+w_Si3/2.0,y_offset-taper_bigend/2.0), pya.Point(x0+w_Si3/2.0+taper_length,y_offset-taper_smallend/2.0), pya.Point(x0+w_Si3/2.0+taper_length,y_offset+taper_smallend/2.0), pya.Point(x0+w_Si3/2.0,y_offset+taper_bigend/2.0)] shapes(LayerSi3N).insert(pya.Polygon(pin1pts)) shapes(LayerSi3N).insert(pya.Polygon(pin2pts)) shapes(LayerSi3N).insert(pya.Polygon(pin3pts)) shapes(LayerSi3N).insert(pya.Polygon(pin4pts)) # arc angles # doping: angle_min_doping = -35 angle_max_doping = 215 # VC contact: angle_min_VC = angle_min_doping + 8 angle_max_VC = angle_max_doping - 8 # M1: angle_min_M1 = angle_min_VC - 4 angle_max_M1 = angle_max_VC + 4 # MH: angle_min_MH = -75.0 angle_max_MH = 255 from SiEPIC.utils import arc #Create the N Layer self.cell.shapes(LayernN).insert(pya.Path(arc(r_n, angle_min_doping, angle_max_doping), w_1).transformed(t).simple_polygon()) #Create the P Layer self.cell.shapes(LayerpN).insert(pya.Path(arc(r_p, angle_min_doping, angle_max_doping), w_1).transformed(t).simple_polygon()) #Create the N+ Layer self.cell.shapes(LayernpN).insert(pya.Path(arc(r_np, angle_min_doping, angle_max_doping), w_1).transformed(t).simple_polygon()) #Create the P+ Layer self.cell.shapes(LayerppN).insert(pya.Path(arc(r_pp, angle_min_doping, angle_max_doping), w_1).transformed(t).simple_polygon()) #Create the N++ Layer self.cell.shapes(LayernppN).insert(pya.Path(arc(r_npp, angle_min_doping, angle_max_doping), w_2).transformed(t).simple_polygon()) #Create the P+ +Layer poly = pya.Path(arc(r_ppp, angle_min_doping, angle_max_doping), w_2).transformed(t).simple_polygon() self.cell.shapes(LayerpppN).insert(pya.Region(poly) - pya.Region(pya.Box(x0-r_ppp-w_2/2, y_offset-w/2 - 0.75/dbu, x0+r_ppp+w/2, y_offset+w/2 + 0.75/dbu))) #Create the VC Layer self.cell.shapes(LayervcN).insert(pya.Path(arc(r_vc1, angle_min_VC, angle_max_VC), w_vc).transformed(t).simple_polygon()) poly = pya.Path(arc(r_vc2, angle_min_VC, angle_max_VC), w_vc).transformed(t).simple_polygon() self.cell.shapes(LayervcN).insert(pya.Region(poly) - pya.Region(pya.Box(x0-r_vc2-w_vc/2, y_offset-w/2 - 1.5/dbu, x0+r_vc2+w_vc/2, y_offset+w/2 + 1.5/dbu))) #Create the M1 Layer self.cell.shapes(Layerm1N).insert(pya.Polygon(arc(w_m1_in, angle_min_doping, angle_max_doping) + [pya.Point(0, 0)]).transformed(t)) self.cell.shapes(Layerm1N).insert(pya.Polygon(arc(w_m1_in/2.0, 0, 360)).transformed(t)) self.cell.shapes(Layerm1N).insert(pya.Path(arc(r_m1_out, angle_min_M1, angle_max_M1), w_m1_out).transformed(t).simple_polygon()) boxM11 = pya.Box(x0-w_via, y0 + r_m1_out + w_m1_out-h_via, x0+w_via, y0 + r_m1_out + w_m1_out+h_via) shapes(Layerm1N).insert(boxM11) #Create the ML Layer self.cell.shapes(LayermlN).insert(pya.Polygon(arc(w_m1_in/2.0, 0, 360)).transformed(t)) #Create the VL Layer, as well as the electrical PinRec geometries # centre contact (P, anode): self.cell.shapes(LayervlN).insert(pya.Polygon(arc(r_vl, 0, 360)).transformed(t)) self.cell.shapes(LayerPinRecN).insert(pya.Polygon(arc(r_vl, 0, 360)).transformed(t)) shapes(LayerPinRecN).insert(pya.Text ("elec1a", pya.Trans(pya.Trans.R0,x0,y0))).text_size = 0.5/dbu shapes(LayerPinRecN).insert(pya.Box(x0-w_via/2, y0-w_via/2, x0+w_via/2, y0+w_via/2)) # top contact (N, cathode): boxVL1 = pya.Box(x0-w_via/2, y0 + r_vc2 + w_vc/2 + 2.0/dbu, x0+w_via/2, y0 + r_vc2 + w_vc/2 + 2.0/dbu+ h_via) shapes(LayervlN).insert(boxVL1) shapes(LayerPinRecN).insert(boxVL1) shapes(LayerPinRecN).insert(pya.Text ("elec1c", pya.Trans(pya.Trans.R0,x0,y0 + r_vc2 + w_vc/2 + 2.0/dbu+ h_via/2))).text_size = 0.5/dbu # heater contacts boxVL3 = pya.Box(x0+(r_mh_in)*cos(angle_min_MH/180*pi) + 2.5/dbu, -w/2.0 - 10/dbu, x0 + (r_mh_in)*cos(angle_min_MH/180*pi) + 7.5/dbu, -w/2.0 - 5/dbu) shapes(LayervlN).insert(boxVL3) shapes(LayerPinRecN).insert(boxVL3) shapes(LayerPinRecN).insert(pya.Text ("elec2h2", pya.Trans(pya.Trans.R0,x0+(r_mh_in)*cos(angle_min_MH/180*pi) + 5.0/dbu,-w/2.0 - 7.5/dbu))).text_size = 0.5/dbu boxVL4 = pya.Box(x0-(r_mh_in)*cos(angle_min_MH/180*pi)- 7.5/dbu, -w/2.0 - 10/dbu, x0 - (r_mh_in)*cos(angle_min_MH/180*pi) - 2.5/dbu, -w/2.0 - 5/dbu) shapes(LayervlN).insert(boxVL4) shapes(LayerPinRecN).insert(boxVL4) shapes(LayerPinRecN).insert(pya.Text ("elec2h1", pya.Trans(pya.Trans.R0,x0-(r_mh_in)*cos(angle_min_MH/180*pi) - 5.0/dbu,-w/2.0 - 7.5/dbu))).text_size = 0.5/dbu #Create the MH Layer self.cell.shapes(LayermhN).insert(pya.Path(arc(r_mh, angle_min_MH, angle_max_MH), w_mh).transformed(t).simple_polygon()) boxMH1 = pya.Box(x0+(r_mh_in)*cos(angle_min_MH/180*pi), -w/2.0 - 2.5/dbu, x0 + (r_mh_in)*cos(angle_min_MH/180*pi) + w_mh, y0 +(r_mh_in)*sin(angle_min_MH/180*pi)) shapes(LayermhN).insert(boxMH1) boxMH2 = pya.Box(x0-(r_mh_in)*cos(angle_min_MH/180*pi) - w_mh, -w/2.0 - 2.5/dbu, x0 - (r_mh_in)*cos(angle_min_MH/180*pi), y0 +(r_mh_in)*sin(angle_min_MH/180*pi)) shapes(LayermhN).insert(boxMH2) boxMH3 = pya.Box(x0+(r_mh_in)*cos(angle_min_MH/180*pi), -w/2.0 - 12.5/dbu, x0 + (r_mh_in)*cos(angle_min_MH/180*pi) + 10/dbu, -w/2.0 - 2.5/dbu) shapes(LayermhN).insert(boxMH3) boxMH4 = pya.Box(x0-(r_mh_in)*cos(angle_min_MH/180*pi)- 10/dbu, -w/2.0 - 12.5/dbu, x0 - (r_mh_in)*cos(angle_min_MH/180*pi), -w/2.0 - 2.5/dbu) shapes(LayermhN).insert(boxMH4) # Create the pins, as short paths: from SiEPIC._globals import PIN_LENGTH as pin_length shapes(LayerPinRecN).insert(pya.Path([pya.Point(x0 - (w_Si3 / 2. + taper_length) + pin_length/2., 0), pya.Point(x0 - (w_Si3 / 2. + taper_length) - pin_length/2., 0)], w)) shapes(LayerPinRecN).insert(pya.Text("opt1", pya.Trans(pya.Trans.R0,x0 - (w_Si3 / 2. + taper_length), 0))).text_size = 0.5/dbu shapes(LayerPinRecN).insert(pya.Path([pya.Point(x0 + (w_Si3 / 2. + taper_length) - pin_length/2., 0), pya.Point(x0 + (w_Si3 / 2. + taper_length) + pin_length/2., 0)], w)) shapes(LayerPinRecN).insert(pya.Text("opt2", pya.Trans(pya.Trans.R0,x0 + (w_Si3 / 2. + taper_length), 0))).text_size = 0.5/dbu shapes(LayerPinRecN).insert(pya.Path([pya.Point(x0 - (w_Si3 / 2. + taper_length) + pin_length/2., y_offset), pya.Point(x0 - (w_Si3 / 2. + taper_length) - pin_length/2., y_offset)], w)) shapes(LayerPinRecN).insert(pya.Text("opt3", pya.Trans(pya.Trans.R0,x0 - (w_Si3 / 2. + taper_length), y_offset))).text_size = 0.5/dbu shapes(LayerPinRecN).insert(pya.Path([pya.Point(x0 + (w_Si3 / 2. + taper_length) - pin_length/2., y_offset), pya.Point(x0 + (w_Si3 / 2. + taper_length) + pin_length/2., y_offset)], w)) shapes(LayerPinRecN).insert(pya.Text("opt4", pya.Trans(pya.Trans.R0,x0 + (w_Si3 / 2. + taper_length), y_offset))).text_size = 0.5/dbu # Create the device recognition layer shapes(LayerDevRecN).insert(pya.Box(x0 - (w_Si3 / 2 + taper_length), -w/2.0 - 12.5/dbu, x0 + (w_Si3 / 2 + taper_length), y0 + r_m1_out + w_m1_out+h_via )) # Compact model information shape = shapes(LayerDevRecN).insert(pya.Text('Lumerical_INTERCONNECT_library=Design kits/GSiP', \ pya.Trans(pya.Trans.R0,0, 0))).text_size = 0.3/dbu shapes(LayerDevRecN).insert(pya.Text('Component=Ring_Modulator_DB', \ pya.Trans(pya.Trans.R0,0, w*2))).text_size = 0.3/dbu shapes(LayerDevRecN).insert(pya.Text('Component_ID=%s' % self.component_ID, \ pya.Trans(pya.Trans.R0,0, w*4))).text_size = 0.3/dbu shapes(LayerDevRecN).insert(pya.Text \ ('Spice_param:radius=%.3fu wg_width=%.3fu gap=%.3fu gap_monitor=%.3fu' %\ (self.r, self.w, self.g, self.gmon), \ pya.Trans(pya.Trans.R0,0, -w*2) ) ).text_size = 0.3/dbu # Add a polygon text description from SiEPIC.utils import layout_pgtext if self.textpolygon : layout_pgtext(self.cell, self.textl, self.w, self.r+self.w, "%.3f-%g" % ( self.r, self.g), 1) # Reference publication: shapes(TextLayerN).insert(pya.Text ("Ref: Raphael Dube-Demers, JLT, 2015", pya.Trans(pya.Trans.R0,x0 - (w_Si3 / 2 + taper_length), -w/2.0 - 12.5/dbu+4.0/dbu))).text_size = 0.7/dbu shapes(TextLayerN).insert(pya.Text ("http://dx.doi.org/10.1109/JLT.2015.2462804", pya.Trans(pya.Trans.R0,x0 - (w_Si3 / 2 + taper_length), -w/2.0 - 12.5/dbu+1.0/dbu))).text_size = 0.7/dbu
def produce_impl(self): # This is the main part of the implementation: create the layout from math import pi, cos, sin from SiEPIC.extend import to_itype # fetch the parameters # TECHNOLOGY = get_technology_by_name('GSiP') dbu = self.layout.dbu ly = self.layout shapes = self.cell.shapes LayerSi = self.silayer LayerSi3 = ly.layer(self.si3layer) LayerSiN = ly.layer(LayerSi) LayervlN = ly.layer(self.vllayer) LayermlN = ly.layer(self.mllayer) LayermhN = ly.layer(self.mhlayer) TextLayerN = ly.layer(self.textl) LayerPinRecN = ly.layer(self.pinrec) LayerDevRecN = ly.layer(self.devrec) # Define variables for the Modulator # Variables for the Si waveguide w = to_itype(self.w, dbu) r = to_itype(self.r, dbu) g = to_itype(self.g, dbu) gmon = to_itype(self.gmon, dbu) #Variables for the N layer w_1 = 2.0 / dbu #same for N, P, N+, P+ layer r_n = to_itype(self.r - 1.0, dbu) #Variables for the VC layer w_vc = to_itype(4.0, dbu) r_vc1 = to_itype(self.r - 3.75, dbu) r_vc2 = to_itype(self.r + 3.75, dbu) #Variables for the M1 layer w_m1_in = r_vc1 + w_vc / 2.0 + to_itype(0.5, dbu) r_m1_in = r_vc1 + w_vc / 2.0 + to_itype(0.5, dbu) / 2.0 w_m1_out = to_itype(6.0, dbu) r_m1_out = to_itype(self.r + 4.25, dbu) #Variables for the VL layer r_vl = w_m1_in / 2.0 - to_itype(2.1, dbu) w_via = to_itype(5.0, dbu) h_via = to_itype(5.0, dbu) # Variables for the SiEtch2 layer (Slab) w_Si3 = w_m1_out + 2 * (r_m1_out) h_Si3 = w_Si3 taper_bigend = to_itype(2, dbu) taper_smallend = to_itype(0.3, dbu) taper_length = to_itype(5, dbu) #Variables for the MH layer w_mh = to_itype(2.0, dbu) r_mh = r r_mh_in = r_mh - w_mh / 2.0 #Define Ring centre x0 = r + w / 2 y0 = r + g + w ###################### # Generate the layout: # Create the ring resonator t = pya.Trans(pya.Trans.R0, (self.r + self.w / 2) / dbu, (self.r + self.g + self.w) / dbu) pcell = ly.create_cell("Ring", "GSiP", { "layer": LayerSi, "radius": self.r, "width": self.w }) self.cell.insert(pya.CellInstArray(pcell.cell_index(), t)) # Create the two waveguides wg1 = pya.Box(x0 - (w_Si3 / 2 + taper_length), -w / 2, x0 + (w_Si3 / 2 + taper_length), w / 2) shapes(LayerSiN).insert(wg1) y_offset = 2 * r + g + gmon + 2 * w wg2 = pya.Box(x0 - (w_Si3 / 2 + taper_length), y_offset - w / 2, x0 + (w_Si3 / 2 + taper_length), y_offset + w / 2) shapes(LayerSiN).insert(wg2) #Create the SiEtch2 (Slab) layer boxSi3 = pya.Box(x0 - w_Si3 / 2.0, y0 - h_Si3 / 2.0, x0 + w_Si3 / 2.0, y0 + h_Si3 / 2.0) shapes(LayerSi3).insert(boxSi3) pin1pts = [ pya.Point(x0 - w_Si3 / 2.0, -taper_bigend / 2.0), pya.Point(x0 - w_Si3 / 2.0 - taper_length, -taper_smallend / 2.0), pya.Point(x0 - w_Si3 / 2.0 - taper_length, taper_smallend / 2.0), pya.Point(x0 - w_Si3 / 2.0, taper_bigend / 2.0) ] pin2pts = [ pya.Point(x0 + w_Si3 / 2.0, -taper_bigend / 2.0), pya.Point(x0 + w_Si3 / 2.0 + taper_length, -taper_smallend / 2.0), pya.Point(x0 + w_Si3 / 2.0 + taper_length, taper_smallend / 2.0), pya.Point(x0 + w_Si3 / 2.0, +taper_bigend / 2.0) ] pin3pts = [ pya.Point(x0 - w_Si3 / 2.0, y_offset - taper_bigend / 2.0), pya.Point(x0 - w_Si3 / 2.0 - taper_length, y_offset - taper_smallend / 2.0), pya.Point(x0 - w_Si3 / 2.0 - taper_length, y_offset + taper_smallend / 2.0), pya.Point(x0 - w_Si3 / 2.0, y_offset + taper_bigend / 2.0) ] pin4pts = [ pya.Point(x0 + w_Si3 / 2.0, y_offset - taper_bigend / 2.0), pya.Point(x0 + w_Si3 / 2.0 + taper_length, y_offset - taper_smallend / 2.0), pya.Point(x0 + w_Si3 / 2.0 + taper_length, y_offset + taper_smallend / 2.0), pya.Point(x0 + w_Si3 / 2.0, y_offset + taper_bigend / 2.0) ] shapes(LayerSi3).insert(pya.Polygon(pin1pts)) shapes(LayerSi3).insert(pya.Polygon(pin2pts)) shapes(LayerSi3).insert(pya.Polygon(pin3pts)) shapes(LayerSi3).insert(pya.Polygon(pin4pts)) from SiEPIC.utils import arc # arc angles # doping: angle_min_doping = -35 angle_max_doping = 215 # VC contact: angle_min_VC = angle_min_doping + 8 angle_max_VC = angle_max_doping - 8 # M1: angle_min_M1 = angle_min_VC - 4 angle_max_M1 = angle_max_VC + 4 # MH: angle_min_MH = -75.0 angle_max_MH = 255 #Create the VL Layer, as well as the electrical PinRec geometries # heater contacts boxVL3 = pya.Box( x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi) + 2.5 / dbu, -w / 2.0 - 10 / dbu, x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi) + 7.5 / dbu, -w / 2.0 - 5 / dbu) shapes(LayervlN).insert(boxVL3) shapes(LayerPinRecN).insert(boxVL3) shapes(LayerPinRecN).insert( pya.Text( "elec2h2", pya.Trans( pya.Trans.R0, x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi) + 5.0 / dbu, -w / 2.0 - 7.5 / dbu))).text_size = 0.5 / dbu boxVL4 = pya.Box( x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi) - 7.5 / dbu, -w / 2.0 - 10 / dbu, x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi) - 2.5 / dbu, -w / 2.0 - 5 / dbu) shapes(LayervlN).insert(boxVL4) shapes(LayerPinRecN).insert(boxVL4) shapes(LayerPinRecN).insert( pya.Text( "elec2h1", pya.Trans( pya.Trans.R0, x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi) - 5.0 / dbu, -w / 2.0 - 7.5 / dbu))).text_size = 0.5 / dbu #Create the MH Layer poly = pya.Path(arc(self.r / dbu, angle_min_MH, angle_max_MH), w_mh).transformed(t).simple_polygon() self.cell.shapes(LayermhN).insert(poly) boxMH1 = pya.Box(x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi), -w / 2.0 - 2.5 / dbu, x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi) + w_mh, y0 + (r_mh_in) * sin(angle_min_MH / 180 * pi)) shapes(LayermhN).insert(boxMH1) boxMH2 = pya.Box(x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi) - w_mh, -w / 2.0 - 2.5 / dbu, x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi), y0 + (r_mh_in) * sin(angle_min_MH / 180 * pi)) shapes(LayermhN).insert(boxMH2) boxMH3 = pya.Box( x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi), -w / 2.0 - 12.5 / dbu, x0 + (r_mh_in) * cos(angle_min_MH / 180 * pi) + 10 / dbu, -w / 2.0 - 2.5 / dbu) shapes(LayermhN).insert(boxMH3) boxMH4 = pya.Box( x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi) - 10 / dbu, -w / 2.0 - 12.5 / dbu, x0 - (r_mh_in) * cos(angle_min_MH / 180 * pi), -w / 2.0 - 2.5 / dbu) shapes(LayermhN).insert(boxMH4) # Create the pins, as short paths: from SiEPIC._globals import PIN_LENGTH as pin_length shapes(LayerPinRecN).insert( pya.Path([ pya.Point(x0 - (w_Si3 / 2 + taper_length) + pin_length / 2, 0), pya.Point(x0 - (w_Si3 / 2 + taper_length) - pin_length / 2, 0) ], w)) shapes(LayerPinRecN).insert( pya.Text( "opt1", pya.Trans(pya.Trans.R0, x0 - (w_Si3 / 2 + taper_length), 0))).text_size = 0.5 / dbu shapes(LayerPinRecN).insert( pya.Path([ pya.Point(x0 + (w_Si3 / 2 + taper_length) - pin_length / 2, 0), pya.Point(x0 + (w_Si3 / 2 + taper_length) + pin_length / 2, 0) ], w)) shapes(LayerPinRecN).insert( pya.Text( "opt2", pya.Trans(pya.Trans.R0, x0 + (w_Si3 / 2 + taper_length), 0))).text_size = 0.5 / dbu shapes(LayerPinRecN).insert( pya.Path([ pya.Point(x0 - (w_Si3 / 2 + taper_length) + pin_length / 2, y_offset), pya.Point(x0 - (w_Si3 / 2 + taper_length) - pin_length / 2, y_offset) ], w)) shapes(LayerPinRecN).insert( pya.Text( "opt3", pya.Trans(pya.Trans.R0, x0 - (w_Si3 / 2 + taper_length), y_offset))).text_size = 0.5 / dbu shapes(LayerPinRecN).insert( pya.Path([ pya.Point(x0 + (w_Si3 / 2 + taper_length) - pin_length / 2, y_offset), pya.Point(x0 + (w_Si3 / 2 + taper_length) + pin_length / 2, y_offset) ], w)) shapes(LayerPinRecN).insert( pya.Text( "opt4", pya.Trans(pya.Trans.R0, x0 + (w_Si3 / 2 + taper_length), y_offset))).text_size = 0.5 / dbu # Create the device recognition layer shapes(LayerDevRecN).insert( pya.Box(x0 - (w_Si3 / 2 + taper_length), -w / 2.0 - 12.5 / dbu, x0 + (w_Si3 / 2 + taper_length), y0 + r_m1_out + w_m1_out + h_via)) # Compact model information shape = shapes(LayerDevRecN).insert(pya.Text('Lumerical_INTERCONNECT_library=Design kits/GSiP', \ pya.Trans(pya.Trans.R0,0, 0))).text_size = 0.3/dbu shapes(LayerDevRecN).insert(pya.Text ('Component=Ring_Filter_DB', \ pya.Trans(pya.Trans.R0,0, w*2))).text_size = 0.3/dbu shapes(LayerDevRecN).insert(pya.Text('Component_ID=%s' % self.component_ID, \ pya.Trans(pya.Trans.R0,0, w*4))).text_size = 0.3/dbu shapes(LayerDevRecN).insert(pya.Text \ ('Spice_param:radius=%.3fu wg_width=%.3fu gap=%.3fu gap_monitor=%.3fu' %\ (self.r, self.w, self.g, self.gmon), \ pya.Trans(pya.Trans.R0,0, -w*2) ) ).text_size = 0.3/dbu # Add a polygon text description from SiEPIC.utils import layout_pgtext if self.textpolygon: layout_pgtext(self.cell, self.textl, self.w, self.r + self.w, "%.3f-%g" % (self.r, self.g), 1)