It looks like you're new here. If you want to get involved, click one of these buttons!
Hello,
I am using Klayout for tasks where I probably should just learn SKILL programming. But anyway, I need to create some large hierarchical structures and it is expected that I keep the hierarchy (no flattening) so I build a rather big tower of cells used in cells. I recently started to parameterise this tower to pcells. This worked rather well but I hit one roadblock: If I instantiate a pcell recursively it fails.
I have a small testcase:
class TestCase(pya.PCellDeclarationHelper):
def __init__(self):
super().__init__()
self.param("level", self.TypeInt, "Level", default = 1)
self.param("width", self.TypeDouble, "Width", default = 1.0)
self.param("lay", self.TypeLayer, "Layer", default=pya.LayerInfo(1,0,"ZERO"))
def display_text_impl(self):
return f"{self.__class__.__name__}({self.width:.3f})"
def coerce_parameters_impl(self):
if self.level < 0:
raise ValueError("Error")
def produce_impl(self):
lib = self.layout.library()
pcell_decl = lib.layout().pcell_declaration("TestCase")
self.cell.shapes(self.lay_layer).insert(pya.DBox(pya.DPoint(-0.5*self.width, -0.5*self.width), pya.DPoint(0.5*self.width, 0.5*self.width)))
if self.level > 0:
pcell_variant = self.layout.add_pcell_variant(pcell_decl.id(), [self.level-1, self.width / 3, self.lay])
width_3 = self.width/3
self.cell.insert(pya.CellArrayInstance(pcell_variant, pya.DTrans(-width_3,2*width_3)))
self.cell.insert(pya.CellArrayInstance(pcell_variant, pya.DTrans(width_3,2*width_3)))
As soon as I try to create the new pcell_variant
the self
structure gets destroyed (all instance-variables are still there but nil). A bit digging shows that coerce_parameters_impl
is called with the parameters I expect but always with the same self
value.
It is only the recursive case which creates the problem. Instantiating other pcells works without problems.
I tested klayout-0.27.10 (our IT approved default installation) and klayout-0.29.1on Windows.
Any hints?
Juergen
Comments
Well, you're right. The helper class is actually singleton-style and not re-entrant.
Recursive PCells sound freaky though.
You can code the PCell based on the underlying
PCellDeclaration
object instead ofPCellDeclarationHelper
. This class is stateless and should basically support recursive PCells.Technically, the helper class will provide some services such as decoding the PCell parameter array into named parameters and using temporary attributes.
Here is an example:
init_values
sets attributes named like the PCell parameters and then calls the parameter-less "produce_impl" method. So instead of implementing "produce_impl", but "produce", your method becomes re-entrant. But you will also nee to implement the other methods based on their basic interface.Another option is to register a per-level, parametrized PCell
and inside your function your instantiate the
level - 1
version. This may be kind of clumsy from the user perspective, but provides a natural way to select the levels and also naturally limits the number of levels.I am not sure if you can do recursive PCells with Cadence. Skill is not fully stateless either - even if you carefully use "let" for local variable namespace.
Matthias
P.S. instead of the older "add_pcell_variant", you can use "create_cell" with a PCell name and a parameter hash. That is somewhat easier to use.
Thanks for the feedback.
I tried to work with
PCellDeclaration
directly and it actually work. It took me some time to understand the interface, but I like it more than thePCellDeclarationHelper
interface. Much less magic, everything is just function arguments. Though I lost the direct by name access to parameters.BTW: I tried to use the
create_cell
but I always got nil. The older way just worked for me.For reference, this is now my working example: