param.py 9.31 KB
Newer Older
1
2
3
4
5
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
6
7
import abc
import pykat.exceptions as pkex
8
9
import weakref
    
Daniel Brown's avatar
Daniel Brown committed
10
11
12
13
14
class putable(object):
    """
    Objects that inherit this should be able to have something `put` to it.
    Essentially this means you could write Finesse commands like
    
15
16
    param.put(kat.xaxis.x)
    
Daniel Brown's avatar
Daniel Brown committed
17
18
19
20
21
22
23
    """
    __metaclass__ = abc.ABCMeta
    
    def __init__(self, component_name, parameter_name, isPutable=True):
        self._parameter_name = parameter_name
        self._component_name = component_name
        self._putter = None
24
        self._alt = False
Daniel Brown's avatar
Daniel Brown committed
25
26
27
28
29
        self._isPutable  = isPutable
    
    @property
    def isPutable(self): return self._isPutable
    
30
    def put(self, var, alt=False):
31
32
33
        if not self._isPutable:
            raise pkex.BasePyKatException("Can't put to this object")
            
34
        if var is not None and not isinstance(var, putter):
35
            raise pkex.BasePyKatException("`%s` was not something that can be `put` to a parameter" % str(var))
Daniel Brown's avatar
Daniel Brown committed
36
        
37
        # Remove existing puts
38
39
        if self._putter is not None:
            self._putter.unregister(self)
Daniel Brown's avatar
Daniel Brown committed
40
        
41
        self._putter = var
42
            
43
        self._alt = alt
44
        
45
46
        if var is not None:
            self._putter.register(self)
Daniel Brown's avatar
Daniel Brown committed
47
48
49
        
    def _getPutFinesseText(self):
        rtn = []
50
51

        if self._isPutable and self._putter is not None:
52
            putter_enabled = True
53
54
55
                
            if hasattr(self._putter.owner, 'enabled'):
                putter_enabled = self._putter.owner.enabled
56
57
58
59
60
61
62
63
                                
            if putter_enabled:
                if self._alt:
                    alt = '*'
                else:
                    alt = ''
    
                # if something is being put to this 
64
                rtn.append("put{alt} {comp} {param} ${value}".format(alt=alt, comp=self._component_name, param=self._parameter_name, value=self._putter.put_name()))
Daniel Brown's avatar
Daniel Brown committed
65
66
        
        return rtn
67
68
        
        
Daniel Brown's avatar
Daniel Brown committed
69
70
71
72
73
74
class putter(object):
    """
    If an object can be put to something that is putable it should inherit this
    object.
    """
    
75
    def __init__(self, put_name, owner, isPutter=True):
Daniel Brown's avatar
Daniel Brown committed
76
77
78
        self._put_name = put_name
        self.put_count = 0
        self._isPutter = isPutter
79
        self.putees = [] # list of params that this puts to
80
        
81
        assert(owner is not None)
82
        self.__owner = weakref.ref(owner)
83
    
84
85
86
87
    def _updateOwner(self, newOwner):
        del self.__owner
        self.__owner = weakref.ref(newOwner)
        
88
    def clearPuts(self):
Daniel Brown's avatar
Daniel Brown committed
89
        for _ in self.putees.copy():
90
91
92
            _.put(None)
    
    def register(self, toput):
93
94
95
        if not self._isPutter:
            raise pkex.BasePyKatException("This object can't put")
            
96
97
98
99
        self.put_count += 1
        self.putees.append(toput)
    
    def unregister(self, item):
100
101
102
        if not self._isPutter:
            raise pkex.BasePyKatException("This object can't put")
            
103
104
105
        self.put_count -= 1
        self.putees.remove(item)
        
106
    @property
107
    def owner(self): return self.__owner()
108
109
110
111
112
113
    
    @property
    def name(self): return self._put_name
    
    @property
    def putCount(self): return self.put_count
Daniel Brown's avatar
Daniel Brown committed
114
115
116
117
118
119
120
121
122
    
    @property
    def isPutter(self): return self._isPutter
    
    def put_name(self): return self._put_name
    
        
class Param(putable, putter):

123
    def __init__(self, name, owner, value, canFsig=False, fsig_name=None, isPutable=True, isPutter=True, isTunable=True, var_name=None, register=True):
Daniel Brown's avatar
Daniel Brown committed
124
        self._name = name
125
        self._registered = register
126
        self._owner = weakref.ref(owner)
Daniel Brown's avatar
Daniel Brown committed
127
128
129
        self._value = value
        self._isPutter = isPutter
        self._isTunable = isTunable
130
131
        self._canFsig = False
        
132
133
134
        if self._registered:
            self._owner()._register_param(self)
        
135
136
        if canFsig:
            self._canFsig = True
137
            
138
            if fsig_name is None:
139
                raise pkex.BasePyKatException("If parameter is a possible fsig target the fsig_name argument must be set")
140
                
141
            self.__fsig_name = fsig_name
Daniel Brown's avatar
Daniel Brown committed
142
143
        
        if isPutter:
144
            if var_name is None:
Daniel Brown's avatar
Daniel Brown committed
145
146
                var_name = "var_{0}_{1}".format(owner.name, name)
                
147
        putter.__init__(self, var_name, owner, isPutter)
Daniel Brown's avatar
Daniel Brown committed
148
            
