Technology
In every IPKISS Python script or IPKISS Canvas design you will import a process design kit that has a TECHNOLOGY file.
The goal of the technology file is to describe general settings that are stable across several designs that use the same fab.
These technology settings are managed in a tree structure, rooted in an object created by IPKISS in the module
ipkiss.technology
. Each leaf of this tree we call a technology key
or tech key
.
Although you are free to add whatever you want to a TECHNOLOGY file the following aspects of your design process are usually described by it.
Layers: Contains all the available process layers, drawing pattern purposes, and combinations thereof: ProcessPurposeLayers
Rules and metrics: Contains the general settings for the grid on which shapes are discretized, and design rules for different process layers.
GDSII settings: Contains GDSII import and export settings.
Display settings: Contains settings that are used in visualization routines of IPKISS.
Materials: Materials and materials stacks
Virtual fabrication settings: Contains the description of the virtual fabrication processes that can transform a GDSII mask in a virtually fabricated structure.
Traces: Contains the description of the default waveguides that are used.
Grating Couplers: Contains the description of the default grating couplers that are used.
(Optional) PICAZZO: Technology settings (‘keys’) to be defined in order for PICAZZO to work. If these are not defined you’ll still be able to use IPKISS.
In this guide we will illustrate these concepts so that you can build you own technology file.
Note
This guide assumes knowledge of semiconductor process technology and terminology.
Getting started
IPKISS relies on the definition of a range of technology keys for its proper functioning and tailoring to a specific technology.
As of Luceda 2025.09, all layer-related settings are specified in a single, human-readable configuration file: tech.yaml
.
Creating a basic new design kit technology that enables ipkiss3 features to work with default parameters is simple.
First, create a tech.yaml
configuration file in your technology
folder.
# tech.yaml for pdkname
# This file defines the technology settings for the pdkname PDK.
# It replaces the Python-based technology definition.
Then, create an __init__.py
file in your technology
folder to load the YAML configuration:
__all__ = ["TECH"]
from luceda import technology
TECH = technology.load_tech() # Loads the tech.yaml file
If you adhered to the tech.yaml
naming scheme, then the YAML file will be automatically discovered and loaded, otherwise the name will have to be provided.
This should leave you with the following PDK structure:
pdkname
├── pdkname.cfg
└── ipkiss
└── pdkname
├── technology
│ ├── __init__.py
│ └── tech.yaml
├── __init__.py
└── all.py
When using tech.yaml
like this to specify your technology, many keys will already have a default value to help you to get started quickly.
You can then override the values specific to your technology.
For instance, the default GDSII mask grid in IPKISS is 1nm. To create a technology file with a 5nm GDSII grid, you will need to specify it in your tech.yaml
as follows:
# tech.yaml for pdkname
# This file defines the technology settings for the pdkname PDK.
# It replaces the Python-based technology definition.
# Example of overriding default values:
settings:
metrics:
grid: 5.0e-09 # 5nm GDSII grid
All supported keys and default values for the YAML configuration file are listed in PDK Tech Configuration Schema Reference.
Technology structure
General anatomy of a TECH-tree
A technology in IPKISS is built as a TREE of objects of TechnologyTree
.

