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 GDS

import gdsfactory as gf
from gdsfactory.config import PATH
from gdsfactory.technology import lyp_to_dataclass
c = gf.components.mzi()
c.plot()
../_images/77be629a40c99e860319282571c2a5d26d0f7b9192c4c1c978aca88733f1b17e.png

You can write GDS files.

gdspath = c.write_gds("extra/mzi.gds")
c.pprint_ports()
┏━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ name  width  orientation  layer  center                    port_type ┃
┡━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ o1   │ 0.5   │ 180.0       │ WG    │ (-10.0, 0.0)             │ optical   │
│ o2   │ 0.5   │ 0.0         │ WG    │ (81.10000000000001, 0.0) │ optical   │
└──────┴───────┴─────────────┴───────┴──────────────────────────┴───────────┘

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.

Gdsfactory stores the settings and the ports as part of the GDS metadata

c = gf.import_gds(gdspath)
c.pprint_ports()
c.plot()
┏━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ name  width  orientation  layer  center                    port_type ┃
┡━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ o1   │ 0.5   │ 180.0       │ 0     │ (-10.0, 0.0)             │ optical   │
│ o2   │ 0.5   │ 0.0         │ 0     │ (81.10000000000001, 0.0) │ optical   │
└──────┴───────┴─────────────┴───────┴──────────────────────────┴───────────┘
../_images/77be629a40c99e860319282571c2a5d26d0f7b9192c4c1c978aca88733f1b17e.png
c3 = gf.routing.add_fiber_array(c)
c3.plot()
../_images/b22dd65c19b394af4f4ba87e6b59190b7c4ebde11bb343481005ea3fe354e099.png
gdspath = c3.write_gds("extra/pdk.gds")
gf.labels.write_labels(gdspath, layer_label=(201, 0))
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()
../_images/2cab9d852b619eb580d1da9e5cb3812ee46cd16efcf8ac64c531755a438e8b26.png
c_with_pins.ports = []  # lets rely on the pins to extract the ports
gdspath = c_with_pins.write_gds("extra/wg.gds")
c2 = gf.import_gds(gdspath)
c2.plot()
../_images/2cab9d852b619eb580d1da9e5cb3812ee46cd16efcf8ac64c531755a438e8b26.png
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, pin_layer="PORT")
c3.plot()
../_images/2cab9d852b619eb580d1da9e5cb3812ee46cd16efcf8ac64c531755a438e8b26.png
c3.pprint_ports()
┏━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ name  width  orientation  layer  center       port_type ┃
┡━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ o1   │ 0.5   │ 180.0       │ 3     │ (0.0, 0.0)  │ optical   │
│ o2   │ 0.5   │ 0.0         │ 4     │ (10.0, 0.0) │ optical   │
└──────┴───────┴─────────────┴───────┴─────────────┴───────────┘

Foundries provide PDKs in different formats and commercial tools.

The easiest way to import a PDK into gdsfactory is to:

  1. have each GDS cell into a separate GDS file

  2. have one GDS file with all the cells inside

  3. 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
