Porting circuit models from Ipkiss 3.1.2 to Ipkiss 3.1.3

Old and new style circuit models are compatible with each other. More specifically, a circuit can have both CapheSModelView (old), CapheModelFromNetlist (old) and CircuitModelView (new) views. This compatibility allows a smooth transition from the old to the new syntax for defining compact models.

It is however recommended to move models to the new syntax, for robustness, stability, and ease of use. See the circuitmodel tutorial for more information on how to build new style models.

Below are two of the most common situations that occur when building models, and how the code is converted to the new syntax.

  1. Converting a compact model with an S-matrix

A CapheSModelView that defines an S-matrix used to be written as shown below:

class MyWaveguide(i3.PCell):

    class Netlist(i3.NetlistView):
        def _generate_terms(self, terms):
            terms += i3.OpticalTerm(name='in')
            terms += i3.OpticalTerm(name='out')
            return terms

    class CapheModel(i3.CapheSModelView):
        length = i3.PositiveNumberProperty(doc="Waveguide length", default=100)
        n_eff = i3.PositiveNumberProperty(doc="Effective index", default=2.4)

        def _calculate_S(self, environment, term1, term2, mode1, mode2):
            phase = 2 * np.pi / environment.wavelength * self.n_eff * self.length
            A = 0.99
            if term1.name == 'in' and term2.name == 'out':
                return A * np.exp(1j * phase)
            if term1.name == 'out' and term2.name == 'in':
                return A * np.exp(1j * phase)
            if term1.name == 'in' and term2.name == 'in':
                return 0
            if term1.name == 'out' and term2.name == 'out':
                return 0

This now becomes:

class MyWaveguideModel(i3.CompactModel):
    parameters = ['n_eff', 'length']
    terms = [i3.OpticalTerm(name='in'), i3.OpticalTerm(name='out')]

    def calculate_smatrix(parameters, env, S):
        phase = 2 * np.pi / env.wavelength * parameters.n_eff * parameters.length
        A = 0.99
        S['in', 'out'] = A * np.exp(1j * phase)
        S['out', 'in'] = A * np.exp(1j * phase)
        S['in', 'in'] = 0.0
        S['out', 'out'] = 0.0

class MyWaveguide(i3.PCell):

    class Netlist(i3.NetlistView):
        def _generate_terms(self, terms):
            terms += i3.OpticalTerm(name='in')
            terms += i3.OpticalTerm(name='out')
            return terms

    class CircuitModel(i3.CircuitModelView):
        length = i3.PositiveNumberProperty(doc="Waveguide length", default=100)
        n_eff = i3.PositiveNumberProperty(doc="Effective index", default=2.4)

        def _generate_model(self):
            return MyWaveguideModel(length=self.length, n_eff=self.n_eff)
  1. Converting a hierarchical model

A hierarchical model:

class MyCircuit(i3.PCell):

    class Netlist(i3.NetlistView):
        # defining the netlist here

    class CapheModel(i3.CapheModelFromNetlist):
        pass

Now becomes:

class MyCircuit(i3.PCell):

    class Netlist(i3.NetlistView):
        # defining the netlist here

    class CircuitModel(i3.CircuitModelView):
        def _generate_model(self):
            return i3.HierarchicalModel.from_netlistview(self.netlist_view)