Not signed in (Sign In)

Vanilla 1.1.4 is a product of Lussumo. More Information: Documentation, Community Support.

  1.  

    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...

  2.  

    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.

    • CommentAuthorMatthias
    • CommentTimeJun 30th 2016 edited
     

    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:

    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)
    
    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")
    
        # converts x_off, y_off and spread from ┬Ám to DBU:
        x = int(0.5 + self.x_off / self.layout.dbu)
        y = int(0.5 + self.y_off / self.layout.dbu)
        dx = int(0.5 + self.spread / self.layout.dbu)
    
        for string in strings:
    
          parameters = { "text": string, "layer": self.l, "mag": 2.5 }
          pcell_variant = self.layout.add_pcell_variant(basic_lib, txt_pcell.id(), parameters)
    
          t = pya.Trans(pya.Trans.R0, x, y)
          self.cell.insert(pya.CellInstArray(pcell_variant, t))
    
          x += dx
    
    
    class ARRAY_TEXT_LIBRARY(pya.Library):
      """
      The library where we will put the PCell into
      """
    
      def __init__(self):
    
        # Set the description
        self.description = "Array Text Library"
    
        # Create the PCell declarations
        self.layout().register_pcell("Array Text", ArrayText())
        #self.layout().register_pcell("Array Numbers", ArrayNumbers())
        # That would be the place to put in more PCells ...
    
        # Register us with the name "MyLib".
        # If a library with that name already existed, it will be replaced then.
        self.register("Array Text Library")
    
    
    #Instantiate and register the library
    ARRAY_TEXT_LIBRARY()
    

    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

  3.  

    Thanks, it worked nicely with your code :)