../_images/f2f9cf32811de2fda4d70aafe1826d97b524a3688285c3afa91659d4e11fe644.png
# we write the sample PDK into a single GDS file
gf.write_cells.write_cells_recursively(gdspath="extra/pdk.gds", dirpath="extra/gds")
{'bend_euler_RNone_A90_P0_d7c3a5a9$1': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/bend_euler_RNone_A90_P0_d7c3a5a9$1.gds'),
 'mmi1x2_WNone_WT1_LT10_L_4e0f7121$1': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/mmi1x2_WNone_WT1_LT10_L_4e0f7121$1.gds'),
 'straight_L7_N2_CSstrip$1': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L7_N2_CSstrip$1.gds'),
 'straight_L0p1_N2_CSstrip$1': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L0p1_N2_CSstrip$1.gds'),
 'straight_L2_N2_CSstrip$1': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L2_N2_CSstrip$1.gds'),
 'grating_coupler_ellipti_07e69d9a': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/grating_coupler_ellipti_07e69d9a.gds'),
 'straight_L10_N2_CSstrip$2': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L10_N2_CSstrip$2.gds'),
 'straight_L10_N2_CSstrip$1': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L10_N2_CSstrip$1.gds'),
 'straight_L10_N2_CSstrip': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L10_N2_CSstrip.gds'),
 'straight_L321_N2_CSstrip_W0p5': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L321_N2_CSstrip_W0p5.gds'),
 'straight_L45p081_N2_CSstrip_W0p5': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L45p081_N2_CSstrip_W0p5.gds'),
 'straight_L6p9_N2_CSstrip_W0p5': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L6p9_N2_CSstrip_W0p5.gds'),
 'straight_L5p346_N2_CSstrip_W0p5': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L5p346_N2_CSstrip_W0p5.gds'),
 'straight_L7_N2_CSstrip_W0p5': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L7_N2_CSstrip_W0p5.gds'),
 'straight_L1_N2_CSstrip_W0p5': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L1_N2_CSstrip_W0p5.gds'),
 'straight_L0p5_N2_CSstrip_W0p5': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L0p5_N2_CSstrip_W0p5.gds'),
 'grating_coupler_ellipti_b694ac47': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/grating_coupler_ellipti_b694ac47.gds'),
 'mzi_DL10_LY2_LX0p1_Bben_7a5bab35': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/mzi_DL10_LY2_LX0p1_Bben_7a5bab35.gds'),
 'straight_L2_N2_CSstrip': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L2_N2_CSstrip.gds'),
 'straight_L0p1_N2_CSstrip': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L0p1_N2_CSstrip.gds'),
 'straight_L7_N2_CSstrip': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L7_N2_CSstrip.gds'),
 'mmi1x2_WNone_WT1_LT10_L_4e0f7121': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/mmi1x2_WNone_WT1_LT10_L_4e0f7121.gds'),
 'bend_euler_RNone_A90_P0_d7c3a5a9': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/bend_euler_RNone_A90_P0_d7c3a5a9.gds'),
 'Unnamed_29': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/Unnamed_29.gds'),
 'Unnamed_24': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/Unnamed_24.gds'),
 'Unnamed_15': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/Unnamed_15.gds'),
 'straight_L5p5_N2_CSxs_5228b3b0': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/straight_L5p5_N2_CSxs_5228b3b0.gds'),
 'taper_L10_W0p5_W1_PNone_aeadcc55': PosixPath('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds/taper_L10_W0p5_W1_PNone_aeadcc55.gds')}
print(gf.write_cells.get_import_gds_script("extra/gds"))
from pathlib import Path
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 = Path('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds')

import_gds = partial(gf.import_gds, post_process=add_ports)



@gf.cell
def Unnamed_15()->gf.Component:
    '''Returns Unnamed_15 fixed cell.'''
    return import_gds(gdsdir/'Unnamed_15.gds')




@gf.cell
def Unnamed_24()->gf.Component:
    '''Returns Unnamed_24 fixed cell.'''
    return import_gds(gdsdir/'Unnamed_24.gds')




@gf.cell
def Unnamed_29()->gf.Component:
    '''Returns Unnamed_29 fixed cell.'''
    return import_gds(gdsdir/'Unnamed_29.gds')




@gf.cell
def bend_euler_RNone_A90_P0_d7c3a5a9()->gf.Component:
    '''Returns bend_euler_RNone_A90_P0_d7c3a5a9 fixed cell.'''
    return import_gds(gdsdir/'bend_euler_RNone_A90_P0_d7c3a5a9.gds')




@gf.cell
def bend_euler_RNone_A90_P0_d7c3a5a91()->gf.Component:
    '''Returns bend_euler_RNone_A90_P0_d7c3a5a91 fixed cell.'''
    return import_gds(gdsdir/'bend_euler_RNone_A90_P0_d7c3a5a9$1.gds')




