node_network.py 9.1 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
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
        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
        
    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:
38
39
            n = self.createNode(name)
            self.connectNodeToComp(n, comp, do_callback=False)
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
            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
62
63
64
65
66
        
    def createNode(self, node_name):
        if node_name == 'dump':
            return DumpNode()
            
67
        if node_name in self.__nodes:
68
            # then this node already exists
69
            return self.__nodes[node_name]
Daniel Brown's avatar
Daniel Brown committed
70
        else:
71
72
73
74
75
            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
76
            return n
77
78
79
80
81
        
    def removeNode(self, node):
        if not isinstance(node,Node):
            raise exceptions.ValueError("node argument is not of type Node")
        
82
        if node.name not in self.__nodes:
83
84
            raise exceptions.RuntimeError("Trying to remove node {0} when it has not been added".format(node.name))
        
85
        C = self.getNodeComponents(node)
86
        
87
88
        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
89
            
90
        if len(node.getDetectors()) > 0:
91
92
            raise exceptions.RuntimeError("Cannot remove a node which is attached to detectors still")
        
93
94
        self.__remove_node_attr(node)
        del self.__nodes[node.name] 
95
        
Daniel Brown's avatar
Daniel Brown committed
96
    def hasNode(self, name):
97
        return (name in self.__nodes)
98
99
    
    def getNodes(self):
100
        return self.__nodes.copy()
101
    
Daniel Brown's avatar
Daniel Brown committed
102
103
    def dumpInfo(self):
        
104
105
106
        for name in self.__nodes:
            
            n = self.__nodes[name]
Daniel Brown's avatar
Daniel Brown committed
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
            
            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)
132
    
133
134
    def getComponentNodes(self, comp): return self.__componentNodes[comp.id]
    def getNodeComponents(self, node): return self.__nodeComponents[node.id]
135
    
136
    def __add_node_attr(self, node):
137
138
139

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

160
    def __init__(self, name, network, id):
Daniel Brown's avatar
Daniel Brown committed
161
162
        self._detectors = []
        self.__name = name
163
        self._item = None
Daniel Brown's avatar
Daniel Brown committed
164
        self._network = network
Daniel Brown's avatar
Daniel Brown committed
165
166
167
        self.__q_x = None
        self.__q_y = None
        self.__q_comp = None
168
        self.__id = id
169
        
170
171
172
    @property
    def id(self): return self.__id
    
173
174
    @property
    def network(self): return self._network
Daniel Brown's avatar
Daniel Brown committed
175
    
176
177
178
    @property
    def components(self): return self._network.getNodeComponents(self)
    
179
    @property
Daniel Brown's avatar
Daniel Brown committed
180
181
182
183
184
185
186
187
188
189
    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
190
191
    
    def removeGauss():
Daniel Brown's avatar
Daniel Brown committed
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
        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")
207
        
Daniel Brown's avatar
Daniel Brown committed
208
209
210
    def getFinesseText(self):    
        if self.__q_x is None or self.__q_y is None or self.__q_comp is None:
            return []
211
            
Daniel Brown's avatar
Daniel Brown committed
212
        rtn = []
213
        
Daniel Brown's avatar
Daniel Brown committed
214
215
216
217
218
219
        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
220
        
Daniel Brown's avatar
Daniel Brown committed
221
    def isConnected(self):
222
        if (self.components[0] is not None) and (self.self.components[1] is not None):
223
224
225
226
227
228
            return True
        else:
            return False
      
    def remove(self):
        self._network.removeNode(self)
Daniel Brown's avatar
Daniel Brown committed
229
230
231
232
        
        if self._item != None:
            self._item.scene().removeItem(self._item)
    
233
234
235
236
237
    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,
238
                                                             nsize, nsize, parent)
239
240
241
            
        return self._item
    
242
243
    def getDetectors(self):
        return self._detectors[:]
Daniel Brown's avatar
Daniel Brown committed
244
        
245
246
    def amIConnected(self, obj):
        """
Daniel Brown's avatar
Daniel Brown committed
247
        Checks if obj is connected to the node. Returns true or false in tuple
248
249
        with None or the other object and the node index which it is attached to
        """ 
250
251
252
253
        comps = self.components
        
        if obj == comps[0]:
            if comps[1] == None:
254
255
                ix = -1
            else:
256
                ix = comps[1].getNodes().index(self)
257
                
258
259
260
261
            return [True, comps[1], ix]
            
        elif obj == comps[1]:
            if comps[0] == None:
262
263
                ix = -1
            else:
264
                ix = comps[0].getNodes().index(self)
265
                
266
            return [True, comps[0], ix]
267
268
269
        else:
            return [False, None]
        
270
271
272
    @property
    def name(self): return self.__name      
    
Daniel Brown's avatar
Daniel Brown committed
273
274
275
    
class DumpNode(Node):
    def __init__(self):
Daniel Brown's avatar
Daniel Brown committed
276
        Node.__init__(self, 'dump', None, -1)
Daniel Brown's avatar
Daniel Brown committed
277
278