Spirals with controlled length and port location

This is a sample that shows how to create a spiral that has fixed length and fixed input and output coordinates. Often this is needed when control over the length of the spiral is required from grating coupler to grating coupler.

../_images/sphx_glr_plot_fixed_port_spiral_001.png

Out:

Spiral length: 4999.99983032

# Make sure that demolib is in your PYTHONPATH

import demolib.all as pdk
from picazzo3.wg.spirals.cell import DoubleSpiralWithInCouplingRounded
from ipkiss3 import all as i3
import numpy as np


class FixedPortSpiral(DoubleSpiralWithInCouplingRounded):
    """
    Spiral with fixed position for the ports and a fixed length - A Numerical optimizer is used to get the width of the spiral right.
    """
    x_input = i3.NumberProperty(doc="x position of the input port of the spiral")
    x_output = i3.NumberProperty(doc="x position of the output port of the spiral")
    x_spiral_start = i3.NumberProperty(default=100.0, doc="x position of the start of the spiral")
    total_length = i3.PositiveNumberProperty(default=4000.0, doc="Total length of the spiral")
    tol = i3.PositiveNumberProperty(default=0.001, doc="Tolerance of the numerical optimizer")

    def _default_x_input(self):
        return self.x_spiral_start - 100.0

    def _default_x_output(self):
        return self.x_spiral_start + 400.0

    def _default_n_o_traces(self):
        n_o_traces = super(FixedPortSpiral, self)._default_n_o_traces()
        return n_o_traces + 2

    class Layout(DoubleSpiralWithInCouplingRounded.Layout):

        def _default_inner_size(self):
            # To get the inner size we will perform a iterative optimization on the inner_size.
            # This method does not make any assumption on how the spiral is made
            # and could be ported to other path topologies.

            bs1 = bs2 = self._min_stub_length

            def get_sis(inner_size_x):
                if self.stub_direction == "H":
                    dummy_inner_size = i3.Coord2(inner_size_x,
                                                 2 * bs1 + 2 * bs2 + self.spacing)
                else:
                    dummy_inner_size = (inner_size_x,
                                        + bs1 + bs2 + self.spacing)

                return dummy_inner_size

            def min_get_length(x):

                inner_size_x = x[0]

                dummy = FixedPortSpiral(name=self.name + "_Dummy_Spiral_dummy",
                                        x_input=self.x_input,
                                        x_output=self.x_output,
                                        n_o_loops=self.n_o_loops,
                                        x_spiral_start=self.x_spiral_start)

                dummy_layout = dummy.Layout(inner_size=get_sis(inner_size_x),
                                            spacing=self.spacing,
                                            bend_radius=self.bend_radius,
                                            rounding_algorithm=self.rounding_algorithm,
                                            angle_step=self.angle_step,
                                            manhattan=self.manhattan,
                                            stub_direction=self.stub_direction,
                                            incoupling_length=self.incoupling_length)
                tl = dummy_layout.trace_length()
                return np.abs(tl - self.total_length)

            from scipy.optimize import minimize
            res = minimize(min_get_length,
                           method='Nelder-Mead',
                           x0=[(bs1 + bs2 + 3 * self.spacing) * 2],
                           options={'ftol': self.tol})

            return get_sis(res.x[0])

        def _default_shapes(self):
            shapes = super(FixedPortSpiral.Layout, self)._default_shapes()
            t = i3.Translation(translation=(self.x_spiral_start, 0.0))
            transformed_shapes = [s.transform_copy(transformation=t) for s in shapes]

            p_start = transformed_shapes[0][0]
            p_end = transformed_shapes[-1][-1]

            shape_start = i3.Shape(points=[(self.x_input, p_start[1]), p_start])
            shape_end = i3.Shape(points=[p_end, (self.x_output, p_end[1])])

            all_shapes = [shape_start] + transformed_shapes + [shape_end]

            return all_shapes


spiral = FixedPortSpiral(name="Spiral_5000",
                         x_input=0.0,
                         x_output=1000.0,
                         n_o_loops=5,
                         x_spiral_start=400.0,
                         total_length=5000.
                         )
lv = spiral.Layout()

print("Spiral length: {}".format(lv.trace_length()))

lv.write_gdsii("Fixed_length_spiral.gds")
lv.visualize()