@gf.cell
def grating_coupler_ellipti_07e69d9a()->gf.Component:
    '''Returns grating_coupler_ellipti_07e69d9a fixed cell.'''
    return import_gds(gdsdir/'grating_coupler_ellipti_07e69d9a.gds')




@gf.cell
def grating_coupler_ellipti_b694ac47()->gf.Component:
    '''Returns grating_coupler_ellipti_b694ac47 fixed cell.'''
    return import_gds(gdsdir/'grating_coupler_ellipti_b694ac47.gds')




@gf.cell
def mmi1x2_WNone_WT1_LT10_L_4e0f7121()->gf.Component:
    '''Returns mmi1x2_WNone_WT1_LT10_L_4e0f7121 fixed cell.'''
    return import_gds(gdsdir/'mmi1x2_WNone_WT1_LT10_L_4e0f7121.gds')




@gf.cell
def mmi1x2_WNone_WT1_LT10_L_4e0f71211()->gf.Component:
    '''Returns mmi1x2_WNone_WT1_LT10_L_4e0f71211 fixed cell.'''
    return import_gds(gdsdir/'mmi1x2_WNone_WT1_LT10_L_4e0f7121$1.gds')




@gf.cell
def mzi_DL10_LY2_LX0p1_Bben_7a5bab35()->gf.Component:
    '''Returns mzi_DL10_LY2_LX0p1_Bben_7a5bab35 fixed cell.'''
    return import_gds(gdsdir/'mzi_DL10_LY2_LX0p1_Bben_7a5bab35.gds')




@gf.cell
def straight_L0p1_N2_CSstrip()->gf.Component:
    '''Returns straight_L0p1_N2_CSstrip fixed cell.'''
    return import_gds(gdsdir/'straight_L0p1_N2_CSstrip.gds')




@gf.cell
def straight_L0p1_N2_CSstrip1()->gf.Component:
    '''Returns straight_L0p1_N2_CSstrip1 fixed cell.'''
    return import_gds(gdsdir/'straight_L0p1_N2_CSstrip$1.gds')




@gf.cell
def straight_L0p5_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L0p5_N2_CSstrip_W0p5 fixed cell.'''
    return import_gds(gdsdir/'straight_L0p5_N2_CSstrip_W0p5.gds')




@gf.cell
def straight_L10_N2_CSstrip()->gf.Component:
    '''Returns straight_L10_N2_CSstrip fixed cell.'''
    return import_gds(gdsdir/'straight_L10_N2_CSstrip.gds')




@gf.cell
def straight_L10_N2_CSstrip1()->gf.Component:
    '''Returns straight_L10_N2_CSstrip1 fixed cell.'''
    return import_gds(gdsdir/'straight_L10_N2_CSstrip$1.gds')




@gf.cell
def straight_L10_N2_CSstrip2()->gf.Component:
    '''Returns straight_L10_N2_CSstrip2 fixed cell.'''
    return import_gds(gdsdir/'straight_L10_N2_CSstrip$2.gds')




@gf.cell
def straight_L1_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L1_N2_CSstrip_W0p5 fixed cell.'''
    return import_gds(gdsdir/'straight_L1_N2_CSstrip_W0p5.gds')




@gf.cell
def straight_L2_N2_CSstrip()->gf.Component:
    '''Returns straight_L2_N2_CSstrip fixed cell.'''
    return import_gds(gdsdir/'straight_L2_N2_CSstrip.gds')




@gf.cell
def straight_L2_N2_CSstrip1()->gf.Component:
    '''Returns straight_L2_N2_CSstrip1 fixed cell.'''
    return import_gds(gdsdir/'straight_L2_N2_CSstrip$1.gds')




@gf.cell
def straight_L321_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L321_N2_CSstrip_W0p5 fixed cell.'''
    return import_gds(gdsdir/'straight_L321_N2_CSstrip_W0p5.gds')




@gf.cell
def straight_L45p081_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L45p081_N2_CSstrip_W0p5 fixed cell.'''
    return import_gds(gdsdir/'straight_L45p081_N2_CSstrip_W0p5.gds')




