예제 #1
0
    def test_2_Trans(self):

        a = pya.Trans()
        b = pya.Trans(pya.Trans.M135, pya.Point(17, 5))
        ma = pya.CplxTrans(a, 0.5)
        mb = pya.CplxTrans(b, 2.0)
        u = pya.CplxTrans(a)

        self.assertEqual(str(ma), "r0 *0.5 0,0")
        self.assertEqual(str(mb), "m135 *2 17,5")

        self.assertEqual(ma == mb, False)
        self.assertEqual(ma == ma, True)
        self.assertEqual(ma != mb, True)
        self.assertEqual(ma != ma, False)

        self.assertEqual(str(mb.inverted()), "m135 *0.5 2.5,8.5")

        i = mb.dup()
        i.invert()

        self.assertEqual(str(i), "m135 *0.5 2.5,8.5")
        self.assertEqual(i * mb == u, True)
        self.assertEqual(mb * i == u, True)

        self.assertEqual(str(mb.trans(pya.Point(1, 0))), "17,3")
        self.assertEqual(str(mb.ctrans(2)), "4.0")
        self.assertEqual(str(i.ctrans(2)), "1.0")
예제 #2
0
def make_pin(cell, name, center, w, pin_length, layer, vertical=0):
    """Handy method to create a pin on a device to avoid repetitive code.

  Args:
      cell (pya cell): cell to create the pin on
      name (string): name of the pin
      center (list): center of the pin in dbu. Format: [x, y]
      w (int): width of the pin in dbu
      pin_length (int): length of the pin in dbu, change the sign to determine pin direction. Default is left-to-right.
      layer (pya layer): layer to create the pin on
      vertical (int, optional): flag to determine if pin is vertical or horizontal. Defaults to 0.
  """
    if vertical == 0:
        p1 = pya.Point(center[0] + pin_length / 2, center[1])
        p2 = pya.Point(center[0] - pin_length / 2, center[1])
    elif vertical == 1:
        p1 = pya.Point(center[0], center[1] + pin_length / 2)
        p2 = pya.Point(center[0], center[1] - pin_length / 2)

    pin = pya.Path([p1, p2], w)
    t = Trans(Trans.R0, center[0], center[1])
    text = Text(name, t)
    shape = cell.shapes(layer).insert(text)
    shape.text_size = 0.1
    cell.shapes(layer).insert(pin)

    return shape
예제 #3
0
파일: arrow.py 프로젝트: jurask/ShapeLib
 def transformation_from_shape_impl(self):
   w = self.shape.bbox().width()
   h = self.shape.bbox().height()
   if w > h:
     return pya.Trans(3, False, pya.Point(self.shape.bbox().center().x+0.1*w, self.shape.bbox().center().y))
   else:
     return pya.Trans(pya.Point(self.shape.bbox().center().x, self.shape.bbox().center().y+0.1*h))
예제 #4
0
    def circle(self, diameter, vertices=128):
        '''
      circle(diameter, vertices)
      
      Generates a circle shape
      
      Parameters
      ---------
      diameter : integer
            The diameter of a circle
      vertices : integer (128)
            Number of vertices in the circle (coerce to multiple of 4)
      
      Returns
      ------
      region : [pya.Region]
           A region containing the circle shape
      
      Description
      ------
      The number of vertices is coerced to even numbers to ensure good fracturing
      '''
        r = int(diameter / 2)
        vertices = int(vertices / 4) * 4

        # Create a circle
        polygon = pya.Polygon([
            pya.Point(-r, -r),
            pya.Point(-r, r),
            pya.Point(r, r),
            pya.Point(r, -r)
        ])
        polygon = polygon.round_corners(0, r, vertices)

        return pya.Region(polygon)
예제 #5
0
def layout_taper(cell, layer, trans, w1, w2, length, insert=True):
    """ Lays out a taper

    Args:
        trans: pya.Trans: location and rotation
        w1: width of waveguide, float for DPoint type (microns); int for Point type (nm)
        w2: width of waveguide, float for DPoint type (microns); int for Point type (nm)
        length: length, float
        insert: flag to insert drawn waveguide or return shape, boolean

    """
    import pya
    if type(w1) == type(float()):
        pts = [
            pya.DPoint(0, -w1 / 2),
            pya.DPoint(0, w1 / 2),
            pya.DPoint(length, w2 / 2),
            pya.DPoint(length, -w2 / 2)
        ]
        shape_taper = pya.DPolygon(pts).transformed(trans)
    else:
        pts = [
            pya.Point(0, -w1 / 2),
            pya.Point(0, w1 / 2),
            pya.Point(length, w2 / 2),
            pya.Point(length, -w2 / 2)
        ]
        shape_taper = pya.Polygon(pts).transformed(trans)

    if insert == True:
        cell.shapes(layer).insert(shape_taper)
    else:
        return shape_taper
