components.py 23.2 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 *
Daniel Brown's avatar
Daniel Brown committed
18

19
20
next_component_id = 1

21
22
class NodeGaussSetter(object):
    def __init__(self, component, node):                
Daniel Brown's avatar
Daniel Brown committed
23
24
25
26
        self.__comp = component
        self.__node = node
    
    @property
27
28
    def node(self):
        return self.__node
Daniel Brown's avatar
Daniel Brown committed
29
30
    
    @property
31
32
33
    def q(self):
        return self.__node.qx
        
Daniel Brown's avatar
Daniel Brown committed
34
35
    @q.setter
    def q(self, value):
36
        self.__node.setGauss(self.__comp, complex(value))
Daniel Brown's avatar
Daniel Brown committed
37
38
        
    @property
39
40
    def qx(self):
        return self.__node.qx
Daniel Brown's avatar
Daniel Brown committed
41
42
    @qx.setter
    def qx(self, value):
43
        self.__node.setGauss(self.__comp, complex(value))
Daniel Brown's avatar
Daniel Brown committed
44
45
    
    @property
46
47
    def qy(self):
        return self.__node.qy
Daniel Brown's avatar
Daniel Brown committed
48
49
    @qy.setter
    def qy(self, value):
50
        self.__node.setGauss(self.__comp, self.qx, complex(value))
51
        
52
53
54
class Component(object):
    __metaclass__ = abc.ABCMeta
    
55
    def __init__(self, name):
Daniel Brown's avatar
Daniel Brown committed
56
57
        self.__name = name
        self._svgItem = None
58
59
        self._requested_node_names = []
        self._kat = None
Daniel Brown's avatar
Daniel Brown committed
60
        self.tag = None
61
62
63
64
65
66
        
        # store a unique ID for this component
        global next_component_id
        self.__id = next_component_id
        next_component_id += 1
        
67
68
69
70
71
72
        # 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,), {})
            
73
74
    def _on_kat_add(self, kat):
        """
75
76
77
78
        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.
79
        """
80
81
82
        if self._kat != None:
            raise pkex.BasePyKatException("Component has already been added to a finesse.kat object")
            
83
84
        self._kat = kat
        
85
        kat.nodes.registerComponentNodes(self, self._requested_node_names, self.__on_node_change)
86
        
87
    def __on_node_change(self):
88
        # need to update the node gauss parameter setter members 
Daniel Brown's avatar
Daniel Brown committed
89
        self.__update_node_setters()
90
91
92
93
94
95
        
    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
96
        
97
98
99
        # now we have a list of which to remove
        for key in key_rm:
            ns = self.__dict__[key]
100
101
            delattr(self, '__nodesetter_' + ns.node.name)
            delattr(self.__class__, ns.node.name)
Daniel Brown's avatar
Daniel Brown committed
102
        
103
        for node in self.nodes:
Daniel Brown's avatar
Daniel Brown committed
104
105
106
            if type(node) != pykat.node_network.DumpNode:
                ns = NodeGaussSetter(self, node)
                self.__add_node_setter(ns)
107
108
109
110
111
112
        
    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
113
        name = ns.node.name
114
115
        fget = lambda self: self.__get_node_setter(name)
        
116
        setattr(self.__class__, name, property(fget))
117
118
119
120
        setattr(self, '__nodesetter_' + name, ns)                   

    def __get_node_setter(self, name):
        return getattr(self, '__nodesetter_' + name)   
121
122
        
    @staticmethod
123
124
125
    @abc.abstractmethod
    def parseFinesseText(text):
        """Parses Finesse syntax"""
126
        raise NotImplementedError("This function is not implemented")
127
128

    @abc.abstractmethod
Daniel Brown's avatar
Daniel Brown committed
129
    def getFinesseText(self):
130
        """ Base class for individual Finesse optical components """    
Daniel Brown's avatar
Daniel Brown committed
131
        raise NotImplementedError("This function is not implemented")
