BYUCamachoLab / simphony

A simulator for photonic integrated circuits.
https://simphonyphotonics.rtfd.io
Other
119 stars 35 forks source link

Component with arbitrary number of ports loaded from numerical s-parameter data #90

Closed Andeloth closed 1 year ago

Andeloth commented 1 year ago

It would be good to have some kind of component that can be used to represent an arbitary s-matrix that was simulated in Lumerical for example. Something along these lines would be good:

def custom_component_factory(wl: np.ndarray, s: np.ndarray):
    assert np.ndim(wl) == 1
    assert np.ndim(s) == 3
    assert wl.size == s.shape[0]
    assert s.shape[1] == s.shape[2]
    nports = s.shape[1]

    class ArbitraryComponent(Model):

        ocount=nports

        def __init__(self, wl:np.ndarray, s:np.ndarray):
            self.wl = wl
            self.s = s

        def s_params(self, wl):
            return interpolate(wl, self.wl, self.s)

    return ArbitraryComponent(wl, s)

I used a factory function because I'm not sure that there is another way to dynamically set the number of ports in a class (not instance) variable. Maybe an overloaded init function would work that called this function and returned this? Don't really know.

sequoiap commented 1 year ago

So you want something along the lines of

def custom_component_factory(name: str, wl: np.ndarray, s: np.ndarray):
    def s_params(self, wl):
        return interpolate(wl, self.wl, self.s)

    return type(name, (Model,), {ocount=s.shape[1], wl=wl, s=s, s_params=s_params}

which is really just the same as

def s_params(self, wl):
    return interpolate(wl, self.wl, self.s)

my_models = []
for (name, wl, s) in my_collection:
    my_models.append(type(name, (Model,), {ocount=s.shape[1], wl=wl, s=s, s_params=s_params}))

which is a one=-liner. I don't see a reason to implement a function so that you can replace a one-liner with a different one-liner. We can document this method of creating dynamic models in a tutorial, but I don't think we'll add it to the codebase.