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 gdsfactory as gf

gf.config.rich_output()

Pack#

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

def add_resistance_sweep_info(c):
    c.info["doe"] = "resistance_sweep"
    c.info["analysis"] = "[iv_resistance]"
    c.info["analysis_parameters"] = "[{}]"
    c.info["ports_electrical"] = 2
    c.info["ports_optical"] = 0
    c.info["measurement"] = "iv"
    c.info["measurement_parameters"] = "{}"
    return c


sweep = [gf.components.resistance_sheet(width=width) for width in [1, 10, 50]]
sweep_with_info = [add_resistance_sweep_info(c) for c in sweep]
m = gf.pack(sweep_with_info)
c = m[0]
c.draw_ports()
c.pprint_ports()
c.plot()
┏━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ name    width  orientation  layer        center            port_type  ┃
┡━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ 0_pad1 │ 50.0  │ 270.0       │ MTOP (49/0) │ (30.05, 5.05)    │ electrical │
│ 0_pad2 │ 50.0  │ 270.0       │ MTOP (49/0) │ (130.05, 5.05)   │ electrical │
│ 1_pad1 │ 50.0  │ 270.0       │ MTOP (49/0) │ (30.05, 65.05)   │ electrical │
│ 1_pad2 │ 50.0  │ 270.0       │ MTOP (49/0) │ (130.05, 65.05)  │ electrical │
│ 2_pad1 │ 50.0  │ 270.0       │ MTOP (49/0) │ (30.05, 125.05)  │ electrical │
│ 2_pad2 │ 50.0  │ 270.0       │ MTOP (49/0) │ (130.05, 125.05) │ electrical │
└────────┴───────┴─────────────┴─────────────┴──────────────────┴────────────┘

../_images/c1973490d8eb48316aac1bc2aed7eeccee41868a09ab6ba708d8c8a9a789722f.png
sweep_with_info[0].info

Info(
    resistance=0,
    doe='resistance_sweep',
    analysis='[iv_resistance]',
    analysis_parameters='[{}]',
    ports_electrical=2,
    ports_optical=0,
    measurement='iv',
    measurement_parameters='{}'
)

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

@gf.cell
def spiral_gc(**kwargs):
    """Returns spiral with Grating Couplers."""
    c = gf.components.spiral(**kwargs)
    c = gf.routing.add_fiber_array(c)
    c.info["doe"] = "spirals_sc"  # strip Cband spirals
    c.info["measurement"] = "optical_spectrum"
    c.info["measurement_parameters"] = "{}"
    c.info["analysis"] = "[power_envelope]"
    c.info["analysis_parameters"] = "[]"
    c.info["ports_optical"] = 4
    c.info["ports_electrical"] = 0
    c.info.update(kwargs)
    return c


c = spiral_gc(length=100)
c.plot()

../_images/0a132c0a5826cbb65142cda4fae8c96f0638ded8dccea3a14f9b45a51cbf59b0.png
c.info

Info(
    length=100,
    doe='spirals_sc',
    measurement='optical_spectrum',
    measurement_parameters='{}',
    analysis='[power_envelope]',
    analysis_parameters='[]',
    ports_optical=4,
    ports_electrical=0
)
sweep = [spiral_gc(length=length) for length in [100, 200, 300]]
m = gf.pack(sweep)
c = m[0]
c.plot()

../_images/32e2d2c6f7d4d2711d3e0a83ba594b33752798a5cbb1a247cb1cbfa67ef85a0a.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()

../_images/28bb7335d3ad8c4ed621fda33cbf2a0cf9636343ab7bcf50c606836e663db364.png

Grid#

You can also pack components with a constant spacing.

g = gf.grid(sweep)
g.plot()

../_images/f5c5e5e300349083d4070ddd0661e22c4e6c2513a453b544231072712b15a6dc.png
gh = gf.grid(sweep, shape=(1, len(sweep)))
gh.plot()

../_images/202f5f48002282cbc5e36ec616019238f1becffcba1d1184bddd384acb78325c.png
gh_ymin = gf.grid(sweep, shape=(len(sweep), 1), align_x="xmin")
gh_ymin.plot()

