Beispiel #1
0
  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" )
Beispiel #2
0
  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")
Beispiel #3
0
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
Beispiel #4
0
    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())
Beispiel #5
0
    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)
Beispiel #6
0
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)
Beispiel #7
0
    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())
Beispiel #8
0
    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")
Beispiel #9
0
  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" )
Beispiel #10
0
  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
Beispiel #12
0
    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)