Die assembly#

With gdsfactory you can easily go from a simple Component, to a Component with many components inside.

In the same way that you need to Layout for DRC (Design Rule Check) clean devices, you have to layout obeying the Design for Test (DFT) and Design for Packaging rules.

Design for test#

To measure your chips after fabrication you need to decide your test configurations. This includes Design For Testing Rules like:

  • Individual input and output fibers versus fiber array. You can use add_fiber_array for easier testing and higher throughput, or add_fiber_single for the flexibility of single fibers.

  • Fiber array pitch (127um or 250um) if using a fiber array.

  • Pad pitch for DC and RF high speed probes (100, 125, 150, 200um). Probe configuration (GSG, GS …)

  • Test layout for DC, RF and optical fibers.

from functools import partial

import json
import gdsfactory as gf
from gdsfactory.generic_tech import get_generic_pdk
from gdsfactory.labels import add_label_ehva, add_label_json

Pack#

Lets start with a resistance sweep, where you change the resistance width to measure sheet resistance.

sweep = [gf.components.resistance_sheet(width=width) for width in [1, 10, 100]]
m = gf.pack(sweep)
c = m[0]
c.plot()
2024-04-19 00:22:48.055 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/pack_0.lyp'.
../_images/c0293cfe225376a6e1af026ac28e14b124f816a4abfb35f5ed68b271c0246053.png

Then we add spirals with different lengths to measure waveguide propagation loss. You can use both fiber array or single fiber.

from toolz import compose
from functools import partial
import gdsfactory as gf

gf.config.rich_output()

c = gf.components.spiral_inner_io_fiber_array(length=20e3)
c.info["measurement"] = "optical_loopback2"
c = gf.labels.add_label_json(c)
c.plot()
2024-04-19 00:22:48.594 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/spiral_inner_io_fiber_array_add_label_yaml_aecfddfd.lyp'.

../_images/3fab41363e574dbb8fbd44eb05452445b77dc529cd7b877e276bbeb9fd0beace.png
c.info

Info(length=20000.009, polarization='te', wavelength=1.53, measurement='optical_loopback2')
spiral = gf.components.spiral_inner_io_fiber_single()
spiral.plot()
2024-04-19 00:22:48.899 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/spiral_inner_io_fiber_single.lyp'.

../_images/4e8dd00fcec9b9af8a0ddab3dd27787585d4b55821f81b4af691a7241a6d6739.png
spiral_te = gf.routing.add_fiber_single(
    gf.functions.rotate(gf.components.spiral_inner_io_fiber_single, 90)
)
spiral_te.plot()
2024-04-19 00:22:49.152 | WARNING  | gdsfactory.component:_write_library:1933 - UserWarning: Component rotate_add_fiber_single_6f8349ab has invalid transformations. Try component.flatten_offgrid_references() first.
2024-04-19 00:22:49.175 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/rotate_add_fiber_single_6f8349ab.lyp'.

../_images/86bd82510e117c17f68f2ee52d37b9db0140c1a6c9962a103f1859c918e4a413.png
# which is equivalent to
spiral_te = gf.compose(
    gf.routing.add_fiber_single,
    gf.functions.rotate90,
    gf.components.spiral_inner_io_fiber_single,
)
c = spiral_te(length=10e3)
c.plot()
2024-04-19 00:22:49.623 | WARNING  | gdsfactory.component:_write_library:1933 - UserWarning: Component rotate_add_fiber_single_6774eb77 has invalid transformations. Try component.flatten_offgrid_references() first.
2024-04-19 00:22:49.639 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/rotate_add_fiber_single_6774eb77.lyp'.

../_images/745815b5304ea27ff6926a66d56fc4984674a21433133cb9a4034e5c2df24365.png
add_fiber_single_no_labels = partial(
    gf.routing.add_fiber_single,
    get_input_label_text_function=None,
)

spiral_te = gf.compose(
    add_fiber_single_no_labels,
    gf.functions.rotate90,
    gf.components.spiral_inner_io_fiber_single,
)
sweep = [spiral_te(length=length) for length in [10e3, 20e3, 30e3]]
m = gf.pack(sweep)
c = m[0]
c.plot()
2024-04-19 00:22:50.028 | WARNING  | gdsfactory.component:_write_library:1933 - UserWarning: Component pack_0$1 has invalid transformations. Try component.flatten_offgrid_references() first.
2024-04-19 00:22:50.043 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/pack_0$1.lyp'.