TechnologyTree
As depicted in the figure above each purple box is object of the TechnologyTree
that can contain settings of any kind (depicted in green).
Creating your own TECH amounts to building up such a tree and to place the relevant settings in the leaves.
Settings related to layers can be configured through a tech.yaml
file, that will then be converted to such a tree.
Other more advanced settings (like those related to virtual fabrication), have to be configured by writing
Python code to generate the tree structure.
Technology tree structure
The general tree hierarchy is as follows. PDK developers can add their own subtrees, but the shown tree is the minimum required for IPKISS to work.
TECH
├── ADMIN
├── METRICS
├── PROCESS
├── PURPOSE
├── PPLAYER
├── DISPLAY
├── GDSII
├── OPENACCESS
├── VFABRICATION
├── MATERIALS
├── MATERIAL_STACKS
├── PCELLS
├── BLOCKS
├── PORT
├── TRACE
├── WG_DEFAULTS
├── WG
├── VIAS
├── METAL
Recommended file structure
Simple technology files can be entirely defined in a tech.yaml
file within the technology
folder of your PDK. This approach simplifies the technology definition and makes it more readable.
Not all features are currently supported in the YAML file however, so we recommend that you use the file structure that is used in the si_fab
example PDK.
You could for instance just start by copying it completely and make changes gradually.
pdkname
└── technology
├── __init__.py
├── fibcoup.py
├── materials.py
├── oa_routing.py
├── picazzo.py
├── routing.py
├── rules.py
├── tech.yaml
├── transitions.py
└── vfab.py
This file structure is built up in such a way that the entire technology is imported upon the statement:
import si_fab.all as pdk
If you want to create your own technology, put tech.yaml
inside the technology
folder.
This folder should contain an __init__.py
file that will convert the data defined in tech.yaml
into a technolog tree.
__init__.py
should also import other files defined in the technology
folder, to import keys that can’t be set (yet) using tech.yaml
.
Typically each of the other Python files will contain Python code to configure one branch of the technology tree.
An example of an __init_.py
file looks like this:
__all__ = ["TECH"]
from luceda import technology
TECH = technology.load_tech(techname="MY_PDK")
from . import materials as _
As an example, this is the __init__.py
file from the si_fab
technology.
# flake8: noqa
# ###############################################################
# SI_FAB: Demonstration PDK for Photonics Design
#
# copyright Luceda Photonics 2016
#
# ###############################################################
# Technology data
# ###############################################################
#
# The following imports load the different parts of the
# Technology tree
__all__ = ["TECH"]
from luceda import technology
TECH = technology.load_tech(techname="SI_FAB")
from . import rules as _ # Constants for various design parameters
from . import routing as _ # Sets the rules for optical and electrical routing
from . import picazzo as _ # Required TECH keys for picazzo
from . import fibcoup as _ # Input-output: fiber couplers, iocolumns
from . import materials as _ # Materials and material stacks
from . import transitions as _ # Auto-transitions
from . import vfab as _ # Virtual fabrication
from . import oa_routing as _
from ..components.waveguides.wire import transition as _ # Load the transitions in the AUTOTRANSITIONDATABASE
from ..components.waveguides.rib import transition as _ # Load the transitions in the AUTOTRANSITIONDATABASE
Adding custom and advanced tech keys
The code below illustrates how to set keys that can’t be set through tech.yaml
.
from ipkiss.technology import get_technology
from ipkiss.technology.technology import TechnologyTree
TECH = get_technology()
TECH.MYSETTINGS = TechnologyTree()
TECH.MYSETTINGS.SET1 = 10.0
TECH.MYSETTINGS.MYFIRSTSUBJECT = TechnologyTree()
TECH.MYSETTINGS.MYFIRSTSUBJECT.SET1 = "Hello"
TECH.MYSETTINGS.MYFIRSTSUBJECT.SET2 = 300.0
print(TECH.MYSETTINGS.MYFIRSTSUBJECT.SET1)
Technology tree keys
There are many settings in the technology tree that can be overridden. We will elaborate over the most important ones.
Name of the technology
When creating a new technology file, you should give it a name:
from luceda import technology
TECH = technology.load_tech(techname="SI_FAB")
Layers
Process layers and drawing purposes define the available ProcessLayers
, PatternPurpose
, and
combinations thereof, known as ProcessPurposeLayer
.
Process Layers
A ProcessLayer
describes a process module with a specific function, such as a waveguide, fiber coupler, rib etch, implants, or metalization.
The process layers that are defined in the YAML configuration file can be accessed as TECH.PROCESS.<name>
,
where <name>
is the name you specified in the YAML file.
This is how it is done in the si_fab
technology:
layers:
- {name: NONE, doc: No specific process, number: 100, ipkiss: {name: No specific process}}
- {name: SI, doc: Unetched silicon, number: 1, ipkiss: {name: Unetched silicon}}
- {name: SHALLOW, doc: Fiber Couplers and Rib Waveguide (shallow etched Si), number: 2, ipkiss: {name: Fiber Couplers and Rib Waveguide (shallow etched Si)}}
- {name: SIN, doc: Silicon nitride, number: 6, ipkiss: {name: Silicon nitride}}
- {name: SIN_SHALLOW, doc: 'Thin silicon nitride layer, used for edge couplers', number: 7, ipkiss: {name: 'Thin silicon nitride layer, used for edge couplers'}}
- {name: HT, doc: Heater, number: 1000, ipkiss: {name: Heater}}
- {name: M1, doc: Metallization 1, number: 3, ipkiss: {name: Metallization 1}}
- {name: M2, doc: Metallization 2, number: 4, ipkiss: {name: Metallization 2}}
- {name: V12, doc: Via between M1 and M2, number: 5, ipkiss: {name: Via between M1 and M2}}
- {name: N, doc: N+ implant, number: 11, ipkiss: {name: N+ implant}}
- {name: P, doc: P+ implant, number: 12, ipkiss: {name: P+ implant}}
- {name: GE, doc: Germanium, number: 16, ipkiss: {name: Germanium}}
- {name: NPLUS, doc: N++ implant, number: 13, ipkiss: {name: N++ implant}}
- {name: PPLUS, doc: P++ implant, number: 14, ipkiss: {name: P++ implant}}
- {name: CON, doc: Contact, number: 15, ipkiss: {name: Contact}}
- {name: BEZ_S, doc: BEZ_S, number: 300}
- {name: BEZ_B, doc: BEZ_B, number: 301}
- {name: BEZ_U, doc: BEZ_U, number: 302}
- {name: SB, doc: SB, number: 303}
Pattern Purposes
A PatternPurpose
describes different purposes for drawing on a mask.
This discriminates between types of drawing that will end up on the actual mask (e.g., trenches vs. holes vs. lines) or types of data that do not directly end up on the mask (e.g., exclusion zones, DRC waiver zones, pin recognition, device recognition).
As a result, pattern purposes are described with the process engineer in mind, not the designer who starts from functional devices.
The default mask drawing-related purposes in Ipkiss are divided according to mask polarity: dark field or light field. How that translates into the specific process depends on the lithographic resist tone (positive or negative), which is not considered here. The process engineer who defines the possible combinations between process layers and pattern purposes knows this, and the designer should not need to “care.”
Every PatternPurpose
has a name (e.g., “Dark-field Line”) and an extension (e.g., “DFLIN”).
The purpose layers that are defined in the YAML configuration file can be accessed as TECH.PURPOSE.<name>
,
where <name>
is the name you specified in the YAML file.
This is how we define the Light Field pattern in the si_fab
technology:
purposes:
- {name: ERROR, number: 100, ipkiss: {name: Error, extension: ERR}}
- {name: DOC, number: 50, ipkiss: {name: Documentation}}
- {name: TRACE, number: 25, ipkiss: {name: Trace, extension: TRC}}
- {name: PINREC, number: 22, ipkiss: {name: Pin recognition, extension: PIN}}
- {name: DEVREC, number: 1000, ipkiss: {name: Device recognition}}
- {name: BBOX, number: 21, ipkiss: {name: Bounding Box}}
- {name: SIMBND, number: 1001, ipkiss: {name: Simulation boundary}}
- {name: IGNORE, number: 1002, ipkiss: {name: Ignored}}
- {name: DRWSUB, number: 26, ipkiss: {name: Subtracted drawing}}
- {name: TEXT, number: 24, ipkiss: {name: Text, extension: TXT}}
- {name: UNUSED, number: 101, ipkiss: {name: Unused}}
Process-Purpose Layers
The process engineer defines the possible combinations between ProcessLayer
and PatternPurposes.
Some ProcessLayers
may only have drawings in one PatternPurpose
, whereas others may have many PatternPurpose
associated.
Each (ProcessLayer, PatternPurpose) pair is defined as a ProcessPurposeLayer (PPLayer).
We make the translation between the process engineer and the designer using these ProcessPurposeLayer
objects.
Whereas the ProcessLayers and specifically the PatternPurpose
make more sense to the process engineer,
we give the ProcessPurposeLayer
names and descriptions that make functional sense to the designer (e.g., “waveguide core,” “fiber coupler trenches,” “exclusion zone,” “implanted area”).
The process-purpose layers that are defined in the YAML configuration file can be accessed as TECH.PPLAYER.<name>
,
where <name>
is the name you specified in the YAML file.
This is how we define the Process-Purpose pairs (layer-purpose pairs) in the si_fab
technology:
lpps:
- {name: SI, lpp: [SI, DRAWING]}
- {name: SI_TRENCH, lpp: [SI, DRWSUB]}
- {name: SI_CLADDING, lpp: [SI, UNUSED]}
- {name: TEXT, lpp: [SI, TEXT]}
- {name: SHALLOW, lpp: [SHALLOW, DRAWING]}
- {name: SHALLOW_TRENCH, lpp: [SHALLOW, DRWSUB]}
- {name: SIN, lpp: [SIN, DRAWING]}
- {name: SIN_CLADDING, lpp: [SIN, UNUSED]}
- {name: SIN_SHALLOW, lpp: [SIN_SHALLOW, DRAWING]}
- {name: SIN_SHALLOW_TRENCH, lpp: [SIN_SHALLOW, DRWSUB]}
- {name: GE, lpp: [GE, DRAWING]}
- {name: HT, lpp: [HT, DRAWING]}
- {name: M1, lpp: [M1, DRAWING]}
- {name: M2, lpp: [M2, DRAWING]}
- {name: V12, lpp: [V12, DRAWING]}
- {name: N, lpp: [N, DRAWING], ipkiss: {name: N_DRW}}
- {name: NPLUS, lpp: [NPLUS, DRAWING], ipkiss: {name: NPLUS_DRW}}
- {name: P, lpp: [P, DRAWING], ipkiss: {name: P_DRW}}
- {name: PPLUS, lpp: [PPLUS, DRAWING], ipkiss: {name: PPLUS_DRW}}
- {name: PINREC, lpp: [NONE, PINREC]}
- {name: NONE, lpp: [NONE, UNUSED]}
- {name: CON, lpp: [CON, DRAWING], ipkiss: {name: CON_DRW}}
- {name: DOC, lpp: [NONE, DOC]}
- {name: WIRE_TRACE, lpp: [SI, TRACE], ipkiss: {name: WIRE_TRC}}
- {name: RIB_TRACE, lpp: [SHALLOW, TRACE], ipkiss: {name: RIB_TRC}}
- {name: BEZ_S, lpp: [BEZ_S, TRACE], ipkiss: {name: layer0}}
- {name: BEZ_B, lpp: [BEZ_B, DRAWING]}
- {name: BEZ_U, lpp: [BEZ_U, DRAWING]}
- {name: SB, lpp: [SB, DRAWING]}
- {name: ERROR_GENERIC, lpp: [NONE, ERROR], ipkiss: {tech_path: [ERROR, GENERIC], name: ERROR}}
GDSII
The TECH tree contains GDSII import and export settings from IPKISS to GDSII. The settings make sure that there is a mapping between each PPlayer (ProcessLayer, PatternPurpose) in IPKISS and (Layer, Datatype) in GDSII.
In addition, several settings and filters ensure that we can export GDSII files compatible with the back-end maskprep tools used. These are made by default and we don’t need to touch.
GDSII layer tables
The TECH.GDSII.LAYERTABLE key maps (ProcessLayer, PatternPurpose) and GDSII (Layer, Datatype) pairs. Only these layers are exported/imported. Others are ignored upon export, or an error is raised upon import.
These can be configured via the tech.yaml
file under the gds.layer_table
key. For example:
gds:
layer_table:
- {lpp: [SI, DRAWING], number: [1, 0]}
- {lpp: [SI, TEXT], number: [1, 1]}
- {lpp: [SI, DRWSUB], number: [1, 2]}
- {lpp: [SHALLOW, DRAWING], number: [2, 0]}
- {lpp: [SHALLOW, DRWSUB], number: [2, 2]}
- {lpp: [SIN, DRAWING], number: [3, 0]}
- {lpp: [SIN_SHALLOW, DRAWING], number: [4, 0]}
- {lpp: [SIN_SHALLOW, DRWSUB], number: [4, 2]}
- {lpp: [N, DRAWING], number: [5, 0]}
- {lpp: [NPLUS, DRAWING], number: [6, 0]}
- {lpp: [P, DRAWING], number: [7, 0]}
- {lpp: [PPLUS, DRAWING], number: [8, 0]}
- {lpp: [CON, DRAWING], number: [11, 0]}
- {lpp: [HT, DRAWING], number: [15, 0]}
- {lpp: [M1, DRAWING], number: [20, 0]}
- {lpp: [V12, DRAWING], number: [21, 0]}
- {lpp: [M2, DRAWING], number: [22, 0]}
- {lpp: [GE, DRAWING], number: [30, 0]}
- {lpp: [NONE, DOC], number: [50, 0]}
- {lpp: [NONE, ERROR], number: [50, 1]}
- {lpp: [SI, UNUSED], number: [50, 2]}
- {lpp: [SIN, UNUSED], number: [50, 12]}
- {lpp: [NONE, PINREC], number: [50, 3]}
Display Settings
IPKISS contains several visualization functions such as visualize
. The display settings and their association with the ProcessPurposeLayer
for visualization
is defined in the TECH.DISPLAY tree. The display settings are set in an object of the DisplayStyle
. Each ProcessPurposeLayer
that needs to be visualized can be then be associated with a DisplayStyle
to form a DisplayStyleSet
.
The DisplayStyleSet
is then added to TECH.DISPLAY.DEFAULT_DISPLAY_STYLE_SET
Here is a simplified example - the same technique is used in the si_fab technology.
display:
lpps:
- lpp: Metal1
color: luceda_purple
alpha: 0.5
pattern: lines-diagonal-right
edge_width: 2
edge_color: [123, 0, 255]
custom_colors:
luceda_purple: "#7b7bfc"
luceda_green: [12, 234, 21]
Materials
Materials and their settings are added using two trees in the TECH tree.
These are currently still defined in Python files (materials.py
) within the technology folder.
TECH.MATERIALS
Here actual physical materials are defined. This is done using the class i3.Material
that are added to a i3.MaterialFactory
. Each material is associate with a DisplayStyle
and with a boolean that determines if it is a solid or not.
TECH.MATERIALS = MaterialFactory()
TECH.MATERIALS.AIR = Air(name="air", display_style=DisplayStyle(color=color.COLOR_BLUE_CRAYOLA, alpha=0.1), solid=False)
TECH.MATERIALS.SILICON = Silicon(name="Silicon", display_style=DisplayStyle(color=COLOR_UGLY_PINK))
TECH.MATERIALS.SILICON_NITRIDE = SiNitride(
name="Silicon Nitride", display_style=DisplayStyle(color=COLOR_DARK_BABY_BLUE)
)
TECH.MATERIALS.SILICON_OXIDE = SiOxide(
name="Silicon Oxide", display_style=DisplayStyle(color=COLOR_BABY_BLUE, alpha=0.2)
)
TECH.MATERIALS.P_SILICON = Material(name="P+ Silicon", display_style=DisplayStyle(color=COLOR_LIGHT_RED))
TECH.MATERIALS.N_SILICON = Material(name="N+ Silicon", display_style=DisplayStyle(color=COLOR_LIGHT_BLUE))
TECH.MATERIALS.PPLUS_SILICON = Material(name="P++-Silicon", display_style=DisplayStyle(color=COLOR_DARK_RED))
TECH.MATERIALS.NPLUS_SILICON = Material(name="N++-Silicon", display_style=DisplayStyle(color=COLOR_DARK_BLUE))
TECH.MATERIALS.GERMANIUM = Material(name="Germanium", display_style=DisplayStyle(color=color.COLOR_CHERRY))
TECH.MATERIALS.SILICIDE = Material(name="Silicide", display_style=DisplayStyle(color=color.COLOR_COPPER))
TECH.MATERIALS.TUNGSTEN = Material(name="Tungsten", display_style=DisplayStyle(color=COLOR_TUNGSTEN))
TECH.MATERIALS.TIN = Material(name="Titanium Nitride", display_style=DisplayStyle(color=COLOR_TIN))
TECH.MATERIALS.COPPER = Material(name="Copper", display_style=DisplayStyle(color=COLOR_COPPER_BROWN))
TECH.MATERIALS.ALUMINIUM = Material(name="Aluminium", display_style=DisplayStyle(color=COLOR_AL_GRAY))
TECH.MATERIALS.SILICON.epsilon = 3.47643493603882**2
TECH.MATERIALS.SILICON_NITRIDE.epsilon = 2.025742**2
TECH.MATERIALS.SILICON_OXIDE.epsilon = 1.444023622**2
TECH.MATERIALS.AIR.epsilon = 1.0
####################################################################
# MATERIALS STACKS
####################################################################
TECH.MATERIAL_STACKS
Here actual stack of materials are defined. Material stacks are build by a sequence of a material with a height. These stacks are then used for virtual fabrication. In analogy with Materials, you create i3.MaterialStack
that are added to a i3.MaterialStackFactory
. Each MaterialStack is associate with a DisplayStyle
.
Note
All the material stacks in a single factory must have the same height.
TECH.MATERIAL_STACKS = MaterialStackFactory()
# Thicknesses of the differents layers
MSTACK_SOI_SILICON_OXIDE_HEIGHT = 1.00
MSTACK_SOI_SILICON_HEIGHT = 0.22
MSTACK_SOI_SIN_HEIGHT = 0.300
MSTACK_SOI_SIN_RIB_HEIGHT = 0.150
MSTACK_SOI_RIB_HEIGHT = 0.100
# always have 0.5 contact thickness in total
MSTACK_GAP_HEIGHT = 0.15
MSTACK_CON1_HEIGHT = 1.0
MSTACK_MHT_HEIGHT = 0.15
MSTACK_M1_HEIGHT = 0.5
MSTACK_IMD12_HEIGHT = 1.0
MSTACK_M2_HEIGHT = 0.5
MSTACK_CON_HEIGHT = MSTACK_CON1_HEIGHT + MSTACK_GAP_HEIGHT + MSTACK_SOI_SIN_HEIGHT
# Material stacks in the Silicon layer
TECH.MATERIAL_STACKS.MSTACK_SOI_INVALID = MaterialStack(
name="INVALID",
materials_heights=[
(TECH.MATERIALS.AIR, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.AIR, MSTACK_SOI_SILICON_HEIGHT),
(TECH.MATERIALS.AIR, MSTACK_CON_HEIGHT),
],
display_style=DisplayStyle(color=color.COLOR_WHITE),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_OX = MaterialStack(
name="Oxide",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_BABY_BLUE),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_SI = MaterialStack(
name=f"{int(MSTACK_SOI_SILICON_HEIGHT * 1000)}nm Si",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.SILICON, MSTACK_SOI_SILICON_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_DARK_UGLY_PINK),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_SIN = MaterialStack(
name=f"{int(MSTACK_SOI_SIN_HEIGHT * 1000)}nm SiN",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT + MSTACK_SOI_SILICON_HEIGHT + MSTACK_GAP_HEIGHT),
(TECH.MATERIALS.SILICON_NITRIDE, MSTACK_SOI_SIN_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON1_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_DARK_BABY_BLUE),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_SI_SIN = MaterialStack(
name=f" {int(MSTACK_SOI_SILICON_HEIGHT * 1000)} nm Si + {int(MSTACK_SOI_SIN_HEIGHT * 1000)}nm SiN",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.SILICON, MSTACK_SOI_SILICON_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_GAP_HEIGHT),
(TECH.MATERIALS.SILICON_NITRIDE, MSTACK_SOI_SIN_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON1_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_DARK_BABY_BLUE),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_RIB = MaterialStack(
name=f"{int(MSTACK_SOI_RIB_HEIGHT * 1000)}nm Si",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.SILICON, MSTACK_SOI_RIB_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_HEIGHT - MSTACK_SOI_RIB_HEIGHT + MSTACK_CON_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_LIGHT_UGLY_PINK),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_SIN_RIB = MaterialStack(
name=f"{int(MSTACK_SOI_SIN_RIB_HEIGHT * 1000)}nm SiN",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT + MSTACK_SOI_SILICON_HEIGHT + MSTACK_GAP_HEIGHT),
(TECH.MATERIALS.SILICON_NITRIDE, MSTACK_SOI_SIN_RIB_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SIN_HEIGHT - MSTACK_SOI_SIN_RIB_HEIGHT + MSTACK_CON1_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_LIGHT_UGLY_PINK),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_RIB_SIN = MaterialStack(
name=f"{int(MSTACK_SOI_RIB_HEIGHT * 1000)}nm Si + {int(MSTACK_SOI_SIN_HEIGHT * 1000)}nm SiN",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.SILICON, MSTACK_SOI_RIB_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_HEIGHT - MSTACK_SOI_RIB_HEIGHT + MSTACK_GAP_HEIGHT),
(TECH.MATERIALS.SILICON_NITRIDE, MSTACK_SOI_SIN_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON1_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_LIGHT_UGLY_PINK),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_N = MaterialStack(
name=f"{int(MSTACK_SOI_SILICON_HEIGHT * 1000)}nm N+ implant",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.N_SILICON, MSTACK_SOI_SILICON_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON_HEIGHT),
],
display_style=DisplayStyle(color=color.COLOR_BLUE),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_N_SIN = MaterialStack(
name=f"{int(MSTACK_SOI_SILICON_HEIGHT * 1000)}nm N+ implant + {int(MSTACK_SOI_SIN_HEIGHT * 1000)}nm SiN",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.N_SILICON, MSTACK_SOI_SILICON_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_GAP_HEIGHT),
(TECH.MATERIALS.SILICON_NITRIDE, MSTACK_SOI_SIN_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON1_HEIGHT),
],
display_style=DisplayStyle(color=color.COLOR_BLUE),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_RIB_N = MaterialStack(
name=f"{int(MSTACK_SOI_RIB_HEIGHT * 1000)}nm N+ implant",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.N_SILICON, MSTACK_SOI_RIB_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_HEIGHT + MSTACK_CON_HEIGHT - MSTACK_SOI_RIB_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_LIGHT_BLUE),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_RIB_N_SIN = MaterialStack(
name=f"{int(MSTACK_SOI_RIB_HEIGHT * 1000)}nm N+ implant + {int(MSTACK_SOI_SIN_HEIGHT * 1000)}nm SiN",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.N_SILICON, MSTACK_SOI_RIB_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_HEIGHT - MSTACK_SOI_RIB_HEIGHT + MSTACK_GAP_HEIGHT),
(TECH.MATERIALS.SILICON_NITRIDE, MSTACK_SOI_SIN_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON1_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_LIGHT_BLUE),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_NPLUS = MaterialStack(
name=f"{int(MSTACK_SOI_RIB_HEIGHT * 1000)}nm N++ implant",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.NPLUS_SILICON, MSTACK_SOI_RIB_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_HEIGHT - MSTACK_SOI_RIB_HEIGHT + MSTACK_CON_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_DARK_BLUE),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_NPLUS_SIN = MaterialStack(
name=f"{int(MSTACK_SOI_RIB_HEIGHT * 1000)}nm N++ implant + {int(MSTACK_SOI_SIN_HEIGHT * 1000)}nm SiN",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.NPLUS_SILICON, MSTACK_SOI_RIB_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_HEIGHT - MSTACK_SOI_RIB_HEIGHT + MSTACK_GAP_HEIGHT),
(TECH.MATERIALS.SILICON_NITRIDE, MSTACK_SOI_SIN_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON1_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_DARK_BLUE),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_NPLUS_CON = MaterialStack(
name=f"{int(MSTACK_SOI_RIB_HEIGHT * 1000)}nm N++ implant + Contact",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.NPLUS_SILICON, MSTACK_SOI_RIB_HEIGHT),
(TECH.MATERIALS.TUNGSTEN, MSTACK_SOI_SILICON_HEIGHT - MSTACK_SOI_RIB_HEIGHT + MSTACK_CON_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_TUNGSTEN),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_P = MaterialStack(
name=f"{int(MSTACK_SOI_SILICON_HEIGHT * 1000)}nm P+ implant",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.P_SILICON, MSTACK_SOI_SILICON_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON_HEIGHT),
],
display_style=DisplayStyle(color=color.COLOR_RED),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_P_SIN = MaterialStack(
name=f"{int(MSTACK_SOI_SILICON_HEIGHT * 1000)}nm P+ implant + {int(MSTACK_SOI_SIN_HEIGHT * 1000)}nm SiN",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.P_SILICON, MSTACK_SOI_SILICON_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_GAP_HEIGHT),
(TECH.MATERIALS.SILICON_NITRIDE, MSTACK_SOI_SIN_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON1_HEIGHT),
],
display_style=DisplayStyle(color=color.COLOR_RED),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_RIB_P = MaterialStack(
name=f"{int(MSTACK_SOI_RIB_HEIGHT * 1000)}nm P+ implant",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.P_SILICON, MSTACK_SOI_RIB_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_HEIGHT - MSTACK_SOI_RIB_HEIGHT + MSTACK_CON_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_LIGHT_RED),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_RIB_P_SIN = MaterialStack(
name=f"{int(MSTACK_SOI_RIB_HEIGHT * 1000)}nm P+ implant + {int(MSTACK_SOI_SIN_HEIGHT * 1000)}nm SiN",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.P_SILICON, MSTACK_SOI_RIB_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_HEIGHT - MSTACK_SOI_RIB_HEIGHT + MSTACK_GAP_HEIGHT),
(TECH.MATERIALS.SILICON_NITRIDE, MSTACK_SOI_SIN_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON1_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_LIGHT_RED),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_PPLUS = MaterialStack(
name=f"{int(MSTACK_SOI_RIB_HEIGHT * 1000)}nm P++ implant",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.PPLUS_SILICON, MSTACK_SOI_RIB_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_HEIGHT - MSTACK_SOI_RIB_HEIGHT + MSTACK_CON_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_DARK_RED),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_PPLUS_SIN = MaterialStack(
name=f"{int(MSTACK_SOI_RIB_HEIGHT * 1000)}nm P++ implant + {int(MSTACK_SOI_SIN_HEIGHT * 1000)}nm SiN",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.PPLUS_SILICON, MSTACK_SOI_RIB_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_HEIGHT - MSTACK_SOI_RIB_HEIGHT + MSTACK_GAP_HEIGHT),
(TECH.MATERIALS.SILICON_NITRIDE, MSTACK_SOI_SIN_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_CON1_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_DARK_RED),
)
TECH.MATERIAL_STACKS.MSTACK_SOI_PPLUS_CON = MaterialStack(
name=f"{int(MSTACK_SOI_RIB_HEIGHT * 1000)}nm P++ implant + Contact",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_SOI_SILICON_OXIDE_HEIGHT),
(TECH.MATERIALS.PPLUS_SILICON, MSTACK_SOI_RIB_HEIGHT),
(TECH.MATERIALS.TUNGSTEN, MSTACK_SOI_SILICON_HEIGHT - MSTACK_SOI_RIB_HEIGHT + MSTACK_CON_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_TUNGSTEN),
)
# Material stacks in the metal1 and heater layers
TECH.MATERIAL_STACKS.MSTACK_METAL_DIEL = MaterialStack(
name="BEOL Oxide",
materials_heights=[(TECH.MATERIALS.SILICON_OXIDE, MSTACK_M1_HEIGHT + MSTACK_MHT_HEIGHT)],
display_style=DisplayStyle(color=COLOR_BABY_BLUE),
)
TECH.MATERIAL_STACKS.MSTACK_METAL_M1 = MaterialStack(
name="M1",
materials_heights=[(TECH.MATERIALS.SILICON_OXIDE, MSTACK_MHT_HEIGHT), (TECH.MATERIALS.ALUMINIUM, MSTACK_M1_HEIGHT)],
display_style=DisplayStyle(color=COLOR_AL_GRAY),
)
TECH.MATERIAL_STACKS.MSTACK_METAL_MHT = MaterialStack(
name="MHT",
materials_heights=[(TECH.MATERIALS.TIN, MSTACK_MHT_HEIGHT), (TECH.MATERIALS.SILICON_OXIDE, MSTACK_M1_HEIGHT)],
display_style=DisplayStyle(color=COLOR_TIN),
)
TECH.MATERIAL_STACKS.MSTACK_METAL_M1_MHT = MaterialStack(
name="M1_MHT",
materials_heights=[(TECH.MATERIALS.TIN, MSTACK_MHT_HEIGHT), (TECH.MATERIALS.ALUMINIUM, MSTACK_M1_HEIGHT)],
display_style=DisplayStyle(color=COLOR_AL_GRAY),
)
TECH.MATERIAL_STACKS.MSTACK_METAL_M1_CON = MaterialStack(
name="M1_CON",
materials_heights=[(TECH.MATERIALS.TUNGSTEN, MSTACK_MHT_HEIGHT), (TECH.MATERIALS.ALUMINIUM, MSTACK_M1_HEIGHT)],
display_style=DisplayStyle(color=COLOR_TUNGSTEN),
)
# Material stacks in the metal layer (only M2)
TECH.MATERIAL_STACKS.MSTACK_METAL2_DIEL = MaterialStack(
name="Oxide",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_IMD12_HEIGHT),
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_M2_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_BABY_BLUE),
)
TECH.MATERIAL_STACKS.MSTACK_METAL2_M = MaterialStack(
name="M2",
materials_heights=[
(TECH.MATERIALS.SILICON_OXIDE, MSTACK_IMD12_HEIGHT),
(TECH.MATERIALS.ALUMINIUM, MSTACK_M2_HEIGHT),
],
display_style=DisplayStyle(color=COLOR_AL_GRAY),
)
TECH.MATERIAL_STACKS.MSTACK_METAL_M2_CON = MaterialStack(
name="M2 + Contact",
materials_heights=[(TECH.MATERIALS.TUNGSTEN, MSTACK_IMD12_HEIGHT), (TECH.MATERIALS.ALUMINIUM, MSTACK_M2_HEIGHT)],
display_style=DisplayStyle(color=COLOR_TUNGSTEN),
)
Virtual Fabrication
Virtual fabrication generates a 3D representation of a component starting from a Layout.
These are currently still defined in Python files (vfab.py
) within the technology folder.
This is done by transforming a Layout constituted of elements (ProcessPurposeLayer
on a shape) to a series of non-overlapping shapes that are associated with a material stack.
In order to set this up, you will need to specify a virtual fabrication process flow:
i3.VFabricationProcessFlow
:
active_processes: Which (masked) process steps (
ProcessLayer
objects) are used within the virtual fabrication flow.process_layer_map: How the mask layer for each process layer is generated. A fabrication mask for a process step could be defined by just a single drawn layer in the layout, but could also be a generated layer: the result of a boolean operation between multiple drawn layers.
process_to_material_stack_map: How a combination of process layers relates to a specific material stack
is_lf_fabrication: Whether a mask layer is to be interpreted as light-field (LF) or dark-field (DF). Absent layers are interpreted as dark-field (DF).
Mask layers
All the drawn layers associated with a fabrication process step (ipkiss.process.layer.ProcessLayer
) need to be combined to a mask that tells if a process is either 1 or 0 at a specific point.
This is done through a set of boolean operations between the drawn layers.
Assume the following example: we have a process which has 2 process layers:
PROCESS1, for which the mask is directly defined by LAYER1, and
PROCESS2, for which the mask is generated by the boolean xor between LAYER2 and LAYER3.
These process_layer_map and is_lf_fabrication settings are defined in Python.

