ipkiss3.all.Place

class ipkiss3.all.Place(pos_selector, position, angle=None)

Specifies that an instance or its port should be placed on a given position and angle (angle is 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 specify an angle and choose to place a port that has an angle, then the instance is rotated such that the port’s angle will equal this desired angle.

If you place a port with an undefined port angle (angle=None), and you specify an angle in Place, then the port’s angle will stay ‘None’ but its instance will be rotated.

Examples

>>> i3.Place('inst', (0, 0))                 # Place 'inst' at (0, 0), original transformations are kept
>>> i3.Place('inst', (0, 0), angle=90)       # Place 'inst at (0, 0) with a rotation of 90 degrees, original transformations are discarded
>>> i3.Place('inst:out', (0, 0))             # Place port 'out' of 'inst' at (0, 0) with the angle of the port of the instance
>>> i3.Place('inst:out', (0, 0), angle=90)   # Place port 'out' of 'inst' (original port angle = 180) at (0, 0), with port angle 90 degrees, original transformations are discarded
>>> i3.Place('inst:out', (0, 0), angle=90)   # Place port 'out' of 'inst' (original port angle is None) at (0, 0), with a rotation of 90 degrees, original transformations are discarded

Below a few examples that illustrate how to use the Place spec to put instances or ports on a specified position. In the examples we use LayoutCell to quickly visualize the results.

Optical components

import ipkiss3.all as i3
from pylab import plt

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

insts = i3.place_insts({
  'wg': wg
}, [
  # this specifies that the origin '(0, 0)' of 'wg' should be at (10, 0)
  i3.Place('wg', (10, 0))
])

i3.LayoutCell().Layout(instances=insts, ports=insts['wg'].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-Place-1.png

Instead of specifying the position of the origin of an instance, we can also specify that a port should be placed at a given position.

insts = i3.place_insts({
  'wg': wg
}, [
  # We specify that the 'out' port of 'wg' should be at (10, 0)
  i3.Place('wg:out', (10, 0))
])

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wg'].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-Place-2.png

By default the rotation 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.

insts = i3.place_insts({
  'wg': wg
}, [
  # origin of 'wg' must be at (0, 0) with an angle of 45 deg
  i3.Place('wg', (0, 0), angle=45)
])

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wg'].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-Place-3.png

This works as well for ports:

insts = i3.place_insts({
  'wg': wg
}, [
  # port 'wg:out' must be at (0, 0) with an angle of 90 deg
  i3.Place('wg:out', (0, 0), angle=90)
])

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wg'].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-Place-4.png

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

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

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wg'].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-Place-5.png

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

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

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wg'].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-Place-6.png

Electrical components

The examples above are easily replicated in the electrical domain by changing i3.RoundedWaveguide to i3.ElectricalWire. For example:

import ipkiss3.all as i3
from pylab import plt

wire = i3.ElectricalWire().Layout(shape=[
  (-10, 0),
  (0, 0),
  (10, 10),
])

insts = i3.place_insts({
  'wire': wire
}, [
  # We specify that the 'out' port of 'wire' should be at (10, 0)
  i3.Place('wire:out', (10, 0))
])

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wire'].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-Place-7.png

The results will mostly be the same, but there is a difference when placing electrical ports and specifiying an angle. If the angle is undefined (which may happen with some type of electrical ports), its instance is rotated instead:

insts = i3.place_insts({
  'wire': wire
}, [
  # port 'wire:out' must be at (0, 0) with its instance rotated 90 degress.
  i3.Place('wire:out', (0, 0), angle=90)
])

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wire'].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-Place-8.png

Compare this to the same situation in the optical domain:

insts = i3.place_insts({
  'wg': wg
}, [
  # port 'wg:out' must be at (0, 0) with an angle of 90 deg
  i3.Place('wg:out', (0, 0), angle=90)
])

lv = i3.LayoutCell().Layout(instances=insts, ports=insts['wg'].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-Place-9.png

Note

If the electrical ports have defined port angles (just like optical ports), then the placement specifications of those ports will work exactly the same as with optical ports.