../_images/be6f9459e9cf7da2360e930314c104790551f4229be4f057f2fd8c4fc58e06b7.png
from toolz import compose
from functools import partial
import gdsfactory as gf

c = gf.components.spiral_inner_io_fiber_array(length=20e3)
c.info["measurement"] = "optical_loopback2"
c = gf.labels.add_label_json(c)
c.show()
c.plot()
2024-04-19 00:22:50.217 | WARNING  | gdsfactory.klive:show:49 - UserWarning: Could not connect to klive server. Is klayout open and klive plugin installed?
2024-04-19 00:22:50.241 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/spiral_inner_io_fiber_array_add_label_yaml_aecfddfd.lyp'.

../_images/3fab41363e574dbb8fbd44eb05452445b77dc529cd7b877e276bbeb9fd0beace.png
def add_label_json(component):
    """Add label json and component.info)"""
    component.info["measurement"] = "optical_loopback2"
    component = gf.labels.add_label_json(component)
    return component
sweep = [
    add_label_json(gf.components.spiral_inner_io_fiber_array(length=length))
    for length in [20e3, 30e3, 40e3]
]
m = gf.pack(sweep)
c = m[0]
c.show()
c.plot()
2024-04-19 00:22:50.618 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/pack_0$2.lyp'.

../_images/f6fdfa19764854095153a2ee3f0ad04c6b832914cce6a5624413307cf1bf1e52.png

You can also add some physical labels that will be fabricated. For example you can add prefix S at the north-center of each spiral using text_rectangular which is DRC clean and anchored on nc (north-center)

text_metal = partial(gf.components.text_rectangular_multi_layer, layers=("M1",))

m = gf.pack(sweep, text=text_metal, text_anchors=("cw",), text_prefix="s")
c = m[0]
c.show()
c.plot()
2024-04-19 00:22:50.802 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/pack_0$3.lyp'.

../_images/3280f6b5375276442b45c81e7a8ca4f28be0cafb3a0dc0b6bba33d3c7b549526.png

Grid#

You can also pack components with a constant spacing.

g = gf.grid_with_component_name(sweep)
g.plot()
2024-04-19 00:22:51.016 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/grid_488b5359.lyp'.

../_images/887aaef69ec715d12e406eee8bf146378198b74bfa8bc25505f0ee24acf0bd2f.png
gh = gf.grid_with_component_name(sweep, shape=(1, len(sweep)))
gh.plot()
2024-04-19 00:22:51.322 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/grid_c1926508.lyp'.

../_images/9e8729e758ff1827aed06856abb959aa92f3f5aa4d306c04274dea172d6f9b78.png
gh_ymin = gf.grid_with_component_name(sweep, shape=(len(sweep), 1), align_x="xmin")
gh_ymin.plot()
2024-04-19 00:22:51.533 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/grid_034c17d4.lyp'.

../_images/7cde136eb097512bc151767e24a3e49e900503ee6a9358b14fd691ad6486dd50.png

You can also add text labels to each element of the sweep

gh_ymin = gf.grid_with_text(
    sweep, shape=(len(sweep), 1), align_x="xmax", text=text_metal
)
gh_ymin.plot()
2024-04-19 00:22:51.761 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/grid_with_text_8d4b9749.lyp'.

../_images/fe6fc8f9a7cbaf3a18a3878679ab1826eade4d0bf192a444ddc28e9d3a05985f.png

You have 2 ways of defining a mask:

  1. in python

  2. in YAML

1. Component in python#

You can define a Component top cell reticle or die using grid and pack python functions.

text_metal3 = partial(gf.components.text_rectangular_multi_layer, layers=((49, 0),))
grid = partial(gf.grid_with_text, text=text_metal3)
pack = partial(gf.pack, text=text_metal3)

gratings_sweep = [
    gf.components.grating_coupler_elliptical(taper_angle=taper_angle)
    for taper_angle in [20, 30, 40]
]
gratings = grid(gratings_sweep, text=None)
gratings.plot()
2024-04-19 00:22:51.986 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/grid_with_text_26482ab8.lyp'.