@gf.cell
def straight_L5p346_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L5p346_N2_CSstrip_W0p5 fixed cell.'''
    return import_gds(gdsdir/'straight_L5p346_N2_CSstrip_W0p5.gds')




@gf.cell
def straight_L5p5_N2_CSxs_5228b3b0()->gf.Component:
    '''Returns straight_L5p5_N2_CSxs_5228b3b0 fixed cell.'''
    return import_gds(gdsdir/'straight_L5p5_N2_CSxs_5228b3b0.gds')




@gf.cell
def straight_L6p9_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L6p9_N2_CSstrip_W0p5 fixed cell.'''
    return import_gds(gdsdir/'straight_L6p9_N2_CSstrip_W0p5.gds')




@gf.cell
def straight_L7_N2_CSstrip()->gf.Component:
    '''Returns straight_L7_N2_CSstrip fixed cell.'''
    return import_gds(gdsdir/'straight_L7_N2_CSstrip.gds')




@gf.cell
def straight_L7_N2_CSstrip1()->gf.Component:
    '''Returns straight_L7_N2_CSstrip1 fixed cell.'''
    return import_gds(gdsdir/'straight_L7_N2_CSstrip$1.gds')




@gf.cell
def straight_L7_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L7_N2_CSstrip_W0p5 fixed cell.'''
    return import_gds(gdsdir/'straight_L7_N2_CSstrip_W0p5.gds')




@gf.cell
def taper_L10_W0p5_W1_PNone_aeadcc55()->gf.Component:
    '''Returns taper_L10_W0p5_W1_PNone_aeadcc55 fixed cell.'''
    return import_gds(gdsdir/'taper_L10_W0p5_W1_PNone_aeadcc55.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"))
from pathlib import Path
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 = Path('/home/runner/work/gdsfactory/gdsfactory/notebooks/extra/gds')

import_gds = partial(gf.import_gds, post_process=add_ports)



@gf.cell
def Unnamed_15()->gf.Component:
    '''Returns Unnamed_15 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.Unnamed_15()
      c.plot()
    '''
    return import_gds(gdsdir/'Unnamed_15.gds')




@gf.cell
def Unnamed_24()->gf.Component:
    '''Returns Unnamed_24 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.Unnamed_24()
      c.plot()
    '''
    return import_gds(gdsdir/'Unnamed_24.gds')




@gf.cell
def Unnamed_29()->gf.Component:
    '''Returns Unnamed_29 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.Unnamed_29()
      c.plot()
    '''
    return import_gds(gdsdir/'Unnamed_29.gds')




@gf.cell
def bend_euler_RNone_A90_P0_d7c3a5a9()->gf.Component:
    '''Returns bend_euler_RNone_A90_P0_d7c3a5a9 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.bend_euler_RNone_A90_P0_d7c3a5a9()
      c.plot()
    '''
    return import_gds(gdsdir/'bend_euler_RNone_A90_P0_d7c3a5a9.gds')




@gf.cell
def bend_euler_RNone_A90_P0_d7c3a5a91()->gf.Component:
    '''Returns bend_euler_RNone_A90_P0_d7c3a5a91 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.bend_euler_RNone_A90_P0_d7c3a5a91()
      c.plot()
    '''
    return import_gds(gdsdir/'bend_euler_RNone_A90_P0_d7c3a5a9$1.gds')




@gf.cell
def grating_coupler_ellipti_07e69d9a()->gf.Component:
    '''Returns grating_coupler_ellipti_07e69d9a fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.grating_coupler_ellipti_07e69d9a()
      c.plot()
    '''
    return import_gds(gdsdir/'grating_coupler_ellipti_07e69d9a.gds')




@gf.cell
def grating_coupler_ellipti_b694ac47()->gf.Component:
    '''Returns grating_coupler_ellipti_b694ac47 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.grating_coupler_ellipti_b694ac47()
      c.plot()
    '''
    return import_gds(gdsdir/'grating_coupler_ellipti_b694ac47.gds')




@gf.cell
def mmi1x2_WNone_WT1_LT10_L_4e0f7121()->gf.Component:
    '''Returns mmi1x2_WNone_WT1_LT10_L_4e0f7121 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.mmi1x2_WNone_WT1_LT10_L_4e0f7121()
      c.plot()
    '''
    return import_gds(gdsdir/'mmi1x2_WNone_WT1_LT10_L_4e0f7121.gds')




@gf.cell
def mmi1x2_WNone_WT1_LT10_L_4e0f71211()->gf.Component:
    '''Returns mmi1x2_WNone_WT1_LT10_L_4e0f71211 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.mmi1x2_WNone_WT1_LT10_L_4e0f71211()
      c.plot()
    '''
    return import_gds(gdsdir/'mmi1x2_WNone_WT1_LT10_L_4e0f7121$1.gds')




@gf.cell
def mzi_DL10_LY2_LX0p1_Bben_7a5bab35()->gf.Component:
    '''Returns mzi_DL10_LY2_LX0p1_Bben_7a5bab35 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.mzi_DL10_LY2_LX0p1_Bben_7a5bab35()
      c.plot()
    '''
    return import_gds(gdsdir/'mzi_DL10_LY2_LX0p1_Bben_7a5bab35.gds')




@gf.cell
def straight_L0p1_N2_CSstrip()->gf.Component:
    '''Returns straight_L0p1_N2_CSstrip fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L0p1_N2_CSstrip()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L0p1_N2_CSstrip.gds')




