Import PDK#
Import PDK from GDS files#
To import a PDK from GDS files into gdsfactory you need:
GDS file with all the cells that you want to import in the PDK (or separate GDS files, where each file contains a GDS design).
Ideally you also get:
Klayout layer properties files, to define the Layers that you can use when creating new custom Components. This allows you to define the LayerMap that maps Layer_name to (GDS_LAYER, GDS_PuRPOSE).
layer_stack information (material index, thickness, z positions of each layer).
DRC rules. If you don’t get this you can easily build one using klayout.
GDS files are great for describing geometry thanks to the concept of References, where you store any geometry only once in memory.
For storing device metadata (settings, port locations, port widths, port angles …) there is no clear standard.
gdsfactory
stores the that metadata in YAML
files, and also has functions to add pins
Component.write_gds()
saves GDSComponent.write_gds_metadata()
save GDS + YAML metadata
import gdsfactory as gf
from gdsfactory.config import PATH
from gdsfactory.generic_tech import get_generic_pdk
from gdsfactory.technology import lyp_to_dataclass
gf.config.rich_output()
c = gf.components.mzi()
c.plot()
You can write GDS files only
gdspath = c.write_gds("extra/mzi.gds")
2024-10-31 18:39:59.949 | INFO | gdsfactory.component:_write_library:2004 - Wrote to 'extra/mzi.gds'
Or GDS with YAML metadata information (ports, settings, cells …)
gdspath = c.write_gds("extra/mzi.gds", with_metadata=True)
2024-10-31 18:39:59.961 | INFO | gdsfactory.component:_write_library:2004 - Wrote to 'extra/mzi.gds'
2024-10-31 18:39:59.982 | INFO | gdsfactory.component:_write_library:2008 - Write YAML metadata to 'extra/mzi.yml'
This created a mzi.yml
file that contains:
ports
cells (flat list of cells)
info (function name, module, changed settings, full settings, default settings)
c.pprint()
{ │ 'settings': { │ │ 'delta_length': 10.0, │ │ 'length_y': 2.0, │ │ 'length_x': 0.1, │ │ 'bend': {'function': 'bend_euler'}, │ │ 'straight': {'function': 'straight'}, │ │ 'splitter': 'mmi1x2', │ │ 'with_splitter': True, │ │ 'port_e1_splitter': 'o2', │ │ 'port_e0_splitter': 'o3', │ │ 'port_e1_combiner': 'o2', │ │ 'port_e0_combiner': 'o3', │ │ 'nbends': 2, │ │ 'cross_section': 'xs_sc', │ │ 'mirror_bot': False, │ │ 'add_optical_ports_arms': False, │ │ 'add_electrical_ports_bot': True, │ │ 'min_length': 0.01 │ }, │ 'function': 'mzi', │ 'module': 'gdsfactory.components.mzi', │ 'name': 'mzi', │ 'info': {} }
You can read GDS files into gdsfactory thanks to the import_gds
function
import_gds
reads the same GDS file from disk without losing any information
c = gf.import_gds(gdspath, read_metadata=True)
c.plot()
2024-10-31 18:40:00.001 | INFO | gdsfactory.read.import_gds:import_gds:123 - Read YAML metadata from extra/mzi.yml
c2 = gf.import_gds(gdspath, read_metadata=True)
c2.plot()
c2.name
'mzi'
c3 = gf.routing.add_fiber_single(c2)
c3.plot()
gdspath = c3.write_gds("extra/pdk.gds", with_metadata=True)
2024-10-31 18:40:00.585 | INFO | gdsfactory.component:_write_library:2004 - Wrote to 'extra/pdk.gds'
2024-10-31 18:40:00.619 | INFO | gdsfactory.component:_write_library:2008 - Write YAML metadata to 'extra/pdk.yml'
gf.labels.write_labels.write_labels_klayout(gdspath, layer_label=(201, 0))
2024-10-31 18:40:00.625 | INFO | gdsfactory.labels.write_labels:write_labels_klayout:95 - Wrote 0 labels to CSV /home/runner/work/gdsfactory7/gdsfactory7/notebooks/extra/pdk.csv
PosixPath('extra/pdk.csv')
add ports from pins#
Sometimes the GDS does not have YAML metadata, therefore you need to figure out the port locations, widths and orientations.
gdsfactory provides you with functions that will add ports to the component by looking for pins shapes on a specific layers (port_markers or pins)
There are different pin standards supported to automatically add ports to components:
PINs towards the inside of the port (port at the outer part of the PIN)
PINs with half of the pin inside and half outside (port at the center of the PIN)
PIN with only labels (no shapes). You have to manually specify the width of the port.
Lets add pins, save a GDS and then import it back.
from functools import partial
c = gf.components.straight()
c_with_pins = gf.add_pins.add_pins_container(component=c)
c_with_pins.plot(show_ports=False)
gdspath = c_with_pins.write_gds("extra/wg.gds")
2024-10-31 18:40:00.775 | INFO | gdsfactory.component:_write_library:2004 - Wrote to 'extra/wg.gds'
c2 = gf.import_gds(gdspath)
c2.plot()
c2.ports # import_gds does not automatically add the pins
{}
c3 = gf.import_gds(gdspath)
c3 = gf.add_ports.add_ports_from_markers_inside(c3, port_layer="PORT")
c3.plot(show_ports=False)
c3.pprint_ports()
┏━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┓ ┃ name ┃ width ┃ center ┃ orientation ┃ layer ┃ port_type ┃ ┡━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━┩ │ o1 │ 0.5 │ [0.0, 0.0] │ 180 │ [1, 10] │ optical │ │ o2 │ 0.5 │ [10.0, 0.0] │ 0 │ [1, 10] │ optical │ └──────┴───────┴─────────────┴─────────────┴─────────┴───────────┘
Foundries provide PDKs in different formats and commercial tools.
The easiest way to import a PDK into gdsfactory is to:
have each GDS cell into a separate GDS file
have one GDS file with all the cells inside
Have a KLayout layermap. Makes easier to create the layermap.
With that you can easily create the PDK as as python package.
Thanks to having a gdsfactory PDK as a python package you can:
version control your PDK using GIT to keep track of changes and work on a team
write tests of your pdk components to avoid unwanted changes from one component to another.
ensure you maintain the quality of the PDK with continuous integration checks
pin the version of gdsfactory, so new updates of gdsfactory won’t affect your code
name your PDK version using semantic versioning. For example patches increase the last number (0.0.1 -> 0.0.2)
install your PDK easily
pip install pdk_fab_a
and easily interface with other tools
To create a Python package you can start from a customizable template (thanks to cookiecutter)
You can create a python package by running this 2 commands inside a terminal:
pip install cookiecutter
cookiecutter gh:joamatab/python
It will ask you some questions to fill in the template for the python package.
Then you can add the information about the GDS files and the Layers inside that package
print(lyp_to_dataclass(PATH.klayout_lyp))
from gdsfactory.typings import Layer
from gdsfactory.technology.layer_map import LayerMap
class LayerMapFab(LayerMap):
CAPACITOR: Layer = (42, 0)
DEEPTRENCH: Layer = (4, 0)
DEEP_ETCH: Layer = (3, 6)
DICING: Layer = (65, 0)
DRC_EXCLUDE: Layer = (67, 0)
DRC_MARKER: Layer = (205, 0)
DevRec: Layer = (68, 0)
ERROR_PATH: Layer = (1000, 0)
Errors: Layer = (69, 0)
FLOORPLAN: Layer = (64, 0)
FbrTgt: Layer = (81, 0)
GE: Layer = (5, 0)
GENPP: Layer = (26, 0)
GEPPP: Layer = (29, 0)
LABEL_INSTANCES: Layer = (206, 0)
LABEL_OPTICAL_IO: Layer = (201, 0)
LABEL_SETTINGS: Layer = (202, 0)
Lumerical: Layer = (733, 0)
M1: Layer = (41, 0)
M1TILES: Layer = (191, 0)
M2: Layer = (45, 0)
M3: Layer = (49, 0)
METALOPEN: Layer = (46, 0)
MH: Layer = (47, 0)
MONITOR: Layer = (101, 0)
N: Layer = (20, 0)
NOTILE_M1: Layer = (71, 0)
NOTILE_M2: Layer = (72, 0)
NOTILE_M3: Layer = (73, 0)
NP: Layer = (22, 0)
NPP: Layer = (24, 0)
OXIDE_ETCH: Layer = (6, 0)
PDPP: Layer = (27, 0)
PP: Layer = (23, 0)
PPP: Layer = (25, 0)
P_210: Layer = (21, 0)
PinRec: Layer = (1, 10)
PinRecM: Layer = (1, 11)
SHALLOW_ETCH: Layer = (2, 6)
SHOW_PORTS: Layer = (1, 12)
SILICIDE: Layer = (39, 0)
SIM_REGION: Layer = (100, 0)
SITILES: Layer = (190, 0)
SLAB150: Layer = (2, 0)
SLAB150CLAD: Layer = (2, 9)
SLAB90: Layer = (3, 0)
SLAB90CLAD: Layer = (3, 1)
SOURCE: Layer = (110, 0)
TE: Layer = (203, 0)
TM: Layer = (204, 0)
Text: Layer = (66, 0)
VIA1: Layer = (44, 0)
VIA2: Layer = (43, 0)
VIAC: Layer = (40, 0)
WAFER: Layer = (99999, 0)
WGCLAD: Layer = (111, 0)
WGN_Nitride: Layer = (34, 0)
WGclad_material: Layer = (36, 0)
Waveguide: Layer = (1, 0)
XS_BOX: Layer = (300, 0)
XS_GE: Layer = (315, 0)
XS_M2: Layer = (399, 0)
XS_MH: Layer = (306, 0)
XS_N: Layer = (320, 0)
XS_NPP: Layer = (321, 0)
XS_OVERLAY: Layer = (311, 0)
XS_OXIDE_M1: Layer = (305, 0)
XS_OXIDE_M2: Layer = (307, 0)
XS_OXIDE_M3: Layer = (311, 0)
XS_OXIDE_MH: Layer = (317, 0)
XS_OXIDE_ML: Layer = (309, 0)
XS_OX_NIT_CLAD: Layer = (304, 0)
XS_OX_SI: Layer = (302, 0)
XS_P: Layer = (330, 0)
XS_PDPP: Layer = (327, 0)
XS_PPP: Layer = (331, 0)
XS_SI: Layer = (301, 0)
XS_SIN: Layer = (319, 0)
XS_SIN2: Layer = (305, 0)
XS_SI_SLAB: Layer = (313, 0)
XS_VIA1: Layer = (308, 0)
XS_VIA2: Layer = (310, 0)
XS_VIAC: Layer = (303, 0)
LAYER = LayerMapFab()
# lets create a sample PDK (for demo purposes only) using GDSfactory
# if the PDK is in a commercial tool you can also do this. Make sure you save a single pdk.gds
sample_pdk_cells = gf.grid(
[
gf.components.straight,
gf.components.bend_euler,
gf.components.grating_coupler_elliptical,
]
)
sample_pdk_cells.write_gds("extra/pdk.gds")
sample_pdk_cells
2024-10-31 18:40:01.136 | INFO | gdsfactory.component:_write_library:2004 - Wrote to 'extra/pdk.gds'
2024-10-31 18:40:01.141 | WARNING | gdsfactory.klive:show:49 - UserWarning: Could not connect to klive server. Is klayout open and klive plugin installed?
grid_d9610e5f: uid 7d30f778, ports ['0_0-o1', '0_0-o2', '1_0-o1', '1_0-o2', '2_0-o1', '2_0-o2'], references ['straight_1', 'bend_euler_1', 'grating_coupler_elliptical_1'], 0 polygons
sample_pdk_cells.get_dependencies()
[
grating_coupler_elliptical: uid 2ade2482, ports ['o1', 'o2'], references [], 32 polygons,
bend_euler: uid 9e37aeb1, ports ['o1', 'o2'], references [], 1 polygons,
straight: uid 3a5ecaf3, ports ['o1', 'o2'], references [], 1 polygons
]
# we write the sample PDK into a single GDS file
gf.write_cells.write_cells_recursively(gdspath="extra/pdk.gds", dirpath="extra/gds")
2024-10-31 18:40:01.306 | INFO | gdsfactory.write_cells:write_cells_recursively:152 - Write 'grid_d9610e5f' to extra/gds/grid_d9610e5f.gds
2024-10-31 18:40:01.308 | INFO | gdsfactory.write_cells:write_cells_recursively:152 - Write 'bend_euler' to extra/gds/bend_euler.gds
2024-10-31 18:40:01.309 | INFO | gdsfactory.write_cells:write_cells_recursively:152 - Write 'grating_coupler_elliptical' to extra/gds/grating_coupler_elliptical.gds
2024-10-31 18:40:01.309 | INFO | gdsfactory.write_cells:write_cells_recursively:152 - Write 'straight' to extra/gds/straight.gds
{
'grid_d9610e5f': PosixPath('extra/gds/grid_d9610e5f.gds'),
'bend_euler': PosixPath('extra/gds/bend_euler.gds'),
'grating_coupler_elliptical': PosixPath('extra/gds/grating_coupler_elliptical.gds'),
'straight': PosixPath('extra/gds/straight.gds')
}
print(gf.write_cells.get_import_gds_script("extra/gds"))
2024-10-31 18:40:01.318 | INFO | gdsfactory.write_cells:get_import_gds_script:105 - Writing 4 cells from PosixPath('/home/runner/work/gdsfactory7/gdsfactory7/notebooks/extra/gds')
from pathlib import PosixPath
from functools import partial
import gdsfactory as gf
add_ports_optical = partial(
gf.add_ports.add_ports_from_markers_inside, pin_layer=(1, 0), port_layer=(2, 0)
)
add_ports_electrical = partial(
gf.add_ports.add_ports_from_markers_inside, pin_layer=(41, 0), port_layer=(1, 0)
)
add_ports = gf.compose(add_ports_optical, add_ports_electrical)
gdsdir = '/home/runner/work/gdsfactory7/gdsfactory7/notebooks/extra/gds'
import_gds = partial(gf.import_gds, gdsdir=gdsdir, decorator=add_ports)
@gf.cell
def bend_euler()->gf.Component:
'''Returns bend_euler fixed cell.'''
return import_gds('bend_euler.gds')
@gf.cell
def grating_coupler_elliptical()->gf.Component:
'''Returns grating_coupler_elliptical fixed cell.'''
return import_gds('grating_coupler_elliptical.gds')
@gf.cell
def grid_d9610e5f()->gf.Component:
'''Returns grid_d9610e5f fixed cell.'''
return import_gds('grid_d9610e5f.gds')
@gf.cell
def straight()->gf.Component:
'''Returns straight fixed cell.'''
return import_gds('straight.gds')
You can also include the code to plot each fix cell in the docstring.
print(gf.write_cells.get_import_gds_script("extra/gds", module="samplepdk.components"))
2024-10-31 18:40:01.324 | INFO | gdsfactory.write_cells:get_import_gds_script:105 - Writing 4 cells from PosixPath('/home/runner/work/gdsfactory7/gdsfactory7/notebooks/extra/gds')
from pathlib import PosixPath
from functools import partial
import gdsfactory as gf
add_ports_optical = partial(
gf.add_ports.add_ports_from_markers_inside, pin_layer=(1, 0), port_layer=(2, 0)
)
add_ports_electrical = partial(
gf.add_ports.add_ports_from_markers_inside, pin_layer=(41, 0), port_layer=(1, 0)
)
add_ports = gf.compose(add_ports_optical, add_ports_electrical)
gdsdir = '/home/runner/work/gdsfactory7/gdsfactory7/notebooks/extra/gds'
import_gds = partial(gf.import_gds, gdsdir=gdsdir, decorator=add_ports)
@gf.cell
def bend_euler()->gf.Component:
'''Returns bend_euler fixed cell.'''
return import_gds('bend_euler.gds')
@gf.cell
def grating_coupler_elliptical()->gf.Component:
'''Returns grating_coupler_elliptical fixed cell.'''
return import_gds('grating_coupler_elliptical.gds')
@gf.cell
def grid_d9610e5f()->gf.Component:
'''Returns grid_d9610e5f fixed cell.'''
return import_gds('grid_d9610e5f.gds')
@gf.cell
def straight()->gf.Component:
'''Returns straight fixed cell.'''
return import_gds('straight.gds')
Import PDK from other python packages#
You can Write the cells to GDS and use the
Ideally you also start transitioning your legacy code Pcells into gdsfactory syntax. It’s a great way to learn the gdsfactory way!
Here is some advice:
Ask your foundry for the gdsfactory PDK.
Leverage the generic pdk cells available in gdsfactory.
Write tests for your cells.
Break the cells into small reusable functions.
use GIT to track changes.
review your code with your colleagues and other gdsfactory developers to get feedback. This is key to get better at coding gdsfactory.
get rid of any warnings you see.
Import PDK from YAML uPDK#
gdsfactory supports read and write to uPDK YAML definition
Lets write a PDK into uPDK YAML definition and then convert it back to a gdsfactory script.
the uPDK extracts the code from the docstrings.
def evanescent_coupler_sample() -> None:
"""Evanescent coupler example.
Args:
coupler_length: length of coupling (min: 0.0, max: 200.0, um).
"""
pass
from gdsfactory.samples.pdk.fab_c import pdk
yaml_pdk_decription = pdk.to_updk()
print(yaml_pdk_decription)
blocks:
bend_euler_nc:
bbox:
- - -3.0
- -3.5
- - 13.5
- -3.5
- - 13.5
- 13.0
- - -3.0
- 13.0
doc: ''
settings: {}
parameters: {}
pins:
o1:
width: 1.0
xsection: xs_6dc110e2
xya:
- 0.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 1.0
xsection: xs_6dc110e2
xya:
- 10.0
- 10.0
- 90.0
alias: null
doc: null
bend_euler_no:
bbox:
- - -3.0
- -3.45
- - 13.45
- -3.45
- - 13.45
- 13.0
- - -3.0
- 13.0
doc: ''
settings: {}
parameters: {}
pins:
o1:
width: 0.9
xsection: xs_dbcb4311
xya:
- 0.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 0.9
xsection: xs_dbcb4311
xya:
- 10.0
- 10.0
- 90.0
alias: null
doc: null
bend_euler_sc:
bbox:
- - -3.0
- -3.25
- - 13.25
- -3.25
- - 13.25
- 13.0
- - -3.0
- 13.0
doc: ''
settings: {}
parameters: {}
pins:
o1:
width: 0.5
xsection: xs_b1b0ed23
xya:
- 0.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 0.5
xsection: xs_b1b0ed23
xya:
- 10.0
- 10.0
- 90.0
alias: null
doc: null
bend_euler_so:
bbox:
- - -3.0
- -3.2
- - 13.2
- -3.2
- - 13.2
- 13.0
- - -3.0
- 13.0
doc: ''
settings: {}
parameters: {}
pins:
o1:
width: 0.4
xsection: xs_28722cff
xya:
- 0.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 0.4
xsection: xs_28722cff
xya:
- 10.0
- 10.0
- 90.0
alias: null
doc: null
gc_sc:
bbox:
- - -3.0
- -14.128
- - 40.18
- -14.128
- - 40.18
- 14.128
- - -3.0
- 14.128
doc: ''
settings: {}
parameters: {}
pins:
o1:
width: 1.0
xsection: null
xya:
- 0.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 10
xsection: null
xya:
- 16.6
- 0.0
- 0.0
alias: null
doc: null
mmi1x2_nc:
bbox:
- - -13.0
- -4.5
- - 18.5
- -4.5
- - 18.5
- 4.5
- - -13.0
- 4.5
doc: ''
settings: {}
parameters:
width_mmi:
value: 3
type: int
doc: null
min: 0
max: 0
unit: null
pins:
o1:
width: 1.0
xsection: xs_6dc110e2
xya:
- -10.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 1.0
xsection: xs_6dc110e2
xya:
- 15.5
- 0.625
- 0.0
alias: null
doc: null
o3:
width: 1.0
xsection: xs_6dc110e2
xya:
- 15.5
- -0.625
- 0.0
alias: null
doc: null
mmi1x2_no:
bbox:
- - -13.0
- -4.5
- - 18.5
- -4.5
- - 18.5
- 4.5
- - -13.0
- 4.5
doc: ''
settings: {}
parameters:
width_mmi:
value: 3
type: int
doc: null
min: 0
max: 0
unit: null
pins:
o1:
width: 0.9
xsection: xs_dbcb4311
xya:
- -10.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 0.9
xsection: xs_dbcb4311
xya:
- 15.5
- 0.625
- 0.0
alias: null
doc: null
o3:
width: 0.9
xsection: xs_dbcb4311
xya:
- 15.5
- -0.625
- 0.0
alias: null
doc: null
mmi1x2_sc:
bbox:
- - -13.0
- -4.5
- - 18.5
- -4.5
- - 18.5
- 4.5
- - -13.0
- 4.5
doc: ''
settings: {}
parameters:
width_mmi:
value: 3
type: int
doc: null
min: 0
max: 0
unit: null
pins:
o1:
width: 0.5
xsection: xs_b1b0ed23
xya:
- -10.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 0.5
xsection: xs_b1b0ed23
xya:
- 15.5
- 0.625
- 0.0
alias: null
doc: null
o3:
width: 0.5
xsection: xs_b1b0ed23
xya:
- 15.5
- -0.625
- 0.0
alias: null
doc: null
mmi1x2_so:
bbox:
- - -13.0
- -4.5
- - 18.5
- -4.5
- - 18.5
- 4.5
- - -13.0
- 4.5
doc: ''
settings: {}
parameters:
width_mmi:
value: 3
type: int
doc: null
min: 0
max: 0
unit: null
pins:
o1:
width: 0.4
xsection: xs_28722cff
xya:
- -10.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 0.4
xsection: xs_28722cff
xya:
- 15.5
- 0.625
- 0.0
alias: null
doc: null
o3:
width: 0.4
xsection: xs_28722cff
xya:
- 15.5
- -0.625
- 0.0
alias: null
doc: null
mzi_nc:
bbox:
- - -13.0
- -31.125
- - 87.12
- -31.125
- - 87.12
- 26.125
- - -13.0
- 26.125
doc: Mzi.
settings:
delta_length:
doc: bottom arm vertical extra length.
min: 0
max: 0
type: float
unit: null
value: 0.0
length_y:
doc: vertical length for both and top arms.
min: 0
max: 0
type: float
unit: null
value: 0.0
length_x:
doc: horizontal length. None uses to the straight_x_bot/top defaults.
min: 0
max: 0
type: float
unit: null
value: 0.0
bend:
doc: 90 degrees bend library.
min: 0
max: 0
type: float
unit: null
value: 0.0
straight:
doc: straight function.
min: 0
max: 0
type: float
unit: null
value: 0.0
straight_y:
doc: straight for length_y and delta_length.
min: 0
max: 0
type: float
unit: null
value: 0.0
straight_x_top:
doc: top straight for length_x.
min: 0
max: 0
type: float
unit: null
value: 0.0
straight_x_bot:
doc: bottom straight for length_x.
min: 0
max: 0
type: float
unit: null
value: 0.0
extend_ports_straight_x:
doc: optional extend ports for straight_x_bot/top.
min: 0
max: 0
type: float
unit: null
value: 0.0
splitter:
doc: splitter function.
min: 0
max: 0
type: float
unit: null
value: 0.0
combiner:
doc: combiner function.
min: 0
max: 0
type: float
unit: null
value: 0.0
with_splitter:
doc: if False removes splitter.
min: 0
max: 0
type: float
unit: null
value: 0.0
port_e1_splitter:
doc: east top splitter port.
min: 0
max: 0
type: float
unit: null
value: 0.0
port_e0_splitter:
doc: east bot splitter port.
min: 0
max: 0
type: float
unit: null
value: 0.0
port_e1_combiner:
doc: east top combiner port.
min: 0
max: 0
type: float
unit: null
value: 0.0
port_e0_combiner:
doc: east bot combiner port.
min: 0
max: 0
type: float
unit: null
value: 0.0
nbends:
doc: from straight top/bot to combiner
min: 0
max: 0
type: float
unit: null
value: 0.0
cross_section:
doc: for routing
min: 0
max: 0
type: float
unit: null
value: 0.0
cross_section_x_top:
doc: optional top cross_section
min: 0
max: 0
type: float
unit: null
value: 0.0
cross_section_x_bot:
doc: optional bottom cross_section
min: 0
max: 0
type: float
unit: null
value: 0.0
mirror_bot:
doc: if true, mirrors the bottom arm.
min: 0
max: 0
type: float
unit: null
value: 0.0
add_optical_ports_arms:
doc: add all other optical ports in the arms
min: 0
max: 0
type: float
unit: null
value: 0.0
add_electrical_ports_bot:
doc: add electrical ports to the bottom arm.
min: 0
max: 0
type: float
unit: null
value: 0.0
min_length:
doc: minimum length for the straight_x_bot/top.
min: 0
max: 0
type: float
unit: null
value: 0.0
parameters:
delta_length:
value: 10.0
type: float
doc: bottom arm vertical extra length.
min: 0
max: 0
unit: null
length_y:
value: 2.0
type: float
doc: vertical length for both and top arms.
min: 0
max: 0
unit: null
length_x:
value: 0.1
type: float
doc: horizontal length. None uses to the straight_x_bot/top defaults.
min: 0
max: 0
unit: null
with_splitter:
value: true
type: bool
doc: if False removes splitter.
min: 0
max: 0
unit: null
port_e1_splitter:
value: o2
type: str
doc: east top splitter port.
min: 0
max: 0
unit: null
port_e0_splitter:
value: o3
type: str
doc: east bot splitter port.
min: 0
max: 0
unit: null
port_e1_combiner:
value: o2
type: str
doc: east top combiner port.
min: 0
max: 0
unit: null
port_e0_combiner:
value: o3
type: str
doc: east bot combiner port.
min: 0
max: 0
unit: null
nbends:
value: 2
type: int
doc: from straight top/bot to combiner
min: 0
max: 0
unit: null
mirror_bot:
value: false
type: bool
doc: if true, mirrors the bottom arm.
min: 0
max: 0
unit: null
add_optical_ports_arms:
value: false
type: bool
doc: add all other optical ports in the arms
min: 0
max: 0
unit: null
add_electrical_ports_bot:
value: true
type: bool
doc: add electrical ports to the bottom arm.
min: 0
max: 0
unit: null
min_length:
value: 0.01
type: float
doc: minimum length for the straight_x_bot/top.
min: 0
max: 0
unit: null
pins:
o1:
width: 1.0
xsection: xs_6dc110e2
xya:
- -10.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 1.0
xsection: xs_6dc110e2
xya:
- 84.12
- 0.0
- 0.0
alias: null
doc: null
mzi_no:
bbox:
- - -13.0
- -31.075000000000003
- - 87.12
- -31.075000000000003
- - 87.12
- 26.075000000000003
- - -13.0
- 26.075000000000003
doc: Mzi.
settings:
delta_length:
doc: bottom arm vertical extra length.
min: 0
max: 0
type: float
unit: null
value: 0.0
length_y:
doc: vertical length for both and top arms.
min: 0
max: 0
type: float
unit: null
value: 0.0
length_x:
doc: horizontal length. None uses to the straight_x_bot/top defaults.
min: 0
max: 0
type: float
unit: null
value: 0.0
bend:
doc: 90 degrees bend library.
min: 0
max: 0
type: float
unit: null
value: 0.0
straight:
doc: straight function.
min: 0
max: 0
type: float
unit: null
value: 0.0
straight_y:
doc: straight for length_y and delta_length.
min: 0
max: 0
type: float
unit: null
value: 0.0
straight_x_top:
doc: top straight for length_x.
min: 0
max: 0
type: float
unit: null
value: 0.0
straight_x_bot:
doc: bottom straight for length_x.
min: 0
max: 0
type: float
unit: null
value: 0.0
extend_ports_straight_x:
doc: optional extend ports for straight_x_bot/top.
min: 0
max: 0
type: float
unit: null
value: 0.0
splitter:
doc: splitter function.
min: 0
max: 0
type: float
unit: null
value: 0.0
combiner:
doc: combiner function.
min: 0
max: 0
type: float
unit: null
value: 0.0
with_splitter:
doc: if False removes splitter.
min: 0
max: 0
type: float
unit: null
value: 0.0
port_e1_splitter:
doc: east top splitter port.
min: 0
max: 0
type: float
unit: null
value: 0.0
port_e0_splitter:
doc: east bot splitter port.
min: 0
max: 0
type: float
unit: null
value: 0.0
port_e1_combiner:
doc: east top combiner port.
min: 0
max: 0
type: float
unit: null
value: 0.0
port_e0_combiner:
doc: east bot combiner port.
min: 0
max: 0
type: float
unit: null
value: 0.0
nbends:
doc: from straight top/bot to combiner
min: 0
max: 0
type: float
unit: null
value: 0.0
cross_section:
doc: for routing
min: 0
max: 0
type: float
unit: null
value: 0.0
cross_section_x_top:
doc: optional top cross_section
min: 0
max: 0
type: float
unit: null
value: 0.0
cross_section_x_bot:
doc: optional bottom cross_section
min: 0
max: 0
type: float
unit: null
value: 0.0
mirror_bot:
doc: if true, mirrors the bottom arm.
min: 0
max: 0
type: float
unit: null
value: 0.0
add_optical_ports_arms:
doc: add all other optical ports in the arms
min: 0
max: 0
type: float
unit: null
value: 0.0
add_electrical_ports_bot:
doc: add electrical ports to the bottom arm.
min: 0
max: 0
type: float
unit: null
value: 0.0
min_length:
doc: minimum length for the straight_x_bot/top.
min: 0
max: 0
type: float
unit: null
value: 0.0
parameters:
delta_length:
value: 10.0
type: float
doc: bottom arm vertical extra length.
min: 0
max: 0
unit: null
length_y:
value: 2.0
type: float
doc: vertical length for both and top arms.
min: 0
max: 0
unit: null
length_x:
value: 0.1
type: float
doc: horizontal length. None uses to the straight_x_bot/top defaults.
min: 0
max: 0
unit: null
with_splitter:
value: true
type: bool
doc: if False removes splitter.
min: 0
max: 0
unit: null
port_e1_splitter:
value: o2
type: str
doc: east top splitter port.
min: 0
max: 0
unit: null
port_e0_splitter:
value: o3
type: str
doc: east bot splitter port.
min: 0
max: 0
unit: null
port_e1_combiner:
value: o2
type: str
doc: east top combiner port.
min: 0
max: 0
unit: null
port_e0_combiner:
value: o3
type: str
doc: east bot combiner port.
min: 0
max: 0
unit: null
nbends:
value: 2
type: int
doc: from straight top/bot to combiner
min: 0
max: 0
unit: null
mirror_bot:
value: false
type: bool
doc: if true, mirrors the bottom arm.
min: 0
max: 0
unit: null
add_optical_ports_arms:
value: false
type: bool
doc: add all other optical ports in the arms
min: 0
max: 0
unit: null
add_electrical_ports_bot:
value: true
type: bool
doc: add electrical ports to the bottom arm.
min: 0
max: 0
unit: null
min_length:
value: 0.01
type: float
doc: minimum length for the straight_x_bot/top.
min: 0
max: 0
unit: null
pins:
o1:
width: 0.9
xsection: xs_dbcb4311
xya:
- -10.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 0.9
xsection: xs_dbcb4311
xya:
- 84.12
- 0.0
- 0.0
alias: null
doc: null
straight_nc:
bbox:
- - -3.0
- -3.5
- - 13.0
- -3.5
- - 13.0
- 3.5
- - -3.0
- 3.5
doc: ''
settings: {}
parameters: {}
pins:
o1:
width: 1.0
xsection: xs_6dc110e2
xya:
- 0.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 1.0
xsection: xs_6dc110e2
xya:
- 10.0
- 0.0
- 0.0
alias: null
doc: null
straight_no:
bbox:
- - -3.0
- -3.45
- - 13.0
- -3.45
- - 13.0
- 3.45
- - -3.0
- 3.45
doc: ''
settings: {}
parameters: {}
pins:
o1:
width: 0.9
xsection: xs_dbcb4311
xya:
- 0.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 0.9
xsection: xs_dbcb4311
xya:
- 10.0
- 0.0
- 0.0
alias: null
doc: null
straight_sc:
bbox:
- - -3.0
- -3.5
- - 13.0
- -3.5
- - 13.0
- 3.5
- - -3.0
- 3.5
doc: ''
settings: {}
parameters: {}
pins:
o1:
width: 1.0
xsection: xs_6dc110e2
xya:
- 0.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 1.0
xsection: xs_6dc110e2
xya:
- 10.0
- 0.0
- 0.0
alias: null
doc: null
straight_so:
bbox:
- - -3.0
- -3.2
- - 13.0
- -3.2
- - 13.0
- 3.2
- - -3.0
- 3.2
doc: ''
settings: {}
parameters: {}
pins:
o1:
width: 0.4
xsection: xs_28722cff
xya:
- 0.0
- 0.0
- 180.0
alias: null
doc: null
o2:
width: 0.4
xsection: xs_28722cff
xya:
- 10.0
- 0.0
- 0.0
alias: null
doc: null
xsections:
strip:
width: 0.5
strip_nc:
width: 1.0
strip_no:
width: 0.9
strip_sc:
width: 0.5
strip_so:
width: 0.4
xs_nc:
width: 1.0
xs_no:
width: 0.9
xs_sc:
width: 0.5
xs_so:
width: 0.4
header:
description: fab_c_demopdk
from gdsfactory.read.from_updk import from_updk
gdsfactory_script = from_updk(yaml_pdk_decription)
print(gdsfactory_script)
import sys
from functools import partial
import gdsfactory as gf
from gdsfactory.get_factories import get_cells
from gdsfactory.add_pins import add_pins_inside2um
cell = partial(gf.cell, naming_style='updk', autoname=False)
layer_bbox = (68, 0)
layer_bbmetal = None
layer_pin_label = None
layer_pin = None
layer_pin_optical = None
layer_pin_electrical = None
layer_label = None
layer_text = (1, 0)
text_function = partial(gf.components.text, layer=layer_text, justify="center", size=2.0)
add_pins = partial(add_pins_inside2um, layer_label=layer_label, layer=layer_pin_optical)
strip = gf.CrossSection(width=0.5)
strip_nc = gf.CrossSection(width=1.0)
strip_no = gf.CrossSection(width=0.9)
strip_sc = gf.CrossSection(width=0.5)
strip_so = gf.CrossSection(width=0.4)
xs_nc = gf.CrossSection(width=1.0)
xs_no = gf.CrossSection(width=0.9)
xs_sc = gf.CrossSection(width=0.5)
xs_so = gf.CrossSection(width=0.4)
cross_sections = dict(strip=strip,strip_nc=strip_nc,strip_no=strip_no,strip_sc=strip_sc,strip_so=strip_so,xs_nc=xs_nc,xs_no=xs_no,xs_sc=xs_sc,xs_so=xs_so)
@cell
def bend_euler_nc()->gf.Component:
""""""
c = gf.Component()
p = c.add_polygon([[-3.0, -3.5], [13.5, -3.5], [13.5, 13.0], [-3.0, 13.0]], layer=layer_bbox)
xc, yc = p.center
name = f'bend_euler_nc'
c.add_label(text=f'Parameters:\n', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_6dc110e2', center=(0.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_6dc110e2', center=(10.0, 10.0), orientation=90.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def bend_euler_no()->gf.Component:
""""""
c = gf.Component()
p = c.add_polygon([[-3.0, -3.45], [13.45, -3.45], [13.45, 13.0], [-3.0, 13.0]], layer=layer_bbox)
xc, yc = p.center
name = f'bend_euler_no'
c.add_label(text=f'Parameters:\n', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_dbcb4311', center=(0.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_dbcb4311', center=(10.0, 10.0), orientation=90.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def bend_euler_sc()->gf.Component:
""""""
c = gf.Component()
p = c.add_polygon([[-3.0, -3.25], [13.25, -3.25], [13.25, 13.0], [-3.0, 13.0]], layer=layer_bbox)
xc, yc = p.center
name = f'bend_euler_sc'
c.add_label(text=f'Parameters:\n', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_b1b0ed23', center=(0.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_b1b0ed23', center=(10.0, 10.0), orientation=90.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def bend_euler_so()->gf.Component:
""""""
c = gf.Component()
p = c.add_polygon([[-3.0, -3.2], [13.2, -3.2], [13.2, 13.0], [-3.0, 13.0]], layer=layer_bbox)
xc, yc = p.center
name = f'bend_euler_so'
c.add_label(text=f'Parameters:\n', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_28722cff', center=(0.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_28722cff', center=(10.0, 10.0), orientation=90.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def gc_sc()->gf.Component:
""""""
c = gf.Component()
p = c.add_polygon([[-3.0, -14.128], [40.18, -14.128], [40.18, 14.128], [-3.0, 14.128]], layer=layer_bbox)
xc, yc = p.center
name = f'gc_sc'
c.add_label(text=f'Parameters:\n', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section=None, center=(0.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section=None, center=(16.6, 0.0), orientation=0.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def mmi1x2_nc(width_mmi:int=3)->gf.Component:
"""
Args:
width_mmi: None (min: 0, max: 0, None).
"""
c = gf.Component()
p = c.add_polygon([[-13.0, -4.5], [18.5, -4.5], [18.5, 4.5], [-13.0, 4.5]], layer=layer_bbox)
xc, yc = p.center
name = f'mmi1x2_nc:width_mmi={width_mmi}'
c.add_label(text=f'Parameters:\nwidth_mmi={width_mmi}', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_6dc110e2', center=(-10.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_6dc110e2', center=(15.5, 0.625), orientation=0.0, port_type='optical')
c.add_port(name='o3', cross_section='xs_6dc110e2', center=(15.5, -0.625), orientation=0.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def mmi1x2_no(width_mmi:int=3)->gf.Component:
"""
Args:
width_mmi: None (min: 0, max: 0, None).
"""
c = gf.Component()
p = c.add_polygon([[-13.0, -4.5], [18.5, -4.5], [18.5, 4.5], [-13.0, 4.5]], layer=layer_bbox)
xc, yc = p.center
name = f'mmi1x2_no:width_mmi={width_mmi}'
c.add_label(text=f'Parameters:\nwidth_mmi={width_mmi}', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_dbcb4311', center=(-10.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_dbcb4311', center=(15.5, 0.625), orientation=0.0, port_type='optical')
c.add_port(name='o3', cross_section='xs_dbcb4311', center=(15.5, -0.625), orientation=0.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def mmi1x2_sc(width_mmi:int=3)->gf.Component:
"""
Args:
width_mmi: None (min: 0, max: 0, None).
"""
c = gf.Component()
p = c.add_polygon([[-13.0, -4.5], [18.5, -4.5], [18.5, 4.5], [-13.0, 4.5]], layer=layer_bbox)
xc, yc = p.center
name = f'mmi1x2_sc:width_mmi={width_mmi}'
c.add_label(text=f'Parameters:\nwidth_mmi={width_mmi}', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_b1b0ed23', center=(-10.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_b1b0ed23', center=(15.5, 0.625), orientation=0.0, port_type='optical')
c.add_port(name='o3', cross_section='xs_b1b0ed23', center=(15.5, -0.625), orientation=0.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def mmi1x2_so(width_mmi:int=3)->gf.Component:
"""
Args:
width_mmi: None (min: 0, max: 0, None).
"""
c = gf.Component()
p = c.add_polygon([[-13.0, -4.5], [18.5, -4.5], [18.5, 4.5], [-13.0, 4.5]], layer=layer_bbox)
xc, yc = p.center
name = f'mmi1x2_so:width_mmi={width_mmi}'
c.add_label(text=f'Parameters:\nwidth_mmi={width_mmi}', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_28722cff', center=(-10.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_28722cff', center=(15.5, 0.625), orientation=0.0, port_type='optical')
c.add_port(name='o3', cross_section='xs_28722cff', center=(15.5, -0.625), orientation=0.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def mzi_nc(delta_length:float=10.0, length_y:float=2.0, length_x:float=0.1, with_splitter:bool=True, port_e1_splitter:str=o2, port_e0_splitter:str=o3, port_e1_combiner:str=o2, port_e0_combiner:str=o3, nbends:int=2, mirror_bot:bool=False, add_optical_ports_arms:bool=False, add_electrical_ports_bot:bool=True, min_length:float=0.01)->gf.Component:
"""Mzi.
Args:
delta_length: bottom arm vertical extra length. (min: 0, max: 0, None).
length_y: vertical length for both and top arms. (min: 0, max: 0, None).
length_x: horizontal length. None uses to the straight_x_bot/top defaults. (min: 0, max: 0, None).
with_splitter: if False removes splitter. (min: 0, max: 0, None).
port_e1_splitter: east top splitter port. (min: 0, max: 0, None).
port_e0_splitter: east bot splitter port. (min: 0, max: 0, None).
port_e1_combiner: east top combiner port. (min: 0, max: 0, None).
port_e0_combiner: east bot combiner port. (min: 0, max: 0, None).
nbends: from straight top/bot to combiner (min: 0, max: 0, None).
mirror_bot: if true, mirrors the bottom arm. (min: 0, max: 0, None).
add_optical_ports_arms: add all other optical ports in the arms (min: 0, max: 0, None).
add_electrical_ports_bot: add electrical ports to the bottom arm. (min: 0, max: 0, None).
min_length: minimum length for the straight_x_bot/top. (min: 0, max: 0, None).
"""
c = gf.Component()
p = c.add_polygon([[-13.0, -31.125], [87.12, -31.125], [87.12, 26.125], [-13.0, 26.125]], layer=layer_bbox)
xc, yc = p.center
name = f'mzi_nc:delta_length={delta_length},length_y={length_y},length_x={length_x},with_splitter={with_splitter},port_e1_splitter={port_e1_splitter},port_e0_splitter={port_e0_splitter},port_e1_combiner={port_e1_combiner},port_e0_combiner={port_e0_combiner},nbends={nbends},mirror_bot={mirror_bot},add_optical_ports_arms={add_optical_ports_arms},add_electrical_ports_bot={add_electrical_ports_bot},min_length={min_length}'
c.add_label(text=f'Parameters:\ndelta_length={delta_length}\nlength_y={length_y}\nlength_x={length_x}\nwith_splitter={with_splitter}\nport_e1_splitter={port_e1_splitter}\nport_e0_splitter={port_e0_splitter}\nport_e1_combiner={port_e1_combiner}\nport_e0_combiner={port_e0_combiner}\nnbends={nbends}\nmirror_bot={mirror_bot}\nadd_optical_ports_arms={add_optical_ports_arms}\nadd_electrical_ports_bot={add_electrical_ports_bot}\nmin_length={min_length}', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_6dc110e2', center=(-10.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_6dc110e2', center=(84.12, 0.0), orientation=0.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def mzi_no(delta_length:float=10.0, length_y:float=2.0, length_x:float=0.1, with_splitter:bool=True, port_e1_splitter:str=o2, port_e0_splitter:str=o3, port_e1_combiner:str=o2, port_e0_combiner:str=o3, nbends:int=2, mirror_bot:bool=False, add_optical_ports_arms:bool=False, add_electrical_ports_bot:bool=True, min_length:float=0.01)->gf.Component:
"""Mzi.
Args:
delta_length: bottom arm vertical extra length. (min: 0, max: 0, None).
length_y: vertical length for both and top arms. (min: 0, max: 0, None).
length_x: horizontal length. None uses to the straight_x_bot/top defaults. (min: 0, max: 0, None).
with_splitter: if False removes splitter. (min: 0, max: 0, None).
port_e1_splitter: east top splitter port. (min: 0, max: 0, None).
port_e0_splitter: east bot splitter port. (min: 0, max: 0, None).
port_e1_combiner: east top combiner port. (min: 0, max: 0, None).
port_e0_combiner: east bot combiner port. (min: 0, max: 0, None).
nbends: from straight top/bot to combiner (min: 0, max: 0, None).
mirror_bot: if true, mirrors the bottom arm. (min: 0, max: 0, None).
add_optical_ports_arms: add all other optical ports in the arms (min: 0, max: 0, None).
add_electrical_ports_bot: add electrical ports to the bottom arm. (min: 0, max: 0, None).
min_length: minimum length for the straight_x_bot/top. (min: 0, max: 0, None).
"""
c = gf.Component()
p = c.add_polygon([[-13.0, -31.075000000000003], [87.12, -31.075000000000003], [87.12, 26.075000000000003], [-13.0, 26.075000000000003]], layer=layer_bbox)
xc, yc = p.center
name = f'mzi_no:delta_length={delta_length},length_y={length_y},length_x={length_x},with_splitter={with_splitter},port_e1_splitter={port_e1_splitter},port_e0_splitter={port_e0_splitter},port_e1_combiner={port_e1_combiner},port_e0_combiner={port_e0_combiner},nbends={nbends},mirror_bot={mirror_bot},add_optical_ports_arms={add_optical_ports_arms},add_electrical_ports_bot={add_electrical_ports_bot},min_length={min_length}'
c.add_label(text=f'Parameters:\ndelta_length={delta_length}\nlength_y={length_y}\nlength_x={length_x}\nwith_splitter={with_splitter}\nport_e1_splitter={port_e1_splitter}\nport_e0_splitter={port_e0_splitter}\nport_e1_combiner={port_e1_combiner}\nport_e0_combiner={port_e0_combiner}\nnbends={nbends}\nmirror_bot={mirror_bot}\nadd_optical_ports_arms={add_optical_ports_arms}\nadd_electrical_ports_bot={add_electrical_ports_bot}\nmin_length={min_length}', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_dbcb4311', center=(-10.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_dbcb4311', center=(84.12, 0.0), orientation=0.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def straight_nc()->gf.Component:
""""""
c = gf.Component()
p = c.add_polygon([[-3.0, -3.5], [13.0, -3.5], [13.0, 3.5], [-3.0, 3.5]], layer=layer_bbox)
xc, yc = p.center
name = f'straight_nc'
c.add_label(text=f'Parameters:\n', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_6dc110e2', center=(0.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_6dc110e2', center=(10.0, 0.0), orientation=0.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def straight_no()->gf.Component:
""""""
c = gf.Component()
p = c.add_polygon([[-3.0, -3.45], [13.0, -3.45], [13.0, 3.45], [-3.0, 3.45]], layer=layer_bbox)
xc, yc = p.center
name = f'straight_no'
c.add_label(text=f'Parameters:\n', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_dbcb4311', center=(0.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_dbcb4311', center=(10.0, 0.0), orientation=0.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def straight_sc()->gf.Component:
""""""
c = gf.Component()
p = c.add_polygon([[-3.0, -3.5], [13.0, -3.5], [13.0, 3.5], [-3.0, 3.5]], layer=layer_bbox)
xc, yc = p.center
name = f'straight_sc'
c.add_label(text=f'Parameters:\n', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_6dc110e2', center=(0.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_6dc110e2', center=(10.0, 0.0), orientation=0.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
@cell
def straight_so()->gf.Component:
""""""
c = gf.Component()
p = c.add_polygon([[-3.0, -3.2], [13.0, -3.2], [13.0, 3.2], [-3.0, 3.2]], layer=layer_bbox)
xc, yc = p.center
name = f'straight_so'
c.add_label(text=f'Parameters:\n', position=(0,0), layer=layer_label)
c.add_port(name='o1', cross_section='xs_28722cff', center=(0.0, 0.0), orientation=180.0, port_type='optical')
c.add_port(name='o2', cross_section='xs_28722cff', center=(10.0, 0.0), orientation=0.0, port_type='optical')
c.name = name
if layer_pin:
add_pins(c, layer=layer_pin)
return c
if __name__ == "__main__":
c = straight_so()
c.show(show_ports=True)
Build your own PDK#
You can create a PDK as a python library using a cookiecutter template. For example, you can use this one.
pip install cookiecutter
cookiecutter gh:joamatab/python
Or you can fork the ubcpdk and create new PCell functions that use the correct layers for your foundry. For example.
from pydantic import BaseModel
class LayerMap(BaseModel):
WGCORE = (3, 0)
DEVREC: Layer = (68, 0)
PORT: Layer = (1, 10) # PinRec
PORTE: Layer = (1, 11) # PinRecM
FLOORPLAN: Layer = (99, 0)
TE: Layer = (203, 0)
TM: Layer = (204, 0)
TEXT: Layer = (66, 0)
LABEL_INSTANCE: Layer = (66, 0)
LAYER = LayerMap()