Layout of the structure to be virtually fabricated
We can write the process_layer_map as follows:
process_layer_map = {
TECH.PROCESS.PROCESS1: TECH.PPLAYER.LAYER1,
TECH.PROCESS.PROCESS2: TECH.PPLAYER.LAYER2 ^ TECH.PPLAYER.LAYER3
}
For the virtual fabrication, it does not matter whether the layers are i3.Layer
or PPLayer
objects.
These specified boolean operations defined will be used to create a final mask layer for each process:

Final mask layers generated for each process layer
From mask layers to material stacks
The final mask layers are mapped to material stacks with a combination of two specifications:
process_to_material_stack_map: related combinations of final mask layers to a material stack (
i3.MaterialStack
), where for every point in the layout there is a one (1) or a zero (0) for each final mask layer.is_lf_fabrication: specifies whether drawn areas on the final mask layer are 1 or 0.
If the corresponding entry is False, then a drawn shape on the final mask will be associated with a 1 in the process_to_material_stack_map table.
If the corresponding entry is True, then a drawn shape on the final mask will be associated with a 0 in the process_to_material_stack_map table.
TECH.VFABRICATION = TechnologyTree()
TECH.VFABRICATION.PROCESS_FLOW = VFabricationProcessFlow(
active_processes=[
TECH.PROCESS.PROCESS1,
TECH.PROCESS.PROCESS2
],
process_layer_map={
TECH.PROCESS.PROCESS1: TECH.PPLAYER.LAYER1,
TECH.PROCESS.PROCESS2: TECH.PPLAYER.LAYER2 ^ TECH.PPLAYER.LAYER3
},
process_to_material_stack_map=[
((0, 0), TECH.MATERIAL_STACKS.STACK_0),
((0, 1), TECH.MATERIAL_STACKS.STACK_1),
((1, 0), TECH.MATERIAL_STACKS.STACK_2),
((1, 1), TECH.MATERIAL_STACKS.STACK_3),
],
is_lf_fabrication={
TECH.PROCESS.PROCESS1: False,
TECH.PROCESS.PROCESS2: False
}
)
Note
The first entry in the process_material_stack_map is used as the default (background) material stack.
As illustrated below the masks are then combined to create virtually fabricated structure.

