node_network.py 9.21 KB
Newer Older
Daniel Brown's avatar
Daniel Brown committed
1
2
3
4
5
6
7
# -*- coding: utf-8 -*-
"""
Created on Sun Jan 27 10:02:41 2013

@author: Daniel
"""
import exceptions
8
import pykat.gui.graphics
9
import pykat.exceptions as pkex
Daniel Brown's avatar
Daniel Brown committed
10
11
12
from pykat.components import Component
from pykat.detectors import Detector

13
class NodeNetwork(object):
Daniel Brown's avatar
Daniel Brown committed
14
    def __init__(self, kat):
15
        self.__nodes = {}
Daniel Brown's avatar
Daniel Brown committed
16
        self.__kat = kat
17
18
19
20
21
        self.__nodeComponents = {} # dictionary of tuples containing which components are connected to a node
        self.__componentNodes = {} # dictionary of tuples containing which nodes are connected to a given component
        self.__componentCallback = {}
        self.__node_id = 1
        
22
23
24
        cls = type(self)
        self.__class__ = type(cls.__name__, (cls,), {})
        
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    def registerComponentNodes(self, comp, node_names, change_callback):
        """
        For a given component we create some nodes or get existing ones and 
        attach them to this component. Also specify a callback function that
        is called whenever the nodes attached to this component are changed
        , e.g. connected, disconnected, name change, etc.
        """
        if not isinstance(comp, Component):
            raise exceptions.ValueError("comp argument is not of type Component")
        
        if comp.id in self.__componentNodes:
            raise pkex.BasePyKatException("Component has already been registered")
        
        list = []
        
        for name in node_names:
41
42
            n = self.createNode(name)
            self.connectNodeToComp(n, comp, do_callback=False)
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
            list.append(n)
        
        self.__componentNodes[comp.id] = tuple(list)
        self.__componentCallback[comp.id] = change_callback
        
        change_callback()
    
    def connectNodeToComp(self, node, comp, do_callback=True):
        if node.id in self.__nodeComponents:
            comps = self.__nodeComponents[node.id]
        else:
            comps = ()
        
        if len(comps) >= 2:
            raise pkex.BasePyKatException("Node is already connected to 2 components")
        
        l = list(comps)
        l.append(comp)
        
        self.__nodeComponents[node.id] = tuple(l)
        
        if do_callback: self.__componentCallback[comp.id]()
Daniel Brown's avatar
Daniel Brown committed
65
66
67
68
69
        
    def createNode(self, node_name):
        if node_name == 'dump':
            return DumpNode()
            
70
        if node_name in self.__nodes:
71
            # then this node already exists
72
            return self.__nodes[node_name]
Daniel Brown's avatar
Daniel Brown committed
73
        else:
74
75
76
77
78
            n = Node(node_name, self, self.__node_id)
            
            self.__node_id += 1
            self.__add_node_attr(n) # add node as a member of this object, e.g. kat.nodes.n
            self.__nodes[node_name] = n
Daniel Brown's avatar
Daniel Brown committed
79
            return n
80
81
82
83
84
        
    def removeNode(self, node):
        if not isinstance(node,Node):
            raise exceptions.ValueError("node argument is not of type Node")
        
85
        if node.name not in self.__nodes:
86
87
            raise exceptions.RuntimeError("Trying to remove node {0} when it has not been added".format(node.name))
        
88
        C = self.getNodeComponents(node)
89
        
90
91
        if C[0] is not None or C[1] is not None:
            raise exceptions.RuntimeError("Cannot remove a node which is attached to components")
Daniel Brown's avatar
Daniel Brown committed
92
            
93
        if len(node.getDetectors()) > 0:
94
95
            raise exceptions.RuntimeError("Cannot remove a node which is attached to detectors still")
        
96
97
        self.__remove_node_attr(node)
        del self.__nodes[node.name] 
98
        
Daniel Brown's avatar
Daniel Brown committed
99
    def hasNode(self, name):
100
        return (name in self.__nodes)
101
102
    
    def getNodes(self):
103
        return self.__nodes.copy()
104
    
Daniel Brown's avatar
Daniel Brown committed
105
106
    def dumpInfo(self):
        
107
108
109
        for name in self.__nodes:
            
            n = self.__nodes[name]
Daniel Brown's avatar
Daniel Brown committed
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
            
            items = n.getComponents()
            comp = items[0][:]
            det = items[1]
            
            if comp[0] == None:
                comp1 = 'dump'
            else:
                comp1 = comp[0].name
            
            if comp[1] == None:
                comp2 = 'dump'
            else:
                comp2 = comp[1].name    
            
            detectors = ""
            
            if len(det) > 0:
                detectors = "Detectors: "
                
                for d in det:
                    detectors = detectors + d.name + " "
                
            print "node: {0} connected:{1} {2}->{3} {4}".format(
                    n.name,n.isConnected(),comp1, comp2, detectors)
135
    
136
137
    def getComponentNodes(self, comp): return self.__componentNodes[comp.id]
    def getNodeComponents(self, node): return self.__nodeComponents[node.id]
138
    
139
    def __add_node_attr(self, node):
140
141
142

        if not isinstance(node, Node):
            raise exceptions.ValueError("Argument is not of type Node")
Daniel Brown's avatar
Daniel Brown committed
143
        
144
        name = node.name
145
        fget = lambda self: self.__get_node_attr(name)