132

133
    @abc.abstractmethod
Daniel Brown's avatar
Daniel Brown committed
134
135
    def getQGraphicsItem(self):    
        return None      
136
137
138
    
    @property
    def nodes(self): return self._kat.nodes.getComponentNodes(self) 
139
140
141
142
143
144
145
    
    @property    
    def name(self): return self.__name      
    
    @property
    def id(self): return self.__id
    
146
147
    def __str__(self): return self.name
    
148
149
class Param(float):
    def __new__(self,name,value):
150
        return float.__new__(self,SIfloat(value))
151
         
Daniel Brown's avatar
Daniel Brown committed
152
153
154
    def __init__(self,name,value):
        self.__name = name
        
155
    name = property(lambda self: self.__name)
Daniel Brown's avatar
Daniel Brown committed
156

157
158
159
160
161
162
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)

163
164
165
166
167
168
169
        self.__R = SIfloat(R)
        self.__T = SIfloat(T)
        self.__phi = SIfloat(phi)
        self.__Rcx = SIfloat(Rcx)
        self.__Rcy = SIfloat(Rcy)
        self.__xbeta = SIfloat(xbeta)
        self.__ybeta = SIfloat(ybeta)
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
        self.__mass = SIfloat(mass)
        self.__r_ap = SIfloat(r_ap)

    def getAttributeText(self):
        rtn = []
        
        if self.Rcx != 0: rtn.append("attr {0} Rcx {1}".format(self.name,self.__Rcx))
        if self.Rcy != 0: rtn.append("attr {0} Rcy {1}".format(self.name,self.__Rcy))
        if self.xbeta != 0: rtn.append("attr {0} xbeta {1}".format(self.name,self.__xbeta))
        if self.ybeta != 0: rtn.append("attr {0} ybeta {1}".format(self.name,self.__ybeta))
        if self.mass != 0: rtn.append("attr {0} mass {1}".format(self.name,self.__mass))
        if self.r_ap != 0: rtn.append("attr {0} r_ap {1}".format(self.name,self.__r_ap))
        
        return rtn
        
Daniel Brown's avatar
Daniel Brown committed
185
    @property
186
    def r_ap(self): return Param('r_ap', self.__r_ap)
Daniel Brown's avatar
Daniel Brown committed
187
    @r_ap.setter
188
    def r_ap(self,value): self.__aperture = SIfloat(value)
Daniel Brown's avatar
Daniel Brown committed
189

190
191
192
    @property
    def mass(self): return Param('mass', self.__mass)
    @mass.setter
193
    def mass(self,value): self.__mass = SIfloat(value)
194
    
195
    @property
196
    def R(self): return Param('R', self.__R)
197
    @R.setter
198
    def R(self,value): self.__R = SIfloat(value)
199
    
200
201
202
    @property
    def T(self): return Param('T', self.__T)
    @T.setter
203
    def T(self,value): self.__T = SIfloat(value)
204
205
206
207
        
    @property
    def phi(self): return Param('phi', self.__phi)
    @phi.setter
208
    def phi(self,value): self.__phi = SIfloat(value)
209
210
211
212
    
    @property
    def Rcx(self): return Param('Rcx', self.__Rcx)
    @Rcx.setter
213
    def Rcx(self,value): self.__Rcx = SIfloat(value)
214
    
215
216
217
    @property
    def Rcy(self): return Param('Rcy', self.__Rcy)
    @Rcy.setter
218
    def Rcy(self,value): self.__Rcy = SIfloat(value)
219
220
221
222
    
    @property
    def xbeta(self): return Param('xbeta', self.__xbeta)
    @xbeta.setter
223
    def xbeta(self,value): self.__xbeta = SIfloat(value)
224
    
225
226
227
    @property
    def ybeta(self): return Param('ybeta', self.__ybeta)
    @ybeta.setter