예제 #6
0
    def produce_impl(self):

        # fetch the parameters
        dbu = self.layout.dbu
        ly = self.layout
        shapes = self.cell.shapes

        LayerSi = self.layer
        LayerSiN = ly.layer(LayerSi)
        LayerPinRecN = ly.layer(self.pinrec)
        LayerDevRecN = ly.layer(self.devrec)

        # Determine the period such that the waveguide length is as desired.  Slight adjustment to period
        N_boxes = int(round(self.length / self.target_period - 0.5))
        grating_period = self.length / (N_boxes) / dbu

        # Draw the Bragg grating:
        box_width = int(round(grating_period * self.duty))

        w = self.swg_wg_width / dbu
        half_w = w / 2
        for i in range(0, N_boxes + 1):
            x = int(round((i * grating_period - box_width / 2)))
            box1 = Box(x, -half_w, x + box_width, half_w)
            shapes(LayerSiN).insert(box1)
        length = self.length / dbu

        # Strip waveguide:
        w_strip = self.strip_wg_width / dbu
        if w_strip > 0:
            box1 = Box(0, -w_strip / 2, length, w_strip / 2)
            shapes(LayerSiN).insert(box1)

        # Create the device recognition layer
        points = [pya.Point(0, 0), pya.Point(length, 0)]
        path = pya.Path(points, w)
        path = pya.Path(points, w * 3)
        shapes(LayerDevRecN).insert(path.simple_polygon())

        # Pins on the waveguide:
        from SiEPIC._globals import PIN_LENGTH as pin_length
        make_pin(self.cell, "opt1", [0, 0], w, pin_length, LayerPinRecN)
        make_pin(self.cell, "opt2", [length, 0], w, -pin_length, LayerPinRecN)

        # Compact model information
        t = Trans(Trans.R0, 0, -w * 1.5 + 0.1 / dbu)
        text = Text('Lumerical_INTERCONNECT_library=Design kits/ebeam', t)
        shape = shapes(LayerDevRecN).insert(text)
        shape.text_size = 0.1 / dbu
        t = Trans(Trans.R0, 0, -w * 1.5 + 0.2 / dbu)
        text = Text('Component=NO_MODEL_AVAILABLE', t)
        shape = shapes(LayerDevRecN).insert(text)
        shape.text_size = 0.1 / dbu
        t = Trans(Trans.R0, 0, -w * 1.5)
        text = Text \
          ('Spice_param:length=%.3fu target_period=%.3fu grating_period=%.3fu swg_wg_width=%.3fu strip_wg_width=%.3fu duty=%.3f ' %\
          (self.length, self.target_period, round(grating_period)*dbu, self.swg_wg_width, self.strip_wg_width, self.duty), t )
        shape = shapes(LayerDevRecN).insert(text)
        shape.text_size = 0.1 / dbu
예제 #7
0
 def vernier(self, width, length, pitch):
   '''
   vernier(width, length, pitch)
   
   Generates a vernier scale
   
   Parameters
   ---------
   width : integer
         The width of each tick marker
   length : integer
         The length of the central tick mark
         The major tick marks are 3/4 this length
         The minor tick marks are half this length
   pitch : integer
         The distance between each tick mark
   
   Returns
   ------
   region : [pya.Region]
        A region containing the vernier scale
   
   Description
   ---------
   A pair of vernier scale can be used to measure misalignment by eye.
   
   In photolithography the wafer will contain one vernier pattern (width = 4, length = 40, pitch = 8, units = micron)
   and the mask will contain a second vernier pattern (pitch = 8.2) providing an alignment measurement resolution of 0.2 micron.
   '''
   scaleM = 0.75
   scaleS = 0.5
   
   # Create the large tick mark
   polygons = []
   #tick = pya.Polygon([pya.Point(0,0), pya.Point(length,0), pya.Point(length,width), pya.Point(0,width)])
   tick = pya.Polygon([pya.Point(0,0), pya.Point(0,width), pya.Point(length,width), pya.Point(length,0)])
   tc = pya.ICplxTrans(int(-length/2),int(-width/2))
   polygons.append(tc.trans(tick))
   
   # Create the medium tick mark
   #tickm = pya.Polygon([pya.Point(0,0), pya.Point(length*scaleM,0), pya.Point(length*scaleM,width), pya.Point(0,width)])
   tickm = pya.Polygon([pya.Point(0,0), pya.Point(0,width), pya.Point(length*scaleM,width), pya.Point(length*scaleM,0)])
   pos = [-2, -1, 1, 2]
   for i in pos:
     tt = pya.ICplxTrans(0,int(i*pitch*5))
     polygons.append(tc.trans(tt.trans(tickm)))
   
   # Create the small tick mark
   #ticks = pya.Polygon([pya.Point(0,0), pya.Point(length*scaleS,0), pya.Point(length*scaleS,width), pya.Point(0,width)])
   ticks = pya.Polygon([pya.Point(0,0), pya.Point(0,width), pya.Point(length*scaleS,width), pya.Point(length*scaleS,0)])
   pos = [-9, -8, -7, -6, -4, -3, -2, -1, 1, 2, 3, 4, 6, 7, 8, 9]
   for i in pos:
     tt = pya.ICplxTrans(0,int(i*pitch))
     polygons.append(tc.trans(tt.trans(ticks)))
     
   return pya.Region(polygons)
