ipkiss3.all.PlaceRelative

class ipkiss3.all.PlaceRelative(pos_selector1, pos_selector2, offset, angle=None)

Specifies that an instance (inst1) or a port (inst1:port) should be placed relative to another instance (inst2) or a port (inst2:port) with a given offset (x, y) and an angle (optional).

If angle is not specified (i.e. angle=None), then the instance will keep its original transformations. If angle is specified, the original transformations will be overridden and the instance will be rotated. If you place a port and specify an angle, the port’s angle will be the given angle.

Examples

>>> # Place 'inst1' relative to 'inst2' with an offset (10, 15). Original transformations are kept.
>>> i3.PlaceRelative('inst1', 'inst2', (10, 15))
>>> # Place 'inst1' relative to 'inst2' with an offset (10, 15). Rotation of 'inst1' is 45.
>>> i3.PlaceRelative('inst1', 'inst2', (10, 15), angle=45)
>>> # Place port 'out' of 'inst1' (with port angle 180 degrees) relative to port 'in' from 'inst2' with an offset (10, 0).
>>> i3.PlaceRelative('inst1:out', 'inst2:in', (10, 0), angle=180)
>>> # Place port 'out' of 'inst1' relative to port 'in' from 'inst2' with an offset (-10, -10). Original transformations are kept.
>>> i3.PlaceRelative('inst1:out', 'inst2:in', (-10, -10))

Below a few examples that illustrate how to use the PlaceRelative spec to put instances or ports relative to other instances. In the examples we use LayoutCell to quickly visualize the results.

import ipkiss3.all as i3
from pylab import plt

wg1 = i3.RoundedWaveguide().Layout(shape=[
  (0, 0),
  (10, 0),
])

wg2 = i3.RoundedWaveguide().Layout(shape=[
  (-5, 0),
  (0, 0),
  (10, 10),
])

insts = i3.place_insts({
  'wg1': wg1,
  'wg2': wg2
}, [
  # this specifies that the origin '(0, 0)' of 'wg1' should be at (10, 0) and that 'wg2' should be placed 10 micron
  # further in both X and Y direction, relative to 'wg1'.
  i3.Place('wg1', (10, 0)),
  i3.PlaceRelative('wg2', 'wg1', (10, 10))
])

i3.LayoutCell().Layout(instances=insts, ports=insts['wg1'].ports + insts['wg2'].ports).visualize(annotate=True)
ax = plt.gca()
ax.hlines(xmin=-20, xmax=20, y=0, linestyle='dashed')
ax.vlines(ymin=-20, ymax=20, x=0, linestyle='dashed')
../../../_images/ipkiss3-all-PlaceRelative-1.png

Instead of specifying the position of the origin of an instance, we can also specify that a port should be placed relative to another instance or its port.

insts = i3.place_insts({
  'wg1': wg1,
  'wg2': wg2
}, [
  # We specify that the 'in' port of 'wg2' should be placed 10 micron further in both X and Y direction.
  # (This corresponds to (20, 10)).
  i3.Place('wg1', (10, 0)),
  i3.PlaceRelative('wg2:in', 'wg1', (10, 10) )
])

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wg1'].ports + insts['wg2'].ports)
lv.visualize(annotate=True)
ax = plt.gca()
ax.hlines(xmin=-20, xmax=20, y=0, linestyle='dashed')
ax.vlines(ymin=-20, ymax=20, x=0, linestyle='dashed')
../../../_images/ipkiss3-all-PlaceRelative-2.png

By default the transformation of the instance or the port remains untouched. But by specifying the angle attribute, we can place the instance or port with a different rotation. In this case the original transformation of the instance is discarded.

insts = i3.place_insts({
  'wg1': wg1,
  'wg2': wg2
}, [
  # origin of 'wg1' must be at (0, 0) and 'wg2' must be placed relative to 'wg1' and have an angle of 45.
  i3.Place('wg1', (0, 0)),
  i3.PlaceRelative('wg2', 'wg1', (10, 10), angle=45)
])

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wg1'].ports + insts['wg2'].ports)
lv.visualize(annotate=True)
ax = plt.gca()
ax.hlines(xmin=-20, xmax=20, y=0, linestyle='dashed')
ax.vlines(ymin=-20, ymax=20, x=0, linestyle='dashed')
../../../_images/ipkiss3-all-PlaceRelative-3.png

This works as well for ports:

insts = i3.place_insts({
  'wg1': wg1,
  'wg2': wg2
}, [
  # port 'wg2:out' must be at (15, 10) further than 'wg1' with an angle of 90 deg.
  i3.Place('wg1', (0, 0)),
  i3.PlaceRelative('wg2:in', 'wg1', (15, 10), angle=90)
])

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wg1'].ports + insts['wg2'].ports)
lv.visualize(annotate=True)
ax = plt.gca()
ax.hlines(xmin=-20, xmax=20, y=0, linestyle='dashed')
ax.vlines(ymin=-20, ymax=20, x=0, linestyle='dashed')
../../../_images/ipkiss3-all-PlaceRelative-4.png

Use the FlipH/FlipV specs to declare that you want to place a mirrored version of your component.

insts = i3.place_insts({
  'wg1': wg1,
  'wg2': wg2
}, [
  # Place a horizontally mirrored instance of 'wg2' instead of the normal one.
  i3.FlipH('wg2'),
  i3.Place('wg1', (0, 0)),
  i3.PlaceRelative('wg2', 'wg1', (10, 10))
])

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wg1'].ports + insts['wg2'].ports)
lv.visualize(annotate=True)
ax = plt.gca()
ax.hlines(xmin=-20, xmax=20, y=0, linestyle='dashed')
ax.vlines(ymin=-20, ymax=20, x=0, linestyle='dashed')
../../../_images/ipkiss3-all-PlaceRelative-5.png

When you’re providing an already rotated instance as input to place_insts and don’t specify the angle attribute of PlaceRelative, the transformation (in this case a rotation) will be kept.

insts = i3.place_insts(i3.InstanceDict([
  i3.SRef(name='wg1',
          reference=wg1,
          transformation=i3.Rotation(rotation=45.)),
  i3.SRef(name='wg2',
          reference=wg2,
          transformation=i3.Rotation(rotation=45.))
]), [
  i3.Place('wg1', (-10, 0)),
  i3.PlaceRelative('wg2', 'wg1', (20, 10))
])

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wg1'].ports + insts['wg2'].ports)
lv.visualize(annotate=True)
ax.hlines(xmin=-20, xmax=20, y=0, linestyle='dashed')
ax.vlines(ymin=-20, ymax=20, x=0, linestyle='dashed')
../../../_images/ipkiss3-all-PlaceRelative-6.png