Skip to content
Snippets Groups Projects
Select Git revision
  • b1276f51ef68af67e5b0e9e3ca90564a165c490c
  • master default protected
  • v0.1
3 results

projection_matrix.py

Blame
  • commands.py 18.62 KiB
    # -*- coding: utf-8 -*-
    """
    Created on Mon Jan 28 11:58:09 2013
    
    @author: Daniel
    """
    from __future__ import absolute_import
    from __future__ import division
    from __future__ import print_function
    from __future__ import unicode_literals
    
    import numpy
    import pykat.external.six as six
    import pykat.exceptions as pkex
    
    if six.PY2:
    	import exceptions
        
    from pykat.components import *
    from pykat.structs import *
    from numpy import min, max
    from pykat.param import Param, putter
    from collections import namedtuple
    from pykat.optics.gaussian_beams import beam_param
    
    
    
    
    class Command(object):
        __metaclass__ = abc.ABCMeta
        
        def __init__(self, name, unique):
            self.__unique = unique
            self.tag = None
            self.__removed = False
            self.__name = name.strip("*")
            self._putters = []
        
        def __deepcopy__(self, memo):
            """
            When deep copying a kat object we need to take into account
            the instance specific properties.
            """
    
            cls = self.__class__
            result = cls.__new__(cls)
            result.__dict__ = copy.deepcopy(self.__dict__, memo)
            
            for _ in result._putters:
                _._updateOwner(result)
            
            return result
                
        def getFinesseText(self):
            """ Base class for individual finesse optical components """
            raise NotImplementedError("This function is not implemented")
    
        @staticmethod
        def parseFinesseText(line, kat):
            raise NotImplementedError("This function is not implemented")
    
        def _on_kat_add(self, kat):
            """
            Called when this component has been added to a kat object
            """
            self._kat = kat
            
            for _ in self._putters:
                kat.registerVariable(_.name, _)
    
        def _on_kat_remove(self):
            self.__removed = True
            
            for i in range(len(self._putters)):
                _ = self._putters[i]
                
                self._kat.unregisterVariable(_.name)
                _.clearPuts()
            
            for i in range(len(self._putters)):  
                del self._putters[0]
                
            del self._putters[:]
            
            
        def remove(self):
            if self.__removed:
                raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
            else:
                self._kat.remove(self)
        
        @property
        def name(self): return self.__name
        
        @property
        def removed(self): return self.__removed
    
    
    
    
    
    class variable(Command):
        def __init__(self, name, value):
            Command.__init__(self, name, False)
            self.__value = value
        
        def getFinesseText(self):
            return "variable {name} {value}".format(name=self.name, value=self.value)
        
        @staticmethod
        def parseFinesseText(line, kat):
            v = line.split()
            
            if len(v) != 3:
                raise pkex.BasePyKatException("'{0}' not a valid Finesse variable command".format(line))
            
            return variable(v[1], SIfloat(v[2]))
        
        @property
        def value(self): return self.__value
        @value.setter
        def value(self, Value): self.__value = SIfloat(Value)
    
    
    
    
    
    class func(Command):
        def __init__(self, name, value):
            Command.__init__(self, name, False)
            
            self.value = value
            self.noplot = False
            self.enabled = True
            
            self.output = putter(name, self)
            self._putters.append(self.output)
            
        def getFinesseText(self):
            rtn = []
    
            if self.enabled:
                if self.noplot:
                    rtn.append("noplot " + self.name)
            
                rtn.append("func {name} = {value}".format(name=self.name, value=str(self.value)))
    
            return rtn
    
        @staticmethod
        def parseFinesseText(line, kat):
            v = line.split(None, 3)
            v2 = line.split("=", 2)
            
            if "=" in v and len(v) == 4:
                v.remove("=")
                return func(v[1], v[2]) 
            if len(v2) == 2:
                return func(v2[0].split()[1], v2[1]) 
            else:
                raise pkex.BasePyKatException("'{0}' not a valid Finesse func command".format(line))
                
    
    class lock(Command):
        def __init__(self, name, variable, gain, accuracy, singleLock=False):
            Command.__init__(self, name, False)
            
            self.__variable = variable
            self.__gain = gain
            self.__accuracy = accuracy
            self.singleLock = singleLock
            self.enabled = True
            
            
            self.output = putter(name, self)
            self._putters.append(self.output)
    
    
        @staticmethod
        def parseFinesseText(line, kat):
            v = line.split()
            
            if len(v) != 5:
                raise pkex.BasePyKatException("'{0}' not a valid Finesse lock command".format(line))
                
            return lock(v[1], v[2], SIfloat(v[3]), SIfloat(v[4]), "*" in v[0])
    
    
        def getFinesseText(self):
            if self.enabled:
                cmds = "{name} {var} {gain} {accuracy}".format( name=self.name,
                                                                var=str(self.variable),
                                                                gain=str(self.gain),
                                                                accuracy=str(self.accuracy))
                
                if self.singleLock:
                    return "lock* %s" % cmds
                else:
                    return "lock %s" % cmds
            else:
                return None
    
        @property
        def variable(self): return self.__variable
        @variable.setter
        def variable(self, value): self.__variable = value
    
        @property
        def gain(self): return self.__gain
        @gain.setter
        def gain(self, value): self.__gain = SIfloat(value)
    
        @property
        def accuracy(self): return self.__accuracy
        @accuracy.setter
        def accuracy(self, value): self.__accuracy = SIfloat(value)
    
    
    
    class cavity(Command):
        def __init__(self, name, c1, n1, c2, n2):
            Command.__init__(self, name, False)
            
            self.__c1 = c1
            self.__c2 = c2
            self.__n1 = n1
            self.__n2 = n2
            
            self.enabled = True
    
        def getFinesseText(self):
            if self.enabled:
                return 'cav {0} {1} {2} {3} {4}'.format(self.name, self.__c1.name, self.__n1.name, self.__c2.name, self.__n2.name);
            else:
                return None
    
        @staticmethod
        def parseFinesseText(line, kat):
            v = line.split()
            
            if len(v) != 6:
                raise pkex.BasePyKatException("cav command format `{0}` is incorrect".format(line))
            
            if v[2] not in kat.components:
                raise pkex.BasePyKatException("cav command `{0}` refers to component `{1}` which does not exist".format(line, v[2]))
            
            if v[4] not in kat.components:
                raise pkex.BasePyKatException("cav command `{0}` refers to component `{1}` which does not exist".format(line, v[4]))
            
            if v[3] not in kat.nodes.getNodes():
                raise pkex.BasePyKatException("cav command `{0}` refers to node `{1}` which does not exist".format(line, v[3]))
            
            if v[5] not in kat.nodes.getNodes():
                raise pkex.BasePyKatException("cav command `{0}` refers to node `{1}` which does not exist".format(line, v[5]))
            
            c1 = getattr(kat, v[2])
            c2 = getattr(kat, v[4])
            
            n1 = getattr(kat.nodes, v[3])
            n2 = getattr(kat.nodes, v[5])
            
            if not hasattr(c1, n1.name):
                raise pkex.BasePyKatException("cav command `{0}`: node `{1}` is not attached to `{2}`".format(line, n1.name, c1.name))
            
            if not hasattr(c2, n2.name):
                raise pkex.BasePyKatException("cav command `{0}`: node `{1}` is not attached to `{2}`".format(line, n2.name, c2.name))
                
            return pykat.commands.cavity(v[1], c1, n1, c2, n2)
            
            
    class gauss(object):
        @staticmethod
        def parseFinesseText(text, kat):
            
            values = text.split()
            if not values[0].startswith("gauss") or (len(values) != 6 and len(values) != 8):
                raise pkex.BasePyKatException("'{0}' not a valid Finesse gauss command".format(text))        
            
            name = values[1]
            component = values[2]
            node = values[3]
            
            # setting the name of the gauss parameter is slightly convoluted
            # as we don't explicitly store gauss paramters as an object, they
            # are simply just complex numbers stored at each node. To fix this
            # the name is stored in the NodeGaussSetter object for each component
            
            if component in kat.components:
                c = kat.components[component]
                if hasattr(c, node):
                    ns = getattr(c, node)
                    ns.name = name
                else:
                    raise pkex.BasePyKatException("Component '{0}' is not attached to node {1}".format(component, node))        
            else:
                raise pkex.BasePyKatException("Component '{0}' was not found".format(component))        
            
            if not values[0].endswith("*"):
                if len(values) == 6:
                    gp = beam_param(kat.lambda0, w0=values[-2], z=values[-1])
                elif len(values) == 8:
                    gpx = beam_param(kat.lambda0, w0=values[-4], z=values[-3])
                    gpy = beam_param(kat.lambda0, w0=values[-2], z=values[-1])
            elif values[0].endswith("*"):
                if len(values) == 6:
                    gp = beam_param(kat.lambda0, z=values[-2], zr=values[-1])
                elif len(values) == 8:
                    gpx = beam_param(kat.lambda0, z=values[-4], zr=values[-3])
                    gpy = beam_param(kat.lambda0, z=values[-2], zr=values[-1])
            elif values[0].endswith("**"):
                if len(values) == 6:
                    gp = beam_param(kat.lambda0, w=values[-2], rc=values[-1])
                elif len(values) == 8:
                    gpx = beam_param(kat.lambda0, w=values[-4], rc=values[-3])
                    gpy = beam_param(kat.lambda0, w=values[-2], rc=values[-1])
            else:
                raise pkex.BasePyKatException("Unexpected ending to gauss command '{0}'".format(text))
                
            if len(values) == 6:
                kat.nodes[node].setGauss(kat.components[component], gp)
            else:
                kat.nodes[node].setGauss(kat.components[component], gpx, gpy)
     
    # class tf(Command):
    #
    #     class fQ(object):
    #         def __init__(self, f, Q, tf):
    #             assert(tf is not None)
    #             self._tf = tf
    #             self.__f = Param("f", self, None, canFsig=False, isPutable=True, isPutter=False, isTunable=True)
    #             self.__Q = Param("Q", self, None, canFsig=False, isPutable=True, isPutter=False, isTunable=True)
    #
    #         def _register_param(self, param):
    #             self._tf._params.append(param)
    #
    #         @property
    #         def f(self): return self.__f
    #         @f.setter
    #         def f(self,value): self.__f.value = SIfloat(value)
    #
    #         @property
    #         def Q(self): return self.__Q
    #         @Q.setter
    #         def Q(self,value): self.__Q.value = SIfloat(value)
    #
    #     def __init__(self, name):
    #         Command.__init__(self, name, False)
    #         self.zeros = []
    #         self.poles = []
    #         self.gain = 1
    #         self.phase = 0
    #         self._params = []
    #
    #     def addPole(self,f, Q):
    #         self.poles.append(tf.fQ(SIfloat(f), SIfloat(Q), self))
    #
    #     def addZero(self,f, Q):
    #         self.zeros.append(tf.fQ(SIfloat(f), SIfloat(Q), self))
    #
    #     @staticmethod
    #     def parseFinesseText(text):
    #         values = text.split()
    #
    #         if ((len(values)-4) % 3) != 0:
    #             raise pkex.BasePyKatException("Transfer function Finesse code format incorrect '{0}'".format(text))
    #
    #         _tf = tf(values[1])
    #
    #         _tf.gain = SIfloat(values[2])
    #         _tf.phase = SIfloat(values[3])
    #
    #         N = int((len(values)-4) / 3)
    #
    #         for i in range(1,N+1):
    #             if values[i*3+1] == 'p':
    #                 _tf.addPole(SIfloat(values[i*3+2]), SIfloat(values[i*3+3]))
    #             elif values[i*3+1] == 'z':
    #                 _tf.addZero(SIfloat(values[i*3+2]), SIfloat(values[i*3+3]))
    #             else:
    #                 raise pkex.BasePyKatException("Transfer function pole/zero Finesse code format incorrect '{0}'".format(text))
    #
    #         return _tf
    #
    #     def getFinesseText(self):
    #         rtn = "tf {name} {gain} {phase} ".format(name=self.name,gain=self.gain,phase=self.phase)
    #
    #         for p in self.poles:
    #             rtn += "p {f} {Q} ".format(f=p.f, Q=p.Q)
    #
    #         for z in self.zeros:
    #             rtn += "p {f} {Q} ".format(f=z.f, Q=z.Q)
    #
    #         return rtn
                       
    class tf(Command):
        
        class fQ(object):
            def __init__(self, f, Q):
                self.f = f
                self.Q = Q
                
        def __init__(self, name):
            Command.__init__(self, name, False)
            self.zeros = []
            self.poles = []
            self.gain = 1
            self.phase = 0
        
        def addPole(self,f, Q):
            self.poles.append(tf.fQ(SIfloat(f), SIfloat(Q)))
        
        def addZero(self,f, Q):
            self.zeros.append(tf.fQ(SIfloat(f), SIfloat(Q)))
        
        @staticmethod
        def parseFinesseText(text):
            values = text.split()
            
            if ((len(values)-4) % 3) != 0:
                raise pkex.BasePyKatException("Transfer function Finesse code format incorrect '{0}'".format(text))
    
            _tf = tf(values[1])
            
            _tf.gain = SIfloat(values[2])
            _tf.phase = SIfloat(values[3])
            
            N = int((len(values)-4) / 3)
            
            for i in range(1,N+1):
                if values[i*3+1] == 'p':
                    _tf.addPole(SIfloat(values[i*3+2]), SIfloat(values[i*3+3]))
                elif values[i*3+1] == 'z':
                    _tf.addZero(SIfloat(values[i*3+2]), SIfloat(values[i*3+3]))
                else:
                    raise pkex.BasePyKatException("Transfer function pole/zero Finesse code format incorrect '{0}'".format(text))
        
            return _tf
            
        def getFinesseText(self):
            rtn = "tf {name} {gain} {phase} ".format(name=self.name,gain=self.gain,phase=self.phase)
            
            for p in self.poles:
                rtn += "p {f} {Q} ".format(f=p.f, Q=p.Q)
            
            for z in self.zeros:
                rtn += "p {f} {Q} ".format(f=z.f, Q=z.Q)
            
            return rtn
            
    class xaxis(Command):
        """
        The xaxis object is a unique object to each pykat.finesse.kat instance. It provides
        and interface to the xaxis command in FINESSE.
        """
        
        def __init__(self, scale, limits, param, steps, comp=None, axis_type="xaxis"):
            """
            Typical usage:
                xaxis(["lin" or "log"], [upper, lower], param, steps)
                
            param must be an object of the type pykat.param.Param whose
            isPutable() member returns true.
            
            steps is the number of points to compute between upper and lower limits.
            """
            Command.__init__(self, axis_type, True)
            
            self._axis_type = axis_type
            
            self._set_variables()
            
            if scale == "lin":
                scale = Scale.linear
            elif scale == "log":
                scale = Scale.logarithmic
            elif isinstance(scale, six.string_types):
                # else we have a string but not a recognisable one
                raise pkex.BasePyKatException("scale argument '{0}' is not valid, must be 'lin' or 'log'".format(scale))
    
            if scale != Scale.linear and scale != Scale.logarithmic:
                raise pkex.BasePyKatException("scale is not Scale.linear or Scale.logarithmic")
    
            self.scale = scale
    
            if numpy.size(limits) != 2 :
                raise pkex.BasePyKatException("limits input should be a 2x1 vector of limits for the xaxis")
    
            self.limits = numpy.array(SIfloat(limits)).astype(float)
    
            if int(steps) <= 0 :
                raise pkex.BasePyKatException("steps value should be > 0")
    
            self.steps = int(steps)
    
            if isinstance(param, six.string_types):
                self.__param = param
                if comp == None:
                    raise pkex.BasePyKatException("If parameter is set with a string, the comp argument must set the component name")
                    
                self.__comp = comp
            elif not isinstance(param, Param) :
                raise pkex.BasePyKatException("param argument is not of type Param")
            else:
                self.__param = param
                self.__comp = param._owner()
    
        def _set_variables(self):
            self.x = putter("x1", self)
            self.mx = putter("mx1", self)
    
            self._putters.append(self.x)
            self._putters.append(self.mx)
            
        @property
        def param(self): return self.__param
        @param.setter
        def param(self, value):
            if not isinstance(value, Param):
                raise pkex.BasePyKatException("param argument is not of type Param")
            else:
                self.__param = value
                self.__comp = value._owner()
                
        @staticmethod
        def parseFinesseText(text):
            values = text.split()
    
            if values[0] != "xaxis" and values[0] != "xaxis*":
                raise pkex.BasePyKatException("'{0}' not a valid Finesse xaxis command".format(text))
    
            axis_type = values[0]
    
            values.pop(0) # remove initial value
    
            if len(values) != 6:
                raise pkex.BasePyKatException("xaxis Finesse code format incorrect '{0}'".format(text))
    
            return xaxis(values[2], [values[3], values[4]], values[1], values[5], comp=values[0], axis_type=axis_type)
    
        def getFinesseText(self):
            if(self._kat.noxaxis):
                return '# noaxis is true, switching xaxis off'
            
            # store either the component name of the string provided
            comp_name = self.__comp.name if hasattr(self.__comp, "name") else self.__comp
            param_name = self.__param.name if isinstance(self.__param, Param) else self.__param
            
            return '{axis_type} {0} {1} {2} {3:.16g} {4:.16g} {5}'.format(
                    comp_name, param_name, self.scale,
                    self.limits[0], self.limits[1], self.steps, axis_type=self._axis_type);
    
    class x2axis(xaxis):
        def __init__(self, scale, limits, param, steps, comp=None, axis_type="x2axis"):
            xaxis.__init__(self, scale, limits, param, steps, comp=comp, axis_type=axis_type)
    
        def _set_variables(self):
            self.x = putter("x2", self)
            self.mx = putter("mx2", self)
    
            self._putters.append(self.x)
            self._putters.append(self.mx)
            
        @staticmethod
        def parseFinesseText(text):
            values = text.split()
    
            if values[0] != "x2axis" and values[0] != "x2axis*":
                raise pkex.BasePyKatException("'{0}' not a valid Finesse xaxis command".format(text))
    
            axis_type = values[0]
    
            values.pop(0) # remove initial value
    
            if len(values) != 6:
                raise pkex.BasePyKatException("xaxis Finesse code format incorrect '{0}'".format(text))
    
            return x2axis(values[2], [values[3], values[4]], values[1], values[5], comp=values[0],axis_type=axis_type)