Refresh library entries programatically

edited September 19 in KLayout Support

Hello,

I'm attempting to implement a PCell library which references itself to construct more complex PCells. In order to do that I need to populate the library without destroying it and rebuilding it since it would cause to unlink all existing PCells.

I achieved to do that by creating the library and using the Library reference instead of using the "self", but the library entries don't automatically refresh like it does when executing the regular self.register(xx).
I tried using self.refresh(), lib.register(xx) again, lib.refresh(), updating the QWidget associated with the libraries, and there's no "library.unregister()" function to try (actually nor "layout.unregister_pcell()" but there is "remove_technology". I guess library.delete() would be the equivalent).
The only solution I found was to switch the selected library view to the "Basic" one and then back.

Here's a sample:

import pya, os
import importlib.util as ilib

lv = pya.Application.instance().main_window().current_view()
wid = lv.widget()
widLib = lv.widget().libraries_frame()

def ezimport(filePath):
  # Makes it less verbose to import modules found from the executing fileName
  # → Script executed from a technology
  extFilePath = filePath.split("/")
  selfPath = os.path.join(os.path.dirname(__file__),*extFilePath)
  spec = ilib.spec_from_file_location(extFilePath[-1], selfPath)

  md = ilib.module_from_spec(spec)
  spec.loader.exec_module(md)
  return md

ent1 = ezimport("ent1_PCell.py")
ent2 = ezimport("ent2_PCell.py")

class NEW_LIB(pya.Library):

  def __init__(self):

    lib = pya.Library.library_by_name("NEW_LIB")
    if not(lib):
      # Set the description
      self.description = "New Library"
      self.register("NEW_LIB")

    self.lib = pya.Library.library_by_name("NEW_LIB")

    # Create the PCell declarations
    # Register PCells to the already existing NEW_LIB already exists
    self.lib.layout().register_pcell("ENTRY1", ent1.PCell1())
    self.lib.layout().register_pcell("ENTRY2", ent2.PCell2())

    self.lib.register("NEW_LIB") # Only registers internally, won't update the library view
    self.refresh() # Won't do a thing
    lib.refresh() # Won't do a thing

    wid.update() # Won't do a thing
    wid.repaint() # Won't do a thing
    widLib.update() # Won't do a thing
    widLib.repaint() # Won't do a thing

# Instantiate and register the library
NEW_LIB()

Thank you,
Gerard

Comments

  • edited September 19

    I found another way to solve it (through the intended way).
    Using self.register() by the end of the library class, and send self as a parameter for the PCell1 class (be it PCell2 is to be a child of PCell1). The child PCells would be registered inside the definition of the parent PCell class, so only the parent PCells are required to be registered explicitly in the library class.
    One thing I notice however is that the sub-cell name has the library repeated, and hiding the instanced PCell won't hide a standalone one.

    Here's a simplified full code:

    import pya
    
    class PCell2(pya.PCellDeclarationHelper):
      def __init__(self, lib):
        super(PCell2, self).__init__()
    
        self.lib = lib
    
      def display_text_impl(self):
        return "PCell2"
    
      def produce_impl(self):
        poly = pya.Polygon([
          pya.Point(300,0),
          pya.Point(600,0),
          pya.Point(500,200),
          pya.Point(300,200),
        ])
    
        self.cell.shapes(pya.LayerInfo(1)).insert(poly)
    
    
    class PCell1(pya.PCellDeclarationHelper):
    
      def __init__(self, lib):
        super(PCell1, self).__init__()
    
        self.lib = lib
        self.PCell2Id = self.lib.layout().register_pcell("PCell2", PCell2(lib))
    
      def display_text_impl(self):
        return "PCell1"
    
      def produce_impl(self):
    
        inst = self.layout.add_pcell_variant(self.lib, self.PCell2Id, [])
    
        poly = pya.Polygon([
          pya.Point(0,0),
          pya.Point(200,0),
          pya.Point(200,200),
          pya.Point(0,200),
        ])
    
        self.cell.shapes(pya.LayerInfo(1)).insert(poly)
    
        self.cell.insert(pya.CellInstArray(inst, pya.Trans()))
    
    
    class PCELL_LIB(pya.Library):
    
      def __init__(self):
        self.layout().register_pcell("PCell1", PCell1(self))
        self.register("PCELL_LIB")
    
    PCELL_LIB()
    
  • edited September 19

    Hi @Tabra,

    You can register multiple PCells per library.

    Why not just doing:

    class PCell2(pya.PCellDeclarationHelper):
    ...
    
    class PCell1(pya.PCellDeclarationHelper):
    
      def __init__(self, lib):
        super(PCell1, self).__init__()
    
        self.lib = lib
        self.PCell2Id = self.lib.layout().pcell_id("PCell2")
    ...
    
    class PCELL_LIB(pya.Library):
    
      def __init__(self):
        self.layout().register_pcell("PCell2", PCell2(self))   # needs to come first
        self.layout().register_pcell("PCell1", PCell1(self))
        self.register("PCELL_LIB")
    
    PCELL_LIB()
    

    So you just need to register in the proper order. If you delay the "pcell_id" calls to the point when you really need it (in produce_impl), you could even realize recursive dependencies. But I'd say that is bad style.

    Matthias

Sign In or Register to comment.