../_images/533bc7decef18f00dfcfbcca594844758e2c2793526832299b5103bc314fd01a.png
gratings_sweep = [
    gf.components.grating_coupler_elliptical(taper_angle=taper_angle)
    for taper_angle in [20, 30, 40]
]
gratings_loss_sweep = [
    gf.components.grating_coupler_loss_fiber_single(grating_coupler=grating)
    for grating in gratings_sweep
]
gratings = grid(
    gratings_loss_sweep, shape=(1, len(gratings_loss_sweep)), spacing=(40, 0)
)
gratings.plot()
2024-04-19 00:22:52.252 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/grid_with_text_77c2af8a.lyp'.

../_images/11a5755c197f5f83f8c64dfd779217efdddb78fda24251414624facf407bb7d3.png
sweep_resistance = [
    gf.components.resistance_sheet(width=width) for width in [1, 10, 100]
]
resistance = gf.pack(sweep_resistance)[0]
resistance.plot()
2024-04-19 00:22:52.460 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/pack_0$4.lyp'.

../_images/c0293cfe225376a6e1af026ac28e14b124f816a4abfb35f5ed68b271c0246053.png
spiral_te = gf.compose(
    gf.routing.add_fiber_single,
    gf.functions.rotate90,
    gf.components.spiral_inner_io_fiber_single,
)
sweep_spirals = [spiral_te(length=length) for length in [10e3, 20e3, 30e3]]
spirals = gf.pack(sweep_spirals)[0]
spirals.plot()
2024-04-19 00:22:52.663 | WARNING  | gdsfactory.component:_write_library:1933 - UserWarning: Component pack_0$5 has invalid transformations. Try component.flatten_offgrid_references() first.
2024-04-19 00:22:52.686 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/pack_0$5.lyp'.

../_images/be6f9459e9cf7da2360e930314c104790551f4229be4f057f2fd8c4fc58e06b7.png
mask = gf.pack([spirals, resistance, gratings])[0]
mask.plot()
2024-04-19 00:22:52.850 | WARNING  | gdsfactory.component:_write_library:1933 - UserWarning: Component pack_0$6 has invalid transformations. Try component.flatten_offgrid_references() first.
2024-04-19 00:22:52.868 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/pack_0$6.lyp'.

../_images/5a0c9d397aab46783047e42c4a2c294d68565dd9abc3fe432f1252a08dfadb17.png

As you can see you can define your mask in a single line.

For more complex mask, you can also create a new cell to build up more complexity

@gf.cell
def mask():
    c = gf.Component()
    c << gf.pack([spirals, resistance, gratings])[0]
    c << gf.components.seal_ring(c.bbox)
    return c


c = mask()
c.plot()
2024-04-19 00:22:53.053 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/mask.lyp'.

../_images/faf682e800cd9d653a70d3074ebc39f700ba4268518059e8366d57b1a606fb79.png

2. Component in YAML#

You can also define your component in YAML format thanks to gdsfactory.read.from_yaml

You need to define:

  • instances

  • placements

  • routes (optional)

and you can leverage:

  1. pack_doe

  2. pack_doe_grid

2.1 pack_doe#

pack_doe places components as compact as possible.

c = gf.read.from_yaml(
    """
name: mask_grid

instances:
  rings:
    component: pack_doe
    settings:
      doe: ring_single
      settings:
        radius: [30, 50, 20, 40]
        length_x: [1, 2, 3]
      do_permutations: True
      function:
        function: add_fiber_array
        settings:
            fanout_length: 200

  mzis:
    component: pack_doe
    settings:
      doe: mzi
      settings:
        delta_length: [10, 100]
      function: add_fiber_array

placements:
  rings:
    xmin: 50

  mzis:
    xmin: rings,east
"""
)

c.plot()
2024-04-19 00:22:53.213 | WARNING  | gdsfactory.read.from_yaml:from_yaml:692 - UserWarning: prefix is deprecated and will be removed soon. _from_yaml
2024-04-19 00:22:53.920 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/mask_grid_80db99b8.lyp'.

../_images/223d73ef9d5c1eb217ca13602bbdf1026bb86c98e36e309b8be07576f21cac9f.png