146
        
147
        setattr(self.__class__, name, property(fget))
148
        setattr(self, '__node_' + name, node)                   
Daniel Brown's avatar
Daniel Brown committed
149
    
150
    def __remove_node_attr(self, node):
151
152
153
154
        if not isinstance(node, Node):
            raise exceptions.ValueError("Argument is not of type Node")
        
        name = node.name
155
        detattr(self.__class__, '__node_' + name)
Daniel Brown's avatar
Daniel Brown committed
156
        delattr(self, name)
157
        
158
    def __get_node_attr(self, name):
159
160
161
        return getattr(self, '__node_' + name)        
        
class Node(object):
Daniel Brown's avatar
Daniel Brown committed
162

163
    def __init__(self, name, network, id):
Daniel Brown's avatar
Daniel Brown committed
164
165
        self._detectors = []
        self.__name = name
166
        self._item = None
Daniel Brown's avatar
Daniel Brown committed
167
        self._network = network
Daniel Brown's avatar
Daniel Brown committed
168
169
170
        self.__q_x = None
        self.__q_y = None
        self.__q_comp = None
171
        self.__id = id
172
        
173
174
175
    @property
    def id(self): return self.__id
    
176
177
    @property
    def network(self): return self._network
Daniel Brown's avatar
Daniel Brown committed
178
    
179
180
181
    @property
    def components(self): return self._network.getNodeComponents(self)
    
182
    @property
Daniel Brown's avatar
Daniel Brown committed
183
184
185
186
187
188
189
190
191
192
    def q(self):
        if self.__q_x == self.__q_y:
            return self.__q_x
        else:
            return (self.__q_x, self.__q_y)
            
    @property
    def qx(self): return self.__q_x
    @property
    def qy(self): return self.__q_y
193
194
    
    def removeGauss():
Daniel Brown's avatar
Daniel Brown committed
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
        self.__q_x = None
        self.__q_y = None
        self.__q_comp = None
    
    def setGauss(self, component, *args):
        self.__q_comp = component
        
        if len(args) == 1:
            self.__q_x = args[0]
            self.__q_y = args[0]
        elif len(args) == 2:
            self.__q_x = args[0]
            self.__q_y = args[1]
        else:
            raise pkex.BasePyKatException("Must specify either 1 Gaussian beam parameter or 2 for astigmatic beams")
210
        
Daniel Brown's avatar
Daniel Brown committed
211
212
213
    def getFinesseText(self):    
        if self.__q_x is None or self.__q_y is None or self.__q_comp is None:
            return []
214
            
Daniel Brown's avatar
Daniel Brown committed
215
        rtn = []
216
        
Daniel Brown's avatar
Daniel Brown committed
217
218
219
220
221
222
        if self.__q_x == self.__q_y:
            rtn.append("gauss* g_{node} {comp} {node} {z} {zr}".format(node=self.name, comp=self.__q_comp.name, z=self.__q_x.real, zr=self.__q_x.imag))
        else:
            rtn.append("gauss* g_{node} {comp} {node} {zx} {zrx} {zy} {zry}".format(node=self.name, comp=self.__q_comp.name, zx=self.__q_x.real, zrx=self.__q_x.imag, zy=self.__q_y.real, zry=self.__q_y.imag))
            
        return rtn
223
        
Daniel Brown's avatar
Daniel Brown committed
224
    def isConnected(self):
225
        if (self.components[0] is not None) and (self.self.components[1] is not None):
226
227
228
229
230
231
            return True
        else:
            return False
      
    def remove(self):
        self._network.removeNode(self)
Daniel Brown's avatar
Daniel Brown committed
232
233
234
235
        
        if self._item != None:
            self._item.scene().removeItem(self._item)
    
236
237
238
239
240
    def getQGraphicsItem(self,dx=0,dy=0,nsize=8,parent=None):
        if self._item == None:
            self._item = pykat.gui.graphics.NodeQGraphicItem(self,
                                                             dx,dy,
                                                             -nsize/2,-nsize/2,
241
                                                             nsize, nsize, parent)
242
243
244
            
        return self._item
    
245
246
    def getDetectors(self):
        return self._detectors[:]
Daniel Brown's avatar
Daniel Brown committed
247
        
248
249
    def amIConnected(self, obj):
        """
Daniel Brown's avatar
Daniel Brown committed
250
        Checks if obj is connected to the node. Returns true or false in tuple
251
252
        with None or the other object and the node index which it is attached to
        """ 
253
254
255
256
        comps = self.components
        
        if obj == comps[0]:
            if comps[1] == None:
257
258
                ix = -1
            else:
259
                ix = comps[1].getNodes().index(self)
260
                
261
262
263
264
            return [True, comps[1], ix]
            
        elif obj == comps[1]:
            if comps[0] == None:
265
266
                ix = -1
            else:
267
                ix = comps[0].getNodes().index(self)
268
                
269
            return [True, comps[0], ix]
270
271
272
        else:
            return [False, None]
        
273
274
275
    @property
    def name(self): return self.__name      
    
Daniel Brown's avatar
Daniel Brown committed
276
277
278
    
class DumpNode(Node):
    def __init__(self):
Daniel Brown's avatar
Daniel Brown committed
279
        Node.__init__(self, 'dump', None, -1)
Daniel Brown's avatar
Daniel Brown committed
280
281