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

Merge remote-tracking branch 'upstream/master'

parents 4e3ed73a 3883f95c
......@@ -34,6 +34,22 @@ 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 """
......@@ -49,9 +65,29 @@ class Command(object):
"""
self._kat = kat
for _ in self._putters:
kat.registerVariable(_.name, _)
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)
self.__removed = True
@property
def name(self): return self.__name
......@@ -95,10 +131,15 @@ 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.enabled:
if self.noplot:
rtn.append("noplot " + self.name)
......@@ -120,9 +161,6 @@ class func(Command):
raise pkex.BasePyKatException("'{0}' not a valid Finesse func command".format(line))
class lock(Command):
def __init__(self, name, variable, gain, accuracy, singleLock=False):
Command.__init__(self, name, False)
......@@ -134,6 +172,10 @@ class lock(Command):
self.enabled = True
self.output = putter(name, self)
self._putters.append(self.output)
@staticmethod
def parseFinesseText(line, kat):
v = line.split()
......@@ -279,6 +321,77 @@ class gauss(object):
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):
......@@ -354,8 +467,11 @@ 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
......@@ -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):
......@@ -163,6 +166,16 @@ class Component(object):
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,17 +250,11 @@ class Component(object):
def __str__(self): return self.name
def remove(self):
if self.__removed:
raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
else:
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
def getOptivisParameterDict(self):
if len(self._params) == 0:
return None
......
......@@ -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))
......
......@@ -753,6 +753,7 @@ class kat(object):
self.vacuum = []
self.__prevrunfilename = None
self.printmatrix = None
self.__variables = {}
# initialise default block
self.__currentTag= NO_BLOCK
......@@ -1005,7 +1006,7 @@ class kat(object):
else:
return
for o in self.__blocks[name].contents:
for o in self.__blocks[name].contents.copy():
self.remove(o)
del self.__blocks[name]
......@@ -1013,6 +1014,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:
......@@ -1190,6 +1216,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))
......@@ -1240,6 +1268,40 @@ class kat(object):
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",]
......@@ -1376,7 +1438,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):
......@@ -1649,14 +1711,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:]]
......@@ -1767,6 +1829,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,46 +21,97 @@ 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):
def put(self, var, alt=False):
if not self._isPutable:
raise pkex.BasePyKatException("Can't put to this object")
if not isinstance(var, putter):
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))
if self._putter != None:
self._putter.put_count -= 1
self._putter.putees.remove(self)
# Remove existing puts
if self._putter is not None:
self._putter.unregister(self)
self._putter = var
if var != None:
self._putter.put_count += 1
self._putter.putees.append(self)
self._alt = alt
if var is not None:
self._putter.register(self)
def _getPutFinesseText(self):
rtn = []
if self._isPutable and self._putter is not None:
putter_enabled = True
if hasattr(self._putter.owner, 'enabled'):
putter_enabled = self._putter.owner.enabled
if putter_enabled:
if self._alt:
alt = '*'
else:
alt = ''
# if something is being put to this
if self._putter != None:
rtn.append("put {comp} {param} ${value}".format(comp=self._component_name, param=self._parameter_name, value=self._putter.put_name()))
rtn.append("put{alt} {comp} {param} ${value}".format(alt=alt, comp=self._component_name, param=self._parameter_name, value=self._putter.put_name()))
return rtn
class putter(object):
"""
If an object can be put to something that is putable it should inherit this
object.
"""
def __init__(self, put_name, isPutter=True):
def __init__(self, put_name, owner, isPutter=True):
self._put_name = put_name
self.put_count = 0
self._isPutter = isPutter
self.putees = [] # list of params that this puts to
assert(owner is not None)
self.__owner = weakref.ref(owner)
def _updateOwner(self, newOwner):
del self.__owner
self.__owner = weakref.ref(newOwner)
def clearPuts(self):
for _ in self.putees.copy():
_.put(None)
def register(self, toput):
if not self._isPutter:
raise pkex.BasePyKatException("This object can't put")
self.put_count += 1
self.putees.append(toput)
def unregister(self, item):
if not self._isPutter:
raise pkex.BasePyKatException("This object can't put")
self.put_count -= 1
self.putees.remove(item)
@property
def owner(self): return self.__owner()
@property
def name(self): return self._put_name
@property
def putCount(self): return self.put_count
@property
def isPutter(self): return self._isPutter
......@@ -68,15 +120,18 @@ class putter(object):
class Param(putable, putter):
def __init__(self, name, owner, value, canFsig=False, fsig_name=None, isPutable=True, isPutter=True, isTunable=True, var_name=None):
def __init__(self, name, owner, value, canFsig=False, fsig_name=None, isPutable=True, isPutter=True, isTunable=True, var_name=None, register=True):
self._name = name
self._registered = register
self._owner = weakref.ref(owner)
self._value = value
self._isPutter = isPutter
self._isTunable = isTunable
self._owner()._register_param(self)
self._canFsig = False
if self._registered:
self._owner()._register_param(self)
if canFsig:
self._canFsig = True
......@@ -89,19 +144,10 @@ class Param(putable, putter):
if var_name is None:
var_name = "var_{0}_{1}".format(owner.name, name)
putter.__init__(self, var_name, isPutter)
putter.__init__(self, var_name, owner, isPutter)
putable.__init__(self, owner.name, name, isPutable)
def _updateOwner(self, newOwner):
"""
This updates the internal weak reference to link a parameter to who owns it.
Should only be called by the __deepcopy__ component method to ensure things
are kept up to date.
"""
del self._owner
self._owner = weakref.ref(newOwner)
@property
def canFsig(self): return self._canFsig
......@@ -163,6 +209,15 @@ class Param(putable, putter):
return rtn
def _updateOwner(self, newOwner):
"""
This updates the internal weak reference to link a parameter to who owns it.
Should only be called by the __deepcopy__ component method to ensure things
are kept up to date.
"""
del self._owner
self._owner = weakref.ref(newOwner)
def _onOwnerRemoved(self):
#if this param can be put somewhere we need to check if it is
if self.isPutable:
......
......@@ -13,9 +13,11 @@ kat.loadKatFile("LHO_IFO_maxtem2.kat") # load the conf
kat.parseKatCode( "fsig sig1 ETMXHR 10 180")
kat.parseKatCode( "fsig sig1 ETMYHR 10 0")
kat.parseKatCode( "pd1 myomc 10 nOMC_HROC_trans")
kat.parseKatCode( "put myomc f1 $x1") # to follow
kat.parseKatCode( "xaxis sig1 f log 10 1k 10")
kat.parseKatCode( "put myomc f1 $x1") # to follow
kat.parseKatCode( "yaxis abs:deg")
kat.verbose = True
out = kat.run() # do the computation
result.append(out['myomc']) # append the result
print("PASSED")
\ No newline at end of file
......@@ -25,6 +25,9 @@ assert(kat0.nodes.n0 != kat1.nodes.n0)
assert(kat0.o1 != kat1.o1)
assert(kat0.o1.__class__ != kat1.o1.__class__)
assert(kat0.m1.phi.owner == kat0.m1)
assert(kat1.m1.phi.owner == kat1.m1)