2.2 pack_doe_grid#

pack_doe_grid places each component on a regular grid

c = gf.read.from_yaml(
    """
name: mask_compact

instances:
  rings:
    component: pack_doe
    settings:
      doe: ring_single
      settings:
        radius: [30, 50, 20, 40]
        length_x: [1, 2, 3]
      do_permutations: True
      function:
        function: add_fiber_array
        settings:
            fanout_length: 200


  mzis:
    component: pack_doe_grid
    settings:
      doe: mzi
      settings:
        delta_length: [10, 100]
      do_permutations: True
      spacing: [10, 10]
      function: add_fiber_array

placements:
  rings:
    xmin: 50

  mzis:
    xmin: rings,east
"""
)
c.plot()
2024-04-19 00:22:54.106 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/mask_compact_6d4ddaf1.lyp'.

../_images/3678f7b4b34928b90081f11ed0a5f838af9535a6965d09c8f2029b2bf9b1639e.png

Automated testing exposing all ports#

You can promote all the ports that need to be tested to the top level component and then write a CSV test manifest.

This is the recommended way for measuring components that have electrical and optical port.

test_info_spirals = dict(
    doe="spirals_sc",
    measurement="optical_loopback4",
    analysis="optical_loopback4_spirals",
)
test_info_mzi_heaters = dict(
    doe="mzis_heaters",
    analysis="mzi_heater",
    measurement="optical_loopback4_heater_sweep",
)
test_info_ring_heaters = dict(
    doe="ring_heaters",
    analysis="ring_heater",
    measurement="optical_loopback2_heater_sweep",
)


def sample_reticle() -> gf.Component:
    """Returns MZI with TE grating couplers."""

    mzis = [
        gf.components.mzi2x2_2x2_phase_shifter(length_x=length)
        for length in [100, 200, 300]
    ]
    rings = [
        gf.components.ring_single_heater(length_x=length_x) for length_x in [10, 20, 30]
    ]

    spirals_te = [
        gf.components.spiral_inner_io_fiber_array(
            length=length,
        )
        for length in [20e3, 40e3, 60e3]
    ]
    mzis_te = [
        gf.components.add_fiber_array_optical_south_electrical_north(
            mzi,
            electrical_port_names=["top_l_e2", "top_r_e2"],
        )
        for mzi in mzis
    ]
    rings_te = [
        gf.components.add_fiber_array_optical_south_electrical_north(
            ring,
            electrical_port_names=["l_e2", "r_e2"],
        )
        for ring in rings
    ]

    for component in mzis_te:
        component.info.update(test_info_mzi_heaters)

    for component in rings_te:
        component.info.update(test_info_ring_heaters)

    for component in spirals_te:
        component.info.update(test_info_spirals)

    components = mzis_te + rings_te + spirals_te
    return gf.pack(components)[0]


c = sample_reticle()
c.plot()
2024-04-19 00:22:54.891 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/pack_0$10.lyp'.

