Commit eef8f458 authored by Sebastian Steinlechner's avatar Sebastian Steinlechner
Browse files

Merge remote-tracking branch 'upstream/master'

parents 4e3ed73a 3883f95c
...@@ -34,7 +34,23 @@ class Command(object): ...@@ -34,7 +34,23 @@ class Command(object):
self.tag = None self.tag = None
self.__removed = False self.__removed = False
self.__name = name.strip("*") 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): def getFinesseText(self):
""" Base class for individual finesse optical components """ """ Base class for individual finesse optical components """
raise NotImplementedError("This function is not implemented") raise NotImplementedError("This function is not implemented")
...@@ -48,10 +64,30 @@ class Command(object): ...@@ -48,10 +64,30 @@ class Command(object):
Called when this component has been added to a kat object Called when this component has been added to a kat object
""" """
self._kat = kat self._kat = kat
for _ in self._putters:
kat.registerVariable(_.name, _)
def remove(self): def _on_kat_remove(self):
self._kat.remove(self)
self.__removed = True 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 @property
def name(self): return self.__name def name(self): return self.__name
...@@ -95,14 +131,19 @@ class func(Command): ...@@ -95,14 +131,19 @@ class func(Command):
self.value = value self.value = value
self.noplot = False self.noplot = False
self.enabled = True
self.output = putter(name, self)
self._putters.append(self.output)
def getFinesseText(self): def getFinesseText(self):
rtn = [] rtn = []
if self.noplot: if self.enabled:
rtn.append("noplot " + self.name) 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 return rtn
...@@ -118,10 +159,7 @@ class func(Command): ...@@ -118,10 +159,7 @@ class func(Command):
return func(v2[0].split()[1], v2[1]) return func(v2[0].split()[1], v2[1])
else: else:
raise pkex.BasePyKatException("'{0}' not a valid Finesse func command".format(line)) raise pkex.BasePyKatException("'{0}' not a valid Finesse func command".format(line))
class lock(Command): class lock(Command):
def __init__(self, name, variable, gain, accuracy, singleLock=False): def __init__(self, name, variable, gain, accuracy, singleLock=False):
...@@ -132,6 +170,10 @@ class lock(Command): ...@@ -132,6 +170,10 @@ class lock(Command):
self.__accuracy = accuracy self.__accuracy = accuracy
self.singleLock = singleLock self.singleLock = singleLock
self.enabled = True self.enabled = True
self.output = putter(name, self)
self._putters.append(self.output)
@staticmethod @staticmethod
...@@ -278,7 +320,78 @@ class gauss(object): ...@@ -278,7 +320,78 @@ class gauss(object):
kat.nodes[node].setGauss(kat.components[component], gp) kat.nodes[node].setGauss(kat.components[component], gp)
else: else:
kat.nodes[node].setGauss(kat.components[component], gpx, gpy) 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 tf(Command):
class fQ(object): class fQ(object):
...@@ -298,7 +411,7 @@ class tf(Command): ...@@ -298,7 +411,7 @@ class tf(Command):
def addZero(self,f, Q): def addZero(self,f, Q):
self.zeros.append(tf.fQ(SIfloat(f), SIfloat(Q))) self.zeros.append(tf.fQ(SIfloat(f), SIfloat(Q)))
@staticmethod @staticmethod
def parseFinesseText(text): def parseFinesseText(text):
values = text.split() values = text.split()
...@@ -354,9 +467,12 @@ class xaxis(Command): ...@@ -354,9 +467,12 @@ class xaxis(Command):
self._axis_type = axis_type self._axis_type = axis_type
self.x = putter("x1") self.x = putter("x1", self)
self.mx = putter("mx1") self.mx = putter("mx1", self)
self._putters.append(self.x)
self._putters.append(self.mx)
if scale == "lin": if scale == "lin":
scale = Scale.linear scale = Scale.linear
elif scale == "log": elif scale == "log":
...@@ -433,8 +549,11 @@ class xaxis(Command): ...@@ -433,8 +549,11 @@ class xaxis(Command):
class x2axis(xaxis): class x2axis(xaxis):
def __init__(self, scale, limits, param, steps, comp=None, axis_type="x2axis"): 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) xaxis.__init__(self, scale, limits, param, steps, comp=comp, axis_type=axis_type)
self.x = putter("x2") self.x = putter("x2", self)
self.mx = putter("mx2") self.mx = putter("mx2", self)
self._putters.append(self.x)
self._putters.append(self.mx)
@staticmethod @staticmethod
def parseFinesseText(text): def parseFinesseText(text):
......
...@@ -84,7 +84,7 @@ class NodeGaussSetter(object): ...@@ -84,7 +84,7 @@ class NodeGaussSetter(object):
def qy(self, value): def qy(self, value):
self.__node().setGauss(self.__comp(), self.qx, complex(value)) self.__node().setGauss(self.__comp(), self.qx, complex(value))
id___ = 0 id_____pykat_class = 0
class Component(object): class Component(object):
__metaclass__ = abc.ABCMeta __metaclass__ = abc.ABCMeta
...@@ -93,9 +93,9 @@ class Component(object): ...@@ -93,9 +93,9 @@ class Component(object):
# This creates an instance specific class for the component # This creates an instance specific class for the component
# this enables us to add properties to instances rather than # this enables us to add properties to instances rather than
# all classes # all classes
global id___ global id_____pykat_class
id___ += 1 id_____pykat_class += 1
cnew_name = str("%s.%s_%i" % (cls.__module__, cls.__name__, id___)) cnew_name = str("%s.%s_%i" % (cls.__module__, cls.__name__, id_____pykat_class))
cnew = type(cnew_name, (cls,), {}) cnew = type(cnew_name, (cls,), {})
...@@ -130,6 +130,9 @@ class Component(object): ...@@ -130,6 +130,9 @@ class Component(object):
result = self.__class__.__new__(self.__class__.__base__) result = self.__class__.__new__(self.__class__.__base__)
result.__dict__ = copy.deepcopy(self.__dict__, memo) result.__dict__ = copy.deepcopy(self.__dict__, memo)
for _ in result._params:
_._updateOwner(result)
return result return result
def _register_param(self, param): def _register_param(self, param):
...@@ -162,7 +165,17 @@ class Component(object): ...@@ -162,7 +165,17 @@ class Component(object):
self._kat = kat self._kat = kat
kat.nodes.registerComponentNodes(self, self._requested_node_names, self.__on_node_change) 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): def __on_node_change(self):
# need to update the node gauss parameter setter members # need to update the node gauss parameter setter members
self.__update_node_setters() self.__update_node_setters()
...@@ -237,16 +250,10 @@ class Component(object): ...@@ -237,16 +250,10 @@ class Component(object):
def __str__(self): return self.name def __str__(self): return self.name
def remove(self): def remove(self):
self._kat.remove(self) if self.__removed:
raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
# inform all parameters that we have removed its owner else:
# so that it can then warn about any puts/vars/xaxis self._kat.remove(self)
for p in self._params:
p._onOwnerRemoved()
del self._params[:]
self.__removed = True
def getOptivisParameterDict(self): def getOptivisParameterDict(self):
if len(self._params) == 0: if len(self._params) == 0:
......
...@@ -31,7 +31,7 @@ if USE_GUI: ...@@ -31,7 +31,7 @@ if USE_GUI:
import pykat.gui.resources import pykat.gui.resources
from pykat.gui.graphics import * from pykat.gui.graphics import *
id___ = 0 id_____pykat_class = 0
class BaseDetector(object) : class BaseDetector(object) :
""" """
...@@ -45,9 +45,9 @@ class BaseDetector(object) : ...@@ -45,9 +45,9 @@ class BaseDetector(object) :
# This creates an instance specific class for the component # This creates an instance specific class for the component
# this enables us to add properties to instances rather than # this enables us to add properties to instances rather than
# all classes # all classes
global id___ global id_____pykat_class
id___ += 1 id_____pykat_class += 1
cnew_name = str("%s.%s_%i" % (cls.__module__, cls.__name__, id___)) cnew_name = str("%s.%s_%i" % (cls.__module__, cls.__name__, id_____pykat_class))
cnew = type(cnew_name, (cls,), {}) cnew = type(cnew_name, (cls,), {})
...@@ -120,6 +120,9 @@ class BaseDetector(object) : ...@@ -120,6 +120,9 @@ class BaseDetector(object) :
if rn != None: if rn != None:
self._nodes.append(kat.nodes.createNode(rn)) self._nodes.append(kat.nodes.createNode(rn))
def _on_kat_remove(self):
self.__removed = True
def remove(self): def remove(self):
if self.__removed: if self.__removed:
raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name)) raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
......
...@@ -753,6 +753,7 @@ class kat(object): ...@@ -753,6 +753,7 @@ class kat(object):
self.vacuum = [] self.vacuum = []
self.__prevrunfilename = None self.__prevrunfilename = None
self.printmatrix = None self.printmatrix = None
self.__variables = {}
# initialise default block # initialise default block
self.__currentTag= NO_BLOCK self.__currentTag= NO_BLOCK
...@@ -1004,8 +1005,8 @@ class kat(object): ...@@ -1004,8 +1005,8 @@ class kat(object):
sys.exit(1) sys.exit(1)
else: else:
return return
for o in self.__blocks[name].contents: for o in self.__blocks[name].contents.copy():
self.remove(o) self.remove(o)
del self.__blocks[name] del self.__blocks[name]
...@@ -1013,6 +1014,31 @@ class kat(object): ...@@ -1013,6 +1014,31 @@ class kat(object):
def __str__(self): def __str__(self):
return "".join(self.generateKatScript()) 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): def parseCommands(self, commands, blocks=None, addToBlock=None):
try: try:
if addToBlock is not None and blocks is not None: if addToBlock is not None and blocks is not None:
...@@ -1190,6 +1216,8 @@ class kat(object): ...@@ -1190,6 +1216,8 @@ class kat(object):
after_process.append((line, self.__currentTag)) after_process.append((line, self.__currentTag))
elif(first == "noplot"): elif(first == "noplot"):
after_process.append((line, self.__currentTag)) after_process.append((line, self.__currentTag))
elif(first == "put" or first == "put*"):
after_process.append((line, self.__currentTag))
else: else:
if self.verbose: if self.verbose:
print ("Parsing `{0}` into pykat object not implemented yet, added as extra line.".format(line)) print ("Parsing `{0}` into pykat object not implemented yet, added as extra line.".format(line))
...@@ -1239,7 +1267,41 @@ class kat(object): ...@@ -1239,7 +1267,41 @@ class kat(object):
raise pkex.BasePyKatException("noplot command `{0}` refers to non-existing detector".format(line)) raise pkex.BasePyKatException("noplot command `{0}` refers to non-existing detector".format(line))
getattr(self, rest).noplot = True 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"): elif (first == "scale"):
v = line.split() v = line.split()
accepted = ["psd","psd_hf","asd","asd_hf","meter", "ampere", "deg", "rad", "1/deg", "1/rad",] accepted = ["psd","psd_hf","asd","asd_hf","meter", "ampere", "deg", "rad", "1/deg", "1/rad",]
...@@ -1376,7 +1438,7 @@ class kat(object): ...@@ -1376,7 +1438,7 @@ class kat(object):
except pkex.BasePyKatException as ex: 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) sys.exit(1)
def saveScript(self, filename=None): def saveScript(self, filename=None):
...@@ -1649,14 +1711,14 @@ class kat(object): ...@@ -1649,14 +1711,14 @@ class kat(object):
#if len(self.detectors.keys()) > 0: #if len(self.detectors.keys()) > 0:
if hasattr(self, "x2axis") and self.noxaxis == False: 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.xlabel = hdr[0]
r.ylabel = hdr[1] r.ylabel = hdr[1]
r.zlabels = [s.strip() for s in hdr[2:]] r.zlabels = [s.strip() for s in hdr[2:]]
#r.zlabels = map(str.strip, hdr[2:]) #r.zlabels = map(str.strip, hdr[2:])
else: else:
[r.x,r.y,hdr] = self.readOutFile(outfile) [r.x, r.y, hdr] = self.readOutFile(outfile)
r.xlabel = hdr[0] r.xlabel = hdr[0]
r.ylabels = [s.strip() for s in hdr[1:]] r.ylabels = [s.strip() for s in hdr[1:]]
...@@ -1767,6 +1829,9 @@ class kat(object): ...@@ -1767,6 +1829,9 @@ class kat(object):
del nodes del nodes
if hasattr(obj, "_on_kat_remove"):
obj._on_kat_remove()
#import gc #import gc
#print (gc.get_referrers(obj)) #print (gc.get_referrers(obj))
......
...@@ -12,7 +12,8 @@ class putable(object): ...@@ -12,7 +12,8 @@ class putable(object):
Objects that inherit this should be able to have something `put` to it. Objects that inherit this should be able to have something `put` to it.
Essentially this means you could write Finesse commands like Essentially this means you could write Finesse commands like
put this parameter value param.put(kat.xaxis.x)
""" """
__metaclass__ = abc.ABCMeta __metaclass__ = abc.ABCMeta
...@@ -20,45 +21,96 @@ class putable(object): ...@@ -20,45 +21,96 @@ class putable(object):
self._parameter_name = parameter_name self._parameter_name = parameter_name
self._component_name = component_name self._component_name = component_name
self._putter = None self._putter = None
self._alt = False
self._isPutable = isPutable self._isPutable = isPutable
@property @property
def isPutable(self): return self._isPutable def isPutable(self): return self._isPutable
def put(self, var): def put(self, var, alt=False):
if not self._isPutable:
if not isinstance(var, putter): raise pkex.BasePyKatException("Can't put to this object")
raise pkex.BasePyKatException("var was not something that can be `put` as a value")
if var is not None and not isinstance(var, putter):
raise pkex.BasePyKatException("`%s` was not something that can be `put` to a parameter" % str(var))