Mechanism used for the virtual fabrication.
Our samples contain an executable example on how to define a virtual fabrication and how visualize it or use it for cross sections.
It’s a good start to experiment with it to get a better understanding about its inner behavior.
You can find it at samples/technology/virtual_fabrication_example.py or download it here
# This is an advanced example on how to build Virtual Fabrication Process Flows.
# It's meant for PDK and library builders who want to include this process information
# in their technology. This way users of the PDK can with little effort export their
# components to 3rd party solvers.
import ipkiss3.all as i3
from ipkiss.visualisation.display_style import DisplayStyle
from ipkiss.visualisation import color
dummy_mat = i3.Material(name="dummy0_mat", epsilon=1, display_style=DisplayStyle(color=color.COLOR_SANGRIA))
# We'll have 4 material stacks
dummy_mstack0 = i3.MaterialStack(
name="dummy0", materials_heights=[(dummy_mat, 1.0)], display_style=DisplayStyle(color=color.COLOR_CHERRY)
)
dummy_mstack1 = i3.MaterialStack(
name="dummy1", materials_heights=[(dummy_mat, 2.0)], display_style=DisplayStyle(color=color.COLOR_DARK_GREEN)
)
dummy_mstack2 = i3.MaterialStack(
name="dummy2", materials_heights=[(dummy_mat, 3.0)], display_style=DisplayStyle(color=color.COLOR_GRAY)
)
dummy_mstack3 = i3.MaterialStack(
name="dummy3", materials_heights=[(dummy_mat, 0.5)], display_style=DisplayStyle(color=color.COLOR_MAGENTA)
)
# We'll use 3 Layers in our test structure
LAY0 = i3.Layer(0)
LAY1 = i3.Layer(1)
LAY2 = i3.Layer(2)
# and our technology uses 3 processes
PROCESS1 = i3.ProcessLayer(extension="ext1", name="dummyproc1")
PROCESS2 = i3.ProcessLayer(extension="ext2", name="dummyproc2")
PROCESS3 = i3.ProcessLayer(extension="ext3", name="dummyproc3")
vfab_flow = i3.VFabricationProcessFlow(
active_processes=[PROCESS1, PROCESS2, PROCESS3],
process_layer_map={
# any of LAY0, LAY1 or LAY2 :
PROCESS1: LAY0 | LAY1 | LAY2,
# everwhere LAY1 or LAY2 :
PROCESS2: (LAY1 & LAY2) | (LAY1 & LAY0) | (LAY2 & LAY0),
# only when all layers are present:
PROCESS3: LAY0 & LAY1 & LAY2,
},
process_to_material_stack_map=[
((0, 0, 0), dummy_mstack2),
((1, 0, 0), dummy_mstack0), # mstack 0 where only 1 layer is present
((1, 1, 0), dummy_mstack1), # mstack 1 where any combination of 2 layers is present
((1, 1, 1), dummy_mstack3), # mstack 3 where all layers are present
],
)
# We make a Venn - Diagram like teststructure
lay = i3.LayoutCell().Layout(
elements=[
i3.Circle(layer=LAY0, center=(-3, 0), radius=5.0),
i3.Circle(layer=LAY1, center=(3, 0), radius=5.0),
i3.Circle(layer=LAY2, center=(0, 5), radius=5.0),
]
)
# We visualize the layers
lay.visualize()
# visualize_2d displays a top down view of the fabricated layout
lay.visualize_2d(vfabrication_process_flow=vfab_flow)
# we can also calculate and visualize the cross_section
lay.cross_section(i3.Shape([(-9, 3), (9, 3)]), process_flow=vfab_flow).visualize()