../_images/181817b3c2cc9d83f1dbfdde79caa590e238bcb73bda7e52b2e3bea501df1092.png
c.pprint_ports()
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━┓
┃ name                                         width  center                orientation  layer    port_type  ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━┩
│ mzi_add_fiber_array_optical_south_electric… │ 80.0  │ [285.635, 1260.05]   │ 270.0       │ [49, 0] │ electrical │
│ mzi_add_fiber_array_optical_south_electric… │ 80.0  │ [385.635, 1260.05]   │ 270.0       │ [49, 0] │ electrical │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [18.135, 1055.495]   │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [653.135, 1055.495]  │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [145.135, 1055.495]  │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [272.135, 1055.495]  │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [399.135, 1055.495]  │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [526.135, 1055.495]  │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 80.0  │ [285.635, 920.05]    │ 270.0       │ [49, 0] │ electrical │
│ mzi_add_fiber_array_optical_south_electric… │ 80.0  │ [385.635, 920.05]    │ 270.0       │ [49, 0] │ electrical │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [18.135, 715.495]    │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [653.135, 715.495]   │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [145.135, 715.495]   │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [272.135, 715.495]   │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [399.135, 715.495]   │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [526.135, 715.495]   │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 80.0  │ [285.635, 580.05]    │ 270.0       │ [49, 0] │ electrical │
│ mzi_add_fiber_array_optical_south_electric… │ 80.0  │ [385.635, 580.05]    │ 270.0       │ [49, 0] │ electrical │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [18.135, 375.495]    │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [653.135, 375.495]   │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [145.135, 375.495]   │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [272.135, 375.495]   │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [399.135, 375.495]   │ 90.0        │ [1, 0]  │ optical    │
│ mzi_add_fiber_array_optical_south_electric… │ 0.5   │ [526.135, 375.495]   │ 90.0        │ [1, 0]  │ optical    │
│ ring_single_heater_add_fiber_array_optical… │ 80.0  │ [829.805, 1260.05]   │ 270.0       │ [49, 0] │ electrical │
│ ring_single_heater_add_fiber_array_optical… │ 80.0  │ [929.805, 1260.05]   │ 270.0       │ [49, 0] │ electrical │
│ ring_single_heater_add_fiber_array_optical… │ 0.5   │ [689.305, 1055.494]  │ 90.0        │ [1, 0]  │ optical    │
│ ring_single_heater_add_fiber_array_optical… │ 0.5   │ [1070.305, 1055.494] │ 90.0        │ [1, 0]  │ optical    │
│ ring_single_heater_add_fiber_array_optical… │ 0.5   │ [816.305, 1055.494]  │ 90.0        │ [1, 0]  │ optical    │
│ ring_single_heater_add_fiber_array_optical… │ 0.5   │ [943.305, 1055.494]  │ 90.0        │ [1, 0]  │ optical    │
│ ring_single_heater_add_fiber_array_optical… │ 80.0  │ [829.805, 580.05]    │ 270.0       │ [49, 0] │ electrical │
│ ring_single_heater_add_fiber_array_optical… │ 80.0  │ [929.805, 580.05]    │ 270.0       │ [49, 0] │ electrical │
│ ring_single_heater_add_fiber_array_optical… │ 0.5   │ [689.305, 375.494]   │ 90.0        │ [1, 0]  │ optical    │
│ ring_single_heater_add_fiber_array_optical… │ 0.5   │ [1070.305, 375.494]  │ 90.0        │ [1, 0]  │ optical    │
│ ring_single_heater_add_fiber_array_optical… │ 0.5   │ [816.305, 375.494]   │ 90.0        │ [1, 0]  │ optical    │
│ ring_single_heater_add_fiber_array_optical… │ 0.5   │ [943.305, 375.494]   │ 90.0        │ [1, 0]  │ optical    │
│ ring_single_heater_add_fiber_array_optical… │ 80.0  │ [829.805, 920.05]    │ 270.0       │ [49, 0] │ electrical │
│ ring_single_heater_add_fiber_array_optical… │ 80.0  │ [929.805, 920.05]    │ 270.0       │ [49, 0] │ electrical │
│ ring_single_heater_add_fiber_array_optical… │ 0.5   │ [689.305, 715.494]   │ 90.0        │ [1, 0]  │ optical    │
│ ring_single_heater_add_fiber_array_optical… │ 0.5   │ [1070.305, 715.494]  │ 90.0        │ [1, 0]  │ optical    │
│ ring_single_heater_add_fiber_array_optical… │ 0.5   │ [816.305, 715.494]   │ 90.0        │ [1, 0]  │ optical    │
│ ring_single_heater_add_fiber_array_optical… │ 0.5   │ [943.305, 715.494]   │ 90.0        │ [1, 0]  │ optical    │
│ spiral_inner_io_fiber_array-loopback1       │ 0.5   │ [360.824, 1455.3]    │ 90.0        │ [1, 0]  │ optical    │
│ spiral_inner_io_fiber_array-loopback2       │ 0.5   │ [741.824, 1455.3]    │ 90.0        │ [1, 0]  │ optical    │
│ spiral_inner_io_fiber_array-o1              │ 0.5   │ [487.824, 1459.3]    │ 90.0        │ [1, 0]  │ optical    │
│ spiral_inner_io_fiber_array-o2              │ 0.5   │ [614.824, 1459.3]    │ 90.0        │ [1, 0]  │ optical    │
│ spiral_inner_io_fiber_array_length40000p0-… │ 0.5   │ [1269.914, 272.8]    │ 90.0        │ [1, 0]  │ optical    │
│ spiral_inner_io_fiber_array_length40000p0-… │ 0.5   │ [1650.914, 272.8]    │ 90.0        │ [1, 0]  │ optical    │
│ spiral_inner_io_fiber_array_length40000p0-… │ 0.5   │ [1396.914, 276.8]    │ 90.0        │ [1, 0]  │ optical    │
│ spiral_inner_io_fiber_array_length40000p0-… │ 0.5   │ [1523.914, 276.8]    │ 90.0        │ [1, 0]  │ optical    │
│ spiral_inner_io_fiber_array_length60000p0-… │ 0.5   │ [2179.01, 110.3]     │ 90.0        │ [1, 0]  │ optical    │
│ spiral_inner_io_fiber_array_length60000p0-… │ 0.5   │ [2560.01, 110.3]     │ 90.0        │ [1, 0]  │ optical    │
│ spiral_inner_io_fiber_array_length60000p0-… │ 0.5   │ [2306.01, 114.3]     │ 90.0        │ [1, 0]  │ optical    │
│ spiral_inner_io_fiber_array_length60000p0-… │ 0.5   │ [2433.01, 114.3]     │ 90.0        │ [1, 0]  │ optical    │
└─────────────────────────────────────────────┴───────┴──────────────────────┴─────────────┴─────────┴────────────┘
df = gf.labels.get_test_manifest(c)
df