예제 #8
0
  def siWafer(self, diameter, primaryFlat, secondaryFlat, angle, vertices = 128):
      '''
      siWafer(diameter, secondaryFlatAngle)
      
      Generates a Silicon Wafer shape
      
      Parameters
      ---------
      diameter : integer
            The diameter of a standard silicon wafer
      primaryFlat : integer
            The length of the primary flat
      secondaryFlat : integer
            The length of the secondary flat
      angle : double
            The location of the secondary flat relative (counterclockwise) to primary flat
      vertices : integer (coerce to even number)
            The number of vertices used to generate the circle
      
      Returns
      ------
      region : [pya.Region]
           A region containing the Si Wafer shape
      
      Description
      ---------
      SEMI Wafer Flat M1-0302 Specification
      Wafer Size  = [2", 3", 100mm, 125mm, 150mm, 200mm, 300mm]
      Diameter [mm] = [50.8, 76.2, 100, 125, 150, 200, 300]
      Thickness [um] = [279, 381, 525 or 625, 625, 675 or 625, 725, 775]
      Primary Flat Length = [15.88, 22.22, 32.5, 42.5, 57.5, Notch, Notch]
      Secondary Flat Length = [8, 11.18, 18, 27.5, 37.5, NA, NA]
      '''
      dList = [50800, 76200, 10000, 12500, 15000]
      pFlatLengthList = [15.88, 22.22, 32.5, 42.5, 57.5]
      sFlatLengthList = [8, 11.18, 18, 27.5, 37.5]
      
      r = int(diameter/2)
      
      #Height of arc position (https://mathworld.wolfram.com/CircularSegment.html)
      pH = r- int(np.sqrt(4*np.power(r,2)-np.power(primaryFlat,2))/2)
      sH = r - int(np.sqrt(4*np.power(r,2)-np.power(secondaryFlat,2))/2)
      
      # Create a circle
      polygon = pya.Polygon([pya.Point(-r,-r), pya.Point(-r,r), pya.Point(r,r), pya.Point(r,-r)])
      polygon = polygon.round_corners(0,r,vertices)
      
      #Create a rectangle to produce the primary flat
      pRectangle = pya.Polygon([pya.Point(-r,r-pH), pya.Point(-r,r+pH), pya.Point(r,r+pH), pya.Point(r,r-pH)])
      
      #Create a rectangle to produce the secondary flat
      sRectangle = pya.Polygon([pya.Point(-r,r-sH), pya.Point(-r,r+sH), pya.Point(r,r+sH), pya.Point(r,r-sH)])
      tt = pya.ICplxTrans(1, angle, False, 0, 0)

      return pya.Region(polygon)-pya.Region(pRectangle)-pya.Region(sRectangle.transform(tt))
예제 #9
0
    def draw_init(self):
        p1 = pya.Point(self.cd / 2, self.cd / 2 + self.length)
        p2 = pya.Point(self.cd / 2, self.cd / 2)
        p3 = pya.Point(self.cd / 2 + self.length, self.cd / 2)
        p4 = pya.Point(self.cd / 2 + self.length, self.cd / 2 + self.length)
        self.cell.shapes(self.layer).insert(
            pya.Path([p1, p2, p3, p4], self.cd, self.cd / 2,
                     self.cd / 2).polygon())

        #        self.cell.shapes(self.layout.layer(10,0)).insert(pya.Box(self.cd,0,self.cd*2,self.cd))
        self.cell.shapes(self.layout.layer(self.via_layer, 0)).insert(
            pya.Box(0, 0, self.cd * 2, self.cd))
예제 #10
0
def drawViaArray(layout, cell, origin, cdX, cdY, pX, pY, Nx, Ny, layerSpec):
    layer = layout.layer(layerSpec[0], layerSpec[1], layerSpec[2])

    for i in xrange(Nx):
        for j in xrange(Ny):
            l = origin[0] + pX * i
            b = origin[1] + pY * j
            r = l + cdX
            t = b + cdY
            ll = pya.Point(int(l), int(b))
            tr = pya.Point(int(r), int(t))
            cell.shapes(layer).insert(pya.Box(ll, tr))
예제 #11
0
def layout_taper(cell, layer, trans, w1, w2, length):
    """ Lays out a taper

    Args:
        trans: pya.Trans: location and rotation
        w1: width of waveguide, float
        w2: width of waveguide, float
        length: length, float

    """
    import pya
    pts = [pya.Point(0,-w1/2), pya.Point(0,w1/2), pya.Point(length,w2/2), pya.Point(length,-w2/2)]
    cell.shapes(layer).insert(pya.Polygon(pts).transformed(trans))