Traces
Contains the default settings for drawing traces such as waveguides and electrical traces. Three different trees need to be built.
Default waveguide templates for optical and electrical routing are defined as well.
These are currently still defined in Python files (routing.py
) within the technology folder.
# Generic trace defaults
TECH.TRACE.DEFAULT_LAYER = TECH.PPLAYER.SI
TECH.TRACE.CONTROL_SHAPE_LAYER = TECH.PPLAYER.WIRE_TRACE
TECH.DEFAULT_WAVELENGTH = 1.55
# Generic port defaults
TECH.PORT.DEFAULT_LAYER = TECH.PPLAYER.PINREC # Default layer for drawing pins
# Waveguide defaults
TECH.WG_DEFAULTS.N_EFF = 2.4
TECH.WG_DEFAULTS.N_GROUP = 4.4
TECH.WG_DEFAULTS.LOSS_DB_PERM = 0.0
TECH.WG_DEFAULTS.CORE_LAYER = Layer(0)
# Default waveguide routing template
TECH.PCELLS.WG = TechnologyTree()
TECH.PCELLS.WG.WIRE = SiWireWaveguideTemplate()
TECH.PCELLS.WG.RIB = SiRibWaveguideTemplate()
TECH.PCELLS.WG.DEFAULT = TECH.PCELLS.WG.WIRE
# Default metal routing template
TECH.PCELLS.METAL.DEFAULT = M1WireTemplate()
OpenAccess (Link for Siemens EDA only)
IPKISS can export a database to OpenAccess. This database can then be used inside other EDA tools supporting OpenAccess.
Layer settings
Layer settings for the OpenAccess database are in the TECH.OPENACCESS settings tree. OpenAccess uses similar concepts as IPKISS, hence a one-to-one map between the two is easily made.
IPKISS Concept |
OpenAccess concept |
---|---|
ProcessLayer |
oaPhysicalLayer |
PatternPurpose |
oaPurpose |
PPLayer |
LayerPurposePair (LPP) extension - not in standard OA |
When using Link for Siemens EDA, the following TECH keys need to be set up:
TECH.OPENACCESS.EXPORT_LAYER_MAP: map of ProcessLayer to an oaPhysicalLayer number which will be used to identify the Layer
TECH.OPENACCESS.EXPORT_PURPOSE_MAP: map of PatternPurpose to an oaPurpose number which will be used to identify the Purpose. Note that OpenAccess has a number of reserved purposes.
TECH.OPENACCESS.FILTER: IPKISS Filter which will be applied to each object exported to OpenAccess. This allows to have the same data exported to OpenAccess (e.g. cut polygons) as to GDSII (or differently, if desired).
Hence, the mapping between IPKISS and OpenAccess is always done for Layers and for Purposes separately, unlike for GDSII where it is possible to map any (ProcessLayer, PatternPurpose) pair onto any (GDSII layer, GDSII datatype) pair. The PPLayer to LPP mapping is made implicitly and cannot be altered.
This mapping can be done in the YAML configuration file, by providing a number keyword when defining your layers and purposes. A default filter will also be created, which can be overridden in python if desired.
layers:
- {name: NONE, doc: No specific process, number: 100, ipkiss: {name: No specific process}}
- {name: SI, doc: Unetched silicon, number: 1, ipkiss: {name: Unetched silicon}}
- {name: SHALLOW, doc: Fiber Couplers and Rib Waveguide (shallow etched Si), number: 2, ipkiss: {name: Fiber Couplers and Rib Waveguide (shallow etched Si)}}
- {name: SIN, doc: Silicon nitride, number: 6, ipkiss: {name: Silicon nitride}}
- {name: SIN_SHALLOW, doc: 'Thin silicon nitride layer, used for edge couplers', number: 7, ipkiss: {name: 'Thin silicon nitride layer, used for edge couplers'}}
- {name: HT, doc: Heater, number: 1000, ipkiss: {name: Heater}}
- {name: M1, doc: Metallization 1, number: 3, ipkiss: {name: Metallization 1}}
- {name: M2, doc: Metallization 2, number: 4, ipkiss: {name: Metallization 2}}
- {name: V12, doc: Via between M1 and M2, number: 5, ipkiss: {name: Via between M1 and M2}}
- {name: N, doc: N+ implant, number: 11, ipkiss: {name: N+ implant}}
- {name: P, doc: P+ implant, number: 12, ipkiss: {name: P+ implant}}
- {name: GE, doc: Germanium, number: 16, ipkiss: {name: Germanium}}
- {name: NPLUS, doc: N++ implant, number: 13, ipkiss: {name: N++ implant}}
- {name: PPLUS, doc: P++ implant, number: 14, ipkiss: {name: P++ implant}}
- {name: CON, doc: Contact, number: 15, ipkiss: {name: Contact}}
- {name: BEZ_S, doc: BEZ_S, number: 300}
- {name: BEZ_B, doc: BEZ_B, number: 301}
- {name: BEZ_U, doc: BEZ_U, number: 302}
- {name: SB, doc: SB, number: 303}
purposes:
- {name: ERROR, number: 100, ipkiss: {name: Error, extension: ERR}}
- {name: DOC, number: 50, ipkiss: {name: Documentation}}
- {name: TRACE, number: 25, ipkiss: {name: Trace, extension: TRC}}
- {name: PINREC, number: 22, ipkiss: {name: Pin recognition, extension: PIN}}
- {name: DEVREC, number: 1000, ipkiss: {name: Device recognition}}
- {name: BBOX, number: 21, ipkiss: {name: Bounding Box}}
- {name: SIMBND, number: 1001, ipkiss: {name: Simulation boundary}}
- {name: IGNORE, number: 1002, ipkiss: {name: Ignored}}
- {name: DRWSUB, number: 26, ipkiss: {name: Subtracted drawing}}
- {name: TEXT, number: 24, ipkiss: {name: Text, extension: TXT}}
- {name: UNUSED, number: 101, ipkiss: {name: Unused}}
Note
OpenAccess has a number of reserved purpose numbers. In particular, the default one considered by Link for Siemens EDA is the drawing purpose, used for normal ‘drawn’ mask data. The PatternPurpose which maps to the drawing purpose should not be specified in TECH.OPENACCESS.EXPORT_PURPOSE_MAP.
Also note that, because of this, it is not generally possible to use identical numbers for IPKISS PatternPurpose / OpenAccess oaPurpose / GDSII datatype, unless the drawing purpose is not used.
Routing settings
A TECH.ROUTING.WAVEGUIDE_GENERATION_GUIDE_LAYERS
is defined which contains a mapping from routing layers to
waveguide generation functions. This is defined in Python files (oa_routing.py
) within the technology folder, for example:
# In technology/openaccess.py
TECH = get_technology()
TECH.ROUTING = TechnologyTree()
TECH.ROUTING.WAVEGUIDE_GENERATION_GUIDE_LAYERS = {
TECH.PPLAYER.WG.TRACE: generate_strip_wg,
TECH.PPLAYER.RIB.TRACE: generate_rib_wg,
}
Here, generate_strip_wg
and generate_rib_wg
are functions that generate the waveguide.
A waveguide function takes the start port, end port, and shape as input,
and outputs a (possibly modified) shape, and the waveguide itself.
Below is an example:
# in technology/openaccess.py
def generate_strip_wg(start_port, end_port, shape):
"""Generate a strip waveguide.
Parameters
----------
start_port: i3.Port or None
The starting port. If the user connects the starting point of the shape to a device,
then it contains that port.
If the starting point is not physically connected to a device in the layout, then start_port=None.
end_port: i3.Port or None
Same, for the ending point of the shape.
shape: i3.Shape
Shape the user has drawn, which defines the control points of the waveguide.
If only two points are given and start_port and end_port are given, it means the user expects
a valid drawn route between these two ports. This means the shape needs to be updated
(for example, a Manhattan route).
Returns
-------
shape: i3.Shape
The shape (possibly modified from the original)
waveguide: i3.PCell
The generated waveguide
"""
from ipkiss3.pcell.routing.manhattan import RouteManhattan
from ipkiss3.pcell.photonics.rounded_waveguide import RoundedWaveguide
if len(shape) == 2 and not start_port is None and not end_port is None:
# User wants to auto-route this waveguide between two ports
# RouteManhattan uses the technology defaults - update when needed
shape = RouteManhattan(start_port=start_port, end_port=end_port)
cell_params = {}
if start_port is not None:
cell_params['trace_template'] = start_port.trace_template
elif end_port is not None:
cell_params['trace_template'] = end_port.trace_template
wg = RoundedWaveguide(**cell_params)
layout = wg.Layout(shape=shape)
return shape, wg
The waveguide generation function calculates how a waveguide is generated along a given shape. If the start and end port are given, that means the user wants to connect between two ports. If the user has drawn a straight line between these two ports, it means the user expects the waveguide function to recalculate the shape.
How to use these waveguide routes from an EDA tool is explained in Step 3: Route and generate waveguides.
Required Technology Keys: IPKISS
IPKISS requires a number of technology keys to be defined in order for all the parts of ipkiss to work.
These are automatically created if you create a technology with luceda.technology.load_tech
, so you can focus on overriding
the settings that matter.
The list is given below so that you can find which settings can be overridden.
The documentation on the YAML format can be found at PDK Tech Configuration Schema Reference.
Name generation
The name generator is used to automatically calculate a name for each cell, if a name is not given during initialization. By default, it causes pcells to get the PCELL_ name prefix, and counting starts at 0. If _name_prefix is defined in your pcell, that will be used for the prefix, instead.
TECH.ADMIN.NAME_GENERATOR: Name generator for your PCells.
Discretization metrics
These values affect how the output of the layout is generated.
TECH.METRICS.ANGLE_STEP: Angle step (in degrees) used for discretization of bends, configured in tech.yaml under settings.metrics.angle_step.
TECH.METRICS.GRID: Discretization of the grid GDSII file (in meter), configured in tech.yaml under settings.metrics.grid.
TECH.METRICS.UNIT: Unit of the GDSII file (in meter), configured in tech.yaml under settings.metrics.unit.
Port properties
An optical port is exported with a box drawn on DEFAULT_LAYER. The box dimensions are (TECH.PORT.DEFAULT_LENGTH, self.width)
TECH.PORT.DEFAULT_LAYER: Default layer used for ports, configured in tech.yaml under ports.default_layer.
TECH.PORT.DEFAULT_LENGTH: Default length used for ports, configured in tech.yaml under ports.default_length.
Generic trace properties.
TECH.TRACE.BEND_RADIUS: Default bend radius, used during automatic routing, configured in tech.yaml under waveguides.trace_bend_radius.
TECH.TRACE.DRAW_CONTROL_SHAPE: Turn on/off the drawing of a control shape, configured in tech.yaml under waveguides.trace_draw_control_shape.
TECH.TRACE.CONTROL_SHAPE_LAYER: Layer used for the drawing of the control shape, configured in tech.yaml under waveguides.trace_control_shape_layer.
TECH.TRACE.DEFAULT_LAYER: Default layer used of the drawing of shapes, configured in tech.yaml under waveguides.trace_default_layer.
Default model parameters
TECH.DEFAULT_WAVELENGTH: Default wavelength used for waveguide models, configured in tech.yaml under waveguides.default_wavelength.
TECH.WG_DEFAULTS.N_EFF: Default n_eff for waveguide models, configured in tech.yaml under waveguides.wg_defaults_n_eff.
TECH.WG_DEFAULTS.N_GROUP: Default group index used for waveguide models, configured in tech.yaml under waveguides.wg_defaults_n_group.
TECH.WG_DEFAULTS.LOSS_DB_PERM: Default loss per m in dB used for waveguide models, configured in tech.yaml under waveguides.wg_defaults_loss_db_perm.
Default waveguide parameters.
TECH.WG_DEFAULTS.CORE_LAYER: Default core layer used in waveguides, configured in tech.yaml under waveguides.wg_defaults_core_layer.
TECH.WG.SPACING: Default waveguide spacing used in adaptors, configured in tech.yaml under waveguides.wg_spacing.
TECH.WG.WIRE_WIDTH: Default wire width (needed for backward compatibility), configured in tech.yaml under waveguides.wg_wire_width.
TECH.WG.EXPANDED_TAPER_LENGTH: Default length of an extended taper for extended waveguides, configured in tech.yaml under waveguides.wg_expanded_taper_length.
TECH.WG.EXPANDED_WIDTH: Default width of expanded waveguides, configured in tech.yaml under waveguides.wg_expanded_width.
TECH.WG.TRENCH_WIDTH: Default width of a trench of a waveguide, configured in tech.yaml under waveguides.wg_trench_width.
Used during routing.
TECH.WG.SHORT_STRAIGHT: Default minimum length required for any of the straight sections in a route, configured in tech.yaml under waveguides.wg_short_straight.
TECH.WG.EXPANDED_STRAIGHT: Default length of an expanded straight waveguide, configured in tech.yaml under waveguides.wg_expanded_straight.
TECH.PROCESS.WG: Default process for waveguides, configured in tech.yaml under picazzo.wg_process.
TECH.PROCESS.NONE: Default process for things that are not added to the GDSII.
TECH.PPLAYER.M1.LINE: Default layer for M1 guides, configured in tech.yaml under picazzo.metal1_layer.
TECH.PPLAYER.M2.LINE: Default layer for M2 guides, configured in tech.yaml under picazzo.metal2_layer.
TECH.PPLAYER.V12.PILLAR: Default layer for M12 vias, configured in tech.yaml under picazzo.via12_layer.
TECH.PPLAYER.WG.TEXT: Default layer for text on a design, configured in tech.yaml under picazzo.wg_text.
TECH.PPLAYER.ERROR.GENERIC: Default layer for drawing errors.
TECH.PCELLS.WG.DEFAULT: Default waveguide template for this technology.
TECH.PCELLS.LIB: Default PCELL library.
TECH.PCELLS.METAL.DEFAULT: Default Metal trace template.
TECH.METAL.DEFAULT_PROCESS: Default process used for metals.
TECH.METAL.LINE_WIDTH: Default width of metal traces.
TECH.VIAS.DEFAULT.TOP_SHAPE: Default top_shape of a via.
TECH.VIAS.DEFAULT.BOTTOM_SHAPE: Default bottom_shape of a via.
TECH.VIAS.DEFAULT.VIA_SHAPE: Default pillar shape of a via.
GDS export settings.
These affect how your designs are exported to GDS.
The default EXPORT_LAYER_MAP and IMPORT_LAYER_MAP automatically convert IPKISS layers to a gds
number/datatype and vice versa (through AutoGdsiiLayerOutputMap
/ AutoGdsiiLayerInputMap
).
This is in general not very useful as you want to have control over how the layers are exported.
The best way to do this is to define a layer map manually, and use
GenericGdsiiPPLayerOutputMap
and
GenericGdsiiPPLayerInputMap
.
TECH.GDSII.MAX_NAME_LENGTH: Max name length of a cell in char, configured in tech.yaml under gds.export_options.max_name_length.
TECH.GDSII.EXPORT_LAYER_MAP: GDSII export layer map.
TECH.GDSII.IMPORT_LAYER_MAP: GDSII import layer map.
TECH.GDSII.NAME_FILTER: Filter applied on the names of the PCells before being exported to GDSII, configured in tech.yaml under gds.export_options.name_error_filter.
TECH.GDSII.MAX_VERTEX_COUNT: Max number of vertices in a polygon shape. Splitted otherwise, configured in tech.yaml under gds.export_options.max_vertex_count.
TECH.GDSII.MAX_PATH_LENGTH: Max path length of the GDSII file. Splitted otherwise, configured in tech.yaml under gds.export_options.max_path_length.
TECH.GDSII.STRNAME_CHARACTER_DICT: Dict for the mapping of illegal characters on legal. Applied to all cell names, configured in tech.yaml under gds.export_options.strname_character_dict.
TECH.GDSII.STRNAME_ALLOWED_CHARACTERS: All allowed characters in a cell name, configured in tech.yaml under gds.export_options.strname_allowed_characters.
Filters are functions that are that are applied upon conversion from IPKISS to GDSII. There is a wide range of filters and you can define your own. This is advanced functionality - please contact us if you think you would need them we would be happy to assist.
TECH.GDSII.FILTER: List of filters applied to your PCells before export to GDSII.
Blocks
Blocks are the basic elements added to IoColumn
. Below are default values for the spacing and width of the blocks.
TECH.BLOCKS.DEFAULT_YSPACING: Default spacing between blocks, configured in tech.yaml under blocks.default_yspacing.
TECH.BLOCKS.DEFAULT_WIDTH: Default width of a block, configured in tech.yaml under blocks.default_width.
The default adapter (i.e., A PCell that ‘adapts’ or ‘wraps’ another PCell in an IoBlock to fit it into an IoColumn):
TECH.IO.ADAPTER.DEFAULT_ADAPTER.PCELLS.ADAPTER: Default adapter for I/O blocks.
Drawing purposes
TECH.PURPOSE.BBOX: Purpose for the bounding boxes.
TECH.PURPOSE.LF_AREA: Purpose for light field areas.
TECH.PURPOSE.LF.LINE: Purpose for light field lines.
TECH.PURPOSE.DF.LINE: Purpose for dark field areas.
TECH.PURPOSE.TEXT: Purpose for text.
Visualization
TECH.DISPLAY.DEFAULT_DISPLAY_STYLE_SET: Default display set for visualization in IPKISS.
Transitions
The AUTO_TRANSITION_DATABASE consists of a list of valid transitions (tapers). During automatic routing, if transitions have to be added between two given trace templates (e.g., rib and strib waveguide), the AUTO_TRANSITION_DATABASE is used to look up whether there is a valid transition between both.
TECH.PCELLS.TRANSITION.AUTO_TRANSITION_DATABASE: Default autotransition database.
Errors
TECH.PPLAYER.ERROR.CROSSING: error layer to indicate crossing waveguides
TECH.PPLAYER.ERROR.GENERIC: error layer to indicate other errors
Required Technology Keys: PICAZZO (OPTIONAL)
In order to make the PICAZZO pcell library work on your technology, a set of technology keys are required.
Containers
TECH.CONTAINER.TERMINATE_PORTS.CHILD_SUFFIX: Suffix that will be added to the children of
TerminatePorts
, configured in tech.yaml under picazzo.container_terminate_ports_child_suffix.TECH.CONTAINER.TERMINATE_PORTS.TERMINATION_INSTANCE_PREFIX: Suffix that will be added to the instances of the termination cells in
TerminatePorts
, configured in tech.yaml under picazzo.container_terminate_ports_termination_instance_prefix.
Fiber couplers and IoFibcoup adapters
These provide default values for the parameters of IoFibcoup
and
the picazzo fiber couplers.
TECH.IO.ADAPTER.IOFIBCOUP.CONNECT_TRANSITION_LENGTH: default length of the transition between the ‘fanout’ section and the straight connection traces to the fiber coupler in IoFibcoup, configured in tech.yaml under picazzo.io_adapter.iofibcoup_connect_transition_length.
TECH.IO.ADAPTER.IOFIBCOUP.FANOUT_LENGTH: default length of the ‘fanout’ section in IoFibcoup, configured in tech.yaml under picazzo.io_adapter.iofibcoup_fanout_length.
TECH.IO.ADAPTER.IOFIBCOUP.FIBER_COUPLER_TRANSITION_LENGTH: default transition length to the fiber coupler in IoFibcoup, configured in tech.yaml under picazzo.io_adapter.iofibcoup_fiber_coupler_transition_length.
TECH.IO.ADAPTER.IOFIBCOUP.S_BEND_ANGLE: maximum s-bend angle to use in IoFibcouop, configured in tech.yaml under picazzo.io_adapter.iofibcoup_s_bend_angle.
TECH.IO.FIBCOUP.CURVED.SOCKET.MARGIN_FROM_GRATING: margin behind the grating before the coupler socket ends, configured in tech.yaml under picazzo.io_fibcoup.curved_socket_margin_from_grating.
TECH.IO.FIBCOUP.CURVED.GRATING.ANGLE_SPAN: default angular span of curved grating, configured in tech.yaml under picazzo.io_fibcoup.curved_grating_angle_span.
TECH.IO.FIBCOUP.CURVED.GRATING.BOX_WIDTH: default box width of curved grating, configured in tech.yaml under picazzo.io_fibcoup.curved_grating_box_width.
TECH.IO.FIBCOUP.CURVED.GRATING.FOCAL_DISTANCE: default focal distance of curved grating, configured in tech.yaml under picazzo.io_fibcoup.curved_grating_focal_distance.
TECH.IO.FIBCOUP.CURVED.GRATING.N_O_LINES: default number of grating lines of curved grating, configured in tech.yaml under picazzo.io_fibcoup.curved_grating_n_o_lines.
TECH.IO.FIBCOUP.CURVED.GRATING.PERIOD: default period of curved grating, configured in tech.yaml under picazzo.io_fibcoup.curved_grating_period.
TECH.IO.FIBCOUP.CURVED.GRATING.START_RADIUS: default radius of the first grating line of curved grating, configured in tech.yaml under picazzo.io_fibcoup.curved_grating_start_radius.
TECH.IO.FIBCOUP.CURVED.PCELLS.DEFAULT_GRATING: default curved grating cell.
TECH.IO.FIBCOUP.CURVED.SOCKET.LENGTH: default socket length, configured in tech.yaml under picazzo.io_fibcoup.curved_socket_length.
TECH.IO.FIBCOUP.CURVED.SOCKET.START_TRACE_TEMPLATE: default start trace template of curved grating socket.
TECH.IO.FIBCOUP.CURVED.SOCKET.STRAIGHT_EXTENSION: default straight extension of curved grating behind the grating socket, configured in tech.yaml under picazzo.io_fibcoup.curved_socket_straight_extension.
TECH.IO.FIBCOUP.CURVED.SOCKET.WIDE_TRACE_TEMPLATE: default end trace template of curved grating socket.
TECH.IO.FIBCOUP.DEFAULT.PCELLS.DEFAULT_GRATING: default grating coupler.
TECH.IO.FIBCOUP.DEFAULT.SOCKET.LENGTH: Default property value for curved grating couplers, configured in tech.yaml under picazzo.io_fibcoup.default_socket_length.
TECH.IO.FIBCOUP.STRAIGHT.GRATING.BOX_WIDTH: default box width of straight grating, configured in tech.yaml under picazzo.io_fibcoup.straight_grating_box_width.
TECH.IO.FIBCOUP.STRAIGHT.GRATING.LINE_WIDTH: default linewidth of straight grating, configured in tech.yaml under picazzo.io_fibcoup.straight_grating_line_width.
TECH.IO.FIBCOUP.STRAIGHT.GRATING.N_O_LINES: default number of periods of straight grating, configured in tech.yaml under picazzo.io_fibcoup.straight_grating_n_o_lines.
TECH.IO.FIBCOUP.STRAIGHT.GRATING.PERIOD: default period of straight grating, configured in tech.yaml under picazzo.io_fibcoup.straight_grating_period.
TECH.IO.FIBCOUP.STRAIGHT.PCELLS.DEFAULT_GRATING_TM: default TM grating.
TECH.IO.FIBCOUP.STRAIGHT.SOCKET.LENGTH: default socket length of straight grating, configured in tech.yaml under picazzo.io_fibcoup.straight_socket_length.
TECH.IO.FIBCOUP.STRAIGHT.SOCKET.TRACE_TEMPLATE: default trace template of straight grating.
Modulators
These provide default values for the parameters of LateralPNPhaseShifterTemplate
and py:class:LongitudinalPNPhaseShifterTemplate<picazzo3.modulators.phase.trace.LongitudinalPNPhaseShifterTemplate>
TECH.MODULATORS.PHASESHIFTER.LATPN.BRIDGE_PITCH: configured in tech.yaml under picazzo.modulators.phaseshifter_latpn_bridge_pitch.
TECH.MODULATORS.PHASESHIFTER.LATPN.BRIDGE_WIDTH: configured in tech.yaml under picazzo.modulators.phaseshifter_latpn_bridge_width.
TECH.MODULATORS.PHASESHIFTER.LATPN.JUNCTION_OFFSET: configured in tech.yaml under picazzo.modulators.phaseshifter_latpn_junction_offset.
TECH.MODULATORS.PHASESHIFTER.LONGPN.N_LENGTH: configured in tech.yaml under picazzo.modulators.phaseshifter_longpn_n_length.
TECH.MODULATORS.PHASESHIFTER.LONGPN.N_WIDTH: configured in tech.yaml under picazzo.modulators.phaseshifter_longpn_n_width.
TECH.MODULATORS.PHASESHIFTER.LONGPN.P_LENGTH: configured in tech.yaml under picazzo.modulators.phaseshifter_longpn_p_length.
TECH.MODULATORS.PHASESHIFTER.LONGPN.P_WIDTH: configured in tech.yaml under picazzo.modulators.phaseshifter_longpn_p_width.
TECH.MODULATORS.PHASESHIFTER.PN.JUNCTION_OVERLAP: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_junction_overlap.
TECH.MODULATORS.PHASESHIFTER.PN.NPLUS_EXTENSION: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_nplus_extension.
TECH.MODULATORS.PHASESHIFTER.PN.NPLUS_OFFSET: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_nplus_offset.
TECH.MODULATORS.PHASESHIFTER.PN.NPLUS_WIDTH: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_nplus_width.
TECH.MODULATORS.PHASESHIFTER.PN.N_CONT_OFFSETS: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_n_cont_offsets.
TECH.MODULATORS.PHASESHIFTER.PN.N_CONT_PITCH: configured in tech.yaml under picazzo.modulators.phaseshiftern_pn_n_cont_pitch.
TECH.MODULATORS.PHASESHIFTER.PN.N_METAL1_OFFSET: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_n_metal1_offset.
TECH.MODULATORS.PHASESHIFTER.PN.N_METAL1_WIDTH: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_n_metal1_width.
TECH.MODULATORS.PHASESHIFTER.PN.N_SIL_EXTENSION: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_n_sil_extension.
TECH.MODULATORS.PHASESHIFTER.PN.N_SIL_OFFSET: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_n_sil_offset.
TECH.MODULATORS.PHASESHIFTER.PN.N_SIL_WIDTH: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_n_sil_width.
TECH.MODULATORS.PHASESHIFTER.PN.N_WIDTH: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_n_width.
TECH.MODULATORS.PHASESHIFTER.PN.PPLUS_EXTENSION: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_pplus_extension.
TECH.MODULATORS.PHASESHIFTER.PN.PPLUS_OFFSET: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_pplus_offset.
TECH.MODULATORS.PHASESHIFTER.PN.PPLUS_WIDTH: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_pplus_width.
TECH.MODULATORS.PHASESHIFTER.PN.P_CONT_OFFSETS: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_p_cont_offsets.
TECH.MODULATORS.PHASESHIFTER.PN.P_CONT_PITCH: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_p_cont_pitch.
TECH.MODULATORS.PHASESHIFTER.PN.P_METAL1_OFFSET: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_p_metal1_offset.
TECH.MODULATORS.PHASESHIFTER.PN.P_METAL1_WIDTH: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_p_metal1_width.
TECH.MODULATORS.PHASESHIFTER.PN.P_SIL_EXTENSION: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_p_sil_extension.
TECH.MODULATORS.PHASESHIFTER.PN.P_SIL_OFFSET: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_p_sil_offset.
TECH.MODULATORS.PHASESHIFTER.PN.P_SIL_WIDTH: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_p_sil_width.
TECH.MODULATORS.PHASESHIFTER.PN.P_WIDTH: configured in tech.yaml under picazzo.modulators.phaseshifter_pn_p_width.
waveguides
TECH.PCELLS.WG.RIB: Default ‘rib’ waveguide template
TECH.PCELLS.WG.RIBWIRE: Default ‘ribwire’ waveguide template
TECH.PCELLS.WG.WIRE: Default ‘wire’ waveguide template
PPLayers, ProcessLayers and PatternPurposes
TECH.PPLAYER.FC.TRENCH: Default fiber coupler trench layer
TECH.PPLAYER.N.LINE: Default N implant layer
TECH.PPLAYER.P.LINE: Default P implant layer
TECH.PPLAYER.NONE.DOC: Default documentation layer
TECH.PPLAYER.WG.CLADDING: Default waveguide cladding layer
TECH.PPLAYER.WG.CORE: Default waveguide core layer
TECH.PPLAYER.WG.TRENCH: Default waveguide trench layer
TECH.PROCESS.CON: Default contact hole process
TECH.PROCESS.FC: Default fiber coupler grating process, configured in tech.yaml under picazzo.fc_process.
TECH.PROCESS.HFW: Default HF etch window process (oxide removal)
TECH.PROCESS.M1: Default metal1 process
TECH.PROCESS.M2: Default metal2 process
TECH.PROCESS.N: Default N implant process
TECH.PROCESS.P: Default P implant process
TECH.PROCESS.NPLUS: Default N++ implant process
TECH.PROCESS.PPLUS: Default P++ implant process
TECH.PROCESS.RWG: Default rib waveguide process, configured in tech.yaml under picazzo.rwg_process.
TECH.PROCESS.SIL: Default silicide process, configured in tech.yaml under picazzo.sil_process.
TECH.PROCESS.SK: Default socket waveguide process
TECH.PROCESS.V12: Default via12 process
TECH.PURPOSE.DF.POLYGON: Default dark-field polygon drawing purpose
TECH.PURPOSE.DF_AREA: Default dark-field area drawing purpose
TECH.PURPOSE.DRAWING: Default drawing purpose
Rules
TECH.RWG.CLADDING_WIDTH: Default rib waveguide cladding width
TECH.RWG.RIB_WIDTH: Default rib waveguide rib width (shallow part)
TECH.RWG.STRIP_WIDTH: Default rib waveguide strip core width
TECH.SK.CLADDING_WIDTH: Default socket waveguide cladding width
TECH.TECH.MINIMUM_LINE: Overall minimum linewidth
TECH.TECH.MINIMUM_SPACE: Overall minimum spacing
TECH.VIAS.CONTACT_HOLE.M1_WIDTH: Default metal1 width on contact hole
TECH.VIAS.CONTACT_HOLE.PCELLS.DEFAULT_VIA: Default contact hole cell
TECH.VIAS.CONTACT_HOLE.SIL_WIDTH: Default silicide width on contact hole
TECH.VIAS.CONTACT_HOLE.VIA_WIDTH: Default via width on contact hole
TECH.VIAS.V12.M1_WIDTH: Default metal1 width on via12
TECH.VIAS.V12.M2_WIDTH: Default metal2 width on via12
TECH.VIAS.V12.N_O_SIDES: Default number of sides on via12 polygon
TECH.VIAS.V12.PCELLS.DEFAULT_VIA: Default default via12 cell
TECH.VIAS.V12.VIA_WIDTH: Default width of via12
TECH.WG.BEND_RADIUS: Default waveguide bend radius, configured in tech.yaml under waveguides.wg_bend_radius.
TECH.WG.CLADDING_WIDTH: Default strip waveguide cladding width, configured in tech.yaml under waveguides.wg_cladding_width.
TECH.WG.DC_SPACING: Default strip waveguide directional coupler spacing, configured in tech.yaml under waveguides.wg_dc_spacing.
TECH.WG.SHORT_TRANSITION_LENGTH: Default length of transitions, configured in tech.yaml under waveguides.wg_short_transition_length.
TECH.WG.SLOT_WIDTH: Default slot width for slot waveguides, configured in tech.yaml under waveguides.wg_slot_width.
Advanced cases
Resolving circular dependencies
Technology keys can be any python object. In some cases, you will want to store Ipkiss objects in the TECH tree which in their turn depend on TECH values, creating a circular dependency.
These circular dependencies can be managed by using a DelayedInitTechnologyTree
.
from ipkiss.technology import get_technology
from ipkiss.technology.technology import DelayedInitTechnologyTree
TECH = get_technology()
class MySettingsTree(DelayedInitTechnologyTree):
def initialize(self):
from mymodule import MyClass
self.MYOBJ = MyClass()
# now the technology tree can be fully imported at the start
# of the main script, even if mymodule uses TECH settings
TECH.MYSETTINGS = MySettingsTree()
The initialize
routine will only be called when TECH.MYSETTINGS.MYOBJ will be called.
Note this is not necessary for mainstream design kit implementation.