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.