예제 #12
0
    def ring(self, outerDiameter, innerDiameter, vertices=128, fracture=True):
        '''
      circle(outerDiameter, innerDiameter, vertices)
      
      Generates a circle shape
      
      Parameters
      ---------
      outerDiameter : integer
            The outer diameter of the ring
      innerDiameter : integer
            The inner diameter of the ring
      vertices : integer (128)
            Number of vertices in the circle (coerce to multiples of 4)
      fracture : boolean (True)
            Create the inner polygon with vertices that is optimal for fracturing horizontally
      
      Returns
      ------
      region : [pya.Region]
           A region containing the circle shape
      '''
        ro = int(outerDiameter / 2)
        ri = int(innerDiameter / 2)
        vertices = int(vertices / 4) * 4

        # Create a circle
        polygon = pya.Polygon([
            pya.Point(-ro, -ro),
            pya.Point(-ro, ro),
            pya.Point(ro, ro),
            pya.Point(ro, -ro)
        ])
        polygonOuter = polygon.round_corners(0, ro, vertices)
        polygon = pya.Polygon([
            pya.Point(-ri, -ri),
            pya.Point(-ri, ri),
            pya.Point(ri, ri),
            pya.Point(ri, -ri)
        ])

        if fracture:
            points = polygonOuter.each_point_hull()
            polygonInnerPoints = []
            r2 = np.power(ri, 2)
            for point in points:
                if (ri > np.absolute(point.y)):
                    x = np.sqrt(r2 - np.power(point.y, 2))
                    polygonInnerPoints.append(
                        pya.Point(np.sign(point.x) * x, point.y))
            polygonInner = pya.Polygon(polygonInnerPoints)
        else:
            polygonInner = polygon.round_corners(0, ri, vertices)

        return pya.Region(polygonOuter) - pya.Region(polygonInner)
예제 #13
0
    def produce_impl(self):

        # fetch the parameters
        dbu = self.layout.dbu
        tg = math.tan(math.radians(self.a / 2))

        # compute the bowtie
        pts = []
        pts.append(
            pya.Point(pya.DPoint((-self.lb / 2) / dbu, (self.wb / 2) / dbu)))
        pts.append(
            pya.Point(
                pya.DPoint((-self.lb / 2 - self.lw) / dbu,
                           (self.wb / 2 + self.lw * tg) / dbu)))
        pts.append(
            pya.Point(
                pya.DPoint((-self.lb / 2 - self.lw) / dbu,
                           (-self.wb / 2 - self.lw * tg) / dbu)))
        pts.append(
            pya.Point(pya.DPoint((-self.lb / 2) / dbu, -(self.wb / 2) / dbu)))
        self.cell.shapes(self.l_layer).insert(pya.Polygon(pts))
        pts = []
        pts.append(
            pya.Point(pya.DPoint((self.lb / 2) / dbu, -(self.wb / 2) / dbu)))
        pts.append(
            pya.Point(
                pya.DPoint((self.lb / 2 + self.lw) / dbu,
                           (-self.wb / 2 - self.lw * tg) / dbu)))
        pts.append(
            pya.Point(
                pya.DPoint((self.lb / 2 + self.lw) / dbu,
                           (self.wb / 2 + self.lw * tg) / dbu)))
        pts.append(
            pya.Point(pya.DPoint((self.lb / 2) / dbu, (self.wb / 2) / dbu)))
        self.cell.shapes(self.l_layer).insert(pya.Polygon(pts))
예제 #14
0
def make_pin(cell, name, center, w, pin_length, layer, vertical=0):
    if vertical == 0:
        p1 = pya.Point(center[0] + pin_length / 2, center[1])
        p2 = pya.Point(center[0] - pin_length / 2, center[1])
    elif vertical == 1:
        p1 = pya.Point(center[0], center[1] + pin_length / 2)
        p2 = pya.Point(center[0], center[1] - pin_length / 2)

    pin = pya.Path([p1, p2], w)
    t = Trans(Trans.R0, center[0], center[1])
    text = Text(name, t)
    shape = cell.shapes(layer).insert(text)
    shape.text_size = 0.1
    cell.shapes(layer).insert(pin)
예제 #15
0
def draw_wire_column(cell,
                     layer,
                     cd,
                     min_length,
                     max_length,
                     min_t2t,
                     max_t2t,
                     t2t_grid,
                     max_y,
                     location=[0, 0]):
    offset_x = location[0]
    offset_y = location[1]
    total_x = 0
    total_y = 0
    while total_y < max_y:
        wire_left = total_x
        wire_lower = total_y
        # print min_length, max_length, max_y

        try:
            tmp = min(max_length, max_y - wire_lower)
            wire_length = rd.randint(min_length, tmp)
            # print "wire length", wire_length
        except:
            # print "escape wire"
            break

        wire_upper = wire_lower + wire_length
        wire_right = wire_left + cd
        # print(wire_left+offset_x,wire_lower+offset_y,wire_lower,wire_right)
        wire_ll = pya.Point(wire_left + offset_x, wire_lower + offset_y)
        wire_ur = pya.Point(wire_right + offset_x, wire_upper + offset_y)
        wire = pya.Box(wire_ll, wire_ur)
        cell.shapes(layer).insert(wire)
        # print wire_ll, wire_ur
        # quit()
        try:
            if max_t2t > min_t2t:
                tmp = min(max_t2t, max_y - wire_upper)
                # print min_t2t, tmp, t2t_grid
                t2t = rd.randrange(min_t2t, tmp, t2t_grid)
                # print "t2t", t2t
            else:
                t2t = max_t2t
        except:
            # print "escape t2t"
            break
        # print total_x, max_x, max_length, wire_left
        total_y = total_y + wire_length + t2t
