Running Ipkiss 2.4 code in Ipkiss 3

Ipkiss 3.0 has a syntax which is considerably different from the Ipkiss 2.4 syntax, in order to provide features such as netlisting, device models and multiple view of the same type. A compatibility layer has been provided in order to be able to run existing scripts written for Ipkiss 2.4 on an Ipkisss 3.0 installation.

Most regular scripts should be able to run unmodified on the Ipkiss 3.0 installation. Of course, it is not possible to use the new features of 3.0 using a script in 2.4 syntax. For that you will need to port your Ipkiss 2.4 components to Ipkiss 3.0 syntax. Check out the porting guide for instructions on how to do that.

Users who build their own technology settings file, or power users who use Ipkiss base classes to build an advanced framework, will need to apply a number of changes and pay attention to a few Backward incompatible changes in Ipkiss listed in this document.

Property system

The property system received a complete overhaul in Ipkiss 3.0. A number of things have changed which may impact your current code: Most Ipkiss objects are StrongPropertyInitializer objects. This has not changed from Ipkiss 2.4 to Ipkiss 3.0, but the underlying type enforcement and caching mechanisms have changed.

Using properties on objects that don’t inherit from StrongPropertyInitializer

The following was a common pattern in Ipkiss 2.4:

class A(object):

  prop = DefinitionProperty(default="abc")

class B(A, StrongPropertyInitializer):
  pass

b = B()
print(b.prop) # This would print "abc"

This can be confusing as it might suggest that adding properties to a class that doesn’t inherit from StrongPropertyInitializer is okay. This behavior isn’t supported anymore and will now result in errors, instead you should write the following:

class A(StrongPropertyInitializer):

  prop = DefinitionProperty(default="abc")

class B(A, StrongPropertyInitializer):
  pass

b = B()
print(b.prop)

Overriding Properties with normal python attributes

In 2.4 the following behavior was possible:

class A(StrongPropertyInitializer):
  p = DefinitionProperty(default=123)

class B(A):
  p = 456

This behavior has been changed as it can result in various unexpected side-effects. If you want to override a Property to give it for example a new default value, you must create a new Property. This means that the example above would become:

class A(StrongPropertyInitializer):
  p = DefinitionProperty(default=123)

class B(A):
  p = DefinitionProperty(default=456)

Implementing Restrictions

If you have defined custom Restrictions you might need to make some modifications. If you have a simple restriction that just implements the validate method, you probably don’t need to change anything. The following restriction is for example perfectly valid code.

class EvenRestriction(_PropertyRestriction):
    """
    Restrict to even numbers
    """

    def validate(self, value, obj=None):
        return (value % 2 == 0)

However when you have a more elaborate restriction with attributes you need to take notice of a few things:

  • Use slots for your attributes
  • In your __init__ method, make sure you call the __init__ method of the super class.

Let’s clarify this with an example:

class ModRestriction(_PropertyRestriction):
    """
    Restrict to numbers that are multiple of the given modulo.
    """

    def __init__(self, modulo):
      self.mod = modulo

    def validate(self, value, obj=None):
        return (value % self.modulo == 0)

This should now become:

class ModRestriction(_PropertyRestriction):
    """
    Restrict to numbers that are multiple of the given modulo.
    """
    __slots__ = ('mod',)

    def __init__(self, modulo):
      self.mod = modulo
      super(ModRestriction, self).__init__()

    def validate(self, value, obj=None):
        return (value % self.mod == 0)

Creating classes with definition names that are not declared at first

Consider the following IPKISS 2.4 class:

class MyBaseClass(StrongPropertyInitializer):
    p1 = DefinitionProperty(fdef_name="function_that_doesn_exist_yet")

As you can see, this class has one property, p1, which is defined by calling function_that_doesn_exist_yet. When creating a new class, the following would succeed in IPKISS 2.4:

>>> a = MyBaseClass()

As you can see, the class is successfully created, even if the function to define p1 does not yet exist. The old IPKISS version would fail when asking the value for p1:

>>> print a.p1
AttributeError: 'MyBaseClass' object has no attribute 'function_that_doesn_exist_yet'

In IPKISS 3, this error is caught earlier on, at class creation. Example:

>>> a = MyBaseClass()
ipcore.exceptions.exc.IpcoreAttributeException: Required property 'p1' is not found in keyword arguments of '<class 'MyBaseClass'>' initialization.

It calculated that p1 should be required, and since it wasn’t passed during instantiation, it throws an error. The following would have worked: a = MyBaseClass(p1=4).

Of course, the real use case is when a new class inherits from MyBaseClass, implementing the function_that_doesn_exist_yet function:

class MyParentClass(MyBaseClass):
    def function_that_doesn_exist_yet(self):
        return 5

Which, in both IPKISS versions, yields the same behavior, i.e.:

>>> b = MyParentClass()
>>> print b.p1
5

Number properties are cast to the correct type

As of IPKISS 3.0.1, number properties behave slightly different: basic type (bool, int, float, complex) properties (such as BoolProperty, IntProperty, NumberProperty and ComplexNumberProperty) always cast the assigned value to the correct type. For example:

  • when 1 is passed to a BoolProperty, it is converted to True.

  • when True is passed to a IntProperty, it is converted to 1.

  • when 1 is passed to a NumberProperty (equivalent to FloatProperty), it is converted to 1.0.

  • when 1 is passed to a ComplexNumberProperty, it is converted to 1.0 + 1j.

  • from ipkiss3 import all as i3
    class A(i3.StrongPropertyInitializer):
         p1 = i3.FloatProperty()
    
  • >>> a = A(p1=4)
    >>> a.p1
    4.0
    

