Why shapes formed by box and path has an error of 0.001um to 0.002um

Hi,
I am using python scripting,
Using the following three method, I get three different shapes, although they should have the same structure.

    self.param("taper_l", self.TypeDouble, "The length of S sbend curve", default=1.448)       
    self.param("arm_length", self.TypeDouble, "The arm length", default=3.5)
    ........

    l1 = self.taper_l / dbu
    l2 = self.wg_length / dbu
    l3 = self.arm_length / dbu
    ........
    #method1
    box4= Box(-0.5*(l3-l1), -0.5*(l3-l1), +0.5*(l3-l1),+0.5*(l3-l1))
    shapes(LayerSi).insert(box4)
    #method2
    pin1 = Path([Point(-0.5*(l3-l1), 0),
                Point(0.5*(l3-l1), 0)], (l3-l1))
    shapes(LayerSi).insert(pin1)

    #method3
    pts7 = []
    pts7.append(Point.from_dpoint(DPoint(-0.5*(l3-l1), -0.5*(l3-l1))))
    pts7.append(Point.from_dpoint(DPoint(-0.5*(l3-l1), +0.5*(l3-l1))))
    pts7.append(Point.from_dpoint(DPoint(+0.5*(l3-l1), +0.5*(l3-l1))))
    pts7.append(Point.from_dpoint(DPoint(+0.5*(l3-l1), -0.5*(l3-l1))))

    self.cell.shapes(LayerSi).insert(Polygon(pts7))


Only by the third method (polygon), I get the right structure.
Why shapes by box and path has a deviation?

I am very confused by this.
Could anyone give me some assitance?

Comments

  • edited August 2021

    Hi Weiling,

    Why don't you use only DPoint, DBox and DPath??? No need to convert taper_l and arm_length to number of DBU equivalents...

     box = DBox.new(-0.5*(arm_length-taper_l), -0.5*(arm_length-taper_l), +0.5*(arm_length-taper_l),+0.5*(arm_length-taper_l))   #Ruby
    

    Now, let's say:

    l1 = 1.447
    l2 = 3.5

    dbu = 0.001

    in microns (DPoint, ...):

    value = 0.5*(l2-l1) = 1.0265

    This value is rounded to the nearest DBU point > (value/dbu).round*dbu = 1.027

    in DBU units (Point, ...):

    l1_dbu = l1/dbu = 1447.0

    l2_dbu = l2/dbu = 3500.0

    value_dbu = 0.5*(l2_dbu-l1_dbu) = 1026.5

    This value is converted to an integer I guess as Point, Box, ... expect integer values > value_dbu.to_i = 1026

    Notice the difference between .to_i and .round:

    value_dbu.to_i = 1026

    value_dbu.round = 1027

    When using Path make sure the width is a multiple of 2*dbu, else the path edges will be off-DBU-grid as well...

    Cheers,

    Tomas

  • @tomas2004
    Hi, Tomas,
    Thank you very much for your detailed response.
    The method you provide does work. I know little about scripting in klayout. I just followed the way of others in siepic pdk.
    (1)
    Although the method you provide works well, is it wirted by ruby(I see you marked Ruby)?
    Will this make the program unstable when the other parts seems to be written in python?

    class sbend_crossing(pya.PCellDeclarationHelper):
    def init(self):

        # Important: initialize the super class
        super(sbend_crossing, self).__init__()
    

    (2)
    I also find another strange thing.
    I tried to add a structure made up by four arc bend.
    Before, everything works well. When I continue to reduce the length of this structure to 0.6 um, I found that its height is not as expected, it is much smaller, about 0.1um, which could not be caused by dbu.
    Can you see where the problem is?

    Normally, it should look like this:

        self.param("wg_length", self.TypeDouble, "waveguide length", default=10)
        self.param("taper_l", self.TypeDouble, "The length of S sbend curve", default=1.448)
        self.param("wg_width", self.TypeDouble, "The width of port",default=0.4)
        self.param("taper_w", self.TypeDouble, "The width of centre", default=1.714)
        self.param("arm_length", self.TypeDouble, "The arm length", default=3.5)
        .........
        l1 = self.taper_l / dbu
        l2 = self.wg_length / dbu
        l3 = self.arm_length / dbu
    
        w1 = self.wg_width / dbu
        w2 = self.taper_w / dbu
        .........
        radius=((0.5 * l1) ** 2 + (0.5 * sbend_w) ** 2) / (2 * (0.5 *sbend_w))
        angle=180 * asin((2 * (0.5 *l1) * (0.5 * sbend_w)) / (
                        (0.5 * l1) ** 2 + (0.5 * sbend_w) ** 2)) / pi
        from math import pi, cos, sin
    
        pts=[]
        pts1 = []
        pts2 = []
        pts3= []
        pts4 = []
        from SiEPIC.utils import points_per_circle
        circle_fraction = abs(angle) / 360.0
        # npoints = int(points_per_circle(radius / 1000) * circle_fraction)
        # # npoints = int(200 * circle_fraction)
        # # if npoints == 0 or npoints ==1 :
        # if npoints < 50 :
            # npoints = 1
        npoints = int(self.n * circle_fraction)
        da = 2 * pi / npoints * circle_fraction  # increment, in radians
        i_sum=[]
        for i in range(0,  npoints + 1):
            i_sum = i_sum + [i]
    
            pts1.append(pya.Point.from_dpoint(pya.DPoint(
                (radius * sin(i * da)), (radius * (1 - cos(i * da)))+w1/2)))
            pts3.append(pya.Point.from_dpoint(pya.DPoint(2 * radius * sin(pi * angle / 180) +
                                                         (radius * sin(pi +i * da)),
                                                       -(w1 / 2 - 2 * radius * cos(pi * angle / 180) + (
                                                                 radius * (1 - cos(pi + i * da)))) )))
    
        isum1 = i_sum[::-1]
        for i in range(len(isum1)):
            pts2.append(pya.Point.from_dpoint(pya.DPoint(2 * radius * sin(pi * angle / 180) +
                                                        (radius * sin(pi + isum1[i] * da)),
                                                        w1/2-2 * radius * cos(pi * angle / 180) + (
                                                           radius * (1 - cos(pi + isum1[i] * da))))))
            pts4.append(pya.Point.from_dpoint(pya.DPoint(
                (radius * sin(isum1[i] * da)), -(radius * (1 - cos(isum1[i]* da))+ w1 / 2) )))
    
    
        pts = pts1 + pts2 + pts3 + pts4
    
        t9 = Trans(Trans.R0, -l3 - w2 / 2, 0)
        self.cell.shapes(LayerSi).insert(Polygon(pts).transformed(t9))
    
  • Hi Weiling,

    You cannot mix Ruby and Python within a script, but it looks quite similar, just drop the ".new":

    box = DBox.new(-0.5*(arm_length-taper_l), -0.5*(arm_length-taper_l), +0.5*(arm_length-taper_l),+0.5*(arm_length-taper_l))
    

    Check this link: https://www.klayout.de/doc-qt5/programming/python.html

    Cheers,

    Tomas

  • @tomas2004 ,
    Hi, Tomas,
    Thank you very much for your respond.
    I will check it.

    Best regards!
    Weiling

Sign In or Register to comment.