commands.py 10.3 KB
Newer Older
Daniel Brown's avatar
Daniel Brown committed
1
2
3
4
5
6
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 28 11:58:09 2013

@author: Daniel
"""
7
8
9
10
11
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

Daniel Brown's avatar
Daniel Brown committed
12
13
import numpy
from numpy import min,max
14
15
16
17
18
19
import pykat.external.six as six
if six.PY2:
	import exceptions
from pykat.components import *
from pykat.structs import *

Daniel Brown's avatar
Daniel Brown committed
20
from pykat.param import Param, putter
21
import pykat.exceptions as pkex
Daniel Brown's avatar
Daniel Brown committed
22
from collections import namedtuple
23
from pykat.optics.gaussian_beams import beam_param
Daniel Brown's avatar
Daniel Brown committed
24
25

class Command(object):
26
27
    __metaclass__ = abc.ABCMeta
    
28
29
    def __init__(self, name, unique):
        self.__unique = unique
30
31
        self.tag = None
        self.__removed = False
32
        self.__name = name.strip("*")
33
        
Daniel Brown's avatar
Daniel Brown committed
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    def getFinesseText(self):
        """ Base class for individual finesse optical components """
        raise NotImplementedError("This function is not implemented")

    @staticmethod
    def parseFinesseText(text):
        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

48
49
50
51
    def remove(self):
        self._kat.remove(self)
        self.__removed = True
    
52
53
54
    @property
    def name(self): return self.__name
    
55
56
57
    @property
    def removed(self): return self.__removed
    
Daniel Brown's avatar
Daniel Brown committed
58
59
class cavity(Command):
    def __init__(self, name, c1, n1, c2, n2):
60
        Command.__init__(self, name, False)
61
        
Daniel Brown's avatar
Daniel Brown committed
62
63
64
65
        self.__c1 = c1
        self.__c2 = c2
        self.__n1 = n1
        self.__n2 = n2
66
67
        
        self.enabled = True
Daniel Brown's avatar
Daniel Brown committed
68
69

    def getFinesseText(self):
70
71
72
73
        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
Daniel Brown's avatar
Daniel Brown committed
74

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
    @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)
        
        
Daniel Brown's avatar
Daniel Brown committed
109
110
111
class gauss(object):
    @staticmethod
    def parseFinesseText(text, kat):
112
        
113
        values = text.split()
114
        if not values[0].startswith("gauss") or (len(values) != 6 and len(values) != 8):
115
            raise pkex.BasePyKatException("'{0}' not a valid Finesse gauss command".format(text))        
116
        
117
118
119
120
        name = values[1]
        component = values[2]
        node = values[3]
        
Daniel Brown's avatar
Daniel Brown committed
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
        # 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))        
        
136
        if not values[0].endswith("*"):
137
            if len(values) == 6:
138
                gp = beam_param(kat.lambda0, w0=values[-2], z=values[-1])
139
            elif len(values) == 8:
140
141
                gpx = beam_param(kat.lambda0, w0=values[-4], z=values[-3])
                gpy = beam_param(kat.lambda0, w0=values[-2], z=values[-1])
142
143
        elif values[0].endswith("*"):
            if len(values) == 6:
144
                gp = beam_param(kat.lambda0, z=values[-2], zr=values[-1])
145
            elif len(values) == 8:
146
147
                gpx = beam_param(kat.lambda0, z=values[-4], zr=values[-3])
                gpy = beam_param(kat.lambda0, z=values[-2], zr=values[-1])
Daniel Brown's avatar
Daniel Brown committed
148
        elif values[0].endswith("**"):
149
            if len(values) == 6:
150
                gp = beam_param(kat.lambda0, w=values[-2], rc=values[-1])
151
            elif len(values) == 8:
152
153
                gpx = beam_param(kat.lambda0, w=values[-4], rc=values[-3])
                gpy = beam_param(kat.lambda0, w=values[-2], rc=values[-1])
Daniel Brown's avatar
Daniel Brown committed
154
155
156
        else:
            raise pkex.BasePyKatException("Unexpected ending to gauss command '{0}'".format(text))
            
Daniel Brown's avatar
Daniel Brown committed
157
158
159
160
        if len(values) == 6:
            kat.nodes[node].setGauss(kat.components[component], gp)
        else:
            kat.nodes[node].setGauss(kat.components[component], gpx, gpy)
161
            
Daniel Brown's avatar
Daniel Brown committed
162
class tf(Command):
163
    fQ = namedtuple('fQ', ['f', 'Q'])
Daniel Brown's avatar
Daniel Brown committed
164
165
    
    def __init__(self, name, poles, zeros):
166
        Command.__init__(self, name, False)
Daniel Brown's avatar
Daniel Brown committed
167
168
        pass
      
Daniel Brown's avatar
Daniel Brown committed
169
class xaxis(Command):
170
171
172
173
174
    """
    The xaxis object is a unique object to each pykat.finesse.kat instance. It provides
    and interface to the xaxis command in FINESSE.
    """
    
175
    def __init__(self, scale, limits, param, steps, comp=None, axis_type="xaxis"):
176
177
178
179
180
181
182
183
184
        """
        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.
        """
185
        Command.__init__(self, axis_type, True)
186
        
Daniel Brown's avatar
Daniel Brown committed
187
188
189
190
191
192
        self._axis_type = axis_type

        self.x = putter("x1")
        self.mx = putter("mx1")

        if scale == "lin":
193
            scale = Scale.linear
Daniel Brown's avatar
Daniel Brown committed
194
195
        elif scale == "log":
            scale = Scale.logarithmic
196
        elif isinstance(scale, six.string_types):
Daniel Brown's avatar
Daniel Brown committed
197
            # else we have a string but not a recognisable one
198
            raise pkex.BasePyKatException("scale argument '{0}' is not valid, must be 'lin' or 'log'".format(scale))
Daniel Brown's avatar
Daniel Brown committed
199
200

        if scale != Scale.linear and scale != Scale.logarithmic:
201
            raise pkex.BasePyKatException("scale is not Scale.linear or Scale.logarithmic")
Daniel Brown's avatar
Daniel Brown committed
202
203
204
205

        self.scale = scale

        if numpy.size(limits) != 2 :
206
            raise pkex.BasePyKatException("limits input should be a 2x1 vector of limits for the xaxis")
Daniel Brown's avatar
Daniel Brown committed
207
208
209

        self.limits = numpy.array(SIfloat(limits)).astype(float)

210
        if int(steps) <= 0 :
211
            raise pkex.BasePyKatException("steps value should be > 0")
Daniel Brown's avatar
Daniel Brown committed
212
213
214

        self.steps = int(steps)

215
        if isinstance(param, six.string_types):
Daniel Brown's avatar
Daniel Brown committed
216
            self.__param = param
217
218
219
220
            if comp == None:
                raise pkex.BasePyKatException("If parameter is set with a string, the comp argument must set the component name")
                
            self.__comp = comp
Daniel Brown's avatar
Daniel Brown committed
221
        elif not isinstance(param, Param) :
222
            raise pkex.BasePyKatException("param argument is not of type Param")
Daniel Brown's avatar
Daniel Brown committed
223
224
        else:
            self.__param = param
225
            self.__comp = param._owner()
Daniel Brown's avatar
Daniel Brown committed
226

227
228
229
230
    @property
    def param(self): return self.__param
    @param.setter
    def param(self, value):
231
232
233
234
235
236
        if not isinstance(value, Param):
            raise pkex.BasePyKatException("param argument is not of type Param")
        else:
            self.__param = value
            self.__comp = value._owner()
            
Daniel Brown's avatar
Daniel Brown committed
237
238
    @staticmethod
    def parseFinesseText(text):
239
        values = text.split()
Daniel Brown's avatar
Daniel Brown committed
240
241

        if values[0] != "xaxis" and values[0] != "xaxis*":
242
            raise pkex.BasePyKatException("'{0}' not a valid Finesse xaxis command".format(text))
Daniel Brown's avatar
Daniel Brown committed
243
244
245
246
247
248

        axis_type = values[0]

        values.pop(0) # remove initial value

        if len(values) != 6:
249
            raise pkex.BasePyKatException("xaxis Finesse code format incorrect '{0}'".format(text))
Daniel Brown's avatar
Daniel Brown committed
250

251
        return xaxis(values[2], [values[3], values[4]], values[1], values[5], comp=values[0], axis_type=axis_type)
Daniel Brown's avatar
Daniel Brown committed
252
253

    def getFinesseText(self):
254
255
256
        if(self._kat.noxaxis):
            return '# noaxis is true, switching xaxis off'
            
Daniel Brown's avatar
Daniel Brown committed
257
        # store either the component name of the string provided
258
        comp_name = self.__comp.name if hasattr(self.__comp, "name") else self.__comp
Daniel Brown's avatar
Daniel Brown committed
259
        param_name = self.__param.name if isinstance(self.__param, Param) else self.__param
260
        
261
        return '{axis_type} {0} {1} {2} {3:.16g} {4:.16g} {5}'.format(
Daniel Brown's avatar
Daniel Brown committed
262
263
264
265
                comp_name, param_name, self.scale,
                min(self.limits), max(self.limits), self.steps, axis_type=self._axis_type);

class x2axis(xaxis):
266
267
    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)
Daniel Brown's avatar
Daniel Brown committed
268
269
270
271
272
        self.x = putter("x2")
        self.mx = putter("mx2")

    @staticmethod
    def parseFinesseText(text):
273
        values = text.split()
Daniel Brown's avatar
Daniel Brown committed
274
275

        if values[0] != "x2axis" and values[0] != "x2axis*":
276
            raise pkex.BasePyKatException("'{0}' not a valid Finesse xaxis command".format(text))
Daniel Brown's avatar
Daniel Brown committed
277
278
279
280
281
282

        axis_type = values[0]

        values.pop(0) # remove initial value

        if len(values) != 6:
283
            raise pkex.BasePyKatException("xaxis Finesse code format incorrect '{0}'".format(text))
Daniel Brown's avatar
Daniel Brown committed
284

285
        return x2axis(values[2], [values[3], values[4]], values[1], values[5], comp=values[0],axis_type=axis_type)
286
287
288
289


class lock(Command):
    pass