예제 #16
0
def do_non_opc_fill(fill_top_cell, layer, layer_cfg, outline_area,
                    shapes_area):
    non_opc_cfg = layer_cfg['non-opc']
    sp_non = non_opc_cfg['space_to_non_fill']
    sp_fill = non_opc_cfg['space_to_fill']
    # Constant across iterations
    fill_base_area = outline_area - shapes_area.sized(sp_non - half(sp_fill))

    for w, h in zip(non_opc_cfg['width'], non_opc_cfg['height']):
        # Orient the fill in the preferred direction
        if layer_cfg['dir'] == 'H':
            w, h = (max(w, h), min(w, h))
        else:
            w, h = (min(w, h), max(w, h))

        # The set of non-OPC fill shapes may expand on each iteration so we
        # recompute it
        non_opc_fill = pya.Region(
            fill_top_cell.begin_shapes_rec(non_opc_cfg['klayout']))
        fill_area = fill_base_area - non_opc_fill.sized(half(sp_fill))

        small_cell, fill_cell_bbox = create_fill_cell(layer + '_non_opc',
                                                      non_opc_cfg, w, h)
        while not fill_area.is_empty():
            fill_top_cell.fill_region(fill_area, small_cell.cell_index(),
                                      fill_cell_bbox, None, fill_area,
                                      pya.Point(0, 0), None)

        if 'datatype2' in non_opc_cfg:
            e2_cell, _ = create_fill_cell(layer + '_non_opc_e2', non_opc_cfg,
                                          w, h, True)
            double_pattern(fill_top_cell, small_cell, e2_cell)
예제 #17
0
    def test_13(self):

        n = 100
        w = 10000

        ly = pya.Layout()
        l1 = ly.layer(1, 0)
        top = ly.create_cell("TOP")

        ix = 0
        while ix < n:
            sys.stdout.write(str(ix) + "/" + str(n) + "\n")
            sys.stdout.flush()
            iy = 0
            while iy < n:
                x = ix * w
                y = iy * w
                cell = ly.create_cell("X" + str(ix) + "Y" + str(iy))
                cell.shapes(l1).insert(pya.Box(0, 0, w, w))
                top.insert(
                    pya.CellInstArray(cell.cell_index(),
                                      pya.Trans(pya.Point(ix * w, iy * w))))
                iy += 1
            ix += 1

        ly._destroy()
예제 #18
0
파일: core.py 프로젝트: SiEPIC/SiEPIC-Tools
    def get_polygons(self, include_pins=True):
        from .utils import get_layout_variables
        TECHNOLOGY, lv, ly, cell = get_layout_variables()

        r = pya.Region()

        s = self.cell.begin_shapes_rec(ly.layer(TECHNOLOGY['Waveguide']))
        while not (s.at_end()):
            if s.shape().is_polygon() or s.shape().is_box() or s.shape(
            ).is_path():
                r.insert(s.shape().polygon.transformed(s.itrans()))
            s.next()

        if include_pins:
            s = self.cell.begin_shapes_rec(ly.layer(TECHNOLOGY['PinRec']))
            import math
            from .utils import angle_vector
            while not (s.at_end()):
                if s.shape().is_path():
                    p = s.shape().path.transformed(s.itrans())
                    # extend the pin path by 1 micron for FDTD simulations
                    pts = [pt for pt in p.each_point()]
                    # direction / angle of the optical pin
                    rotation = angle_vector(pts[0] - pts[1]) * math.pi / 180
                    pts[1] = (
                        pts[1] -
                        pya.Point(int(math.cos(rotation) * 1000),
                                  int(math.sin(rotation) * 1000))).to_p()
                    r.insert(pya.Path(pts, p.width).polygon())
                s.next()

        r.merge()
        polygons = [p for p in r.each_merged()]

        return polygons
예제 #19
0
    def checkerboard(self, width, num=5):
        '''
    checkerboard(width, num)
    
    Generates a checkerboard pattern
    
    Parameters
    ---------
    width : integer
          The width of each square
    num : integer (5)
          The number of squares
    
    Returns
    ------
    region : pya.Region
         A region containing the checkerboard
    
    Description
    ---------
    A checkerboard pattern is used to qualitatively evaluate the resolution of the print.
    The corners of the checkboard pattern will degrade as resolution gets worse
    '''
        # Create a box
        square = pya.Polygon([
            pya.Point(0, 0),
            pya.Point(0, width),
            pya.Point(width, width),
            pya.Point(width, 0)
        ])
        polygons = []
        tc = pya.ICplxTrans(-int(num * width / 2), -int(num * width / 2))

        if (num % 2 == 1):
            for i in range(num * num):
                if (i % 2 == 0):
                    tt = pya.ICplxTrans(int(i % num * width),
                                        int(i / num * width))
                    polygons.append(tc.trans(tt.trans(square)))
        else:
            for i in range(num):
                for j in range(num):
                    if ((j + i) % 2 == 0):
                        tt = pya.ICplxTrans(int(i * width), int(j * width))
                        polygons.append(tc.trans(tt.trans(square)))

        return pya.Region(polygons)