@gf.cell
def straight_L0p1_N2_CSstrip1()->gf.Component:
    '''Returns straight_L0p1_N2_CSstrip1 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L0p1_N2_CSstrip1()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L0p1_N2_CSstrip$1.gds')




@gf.cell
def straight_L0p5_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L0p5_N2_CSstrip_W0p5 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L0p5_N2_CSstrip_W0p5()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L0p5_N2_CSstrip_W0p5.gds')




@gf.cell
def straight_L10_N2_CSstrip()->gf.Component:
    '''Returns straight_L10_N2_CSstrip fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L10_N2_CSstrip()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L10_N2_CSstrip.gds')




@gf.cell
def straight_L10_N2_CSstrip1()->gf.Component:
    '''Returns straight_L10_N2_CSstrip1 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L10_N2_CSstrip1()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L10_N2_CSstrip$1.gds')




@gf.cell
def straight_L10_N2_CSstrip2()->gf.Component:
    '''Returns straight_L10_N2_CSstrip2 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L10_N2_CSstrip2()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L10_N2_CSstrip$2.gds')




@gf.cell
def straight_L1_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L1_N2_CSstrip_W0p5 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L1_N2_CSstrip_W0p5()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L1_N2_CSstrip_W0p5.gds')




@gf.cell
def straight_L2_N2_CSstrip()->gf.Component:
    '''Returns straight_L2_N2_CSstrip fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L2_N2_CSstrip()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L2_N2_CSstrip.gds')




@gf.cell
def straight_L2_N2_CSstrip1()->gf.Component:
    '''Returns straight_L2_N2_CSstrip1 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L2_N2_CSstrip1()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L2_N2_CSstrip$1.gds')




@gf.cell
def straight_L321_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L321_N2_CSstrip_W0p5 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L321_N2_CSstrip_W0p5()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L321_N2_CSstrip_W0p5.gds')




@gf.cell
def straight_L45p081_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L45p081_N2_CSstrip_W0p5 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L45p081_N2_CSstrip_W0p5()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L45p081_N2_CSstrip_W0p5.gds')




@gf.cell
def straight_L5p346_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L5p346_N2_CSstrip_W0p5 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L5p346_N2_CSstrip_W0p5()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L5p346_N2_CSstrip_W0p5.gds')




