Technology

gdsfactory inclues all the defaults for the generic Technology in TECH dataclass that you can customize.

Layers

A GDS has different layers to describe the different fabrication process steps.

GDS layers have 2 integer numbers: GDSlayer, GDSpurpose

Klayout shows Layers with a color, style and transparency when showing GDS layouts.

[1]:
import gdsfactory as gf
2021-09-25 16:18:58.619 | INFO     | gdsfactory.config:<module>:51 - 3.2.9
[2]:
c = gf.layers.LAYER_SET.preview()
c
../_images/notebooks_03_layers_2_0.png
[2]:
layerset: uid 1, ports [], aliases [], 0 polygons, 164 references
[3]:
layer_wg = gf.LAYER.WG
print(layer_wg)
(1, 0)

Remove layers

You can remove layers using the remove_layers() function.

[4]:
c.remove_layers(layers=(gf.LAYER.WG, gf.LAYER.WGN))
../_images/notebooks_03_layers_5_0.png
[4]:
layerset: uid 1, ports [], aliases [], 0 polygons, 164 references

Remap layers

You can remap layers using the remap_layer to remap some layers

[5]:
c.remap_layers(layermap={(2, 0): gf.LAYER.WGN})
../_images/notebooks_03_layers_7_0.png
[5]:
layerset: uid 1, ports [], aliases [], 0 polygons, 164 references

Extract layers

You can also extract layers using the extract function. This function returns a flattened component that contains the extracted layers.

[6]:
c.extract(layers=(gf.LAYER.WGN,))
../_images/notebooks_03_layers_9_0.png
[6]:
layerset_34_0: uid 328, ports [], aliases [], 13 polygons, 0 references

Custom cross_section

You can create a CrossSection from scratch or you can customize the cross_section functions in gf.cross_section

[7]:
import gdsfactory as gf

strip2 = gf.partial(gf.cross_section.strip, layer=(2, 0))
[8]:
gf.components.straight(cross_section=strip2)
../_images/notebooks_03_layers_12_0.png
[8]:
straight_cross_sectionc_560111aa: uid 329, ports ['o1', 'o2'], aliases [], 1 polygons, 0 references
[9]:
import gdsfactory as gf

pin = gf.partial(
    gf.cross_section.strip,
    sections=(
        gf.tech.Section(width=2, layer=gf.LAYER.N, offset=+1),
        gf.tech.Section(width=2, layer=gf.LAYER.P, offset=-1),
    ),
)
c = gf.components.straight(cross_section=pin)
c
../_images/notebooks_03_layers_13_0.png
[9]:
straight_cross_sectionc_f017ca82: uid 330, ports ['o1', 'o2'], aliases [], 3 polygons, 0 references

How can you group all components to test them?

You can create a dict of functions and group them

factory = dict(
    straight_heater_metal = gf.components.straight_heater_metal,
    bend = gf.components.bend_euler
)
[10]:
import gdsfactory as gf

c = gf.components.straight(layer=(31, 0))
c
../_images/notebooks_03_layers_15_0.png
[10]:
straight_layer31_0: uid 331, ports ['o1', 'o2'], aliases [], 1 polygons, 0 references
[11]:
cross_section = gf.cross_section.nitride
wg = gf.components.straight(cross_section=cross_section)
gc = gf.components.grating_coupler_elliptical_te(layer=(34, 0), wg_width=1.0)
wg_gc = gf.routing.add_fiber_single(
    component=wg, grating_coupler=gc, cross_section=gf.cross_section.nitride
)
wg_gc
../_images/notebooks_03_layers_16_0.png
[11]:
add_fiber_single_compon_e55d29c8: uid 335, ports ['vertical_te_00', 'vertical_te_1'], aliases [], 0 polygons, 8 references

FabA

Lets create some component factories for FabA

FabA only has one Metal layer available that is defined in GDS layer (30, 0)

The metal layer traces are 2um wide

[12]:
import gdsfactory as gf
from gdsfactory.cross_section import strip
from gdsfactory.tech import Layer


WIDTH = 2
LAYER = (30, 0)

fab_a_metal = gf.partial(strip, width=WIDTH, layer=LAYER)
fab_a_metal.__name__ = "fab_a_metal"


straight = gf.partial(gf.components.straight, cross_section=fab_a_metal)
bend_euler = gf.partial(gf.components.bend_euler, cross_section=fab_a_metal)
mmi1x2 = gf.partial(
    gf.components.mmi1x2,
    cross_section=fab_a_metal,
    width=WIDTH,
    width_taper=WIDTH,
    width_mmi=3 * WIDTH,
)
mzi = gf.partial(gf.components.mzi, cross_section=fab_a_metal, splitter=mmi1x2)
gc = gf.partial(
    gf.components.grating_coupler_elliptical_te, layer=LAYER, wg_width=WIDTH
)


def test_waveguide():
    c = gf.components.straight(cross_section=fab_a_metal)
    difftest(c)