There are several reasons for this slight change in behavior:

  • Ensuring consistency: a property denoted as a ComplexNumberProperty should really contain a complex number, and not possibly an integer value.
  • When IPKISS is interfaced with other frameworks (such as Caphe, OpenAccess, or an EDA tool), enforcing the correct types improves consistency and stability of the overall framework.
  • (more technical reason: ) atom, the framework upon which IPKISS is based, work with the same principles.
  • Additional information can be found in :ref:porting301-guide .

Leading and trailing underscores

Ipkiss 3.0 has been made more PEP-8 [1] compliant. As a result, several symbols which were not intended to be used by the user have been renamed. In particular:

  • Several base classes in Ipkiss had a leading and trailing double underscore. These have been renamed to have a single leading underscore and no trailing underscore. Hence, they are now normal symbols for internal use, and not “magic” names anymore. If you have subclassed from these base classes in order to implement your own functionality, you will need to adapt their names in your code.

    Ipkiss 2.4 Ipkiss 3.0
    __PropertyRestriction__ _PropertyRestriction
    __PropertyRestrictionAnd__ _PropertyRestrictionAnd
    __PropertyRestrictionOr__ _PropertyRestrictionOr
    __PropertyRestrictionNot__ _PropertyRestrictionNot
    __BasePropertyDescriptor__ _BasePropertyDescriptor
    __CompoundPropertyProcessor__ _CompoundPropertyProcessor
    __Procedure__ _Procedure
    __Processor__ _Processor
    __StopCriterium__ _StopCriterium
    __Element__ _Element
    __ShapeElement__ _ShapeElement
    __LayerElement__ _LayerElement
    __Group__ _Group
    __BaseWaveguideElement__ _BaseWaveguideElement
    __Aspect__ _Aspect
    __Port__ _Port
    __InPort__ _InPort
    __OutPort__ _OutPort
    __OrientedPort__ _OrientedPort
    __OutOfPlanePort__ _OutOfPlanePort
  • Secondly, a number of class methods or attributes which had leading and trailing double underscores where renamed:

    Ipkiss 2.4 Ipkiss 3.0
    TypedList.__item_type__ TypedList._item_type
    PropertyInitializer.__externally_set_properties__ PropertyInitializer._externally_set_properties
    PropertyInitializer.__unlocked_properties__ PropertyInitializer._unlocked_properties

The notable exception to this is __name_prefix__, which was kept since it is a frequently used attribute. This only holds for Ipkiss 2.4 Structures though - for all new-style PCells however, _name_prefix should be used to alter the naming prefix of the parametric cell.

Layout

Magnification

In IPKISS 2.4, the magnification function rounds integers. For example (for a more elaborate example, see samples/ipkiss/elements.py):

coordinates = Shape([(-179,54), (101,54), (101,149), (59,149)],
                    closed = True)
coordinates.magnify((0.0, 0.0), 0.1)

print coordinates.points

would print

[[-17   5]
 [ 10   5]
 [ 10  14]
 [  5  14]]

In Ipkiss 3.0, the magnification will not round the numbers:

print coordinates.points

yields

[[-17.9   5.4]
 [ 10.1   5.4]
 [ 10.1  14.9]
 [  5.9  14.9]]

This is equal to the behavior when using Python3 compared to Python2. For example, in Python 2:

>>> print 2/3
0

In Python 3:

>>> print 2/3
0.666

Technology files

Ipkiss 3.0 requires a number of new entries in the TECH settings tree: TECH.PCELLS, TECH.TRACE, TECH.DEFAULT_WAVELENGTH, WG_DEFAULTS. Also, in the baseline technology settings trees (default_ipkiss, si_photonics.ipkiss and si_photonics.picazzo), a number of entries were moved from the si_photonics settings to the default_ipkiss settings.

  • If you have your own technology file which directly imports technologies.default_ipkiss or technologies.si_photonics.picazzo.default, then probably your scripts will run as is without modification

  • If you have copied and altered technologies.default_ipkiss or one of the other files, then some entries will be missing. We provide an extra package which you can import that will give you a large chance of not needing further modifications. Just import it after your tech file as follow:

    from my_own_tech import *
    from technologies.compat24.default_ipkiss import *
    
  • If you experience problems, contact us for support

Mixing 3.0 and 2.4 syntax

In Ipkiss 2.4, parametric cells were called Structures and only held layout elements and ports. In Ipkiss 3.0, the PCell is the new datastructure encapsulating all information about a parametric cell. A PCell has Views which define the information relevant to specific parts of the design flow: layout, netlist, Caphe model, etc. Hence, the Ipkiss 2.4 syntax is much more limited and suitable for layout information.

Mixing 2.4 and 3.0 syntax within one design is currently not officially supported. Any design doing so will only be fully functional on the layout level.

Advanced users can try it but should consider a few issues.

  • Ipkiss 2.4 Structures behave like the Layout view of an Ipkiss 3.0 PCell, but don’t have exactly the same API. You can refer to Ipkiss 2.4 Structures from within the Layout view of a PCell using reference elements (SRef, ARef) in the _default_elements() method. When doing so, they will not be recognized as proper Ipkiss 3 child cells (which are defined using ChildCellProperty). Neither can they be taken into account for circuit simulation using Caphe. You can also assign an Ipkiss 2.4 Structure object to a ChildCellProperty of a PCell, but that PCell should then not have any Netlist or CapheModel views.
  • In Ipkiss 2.4, waveguides were elements (groups of geometric shapes drawn on layers), hence the ‘waveguide definitions’ like WgElDefinition are generating waveguide elements. In Ipkiss 3.0, waveguides are (parametric) cells on their own right. In addition, they are derived from the more generic ‘trace templates’ concept. It is difficult to mix TraceTemplates (Ipkiss 3.0)and WaveguideDefinitions (Ipkiss 2.4) in one component.
[1]https://www.python.org/dev/peps/pep-0008/