Commit c87e25eb authored by Andreas Freise's avatar Andreas Freise
Browse files

Merge branch 'master' of gitmaster.atlas.aei.uni-hannover.de:pykat/pykat

parents 2b0d2775 d9f9af21
......@@ -14,7 +14,6 @@ ad ad1 0 n2
kat = finesse.kat(kat_code = code)
kat.add(xaxis("lin", [0, 360], kat.m2, kat.m2.phi, 1000))
kat.add(xaxis("lin", [0, 360], kat.m2, kat.m2.phi, 1000))
r = kat.run(printerr=1)
......
......@@ -23,9 +23,9 @@ kat.parseCommands(code)
kat.add(cavity('cav1', 'm1', 'n3', 'm2', 'n4'))
kat.add(photodiode('pd_cav','n4',[]))
kat.add(photodiode('pd_ref','n2',[]))
kat.add(photodiode('pd_trs','n5',[]))
kat.add(photodiode('pd_cav','n4'))
kat.add(photodiode('pd_ref','n2'))
kat.add(photodiode('pd_trs','n5'))
kat.add(xaxis("lin", [0, 360], kat.m2, kat.m2.phi, 100))
......
......@@ -11,6 +11,9 @@ from components import *
from structs import *
class Command(object):
def __init__(self):
self.tag = None
def getFinesseText(self):
""" Base class for individual finesse optical components """
raise NotImplementedError("This function is not implemented")
......
......@@ -5,6 +5,7 @@ Created on Mon Jan 28 11:10:01 2013
@author: Daniel
"""
import exceptions
import pykat.exceptions as pkex
import pykat
from pykat.node_network import *
from pykat.exceptions import *
......@@ -14,60 +15,102 @@ import pykat.gui.graphics
from pykat.gui.graphics import *
from pykat.SIfloat import *
next_component_id = 1
class NodeGaussSetter:
def __init__(self, component, node):
if not isinstance(component, Component):
raise pkex.BasePyKatException("Value passed is not a Component")
if not isinstance(node, Node):
raise pkex.BasePyKatException("Value passed is not a Node")
self._comp = component
self._node = node
class Component(object) :
def __init__(self, name):
self.__name = name
self._svgItem = None
self._nodes = []
self._nodes = None
self._requested_node_names = []
self._kat = None
self.tag = None
# store a unique ID for this component
global next_component_id
self.__id = next_component_id
next_component_id += 1
def _on_kat_add(self, kat):
"""
Called when this component has been added to a kat object
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.
"""
if self._kat != None:
raise pkex.BasePyKatException("Component has already been added to a finesse.kat object")
self._kat = kat
for node_name in self._requested_node_names:
self._addNode(node_name)
kat.nodes.registerComponentNodes(self, self._requested_node_names, self.__on_node_change)
def __on_node_change(self):
# need to update the node gauss parameter setter members
#self.__update_node_setters()
return
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)]
# now we have a list of which to remove
for key in key_rm:
ns = self.__dict__[key]
detattr(self, '__nodesetter_' + ns._node.name)
delattr(self.__class__, ns._node.name)
for node in self.nodes:
self.__add_node_setter(NodeGaussSetter(self, node))
def __add_node_setter(self, ns):
if not isinstance(ns, NodeGaussSetter):
raise exceptions.ValueError("Argument is not of type NodeGaussSetter")
name = ns.__class__.__name__
fget = lambda self: self.__get_node_setter(name)
setattr(self.__class__, name, property(fget))
setattr(self, '__nodesetter_' + name, ns)
def __get_node_setter(self, name):
return getattr(self, '__nodesetter_' + name)
@staticmethod
def parseFinesseText(text):
raise NotImplementedError("This function is not implemented")
def setAttr(name, value):
raise NotImplementedError("This function is not implemented")
def getFinesseText(self):
""" Base class for individual finesse optical components """
raise NotImplementedError("This function is not implemented")
def getQGraphicsItem(self):
return None
def _addNode(self, name):
""" Adds a node in sequential order to the component, i.e. add them
n1, n2, n3, n4... etc. by the name of the node"""
n = self._kat.nodes.createNode(name)
if n == None:
raise exceptions.RuntimeError("createNode did not return a node for '{0}'".format(name))
else:
n.connect(self)
self._nodes.append(n)
return n
def getNodes(self):
""" Returns a copy of the nodes the component has """
return self._nodes[:]
def __getname(self):
return self.__name
name = property(__getname)
@property
def nodes(self): return self._kat.nodes.getComponentNodes(self)
@property
def name(self): return self.__name
@property
def id(self): return self.__id
class Param(float):
def __new__(self,name,value):
......@@ -97,7 +140,7 @@ class mirror(Component):
self.__ybeta = float(ybeta)
@property
def r_ap(self): return Param('r_ap', self.__mass)
def r_ap(self): return Param('r_ap', self.__r_ap)
@r_ap.setter
def r_ap(self,value): self.__aperture = float(value)
......@@ -169,14 +212,10 @@ class mirror(Component):
def getFinesseText(self):
rtn = []
nodes = self.getNodes()
if len(nodes) != 2:
raise exceptions.RuntimeError("Not enough nodes for mirror")
rtn.append('m {0} {1} {2} {3} {4} {5}'.format(
self.name, self.__R, self.__T, self.__phi,
nodes[0].name, nodes[1].name))
self.nodes[0].name, self.nodes[1].name))
if self.r_ap != 0: rtn.append("attr {0} r_ap {1}".format(self.name,self.__r_ap))
if self.mass != 0: rtn.append("attr {0} mass {1}".format(self.name,self.__mass))
......@@ -189,8 +228,7 @@ class mirror(Component):
def getQGraphicsItem(self):
if self._svgItem == None:
nodes = self.getNodes()
self._svgItem = pykat.gui.graphics.ComponentQGraphicsItem(":/resources/mirror_flat.svg", self ,[(-4,15,nodes[0]), (14,15,nodes[1])])
self._svgItem = pykat.gui.graphics.ComponentQGraphicsItem(":/resources/mirror_flat.svg", self ,[(-4,15,self.nodes[0]), (14,15,self.nodes[1])])
return self._svgItem
......@@ -232,12 +270,10 @@ class space(Component):
raise exceptions.RuntimeError("Space Finesse code format incorrect '{0}'".format(text))
def getFinesseText(self):
nodes = self.getNodes()
if self.__n == 1:
return 's {0} {1} {2} {3}'.format(self.name, self.__L, nodes[0].name, nodes[1].name)
return 's {0} {1} {2} {3}'.format(self.name, self.__L, self.nodes[0].name, self.nodes[1].name)
else:
return 's {0} {1} {2} {3} {4}'.format(self.name, self.__L, self.__n, nodes[0].name, nodes[1].name)
return 's {0} {1} {2} {3} {4}'.format(self.name, self.__L, self.__n, self.nodes[0].name, self.nodes[1].name)
def getQGraphicsItem(self):
if self._QItem == None:
......@@ -245,19 +281,19 @@ class space(Component):
return self._QItem
def changeNode(self, node_old, node_new):
'''
Called when a space's node has been connected
to another components node
'''
node_new.connect(self)
node_old.disconnect(self)
if self._nodes[0] == node_old:
self._nodes[0] = node_new
if self._nodes[1] == node_old:
self._nodes[1] = node_new
# def changeNode(self, node_old, node_new):
# '''
# Called when a space's node has been connected
# to another components node
# '''
# node_new.connect(self)
# node_old.disconnect(self)
# if self._nodes[0] == node_old:
# self._nodes[0] = node_new
# if self._nodes[1] == node_old:
# self._nodes[1] = node_newf
class laser(Component):
......@@ -302,15 +338,11 @@ class laser(Component):
raise exceptions.FinesseParse("Laser Finesse code format incorrect '{0}'".format(text))
def getFinesseText(self):
nodes = self.getNodes()
return 'l {0} {1} {2} {3} {4}'.format(self.name, self.__power, self.__f_offset, self.__phase, nodes[0].name)
return 'l {0} {1} {2} {3} {4}'.format(self.name, self.__power, self.__f_offset, self.__phase, self.nodes[0].name)
def getQGraphicsItem(self):
if self._svgItem == None:
nodes = self.getNodes()
self._svgItem = pykat.gui.graphics.ComponentQGraphicsItem(":/resources/laser.svg",
self,[(65,25,nodes[0])])
self._svgItem = pykat.gui.graphics.ComponentQGraphicsItem(":/resources/laser.svg", self, [(65,25,self.nodes[0])])
return self._svgItem
......@@ -18,6 +18,8 @@ class Detector(object) :
self._kat = None
self.noplot = False
self.enabled = True
self.tag = None
self.__node = None
if node.find('*'):
self._alternate_beam = True
......@@ -26,7 +28,7 @@ class Detector(object) :
self.__requested_node = node
def _on_kat_add(self, kat):
self._node = kat.nodes.createNode(self.__requested_node)
self.__node = kat.nodes.createNode(self.__requested_node)
@staticmethod
def parseFinesseText(text):
......@@ -39,8 +41,8 @@ class Detector(object) :
def getQGraphicsItem(self):
return None
def getNodes(self):
return [self._node]
@property
def node(self): return self.__node
def __getname(self):
return self.__name
......@@ -85,7 +87,7 @@ class photodiode(Detector):
self.values[key] = SIfloat(value)
def __init__(self, name, node, senstype, num_demods, demods):
def __init__(self, name, node, senstype=None, num_demods=0, demods=[]):
Detector.__init__(self, name, node)
if num_demods>2:
raise NotImplementedError("pd with more than two demodulations not implemented yet")
......@@ -93,10 +95,10 @@ class photodiode(Detector):
self.senstype = senstype
# every second element into f (starting at 1)
self.f(demods[::2])
print self.f[1]
# every second element into phi (starting at 2)
self.phi([1,2])
print self.phi[1]
for i in demods[1::2]:
self.phi.append(i)
......@@ -147,9 +149,9 @@ class photodiode(Detector):
rtn = []
if self._alternate_beam:
rtn.append("pd {0} {1}".format(self.name, self._node.name))
rtn.append("pd {0} {1}".format(self.name, self.node.name))
else:
rtn.append("pd {0} {1}*".format(self.name, self._node.name))
rtn.append("pd {0} {1}*".format(self.name, self.node.name))
if self.noplot:
rtn.append("noplot {0}".format(self.name))
......@@ -160,7 +162,7 @@ class photodiode(Detector):
def getQGraphicsItem(self):
if self._svgItem == None:
self._svgItem = ComponentQGraphicsItem(":/resources/photodiode_red.svg",self,[(-5,11,self._node)])
self._svgItem = ComponentQGraphicsItem(":/resources/photodiode_red.svg",self,[(-5,11,self.node)])
return self._svgItem
......@@ -43,7 +43,8 @@ from pykat.commands import Command, xaxis
from pykat.gui.gui import pyKatGUI
NO_GUI = False
NO_BLOCK = "NO_BLOCK"
class katRun(object):
def __init__(self):
self.runDateTime = datetime.datetime.now()
......@@ -54,12 +55,9 @@ class katRun(object):
self.katScript = None
self.katVersion = None
def saveKatRun(self, run, filename):
if not isinstance(run, katRun):
raise BasePyKatException("run object must be a katRun type")
def saveKatRun(self, filename):
with open(filename,'w') as outfile:
pickle.dump(run, outfile, pickle.HIGHEST_PROTOCOL)
pickle.dump(self, outfile)
@staticmethod
def loadKatRun(filename):
......@@ -67,11 +65,21 @@ class katRun(object):
return pickle.load(infile)
class Block:
def __init__(self, name):
self.__name = name
self.contents = [] # List of objects and strings of finesse code
self.enabled = True
@property
def name(self): return self.__name
class kat(object):
def __init__(self, kat_file=None, kat_code=None, katdir="", katname="", tempdir=None, tempname=None):
self.scene = None # scene object for GUI
self.__blocks = {} # dictionary of blocks that are used
self.__components = {} # dictionary of optical components
self.__detectors = {} # dictionary of detectors
self.__commands = {} # dictionary of commands
......@@ -83,7 +91,9 @@ class kat(object):
self.__tempdir = tempdir
self.__tempname = tempname
self.pykatgui = None
# Various
# Various options for running finesse, typicaly the commands with just 1 input
# and have no name attached to them.
self.__phase = None
self.__maxtem = None
self.__noxaxis = None
......@@ -128,10 +138,14 @@ class kat(object):
def parseCommands(self, commands):
blockComment = False
self.__currentTag= ""
self.__currentTag= NO_BLOCK
if not (NO_BLOCK in self.__blocks):
self.__blocks[NO_BLOCK] = Block(NO_BLOCK)
commands=self.remove_comments(commands)
for line in commands.split("\n"):
#for line in commands:
if len(line.strip()) >= 2:
......@@ -142,11 +156,19 @@ class kat(object):
if values[0] == "%%%":
if values[1] == "FTblock":
newTag = values[2]
if newTag != self.__currentTag and self.__currentTag:
if self.__currentTag != None and newTag != self.__currentTag:
warnings.warn("found block {0} before block {1} ended".format(newTag, self.__currentTag))
if newTag in self.__blocks:
raise pkex.BasePyKatException("Block `{0}` has already been read")
self.__blocks[newTag] = Block(newTag) # create new list to store all references to components in block
self.__currentTag = newTag
if values[1] == "FTend":
self.__currentTag = ""
self.__currentTag = NO_BLOCK
continue
#warnings.warn("current tag {0}".format(self.__currentTag))
......@@ -163,21 +185,26 @@ class kat(object):
continue
first = line.split(" ",1)[0]
obj = None
if(first == "m"):
self.add(pykat.components.mirror.parseFinesseText(line))
obj = pykat.components.mirror.parseFinesseText(line)
elif(first == "s"):
self.add(pykat.components.space.parseFinesseText(line))
obj = pykat.components.space.parseFinesseText(line)
elif(first == "l"):
self.add(pykat.components.laser.parseFinesseText(line))
elif(first == "xaxis" or first == "x2axis" or first == "xaxis*" or first == "x2axis*"):
self.add(pykat.commands.xaxis.parseFinesseText(line))
#elif(first[0:2] == "pd"):
#self.add(pykat.detectors.photodiode.parseFinesseText(line))
obj = pykat.components.laser.parseFinesseText(line)
elif(first == "xaxis" or first == "x2axis" or first == "xaxis*" or first == "x2axis*"):
obj = pykat.commands.xaxis.parseFinesseText(line)
else:
print "Parsing `{0}` into pykat object not implemented yet, added as extra line.".format(line)
self.__extra_lines.append(line + "\n")
self.__currentTag= ""
obj = line
# manually add the line to the block contents
self.__blocks[self.__currentTag].contents.append(line)
if not isinstance(obj, str):
self.add(obj)
self.__currentTag = NO_BLOCK
def run(self, printout=1, printerr=1, save_output=False, save_kat=False,kat_name=None) :
"""
......@@ -314,10 +341,11 @@ class kat(object):
print fe
def add(self, obj) :
print type(obj)
def add(self, obj):
try:
obj.tag = self.__currentTag
self.__blocks[self.__currentTag].contents.append(obj)
if isinstance(obj, Component):
if obj.name in self.__components :
......@@ -378,37 +406,28 @@ class kat(object):
out = []
for key in self.__components:
txt = self.__components[key].getFinesseText()
for key in self.__blocks:
objs = self.__blocks[key].contents
if txt != None:
if isinstance(txt,list):
for t in txt: out.append(t+ "\n")
else:
out.append(txt + "\n")
for key in self.__detectors:
txt = self.__detectors[key].getFinesseText()
out.append("%%% FTblock " + key + "\n")
if txt != None:
if isinstance(txt,list):
for t in txt: out.append(t+ "\n")
else:
out.append(txt + "\n")
for obj in objs:
if isinstance(obj, str):
out.append(obj + '\n')
elif isinstance(obj, Component) or isinstance(obj, Detector) or isinstance(obj, Command):
txt = obj.getFinesseText()
if txt != None:
if isinstance(txt,list):
for t in txt: out.append(t + "\n")
else:
out.append(txt + "\n")
out.append("%%% FTend " + key + "\n")
if self.noxaxis != None and self.noxaxis == True:
out.append("noxaxis\n")
for key in self.__commands:
if self.noxaxis == None or (self.noxaxis == True and isinstance(self.__commands[key], xaxis)):
txt = self.__commands[key].getFinesseText()
if txt != None:
if isinstance(txt,list):
for t in txt: out.append(t+ "\n")
else:
out.append(txt + "\n")
# now loop through all the nodes and get any gauss commands
for key in self.nodes.getNodes():
......@@ -422,14 +441,7 @@ class kat(object):
if self.phase != None: out.append("phase {0}\n".format(self.phase))
if self.maxtem != None: out.append("maxtem {0}\n".format(self.maxtem))
# There maybe extra lines we want to include in the kat
# script which aren't parseable into components, detectors
# or commands. Typically when something hasn't been fully
# supported yet. So bung these extra lines on at the end
for lines in self.__extra_lines:
out.append(lines)
# ensure we don't do any plotting. That should be handled
# by user themselves
out.append("gnuterm no\n")
......
......@@ -12,51 +12,99 @@ from pykat.detectors import Detector
class NodeNetwork(object):
def __init__(self, kat):
self._nodes = {}
self.__nodes = {}
self.__kat = kat
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:
n = self.createNode(name)
self.connectNodeToComp(n, comp, do_callback=False)
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]()
def createNode(self, node_name):