228
    def ybeta(self,value): self.__ybeta = SIfloat(value)
229
230
231
    
    @property
    def Rc(self):
Daniel Brown's avatar
Daniel Brown committed
232
233
234
235
236
        if self.Rcx == self.Rcy:
            return self.Rcx
        else:
            return [self.Rcx, self.Rcy]
    
237
238
    @Rc.setter
    def Rc(self,value):
239
240
        self.Rcx = SIfloat(value)
        self.Rcy = SIfloat(value)
241
242
243
244
245
246
247

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)
248
249
250
251
252
    
    @staticmethod
    def parseFinesseText(text):
        values = text.split(" ")

253
        if values[0] != "m" and values[0] != "m1" and values[0] != "m2":
254
255
            raise exceptions.RuntimeError("'{0}' not a valid Finesse mirror command".format(text))
        
Andreas Freise's avatar
Andreas Freise committed
256
        if len(values) != 7:
257
258
            raise exceptions.RuntimeError("Mirror Finesse code format incorrect '{0}'".format(text))

259
        if len(values[0])==1:
Andreas Freise's avatar
Andreas Freise committed
260
            values.pop(0) # remove initial value
261
262
            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
263
264
            if values[0][1]=="1":
                values.pop(0) # remove initial value
265
266
                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
267
                values.pop(0) # remove initial value
268
269
                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
270
271
    def getFinesseText(self):        
        rtn = []
272
            
Daniel Brown's avatar
Daniel Brown committed
273
        rtn.append('m {0} {1} {2} {3} {4} {5}'.format(
274
                self.name, self.R, self.T, self.phi,
275
                self.nodes[0].name, self.nodes[1].name))
Daniel Brown's avatar
Daniel Brown committed
276

277
        rtn.extend(super(mirror, self).getAttributeText())
Daniel Brown's avatar
Daniel Brown committed
278
279
280
281
282
        
        return rtn
        
    def getQGraphicsItem(self):
        if self._svgItem == None:
283
            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
284
            
Daniel Brown's avatar
Daniel Brown committed
285
        return self._svgItem
Sean Leavey's avatar
Sean Leavey committed
286

287
288
289
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
        
        self._requested_node_names.append(node1)
        self._requested_node_names.append(node2)
        self._requested_node_names.append(node3)
        self._requested_node_names.append(node4)
             
        self.__alpha = SIfloat(alpha)
    
    @property
    def alpha(self): return Param('alpha', self.__alpha)
    @alpha.setter
    def alpha(self,value): self.__alpha = SIfloat(value)
    
    @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])
            
324
    def getFinesseText(self):
Sean Leavey's avatar
Sean Leavey committed
325
326
327
        rtn = []
            
        rtn.append('bs {0} {1} {2} {3} {4} {5} {6} {7} {8}'.format(
328
329
                self.name, self.R, self.T, self.phi,
                self.alpha, self.nodes[0].name,
Sean Leavey's avatar
Sean Leavey committed
330
331
332
                self.nodes[1].name, self.nodes[2].name,
                self.nodes[3].name))

333
        rtn.extend(super(beamSplitter, self).getAttributeText())
Sean Leavey's avatar
Sean Leavey committed
334
335
336
337
338
339
340
341
342
        
        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
343
344
   
class space(Component):
345
    def __init__(self, name, node1, node2, L=0, n=1):
346
        Component.__init__(self, name)
Daniel Brown's avatar
Daniel Brown committed
347
        
348
349
        self._requested_node_names.append(node1)
        self._requested_node_names.append(node2)
350
        self._QItem = None
Andreas Freise's avatar
Andreas Freise committed
351
352
        self.__L = SIfloat(L)
        self.__n = SIfloat(n)
353
354
355
356
        
    @property
    def L(self): return Param('L', self.__L)
    @L.setter
Andreas Freise's avatar
Andreas Freise committed
357
    def L(self,value): self.__L = SIfloat(value)