cell measurement measurement_settings analysis analysis_settings doe polarization analysis doe wavelength length measurement parent
0 mzi_add_fiber_array_optical_south_electrical_n... optical_loopback4_heater_sweep None mzi_heater None mzis_heaters None mzi_heater mzis_heaters NaN NaN optical_loopback4_heater_sweep mzi_add_fiber_array_optical_south_electrical_n...
1 mzi_add_fiber_array_optical_south_electrical_n... optical_loopback4_heater_sweep None mzi_heater None mzis_heaters None mzi_heater mzis_heaters NaN NaN optical_loopback4_heater_sweep mzi_add_fiber_array_optical_south_electrical_n...
2 mzi_add_fiber_array_optical_south_electrical_n... optical_loopback4_heater_sweep None mzi_heater None mzis_heaters None mzi_heater mzis_heaters NaN NaN optical_loopback4_heater_sweep mzi_add_fiber_array_optical_south_electrical_n...
3 ring_single_heater_add_fiber_array_optical_sou... optical_loopback2_heater_sweep None ring_heater None ring_heaters None ring_heater ring_heaters NaN NaN optical_loopback2_heater_sweep ring_single_heater_add_fiber_array_optical_sou...
4 ring_single_heater_add_fiber_array_optical_sou... optical_loopback2_heater_sweep None ring_heater None ring_heaters None ring_heater ring_heaters NaN NaN optical_loopback2_heater_sweep ring_single_heater_add_fiber_array_optical_sou...
5 ring_single_heater_add_fiber_array_optical_sou... optical_loopback2_heater_sweep None ring_heater None ring_heaters None ring_heater ring_heaters NaN NaN optical_loopback2_heater_sweep ring_single_heater_add_fiber_array_optical_sou...
6 spiral_inner_io_fiber_array optical_loopback4 None optical_loopback4_spirals None spirals_sc te optical_loopback4_spirals spirals_sc 1.53 20000.009 optical_loopback4 spiral_inner_io_fiber_array
7 spiral_inner_io_fiber_array_length40000p0 optical_loopback4 None optical_loopback4_spirals None spirals_sc te optical_loopback4_spirals spirals_sc 1.53 39999.989 optical_loopback4 spiral_inner_io_fiber_array_length40000p0
8 spiral_inner_io_fiber_array_length60000p0 optical_loopback4 None optical_loopback4_spirals None spirals_sc te optical_loopback4_spirals spirals_sc 1.53 60000.013 optical_loopback4 spiral_inner_io_fiber_array_length60000p0
df.to_csv("test_manifest.csv")
def sample_reticle_grid() -> gf.Component:
    """Returns sample reticle with grid packer."""

    mzis = [
        gf.components.mzi2x2_2x2_phase_shifter(length_x=length)
        for length in [100, 200, 300]
    ]
    rings = [
        gf.components.ring_single_heater(length_x=length_x) for length_x in [10, 20, 30]
    ]

    spirals_te = [
        gf.components.spiral_inner_io_fiber_array(
            length=length,
        )
        for length in [20e3, 40e3, 60e3]
    ]
    mzis_te = [
        gf.components.add_fiber_array_optical_south_electrical_north(
            mzi,
            electrical_port_names=["top_l_e2", "top_r_e2"],
        )
        for mzi in mzis
    ]
    rings_te = [
        gf.components.add_fiber_array_optical_south_electrical_north(
            ring,
            electrical_port_names=["l_e2", "r_e2"],
        )
        for ring in rings
    ]

    for component in mzis_te:
        component.info.update(test_info_mzi_heaters)

    for component in rings_te:
        component.info.update(test_info_ring_heaters)

    for component in spirals_te:
        component.info.update(test_info_spirals)

    components = mzis_te + rings_te + spirals_te
    return gf.grid(components)


