Example of defining a customized technology¶
In this example, we define a customized technology by extending a predefined technology in ipkiss. We add a layer which is used to open the back-end oxide (top oxide) on top of the waveguides. This can be used to open a window for a sensing application, for instance to let a gas or fluid reach a ring resonator on top of which a window is opened.
- how to create a customized technology file by importing a predefined file
- how to add a new process layer
- how to define import and export settings and visualization
- how to define a virtual fabrication process
- how to alter values in the predefined technology files
Files (see: samples/ipkiss3/samples/wrapped_disk)
There are two files contained in this step.
mytech/__init__.py: this is the file which defines the customized technology
execute.py: this is the file that is executed by python. It defines the covered ring resonator
How to run this example
To run the example, run ‘execute.py’.
We start by creating an empty folder for the new technology (in this example ‘mytech’), and create a file __init__.py.
The __init__.py file starts by importing a predefined technology in ipkiss, and assigning a meaningful name to the technology:
from technologies import silicon_photonics TECH.name = "CUSTOMIZED TECHNOLOGY SAMPLE"
Adding a process layer¶
In order to add a new layer, we need to do two things:
- Add the ProcessLayer - this tells ipkiss about the existance of the layer related to a specific process module
- Add one or more ProcessPurposeLayers - this tells ipkiss which combinations of the new ProcessLayer and PatterPurposes exist. In this sample we’ll add only one.
TECH.PROCESS.OXIDE_OPEN = ProcessLayer(name="OX_OPEN", extension="OXO") TECH.PPLAYER.OXIDE_OPEN = ProcessPurposeLayer(process=TECH.PROCESS.OXIDE_OPEN, purpose=TECH.PURPOSE.DF.TRENCH, name="OX_OPEN")
The TECH.PURPOSE.DF.TRENCH pattern purpose means that the geometries drawn will be etched trenches on a dark (unetched) field.
The technology tree can contain some design rules, defaults or drawing guidelines. In this case, we’ll add a few keys for the minimum width and spacing of patterns on our new OXIDE_OPEN layer:
TECH.OXIDE_OPEN = TechnologyTree() TECH.OXIDE_OPEN.MIN_WIDTH = 10.0 # minimum width of 10.0um TECH.OXIDE_OPEN.MIN_SPACING = 5.0 # minimum spacing of 5.0um
Visualization and import/export settings¶
In order to make the new layer export to GDSII (and import from GDSII), we need to tell ipkiss which layer number to use for the process layer. In the technology example shipped with Ipkiss, every process layer corresponds to a GDSII Layer number, and every pattern purpose corresponds to a GDSII datatype. This can be controlled in a more fine-grained way, but that is outside the scope of this sample.
In order to have Ipkiss visualize the layer using the .visualize() method on a Layout view, we need to set the display style for the ProcessPurposeLayer. In this case, we set it to a yellow color with a 50% transparance.
TECH.GDSII.PROCESS_LAYER_MAP[TECH.PROCESS.OXIDE_OPEN] = 10 DISPLAY_OXIDE_OPEN = DisplayStyle(color = color.COLOR_YELLOW, alpha = 0.5, edgewidth = 1.0) TECH.DISPLAY.DEFAULT_DISPLAY_STYLE_SET.append((TECH.PPLAYER.OXIDE_OPEN, DISPLAY_OXIDE_OPEN))
Overwriting technology keys¶
Overwriting technology settings which were already defined, is possible as well. We can for instance increase the default bend radius on the WG layer to 10 micrometer:
TECH.WG.overwrite_allowed.append("BEND_RADIUS") TECH.WG.BEND_RADIUS = 10.0
Example: ring resonator with back-end opening cover layer¶
In order to use our newly defined technology, we make sure to import it before anything else in the main script. Make sure it is imported before ipkiss3 and before any picazzo library components ! Make sure that your new technology folder (in this case ‘mytech’) is in your PYTHONPATH.
from mytech import TECH import ipkiss3.all as i3 from picazzo3.filters.ring import RingRect180DropFilter
We continue by defining a simple PCell which consists of a ring resonator and a cover layer:
class RingWithWindow(i3.PCell): ring_resonator = i3.ChildCellProperty() def _default_ring_resonator(self): return RingRect180DropFilter() class Layout(i3.LayoutView): def _generate_instances(self, insts): insts += i3.SRef(reference=self.ring_resonator, position=(0.0,0.0)) return insts def _generate_elements(self, elems): si = self.ring_resonator.size_info() size = (min(si.width, TECH.OXIDE_OPEN.MIN_WIDTH), min(si.height, TECH.OXIDE_OPEN.MIN_WIDTH)) # use rule in tech elems += i3.Rectangle(layer=TECH.PPLAYER.OXIDE_OPEN, center=(0.0,0.0), box_size=size) return elems
We can now instantiate the component, visualize its layout and export to GDSII:
R = RingWithWindow(name="ring_with_window") Rlayout = R.Layout() Rlayout.visualize() # show layout elements Rlayout.visualize_2d() # virtually fabricated Rlayout.write_gdsii("ring_with_window.gds")
- First simple circuit design
- Example of a Disk Resonator with Wraparound waveguide
- Example of an athermal Mach-Zehnder Interferometer
- Example of a Mach-Zehnder Lattice filter
- Example of a customized Place and Route cell
- Example of defining a customized technology
- Creating a Cell from an Existing GDSII file