components.py 25.6 KB
Newer Older
Daniel Brown's avatar
Daniel Brown committed
1
2
3
4
5
6
7
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 28 11:10:01 2013

@author: Daniel
"""
import exceptions
8
import pykat.exceptions as pkex
Daniel Brown's avatar
Daniel Brown committed
9
10
import pykat
from pykat.node_network import *
Andreas Freise's avatar
Andreas Freise committed
11
from pykat.exceptions import *
12
import abc
Daniel Brown's avatar
Daniel Brown committed
13
14
15
16

import pykat.gui.resources
import pykat.gui.graphics
from pykat.gui.graphics import *
Andreas Freise's avatar
Andreas Freise committed
17
from pykat.SIfloat import *
18
from pykat.param import Param, AttrParam
Daniel Brown's avatar
Daniel Brown committed
19

20
21
next_component_id = 1

22
23
class NodeGaussSetter(object):
    def __init__(self, component, node):                
Daniel Brown's avatar
Daniel Brown committed
24
25
26
27
        self.__comp = component
        self.__node = node
    
    @property
28
29
    def node(self):
        return self.__node
Daniel Brown's avatar
Daniel Brown committed
30
31
    
    @property
32
33
34
    def q(self):
        return self.__node.qx
        
Daniel Brown's avatar
Daniel Brown committed
35
36
    @q.setter
    def q(self, value):
37
        self.__node.setGauss(self.__comp, complex(value))
Daniel Brown's avatar
Daniel Brown committed
38
39
        
    @property
40
41
    def qx(self):
        return self.__node.qx
Daniel Brown's avatar
Daniel Brown committed
42
43
    @qx.setter
    def qx(self, value):
44
        self.__node.setGauss(self.__comp, complex(value))
Daniel Brown's avatar
Daniel Brown committed
45
46
    
    @property
47
48
    def qy(self):
        return self.__node.qy
Daniel Brown's avatar
Daniel Brown committed
49
50
    @qy.setter
    def qy(self, value):
51
        self.__node.setGauss(self.__comp, self.qx, complex(value))
52
        
53
54
55
class Component(object):
    __metaclass__ = abc.ABCMeta
    
56
    def __init__(self, name):
Daniel Brown's avatar
Daniel Brown committed
57
58
        self.__name = name
        self._svgItem = None
59
60
        self._requested_node_names = []
        self._kat = None
Daniel Brown's avatar
Daniel Brown committed
61
        self.tag = None
62
        self._params = []
63
64
65
66
67
68
        
        # store a unique ID for this component
        global next_component_id
        self.__id = next_component_id
        next_component_id += 1
        
69
70
71
72
73
        # This creates an instance specific class for the component
        # this enables us to add properties to instances rather than
        # all classes
        cls = type(self)
        self.__class__ = type(cls.__name__, (cls,), {})
74
75
76
77
    
    def _register_param(self, param):
        self._params.append(param)
        
78
79
    def _on_kat_add(self, kat):
        """
80
81
82
83
        Called when this component has been added to a kat object.
        kat is the finesse.kat object which it now belongs to and
        node_array is an array specific to this object which contains
        references to the nodes that are attached to it.
