Commit 847ec1e5 authored by Andreas Freise's avatar Andreas Freise
Browse files

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

parents 18729b12 8e2b56af
......@@ -6,6 +6,8 @@ It aims to provide a Python toolset for automating more complex tasks
as well as providing a GUI for manipulating and viewing simulation
setups.
Source code is hosted at https://git.ligo.org/finesse/pykat
Installation
-------------
......
......@@ -3,7 +3,7 @@ from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
__version__ = "1.0.14"
__version__ = "1.0.17"
# This flag is used to switch on the gui features in pkat at import time
USE_GUI = False
......@@ -20,7 +20,7 @@ except ImportError:
import pykat.exceptions as pkex
NoGUIException = pkex.BasePyKatException("No PyQt4 module was found so cannot open a GUI")
import pykat.finesse as finesse
import pykat.components as components
import pykat.detectors as detectors
......@@ -30,4 +30,3 @@ from pykat.optics.gaussian_beams import BeamParam
from pykat.plotting import init_pykat_plotting
......@@ -10,6 +10,8 @@ from __future__ import print_function
from __future__ import unicode_literals
import numpy
import warnings
import pykat
import pykat.external.six as six
import pykat.exceptions as pkex
......@@ -22,35 +24,38 @@ from numpy import min, max
from pykat.param import Param, putter
from collections import namedtuple
from pykat.optics.gaussian_beams import BeamParam
from pykat.freeze import canFreeze
@canFreeze
class Command(object):
__metaclass__ = abc.ABCMeta
def __init__(self, name, unique):
self.__dict__["____FROZEN____"] = False
self._kat = None
self.__unique = unique
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._unfreeze()
result.__dict__ = copy.deepcopy(self.__dict__, memo)
for _ in result._putters:
_._updateOwner(result)
result._freeze()
return result
def getFinesseText(self):
""" Base class for individual finesse optical components """
raise NotImplementedError("This function is not implemented")
......@@ -103,7 +108,8 @@ class variable(Command):
def __init__(self, name, value):
Command.__init__(self, name, False)
self.__value = value
self._freeze()
def getFinesseText(self):
return "variable {name} {value}".format(name=self.name, value=self.value)
......@@ -135,6 +141,8 @@ class func(Command):
self.output = putter(name, self)
self._putters.append(self.output)
self._freeze()
def getFinesseText(self):
rtn = []
......@@ -175,7 +183,8 @@ class lock(Command):
self.output = putter(name, self)
self._putters.append(self.output)
self._freeze()
@staticmethod
def parseFinesseText(line, kat):
v = line.split()
......@@ -228,6 +237,8 @@ class cavity(Command):
self.enabled = True
self._freeze()
def getFinesseText(self):
if self.enabled:
return 'cav {0} {1} {2} {3} {4}'.format(self.name, self.__c1.name, self.__n1.name, self.__c2.name, self.__n2.name);
......@@ -405,6 +416,8 @@ class tf(Command):
self.poles = []
self.gain = 1
self.phase = 0
self._freeze()
def addPole(self,f, Q):
self.poles.append(tf.fQ(SIfloat(f), SIfloat(Q)))
......@@ -504,6 +517,8 @@ class xaxis(Command):
self.__param = param
self.__comp = param._owner()
self._freeze()
def _set_variables(self):
self.x = putter("x1", self)
self.mx = putter("mx1", self)
......
......@@ -16,6 +16,7 @@ import pykat.external.six as six
if six.PY2:
import exceptions
import warnings
import pykat.exceptions as pkex
import pykat
from pykat.node_network import *
......@@ -36,6 +37,7 @@ from pykat.param import Param, AttrParam
import weakref
import pykat.exceptions as pkex
from copy import deepcopy
from pykat.freeze import canFreeze
next_component_id = 1
......@@ -85,7 +87,8 @@ class NodeGaussSetter(object):
self.__node().setGauss(self.__comp(), self.qx, complex(value))
id_____pykat_class = 0
@canFreeze
class Component(object):
__metaclass__ = abc.ABCMeta
......@@ -99,9 +102,11 @@ class Component(object):
cnew = type(cnew_name, (cls,), {})
return object.__new__(cnew)
o = object.__new__(cnew)
return o
def __init__(self, name=None):
self._unfreeze()
self._optivis_component = None
self.__name = name
......@@ -118,21 +123,22 @@ class Component(object):
global next_component_id
self.__id = next_component_id
next_component_id += 1
def __deepcopy__(self, memo):
"""
When deep copying a kat object we need to take into account
the instance specific properties.
"""
# Here we create a copy of this object based of the base class
# of this one, otherwise we're making a copy of a copy of a copy...
result = self.__class__.__new__(self.__class__.__base__)
result._unfreeze()
result.__dict__ = copy.deepcopy(self.__dict__, memo)
for _ in result._params:
_._updateOwner(result)
result._freeze()
return result
def _register_param(self, param):
......@@ -204,7 +210,8 @@ class Component(object):
self.__add_node_setter(ns)
def __add_node_setter(self, ns):
self._unfreeze()
if not isinstance(ns, NodeGaussSetter):
raise exceptions.ValueError("Argument is not of type NodeGaussSetter")
......@@ -214,6 +221,8 @@ class Component(object):
setattr(self.__class__, name, property(fget))
setattr(self, '__nodesetter_' + name, ns)
self._freeze()
def __get_node_setter(self, name):
return getattr(self, '__nodesetter_' + name)
......@@ -500,7 +509,8 @@ class mirror(AbstractMirrorComponent):
self._requested_node_names.append(node1)
self._requested_node_names.append(node2)
self._freeze()
def parseAttributes(self, values):
for key in values.keys():
......@@ -592,6 +602,8 @@ class beamSplitter(AbstractMirrorComponent):
self._requested_node_names.append(node3)
self._requested_node_names.append(node4)
self.__alpha = Param("alpha", self, SIfloat(alpha))
self._freeze()
@property
def alpha(self): return self.__alpha
......@@ -704,6 +716,8 @@ class space(Component):
self.__gy = AttrParam("gy", self, gy)
self._default_fsig_param = self.__L
self._freeze()
@property
def L(self): return self.__L
......@@ -830,6 +844,8 @@ class grating(Component):
self.__rho_0 = AttrParam("rho_0", self, SIfloat(rho_0))
self.__alpha = AttrParam("alpha", self, SIfloat(alpha))
self._svgItem = None
self._freeze()
@property
def n(self): return Param('n', self.__n)
......@@ -959,6 +975,7 @@ class isolator(Component):
self.__S = Param("S",self,SIfloat(S))
self.__L = Param("L",self,SIfloat(L))
self._freeze()
@property
def S(self): return self.__S
......@@ -1064,6 +1081,8 @@ class isolator1(Component):
self._requested_node_names.append(node4)
self._svgItem = None
self._freeze()
@staticmethod
def parseFinesseText(text):
values = text.split()
......@@ -1104,6 +1123,8 @@ class lens(Component):
self._svgItem = None
self.__f = Param("f", self, SIfloat(f))
self.__p = Param("p", self, SIfloat(p))
self._freeze()
@property
def f(self): return self.__f
......@@ -1200,6 +1221,8 @@ class modulator(Component):
self.type = modulation_type
self._default_fsig_param = self.__phase
self._freeze()
@property
def f(self): return self.__f
......@@ -1316,6 +1339,8 @@ class laser(Component):
self._svgItem = None
self._default_fsig_param = self.__f_offset
self._freeze()
@property
def P(self): return self.__power
......@@ -1413,6 +1438,9 @@ class squeezer(Component):
self.__angle = Param("angle", self, SIfloat(angle), canFsig=False, fsig_name="angle")
self._svgItem = None
self.entangled_carrier = entangled_carrier
self._freeze()
@property
def db(self): return self.__db
......
......@@ -26,6 +26,7 @@ import warnings
import copy
from pykat import USE_GUI, NoGUIException
from pykat.freeze import canFreeze
if USE_GUI:
import pykat.gui.resources
......@@ -33,6 +34,7 @@ if USE_GUI:
id_____pykat_class = 0
@canFreeze
class BaseDetector(object) :
"""
This is a base class for all detectors. Classes Detector1 and Detector2 should be used directly.
......@@ -51,9 +53,12 @@ class BaseDetector(object) :
cnew = type(cnew_name, (cls,), {})
return object.__new__(cnew)
o = object.__new__(cnew)
return o
def __init__(self, name, nodes=None, max_nodes=1):
self._unfreeze()
self.__name = name
self._svgItem = None
......@@ -106,8 +111,10 @@ class BaseDetector(object) :
# Here we create a copy of this object based of the base class
# of this one, otherwise we're making a copy of a copy of a copy...
result = self.__class__.__new__(self.__class__.__base__)
result._unfreeze()
result.__dict__ = copy.deepcopy(self.__dict__, memo)
result._freeze()
return result
def _register_param(self, param):
......@@ -243,6 +250,8 @@ class beam(Detector1):
self.alternate_beam = alternate_beam
self.__f = Param("f", self, frequency)
self._freeze()
@property
def f(self): return self.__f
......@@ -291,6 +300,8 @@ class cp(Detector0):
self.cavity = str(cavity)
self.direction = direction
self.parameter = parameter
self._freeze()
@property
def direction(self): return self.__direction
......@@ -345,6 +356,8 @@ class xd(Detector0):
self.component = component
self.motion = motion
self._freeze()
@staticmethod
def parseFinesseText(text):
......@@ -373,6 +386,8 @@ class ad(Detector1):
self.alternate_beam = alternate_beam
self.__f = Param("f", self, frequency)
self._freeze()
@property
def mode(self): return self.__mode
@mode.setter
......@@ -426,6 +441,8 @@ class gouy(Detector1):
self.spaces = copy.copy(spaces)
self.direction = direction
self.alternate_beam = False
self._freeze()
@property
def direction(self): return self.__dir
......@@ -475,6 +492,8 @@ class bp(Detector1):
self.parameter = parameter
self.direction = direction
self.alternate_beam = alternate_beam
self._freeze()
@property
def direction(self): return self.__dir
......@@ -598,9 +617,10 @@ class pd(Detector1):
ps[i].value = kwargs[p]
elif i<num_demods-1:
raise pkex.BasePyKatException("Missing demodulation phase {0} (phase{0})".format(i+1))
self.__set_demod_attrs()
self._freeze()
@property
def senstype(self): return self.__senstype
......@@ -655,6 +675,7 @@ class pd(Detector1):
For the set number of demodulations the correct number of
Parameters are created.
"""
self._unfreeze()
# if there are demodulations present then we want to add
# the various parameters so they are available for users
......@@ -678,8 +699,8 @@ class pd(Detector1):
if hasattr(self, "phase"+name):
delattr(self.__class__, "phase"+name)
else:
return
self._freeze()
@staticmethod
def parseFinesseText(text):
......@@ -776,7 +797,11 @@ class qnoised(pd):
def __init__(self, name, num_demods, node_name, alternate_beam=False, pdtype=None, **kwargs):
super(qnoised, self).__init__(name, num_demods, node_name, alternate_beam=alternate_beam, pdtype=pdtype, **kwargs)
self._unfreeze()
self.__homangle = AttrParam("homangle", self, None)
self._freeze()
@property
def homangle(self): return self.__homangle
......@@ -985,7 +1010,9 @@ class hd(Detector2):
BaseDetector.__init__(self, name, (node1_name, node2_name), max_nodes=2)
self.__phase = Param("phase", self, phase)
self._freeze()
@property
def phase(self): return self.__phase
@phase.setter
......@@ -1026,6 +1053,8 @@ class qhd(Detector2):
self.__phase = Param("phase", self, phase)
self.sensitivity = sensitivity
self._freeze()
@property
def phase(self): return self.__phase
......
......@@ -87,14 +87,13 @@ from pykat.commands import Command, xaxis
from pykat.SIfloat import *
from pykat.param import Param, AttrParam
from pykat.external import progressbar
from pykat.freeze import canFreeze
import pykat.external.six as six
import pykat.exceptions as pkex
from pykat import USE_GUI, HAS_OPTIVIS, NoGUIException
if HAS_OPTIVIS:
from optivis.bench.labels import Label as optivis_label
from optivis.geometry import Coordinates as optivis_coord
......@@ -210,6 +209,16 @@ class BlockedKatFile(object):
bkf.write("mytest.kat")
"""
def __str__(self):
rtn = ""
for block in self.ordering:
rtn += "\n%%% FTblock " + block + "\n"
rtn += self.blocks[block]
rtn += "%%% FTend " + block + "\n"
return rtn
def __init__(self, NO_BLOCK="NO_BLOCK"):
self.__NO_BLOCK = NO_BLOCK
self.ordering = [self.__NO_BLOCK]
......@@ -265,12 +274,14 @@ class BlockedKatFile(object):
if len(values) >= 3 and values[0] == "%%%":
if values[1] == "FTblock":
newTag = values[2]
if self.__currentBlock != None and self.__currentBlock != self.__NO_BLOCK:
warnings.warn("found block {0} before block {1} ended".format(newTag, self.__currentBlock))
if newTag in self.blocks:
raise pkex.BasePyKatException("Block `{0}` has already been read".format(newTag))
#raise pkex.BasePyKatException("Block `{0}` has already been read".format(newTag))
self.__currentBlock = newTag
continue
self.blocks[newTag] = ""
self.__currentBlock = newTag
......@@ -330,18 +341,24 @@ def GUILength(L):
Should scale the lengths in some way to handle km and mm for time being
"""
return L # * ( 40 * erfc(L/400.0) + 0.01)
@canFreeze
class KatRun(object):
def __init__(self):
self._unfreeze()
self.runtime = None
self.StartDateTime = datetime.datetime.now()
self.x = None
self.stdout = None
self.stderr = None
self.runDateTime = None
self.y = None
self.xlabel = None
self.ylabels = None
self.katScript = None
self.katVersion = None
self.yaxis = None
self._freeze()
def info(self):
......@@ -623,9 +640,11 @@ class KatRun(object):
return out.squeeze()
else:
raise pkex.BasePyKatException("No output by the name '{0}' found in the output".format(str(value)))
@canFreeze
class KatRun2D(object):
def __init__(self):
self._unfreeze()
self.runtime = None
self.startDateTime = datetime.datetime.now()
self.x = None
......@@ -638,6 +657,7 @@ class KatRun2D(object):
self.katVersion = None
self.stderr = None
self.stdout = None
self._freeze()
def saveKatRun(self, filename):
with open(filename,'w') as outfile:
......@@ -658,10 +678,13 @@ class KatRun2D(object):
else:
raise pkex.BasePyKatException("No output by the name {0} found".format(str(value)))
@canFreeze
class Signals(object):
@canFreeze
class fsig(object):
def __init__(self, param, name, amplitude, phase, signal):
self._unfreeze()
self._params = []
self.__target = param
self.__name = name
......@@ -669,6 +692,7 @@ class Signals(object):
self.__phase = Param("phase", self, SIfloat(phase))
self.__removed = False
self.__signal = signal
self._freeze()
# unfortunatenly the target names for fsig are not the same as the
# various parameter names of the components, e.g. mirror xbeta is x
......@@ -691,7 +715,7 @@ class Signals(object):
raise pkex.BasePyKatException("Signal {0} has already been marked as removed".format(self.name))
else:
self.__signal.targets.remove(self)
self.__remove = True
self.__removed = True
@property
def name(self): return self.__name
......@@ -742,29 +766,36 @@ class Signals(object):
del self.targets[:]
self.f = None
@property
def f(self): return self.__f
@f.setter
def f(self,value):
if value is None:
self.__f.value = None
return
v = SIfloat(value)
if v <= 0:
raise pkex.BasePyKatException("Signal frequency must be greater than 0.")
self.__f.value = SIfloat(value)
def __init__(self, kat):
self._unfreeze()
self._default_name = "fsignal"
self.targets = []
self._params = []
self.__f = Param("f", self, None)
self._kat = kat
self._freeze()
def _register_param(self, param):
self._params.append(param)
def apply(self, target, amplitude, phase, name=None):
if target is None:
raise pkex.BasePyKatException("No target was specified for signal to be applied")
......@@ -811,6 +842,7 @@ Constant = namedtuple('Constant', 'name, value, usedBy')
id___ = 0
@canFreeze
class kat(object):
def __new__(cls, *args, **kwargs):
......@@ -828,7 +860,7 @@ class kat(object):
return object.__new__(cnew)
def __init__(self, kat_file=None, kat_code=None, katdir="", katname="", tempdir=None, tempname=None):