c = mzi()
c_gc = gf.routing.add_fiber_array(
    component=c, grating_coupler=gc, cross_section=fab_a_metal
)
c_gc
../_images/notebooks_03_layers_18_0.png
[12]:
add_fiber_array_compone_ca1511ee: uid 358, ports ['vertical_te_00', 'vertical_te_01'], aliases [], 0 polygons, 22 references

you can also add a cell decorator in case you want to add pins or device recognition layers

[13]:
import gdsfactory as gf
from gdsfactory.add_pins import add_outline, add_pins
from gdsfactory.cross_section import strip
from gdsfactory.difftest import difftest
from gdsfactory.tech import Library

WIDTH = 2
LAYER = (30, 0)

fab_a_metal = gf.partial(strip, width=WIDTH, layer=LAYER)


def test_waveguide():
    c = gf.components.straight(cross_section=fab_a_metal)
    difftest(c)


def decorator(component) -> None:
    """Fab specific functions over a component."""
    add_pins(component)
    add_outline(component)


mmi2x2 = gf.partial(gf.components.mmi2x2, decorator=decorator)
mmi1x2 = gf.partial(gf.components.mmi1x2, decorator=decorator)
bend_euler = gf.partial(gf.components.bend_euler, decorator=decorator)
straight = gf.partial(gf.components.straight, decorator=decorator)
mzi = gf.partial(gf.components.mzi, splitter=mmi1x2, bend=bend_euler, straight=straight)

LIBRARY = Library(name="fab_a")
LIBRARY.register([mmi2x2, mmi1x2, mzi])

mzi()
../_images/notebooks_03_layers_20_0.png
[13]:
mzi_bendbend_eulerdecor_f4d4f755: uid 367, ports ['o1', 'o2'], aliases [], 0 polygons, 4 references

FabB

FabB has photonic waveguides that require many cladding layers to avoid dopants

Lets say that the waveguides are defined in layer (2, 0) and are 0.3um wide

[14]:
import gdsfactory as gf
from gdsfactory.cross_section import strip
from gdsfactory.difftest import difftest

WIDTH = 0.3
LAYER = (2, 0)
LAYERS_CLADDING = ((71, 0), (68, 0))


fab_b_metal = gf.partial(
    strip,
    width=WIDTH,
    layer=LAYER,
    layers_cladding=LAYERS_CLADDING,
)
fab_b_metal.__name__ = "fab_b_metal"


straight = gf.partial(gf.components.straight, cross_section=fab_b_metal)
bend_euler = gf.partial(gf.components.bend_euler, cross_section=fab_b_metal)
mmi1x2 = gf.partial(
    gf.components.mmi1x2,
    cross_section=fab_b_metal,
    width=WIDTH,
    width_taper=WIDTH,
    width_mmi=4 * WIDTH,
)
mzi = gf.partial(gf.components.mzi, cross_section=fab_b_metal, splitter=mmi1x2)
gc = gf.partial(
    gf.components.grating_coupler_elliptical_te, layer=LAYER, wg_width=WIDTH
)


def test_waveguide():
    c = gf.components.straight(cross_section=fab_b_metal)
    difftest(c)


c = mzi()
wg_gc = gf.routing.add_fiber_array(
    component=c, grating_coupler=gc, cross_section=fab_b_metal
)
wg_gc
../_images/notebooks_03_layers_22_0.png
[14]:
add_fiber_array_compone_fc77bb57: uid 389, ports ['vertical_te_00', 'vertical_te_01'], aliases [], 0 polygons, 22 references

FabC

Lets assume that fab C has both Silicon and Silicon Nitride components, and you need different waveguide widths for C and O band.

Lets asume that O band nitride waveguide width is 0.9 and Cband Nitride waveguide width is 1um, and for 0.4um for Silicon O band and 0.5um for silicon Cband.

Lets also that this foundry has an LVS flow where all components have optical pins defined in layer (100, 0)

[15]:
from typing import Callable, Dict, Optional, Tuple
import pydantic.dataclasses as dataclasses

import gdsfactory as gf
from gdsfactory.add_pins import add_pin_square_inside
from gdsfactory.component import Component, ComponentReference
from gdsfactory.cross_section import strip
from gdsfactory.tech import LayerLevel, LayerStack, Library, Tech
from gdsfactory.types import Layer


@dataclasses.dataclass(frozen=True)
class LayerMap:
    WG: Layer = (10, 1)
    WG_CLAD: Layer = (10, 2)
    WGN: Layer = (34, 0)
    WGN_CLAD: Layer = (36, 0)
    PIN: Layer = (100, 0)


LAYER = LayerMap()
WIDTH_NITRIDE_OBAND = 0.9
WIDTH_NITRIDE_CBAND = 1.0
PORT_TYPE_TO_LAYER = dict(optical=(100, 0))


def get_layer_stack_fab_c(thickness: float = 350.0) -> LayerStack:
    """Returns generic LayerStack"""
    return LayerStack(
            core=LayerLevel(
                layer=(34, 0),
                thickness=350.0,
                zmin=220.0 + 100.0,
            ),
            clad=LayerLevel(layer=(36, 0)),
    )