358
359
360
    @property
    def n(self): return Param('n', self.__n)
    @n.setter
Andreas Freise's avatar
Andreas Freise committed
361
    def n(self,value): self.__n = SIfloat(value)
362
    
363
364
365
366
367
368
369
370
371
372
    @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
373
            return space(values[0], values[3], values[4], values[1], values[2])
374
        elif len(values) == 4:
Sean Leavey's avatar
Sean Leavey committed
375
            return space(values[0], values[2], values[3], values[1])
376
377
378
        else:
            raise exceptions.RuntimeError("Space Finesse code format incorrect '{0}'".format(text))
        
Daniel Brown's avatar
Daniel Brown committed
379
    def getFinesseText(self):
380
        if self.__n == 1:
381
            return 's {0} {1} {2} {3}'.format(self.name, self.__L, self.nodes[0].name, self.nodes[1].name)            
Daniel Brown's avatar
Daniel Brown committed
382
        else:
383
            return 's {0} {1} {2} {3} {4}'.format(self.name, self.__L, self.__n, self.nodes[0].name, self.nodes[1].name)            
Daniel Brown's avatar
Daniel Brown committed
384
       
385
386
    def getQGraphicsItem(self):
        if self._QItem == None:
387
            self._QItem = pykat.gui.graphics.SpaceQGraphicsItem(self)
388
        
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
        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
        self.__d = SIfloat(d)
        self.__eta_0 = SIfloat(eta_0)
        self.__eta_1 = SIfloat(eta_1)
        self.__eta_2 = SIfloat(eta_2)
        self.__eta_3 = SIfloat(eta_3)
        self.__rho_0 = SIfloat(rho_0)
        self.__alpha = SIfloat(alpha)
    
    @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
    def d(self): return Param('d', self.__d)
    @d.setter
    def d(self, value): self.__d = SIfloat(value)
    
    @property
    def eta_0(self): return Param('eta_0', self.__eta_0)
    @eta_0.setter
    def eta_0(self, value): self.__eta_0 = SIfloat(value)
    
    @property
    def eta_1(self): return Param('eta_1', self.__eta_1)
    @eta_1.setter
    def eta_1(self, value): self.__eta_1 = SIfloat(value)
    
    @property
    def eta_2(self): return Param('eta_2', self.__eta_2)
    @eta_2.setter
    def eta_2(self, value): self.__eta_2 = SIfloat(value)
    
    @property
    def eta_3(self): return Param('eta_3', self.__eta_3)
    @eta_3.setter
    def eta_3(self, value): self.__eta_3 = SIfloat(value)
    
    @property
    def rho_0(self): return Param('rho_0', self.__rho_0)
    @rho_0.setter
    def rho_0(self, value): self.__rho_0 = SIfloat(value)
    
    @property
    def alpha(self): return Param('alpha', self.__alpha)
    @alpha.setter
    def alpha(self, value): self.__alpha = SIfloat(value)
    
    @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:
484
485
486
            if len(values) != 4:
                raise exceptions.RuntimeError("Two port grating must have 2 nodes defined")

487
488
            return grating(values[0], values[2], values[3], None, None, n, values[1])
        elif n == 3:
489
490
491
            if len(values) != 5:
                raise exceptions.RuntimeError("Three port grating must have 3 nodes defined")
            
492
493
            return grating(values[0], values[2], values[3], values[4], None, n, values[1])
        else:
494
495
496
            if len(values) != 6:
                raise exceptions.RuntimeError("Four port grating must have 4 nodes defined")
            
497
498
499
            return grating(values[0], values[2], values[3], values[4], values[5], n, values[1])
        
    def getFinesseText(self):
500
501
        rtn = []
        
502
        if self.__n == 2:
503
            rtn.append('gr{0} {1} {2} {3} {4}'.format(self.__n, self.name, self.__d, self.nodes[0].name, self.nodes[1].name))