c = sample_reticle_grid()
c.plot()
2024-04-19 00:22:55.186 | WARNING  | gdsfactory.component:_write_library:1933 - UserWarning: Component grid_21df96cc has invalid transformations. Try component.flatten_offgrid_references() first.
2024-04-19 00:22:55.204 | INFO     | gdsfactory.technology.layer_views:to_lyp:1018 - LayerViews written to '/tmp/gdsfactory/grid_21df96cc.lyp'.

../_images/ac061d87c85b84b7b7f7915676a003f313bcfaf0d372cac5aa232489c089c684.png
df = gf.labels.get_test_manifest(c)
df

cell measurement measurement_settings analysis analysis_settings doe polarization analysis doe wavelength length measurement parent
0 mzi_add_fiber_array_optical_south_electrical_n... optical_loopback4_heater_sweep None mzi_heater None mzis_heaters None mzi_heater mzis_heaters NaN NaN optical_loopback4_heater_sweep mzi_add_fiber_array_optical_south_electrical_n...
1 mzi_add_fiber_array_optical_south_electrical_n... optical_loopback4_heater_sweep None mzi_heater None mzis_heaters None mzi_heater mzis_heaters NaN NaN optical_loopback4_heater_sweep mzi_add_fiber_array_optical_south_electrical_n...
2 mzi_add_fiber_array_optical_south_electrical_n... optical_loopback4_heater_sweep None mzi_heater None mzis_heaters None mzi_heater mzis_heaters NaN NaN optical_loopback4_heater_sweep mzi_add_fiber_array_optical_south_electrical_n...
3 ring_single_heater_add_fiber_array_optical_sou... optical_loopback2_heater_sweep None ring_heater None ring_heaters None ring_heater ring_heaters NaN NaN optical_loopback2_heater_sweep ring_single_heater_add_fiber_array_optical_sou...
4 ring_single_heater_add_fiber_array_optical_sou... optical_loopback2_heater_sweep None ring_heater None ring_heaters None ring_heater ring_heaters NaN NaN optical_loopback2_heater_sweep ring_single_heater_add_fiber_array_optical_sou...
5 ring_single_heater_add_fiber_array_optical_sou... optical_loopback2_heater_sweep None ring_heater None ring_heaters None ring_heater ring_heaters NaN NaN optical_loopback2_heater_sweep ring_single_heater_add_fiber_array_optical_sou...
6 spiral_inner_io_fiber_array optical_loopback4 None optical_loopback4_spirals None spirals_sc te optical_loopback4_spirals spirals_sc 1.53 20000.009 optical_loopback4 spiral_inner_io_fiber_array
7 spiral_inner_io_fiber_array_length40000p0 optical_loopback4 None optical_loopback4_spirals None spirals_sc te optical_loopback4_spirals spirals_sc 1.53 39999.989 optical_loopback4 spiral_inner_io_fiber_array_length40000p0
8 spiral_inner_io_fiber_array_length60000p0 optical_loopback4 None optical_loopback4_spirals None spirals_sc te optical_loopback4_spirals spirals_sc 1.53 60000.013 optical_loopback4 spiral_inner_io_fiber_array_length60000p0
df.to_csv("test_manifest.csv")

You can see a test manifest example here