84
        """
85
86
87
        if self._kat != None:
            raise pkex.BasePyKatException("Component has already been added to a finesse.kat object")
            
88
89
        self._kat = kat
        
90
        kat.nodes.registerComponentNodes(self, self._requested_node_names, self.__on_node_change)
91
        
92
    def __on_node_change(self):
93
        # need to update the node gauss parameter setter members 
Daniel Brown's avatar
Daniel Brown committed
94
        self.__update_node_setters()
95
96
97
98
99
100
        
    def __update_node_setters(self):
        # check if any node setters have already been added. If so we
        # need to remove them. This function should get called if the nodes
        # are updated, either by some function call or the GUI
        key_rm = [k for k in self.__dict__ if k.startswith("__nodesetter_", 0, 13)]
Daniel Brown's avatar
Daniel Brown committed
101
        
102
103
104
        # now we have a list of which to remove
        for key in key_rm:
            ns = self.__dict__[key]
105
106
            delattr(self, '__nodesetter_' + ns.node.name)
            delattr(self.__class__, ns.node.name)
Daniel Brown's avatar
Daniel Brown committed
107
        
108
        for node in self.nodes:
Daniel Brown's avatar
Daniel Brown committed
109
110
111
            if type(node) != pykat.node_network.DumpNode:
                ns = NodeGaussSetter(self, node)
                self.__add_node_setter(ns)
112
113
114
115
116
117
        
    def __add_node_setter(self, ns):

        if not isinstance(ns, NodeGaussSetter):
            raise exceptions.ValueError("Argument is not of type NodeGaussSetter")
        
Daniel Brown's avatar
Daniel Brown committed
118
        name = ns.node.name
119
120
        fget = lambda self: self.__get_node_setter(name)
        
121
        setattr(self.__class__, name, property(fget))
122
123
124
125
        setattr(self, '__nodesetter_' + name, ns)                   

    def __get_node_setter(self, name):
        return getattr(self, '__nodesetter_' + name)   
126
127
        
    @staticmethod
128
129
130
    @abc.abstractmethod
    def parseFinesseText(text):
        """Parses Finesse syntax"""
131
        raise NotImplementedError("This function is not implemented")
132
133

    @abc.abstractmethod
Daniel Brown's avatar
Daniel Brown committed
134
    def getFinesseText(self):
135
        """ Base class for individual Finesse optical components """    
Daniel Brown's avatar
Daniel Brown committed
136
        raise NotImplementedError("This function is not implemented")
137

138
    @abc.abstractmethod
Daniel Brown's avatar
Daniel Brown committed
139
140
    def getQGraphicsItem(self):    
        return None      
141
142
143
    
    @property
    def nodes(self): return self._kat.nodes.getComponentNodes(self) 
144
145
146
147
148
149
150
    
    @property    
    def name(self): return self.__name      
    
    @property
    def id(self): return self.__id
    
151
152
    def __str__(self): return self.name
    
153
154
155
156
157
158
class AbstractMirrorComponent(Component):
    __metaclass__ = abc.ABCMeta
    
    def __init__(self, name, R=0, T=0, phi=0, Rcx=0, Rcy=0, xbeta=0, ybeta=0, mass=0, r_ap=0):
        super(AbstractMirrorComponent, self).__init__(name)

159
160
161
162
163
164
165
166
167
        self.__R = Param("R", self, SIfloat(R))
        self.__T = Param("T", self, SIfloat(T))
        self.__phi = Param("phi", self, SIfloat(phi))
        self.__Rcx = AttrParam("Rcx", self, SIfloat(Rcx))
        self.__Rcy = AttrParam("Rcy", self, SIfloat(Rcy))
        self.__xbeta = AttrParam("xbeta", self, SIfloat(xbeta))
        self.__ybeta = AttrParam("ybeta", self, SIfloat(ybeta))
        self.__mass = AttrParam("mass", self, SIfloat(mass))
        self.__r_ap = AttrParam("r_ap", self, SIfloat(r_ap))
168
        
Daniel Brown's avatar
Daniel Brown committed
169
    @property
170
    def r_ap(self): return self.__r_ap
Daniel Brown's avatar
Daniel Brown committed
171
    @r_ap.setter
172
    def r_ap(self,value): self.__r_ap.value = SIfloat(value)
Daniel Brown's avatar
Daniel Brown committed
173

174
    @property
175
    def mass(self): return self.__mass
176
    @mass.setter
177
    def mass(self,value): self.__mass.value = SIfloat(value)
178
    
179
    @property
180
    def R(self): return self.__R
181
    @R.setter
182
    def R(self,value): self.__R.value = SIfloat(value)
183
    
184
    @property
185
    def T(self): return self.__T
186
    @T.setter
187
    def T(self,value): self.__T.value = SIfloat(value)
188
189
        
    @property
190
    def phi(self): return self.__phi
191
    @phi.setter
192
    def phi(self,value): self.__phi.value = SIfloat(value)
193
194
    
    @property
195
    def Rcx(self): return self.__Rcx
196
    @Rcx.setter
197
    def Rcx(self,value): self.__Rcx.value = SIfloat(value)
198
    
199
    @property
200
    def Rcy(self): return self.__Rcy
201
    @Rcy.setter
202
    def Rcy(self,value): self.__Rcy.value = SIfloat(value)
203
204
    
    @property
205
    def xbeta(self): return self.__xbeta
206
    @xbeta.setter
207
    def xbeta(self,value): self.__xbeta.value = SIfloat(value)
208
    
209
    @property
210
    def ybeta(self): return self.__ybeta
211
    @ybeta.setter
212
    def ybeta(self,value): self.__ybeta.value = SIfloat(value)
213
214
215
    
    @property
    def Rc(self):
Daniel Brown's avatar
Daniel Brown committed
216
217
218
219
220
        if self.Rcx == self.Rcy:
            return self.Rcx
        else:
            return [self.Rcx, self.Rcy]
    
221
222
    @Rc.setter
    def Rc(self,value):
223
224
        self.Rcx.value = SIfloat(value)
        self.Rcy.value = SIfloat(value)
225
226
227
228
229
230
231

class mirror(AbstractMirrorComponent):
    def __init__(self,name,node1,node2,R=0,T=0,phi=0,Rcx=0,Rcy=0,xbeta=0,ybeta=0,mass=0, r_ap=0):
        super(mirror, self).__init__(name, R, T, phi, Rcx, Rcy, xbeta, ybeta, mass, r_ap)
        
        self._requested_node_names.append(node1)
        self._requested_node_names.append(node2)
232
233
234
235
236
    
    @staticmethod
    def parseFinesseText(text):
        values = text.split(" ")

237
        if values[0] != "m" and values[0] != "m1" and values[0] != "m2":
238
239
            raise exceptions.RuntimeError("'{0}' not a valid Finesse mirror command".format(text))
        
Andreas Freise's avatar
Andreas Freise committed
240
        if len(values) != 7:
241
242
            raise exceptions.RuntimeError("Mirror Finesse code format incorrect '{0}'".format(text))

243
        if len(values[0])==1:
Andreas Freise's avatar
Andreas Freise committed
244
            values.pop(0) # remove initial value
245
246
            return mirror(values[0], values[4], values[5], R=values[1], T=values[2], phi=values[3])
        else:
Andreas Freise's avatar
Andreas Freise committed
247
248
            if values[0][1]=="1":
                values.pop(0) # remove initial value
249
250
                return mirror(values[0], values[4], values[5], R=1.0-SIfloat(values[1])-SIfloat(values[2]), T=values[1], phi=values[3])
            else:
Andreas Freise's avatar
Andreas Freise committed
251
                values.pop(0) # remove initial value
252
253
                return mirror(values[0], values[4], values[5], R=values[1], T=1.0-SIfloat(values[1])-SIfloat(values[2]), phi=values[3])

Daniel Brown's avatar
Daniel Brown committed
254
255
    def getFinesseText(self):        
        rtn = []
256
            
Daniel Brown's avatar
Daniel Brown committed
257
        rtn.append('m {0} {1} {2} {3} {4} {5}'.format(
258
                self.name, self.R.value, self.T.value, self.phi.value,
259
                self.nodes[0].name, self.nodes[1].name))
Daniel Brown's avatar
Daniel Brown committed
260

261
262
263
        for p in self._params:
            rtn.extend(p.getFinesseText())
                    
Daniel Brown's avatar
Daniel Brown committed
264
265
266
267
        return rtn
        
    def getQGraphicsItem(self):
        if self._svgItem == None:
268
            self._svgItem = pykat.gui.graphics.ComponentQGraphicsItem(":/resources/mirror_flat.svg", self ,[(-4,15,self.nodes[0]), (14,15,self.nodes[1])])
Daniel Brown's avatar
Daniel Brown committed
269
            
Daniel Brown's avatar
Daniel Brown committed
270
        return self._svgItem
Sean Leavey's avatar
Sean Leavey committed
271

272
273
274
class beamSplitter(AbstractMirrorComponent):
    def __init__(self, name, node1, node2, node3, node4, R = 0, T = 0, phi = 0, alpha = 0, Rcx = 0, Rcy = 0, xbeta = 0, ybeta = 0, mass = 0, r_ap = 0):
        super(beamSplitter, self).__init__(name, R, T, phi, Rcx, Rcy, xbeta, ybeta, mass, r_ap)
Sean Leavey's avatar
Sean Leavey committed
275
276
277
278
279
280
        
        self._requested_node_names.append(node1)
        self._requested_node_names.append(node2)
        self._requested_node_names.append(node3)
        self._requested_node_names.append(node4)
             
281
        self.__alpha = AttrParam("alpha", self, SIfloat(alpha))
Sean Leavey's avatar
Sean Leavey committed
282
283
    
    @property
284
    def alpha(self): return self.__alpha
Sean Leavey's avatar
Sean Leavey committed
285
    @alpha.setter
286
    def alpha(self,value): self.__alpha.value = SIfloat(value)
Sean Leavey's avatar
Sean Leavey committed
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
    
    @staticmethod
    def parseFinesseText(text):
        values = text.split(" ")

        if values[0] != "bs" and values[0] != "bs1" and values[0] != "bs2":
            raise exceptions.RuntimeError("'{0}' not a valid Finesse beam splitter command".format(text))
        
        if len(values) != 10:
            raise exceptions.RuntimeError("Beam splitter Finesse code format incorrect '{0}'".format(text))

        if len(values[0])==1:
            values.pop(0) # remove initial value
            return beamSplitter(values[0], values[5], values[6], values[7], values[8], values[1], values[2], values[3], values[4])
        else:
            if values[0][1]=="1":
                values.pop(0) # remove initial value
                return beamSplitter(values[0], values[5], values[6], values[7], values[8], 1.0 - SIfloat(values[1]) - SIfloat(values[2]), values[1], values[3], values[4])
            else:
                values.pop(0) # remove initial value
                return beamSplitter(values[0], values[5], values[6], values[7], values[8], values[1], 1.0 - SIfloat(values[1]) - SIfloat(values[2]), values[3], values[4])
            
309
    def getFinesseText(self):
Sean Leavey's avatar
Sean Leavey committed
310
311
312
        rtn = []
            
        rtn.append('bs {0} {1} {2} {3} {4} {5} {6} {7} {8}'.format(
313
314
                self.name, self.R.value, self.T.value, self.phi.value,
                self.alpha.value, self.nodes[0].name,
Sean Leavey's avatar
Sean Leavey committed
315
316
317
                self.nodes[1].name, self.nodes[2].name,
                self.nodes[3].name))

318
319
320
        for p in self._params:
            rtn.extend(p.getFinesseText())
            
Sean Leavey's avatar
Sean Leavey committed
321
322
323
324
325
326
327
328
        return rtn
        
    def getQGraphicsItem(self):
        if self._svgItem == None:
            # FIXME: make proper SVG component for beam splitter
            self._svgItem = pykat.gui.graphics.ComponentQGraphicsItem(":/resources/mirror_flat.svg", self ,[(-4,15,self.nodes[0]), (14,15,self.nodes[1])])
            
        return self._svgItem
Daniel Brown's avatar
Daniel Brown committed
329
330
   
class space(Component):
331
    def __init__(self, name, node1, node2, L=0, n=1):
332
        Component.__init__(self, name)
Daniel Brown's avatar
Daniel Brown committed
333
        
334
335
        self._requested_node_names.append(node1)
        self._requested_node_names.append(node2)
336
        self._QItem = None
337
338
        self.__L = Param("L", self, SIfloat(L))
        self.__n = Param("n", self, SIfloat(n))
339
340
        
    @property
341
    def L(self): return self.__L
342
    @L.setter
343
    def L(self,value): self.__L,value = SIfloat(value)
344
    @property
345
    def n(self): return self.__n
346
    @n.setter
347
    def n(self,value): self.__n.value = SIfloat(value)
348
    
349
350
351
352
353
354
355
356
357
358
    @staticmethod
    def parseFinesseText(text):
        values = text.split(" ")

        if values[0] != "s":
            raise exceptions.RuntimeError("'{0}' not a valid Finesse space command".format(text))

        values.pop(0) # remove initial value
        
        if len(values) == 5:
Sean Leavey's avatar
Sean Leavey committed
359
            return space(values[0], values[3], values[4], values[1], values[2])
360
        elif len(values) == 4:
Sean Leavey's avatar
Sean Leavey committed
361
            return space(values[0], values[2], values[3], values[1])
362
363
364
        else:
            raise exceptions.RuntimeError("Space Finesse code format incorrect '{0}'".format(text))
        
Daniel Brown's avatar
Daniel Brown committed
365
    def getFinesseText(self):
366
367
        rtn = []
        
368
        if self.__n == 1:
369
            rtn.append('s {0} {1} {2} {3}'.format(self.name, self.__L.value, self.nodes[0].name, self.nodes[1].name))
Daniel Brown's avatar
Daniel Brown committed
370
        else:
371
            rtn.append('s {0} {1} {2} {3} {4}'.format(self.name, self.__L.value, self.__n.value, self.nodes[0].name, self.nodes[1].name))
Daniel Brown's avatar
Daniel Brown committed
372
       
373
374
375
376
377
        for p in self._params:
            rtn.extend(p.getFinesseText())
            
        return rtn
        
378
379
    def getQGraphicsItem(self):
        if self._QItem == None:
380
            self._QItem = pykat.gui.graphics.SpaceQGraphicsItem(self)
381
        
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
        return self._QItem

class grating(Component):
    def __init__(self, name, node1, node2, node3 = None, node4 = None, n = 2, d = 0, eta_0 = 0, eta_1 = 0, eta_2 = 0, eta_3 = 0, rho_0 = 0, alpha = 0): # TODO: implement Rcx, Rcy and Rc
        Component.__init__(self, name)
        
        self._requested_node_names.append(node1)
        self._requested_node_names.append(node2)

        if n > 2:
            if node3 != None:
                self._requested_node_names.append(node3)
            else:
                raise exceptions.RuntimeError("Grating node 3 not specified")

        if n > 3:
            if node4 != None:
                self._requested_node_names.append(node4)
            else:
                raise exceptions.RuntimeError("Grating node 4 not specified")

        if n > 4 or n < 2:
            raise exceptions.RuntimeError("Grating must have between 2 and 4 ports")
        
        self.__n = n
407
408
409
410
411
412
413
        self.__d = Param("d", self, SIfloat(d))
        self.__eta_0 = AttrParam("eta_0", self, SIfloat(eta_0))
        self.__eta_1 = AttrParam("eta_1", self, SIfloat(eta_1))
        self.__eta_2 = AttrParam("eta_2", self, SIfloat(eta_2))
        self.__eta_3 = AttrParam("eta_3", self, SIfloat(eta_3))
        self.__rho_0 = AttrParam("rho_0", self, SIfloat(rho_0))
        self.__alpha = AttrParam("alpha", self, SIfloat(alpha))
414
415
416
417
418
419
420
421
422
423
424
    
    @property
    def n(self): return Param('n', self.__n)
    @n.setter
    def n(self, value):
        if value < 2 or value > 4:
            raise exceptions.RuntimeError("Grating must have between 2 and 4 ports")
        else:
            self.__n = value
    
    @property
425
    def d(self): return self.__d
426
    @d.setter
427
    def d(self, value): self.__d.value = SIfloat(value)
428
429
    
    @property
430
    def eta_0(self): return self.__eta_0
431
    @eta_0.setter
432
    def eta_0(self, value): self.__eta_0.value = SIfloat(value)
433
434
    
    @property
435
    def eta_1(self): return self.__eta_1
436
    @eta_1.setter
437
    def eta_1(self, value): self.__eta_1.value = SIfloat(value)
438
439
    
    @property
440
    def eta_2(self): return self.__eta_2
441
    @eta_2.setter
442
    def eta_2(self, value): self.__eta_2.value = SIfloat(value)
443
444
    
    @property
445
    def eta_3(self): return self.__eta_3
446
    @eta_3.setter
447
    def eta_3(self, value): self.__eta_3.value = SIfloat(value)
448
449
    
    @property
450
    def rho_0(self): return self.__rho_0
451
    @rho_0.setter
452
    def rho_0(self, value): self.__rho_0.value = SIfloat(value)
453
454
    
    @property
455
    def alpha(self): return self.__alpha
456
    @alpha.setter
457
    def alpha(self, value): self.__alpha.value = SIfloat(value)
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
    
    @staticmethod
    def parseFinesseText(text):
        values = text.split(" ")

        if values[0][0 : 2] != "gr":
            raise exceptions.RuntimeError("'{0}' not a valid Finesse grating command".format(text))

        if len(values[0]) > 2:
            if int(values[0][2]) > 4 or int(values[0][2]) < 2:
                raise exceptions.RuntimeError("Grating must have between 2 and 4 ports")
            else:
                n = int(values[0][2])
        else:
            n = 2

        values.pop(0) # remove initial value
        
        if n == 2:
477
478
479
            if len(values) != 4:
                raise exceptions.RuntimeError("Two port grating must have 2 nodes defined")

480
481
            return grating(values[0], values[2], values[3], None, None, n, values[1])
        elif n == 3:
482
483
484
            if len(values) != 5:
                raise exceptions.RuntimeError("Three port grating must have 3 nodes defined")
            
485
486
            return grating(values[0], values[2], values[3], values[4], None, n, values[1])
        else:
487
488
489
            if len(values) != 6:
                raise exceptions.RuntimeError("Four port grating must have 4 nodes defined")
            
490
491
492
            return grating(values[0], values[2], values[3], values[4], values[5], n, values[1])
        
    def getFinesseText(self):
493
494
        rtn = []
        
495
        if self.__n == 2:
496
            rtn.append('gr{0} {1} {2} {3} {4}'.format(self.__n, self.name, self.__d.value, self.nodes[0].name, self.nodes[1].name))
497
        elif self.__n == 3:
498
            rtn.append('gr{0} {1} {2} {3} {4} {5}'.format(self.__n, self.name, self.__d.value, self.nodes[0].name, self.nodes[1].name, self.nodes[2].name))
499
        else:
500
            rtn.append('gr{0} {1} {2} {3} {4} {5} {6}'.format(self.__n, self.name, self.__d.value, self.nodes[0].name, self.nodes[1].name, self.nodes[2].name, self.nodes[3].name))
501
        
502
503
        for p in self._params:
            rtn.extend(p.getFinesseText())
504
505
        
        return rtn
506
507
508
509
510
511
       
    def getQGraphicsItem(self):
        if self._QItem == None:
            self._QItem = pykat.gui.graphics.SpaceQGraphicsItem(self) # TODO: make SVG graphic for grating
        
        return self._QItem
Sean Leavey's avatar
Sean Leavey committed
512
513
514
515
516
517
518
519

class isolator(Component):
    def __init__(self, name, node1, node2, S = 0):
        Component.__init__(self, name)
        
        self._requested_node_names.append(node1)
        self._requested_node_names.append(node2)
        
520
        self.__S = Param("S",self,SIfloat(S))
Sean Leavey's avatar
Sean Leavey committed
521
522
        
    @property
523
    def S(self): return self.__S
Sean Leavey's avatar
Sean Leavey committed
524
    @S.setter
525
    def S(self, value): self.__S.value = SIfloat(value)
Sean Leavey's avatar
Sean Leavey committed
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
    
    @staticmethod
    def parseFinesseText(text):
        values = text.split(" ")

        if values[0] != "isol":
            raise exceptions.RuntimeError("'{0}' not a valid Finesse isolator command".format(text))

        values.pop(0) # remove initial value
        
        if len(values) == 4:
            return isolator(values[0], values[2], values[3], values[1])
        else:
            raise exceptions.RuntimeError("Isolator Finesse code format incorrect '{0}'".format(text))
        
    def getFinesseText(self):
542
543
544
545
546
547
        rtn = ['isol {0} {1} {2} {3}'.format(self.name, self.S.value, self.nodes[0].name, self.nodes[1].name)]
        
        for p in self._params:
            rtn.extend(p.getFinesseText())
            
        return rtn
Sean Leavey's avatar
Sean Leavey committed
548
549
550
551
552
553

    def getQGraphicsItem(self):
        if self._QItem == None:
            self._QItem = pykat.gui.graphics.SpaceQGraphicsItem(self) # TODO: make isolator graphic
        
        return self._QItem
Sean Leavey's avatar
Sean Leavey committed
554
555
556
557
558
559
560
561

class lens(Component):
    def __init__(self, name, node1, node2, f):
        Component.__init__(self, name)
        
        self._requested_node_names.append(node1)
        self._requested_node_names.append(node2)
        
562
        self.__f = Param("f", self, SIfloat(f))
Sean Leavey's avatar
Sean Leavey committed
563
564
        
    @property
565
    def f(self): return self.__f
Sean Leavey's avatar
Sean Leavey committed
566
    @f.setter
567
    def f(self, value): self.__f.value = SIfloat(value)
Sean Leavey's avatar
Sean Leavey committed
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
    
    @staticmethod
    def parseFinesseText(text):
        values = text.split(" ")

        if values[0] != "lens":
            raise exceptions.RuntimeError("'{0}' not a valid Finesse lens command".format(text))

        values.pop(0) # remove initial value
        
        if len(values) == 4:
            return lens(values[0], values[2], values[3], values[1])
        else:
            raise exceptions.RuntimeError("Lens Finesse code format incorrect '{0}'".format(text))
        
    def getFinesseText(self):
584
585
586
587
588
589
590
        rtn = ['lens {0} {1} {2} {3}'.format(self.name, self.f.value, self.nodes[0].name, self.nodes[1].name)]
        
        for p in self._params:
            rtn.extend(p.getFinesseText())
            
        return rtn
        
Sean Leavey's avatar
Sean Leavey committed
591
592
593
594
595
    def getQGraphicsItem(self):
        if self._QItem == None:
            self._QItem = pykat.gui.graphics.SpaceQGraphicsItem(self) # TODO: make lens graphic
        
        return self._QItem
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
        
class modulator(Component):
    def __init__(self, name, f, midx, order, modulation_type, node1, node2, phase=0):
        Component.__init__(self, name)
        
        self._requested_node_names.append(node1)
        self._requested_node_names.append(node2)
        
        self.__f = Param("f", self, SIfloat(f))
        self.__midx = Param("midx", self, SIfloat(midx))
        self.__phase = Param("phase", self, SIfloat(phase))
        self.__order = order
        self.type = modulation_type
        
            
    @property 
    def f(self): return self.__f
    @f.setter
    def f(self, value): self.__f.value = SIfloat(value)
    
    @property 
    def midx(self): return self.__midx
    @midx.setter
    def midx(self, value): self.__midx.value = SIfloat(value)
    
    @property 
    def phase(self): return self.__phase
    @phase.setter
    def phase(self, value): self.__phase.value = SIfloat(value)
    
    @property 
    def order(self): return self.__order
    @order.setter
    def order(self, value):
        if order <= 1 and order > 6:
            raise pkex.BasePyKatException("modulator order must be between 1 and 6")
            
        self.__order = int(value)
    
    @property 
    def type(self): return self.__type
    @type.setter
    def type(self, value):
        if value != "am" and value != "pm":
            raise pkex.BasePyKatException("Modulator type must be am (amplitude modulation) or pm (phase modulation)")
            
        self.__type = str(value)
643
    
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
    @staticmethod
    def parseFinesseText(text):
        v = text.split(" ")

        if v[0] != "mod":
            raise exceptions.RuntimeError("'{0}' not a valid Finesse modulator command".format(text))

        v.pop(0) # remove initial value
        
        if len(v) == 7:
            return modulator(v[0], v[1], v[2], v[3], v[4], v[5], v[6])
        if len(v) == 8:
            return modulator(v[0], v[1], v[2], v[3], v[4], v[6], v[7], phase=v[5])
        else:
            raise pkex.BasePyKatException("Modulator Finesse code format incorrect '{0}'".format(text))
        
    def getFinesseText(self):
        rtn = ['mod {0} {1} {2} {3} {4} {5} {6} {7}'.format(self.name, self.f, self.midx, self.order, self.type, self.phase, self.nodes[0].name, self.nodes[1].name)]
        
        for p in self._params:
            rtn.extend(p.getFinesseText())
            
        return rtn
        
    def getQGraphicsItem(self):
        if self._QItem == None:
            self._QItem = pykat.gui.graphics.SpaceQGraphicsItem(self) # TODO: make lens graphic
        
        return self._QItem

Daniel Brown's avatar
Daniel Brown committed
674
class laser(Component):
675
676
677
678
    def __init__(self,name,node,P=1,f_offset=0,phase=0):
        Component.__init__(self,name)
        
        self._requested_node_names.append(node)
Daniel Brown's avatar
Daniel Brown committed
679
        
680
681
682
683
        self.__power = Param("P", self, SIfloat(P))
        self.__f_offset = Param("f", self, SIfloat(f_offset))
        self.__phase = Param("phase", self, SIfloat(phase))
        self.__noise = AttrParam("noise", self, 0)
Daniel Brown's avatar
Daniel Brown committed
684
        
685
    @property
686
    def power(self): return self.__power
687
    @power.setter
688
    def power(self,value): self.__power.value = float(value)
689
690
    
    @property
691
692
693
    def f(self): return self.__f_offset
    @f.setter
    def f(self,value): self.__f_offset.value = float(value)
694
695
    
    @property
696
    def phase(self): return self.__phase
697
    @phase.setter
698
    def phase(self,value): self.__phase.value = float(value)
699
    
700
701
702
703
704
705
706
707
708
709
710
711
712
713
    @staticmethod
    def parseFinesseText(text):
        values = text.split(" ")

        if values[0] != "l":
            raise exceptions.RuntimeError("'{0}' not a valid Finesse laser command".format(text))

        values.pop(0) # remove initial value
        
        if len(values) == 5:
            return laser(values[0],values[4],P=values[1],f_offset=values[2],phase=values[3])
        elif len(values) == 4:
            return laser(values[0],values[3],P=values[1],f_offset=values[2], phase=0)
        else:
Andreas Freise's avatar
Andreas Freise committed
714
            raise exceptions.FinesseParse("Laser Finesse code format incorrect '{0}'".format(text))
715
    
Daniel Brown's avatar
Daniel Brown committed
716
    def getFinesseText(self):
717
718
719
720
721
722
        rtn = ['l {0} {1} {2} {3} {4}'.format(self.name, self.__power.value, self.__f_offset.value, self.__phase.value, self.nodes[0].name)]
        
        for p in self._params:
            rtn.extend(p.getFinesseText())
        
        return rtn
Daniel Brown's avatar
Daniel Brown committed
723
724
725
         
    def getQGraphicsItem(self):
        if self._svgItem == None:
726
            self._svgItem = pykat.gui.graphics.ComponentQGraphicsItem(":/resources/laser.svg", self, [(65,25,self.nodes[0])])
Daniel Brown's avatar
Daniel Brown committed
727
728
729
            
        return self._svgItem