It looks like you're new here. If you want to get involved, click one of these buttons!
Hi folks,
I have trouble getting PCells instantiated using Python. KLayout just crashed with wild Qt errors...
What I try to do is having a PCell which will add text markers to an array of PCells, which I at the moment instantiate by hand. So basically label arrays with "A B C....AA AB...".
Here's my code:
import pya
import math
from string import ascii_uppercase
from itertools import count, product, islice
def multiletters(seq):
for n in count(1):
for s in product(seq, repeat=n):
yield ''.join(s)
"""
This sample PCell implements a library called "MyLib" with a single PCell that
draws a circle. It demonstrates the basic implementation techniques for a PCell
and how to use the "guiding shape" feature to implement a handle for the circle
radius.
NOTE: after changing the code, the macro needs to be rerun to install the new
implementation. The macro is also set to "auto run" to install the PCell
when KLayout is run.
"""
class ArrayText(pya.PCellDeclarationHelper):
"""
The PCell declaration for the circle
"""
def __init__(self):
# Important: initialize the super class
super(ArrayText, self).__init__()
# declare the parameters
self.param("l", self.TypeLayer, "Layer", default = pya.LayerInfo(1, 0))
self.param("textsize", self.TypeInt, "Text Size", default = 30)
self.param("ignore_j", self.TypeBoolean, "Ignore J", default = True)
self.param("spread", self.TypeDouble, "Spread", default = 100)
self.param("n", self.TypeInt, "Number of points", default = 10)
self.param("mirror", self.TypeBoolean, "Mirror", default = False)
self.param("use_offset", self.TypeBoolean, "Use offset instead spread", default = False)
self.param("x_off", self.TypeDouble, "x offset", default = 160.)
self.param("y_off", self.TypeDouble, "y offset", default = 0.)
def display_text_impl(self):
# Provide a descriptive text for the cell
return "Array Text (position...)"
def coerce_parameters_impl(self):
# We employ coerce_parameters_impl to decide whether the handle or the
# numeric parameter has changed (by comparing against the effective
# radius ru) and set ru to the effective radius. We also update the
# numerical value or the shape, depending on which on has not changed.
if self.n <= 0:
self.n = 1
def can_create_from_shape_impl(self):
# Implement the "Create PCell from shape" protocol: we can use any shape which
# has a finite bounding box
return self.shape.is_box() or self.shape.is_polygon() or self.shape.is_path()
def parameters_from_shape_impl(self):
# Implement the "Create PCell from shape" protocol: we set r and l from the shape's
# bounding box width and layer
self.spread = self.shape.bbox().width() * self.layout.dbu
self.textsize = self.shape.bbox().width() * self.layout.dbu
def transformation_from_shape_impl(self):
# Implement the "Create PCell from shape" protocol: we use the center of the shape's
# bounding box to determine the transformation
return pya.Trans(self.shape.bbox().center())
def produce_impl(self):
# This is the main part of the implementation: create the layout
characters = ascii_uppercase
if self.ignore_j:
characters = characters.replace("J","")
try:
strings = list(islice(multiletters(characters), self.n))
except GeneratorExit:
pass
basic_lib = pya.Library.library_by_name("Basic")
txt_pcell = basic_lib.layout().pcell_declaration("TEXT")
if basic_lib == None:
print("BASIC LIB NOT FOUND")
if txt_pcell == None:
print("PCELL TEXT NOT FOUND")
default_parameters_list = txt_pcell.get_parameters()
print("Got default parameter list. Type is: "+str(type(default_parameters_list)))
print("Name\t\t\ŧdefault")
for parameter in default_parameters_list:
print(str(parameter.name)+"\t\t"+str(parameter.default))
pcell_variants = []
for string in strings:
parameters = []
new_parameters = { 'text':string,'layer':self.l_layer, 'mag':2.5 }
for param in default_parameters_list:
if param.name in new_parameters.keys():
print("Exchanged parameter "+str(param.name)+" default from "+str(param.default)+" to "+str(new_parameters[param.name]))
param.default = new_parameters[param.name]
parameters.append(param)
pcell_variant = self.layout.add_pcell_variant(basic_lib, txt_pcell.id(), parameters)
pcell_variants.append(pcell_variant)
t = pya.Trans(pya.Trans.r0(), self.x_off, self.y_off)
new_cell = self.layout.create_cell("ArrayText")
pcell_inst = new_cell.insert(pya.CellInstArray(pcell_variant, t))
Also the generator always raises an GeneratorExit Exception and a popup opens, which in my opinion shouldn't be the right behaviour as the GeneratorExit just stops the generator from iterating?
I'm thankful for any help and insight,
Cheers,
Matthias
PS: sorry, somehow the code markup doesn't work as I expected...
Comments
To get code markup working, preface each line by (at least) four spaces. Not [code][/code]. Link
This is most easily done by pasting into your favorite text editor, select all, press Tab to indent it by four spaces, then copy-paste here.
Hi,
There is another Matthias around but it's not me :-)
I had some trouble getting the code to work without the indents but I guess I got the idea.
The code contains some bugs and here is my version. It requires KLayout 0.24.x or later. The main changes are in produce_impl. I tried to implement the positioning of the text labels assuming the parameters are given in micron units, but other things like proper scaling are missing:
I shall curse the god of evil programming who made the Python guys use exceptions for stopping a loop ... But I know my way around and made the debugger feature configurable: go to "Macro Development Setup" (the "wrench" button on the right of the macro IDE tool bar) and deselect "Ask whether to stop in debugger on exception" on the "Debugging" page.
The first Matthias
Thanks, it worked nicely with your code