504
        elif self.__n == 3:
505
            rtn.append('gr{0} {1} {2} {3} {4} {5}'.format(self.__n, self.name, self.__d, self.nodes[0].name, self.nodes[1].name, self.nodes[2].name))
506
        else:
507
508
509
510
511
512
513
514
515
516
517
            rtn.append('gr{0} {1} {2} {3} {4} {5} {6}'.format(self.__n, self.name, self.__d, self.nodes[0].name, self.nodes[1].name, self.nodes[2].name, self.nodes[3].name))
        
        if self.eta_0 != 0: rtn.append("attr {0} eta_0 {1}".format(self.name,self.__eta_0))
        if self.eta_1 != 0: rtn.append("attr {0} eta_1 {1}".format(self.name,self.__eta_1))
        if self.eta_2 != 0: rtn.append("attr {0} eta_2 {1}".format(self.name,self.__eta_2))
        if self.eta_3 != 0: rtn.append("attr {0} eta_3 {1}".format(self.name,self.__eta_3))
        if self.rho_0 != 0: rtn.append("attr {0} rho_0 {1}".format(self.name,self.__rho_0))
        if self.alpha != 0: rtn.append("attr {0} alpha {1}".format(self.name,self.__alpha))
        # TODO: implement Rcx, Rcy, Rc
        
        return rtn
518
519
520
521
522
523
       
    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
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560

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)
        
        self.__S = SIfloat(S)
        
    @property
    def S(self): return Param('S', self.__S)
    @S.setter
    def S(self, value): self.__S = SIfloat(value)
    
    @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):
        return 'isol {0} {1} {2} {3}'.format(self.name, self.S, self.nodes[0].name, self.nodes[1].name)            

    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
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597

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)
        
        self.__f = SIfloat(f)
        
    @property
    def f(self): return Param('f', self.__f)
    @f.setter
    def f(self, value): self.__f = SIfloat(value)
    
    @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):
        return 'lens {0} {1} {2} {3}'.format(self.name, self.f, self.nodes[0].name, self.nodes[1].name)            

    def getQGraphicsItem(self):
        if self._QItem == None:
            self._QItem = pykat.gui.graphics.SpaceQGraphicsItem(self) # TODO: make lens graphic
        
        return self._QItem
598
    
Daniel Brown's avatar
Daniel Brown committed
599
class laser(Component):
600
601
602
603
    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
604
        
605
606
607
        self.__power = float(P)
        self.__f_offset = float(f_offset)
        self.__phase = float(phase)
Daniel Brown's avatar
Daniel Brown committed
608
        
609
610
611
    @property
    def power(self): return Param('P', self.__power)
    @power.setter
612
    def power(self,value): self.__power = float(value)
613
614
615
616
    
    @property
    def f_offset(self): return Param('f', self.__f_offset)
    @f_offset.setter
617
    def f_offset(self,value): self.__f_offset = float(value)
618
619
620
621
    
    @property
    def phase(self): return Param('phase', self.__phase)
    @phase.setter
622
    def phase(self,value): self.__phase = float(value)
623
    
624
625
626
627
628
629
630
631
632
633
634
635
636
637
    @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
638
            raise exceptions.FinesseParse("Laser Finesse code format incorrect '{0}'".format(text))
639
    
Daniel Brown's avatar
Daniel Brown committed
640
    def getFinesseText(self):
641
        return 'l {0} {1} {2} {3} {4}'.format(self.name, self.__power, self.__f_offset, self.__phase, self.nodes[0].name)            
Daniel Brown's avatar
Daniel Brown committed
642
643
644
         
    def getQGraphicsItem(self):
        if self._svgItem == None:
645
            self._svgItem = pykat.gui.graphics.ComponentQGraphicsItem(":/resources/laser.svg", self, [(65,25,self.nodes[0])])
Daniel Brown's avatar
Daniel Brown committed
646
647
648
            
        return self._svgItem