../_images/b12d28c8dee81a6147d1dc5bf922a61937c9031bf3511a3900ef1faf81594bfe.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()

../_images/5fa109e75a2fd37daee7f41593228956eafb0d2e601225f981bee7fb3ace9cca.png
gh_ymin = gf.grid_with_text(
    sweep,
    shape=(len(sweep), 1),
    align_x="xmax",
    text=text_metal,
    labels=("S100", "S200", "S300"),
)
gh_ymin.plot()

../_images/9e3a1a07f018f83337de1007cb8c5a27e8c91fef4c2c0cba68a75de76d3d03ac.png

You have 2 ways of defining a mask:

  1. in YAML

  2. in Python

YAML Component#

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

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.show()
c.plot()

../_images/cc4541b43e1cca97a5b3095d3ae6b1d4c74d3ffa85e7a0ab7ed5c31162c3fdf8.png

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.show()
c.plot()

../_images/5f2a70f9d11dd6e9b503e986a35766305a7cfb7cbf74eb03b4495389909899ba.png

Automated testing and analysis#

This is useful when you have a lot of components and you want to automate the testing process.

There are two main ways to define which components are testable:

  1. Include a doe (Design of Experiments) field in the component.info dictionary, as well as all relevant test and analysis information.

  2. Include a GDS label in all component test points. There are many ways to define test points, but the most common is to use a GDS label with the format <elec/opt>-<number_of_ports>-<cell_name>. This way you can easily extract all test points from the GDS file.

import pandas as pd

import gdsfactory as gf


@gf.cell
def mzm_gc(length_x=10, **kwargs) -> gf.Component:
    """Returns a MZI with Grating Couplers.

    Args:
        length_x: length of the MZI.
        kwargs: additional settings.
    """
    c = gf.components.mzi2x2_2x2_phase_shifter(
        length_x=length_x, auto_rename_ports=False, **kwargs
    )
    c = gf.routing.add_pads_top(c, port_names=["top_l_e1", "top_r_e3"])
    c = gf.routing.add_fiber_array(c)
    c.info["doe"] = "mzm"
    c.info["measurement"] = "optical_spectrum"
    c.info["analysis"] = "[fsr]"
    c.info["analysis_parameters"] = "[]"
    c.info["ports_electrical"] = 2
    c.info["ports_optical"] = 6
    c.info["length_x"] = length_x
    c.info.update(kwargs)
    return c


def sample_reticle(grid: bool = False) -> gf.Component:
    """Returns MZI with TE grating couplers."""
    from gdsfactory.generic_tech.cells import (
        add_fiber_array_optical_south_electrical_north,
    )

    mzis = [mzm_gc(length_x=lengths) for lengths in [100, 200, 300]]
    spirals = [spiral_gc(length=length) for length in [0, 100, 200]]
    rings = []
    for length_x in [10, 20, 30]:
        ring = gf.components.ring_single_heater(length_x=length_x)
        c = add_fiber_array_optical_south_electrical_north(
            component=ring,
            electrical_port_names=["l_e2", "r_e2"],
        )
        c.name = f"ring_{length_x}"
        c.info["doe"] = "ring_length_x"
        c.info["measurement"] = "optical_spectrum"
        c.info["ports_electrical"] = 2
        c.info["ports_optical"] = 4
        c.info["analysis"] = "[fsr]"
        c.info["analysis_parameters"] = "[]"
        c.info["length_x"] = length_x
        rings.append(c)

    copies = 3  # number of copies of each component
    components = mzis * copies + rings * copies + spirals * copies
    if grid:
        return gf.grid(components)
    c = gf.pack(components)
    if len(c) > 1:
        c = gf.pack(c)[0]
    return c[0]


c = sample_reticle()
c.show()
c

