Last active
December 17, 2024 08:48
-
-
Save g2hollow/9c6954749e9da7786cbee373909dca3c to your computer and use it in GitHub Desktop.
klayout macro pcell sprial
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pya | |
import math | |
""" | |
This sample PCell implements a library called "MyLib" with a single PCell that | |
draws a sprial. It demonstrates the basic implementation techniques for a PCell | |
and how to use the "guiding shape" feature to implement a handle for the inner | |
and out radii of the spiral. | |
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 Spiral(pya.PCellDeclarationHelper): | |
""" | |
The PCell declaration for the sprial | |
""" | |
def __init__(self): | |
# Important: initialize the super class | |
super(Spiral, self).__init__() | |
# declare the parameters | |
self.param("l", self.TypeLayer, "Layer", default = pya.LayerInfo(1, 0)) | |
self.param("n", self.TypeInt, "Number of points", default = 64) | |
self.param("inner_r", self.TypeDouble, "Inner Radius", default = 1) | |
self.param("outer_r", self.TypeDouble, "Outer Radius", default = 10) | |
self.param("width", self.TypeDouble, "Width", default = 1) | |
self.param("spacing", self.TypeDouble, "Spacing", default = 1) | |
self.param("inner_handle", self.TypeShape, "", default = pya.DPoint(0, 0)) | |
self.param("outer_handle", self.TypeShape, "", default = pya.DPoint(0, 0)) | |
# this hidden parameter is used to determine whether the radii have changed | |
# or the "inner/outer" handles have been moved | |
self.param("inner_mem", self.TypeDouble, "Inner_mem", default = 0.0, hidden = True) | |
self.param("outer_mem", self.TypeDouble, "outer_mem", default = 0.0, hidden = True) | |
def display_text_impl(self): | |
# Provide a descriptive text for the cell | |
return "Spiral(L=" + str(self.l) + ",Outer radius=" + ('%.3f' % self.outer_r) + ")" | |
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 | |
# radii *_handle_radius) and set *_mem to the effective radius. We also update the | |
# numerical value or the shape, depending on which on has not changed. | |
inner_handle_radius = None | |
outer_handle_radius = None | |
if isinstance(self.inner_handle, pya.DPoint): | |
# compute distance in micron | |
inner_handle_radius = self.inner_handle.distance(pya.DPoint(0, 0)) | |
if isinstance(self.outer_handle, pya.DPoint): | |
# compute distance in micron | |
outer_handle_radius = self.outer_handle.distance(pya.DPoint(0, 0)) | |
if abs(self.inner_r-self.inner_mem) < 1e-6 and abs(self.outer_r-self.outer_mem) < 1e-6: | |
self.inner_mem = inner_handle_radius | |
self.inner_r = inner_handle_radius | |
self.outer_mem = outer_handle_radius | |
self.outer_r = outer_handle_radius | |
else: | |
self.inner_mem = self.inner_r | |
self.inner_handle = pya.DPoint(-self.inner_r, 0) | |
self.outer_mem = self.outer_r | |
self.outer_handle = pya.DPoint(-self.outer_r, 0) | |
# n must be larger or equal than 4 | |
if self.n <= 4: | |
self.n = 4 | |
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 inner/outr_r and l | |
#from the shape's bounding box width and layer | |
self.inner_r = self.shape.bbox().width() * self.layout.dbu / 4 | |
self.outer_r = self.shape.bbox().width() * self.layout.dbu / 2 | |
self.l = self.layout.get_info(self.layer) | |
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 | |
# fetch the parameters convert to database units | |
inner_r_dbu = self.inner_r / self.layout.dbu | |
outer_r_dbu = self.outer_r / self.layout.dbu | |
# compute the spiral | |
pts = [] | |
da = math.pi * 2 / self.n | |
dr = (self.width+self.spacing)/self.n/self.layout.dbu | |
current_radius = inner_r_dbu | |
current_angle = 0 | |
while current_radius < outer_r_dbu: | |
pts.append(pya.Point.from_dpoint(pya.DPoint(current_radius * math.cos(current_angle), current_radius * math.sin(current_angle)))) | |
current_radius += dr | |
current_angle = (current_angle+da)%(math.pi*2) | |
# create the shape | |
self.cell.shapes(self.l_layer).insert(pya.Path(pts,self.width/self.layout.dbu)) | |
class MyLib(pya.Library): | |
""" | |
The library where we will put the PCell into | |
""" | |
def __init__(self): | |
# Set the description | |
self.description = "My First Library" | |
# Create the PCell declarations | |
self.layout().register_pcell("Spiral", Spiral()) | |
# 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("MyLib") | |
# Instantiate and register the library | |
MyLib() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello and thank you for your nice video. I am trying to make a Macro for serpentine pattern. Could you please help me?