Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Setting properties for PCells

Hi

I am slightly lost in user properties. I understand, that Shape, Cell and CellInstance can all have their properties. I would like to pass some information about a PCell via the properties, but if I use self.cell.set_property(name, value) in produce_impl of a PCellDeclarationHelper, the property does not appear for either PCell variant (one in the Cell view on the left) nor for cell instance (one in the design). How could I set properties for the instances of PCell in the PCell definition code?

Comments

  • Hi,

    you cannot. A PCell shall deliver layout and not modify the external attributes of a cell (such as name, placement, etc.). The user properties are among the external attributes. Instances cannot be accessed from within the PCell because KLayout will optimize the PCell generation such that different instances with the same parameter set will share the same PCellVariant.

    You can use hidden PCell parameters to keep information you don't what to show up in the user interface, if that is the intention should have.

    Regards,

    Matthias

  • edited February 4

    My specific goal was to export Sonnet project files and use properties to define port locations. Then, a script could export all cells irrespective if they are PCell variants or manually created.

    I think I can use the properties of the shapes in the Cell for now.

    Initially I thought, that instances would inherit user properties from a PCell variant. But it seems that even PCell variant does not get the properties of the produced PCell.

  • Hello,

    Yes, shape properties are possible. You could also use texts to label the ports, if that is an option.

    Instance properties cannot be used because the PCell is the target of the instance, not the instance itself. Multiple instances can share the same PCell variant (variant in terms of PCell parameters). Hence there is no connection back from the PCell variant to the instance.

    If you really, really want to have an instance with properties you can create a cell inside the PCell and produce in instance of this cell inside ... but I'd only do this is absolutely necessary.

    Regards,

    Matthias

  • Thank you for the reply (and the great software)!

    Is instances inheriting properties of the cell variants a bad idea? Obliviously many instances would share the inherited properties. And cell variants could get properties during the production.

    I already use text to annotate the ports for users. For Sonnet files I need to tell the index of the polygon edge to be used as a port and finding the edge under a text position seems a bit inefficient. For this purpose I now use the property of the shape.

  • Shape properties are fine. Instances have their own properties and it's not common to have instances inherit cell properties. Both are different concepts and used for very different purposes, so I'd not mix that.

    Matthias

  • edited March 19

    I keep pumping into the same issue and from reading the Q&A regarding the Circle PCell parameters I think other people have reached the same point. I define a lot of features in PCellDeclarationHelper. It generates geometry, but some of the intermediate results are useful for other object and I want to access them.

    First, why do I keep using PCells: I want to make use of API handling copies of cells with same parameters - this is a very nice feature. Also, then a user can turn the top cell into static and change parameters of the children.

    Second, why do I define the geometry and other calculations inside PCellDeclarationHelper? I want to initiate my object via a single interface. If the geometry was defined in another object, I would initiate the geometry object to extract intermediate results and then initialize the library PCell with the same arguments. I want to avoid doing it twice and keep using PCells. Thus, the geometry is defined behind PCell.

    Useful intermediate results from PCells: First, there are geometric locations, which other constructs need to relate to. These I can "leak out" from PCellDeclarationHelper inside coordinates of the Text objects on an extra layer. This is reasonable (although it would be very nice to see some mark at the exact location of Text). However, there are other useful quantities as well. For example, an index for a special polygon edge or a length of my waveguide with rounded edges. How to "leak" them out from PCellDeclarationHelper? I tried two approaches.

    Readonly pcell_parameter - it seems, that they get updated only after a call to coerce_parameters_impl and this only happens after event on the GUI. If I create an instance in the code, the coerce_parameters is never evoked and non of the parameter values is updated even if I set the value in produce_impl. Is that true? Is it possible to work around this? I also tried layout.update().

    Property of Cell objects. Inside PCellDeclarationHelper we have access to some self.cell, to which we add shapes. But if I set self.cell.set_property, these properties are not passed to the Cell object given by layout.create_cell, and also it is not passed to the Instance returned by topcell.insert. This relates to the discussion we had above.

    How to pass out internal variables of PCellDeclarationHelper?

    To check my claims I modified the Circle example by adding the following lines to the end of produce_impl:

        self.cell.set_property("test", "test")
        self.ru = self.r
        print("Prop Inside:", self.cell.property("test"))
        print("Parm Inside:", self.ru)
    

    And in a macro I had following lines:

    params = {"r":105}
    lib = layout.create_cell("Circle", "QCircuit", params)
    inst = cell.insert(pya.DCellInstArray(lib.cell_index(), pya.DTrans(pya.DVector(0, -1200))))
    print("Init only")
    print(layout.properties(lib.prop_id))
    print(layout.properties(inst.prop_id))
    print("Prop Outside inst:",inst.property("test"))
    print("Prop Outside lib:",lib.property("test"))
    print("Param Outside inst:", inst.pcell_parameters_by_name())
    print("Param Outside lib:", lib.pcell_parameters_by_name())
    
    inst.change_pcell_parameters( {"r":101})
    print("Inst param reset")
    print(layout.properties(lib.prop_id))
    print(layout.properties(inst.prop_id))
    print("Prop Outside inst:",inst.property("test"))
    print("Prop Outside lib:",lib.property("test"))
    print("Param Outside inst:", inst.pcell_parameters_by_name())
    print("Param Outside lib:", lib.pcell_parameters_by_name())
    
    layout.update()
    print("Update")
    print(layout.properties(lib.prop_id))
    print(layout.properties(inst.prop_id))
    print("Prop Outside inst:",inst.property("test"))
    print("Prop Outside lib:",lib.property("test"))
    print("Param Outside inst:", inst.pcell_parameters_by_name())
    print("Param Outside lib:", lib.pcell_parameters_by_name())
    

    And here is the output I got:

    Prop Inside: test
    Parm Inside: 109
    Init only
    []
    []
    Prop Outside inst: None
    Prop Outside lib: None
    Param Outside inst: {'l': 1/0, 'rd': None, 'r': 109, 'n': 64, 's': 0,0, 'ru': 0.0}
    Param Outside lib: {'l': 1/0, 'rd': None, 'r': 109, 'n': 64, 's': 0,0, 'ru': 0.0}
    Joonistab
    Prop Inside: test
    Parm Inside: 110
    Inst param reset
    []
    []
    Prop Outside inst: None
    Prop Outside lib: None
    Param Outside inst: {'l': 1/0, 'rd': None, 'r': 110, 'n': 64, 's': 0,0, 'ru': 0.0}
    Param Outside lib: {'l': 1/0, 'rd': None, 'r': 109, 'n': 64, 's': 0,0, 'ru': 0.0}
    Update
    []
    []
    Prop Outside inst: None
    Prop Outside lib: None
    Param Outside inst: {'l': 1/0, 'rd': None, 'r': 110, 'n': 64, 's': 0,0, 'ru': 0.0}
    Param Outside lib: {'l': 1/0, 'rd': None, 'r': 109, 'n': 64, 's': 0,0, 'ru': 0.0}
    

    If I open the PCell parameters window in the GUI and only click apply, I get extra output

    Prop Inside: test
    Parm Inside: 109,0
    

    and if I run single a print command of the macro again, I get

     Param Outside inst: {'l': 'Optical lit. 1' (1/0), 'rd': 218.0, 'r': 109.0, 'n': 64, 's': -109,0, 'ru': 109.0}
    

    as expected.

    I would have been happy, if the output before touching GUI would have included

    ["test":"test"]
    Prop Outside lib: "test"
    Param Outside inst: {'l': 1/0, 'rd': None, 'r': 110, 'n': 64, 's': 0,0, 'ru': 110}
    

    or something similar.

    I know, that I could have set 'ru' in params, but my goal was to calculate something inside PCellDeclarationHelper.

    I hope you see my point and can suggest a workaround. Perhaps, if I understood it all correctly and you consider adding features, I suggest that PCell parameter update was invoked by some additional events via API and the self.cell parameters form PCellDeclarationHelper would be passed to Cell objects in the layout.

    KLayout version 0.25.6, Windows 64 bit build obtained from Lukas via the package manger.

  • edited March 20

    Hi,

    thanks for the lengthy description ... this discussions isn't new, but here are my points:

    1.) doing something from inside the PCell to the objects that use the PCell simply isn't possible. You shouldn't underestimate the complexity of the whole system. The PCell might live in a library which is shared by multiple layouts etc. So then what is the cell or instance that is the PCell in your layout? The cell you see is a pointer (a proxy) to another cell inside a library which itself is a proxy to a PCell variant. The cell you get when you create PCell geometry is the PCell variant proxy. It's cached for performance and two links away from the actual layout. So setting properties on the target layout's cell or even instance simply isn't possible.

    2.) The only storage KLayout gives you are the parameters. Only these are persisted in GDS (how this is done is a discussion on it's own). So using hidden parameters is the only way to store additional attributes.

    It's true that "coerce_parameters"/"coerce_parameters_impl" is only called on manual changes. That's because the user cannot change readonly or hidden parameters. So "coerce_parameters_impl" is there to compute these values.

    When changing parameters programmatically, you don't have this limitation. So you're expected to supply the PCell implementation with the right and consistent parameters. You could even supply a parameter set that goes beyond what is possible in the UI+coerce_parameters. If you really want to have coerce_parameters, you can explicitly call "coerce_parameters" (note: without "_impl"):

    inst = ... # A PCell Instance. 
    # This assumes the PCell is in a library. If not, change "cell().library().layout()" to "cell().layout()":
    inst.change_pcell_parameters(inst.pcell_declaration().coerce_parameters(inst.cell().library().layout(), inst.pcell_parameters()))
    

    There is a strong restriction when a PCell's state can be changed: the functions by which the PCell is supposed to deliver information (update geometry, derive description etc.) are operated in strict readonly mode and cannot modify anything on the PCell. To understand that in detail, you can study the PCellDeclarationHelper implementation which is a thin layer atop of PCellDeclaration. This object lacks some of the convenience of the PCellDeclarationHelper but reveals the strict, low-level API.

    Regards,

    Matthias

  • edited March 21

    Thank you for a detailed reply! I had a look at pcell_declaration_helper.lymand learned about what you described. However, I think I still did not make my goal clear. Sorry for insisting.

    doing something from inside the PCell to the objects that use the PCell simply isn't possible

    I never intend to change instance from PCell declaration, I only want to read PCell Cell properties. lib object in my code is the library Cell, a PCell variant stored in the library layout, right? Why does lib.property("test") or lib.library().layout().properties(lib.library().layout().cell(lib.library_cell_index()).prop_id) not show properties I have set in produce? Somehow produce has added shapes to the Cell, but not the cell parameters.

    So you're expected to supply the PCell implementation with the right and consistent parameters.

    This is clear, but I would use some parameters as inputs and some readonly parameters as outputs. From the documentation alone it was not clear that only coerce_parameters can update parameters. The workaround you suggest works. Now I have to calculate geometry both in coerce_parameters and produce though.

  • Good that it works now :-)

    The answer to your question

    Why does lib.property("test") or lib.library().layout().properties(lib.library().layout().cell(lib.library_cell_index()).prop_id) not show properties I have set in produce? Somehow produce has added shapes to the Cell, but not the cell parameters.

    is simply that "produce" is only intended to produce shapes and instances. By "intended" I mean I have designed it for this purpose and this is the contract between KLayout's core and the PCell implementation. So trying to do something else is working against my design and this contract.

    The cell object this method receives is just a container, not necessarily a real cell. Take caching: in this case, "produce" isn't even called. KLayout will take the data from the cell which acts as the data container for the cache. Think of "cell" as "multi-layered container for shapes plus instances", not as something that lives in your target layout. Properties simply aren't part of this concept. Note also that there is no warranty that "produce" is called if KLayout decides that no update is required. The basis KLayout makes this decision is the parameter set alone. The assumption is that if there is no parameter change, not update is required.

    Matthias

Sign In or Register to comment.