../_images/8b5c05f89052c74bcd294ce6b2a5418831a0d3d30cfd8b7a1574cbef76509158.png
gf.labels.write_test_manifest(c, csvpath="sample_reticle.csv")
df = pd.read_csv("sample_reticle.csv")
df
Warning: 'measurement_parameters' missing from 'mzm_gc_LX100'
Warning: 'measurement_parameters' missing from 'mzm_gc_LX200'
Warning: 'measurement_parameters' missing from 'mzm_gc_LX300'
Warning: 'measurement_parameters' missing from 'mzm_gc_LX100'
Warning: 'measurement_parameters' missing from 'mzm_gc_LX200'
Warning: 'measurement_parameters' missing from 'mzm_gc_LX300'
Warning: 'measurement_parameters' missing from 'mzm_gc_LX100'
Warning: 'measurement_parameters' missing from 'mzm_gc_LX200'
Warning: 'measurement_parameters' missing from 'mzm_gc_LX300'
Warning: 'measurement_parameters' missing from 'ring_10'
Warning: 'measurement_parameters' missing from 'ring_20'
Warning: 'measurement_parameters' missing from 'ring_30'
Warning: 'measurement_parameters' missing from 'ring_10'
Warning: 'measurement_parameters' missing from 'ring_20'
Warning: 'measurement_parameters' missing from 'ring_30'
Warning: 'measurement_parameters' missing from 'ring_10'
Warning: 'measurement_parameters' missing from 'ring_20'
Warning: 'measurement_parameters' missing from 'ring_30'