def add_pins(
    component: Component,
    function: Callable = add_pin_square_inside,
    pin_length: float = 0.5,
    port_layer: Layer = LAYER.PIN,
    **kwargs,
) -> None:
    """Add Pin port markers.

    Args:
        component: to add ports
        function:
        pin_length:
        port_layer:
        function: kwargs

    """
    for p in component.ports.values():
        function(
            component=component,
            port=p,
            layer=port_layer,
            label_layer=port_layer,
            pin_length=pin_length,
            **kwargs,
        )


# cross_sections

fabc_nitride_cband = gf.partial(
    strip, width=WIDTH_NITRIDE_CBAND, layer=LAYER.WGN, layers_cladding=(LAYER.WGN_CLAD,)
)
fabc_nitride_oband = gf.partial(
    strip, width=WIDTH_NITRIDE_OBAND, layer=LAYER.WGN, layers_cladding=(LAYER.WGN_CLAD,)
)


# LEAF COMPONENTS have pins

mmi1x2_nitride_c = gf.partial(
    gf.components.mmi1x2,
    width=WIDTH_NITRIDE_CBAND,
    cross_section=fabc_nitride_cband,
    decorator=add_pins,
)
mmi1x2_nitride_o = gf.partial(
    gf.components.mmi1x2,
    width=WIDTH_NITRIDE_OBAND,
    cross_section=fabc_nitride_oband,
    decorator=add_pins,
)
bend_euler_c = gf.partial(
    gf.components.bend_euler, cross_section=fabc_nitride_cband, decorator=add_pins
)
straight_c = gf.partial(
    gf.components.straight, cross_section=fabc_nitride_cband, decorator=add_pins
)
bend_euler_o = gf.partial(
    gf.components.bend_euler, cross_section=fabc_nitride_oband, decorator=add_pins
)
straight_o = gf.partial(
    gf.components.straight, cross_section=fabc_nitride_oband, decorator=add_pins
)

gc_nitride_c = gf.partial(
    gf.components.grating_coupler_elliptical_te,
    grating_line_width=0.6,
    wg_width=WIDTH_NITRIDE_CBAND,
    layer=LAYER.WGN,
    decorator=add_pins,
)

# HIERARCHICAL COMPONENTS made of leaf components

mzi_nitride_c = gf.partial(
    gf.components.mzi,
    cross_section=fabc_nitride_cband,
    splitter=mmi1x2_nitride_c,
    decorator=add_pins,
    straight=straight_c,
    bend=bend_euler_c,
)
mzi_nitride_o = gf.partial(
    gf.components.mzi,
    cross_section=fabc_nitride_oband,
    splitter=mmi1x2_nitride_c,
    decorator=add_pins,
    straight=straight_o,
    bend=bend_euler_o,
)


TECH_FABC = Tech(name="fab_c")

# for testing
LIBRARY = Library(name="fab_c")
LIBRARY.register(
    [
        mmi1x2_nitride_c,
        mmi1x2_nitride_o,
        bend_euler_c,
        straight_c,
        mzi_nitride_c,
        mzi_nitride_o,
        gc_nitride_c,
    ]
)
[16]:
mzi = mzi_nitride_c()
mzi_gc = gf.routing.add_fiber_single(
    component=mzi,
    grating_coupler=gc_nitride_c,
    cross_section=fabc_nitride_cband,
    optical_routing_type=1,
    straight_factory=straight_c,
    bend_factory=bend_euler_c,
)
mzi_gc
../_images/notebooks_03_layers_25_0.png
[16]:
add_fiber_single_bend_f_f0ed7d8c: uid 410, ports ['vertical_te_00', 'vertical_te_1'], aliases [], 0 polygons, 8 references
[17]:
ls = get_layer_stack_fab_c()
[18]:
ls.to_dict()
[18]:
{'core': {'layer': (34, 0),
  'thickness': 350.0,
  'zmin': 320.0,
  'material': None,
  'sidewall_angle': 0.0},
 'clad': {'layer': (36, 0),
  'thickness': None,
  'zmin': None,
  'material': None,
  'sidewall_angle': 0.0}}

3D rendering

You can also render your components into 3D.

You will need to define two things:

  1. LayerStack: for each layer contains thickness of each material and z position

  2. LayerSet: for each layer contains colors (this file is the same that Klayout uses). You can load it with gf.layers.load_lyp()

[19]:
heater  = gf.c.straight_heater_metal(length=50)
heater
../_images/notebooks_03_layers_29_0.png
[19]:
straight_heater_metal_u_da42eed6: uid 423, ports ['o1', 'o2', 'e1', 'e2'], aliases [], 0 polygons, 3 references
[20]:
scene = gf.to_3d(component=heater, layer_set=gf.layers.LAYER_SET)
scene.show()
[20]:
[ ]: