Commit 8eee71ee authored by Andreas Freise's avatar Andreas Freise
Browse files

Merge branch 'master' of gitlab.aei.uni-hannover.de:finesse/pykat

parents 17bcd615 36b80188
......@@ -3,7 +3,7 @@ from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
__version__ = "1.0.8"
__version__ = "1.0.11"
# This flag is used to switch on the gui features in pkat at import time
USE_GUI = False
......
......@@ -34,7 +34,23 @@ class Command(object):
self.tag = None
self.__removed = False
self.__name = name.strip("*")
self._putters = []
def __deepcopy__(self, memo):
"""
When deep copying a kat object we need to take into account
the instance specific properties.
"""
cls = self.__class__
result = cls.__new__(cls)
result.__dict__ = copy.deepcopy(self.__dict__, memo)
for _ in result._putters:
_._updateOwner(result)
return result
def getFinesseText(self):
""" Base class for individual finesse optical components """
raise NotImplementedError("This function is not implemented")
......@@ -48,10 +64,30 @@ class Command(object):
Called when this component has been added to a kat object
"""
self._kat = kat
for _ in self._putters:
kat.registerVariable(_.name, _)
def remove(self):
self._kat.remove(self)
def _on_kat_remove(self):
self.__removed = True
for i in range(len(self._putters)):
_ = self._putters[i]
self._kat.unregisterVariable(_.name)
_.clearPuts()
for i in range(len(self._putters)):
del self._putters[0]
del self._putters[:]
def remove(self):
if self.__removed:
raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
else:
self._kat.remove(self)
@property
def name(self): return self.__name
......@@ -95,14 +131,19 @@ class func(Command):
self.value = value
self.noplot = False
self.enabled = True
self.output = putter(name, self)
self._putters.append(self.output)
def getFinesseText(self):
rtn = []
if self.noplot:
rtn.append("noplot " + self.name)
if self.enabled:
if self.noplot:
rtn.append("noplot " + self.name)
rtn.append("func {name} = {value}".format(name=self.name, value=str(self.value)))
rtn.append("func {name} = {value}".format(name=self.name, value=str(self.value)))
return rtn
......@@ -118,10 +159,7 @@ class func(Command):
return func(v2[0].split()[1], v2[1])
else:
raise pkex.BasePyKatException("'{0}' not a valid Finesse func command".format(line))
class lock(Command):
def __init__(self, name, variable, gain, accuracy, singleLock=False):
......@@ -132,6 +170,10 @@ class lock(Command):
self.__accuracy = accuracy
self.singleLock = singleLock
self.enabled = True
self.output = putter(name, self)
self._putters.append(self.output)
@staticmethod
......@@ -278,7 +320,78 @@ class gauss(object):
kat.nodes[node].setGauss(kat.components[component], gp)
else:
kat.nodes[node].setGauss(kat.components[component], gpx, gpy)
# class tf(Command):
#
# class fQ(object):
# def __init__(self, f, Q, tf):
# assert(tf is not None)
# self._tf = tf
# self.__f = Param("f", self, None, canFsig=False, isPutable=True, isPutter=False, isTunable=True)
# self.__Q = Param("Q", self, None, canFsig=False, isPutable=True, isPutter=False, isTunable=True)
#
# def _register_param(self, param):
# self._tf._params.append(param)
#
# @property
# def f(self): return self.__f
# @f.setter
# def f(self,value): self.__f.value = SIfloat(value)
#
# @property
# def Q(self): return self.__Q
# @Q.setter
# def Q(self,value): self.__Q.value = SIfloat(value)
#
# def __init__(self, name):
# Command.__init__(self, name, False)
# self.zeros = []
# self.poles = []
# self.gain = 1
# self.phase = 0
# self._params = []
#
# def addPole(self,f, Q):
# self.poles.append(tf.fQ(SIfloat(f), SIfloat(Q), self))
#
# def addZero(self,f, Q):
# self.zeros.append(tf.fQ(SIfloat(f), SIfloat(Q), self))
#
# @staticmethod
# def parseFinesseText(text):
# values = text.split()
#
# if ((len(values)-4) % 3) != 0:
# raise pkex.BasePyKatException("Transfer function Finesse code format incorrect '{0}'".format(text))
#
# _tf = tf(values[1])
#
# _tf.gain = SIfloat(values[2])
# _tf.phase = SIfloat(values[3])
#
# N = int((len(values)-4) / 3)
#
# for i in range(1,N+1):
# if values[i*3+1] == 'p':
# _tf.addPole(SIfloat(values[i*3+2]), SIfloat(values[i*3+3]))
# elif values[i*3+1] == 'z':
# _tf.addZero(SIfloat(values[i*3+2]), SIfloat(values[i*3+3]))
# else:
# raise pkex.BasePyKatException("Transfer function pole/zero Finesse code format incorrect '{0}'".format(text))
#
# return _tf
#
# def getFinesseText(self):
# rtn = "tf {name} {gain} {phase} ".format(name=self.name,gain=self.gain,phase=self.phase)
#
# for p in self.poles:
# rtn += "p {f} {Q} ".format(f=p.f, Q=p.Q)
#
# for z in self.zeros:
# rtn += "p {f} {Q} ".format(f=z.f, Q=z.Q)
#
# return rtn
class tf(Command):
class fQ(object):
......@@ -298,7 +411,7 @@ class tf(Command):
def addZero(self,f, Q):
self.zeros.append(tf.fQ(SIfloat(f), SIfloat(Q)))
@staticmethod
def parseFinesseText(text):
values = text.split()
......@@ -354,9 +467,12 @@ class xaxis(Command):
self._axis_type = axis_type
self.x = putter("x1")
self.mx = putter("mx1")
self.x = putter("x1", self)
self.mx = putter("mx1", self)
self._putters.append(self.x)
self._putters.append(self.mx)
if scale == "lin":
scale = Scale.linear
elif scale == "log":
......@@ -433,8 +549,11 @@ class xaxis(Command):
class x2axis(xaxis):
def __init__(self, scale, limits, param, steps, comp=None, axis_type="x2axis"):
xaxis.__init__(self, scale, limits, param, steps, comp=comp, axis_type=axis_type)
self.x = putter("x2")
self.mx = putter("mx2")
self.x = putter("x2", self)
self.mx = putter("mx2", self)
self._putters.append(self.x)
self._putters.append(self.mx)
@staticmethod
def parseFinesseText(text):
......
......@@ -84,7 +84,7 @@ class NodeGaussSetter(object):
def qy(self, value):
self.__node().setGauss(self.__comp(), self.qx, complex(value))
id___ = 0
id_____pykat_class = 0
class Component(object):
__metaclass__ = abc.ABCMeta
......@@ -93,9 +93,9 @@ class Component(object):
# This creates an instance specific class for the component
# this enables us to add properties to instances rather than
# all classes
global id___
id___ += 1
cnew_name = str("%s.%s_%i" % (cls.__module__, cls.__name__, id___))
global id_____pykat_class
id_____pykat_class += 1
cnew_name = str("%s.%s_%i" % (cls.__module__, cls.__name__, id_____pykat_class))
cnew = type(cnew_name, (cls,), {})
......@@ -130,6 +130,9 @@ class Component(object):
result = self.__class__.__new__(self.__class__.__base__)
result.__dict__ = copy.deepcopy(self.__dict__, memo)
for _ in result._params:
_._updateOwner(result)
return result
def _register_param(self, param):
......@@ -162,7 +165,17 @@ class Component(object):
self._kat = kat
kat.nodes.registerComponentNodes(self, self._requested_node_names, self.__on_node_change)
def _on_kat_remove(self):
# inform all parameters that we have removed its owner
# so that it can then warn about any puts/vars/xaxis
for p in self._params:
p._onOwnerRemoved()
del self._params[:]
self.__removed = True
def __on_node_change(self):
# need to update the node gauss parameter setter members
self.__update_node_setters()
......@@ -237,16 +250,10 @@ class Component(object):
def __str__(self): return self.name
def remove(self):
self._kat.remove(self)
# inform all parameters that we have removed its owner
# so that it can then warn about any puts/vars/xaxis
for p in self._params:
p._onOwnerRemoved()
del self._params[:]
self.__removed = True
if self.__removed:
raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
else:
self._kat.remove(self)
def getOptivisParameterDict(self):
if len(self._params) == 0:
......@@ -497,8 +504,8 @@ class mirror(AbstractMirrorComponent):
return mirror(values[0], values[4], values[5], T=None, R=values[1], L=values[2], phi=values[3])
def getFinesseText(self):
if self.R+self.T+self.L > 1:
raise pkex.BasePyKatException("Mirror {0} has R+T+L > 1".format(self.name))
if abs(self.R + self.T + self.L - 1) > 1e-14:
raise pkex.BasePyKatException("Mirror {0} has R+T+L = {1}, must equal 1 +- 1e-14".format(self.name, self.R+self.T+self.L))
rtn = []
......@@ -632,8 +639,8 @@ class beamSplitter(AbstractMirrorComponent):
values[1], None, values[2], values[3], values[4])
def getFinesseText(self):
if self.R+self.T+self.L > 1:
raise pkex.BasePyKatException("Beamsplitter {0} has R+T+L > 1".format(self.name))
if abs(self.R + self.T + self.L - 1) > 1e-14:
raise pkex.BasePyKatException("Beamsplitter {0} has R+T+L = {1}, must equal 1 +- 1e-14".format(self.name, self.R+self.T+self.L))
rtn = []
......@@ -1320,7 +1327,7 @@ class laser(Component):
return self._svgItem
class squeezer(Component):
def __init__(self, name, node, f=0, db=0, angle=0, phase=0):
def __init__(self, name, node, f=0, db=0, angle=0, phase=0, entangled_carrier=False):
Component.__init__(self,name)
self._requested_node_names.append(node)
......@@ -1330,6 +1337,7 @@ class squeezer(Component):
self.__db = Param("db", self, SIfloat(db), canFsig=False, fsig_name="r")
self.__angle = Param("angle", self, SIfloat(angle), canFsig=False, fsig_name="angle")
self._svgItem = None
self.entangled_carrier = entangled_carrier
@property
def db(self): return self.__db
......@@ -1357,19 +1365,26 @@ class squeezer(Component):
@staticmethod
def parseFinesseText(text):
values = text.split()
if values[0] != "sq":
if values[0][:2] != "sq":
raise pkex.BasePyKatException("'{0}' not a valid Finesse squeezer command".format(text))
entangled_carrier = values[0].endswith("*")
values.pop(0) # remove initial value
if len(values) == 5:
return squeezer(values[0], values[4], f=values[1], db=values[2], angle=values[3])
return squeezer(values[0], values[4], f=values[1],
db=values[2], angle=values[3],
entangled_carrier=entangled_carrier)
else:
raise exceptions.FinesseParse("Squeezer Finesse code format incorrect '{0}'".format(text))
def getFinesseText(self):
rtn = ['sq {0} {1} {2} {3} {4}'.format(self.name, self.f.value, self.db.value, self.angle.value, self.nodes[0].name)]
if self.entangled_carrier:
rtn = ['sq* {0} {1} {2} {3} {4}'.format(self.name, self.f.value, self.db.value, self.angle.value, self.nodes[0].name)]
else:
rtn = ['sq {0} {1} {2} {3} {4}'.format(self.name, self.f.value, self.db.value, self.angle.value, self.nodes[0].name)]
for p in self._params:
rtn.extend(p.getFinesseText())
......
......@@ -31,7 +31,7 @@ if USE_GUI:
import pykat.gui.resources
from pykat.gui.graphics import *
id___ = 0
id_____pykat_class = 0
class BaseDetector(object) :
"""
......@@ -45,9 +45,9 @@ class BaseDetector(object) :
# This creates an instance specific class for the component
# this enables us to add properties to instances rather than
# all classes
global id___
id___ += 1
cnew_name = str("%s.%s_%i" % (cls.__module__, cls.__name__, id___))
global id_____pykat_class
id_____pykat_class += 1
cnew_name = str("%s.%s_%i" % (cls.__module__, cls.__name__, id_____pykat_class))
cnew = type(cnew_name, (cls,), {})
......@@ -120,6 +120,9 @@ class BaseDetector(object) :
if rn != None:
self._nodes.append(kat.nodes.createNode(rn))
def _on_kat_remove(self):
self.__removed = True
def remove(self):
if self.__removed:
raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
......@@ -465,7 +468,7 @@ class gouy(Detector1):
class bp(Detector1):
acceptedParameters = ['w', 'w0', 'z', 'zr', 'g', 'r', 'q']
acceptedParameters = ['w', 'w0', 'z', 'zr', 'g', 'r', 'q', 'Rc']
def __init__(self, name, direction, parameter, node, alternate_beam=False):
BaseDetector.__init__(self, name, node)
......
......@@ -320,7 +320,7 @@ class katRun(object):
"""
import matplotlib.pyplot as pyplot
import pykat.plotting as plt
if not show:
pyplot.ioff()
......@@ -328,6 +328,9 @@ class katRun(object):
kat.verbose = False
kat.parseCommands(self.katScript)
if kat.noxaxis == True:
raise pkex.BasePyKatException("This kat object has noxaxis=True, so there is nothing to plot.")
if yaxis is not None:
kat.yaxis = yaxis
......@@ -745,6 +748,7 @@ class kat(object):
self.vacuum = []
self.__prevrunfilename = None
self.printmatrix = None
self.__variables = {}
# initialise default block
self.__currentTag= NO_BLOCK
......@@ -996,8 +1000,8 @@ class kat(object):
sys.exit(1)
else:
return
for o in self.__blocks[name].contents:
for o in self.__blocks[name].contents.copy():
self.remove(o)
del self.__blocks[name]
......@@ -1005,6 +1009,31 @@ class kat(object):
def __str__(self):
return "".join(self.generateKatScript())
def getVariable(self, name):
if name not in self.__variables:
raise pkex.BasePyKatException("Finesse variable `$%s` does not exist." % name)
return self.__variables[name]
def registerVariable(self, name, putter):
if '$' in name:
raise pkex.BasePyKatException("Finesse variable name `%s` should not include the `$` symbol as it is added internally." % name)
assert(putter is not None)
assert(name == putter.name)
if name in self.__variables:
raise pkex.BasePyKatException("Finesse variable name `%s` already exists." % name)
self.__variables[name] = putter
def unregisterVariable(self, name):
del self.__variables[name]
def printVariables(self):
for key in self.__variables:
print("$" + key, "::::", "owner =", self.__variables[key].owner.name, ", use count =", self.__variables[key].putCount)
def parseCommands(self, commands, blocks=None, addToBlock=None):
try:
if addToBlock is not None and blocks is not None:
......@@ -1077,7 +1106,7 @@ class kat(object):
obj = pykat.components.space.parseFinesseText(line)
elif(first == "l"):
obj = pykat.components.laser.parseFinesseText(line)
elif(first == "sq"):
elif(first[:2] == "sq"):
obj = pykat.components.squeezer.parseFinesseText(line)
elif(first[0:2] == "bs"):
obj = pykat.components.beamSplitter.parseFinesseText(line)
......@@ -1182,6 +1211,8 @@ class kat(object):
after_process.append((line, self.__currentTag))
elif(first == "noplot"):
after_process.append((line, self.__currentTag))
elif(first == "put" or first == "put*"):
after_process.append((line, self.__currentTag))
else:
if self.verbose:
print ("Parsing `{0}` into pykat object not implemented yet, added as extra line.".format(line))
......@@ -1231,7 +1262,41 @@ class kat(object):
raise pkex.BasePyKatException("noplot command `{0}` refers to non-existing detector".format(line))
getattr(self, rest).noplot = True
elif (first == "put" or first =="put*"):
alt = first == "put*"
values = line.split()
obj = values[1]
target = values[2]
variable = values[3]
try:
if not hasattr(self, obj):
raise pkex.BasePyKatException("put command `{0}` refers to non-existing component".format(line))
obj = getattr(self, obj)
if not hasattr(obj, target):
raise pkex.BasePyKatException("put command component `{0}` does not have a parameter `{1}`".format(line, target))
target = getattr(obj, target)
if not target.isPutable:
raise pkex.BasePyKatException("put command `{0}` parameter `{1}` cannot be put to".format(line, target))
target.put(self.getVariable(variable.replace('$', '')), alt)
except pkex.BasePyKatException as ex:
if self.verbose:
print("Warning: ", ex.msg)
print ("Parsing `{0}` into pykat object not implemented yet, added as extra line.".format(line))
obj = line
# manually add the line to the block contents
self.__blocks[block].contents.append(line)
elif (first == "scale"):
v = line.split()
accepted = ["psd","psd_hf","asd","asd_hf","meter", "ampere", "deg", "rad", "1/deg", "1/rad",]
......@@ -1368,7 +1433,7 @@ class kat(object):
except pkex.BasePyKatException as ex:
pkex.PrintError("Error parsing line: '%s':"% line, ex)
pkex.PrintError("Pykat error parsing line: '%s':"% line, ex)
sys.exit(1)
def saveScript(self, filename=None):
......@@ -1600,12 +1665,11 @@ class kat(object):
a = line.split(':', 1)
if a[0].isdigit():
#print("Found %s" % a[0])
values = a[1].split()
node_name = values[1].split("(")[0]
component_name = values[2].split("(")[0]
line1x = ifile.readline().replace('(','').replace(')','')
line2x = ifile.readline().replace('(','').replace(')','')
line1y = ifile.readline().replace('(','').replace(')','')
......@@ -1617,7 +1681,9 @@ class kat(object):
qx = spqx[0].split("=")[1].replace('i','j').replace(' ','')
qy = spqy[0].split("=")[1].replace('i','j').replace(' ','')
traceData[-1][node_name] = (pykat.beam_param(q=complex(qx)), pykat.beam_param(q=complex(qy)))
traceData[-1][node_name] = (pykat.beam_param(q=complex(qx), wavelength=self.lambda0),
pykat.beam_param(q=complex(qy), wavelength=self.lambda0),
component_name)
finally:
ifile.close()
......@@ -1641,14 +1707,14 @@ class kat(object):
#if len(self.detectors.keys()) > 0:
if hasattr(self, "x2axis") and self.noxaxis == False:
[r.x,r.y,r.z,hdr] = self.readOutFile(outfile)
[r.x, r.y, r.z, hdr] = self.readOutFile(outfile)
r.xlabel = hdr[0]
r.ylabel = hdr[1]
r.zlabels = [s.strip() for s in hdr[2:]]
#r.zlabels = map(str.strip, hdr[2:])
else:
[r.x,r.y,hdr] = self.readOutFile(outfile)
[r.x, r.y, hdr] = self.readOutFile(outfile)
r.xlabel = hdr[0]
r.ylabels = [s.strip() for s in hdr[1:]]
......@@ -1759,6 +1825,9 @@ class kat(object):
del nodes
if hasattr(obj, "_on_kat_remove"):
obj._on_kat_remove()
#import gc
#print (gc.get_referrers(obj))
......
......@@ -12,7 +12,8 @@ class putable(object):
Objects that inherit this should be able to have something `put` to it.
Essentially this means you could write Finesse commands like
put this parameter value
param.put(kat.xaxis.x)
"""
__metaclass__ = abc.ABCMeta
......@@ -20,45 +21,96 @@ class putable(object):
self._parameter_name = parameter_name
self._component_name = component_name
self._putter = None
self._alt = False
self._isPutable = isPutable
@property
def isPutable(self): return self._isPutable
def put(self, var):
if not isinstance(var, putter):
raise pkex.BasePyKatException("var was not something that can be `put` as a value")