cell x y info ports settings doe analysis analysis_parameters measurement measurement_parameters ports_optical ports_electrical
0 mzm_gc_LX100 250.020 153.225 {"length_x": 100} {"in_o1": {"name": "in_o1", "center": [145.02,... {"length_x":100} mzm [fsr] [] optical_spectrum NaN 6 2
1 mzm_gc_LX200 200.020 419.775 {"length_x": 200} {"in_o1": {"name": "in_o1", "center": [145.02,... {"length_x":200} mzm [fsr] [] optical_spectrum NaN 6 2
2 mzm_gc_LX300 150.020 686.325 {"length_x": 300} {"in_o1": {"name": "in_o1", "center": [145.02,... {"length_x":300} mzm [fsr] [] optical_spectrum NaN 6 2
3 mzm_gc_LX100 250.020 952.876 {"length_x": 100} {"in_o1": {"name": "in_o1", "center": [145.02,... {"length_x":100} mzm [fsr] [] optical_spectrum NaN 6 2
4 mzm_gc_LX200 200.020 1219.426 {"length_x": 200} {"in_o1": {"name": "in_o1", "center": [145.02,... {"length_x":200} mzm [fsr] [] optical_spectrum NaN 6 2
5 mzm_gc_LX300 150.020 1485.976 {"length_x": 300} {"in_o1": {"name": "in_o1", "center": [145.02,... {"length_x":300} mzm [fsr] [] optical_spectrum NaN 6 2
6 mzm_gc_LX100 250.020 1752.526 {"length_x": 100} {"in_o1": {"name": "in_o1", "center": [145.02,... {"length_x":100} mzm [fsr] [] optical_spectrum NaN 6 2
7 mzm_gc_LX200 200.020 2019.076 {"length_x": 200} {"in_o1": {"name": "in_o1", "center": [145.02,... {"length_x":200} mzm [fsr] [] optical_spectrum NaN 6 2
8 mzm_gc_LX300 820.960 153.225 {"length_x": 300} {"in_o1": {"name": "in_o1", "center": [815.96,... {"length_x":300} mzm [fsr] [] optical_spectrum NaN 6 2
9 ring_10 884.460 367.151 {"length_x": 10} {"o1": {"name": "o1", "center": [815.96, 300.6... {} ring_length_x [fsr] [] optical_spectrum NaN 4 2
10 ring_20 889.460 707.151 {"length_x": 20} {"o1": {"name": "o1", "center": [815.96, 640.6... {} ring_length_x [fsr] [] optical_spectrum NaN 4 2
11 ring_30 894.460 1047.151 {"length_x": 30} {"o1": {"name": "o1", "center": [815.96, 980.6... {} ring_length_x [fsr] [] optical_spectrum NaN 4 2
12 ring_10 884.460 1387.151 {"length_x": 10} {"o1": {"name": "o1", "center": [815.96, 1320.... {} ring_length_x [fsr] [] optical_spectrum NaN 4 2
13 ring_20 889.460 1727.151 {"length_x": 20} {"o1": {"name": "o1", "center": [815.96, 1660.... {} ring_length_x [fsr] [] optical_spectrum NaN 4 2
14 ring_30 1311.400 367.151 {"length_x": 30} {"o1": {"name": "o1", "center": [1232.9, 300.6... {} ring_length_x [fsr] [] optical_spectrum NaN 4 2
15 ring_10 1301.400 707.151 {"length_x": 10} {"o1": {"name": "o1", "center": [1232.9, 640.6... {} ring_length_x [fsr] [] optical_spectrum NaN 4 2
16 ring_20 1306.400 1047.151 {"length_x": 20} {"o1": {"name": "o1", "center": [1232.9, 980.6... {} ring_length_x [fsr] [] optical_spectrum NaN 4 2
17 ring_30 1311.400 1387.151 {"length_x": 30} {"o1": {"name": "o1", "center": [1232.9, 1320.... {} ring_length_x [fsr] [] optical_spectrum NaN 4 2
18 spiral_gc_L200 1395.179 140.351 {"length": 200} {"o1": {"name": "o1", "center": [1551.179, 34.... {"length":200} spirals_sc [power_envelope] [] optical_spectrum {} 4 0
19 spiral_gc_L200 1141.179 1766.901 {"length": 200} {"o1": {"name": "o1", "center": [1297.179, 166... {"length":200} spirals_sc [power_envelope] [] optical_spectrum {} 4 0
20 spiral_gc_L200 1141.179 1950.451 {"length": 200} {"o1": {"name": "o1", "center": [1297.179, 184... {"length":200} spirals_sc [power_envelope] [] optical_spectrum {} 4 0
21 spiral_gc_L100 759.960 2106.901 {"length": 100} {"o1": {"name": "o1", "center": [815.96, 2000.... {"length":100} spirals_sc [power_envelope] [] optical_spectrum {} 4 0
22 spiral_gc_L100 1593.840 323.901 {"length": 100} {"o1": {"name": "o1", "center": [1649.84000000... {"length":100} spirals_sc [power_envelope] [] optical_spectrum {} 4 0
23 spiral_gc_L100 1593.840 507.451 {"length": 100} {"o1": {"name": "o1", "center": [1649.84000000... {"length":100} spirals_sc [power_envelope] [] optical_spectrum {} 4 0
24 spiral_gc_L0 1693.840 680.751 {"length": 0} {"o1": {"name": "o1", "center": [1649.84000000... {"length":0} spirals_sc [power_envelope] [] optical_spectrum {} 4 0
25 spiral_gc_L0 1693.840 854.051 {"length": 0} {"o1": {"name": "o1", "center": [1649.84000000... {"length":0} spirals_sc [power_envelope] [] optical_spectrum {} 4 0
26 spiral_gc_L0 1693.840 1027.351 {"length": 0} {"o1": {"name": "o1", "center": [1649.84000000... {"length":0} spirals_sc [power_envelope] [] optical_spectrum {} 4 0

You can see a test manifest example here

Automated testing with labels#

The GDS info is stored in the GDS file metadata and can be lost if the GDS file is modified with other tools that are not aware of the metadata. To avoid this, GDSFactory also supports a more traditional way of defining test points, using GDS labels.

For example, lets say you want to label the rightmost port of a component with a GDS label port_type-number_of_ports-cell_name. You can do this with the following code:

import gdsfactory as gf
from gdsfactory.typings import LayerSpec

layer_label = "TEXT"


def label_farthest_right_port(
    component: gf.Component, ports: gf.Port | list[gf.Port], layer: LayerSpec, text: str
) -> gf.Component:
    """Adds a label to the right of the farthest right port in a given component.

    Args:
        component: The component to which the label is added.
        ports: A list of ports to evaluate for positioning the label.
        layer: The layer on which the label will be added.
        text: The text to display in the label.
    """
    rightmost_port = max(ports, key=lambda port: port.dx)

    component.add_label(
        text=text,
        position=rightmost_port.dcenter,
        layer=layer,
    )
    return component


c = gf.Component()
ref = c << gf.routing.add_pads_top(gf.components.wire_straight())
label_farthest_right_port(c, ref.ports, layer=layer_label, text="elec-2-wire_straight")
c

../_images/ac00803608b7e1436e2b38cfcaba8b99064dae166e4b58d14b7df788f2b432e4.png
def spiral_gc(length: float = 0, **kwargs) -> gf.Component:
    """Returns a spiral double with Grating Couplers.

    Args:
        length: length of the spiral straight section.
        kwargs: additional settings.

    Keyword Args:
        bend: bend component.
        straight: straight component.
        cross_section: cross_section component.
        spacing: spacing between the spiral loops.
        n_loops: number of loops.
    """
    c0 = gf.c.spiral(length=length, **kwargs)
    c = gf.routing.add_fiber_array(c0)
    c.info["doe"] = "spirals_sc"
    c.info["measurement"] = "optical_spectrum"
    c.info["analysis"] = "[power_envelope]"
    c.info["analysis_parameters"] = "[]"
    c.info["ports_optical"] = 4
    c.info["ports_electrical"] = 0
    c.info.update(kwargs)

    c.name = f"spiral_gc_{length}"
    label_farthest_right_port(c, c.ports, layer=layer_label, text=f"opt-4-{c.name}")
    return c


c = spiral_gc(length=0)
c

../_images/b41c46d0d8404253b87d23ac8015520c0e3804651cba78063e1c0235789ed268.png
def mzi_gc(length_x=10, **kwargs) -> gf.Component:
    """Returns a MZI with Grating Couplers.

    Args:
        length_x: length of the MZI.
        kwargs: additional settings.
    """
    c = gf.components.mzi2x2_2x2_phase_shifter(
        length_x=length_x, auto_rename_ports=False, **kwargs
    )
    c = gf.routing.add_pads_top(c, port_names=("top_l_e1", "top_r_e3"))
    c.name = f"mzi_{length_x}"
    c = gf.routing.add_fiber_array(c)

    c.info["doe"] = "mzi"
    c.info["measurement"] = "optical_spectrum"
    c.info["analysis"] = "[fsr]"
    c.info["analysis_parameters"] = "[]"
    c.info["ports_electrical"] = 2
    c.info["ports_optical"] = 6
    c.info["length_x"] = length_x
    c.info.update(kwargs)

    c.name = f"mzi_gc_{length_x}"
    label_farthest_right_port(
        c,
        c.ports.filter(port_type="vertical_te"),
        layer=layer_label,
        text=f"opt-{c.info['ports_optical']}-{c.name}",
    )
    label_farthest_right_port(
        c,
        c.ports.filter(port_type="electrical"),
        layer=layer_label,
        text=f"elec-{c.info['ports_electrical']}-{c.name}",
    )
    return c


c = mzi_gc(length_x=10)
c

../_images/cae9284ca47d9e650fbd4b74f70ee2e45fc6aaed5d894e978d142908165f0aea.png
def sample_reticle_with_labels(grid: bool = False) -> gf.Component:
    """Returns MZI with TE grating couplers."""
    from gdsfactory.generic_tech.cells import (
        add_fiber_array_optical_south_electrical_north,
    )

    mzis = [mzi_gc(length_x=lengths) for lengths in [100, 200, 300]]
    spirals = [spiral_gc(length=length) for length in [0, 100, 200]]
    rings = []
    for length_x in [10, 20, 30]:
        ring = gf.components.ring_single_heater(length_x=length_x)
        c = add_fiber_array_optical_south_electrical_north(
            component=ring,
            electrical_port_names=["l_e2", "r_e2"],
        )
        c.name = f"ring_{length_x}"
        c.info["doe"] = "ring_length_x"
        c.info["measurement"] = "optical_spectrum"
        c.info["ports_electrical"] = 2
        c.info["ports_optical"] = 4
        c.info["analysis"] = "[fsr]"
        c.info["analysis_parameters"] = "[]"
        label_farthest_right_port(
            c,
            c.ports.filter(port_type="vertical_te"),
            layer=layer_label,
            text=f"opt-{c.info['ports_optical']}-{c.name}",
        )
        label_farthest_right_port(
            c,
            c.ports.filter(port_type="electrical"),
            layer=layer_label,
            text=f"elec-{c.info['ports_electrical']}-{c.name}",
        )
        rings.append(c)

    copies = 3  # number of copies of each component
    components = mzis * copies + rings * copies + spirals * copies
    if grid:
        return gf.grid(components)
    c = gf.pack(components)
    if len(c) > 1:
        c = gf.pack(c)[0]
    return c[0]


c = sample_reticle_with_labels()
c

../_images/36e2a0356b2bfb0c52b7bc18daa465aeb763486b0bfe2850b617a704826e84f3.png

You can also extract all test points from a GDS file using gf.labels.write_labels

import pandas as pd

gdspath = c.write_gds()
csvpath = gf.labels.write_labels(gdspath, layer_label=layer_label)
df = pd.read_csv(csvpath)
df = df.sort_values(by=["text"])
df

text x y angle
13 elec-2-mzi_gc_100 395.920 1724.401 0.0
1 elec-2-mzi_gc_100 395.920 125.100 0.0
7 elec-2-mzi_gc_100 395.920 924.751 0.0
3 elec-2-mzi_gc_200 445.920 391.650 0.0
9 elec-2-mzi_gc_200 445.920 1191.301 0.0
15 elec-2-mzi_gc_200 445.920 1990.951 0.0
5 elec-2-mzi_gc_300 495.920 658.200 0.0
17 elec-2-mzi_gc_300 1166.860 125.100 0.0
11 elec-2-mzi_gc_300 495.920 1457.851 0.0
25 elec-2-ring_10 929.460 1541.600 0.0
19 elec-2-ring_10 929.460 521.600 0.0
31 elec-2-ring_10 1346.400 861.600 0.0
21 elec-2-ring_20 929.460 861.600 0.0
27 elec-2-ring_20 929.460 1881.600 0.0
33 elec-2-ring_20 1346.400 1201.600 0.0
29 elec-2-ring_30 1346.400 521.600 0.0
35 elec-2-ring_30 1346.400 1541.600 0.0
23 elec-2-ring_30 929.460 1201.600 0.0
30 opt-4-ring_10 1486.900 640.661 0.0
18 opt-4-ring_10 1069.960 300.661 0.0
24 opt-4-ring_10 1069.960 1320.661 0.0
32 opt-4-ring_20 1486.900 980.661 0.0
20 opt-4-ring_20 1069.960 640.661 0.0
26 opt-4-ring_20 1069.960 1660.661 0.0
34 opt-4-ring_30 1486.900 1320.661 0.0
28 opt-4-ring_30 1486.900 300.661 0.0
22 opt-4-ring_30 1069.960 980.661 0.0
42 opt-4-spiral_gc_0 1903.840 584.761 0.0
44 opt-4-spiral_gc_0 1903.840 931.361 0.0
43 opt-4-spiral_gc_0 1903.840 758.061 0.0
39 opt-4-spiral_gc_100 1069.960 2000.661 0.0
40 opt-4-spiral_gc_100 1903.840 217.661 0.0
41 opt-4-spiral_gc_100 1903.840 401.211 0.0
36 opt-4-spiral_gc_200 1805.179 34.111 0.0
37 opt-4-spiral_gc_200 1551.179 1660.661 0.0
38 opt-4-spiral_gc_200 1551.179 1844.211 0.0
12 opt-6-mzi_gc_100 653.020 1633.411 0.0
6 opt-6-mzi_gc_100 653.020 833.761 0.0
0 opt-6-mzi_gc_100 653.020 34.110 0.0
14 opt-6-mzi_gc_200 653.020 1899.961 0.0
8 opt-6-mzi_gc_200 653.020 1100.311 0.0
2 opt-6-mzi_gc_200 653.020 300.660 0.0
16 opt-6-mzi_gc_300 1323.960 34.110 0.0
10 opt-6-mzi_gc_300 653.020 1366.861 0.0
4 opt-6-mzi_gc_300 653.020 567.210 0.0