예제 #20
0
    def test_3_Trans(self):

        c = pya.CplxTrans(5, -7)
        self.assertEqual(str(c), "r0 *1 5,-7")
        self.assertEqual(str(pya.CplxTrans.from_s(str(c))), str(c))

        c = pya.CplxTrans(pya.CplxTrans.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.CplxTrans.M135.rot())
        self.assertEqual(str(c.s_trans()), "m135 0,0")
        self.assertAlmostEqual(c.angle, 270)

        c = pya.CplxTrans.from_dtrans(pya.DCplxTrans.M135)
        self.assertEqual(str(c), "m135 *1 0,0")

        c = pya.CplxTrans(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.CplxTrans.R0.rot())
        self.assertEqual(str(c.s_trans()), "r0 0,0")
        self.assertAlmostEqual(c.angle, 0)

        c = pya.CplxTrans(0.75, 45, True, 2.5, -12.5)
        self.assertEqual(str(c), "m22.5 *0.75 2.5,-12.5")
        self.assertEqual(str(pya.CplxTrans.from_s(str(c))), str(c))
        c = pya.CplxTrans(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.CplxTrans.M0.rot())
        self.assertEqual(str(c.s_trans()), "m0 3,-13")
        self.assertAlmostEqual(c.angle, 45)

        self.assertEqual(str(c.ctrans(5)), "3.75")
        self.assertEqual(str(c.trans(pya.Point(12, 16))),
                         "17.3492424049,-14.6213203436")

        self.assertEqual(str(pya.CplxTrans()), "r0 *1 0,0")
        self.assertEqual(pya.CplxTrans().is_unity(), True)
        self.assertEqual((c.inverted() * c).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")
예제 #21
0
def pointlist_to_path(pointlist, dbu):
    # convert [[230.175,169.18],[267.0,169.18],[267.0,252.0],[133.0,252.0],[133.0,221.82],[140.175,221.82]]
    # to pya.Path

    points = []
    for p in points:
        points.append(pya.Point(p[0], p[1]))
    path = pya.Path(points)
    return path
def main():
    # Loop each cut map, & export each GDS as unique name
    for key in cut_d:
        filename = "2_" + key  # Add prefix to the filename
        print("\nfilename : ", filename)

        # Get 1_UNIT (no cuts as a reference) & create SINGLE instance
        for i in gdsFiles:
            layout.read(i)

            for cell in layout.top_cells():
                # we don't want to insert the topcell itself
                if (cell.name != "1_UNIT_CUTS"):
                    print("Adding : " + cell.name)
                    cell_index = cell.cell_index()
                    new_instance = pya.CellInstArray(
                        cell_index, pya.Trans(pya.Point(0, 0)))
                    UNIT.insert(new_instance)

        # Define imported metal as a region (for boolean)
        region_metal = pya.Region(layout.top_cell().begin_shapes_rec(l_metal))

        # Define cut area & make as region
        for ind, each_cut in enumerate(cut_d[key]):
            cut_box_coord = get_cut_coord(each_cut, d)
            UNIT.shapes(l_cut_box).insert(cut_box_coord)
            region_cut_box = pya.Region(cut_box_coord)
            # Do boolean (XOR)
            # For more than 1 cuts, need to loop and take XOR of previous XOR results
            if ind == 0:
                region_xor = region_metal ^ region_cut_box
            else:
                region_xor = region_xor ^ region_cut_box

        # Remove existings metal layer + cut boxes
        # (!!! SKIP THIS TO CHECK CUT BOXES IN GDS !!!)
        layout.clear_layer(l_metal)
        layout.clear_layer(l_cut_box)

        # INSERT BOOLEAN RESULT AS ORIGINAL METAL LAYER
        UNIT.shapes(l_metal).insert(region_xor)

        # Check if filename gds exists -> If so skip "write"
        if os.path.isfile(root + "/" + filename + ".gds"):
            print("**** GDS name by : " + filename + ".gds already exists!")
            print("**** SKIPPING GDS WRITE!!!")
        else:
            # Export GDS
            layout.write(filename + ".gds")

            # Check if this cell can be used as another at different coordinate
            dup_l = get_dup_names(filename + ".gds")
            if dup_l[0] != '':
                for each in dup_l:
                    print("Create copy as : ", each,
                          "  <-----------------------------------------")
                    layout.write(each)
예제 #23
0
class Top_driver(My_Cell):
    """docstring for ClassName"""
    top_vdd = pya.Point(-500, 5350)

    def __init__(self, cell, out_pin, cell_index):

        self.out_pin = out_pin
        self.cell_index = cell_index
        self.cell = cell
예제 #24
0
  def pieceHolderCassette(self,dbu = 1):
      '''
      pieceHolderCassette()
      
      Generates the shape of the Jeol JBX-5500FS piece holder cassette
      
      Parameters
      ---------
      dbu : double
            The database unit
            
      Returns
      ------
      region : [pya.Region]
           A region containing the piece holder cassette shape
           
      Description
      ------
      The center of this piece holder shape (0,0) is at stage position (62.5mm, 37.5mm)
      
      Jeol Stage Y axis is reverse of KLayout Y axis
      '''
      # Create the quarter circle
      r = 36100/dbu
      rx = 62500/dbu
      ry = -37500/dbu
      polygon = pya.Polygon([pya.Point(-r,-r), pya.Point(-r,r), pya.Point(r,r), pya.Point(r,-r)])
      polygon = polygon.round_corners(0,r,128)
      rectangle = pya.Polygon([pya.Point(-r,0), pya.Point(-r,r), pya.Point(r,r), pya.Point(r,0)])
      tt = pya.ICplxTrans(1, 90, False, 0, 0)
      qCircle = pya.Region(polygon)-pya.Region(rectangle)-pya.Region(rectangle.transform(tt))
      
      
      # Create the trapezoid
      trapezoid = pya.Polygon([pya.Point(49500/dbu,-70500/dbu), pya.Point(40500/dbu,-20500/dbu), pya.Point(60500/dbu,-20500/dbu), pya.Point(51500/dbu,-70500/dbu)])
      tt = pya.ICplxTrans(-rx,-ry)
      
      cassette = qCircle + pya.Region(trapezoid.transform(tt))

      return cassette
예제 #25
0
def draw_contact_pair(layout,
                      tmp_cell,
                      cellname,
                      size,
                      spacing,
                      dest,
                      dbu,
                      put_in_array=True,
                      verbose=True,
                      clip=True,
                      origin=np.array([0, 0])):

    l_contact = layout.layer(73, 0, "V1")
    c1ll = pya.Point(origin[0], origin[1])
    size = pya.Point(size[0], size[1])
    c1ur = c1ll + size
    spc = pya.Point(spacing[0], spacing[1])
    c2ll = c1ur + spc
    c2ur = c2ll + size
    tmp_cell.shapes(l_contact).insert(pya.Box(c1ll, c1ur))
    tmp_cell.shapes(l_contact).insert(pya.Box(c2ll, c2ur))
    if clip:
        l_bb = layout.layer(1, 0, "bounding_box")
        # print c1ur.x,c2ll.x
        center = pya.Point((c1ur.x + c2ll.x) / 2, (c1ur.y + c2ll.y) / 2)
        bbll = center - pya.Point(0.125 / dbu, 0.125 / dbu)
        bbur = center + pya.Point(0.125 / dbu, 0.125 / dbu)
        tmp_cell.shapes(l_bb).insert(pya.Box(bbll, bbur))

    if verbose == True:
        tmp_name = cellname + '.oas'
        tmp_cell.write(os.path.join(dest, tmp_name))
예제 #26
0
def arc_bezier(radius, start, stop, bezier, DevRec=None):
    from math import sin, cos, pi
    from SiEPIC.utils import points_per_circle
    N = points_per_circle(radius/1000)/4
    bezier=float(bezier) # in case the input was a string
    if DevRec:
        N = int(N / 3)
    else:
        N = int(N)
    if N < 5:
      N = 100
    L = radius  # effective bend radius / Length of the bend
    diff = 1. / (N - 1)  # convert int to float
    xp = [0, (1 - bezier) * L, L, L]
    yp = [0, 0, bezier * L, L]
    xA = xp[3] - 3 * xp[2] + 3 * xp[1] - xp[0]
    xB = 3 * xp[2] - 6 * xp[1] + 3 * xp[0]
    xC = 3 * xp[1] - 3 * xp[0]
    xD = xp[0]
    yA = yp[3] - 3 * yp[2] + 3 * yp[1] - yp[0]
    yB = 3 * yp[2] - 6 * yp[1] + 3 * yp[0]
    yC = 3 * yp[1] - 3 * yp[0]
    yD = yp[0]

    pts = [pya.Point(-L, 0) + pya.Point(xD, yD)]
    for i in range(1, N - 1):
        t = i * diff
        pts.append(pya.Point(-L, 0) + pya.Point(t**3 * xA + t**2 * xB +
                                                t * xC + xD, t**3 * yA + t**2 * yB + t * yC + yD))
    pts.extend([pya.Point(0, L - 1), pya.Point(0, L)])
    return pts
예제 #27
0
def arc_bezier(radius, start, stop, bezier, DevRec=None):
    from math import sin, cos, pi
    N = 100
    if DevRec:
        N = int(N / 10)
    L = radius  # effective bend radius / Length of the bend
    diff = 1. / (N - 1)  # convert int to float
    xp = [0, (1 - bezier) * L, L, L]
    yp = [0, 0, bezier * L, L]
    xA = xp[3] - 3 * xp[2] + 3 * xp[1] - xp[0]
    xB = 3 * xp[2] - 6 * xp[1] + 3 * xp[0]
    xC = 3 * xp[1] - 3 * xp[0]
    xD = xp[0]
    yA = yp[3] - 3 * yp[2] + 3 * yp[1] - yp[0]
    yB = 3 * yp[2] - 6 * yp[1] + 3 * yp[0]
    yC = 3 * yp[1] - 3 * yp[0]
    yD = yp[0]

    pts = [pya.Point(-L, 0) + pya.Point(xD, yD)]
    for i in range(1, N - 1):
        t = i * diff
        pts.append(
            pya.Point(-L, 0) +
            pya.Point(t**3 * xA + t**2 * xB + t * xC + xD, t**3 * yA +
                      t**2 * yB + t * yC + yD))
    pts.extend([pya.Point(0, L - 1), pya.Point(0, L)])
    return pts
예제 #28
0
def main():

    # Loop each cut locations, & assign GDS name from key
    for key in cut_loc:
        filename = key
        print("\nfilename : ", filename)

        # Read 1_UNIT (no cuts as a reference) & create SINGLE instance
        for each_gds in gds_files:
            KLAYOUT.read(each_gds)

            # Read Top Cell for each GDS file
            for top_cell_read in KLAYOUT.top_cells():
                if (top_cell_read.name != "1_UNIT_CUTS"
                    ):  # Don't insert TOP_CELL("1_UNIT_CUTS") on itself
                    # print ( "Adding " + top_cell_read.name )
                    cell_index = top_cell_read.cell_index()
                    new_instance = pya.CellInstArray(
                        cell_index, pya.Trans(pya.Point(0, 0)))
                    # pya.Trans(pya.Point(0,0)) --> defines the LOCATION at which instance should be placed
                    TOP_CELL.insert(new_instance)

        # Define imported metal as a region (for boolean)
        region_metal = pya.Region(KLAYOUT.top_cell().begin_shapes_rec(l_metal))

        # Define cut area & make as region
        for ind, each_cut in enumerate(cut_loc[key]):
            cut_box_coord = get_cut_coord(each_cut, dim)
            TOP_CELL.shapes(l_cut_box).insert(cut_box_coord)
            region_cut_box = pya.Region(cut_box_coord)
            # Do boolean (XOR)
            # For more than 1 cuts, need to loop and take XOR of previous XOR results
            if ind == 0:
                region_xor = region_metal ^ region_cut_box
            else:
                region_xor = region_xor ^ region_cut_box

        # Remove existings metal layer + cut boxes
        # (!!! SKIP THIS TO CHECK CUT BOXES IN GDS !!!)
        KLAYOUT.clear_layer(l_metal)
        KLAYOUT.clear_layer(l_cut_box)

        # INSERT BOOLEAN RESULT AS ORIGINAL METAL LAYER
        TOP_CELL.shapes(l_metal).insert(region_xor)

        # Check if filename gds exists -> If so skip "write"
        if os.path.isfile(root + "/" + filename + ".gds"):
            print("**** GDS name by : " + filename + ".gds already exists!")
            print("**** SKIPPING GDS WRITE!!!")
        else:
            # Export GDS
            KLAYOUT.write(filename + ".gds")
예제 #29
0
def create(radius, npoints=32):
    """Create a circular-shaped region.

    radius:     radius of the circular area
    npoints:    the circular area is approximated by a polygon, hence the number of vertices
    """
    angles = np.linspace(0, 2 * np.pi, num=npoints, endpoint=False)
    points = []
    for i, ang in enumerate(angles):
        points.append(pya.Point(radius * np.cos(ang), radius * np.sin(ang)))
    circle = pya.Region()
    circle.insert(pya.SimplePolygon(points))
    return circle
예제 #30
0
def do_opc_fill(fill_top_cell, layer, layer_cfg, outline_area, shapes_area):
    has_opc = 'opc' in layer_cfg
    if not has_opc:
        return
    opc_cfg = layer_cfg['opc']
    sp_non = opc_cfg['space_to_non_fill']
    sp_fill = opc_cfg['space_to_fill']
    halo = opc_cfg['halo']

    non_opc_cfg = layer_cfg['non-opc']
    sp_fill_non_opc = non_opc_cfg['space_to_fill'] - half(sp_fill)

    non_opc_fill = pya.Region(
        fill_top_cell.begin_shapes_rec(non_opc_cfg['klayout']))
    if 'klayout2' in non_opc_cfg:
        non_opc_fill |= pya.Region(
            fill_top_cell.begin_shapes_rec(non_opc_cfg['klayout2']))

    fill_base_area = outline_area & (
        shapes_area.sized(halo) - shapes_area.sized(sp_non - half(sp_fill)) -
        non_opc_fill.sized(sp_fill_non_opc))

    is_h = layer_cfg['dir'] == 'H'
    for w, h in zip(opc_cfg['width'], opc_cfg['height']):
        w_space = h_space = half(sp_fill)
        le = opc_cfg.get('space_line_end', 0)
        if is_h:
            w, h = (max(w, h), min(w, h))
            w_space += half(le)
        else:
            w, h = (min(w, h), max(w, h))
            h_space += half(le)

        opc_fill = pya.Region(
            fill_top_cell.begin_shapes_rec(opc_cfg['klayout']))
        if 'klayout2' in opc_cfg:
            opc_fill |= pya.Region(
                fill_top_cell.begin_shapes_rec(opc_cfg['klayout2']))

        fill_area = fill_base_area - opc_fill.sized(w_space, h_space, 2)
        small_cell, fill_cell_bbox = create_fill_cell(layer + '_opc', opc_cfg,
                                                      w, h)
        while not fill_area.is_empty():
            fill_top_cell.fill_region(fill_area, small_cell.cell_index(),
                                      fill_cell_bbox, None, fill_area,
                                      pya.Point(0, 0), None)
        if 'datatype2' in opc_cfg:
            e2_cell, _ = create_fill_cell(layer + '_opc_e2', opc_cfg, w, h,
                                          True)
            double_pattern(fill_top_cell, small_cell, e2_cell)