Cell

Problem:

  1. In GDS each cell must have a unique name.

  2. In GDS two cells stored in the GDS file cannot have the same name.

Solution: The decorator @gf.cell fixes both issues:

  1. By giving the cell a unique name depending on the parameters that you pass

  2. By creating a cache of cells where we use the cell name as the key. This to create two cells with the same name in the same python script.

Lets see how it works

[1]:
import gdsfactory as gf


@gf.cell
def wg(length=10, width=1):
    c = gf.Component()
    c.add_polygon([(0, 0), (length, 0), (length, width), (0, width)], layer=(1, 0))
    c.add_port(name="o1", midpoint=[0, width / 2], width=width, orientation=180)
    c.add_port(name="o2", midpoint=[length, width / 2], width=width, orientation=0)
    return c
2021-09-25 16:18:54.110 | INFO     | gdsfactory.config:<module>:51 - 3.2.9

See how the cells get the name from the parameters that you pass them

[2]:
c = wg()
print(c)

c = wg(width=0.5)
print(c)
wg: uid 1, ports ['o1', 'o2'], aliases [], 1 polygons, 0 references
wg_width500n: uid 2, ports ['o1', 'o2'], aliases [], 1 polygons, 0 references

How can you have add two different references to a cell with the same parameters?

[3]:
import gdsfactory as gf

c = gf.Component("problem")
R1 = gf.components.rectangle(
    size=(4, 2), layer=(0, 0)
)  # Creates a rectangle (same Unique ID uid)
R2 = gf.components.rectangle(size=(4, 2), layer=(0, 0))
# Try Create a new rectangle that we want to change (but has the same name so we will get R1 from the cache)

r1r = c << R1  # Add the first rectangle to c
r2r = c << R2  # Add the second rectangle to c
r2r.move((4, 2))
c
../_images/notebooks_03_cells_autoname_and_cache_5_0.png
[3]:
problem: uid 3, ports [], aliases [], 0 polygons, 2 references
[4]:
print(R1 == R2)
print(R1)
print(R2)
True
rectangle_layer0_0_size4_2: uid 4, ports [], aliases [], 1 polygons, 0 references
rectangle_layer0_0_size4_2: uid 4, ports [], aliases [], 1 polygons, 0 references
[5]:
# lets do it cleaner with references
import gdsfactory as gf

c = gf.Component("solution")
R = gf.components.rectangle(size=(4, 2), layer=(0, 0))

r1 = c << R  # Add the first rectangle reference to c
r2 = c << R  # Add the second rectangle reference to c

r2.rotate(45)
c
../_images/notebooks_03_cells_autoname_and_cache_7_0.png
[5]:
solution: uid 5, ports [], aliases [], 0 polygons, 2 references

Adding port markers

When you use component.show(show_ports=True) it automatically adds pins markers to all ports

[6]:
import gdsfactory as gf

c = gf.components.straight()
c.show(show_ports=True)
c.plot()
../_images/notebooks_03_cells_autoname_and_cache_9_0.png

We can even show ports of all references with component.show(show_subports=True)

[7]:
c = gf.components.mzi_phase_shifter(length_x=50)
c
../_images/notebooks_03_cells_autoname_and_cache_11_0.png
[7]:
mzi_length_x50_straight_f3cda77b: uid 9, ports ['o1', 'o2', 'e1', 'e2'], aliases [], 0 polygons, 4 references

Cache

To avoid that 2 exact cells are not references of the same cell the cell decorator has a cache where if component has already been build it will return the component from the cache

[8]:
@gf.cell
def wg(length=10, width=1):
    c = gf.Component()
    c.add_polygon([(0, 0), (length, 0), (length, width), (0, width)], layer=(1, 0))
    print("calling wg function")
    return c
[9]:
wg1 = wg()  # cell builds a straight
print(wg1)
calling wg function
wg: uid 33, ports [], aliases [], 1 polygons, 0 references
[10]:
wg2 = (
    wg()
)  # cell returns the same straight as before without having to run the function
print(wg2)  # notice that they have the same uuid (unique identifier)
wg: uid 33, ports [], aliases [], 1 polygons, 0 references
[11]:
wg2.plot()
../_images/notebooks_03_cells_autoname_and_cache_16_0.png
[12]:
from gdsfactory.cell import print_cache

Lets say that you change the code of the straight function in a jupyter notebook like this one. (I mostly use Vim/VsCode/Pycharm for creating new cells in python)

[13]:
print_cache()  # Cache gets clear with each show or plot just to be safe
[14]:
wg3 = wg()
wg4 = wg(length=11)
calling wg function
calling wg function
[15]:
print_cache()
wg
wg_length11
[16]:
wg3.plot()
../_images/notebooks_03_cells_autoname_and_cache_22_0.png

To enable nice notebook tutorials, every time we show a cell in Matplotlib or Klayout, we clear the cache, in case you want to develop cells in jupyter notebooks or an IPython kernel

[17]:
print_cache()  # cache is now empty

Validate argument types

To make sure you pass the correct arguments to the cell it runs a validator that checks the type annotations for the function.

For example this will be correct

import gdsfactory as gf

@gf.cell
def straigth_waveguide(length:float):
    return gf.components.straigth(length=length)


component = straigth_waveguide(length=3)

While this will raise an error

import gdsfactory as gf

@gf.cell
def straigth_waveguide(length:float):
    return gf.components.straigth(length=length)


component = straigth_waveguide(length='long')

by default @cell validates all arguments using pydantic

[ ]: