Commit c36617e5 authored by Sean Leavey's avatar Sean Leavey
Browse files

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

parents c2669e6f 8f83578f
......@@ -16,18 +16,17 @@ m m2 0.5 0.5 0 n4 n5
s s3 10 1 n5 n6
yaxis abs:deg
"""
kat = finesse.kat()
pd pd_cav n3
kat.parseCommands(code)
cav c1 m1 n3 m2 n4
kat.add(cavity('cav1', 'm1', 'n3', 'm2', 'n4'))
attr m1 Rc 1
"""
kat.add(photodiode('pd_ref','n2'))
kat.add(photodiode('pd_trs','n5'))
kat.add(photodiode('pd_cav','n4', num_demods=1, demods=[1]))
kat = finesse.kat()
kat.parseCommands(code)
kat.add(xaxis("lin", [0, 360], kat.m2.phi, 100))
......@@ -41,7 +40,7 @@ kat.maxtem = 0
out = kat.run(printout=0,printerr=0)
pl.figure()
pl.plot(out.x, out["pd_cav"])
pl.plot(out.x, out.y)
pl.xlabel(out.xlabel)
pl.ylabel("Intensity [W]")
pl.legend(out.ylabels)
......
import os
import re
import pykat.exceptions as pkex
#staticmethod
__suffix = {'y': 'e-24', # yocto
'z': 'e-21', # zepto
'a': 'e-18', # atto
'f': 'e-15', # femto
'p': 'e-12', # pico
'n': 'e-9', # nano
'u': 'e-6', # micro
'm': 'e-3', # mili
'c': 'e-2', # centi
'd': 'e-1', # deci
'k': 'e3', # kilo
'M': 'e6', # mega
'G': 'e9', # giga
'T': 'e12', # tera
'P': 'e15' # peta
}
def SIfloat(value):
if value==None:
return value
if type(value)==list:
return [convertToFloat(s) for s in value]
else:
return convertToFloat(value)
def convertToFloat(value):
__suffix = {'y': 'e-24', # yocto
'z': 'e-21', # zepto
'a': 'e-18', # atto
'f': 'e-15', # femto
'p': 'e-12', # pico
'n': 'e-9', # nano
'u': 'e-6', # micro
'm': 'e-3', # mili
'c': 'e-2', # centi
'd': 'e-1', # deci
'k': 'e3', # kilo
'M': 'e6', # mega
'G': 'e9', # giga
'T': 'e12', # tera
'P': 'e15' # peta
}
value = str(value)
for i, j in __suffix.iteritems():
value=value.replace(i, str(j))
try:
# first just try and convert the value
return float(value)
except ValueError as ex:
# Catch any casting exeception
value = value.strip()
# only the last value can be an SI scaling letter
last = value[-1]
if last in __suffix:
# remove last character and append the SI scaling
value = value[0:-1] + __suffix[last]
else:
raise pkex.BasePyKatException("Could not convert SI scaling in '{0}' to a float".format(value))
return float(value)
try:
return float(value)
except ValueError as ex:
raise pkex.BasePyKatException("Unable to convert '{0}' into a float".format(value))
......@@ -243,13 +243,43 @@ class AbstractMirrorComponent(Component):
self.Rcx.value = SIfloat(value)
self.Rcy.value = SIfloat(value)
def parseAttribute(self, key, value):
if key in ["Rcx", "Rx", "ROCx", "rx", "rcx", "rocx"]:
self.Rcx = value
elif key in ["Rcy", "Ry", "ROCy", "ry", "rcy", "rocy"]:
self.Rcy = value
elif key in ["Rc", "ROC", "r", "rc", "roc"]:
self.Rc = value
elif key in ["M, m, Mass, mass"]:
self.mass = value
elif key in ["xbeta, xBeta"]:
self.xbeta = value
elif key in ["ybeta, yBeta"]:
self.ybeta = value
elif key in ["x_off"]:
self.x_offset = value
elif key in ["y_off"]:
self.y_offset = value
elif key in ["r_ap"]:
self.r_ap = value
else:
return False
return True
class mirror(AbstractMirrorComponent):
def __init__(self,name,node1,node2,R=None,T=None,L=None,phi=0,Rcx=None,Rcy=None,xbeta=None,ybeta=None,mass=None, r_ap=None):
super(mirror, self).__init__(name, R, T, L, phi, Rcx, Rcy, xbeta, ybeta, mass, r_ap)
self._requested_node_names.append(node1)
self._requested_node_names.append(node2)
def parseAttributes(self, values):
for key in values.keys():
if not self.parseAttribute(key, values[key]):
raise pkex.BasePyKatException("No attribute {0} for mirrors".format(key))
@staticmethod
def parseFinesseText(text):
values = text.split()
......@@ -301,13 +331,22 @@ class beamSplitter(AbstractMirrorComponent):
self._requested_node_names.append(node3)
self._requested_node_names.append(node4)
self.__alpha = Param("alpha", self, SIfloat(alpha))
self.__alpha = AttrParam("alpha", self, SIfloat(alpha))
@property
def alpha(self): return self.__alpha
@alpha.setter
def alpha(self,value): self.__alpha.value = SIfloat(value)
def parseAttributes(self, values):
for key in values.keys():
if not self.parseAttribute(key, values[key]):
if key == "alpha":
self.alpha = values[key]
else:
raise pkex.BasePyKatException("No attribute {0} for mirrors".format(key))
@staticmethod
def parseFinesseText(text):
values = text.split()
......@@ -338,8 +377,8 @@ class beamSplitter(AbstractMirrorComponent):
rtn = []
rtn.append('bs {0} {1} {2} {3} {4} {5} {6} {7} {8}'.format(
self.name, self.R.value, self.T.value, self.alpha.value,
self.phi.value, self.nodes[0].name,
self.name, self.R.value, self.T.value, self.phi.value,
self.alpha.value, self.nodes[0].name,
self.nodes[1].name, self.nodes[2].name,
self.nodes[3].name))
......@@ -365,7 +404,6 @@ class space(Component):
self.__L = Param("L", self, SIfloat(L))
self.__n = Param("n", self, SIfloat(n))
self.__g = AttrParam("g", self, g)
self.__gx = AttrParam("gx", self, gx)
self.__gy = AttrParam("gy", self, gy)
......@@ -379,10 +417,17 @@ class space(Component):
def n(self,value): self.__n.value = SIfloat(value)
@property
def g(self): return self.__g
def g(self):
if self.__gx.value == self.__gy.value:
return self.__g
else:
raise pkex.BasePyKatException("Gouy phase in x and y directions are different, use gx and gy properties instead")
@g.setter
def g(self,value): self.__g.value = SIfloat(value)
def g(self,value):
self.__gx.value = SIfloat(value)
self.__gy.value = SIfloat(value)
@property
def gx(self): return self.__gx
@gx.setter
......@@ -393,6 +438,19 @@ class space(Component):
@gy.setter
def gy(self,value): self.__gy.value = SIfloat(value)
def parseAttributes(self, values):
for key in values.keys():
if key in ["gx","gouyx"]:
self.__gx.value = values[key]
elif key in ["gy", "gouyy"]:
self.__gy.value = values[key]
elif key in ["g, gouy"]:
self.__gx.value = values[key]
self.__gy.value = values[key]
else:
raise pkex.BasePyKatException("No attribute {0} for spaces".format(key))
@staticmethod
def parseFinesseText(text):
values = text.split()
......@@ -558,11 +616,12 @@ class grating(Component):
return self._QItem
class isolator(Component):
def __init__(self, name, node1, node2, S = 0):
def __init__(self, name, node1, node2, node3="dump", S = 0):
Component.__init__(self, name)
self._requested_node_names.append(node1)
self._requested_node_names.append(node2)
self._requested_node_names.append(node3)
self.__S = Param("S",self,SIfloat(S))
......@@ -582,11 +641,13 @@ class isolator(Component):
if len(values) == 4:
return isolator(values[0], values[2], values[3], values[1])
elif len(values) == 5:
return isolator(values[0], values[2], values[3], values[4], values[1])
else:
raise pkex.BasePyKatException("Isolator Finesse code format incorrect '{0}'".format(text))
def getFinesseText(self):
rtn = ['isol {0} {1} {2} {3}'.format(self.name, self.S.value, self.nodes[0].name, self.nodes[1].name)]
rtn = ['isol {0} {1} {2} {3} {4}'.format(self.name, self.S.value, self.nodes[0].name, self.nodes[1].name, self.nodes[2].name)]
for p in self._params:
rtn.extend(p.getFinesseText())
......@@ -744,6 +805,14 @@ class laser(Component):
@phase.setter
def phase(self,value): self.__phase.value = float(value)
def parseAttributes(self, values):
for key in values.keys():
if key == "noise":
self.__noise.value = values[key]
else:
raise pkex.BasePyKatException("No attribute {0} at laser".format(key))
@staticmethod
def parseFinesseText(text):
values = text.split()
......
......@@ -28,17 +28,19 @@ class Detector(object) :
self._mask = {}
self.__scale = None
if node[-1]=='*':
self._alternate_beam = True
node=node[:-1]
if node != None:
if node[-1]=='*':
self._alternate_beam = True
node=node[:-1]
self.__requested_node = node
self.__requested_node = node
def _register_param(self, param):
self._params.append(param)
def _on_kat_add(self, kat):
self.__node = kat.nodes.createNode(self.__requested_node)
if self.__requested_node != None:
self.__node = kat.nodes.createNode(self.__requested_node)
@staticmethod
def parseFinesseText(text):
......@@ -321,7 +323,7 @@ class pd(Detector):
if senstype == None:
senstype = ""
rtn.append("pd{0}{1} {2}{3} {4}{5}".format(senstype, self.num_demods, self.name, fphi_str, self.node.name, alt_str))
if self.scale != None:
......@@ -330,135 +332,135 @@ class pd(Detector):
if self.pdtype != None:
rtn.append("pdtype {0} {1}".format(self.name, self.pdtype))
for p in self._params:
rtn.extend(p.getFinesseText())
for p in self._params:
rtn.extend(p.getFinesseText())
return rtn
class photodiode(Detector):
def qnoised(pd):
def __init__(self, name, num_demods, node_name, alternate_beam=False, pdtype=None, **kwargs):
pd.__init__(self, name, num_demods, node_name, alternate_beam=False, **kwargs)
self.__homangle = AttrParam("homangle", self, None)
@property
def homangle(self): return self.__homangle
@homangle.setter
def homangle(self, value): self.__homangle.value = value
@pd.pdtype.setter
def pdtype(self, value): raise pkex.BasePyKatException("Setting pdtype is not possible with qnoised detectors")
@pd.senstype.setter
def senstype(self,value): raise pkex.BasePyKatException("qnoised detector has no sensitvity type")
@staticmethod
def parseFinesseText(text):
values = text.split()
class __F(list):
def __init__(self, values=None):
if values==None:
values = []
list.__init__(self,[SIfloat(value) for value in values])
if len(values) <= 3:
raise pkex.BasePyKatException("Photodiode code format incorrect '{0}' (2)".format(text))
class __Phi(list):
def __convertValue(self, value):
if value=="max":
return value
else:
return SIfloat(value)
def __init__(self, values=None):
if values==None:
values = []
list.__init__(self,[self.__convertValue(value) for value in values])
def __getitem__(self, key): # probably not needed
if list.__getitem__(self,key)=="max":
return list.__getitem__(self,key)
else:
return float(list.__getitem__(self,key))
demods = values[2]
@property
def f(self): return self.__f
@property
def phi(self): return self.__phi
@property
def pdtype(self): return self.__pdtype
@pdtype.setter
def pdtype(self, value): self.__pdtype = value
def __init__(self, name, node, senstype="", num_demods=0, demods=[], pdtype=None):
Detector.__init__(self, name, node)
if len(values) <= 4 and demods > 0:
raise pkex.BasePyKatException("Photodiode code format incorrect '{0}' (2)".format(text))
elif len(values) > 4 and demods == 0:
raise pkex.BasePyKatException("Photodiode code format incorrect '{0}' (3)".format(text))
num_f_phs = len(values) - 4
expected_f_phs = demods * 2
if not (num_f_phs == expected_f_phs or num_f_phs == expected_f_phs-1):
raise pkex.BasePyKatException("Photodiode code format incorrect '{0}' (4)".format(text))
f = values[3:len(values)-1:2]
phs = values[4:len(values)-1:2]
dict = {}
if num_demods>2:
raise NotImplementedError("pd with more than two demodulations not implemented yet")
for i in range(len(f)):
dict['f{0}'.format(i+1)] = f[i]
for i in range(len(phs)):
dict['phi{0}'.format(i+1)] = phs[i]
self.num_demods = num_demods
self.senstype = senstype
self.__pdtype = pdtype
node = values[-1]
alt_beam = node[-1] == '*'
if alt_beam:
node = node[0:-1]
return qnoised(values[1], demods, node, alternate_beam=alt_beam, **dict)
def getFinesseText(self) :
rtn = []
if self.enabled:
alt_str = ""
fphi_str = ""
if self.alternate_beam:
alt_str = "*"
for n in range(1, 1+self.num_demods):
fphi_str += " " + str(self.__getattribute__("f"+str(n)))
phi_val = self.__getattribute__("phi"+str(n))
if phi_val != None:
fphi_str += " " + str(phi_val)
senstype = self.senstype
if senstype == None:
senstype = ""
rtn.append("qnoised {0} {1} {2} {3}{4}".format(self.name, self.num_demods, fphi_str, self.node.name, alt_str))
if self.scale != None:
rtn.append("scale {1} {0}".format(self.name, self.scale))
for p in self._params:
rtn.extend(p.getFinesseText())
return rtn
def xd(Detector):
# every second element into f (starting at 1)
self.__f = self.__F(demods[::2])
def __init__(self, name, node_name, component, motion):
Detector.__init__(name, None)
# Every second element into phi (starting at 2)
self.__phi = self.__Phi(demods[1::2])
self.__motion = motion
self.__component = component
@property
def motion(self): return self.__motion
@property
def component(self): return self.__component
@staticmethod
def parseFinesseText(text):
values = text.split()
if values[0][0:2] != "pd":
raise exceptions.FinesseParse("'{0}' not a valid photodiode command".format(text))
if len(values[0])==2:
__num_demods=0
__senstype=""
elif len(values[0])==3 or len(values[0])==4:
if values[0][2]=="S":
__senstype="S"
elif values[0][2]=="N":
__senstype="N"
else:
try:
__num_demods=int(values[0][2])
__senstype=""
except ValueError:
raise exceptions.FinesseParse("'{0}' not a valid photodiode command".format(text))
if len(values[0])==4:
try:
__num_demods=int(values[0][3])
except ValueError:
raise exceptions.FinesseParse("'{0}' not a valid photodiode command".format(text))
else:
raise exceptions.FinesseParse("'{0}' not a valid photodiode command".format(text))
if __num_demods<0 or __num_demods>5:
raise exceptions.FinesseParse("'{0}' number of demodulations must be >0 and <5".format(text))
values.pop(0) # remove initial value
if len(values) == 2 * __num_demods + 1 or len(values) == 2 * __num_demods + 2:
return photodiode(values[0], values[-1], __senstype, __num_demods, values[1:len(values)-1])
else:
raise exceptions.FinesseParse("Photodiode code format incorrect '{0}'".format(text))
#return photodiode("name", "node", demods)
#raise NotImplementedError("This function is not implemented")
if len(values) != 4:
raise pkex.BasePyKatException("Motion detector command format incorrect '{0}' (2)".format(text))
return xd(values[1], values[2], values[3])
def getFinesseText(self) :
rtn = []
if self.enabled:
rtn = []
__f_phi=range(len(self.f)+len(self.phi))
__f_phi[::2]=self.f
__f_phi[1::2]=self.phi
__f_phi_str = " ".join(map(str, __f_phi))
if self._alternate_beam:
rtn.append("pd{0}{1} {2} {3} {4}".format(self.senstype, self.num_demods, self.name, __f_phi_str, self.node.name))
else:
rtn.append("pd{0}{1} {2} {3} {4}*".format(self.senstype, self.num_demods, self.name, __f_phi_str, self.node.name))
rtn.append("xd {0} {1} {2}".format(self.name, self.component, self.motion))
if self.scale != None and self.scale !='':
if self.scale != None:
rtn.append("scale {1} {0}".format(self.name, self.scale))
if self.pdtype != None and self.pdtype != '':
rtn.append("pdtype {0} {1}".format(self.name, self.pdtype))
if self.noplot:
rtn.append("noplot {0}".format(self.name))
for p in self._params:
rtn.extend(p.getFinesseText())
return rtn
else:
return None
return rtn
def getQGraphicsItem(self):
if self._svgItem == None:
self._svgItem = ComponentQGraphicsItem(":/resources/photodiode_red.svg",self,[(-5,11,self.node)])
return self._svgItem
\ No newline at end of file
......@@ -34,7 +34,10 @@ import pykat
import warnings
import re
from collections import namedtuple
import itertools
import collections
from collections import namedtuple, OrderedDict
from pykat.node_network import NodeNetwork
from pykat.detectors import Detector
......@@ -53,7 +56,6 @@ NO_GUI = False
NO_BLOCK = "NO_BLOCK"
pykat_web = "www.gwoptics.org/pykat"
class katRun(object):
def __init__(self):
self.runDateTime = datetime.datetime.now()
......@@ -245,7 +247,7 @@ class kat(object):
self.scene = None # scene object for GUI
self.verbose = True
self.__blocks = {} # dictionary of blocks that are used
self.__blocks = OrderedDict() # dictionary of blocks that are used
self.__components = {} # dictionary of optical components
self.__detectors = {} # dictionary of detectors
self.__commands = {} # dictionary of commands
......@@ -258,6 +260,7 @@ class kat(object):
self.pykatgui = None
self.__signals = Signals()
self.constants = {}
self.vacuum = []
# initialise default block
self.__currentTag= NO_BLOCK
......@@ -393,14 +396,14 @@ class kat(object):
if values[1] == "FTblock":
newTag = values[2]
if self.__currentTag != None and newTag != self.__currentTag:
if self.__currentTag != None and self.__currentTag != NO_BLOCK:
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".format(newTag))