ARC PCell

edited December 2014 in Ruby Scripting
Hi everyone.

I am new to KLayout, and am currently trying to design a semiconductor mask within KLayout, I require and ARC, so I have used ARC PCell however I cannot get it operate, I have looked at (http://klayout.de/forum/comments.php?DiscussionID=517).

The file works with "CIRCLE" but not with ARC, I get an "handle" error/message.

The code that I have used is here:

I have left the original code that I used as a base from (http://klayout.de/forum/comments.php?DiscussionID=517)within the code, and adapted as needed.



ly1 = RBA::Layout::new

# database unit 1um:
ly1.dbu = 0.001

# create a top cell
top = ly1.cell(ly1.add_cell("TOP"))

# create a layer: layer number 1, datatype 0
layer = ly1.insert_layer(RBA::LayerInfo::new(1, 0))

# find the lib1
lib1 = RBA::Library.library_by_name("Basic")
lib1 || raise("Unknown lib1 'Basic'")

# find the pcell
pcell_decl1 = lib1.layout.pcell_declaration("ARC")
pcell_decl1 || raise("Unknown PCell 'ARC'")

#pcell_decl1 = lib1.layout.pcell_declaration("CIRCLE")
#pcell_decl1 || raise("Unknown PCell 'CIRLE'")

# set the param1eters
# set some sample parameters (uses GDS layer 10/0):
r = 20.0
param = {
"layer" => RBA::LayerInfo::new(1, 0),
"radius1" => r,
"actual_radius1" => r,
"radius2" => r,
"actual_radius2" => r,
"a1" => 1,
"actual_start_angle" => 1,
"a2" => 90,
"actual_end_angle" => 90,
"npoints" => 100
}

# param = {
# "layer" => RBA::LayerInfo::new(1, 0),
# "radius" => r,
# "actual_radius" => r,
# "npoints" => 64
#}

# build a param array using the param hash as a source
pv1 = pcell_decl1.get_parameters.collect do |p|
param[p.name] || p.default
puts p.name
puts param[p.name]
end

# create a PCell variant cell
pcell_var1 = ly1.add_pcell_variant(lib1, pcell_decl1.id, pv1)

# instantiate that cell
top.insert(RBA::CellInstArray::new(pcell_var1, RBA::Trans::new(RBA::Point::new(0, 0))))

# write the output
outputFile = "arc.gds"
ly1.write(outputFile)



Any help would be greatly appreciated.

Comments

  • edited December 2014

    Hi Ben,

    a working code is this:

    # set the parameters
    # set some sample parameters (uses GDS layer 10/0):
    r1 = 20.0
    r2 = 30.0
    
    param = {
      "layer" => RBA::LayerInfo::new(1, 0),
      "actual_radius1" => r1,
      "actual_radius2" => r2,
      "actual_start_angle" => 1,
      "actual_end_angle" => 90,
      "npoints" => 100
    }
    
    # build a param array using the param hash as a source
    pv1 = pcell_decl1.get_parameters.collect do |p|
      param[p.name] || p.default
    end
    

    There are some modifications:
    * Inner and outer radius must be different
    * The "real" parameters are the "actual_..." ones
    * The puts need to be taken out of the collect loop since the last statement will define the value to be collected and puts does not contribute a value

    The basic problem is that the BASIC library PCell's have been designed for drawing use, not for programmed placement (and scripted placement is not the strength of the KLayout API anyway). Hence they carry some internal parameters like "handle" etc. Those are used to implement the handles which are an alternative way to set the radius and start/end angle. Their interaction is not transparent and they are implemented only insofar the behaviour is well defined for the drawing user. In the case of the ARC implementation the actual_... parameters are taken if the others are left at their defaults - from the perspective of a script user that may be considered a bug. But the above code can serve as a workaround.

    Irregardless of that I'd suggest to consider not using PCell's at all for such a simple case than the ARC. This code does the same without any PCell magic:

    # inner and outer radius
    r1 = 20
    r2 = 30
    
    # start and end angle
    a1 = 1
    a2 = 90
    
    # center point
    xc = 0.0
    yc = 0.0
    
    # Number of points in increments of 5 degree
    n = ((a2 - a1).to_f / 5.0).to_i + 1
    da = (a2 - a1).to_f / n
    
    pt = []
    
    # inner curve
    (n + 1).times do |i|
      x = xc + r1 * Math::cos(Math::PI * (a1 + i * da) / 180.0)
      y = yc + r1 * Math::sin(Math::PI * (a1 + i * da) / 180.0)
      pt << RBA::Point::new((0.5 + x / ly1.dbu).to_i, (0.5 + y / ly1.dbu).to_i)
    end
    
    # outer curve
    (n + 1).times do |i|
      x = xc + r2 * Math::cos(Math::PI * (a1 + (n - i) * da) / 180.0)
      y = yc + r2 * Math::sin(Math::PI * (a1 + (n - i) * da) / 180.0)
      pt << RBA::Point::new((0.5 + x / ly1.dbu).to_i, (0.5 + y / ly1.dbu).to_i)
    end
    
    top.shapes(layer).insert(RBA::Polygon::new(pt))
    

    Matthias

  • edited November -1
    Hi Mathias.

    Thank you for assistance, it is invaluable.

    Thanks.
Sign In or Register to comment.