149
150
        putable.__init__(self, owner.name, name, isPutable)
        
151
152
153
    @property
    def canFsig(self): return self._canFsig
    
154
155
156
    @property
    def owner(self): return self._owner()
    
157
158
159
    @property
    def fsig_name(self): return self.__fsig_name
    
160
161
162
    @property
    def fsigName(self): return self.__fsig_name
    
Daniel Brown's avatar
Daniel Brown committed
163
164
165
166
167
168
169
    @property
    def name(self): return self._name
    
    @property
    def isTuneable(self): return self._isTunable
    
    @property
170
171
172
173
174
175
    def value(self):
        if self._owner().removed:
            raise pkex.BasePyKatException("{0} has been removed from the simulation".format(self._owner().name))
        else:
            return self._value
    
Daniel Brown's avatar
Daniel Brown committed
176
177
    @value.setter
    def value(self, value):
178
179
180
181
182
183
184
185
        if self._owner().removed:
            raise pkex.BasePyKatException("{0} has been removed from the simulation".format(self._owner().name))
        else:
            self._value = value
    
    def __str__(self):
        if self._owner().removed:
            raise pkex.BasePyKatException("{0} has been removed from the simulation".format(self._owner().name))
186
187
        elif type(self.value) == float:
            return repr(self.value)
188
189
190
191
192
193
194
        else:
            return str(self.value)
            
    def __float__(self):
        if self._owner().removed:
            raise pkex.BasePyKatException("{0} has been removed from the simulation".format(self._owner().name))
        else:
195
            return float(self.value)
Daniel Brown's avatar
Daniel Brown committed
196
197
        
    def getFinesseText(self):
198
199
200
        if self._owner().removed:
            raise pkex.BasePyKatException("{0} has been removed from the simulation".format(self._owner().name))
            
Daniel Brown's avatar
Daniel Brown committed
201
202
203
204
205
206
207
        rtn = []
        
        if self.isPutable: rtn.extend(self._getPutFinesseText())
        
        # if this parameter is being put somewhere then we need to
        # set it as a variable
        if self.isPutter and self.put_count > 0:
208
            rtn.append("set {put_name} {comp} {param}".format(put_name=self.put_name(), comp=self._owner().name, param=self.name))
Daniel Brown's avatar
Daniel Brown committed
209
210
        
        return rtn
211
212
213
214
215
216
217
218
219
220
        
    def _updateOwner(self, newOwner):
        """
        This updates the internal weak reference to link a parameter to who owns it.
        Should only be called by the __deepcopy__ component method to ensure things
        are kept up to date.
        """
        del self._owner
        self._owner = weakref.ref(newOwner)
        
221
222
223
224
    def _onOwnerRemoved(self):
        #if this param can be put somewhere we need to check if it is
        if self.isPutable:
            for a in self.putees:
225
                print ("Removing put from {0} {1} to {2} {3}".format(self.owner.name, self.name, a.owner.name, a.name))
226
227
228
229
230
231
232
233
234
                a._putter = None
                self.put_count -= 1
                
            # delete any references left over
            del self.putees[:]
        
        # check if we have anything being put to us
        if self.isPutter:
            if self._putter != None:
235
                print ("Removing put from {0} {1} to {2} {3}".format(self._putter.owner.name, self._putter.name, self.owner.name, self.name))
236
237
238
239
240
                self._putter.put_count -= 1
                self._putter.putees.remove(self)
                self._putter = None
       
       
Daniel Brown's avatar
Daniel Brown committed
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
    def __mul__(self, a):
        return self.value * a
    
    def __imul__(self, a):
        return self.value * (a)
        
    __rmul__ = __mul__
    
    def __add__(self, a):
        return self.value + (a)
    
    def __iadd__(self, a):
        return self.value + (a)
        
    __radd__ = __add__
    
    def __sub__(self, a):
        return self.value - (a)
    
    def __isub__(self, a):
        return self.value - (a)
        
263
264
    def __rsub__(self, a):
        return (a) - self.value
Daniel Brown's avatar
Daniel Brown committed
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
    
    def __div__(self, a):
        return self.value / (a)
    
    def __idiv__(self, a):
        return self.value / complex(a)
        
    def __pow__(self, q):
        return  self.value**q

    def __neg__(self):
        return -self.value
        
    def __eq__(self, q):
        return (q) == self.value
    def __ne__(self, q):
        return (q) != self.value
    def __lt__(self, q):
        return (q) > self.value
    def __gt__(self, q):
        return (q) < self.value        
        
class AttrParam(Param):
    """
    Certain parameters of a component are set using the Finesse `attr` command.
    
    This inherits directly from a Param object so can be set whether this attribute
    is putable or a putter.
    
    If the value pf the parameter is not 0 the attr command will be printed.
    """
    def getFinesseText(self):
297
298
299
        if self._owner().removed:
            raise pkex.BasePyKatException("{0} has been removed from the simulation".format(self._owner().name))

Daniel Brown's avatar
Daniel Brown committed
300
301
        rtn = []
        
302
        if self.value != None:
303
            rtn.append("attr {0} {1} {2}".format(self._owner().name, self.name, self.value))
Daniel Brown's avatar
Daniel Brown committed
304
305
306
            
        rtn.extend(super(AttrParam, self).getFinesseText())
        
307
        return rtn
308
309