@gf.cell
def straight_L5p5_N2_CSxs_5228b3b0()->gf.Component:
    '''Returns straight_L5p5_N2_CSxs_5228b3b0 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L5p5_N2_CSxs_5228b3b0()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L5p5_N2_CSxs_5228b3b0.gds')




@gf.cell
def straight_L6p9_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L6p9_N2_CSstrip_W0p5 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L6p9_N2_CSstrip_W0p5()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L6p9_N2_CSstrip_W0p5.gds')




@gf.cell
def straight_L7_N2_CSstrip()->gf.Component:
    '''Returns straight_L7_N2_CSstrip fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L7_N2_CSstrip()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L7_N2_CSstrip.gds')




@gf.cell
def straight_L7_N2_CSstrip1()->gf.Component:
    '''Returns straight_L7_N2_CSstrip1 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L7_N2_CSstrip1()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L7_N2_CSstrip$1.gds')




@gf.cell
def straight_L7_N2_CSstrip_W0p5()->gf.Component:
    '''Returns straight_L7_N2_CSstrip_W0p5 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.straight_L7_N2_CSstrip_W0p5()
      c.plot()
    '''
    return import_gds(gdsdir/'straight_L7_N2_CSstrip_W0p5.gds')




@gf.cell
def taper_L10_W0p5_W1_PNone_aeadcc55()->gf.Component:
    '''Returns taper_L10_W0p5_W1_PNone_aeadcc55 fixed cell.

    .. plot::
      :include-source:

      import samplepdk

      c = samplepdk.components.taper_L10_W0p5_W1_PNone_aeadcc55()
      c.plot()
    '''
    return import_gds(gdsdir/'taper_L10_W0p5_W1_PNone_aeadcc55.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

PDK.activate()
yaml_pdk = PDK.to_updk()
print(yaml_pdk)
blocks:
  mzi_nc:
    bbox:
    - - -13.0
      - -31.125
    - - 84.10000000000001
      - -31.125
    - - 84.10000000000001
      - 26.125
    - - -13.0
      - 26.125
    doc: Canvas where you add polygons, instances and ports.
    parameters:
      add_optical_ports_arms:
        doc: null
        max: 0
        min: 0
        type: bool
        unit: null
        value: false
      auto_rename_ports:
        doc: null
        max: 0
        min: 0
        type: bool
        unit: null
        value: true
      bend:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: bend_euler_nc
      cross_section:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: strip_nc
      delta_length:
        doc: null
        max: 0
        min: 0
        type: float
        unit: null
        value: 10.0
      length_x:
        doc: null
        max: 0
        min: 0
        type: float
        unit: null
        value: 0.1
      length_y:
        doc: null
        max: 0
        min: 0
        type: float
        unit: null
        value: 2.0
      min_length:
        doc: null
        max: 0
        min: 0
        type: float
        unit: null
        value: 0.01
      mirror_bot:
        doc: null
        max: 0
        min: 0
        type: bool
        unit: null
        value: false
      nbends:
        doc: null
        max: 0
        min: 0
        type: int
        unit: null
        value: 2
      port_e0_combiner:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: o3
      port_e0_splitter:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: o3
      port_e1_combiner:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: o2
      port_e1_splitter:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: o2
      splitter:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: mmi1x2_nc
      straight:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: straight_nc
      with_splitter:
        doc: null
        max: 0
        min: 0
        type: bool
        unit: null
        value: true
    pins:
      o1:
        alias: null
        doc: null
        width: 1000
        xsection: ''
        xya:
        - -10.0
        - 0.0
        - 180.0
      o2:
        alias: null
        doc: null
        width: 1000
        xsection: ''
        xya:
        - 81.10000000000001
        - 0.0
        - 0.0
    settings:
      Properties:
        doc: ''
        max: 0
        min: 0
        type: float
        unit: null
        value: 0.0
      info:
        doc: dictionary that includes derived properties, simulation_settings, settings
        max: 0
        min: 0
        type: float
        unit: null
        value: 0.0
  mzi_no:
    bbox:
    - - -13.0
      - -31.075
    - - 84.10000000000001
      - -31.075
    - - 84.10000000000001
      - 26.075
    - - -13.0
      - 26.075
    doc: Canvas where you add polygons, instances and ports.
    parameters:
      add_optical_ports_arms:
        doc: null
        max: 0
        min: 0
        type: bool
        unit: null
        value: false
      auto_rename_ports:
        doc: null
        max: 0
        min: 0
        type: bool
        unit: null
        value: true
      bend:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: bend_euler_no
      cross_section:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: strip_no
      delta_length:
        doc: null
        max: 0
        min: 0
        type: float
        unit: null
        value: 10.0
      length_x:
        doc: null
        max: 0
        min: 0
        type: float
        unit: null
        value: 0.1
      length_y:
        doc: null
        max: 0
        min: 0
        type: float
        unit: null
        value: 2.0
      min_length:
        doc: null
        max: 0
        min: 0
        type: float
        unit: null
        value: 0.01
      mirror_bot:
        doc: null
        max: 0
        min: 0
        type: bool
        unit: null
        value: false
      nbends:
        doc: null
        max: 0
        min: 0
        type: int
        unit: null
        value: 2
      port_e0_combiner:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: o3
      port_e0_splitter:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: o3
      port_e1_combiner:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: o2
      port_e1_splitter:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: o2
      splitter:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: mmi1x2_no
      straight:
        doc: null
        max: 0
        min: 0
        type: str
        unit: null
        value: straight_no
      with_splitter:
        doc: null
        max: 0
        min: 0
        type: bool
        unit: null
        value: true
    pins:
      o1:
        alias: null
        doc: null
        width: 900
        xsection: ''
        xya:
        - -10.0
        - 0.0
        - 180.0
      o2:
        alias: null
        doc: null
        width: 900
        xsection: ''
        xya:
        - 81.10000000000001
        - 0.0
        - 0.0
    settings:
      Properties:
        doc: ''
        max: 0
        min: 0
        type: float
        unit: null
        value: 0.0
      info:
        doc: dictionary that includes derived properties, simulation_settings, settings
        max: 0
        min: 0
        type: float
        unit: null
        value: 0.0
header:
  description: fab_c_demopdk
xsections:
  strip_nc:
    width: 1.0
  strip_no:
    width: 0.9
  strip_sc:
    width: 0.5
  strip_so:
    width: 0.4
from gdsfactory.read.from_updk import from_updk
from gdsfactory.component import GDSDIR_TEMP

yamlpath = GDSDIR_TEMP / "pdk.yml"
yamlpath.write_text(yaml_pdk)
gdsfactory_script = from_updk(yamlpath)
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 = gf.cell
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_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)

cross_sections = dict(strip_nc=strip_nc,strip_no=strip_no,strip_sc=strip_sc,strip_so=strip_so)

@cell
def mzi_nc(add_optical_ports_arms:bool=False, auto_rename_ports:bool=True, bend:str=bend_euler_nc, cross_section:str=strip_nc, delta_length:float=10.0, length_x:float=0.1, length_y:float=2.0, min_length:float=0.01, mirror_bot:bool=False, nbends:int=2, port_e0_combiner:str=o3, port_e0_splitter:str=o3, port_e1_combiner:str=o2, port_e1_splitter:str=o2, splitter:str=mmi1x2_nc, straight:str=straight_nc, with_splitter:bool=True)->gf.Component:
    """Canvas where you add polygons, instances and ports.

    Args:
    
    """
    c = gf.Component()
    c.add_polygon(((-13.0, -31.125), (84.10000000000001, -31.125), (84.10000000000001, 26.125), (-13.0, 26.125)), layer=layer_bbox)
    xc = c.dx
    yc = c.dy
    name = f'mzi_nc:add_optical_ports_arms={add_optical_ports_arms},auto_rename_ports={auto_rename_ports},bend={bend},cross_section={cross_section},delta_length={delta_length},length_x={length_x},length_y={length_y},min_length={min_length},mirror_bot={mirror_bot},nbends={nbends},port_e0_combiner={port_e0_combiner},port_e0_splitter={port_e0_splitter},port_e1_combiner={port_e1_combiner},port_e1_splitter={port_e1_splitter},splitter={splitter},straight={straight},with_splitter={with_splitter}'
    c.add_label(text=f'Parameters:\nadd_optical_ports_arms={add_optical_ports_arms}\nauto_rename_ports={auto_rename_ports}\nbend={bend}\ncross_section={cross_section}\ndelta_length={delta_length}\nlength_x={length_x}\nlength_y={length_y}\nmin_length={min_length}\nmirror_bot={mirror_bot}\nnbends={nbends}\nport_e0_combiner={port_e0_combiner}\nport_e0_splitter={port_e0_splitter}\nport_e1_combiner={port_e1_combiner}\nport_e1_splitter={port_e1_splitter}\nsplitter={splitter}\nstraight={straight}\nwith_splitter={with_splitter}', position=(0,0), layer=layer_label)
    c.add_port(name='o1', cross_section='', center=(-10.0, 0.0), orientation=180.0, port_type='optical')
    c.ports['o1'].info['cross_section'] = ''
    c.add_port(name='o2', cross_section='', center=(81.10000000000001, 0.0), orientation=0.0, port_type='optical')
    c.ports['o2'].info['cross_section'] = ''

    c.name = name
    if layer_pin:
        add_pins(c, layer=layer_pin)
    return c

@cell
def mzi_no(add_optical_ports_arms:bool=False, auto_rename_ports:bool=True, bend:str=bend_euler_no, cross_section:str=strip_no, delta_length:float=10.0, length_x:float=0.1, length_y:float=2.0, min_length:float=0.01, mirror_bot:bool=False, nbends:int=2, port_e0_combiner:str=o3, port_e0_splitter:str=o3, port_e1_combiner:str=o2, port_e1_splitter:str=o2, splitter:str=mmi1x2_no, straight:str=straight_no, with_splitter:bool=True)->gf.Component:
    """Canvas where you add polygons, instances and ports.

    Args:
    
    """
    c = gf.Component()
    c.add_polygon(((-13.0, -31.075), (84.10000000000001, -31.075), (84.10000000000001, 26.075), (-13.0, 26.075)), layer=layer_bbox)
    xc = c.dx
    yc = c.dy
    name = f'mzi_no:add_optical_ports_arms={add_optical_ports_arms},auto_rename_ports={auto_rename_ports},bend={bend},cross_section={cross_section},delta_length={delta_length},length_x={length_x},length_y={length_y},min_length={min_length},mirror_bot={mirror_bot},nbends={nbends},port_e0_combiner={port_e0_combiner},port_e0_splitter={port_e0_splitter},port_e1_combiner={port_e1_combiner},port_e1_splitter={port_e1_splitter},splitter={splitter},straight={straight},with_splitter={with_splitter}'
    c.add_label(text=f'Parameters:\nadd_optical_ports_arms={add_optical_ports_arms}\nauto_rename_ports={auto_rename_ports}\nbend={bend}\ncross_section={cross_section}\ndelta_length={delta_length}\nlength_x={length_x}\nlength_y={length_y}\nmin_length={min_length}\nmirror_bot={mirror_bot}\nnbends={nbends}\nport_e0_combiner={port_e0_combiner}\nport_e0_splitter={port_e0_splitter}\nport_e1_combiner={port_e1_combiner}\nport_e1_splitter={port_e1_splitter}\nsplitter={splitter}\nstraight={straight}\nwith_splitter={with_splitter}', position=(0,0), layer=layer_label)
    c.add_port(name='o1', cross_section='', center=(-10.0, 0.0), orientation=180.0, port_type='optical')
    c.ports['o1'].info['cross_section'] = ''
    c.add_port(name='o2', cross_section='', center=(81.10000000000001, 0.0), orientation=0.0, port_type='optical')
    c.ports['o2'].info['cross_section'] = ''

    c.name = name
    if layer_pin:
        add_pins(c, layer=layer_pin)
    return c



if __name__ == "__main__":
    c = mzi_no()
    c.show()

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 gdsfactory.technology import LayerMap


class LayerMap(LayerMap):
    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