Skip to content
Snippets Groups Projects
Commit dc470f85 authored by Andreas Freise's avatar Andreas Freise
Browse files

trying to fix wrong commit from some time ago, still needs fixing.

parent 864005dd
Branches
No related tags found
No related merge requests found
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
__version__ = "0.6.2" __version__ = "0.6.2"
# This flag is used to switch on the gui features in pkat at import time # This flag is used to switch on the gui features in pkat at import time
USE_GUI = False USE_GUI = False
HAS_OPTIVIS = False
import imp
try:
imp.find_module('optivis')
HAS_OPTIVIS = True
except ImportError:
HAS_OPTIVIS = False
import pykat.exceptions as pkex import pykat.exceptions as pkex
......
...@@ -9,7 +9,7 @@ from __future__ import division ...@@ -9,7 +9,7 @@ from __future__ import division
from __future__ import print_function from __future__ import print_function
from __future__ import unicode_literals from __future__ import unicode_literals
from pykat import USE_GUI, NoGUIException from pykat import USE_GUI, HAS_OPTIVIS, NoGUIException
import pykat.external.six as six import pykat.external.six as six
...@@ -21,15 +21,22 @@ import pykat ...@@ -21,15 +21,22 @@ import pykat
from pykat.node_network import * from pykat.node_network import *
from pykat.exceptions import * from pykat.exceptions import *
import abc import abc
import copy
from collections import OrderedDict
if HAS_OPTIVIS:
import optivis.bench.components as optivis_components
from optivis.view.canvas import OptivisCanvasItemDataType
from optivis.bench.labels import Label as optivis_label
from optivis.geometry import Coordinates as optivis_coord
import PyQt4
from pykat.SIfloat import * from pykat.SIfloat import *
from pykat.param import Param, AttrParam from pykat.param import Param, AttrParam
import weakref import weakref
import pykat.exceptions as pkex import pykat.exceptions as pkex
from copy import deepcopy
next_component_id = 1
from pykat import USE_GUI, NoGUIException next_component_id = 1
if USE_GUI: if USE_GUI:
import pykat.gui.resources import pykat.gui.resources
...@@ -79,7 +86,15 @@ class NodeGaussSetter(object): ...@@ -79,7 +86,15 @@ class NodeGaussSetter(object):
class Component(object): class Component(object):
__metaclass__ = abc.ABCMeta __metaclass__ = abc.ABCMeta
def __init__(self, name): def __new__(cls, *args, **kwargs):
# This creates an instance specific class for the component
# this enables us to add properties to instances rather than
# all classes
return object.__new__(type(cls.__name__, (cls,), {}), *args, **kwargs)
def __init__(self, name=None):
self._optivis_component = None
self.__name = name self.__name = name
self._svgItem = None self._svgItem = None
self._requested_node_names = [] self._requested_node_names = []
...@@ -88,17 +103,25 @@ class Component(object): ...@@ -88,17 +103,25 @@ class Component(object):
self._params = [] self._params = []
self.__removed = False self.__removed = False
self._default_fsig_param = None self._default_fsig_param = None
self.optivisLabelContent = None
# store a unique ID for this component # store a unique ID for this component
global next_component_id global next_component_id
self.__id = next_component_id self.__id = next_component_id
next_component_id += 1 next_component_id += 1
# This creates an instance specific class for the component
# this enables us to add properties to instances rather than def __deepcopy__(self, memo):
# all classes """
cls = type(self) When deep copying a kat object we need to take into account
self.__class__ = type(cls.__name__, (cls,), {}) the instance specific properties.
"""
result = self.__class__.__new__(self.__class__)
result.__dict__ = copy.deepcopy(self.__dict__, memo)
result.__update_node_setters
return result
def _register_param(self, param): def _register_param(self, param):
self._params.append(param) self._params.append(param)
...@@ -210,18 +233,36 @@ class Component(object): ...@@ -210,18 +233,36 @@ class Component(object):
self.__removed = True self.__removed = True
def __deepcopy__(self, memo): def getOptivisParameterDict(self):
cls = self.__class__ if len(self._params) == 0:
result = cls.__new__(cls) return None
memo[id(self)] = result
for k, v in self.__dict__.items(): d = OrderedDict()
setattr(result, k, deepcopy(v, memo))
for p in result._params: for p in self._params:
p._updateOwner(result) d[p.name] = OptivisCanvasItemDataType.TEXTBOX
return d
def getOptivisTooltip(self):
tooltip = "Name: %s" % self.name
for p in self._params:
if p.value is not None:
tooltip += "\n%s = %s" %(p.name, str(p.value))
return tooltip
def setOptivisLabelContent(self):
"""
Sets default Optivis label contents
"""
if self.optivisLabelContent is None:
self.optivisLabelContent = {}
self.optivisLabelContent["Name"] = self.name
return result
class AbstractMirrorComponent(Component): class AbstractMirrorComponent(Component):
__metaclass__ = abc.ABCMeta __metaclass__ = abc.ABCMeta
...@@ -258,12 +299,12 @@ class AbstractMirrorComponent(Component): ...@@ -258,12 +299,12 @@ class AbstractMirrorComponent(Component):
self.__rxmech = AttrParam("rxmech", self, rxmech) self.__rxmech = AttrParam("rxmech", self, rxmech)
self.__rymech = AttrParam("rymech", self, rymech) self.__rymech = AttrParam("rymech", self, rymech)
self.__z = Param("z", self, 0, canFsig=True, isPutable=False, isPutter=False, isTunable=False, fsig_name="z") self.__z = Param("z", self, None, canFsig=True, isPutable=False, isPutter=False, isTunable=False, fsig_name="z")
self.__rx = Param("rx", self, 0, canFsig=True, isPutable=False, isPutter=False, isTunable=False, fsig_name="rx") self.__rx = Param("rx", self, None, canFsig=True, isPutable=False, isPutter=False, isTunable=False, fsig_name="rx")
self.__ry = Param("ry", self, 0, canFsig=True, isPutable=False, isPutter=False, isTunable=False, fsig_name="ry") self.__ry = Param("ry", self, None, canFsig=True, isPutable=False, isPutter=False, isTunable=False, fsig_name="ry")
self.__Fz = Param("Fz", self, 0, canFsig=True, isPutable=False, isPutter=False, isTunable=False, fsig_name="Fz") self.__Fz = Param("Fz", self, None, canFsig=True, isPutable=False, isPutter=False, isTunable=False, fsig_name="Fz")
self.__Frx = Param("Frx", self, 0, canFsig=True, isPutable=False, isPutter=False, isTunable=False, fsig_name="Frx") self.__Frx = Param("Frx", self, None, canFsig=True, isPutable=False, isPutter=False, isTunable=False, fsig_name="Frx")
self.__Fry = Param("Fry", self, 0, canFsig=True, isPutable=False, isPutter=False, isTunable=False, fsig_name="Fry") self.__Fry = Param("Fry", self, None, canFsig=True, isPutable=False, isPutter=False, isTunable=False, fsig_name="Fry")
self._default_fsig_param = self.__phi self._default_fsig_param = self.__phi
...@@ -450,6 +491,37 @@ class mirror(AbstractMirrorComponent): ...@@ -450,6 +491,37 @@ class mirror(AbstractMirrorComponent):
return rtn return rtn
def getOptivisComponent(self):
self.setOptivisLabelContent()
if self._optivis_component is None:
self._optivis_component = optivis_components.CavityMirror(name=self.name, aoi=0, tooltip=self.getOptivisTooltip, paramList=self.getOptivisParameterDict(), pykatObject=weakref.ref(self))
lbl = optivis_label(text="", position=optivis_coord(0, -1), item=self._optivis_component)
lbl.content["Name"] = self.name
self._optivis_component.labels.append(lbl)
return self._optivis_component
def getOptivisNode(self, mode, kat_node):
mode = mode.lower()
if mode != "input" and mode.lower() != "output":
raise pkex.BasePyKatException("Mode must be either input or output not %s" % mode)
if mode == "input":
if kat_node is self.nodes[0]:
return self._optivis_component.getInputNode("fr")
else:
return self._optivis_component.getInputNode("bk")
elif mode == "output":
if kat_node is self.nodes[0]:
return self._optivis_component.getOutputNode("fr")
else:
return self._optivis_component.getOutputNode("bk")
def getQGraphicsItem(self): def getQGraphicsItem(self):
if not USE_GUI: if not USE_GUI:
raise NoGUIException raise NoGUIException
...@@ -483,6 +555,39 @@ class beamSplitter(AbstractMirrorComponent): ...@@ -483,6 +555,39 @@ class beamSplitter(AbstractMirrorComponent):
else: else:
raise pkex.BasePyKatException("No attribute {0} for mirrors".format(key)) raise pkex.BasePyKatException("No attribute {0} for mirrors".format(key))
def getOptivisComponent(self):
self.setOptivisLabelContent()
if self._optivis_component is None:
self._optivis_component = optivis_components.BeamSplitter(name=self.name, aoi=-self.alpha, tooltip=self.getOptivisTooltip, paramList=self.getOptivisParameterDict(), pykatObject=weakref.ref(self))
return self._optivis_component
def getOptivisNode(self, mode, kat_node):
mode = mode.lower()
if mode != "input" and mode.lower() != "output":
raise pkex.BasePyKatException("Mode must be either input or output")
if mode == "input":
if kat_node is self.nodes[0]:
return self._optivis_component.getInputNode("frA")
elif kat_node is self.nodes[1]:
return self._optivis_component.getInputNode("frB")
elif kat_node is self.nodes[2]:
return self._optivis_component.getInputNode("bkB")
elif kat_node is self.nodes[3]:
return self._optivis_component.getInputNode("bkA")
elif mode == "output":
if kat_node is self.nodes[0]:
return self._optivis_component.getOutputNode("frB")
elif kat_node is self.nodes[1]:
return self._optivis_component.getOutputNode("frA")
elif kat_node is self.nodes[2]:
return self._optivis_component.getOutputNode("bkA")
elif kat_node is self.nodes[3]:
return self._optivis_component.getOutputNode("bkB")
@staticmethod @staticmethod
def parseFinesseText(text): def parseFinesseText(text):
values = text.split() values = text.split()
...@@ -579,6 +684,18 @@ class space(Component): ...@@ -579,6 +684,18 @@ class space(Component):
@gy.setter @gy.setter
def gy(self,value): self.__gy.value = SIfloat(value) def gy(self,value): self.__gy.value = SIfloat(value)
def connectingComponents(self):
"""
Returns the two components that this space connects.
"""
a = list(self.nodes[0].components + self.nodes[1].components)
a = [value for value in a if value != self]
if len(a) != 2:
raise pkex.BasePyKatException("Space should only connect 2 components")
return a
def parseAttributes(self, values): def parseAttributes(self, values):
for key in values.keys(): for key in values.keys():
...@@ -803,6 +920,32 @@ class isolator(Component): ...@@ -803,6 +920,32 @@ class isolator(Component):
return rtn return rtn
def getOptivisComponent(self):
self.setOptivisLabelContent()
if self._optivis_component is None:
self._optivis_component = optivis_components.FaradayIsolator(name=self.name, tooltip=self.getOptivisTooltip, paramList=self.getOptivisParameterDict(), pykatObject=weakref.ref(self))
return self._optivis_component
def getOptivisNode(self, mode, kat_node):
mode = mode.lower()
if mode != "input" and mode.lower() != "output":
raise pkex.BasePyKatException("Mode must be either input or output")
if mode == "input":
if kat_node is self.nodes[0]:
return self._optivis_component.getInputNode("fr")
elif kat_node is self.nodes[1]:
return self._optivis_component.getInputNode("bk")
elif mode == "output":
if kat_node is self.nodes[0]:
return self._optivis_component.getnOutputNode("fr")
elif kat_node is self.nodes[1]:
return self._optivis_component.getOutputNode("bk")
def getQGraphicsItem(self): def getQGraphicsItem(self):
if not USE_GUI: if not USE_GUI:
raise NoGUIException raise NoGUIException
...@@ -848,6 +991,31 @@ class lens(Component): ...@@ -848,6 +991,31 @@ class lens(Component):
return rtn return rtn
def getOptivisComponent(self):
self.setOptivisLabelContent()
if self._optivis_component is None:
self._optivis_component = optivis_components.ConvexLens(name=self.name, tooltip=self.getOptivisTooltip, paramList=self.getOptivisParameterDict(), pykatObject=weakref.ref(self))
return self._optivis_component
def getOptivisNode(self, mode, kat_node):
mode = mode.lower()
if mode != "input" and mode.lower() != "output":
raise pkex.BasePyKatException("Mode must be either input or output")
if mode == "input":
if kat_node is self.nodes[0]:
return self._optivis_component.getInputNode("fr")
elif kat_node is self.nodes[1]:
return self._optivis_component.getInputNode("bk")
elif mode == "output":
if kat_node is self.nodes[0]:
return self._optivis_component.getnOutputNode("fr")
elif kat_node is self.nodes[1]:
return self._optivis_component.getOutputNode("bk")
def getQGraphicsItem(self): def getQGraphicsItem(self):
if not USE_GUI: if not USE_GUI:
raise NoGUIException raise NoGUIException
...@@ -929,6 +1097,31 @@ class modulator(Component): ...@@ -929,6 +1097,31 @@ class modulator(Component):
return rtn return rtn
def getOptivisComponent(self):
self.setOptivisLabelContent()
if self._optivis_component is None:
self._optivis_component = optivis_components.ElectroopticModulator(name=self.name, tooltip=self.getOptivisTooltip, paramList=self.getOptivisParameterDict(), pykatObject=weakref.ref(self))
return self._optivis_component
def getOptivisNode(self, mode, kat_node):
mode = mode.lower()
if mode != "input" and mode.lower() != "output":
raise pkex.BasePyKatException("Mode must be either input or output")
if mode == "input":
if kat_node is self.nodes[0]:
return self._optivis_component.getInputNode("fr")
elif kat_node is self.nodes[1]:
return self._optivis_component.getInputNode("bk")
elif mode == "output":
if kat_node is self.nodes[0]:
return self._optivis_component.getnOutputNode("fr")
elif kat_node is self.nodes[1]:
return self._optivis_component.getOutputNode("bk")
def getQGraphicsItem(self): def getQGraphicsItem(self):
if not USE_GUI: if not USE_GUI:
raise NoGUIException raise NoGUIException
...@@ -999,6 +1192,28 @@ class laser(Component): ...@@ -999,6 +1192,28 @@ class laser(Component):
return rtn return rtn
def getOptivisComponent(self):
self.setOptivisLabelContent()
if self._optivis_component is None:
self._optivis_component = optivis_components.Laser(name=self.name, tooltip=self.getOptivisTooltip, paramList=self.getOptivisParameterDict(), pykatObject=weakref.ref(self))
lbl = optivis_label(text="", position=optivis_coord(0, -1), item=self._optivis_component)
lbl.content["Name"] = self.name
self._optivis_component.labels.append(lbl)
return self._optivis_component
def getOptivisNode(self, mode, kat_node):
mode = mode.lower()
if mode != "input" and mode.lower() != "output":
raise pkex.BasePyKatException("Mode must be either input or output")
if mode == "input":
return None
elif mode == "output":
return self._optivis_component.getOutputNode("out")
def getQGraphicsItem(self): def getQGraphicsItem(self):
if not USE_GUI: if not USE_GUI:
raise NoGUIException raise NoGUIException
......
...@@ -15,7 +15,7 @@ if six.PY2: ...@@ -15,7 +15,7 @@ if six.PY2:
import abc import abc
from pykat.node_network import * from pykat.node_network import *
from pykat.param import Param from pykat.param import Param, AttrParam
from pykat.SIfloat import SIfloat from pykat.SIfloat import SIfloat
import pykat.external.six as six import pykat.external.six as six
...@@ -356,7 +356,13 @@ class bp(Detector1): ...@@ -356,7 +356,13 @@ class bp(Detector1):
class pd(Detector1): class pd(Detector1):
def __init__(self, name, num_demods, node_name, senstype=None, alternate_beam=False, pdtype=None, **kwargs): def __new__(cls, *args, **kwargs):
# This creates an instance specific class for the component
# this enables us to add properties to instances rather than
# all classes
return object.__new__(type(cls.__name__, (cls,), {}), *args, **kwargs)
def __init__(self, name=None, num_demods=1, node_name=None, senstype=None, alternate_beam=False, pdtype=None, **kwargs):
BaseDetector.__init__(self, name, node_name) BaseDetector.__init__(self, name, node_name)
self.__num_demods = num_demods self.__num_demods = num_demods
...@@ -402,12 +408,25 @@ class pd(Detector1): ...@@ -402,12 +408,25 @@ class pd(Detector1):
elif i<num_demods-1: elif i<num_demods-1:
raise pkex.BasePyKatException("Missing demodulation phase {0} (phi{0})".format(i+1)) raise pkex.BasePyKatException("Missing demodulation phase {0} (phi{0})".format(i+1))
# define new class for assigning new attributes
cls = type(self)
self.__class__ = type(cls.__name__, (cls,), {})
self.__set_demod_attrs() self.__set_demod_attrs()
def __deepcopy__(self, memo):
"""
When deep copying a kat object we need to take into account
the instance specific properties.
"""
result = pd(self.name, self.num_demods, self.node.name)
memo[id(self)] = result
result.__dict__ = copy.deepcopy(self.__dict__, memo)
# Find all properties in class we are copying
# and deep copy these to the new class instance
for x in self.__class__.__dict__.items():
if isinstance(x[1], property):
setattr(result.__class__, x[0], x[1])
return result
@property @property
def senstype(self): return self.__senstype def senstype(self): return self.__senstype
@senstype.setter @senstype.setter
...@@ -666,7 +685,7 @@ class qnoised(pd): ...@@ -666,7 +685,7 @@ class qnoised(pd):
class qshot(pd): class qshot(pd):
def __init__(self, name, num_demods, node_name, alternate_beam=False, **kwargs): def __init__(self, name, num_demods, node_name, alternate_beam=False, **kwargs):
super(qnoised, self).__init__(name, num_demods, node_name, alternate_beam=alternate_beam, pdtype=None, senstype=None, **kwargs) super(qshot, self).__init__(name, num_demods, node_name, alternate_beam=alternate_beam, pdtype=None, senstype=None, **kwargs)
@pd.pdtype.setter @pd.pdtype.setter
def pdtype(self, value): def pdtype(self, value):
......
...@@ -34,6 +34,7 @@ import subprocess ...@@ -34,6 +34,7 @@ import subprocess
import tempfile import tempfile
import numpy as np import numpy as np
import datetime import datetime
import time
import pickle import pickle
import pykat import pykat
import warnings import warnings
...@@ -63,6 +64,8 @@ except ImportError: # not 2.6+ or is 3.x ...@@ -63,6 +64,8 @@ except ImportError: # not 2.6+ or is 3.x
print("boom") print("boom")
pass pass
""" """
from math import erfc, pi
from collections import namedtuple, OrderedDict from collections import namedtuple, OrderedDict
from pykat.node_network import NodeNetwork from pykat.node_network import NodeNetwork
...@@ -76,7 +79,13 @@ import pykat.external.six as six ...@@ -76,7 +79,13 @@ import pykat.external.six as six
import pykat.exceptions as pkex import pykat.exceptions as pkex
from pykat import USE_GUI, NoGUIException 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
import PyQt4
if USE_GUI: if USE_GUI:
from pykat.gui.gui import pyKatGUI from pykat.gui.gui import pyKatGUI
...@@ -174,9 +183,16 @@ def f__lkat_trace_callback(lkat, trace_info, getCavities, getNodes, getSpaces): ...@@ -174,9 +183,16 @@ def f__lkat_trace_callback(lkat, trace_info, getCavities, getNodes, getSpaces):
gouyy = space.gouy_y) gouyy = space.gouy_y)
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)
class katRun(object): class katRun(object):
def __init__(self): def __init__(self):
self.runDateTime = datetime.datetime.now() self.runtime = None
self.StartDateTime = datetime.datetime.now()
self.x = None self.x = None
self.y = None self.y = None
self.xlabel = None self.xlabel = None
...@@ -185,7 +201,7 @@ class katRun(object): ...@@ -185,7 +201,7 @@ class katRun(object):
self.katVersion = None self.katVersion = None
self.yaxis = None self.yaxis = None
def plot(self): def plot(self, logy=False):
import pylab import pylab
pylab.plot(self.x, self.y) pylab.plot(self.x, self.y)
...@@ -206,9 +222,10 @@ class katRun(object): ...@@ -206,9 +222,10 @@ class katRun(object):
def __getitem__(self, value): def __getitem__(self, value):
idx = [i for i in range(len(self.ylabels)) if self.ylabels[i].split()[0] == str(value)] idx = [i for i in range(len(self.ylabels)) if self.ylabels[i].split()[0] == str(value)]
out = None
if len(idx) > 0: if len(idx) > 0:
out = self.y[:, idx] #out = self.y[:, idx]
if len(idx) == 1: if len(idx) == 1:
if self.yaxis == "abs:deg": if self.yaxis == "abs:deg":
...@@ -221,6 +238,9 @@ class katRun(object): ...@@ -221,6 +238,9 @@ class katRun(object):
elif self.yaxis == "re:im": elif self.yaxis == "re:im":
out = self.y[:, idx[0]] + 1j*self.y[:, idx[1]] out = self.y[:, idx[0]] + 1j*self.y[:, idx[1]]
if out == None:
out = self.y[:, idx]
if out.size == 1: if out.size == 1:
return out[0].squeeze() return out[0].squeeze()
else: else:
...@@ -230,7 +250,8 @@ class katRun(object): ...@@ -230,7 +250,8 @@ class katRun(object):
class katRun2D(object): class katRun2D(object):
def __init__(self): def __init__(self):
self.runDateTime = datetime.datetime.now() self.runtime
self.startDateTime = datetime.datetime.now()
self.x = None self.x = None
self.y = None self.y = None
self.z = None self.z = None
...@@ -398,11 +419,19 @@ Constant = namedtuple('Constant', 'name, value, usedBy') ...@@ -398,11 +419,19 @@ Constant = namedtuple('Constant', 'name, value, usedBy')
class kat(object): class kat(object):
def __new__(cls, *args, **kwargs):
# This may seem like an arbitrary step but here we are creating a
# new class that is a base class of itself. This is because when
# the kat object adds new components it also adds properties for
# each of these. There properties are unique to each kat object,
# but properties are part of the class definition. Thus if two
# kat objects share the same class definition they also have the
# same properties regardless of whether they have the actual
# object added to it. So we create an instance specific class.
return object.__new__(type(pykat.finesse.kat.__name__, (pykat.finesse.
kat,), {}), *args, **kwargs)
def __init__(self, kat_file=None, kat_code=None, katdir="", katname="", tempdir=None, tempname=None): def __init__(self, kat_file=None, kat_code=None, katdir="", katname="", tempdir=None, tempname=None):
cls = type(self)
self.__class__ = type(cls.__name__, (cls,), {})
self.scene = None # scene object for GUI self.scene = None # scene object for GUI
self.verbose = True self.verbose = True
self.__blocks = OrderedDict() # dictionary of blocks that are used self.__blocks = OrderedDict() # dictionary of blocks that are used
...@@ -512,9 +541,9 @@ class kat(object): ...@@ -512,9 +541,9 @@ class kat(object):
def phase(self,value): self.__phase = int(value) def phase(self,value): self.__phase = int(value)
@property @property
def getPerformanceData(self): return self.__time_code def timeCode(self): return self.__time_code
@getPerformanceData.setter @timeCode.setter
def getPerformanceData(self,value): self.__time_code = bool(value) def timeCode(self,value): self.__time_code = bool(value)
@property @property
def components(self): def components(self):
...@@ -878,6 +907,7 @@ class kat(object): ...@@ -878,6 +907,7 @@ class kat(object):
else: else:
raise pkex.BasePyKatException("'{0}' isnot a valid fsig command".format(line)) raise pkex.BasePyKatException("'{0}' isnot a valid fsig command".format(line))
self.signals.f = freq
self.signals.apply(comp._default_fsig(), amp, phase, name) self.signals.apply(comp._default_fsig(), amp, phase, name)
else: else:
...@@ -913,7 +943,7 @@ class kat(object): ...@@ -913,7 +943,7 @@ class kat(object):
return Process(target=f__lkat_process, args=(callback, cmd, kwargs)) return Process(target=f__lkat_process, args=(callback, cmd, kwargs))
def run(self, printout=0, printerr=0, plot=None, save_output=False, save_kat=False, kat_name=None, cmd_args=None) : def run(self, printout=0, printerr=0, plot=None, save_output=False, save_kat=False, kat_name=None, cmd_args=None, getTraceData=False):
""" """
Runs the current simulation setup that has been built thus far. Runs the current simulation setup that has been built thus far.
It returns a katRun or katRun2D object which is populated with the various It returns a katRun or katRun2D object which is populated with the various
...@@ -925,6 +955,11 @@ class kat(object): ...@@ -925,6 +955,11 @@ class kat(object):
save_kat (bool) - if true does not delete kat file save_kat (bool) - if true does not delete kat file
kat_name (string) - name of kat file if needed, will be randomly generated otherwise kat_name (string) - name of kat file if needed, will be randomly generated otherwise
cmd_args (list of strings) - command line flags to pass to FINESSE cmd_args (list of strings) - command line flags to pass to FINESSE
getTraceData (bool) - If true a list of dictionaries is returned along with the
output file. Each dictionary is the result of the beam tracing
that Finesse performs, the keys are the node names and the values
are the x and y beam parameters. If no tracing is done a None
is returned.
""" """
start = datetime.datetime.now() start = datetime.datetime.now()
...@@ -966,6 +1001,7 @@ class kat(object): ...@@ -966,6 +1001,7 @@ class kat(object):
r.yaxis = self.yaxis r.yaxis = self.yaxis
r.katScript = "".join(self.generateKatScript()) r.katScript = "".join(self.generateKatScript())
r.katScript += "time\n"
if (plot==None): if (plot==None):
# ensure we don't do any plotting. That should be handled # ensure we don't do any plotting. That should be handled
...@@ -997,6 +1033,9 @@ class kat(object): ...@@ -997,6 +1033,9 @@ class kat(object):
if cmd_args != None: if cmd_args != None:
cmd.extend(cmd_args) cmd.extend(cmd_args)
if getTraceData:
cmd.append('--trace')
cmd.append('--no-backspace') cmd.append('--no-backspace')
# set default format so that less repeated numbers are printed to the # set default format so that less repeated numbers are printed to the
# output file, should speed up running and parsing of output files # output file, should speed up running and parsing of output files
...@@ -1061,6 +1100,12 @@ class kat(object): ...@@ -1061,6 +1100,12 @@ class kat(object):
[out,errpipe] = p.communicate() [out,errpipe] = p.communicate()
_out = out.split("\n")
for line in _out[::-1]:
if line.lstrip().startswith('computation time:'):
r.runtime = float(line.split(":")[1].replace("s",""))
if printout == 1: if printout == 1:
print (out) print (out)
else: else:
...@@ -1081,8 +1126,52 @@ class kat(object): ...@@ -1081,8 +1126,52 @@ class kat(object):
root = os.path.splitext(katfile.name) root = os.path.splitext(katfile.name)
base = os.path.basename(root[0]) base = os.path.basename(root[0])
path = os.path.split(katfile.name)[0]
outfile = root[0] + ".out" outfile = root[0] + ".out"
traceData = None
if getTraceData:
# First see if we have any trace files
traceFiles = [file for file in os.listdir(path) if file.endswith(".trace") and file.startswith(base)]
print("Found %i trace files" % len(traceFiles))
print(path)
print(traceFiles)
if len(traceFiles) > 0:
import fileinput
traceData = []
for file in traceFiles:
traceData.append({})
ifile = fileinput.input(os.path.join(path, file))
for line in ifile:
line = line.strip()
if len(line) > 0:
a = line.split(':', 1)
if a[0].isdigit():
print("Found %s" % a[0])
values = a[1].split()
node_name = values[1].split("(")[0]
line1x = ifile.readline()
line2x = ifile.readline()
line1y = ifile.readline()
line2y = ifile.readline()
qx = line2x.strip().split()[0].split("=")[1]
qy = line2y.strip().split()[0].split("=")[1]
traceData[-1][node_name] = (pykat.beam_param(q=complex(qx)), pykat.beam_param(q=complex(qy)))
if save_output: if save_output:
newoutfile = "{0}.out".format(base) newoutfile = "{0}.out".format(base)
...@@ -1096,6 +1185,7 @@ class kat(object): ...@@ -1096,6 +1185,7 @@ class kat(object):
if self.verbose: print ("\nOutput data saved to '{0}'".format(newoutfile)) if self.verbose: print ("\nOutput data saved to '{0}'".format(newoutfile))
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)
...@@ -1137,16 +1227,25 @@ class kat(object): ...@@ -1137,16 +1227,25 @@ class kat(object):
katfile.close() katfile.close()
perfData = [] perfData = []
rtn = [r]
if self.__time_code: if self.__time_code:
perffile = open(root[0] + ".perf",'r') perffile = open(root[0] + ".perf",'r')
for l in perffile.readlines(): for l in perffile.readlines():
vals = l.strip().split() vals = l.strip().split()
perfData.append((vals[0], float(vals[1]), float(vals[2]), float(vals[3]))) perfData.append((vals[0], long(vals[1]), long(vals[2])))
#perfData.append((vals[0], float(vals[1]), float(vals[2]), float(vals[3])))
rtn.append(perfData)
return [r, perfData] if getTraceData:
rtn.append(traceData)
if len(rtn) == 1:
return rtn[0]
else: else:
return r return rtn
except pkex.FinesseRunError as ex: except pkex.FinesseRunError as ex:
pkex.PrintError("Error from Finesse:", ex) pkex.PrintError("Error from Finesse:", ex)
...@@ -1301,11 +1400,11 @@ class kat(object): ...@@ -1301,11 +1400,11 @@ class kat(object):
if hasattr(self, "x2axis") and self.noxaxis == False: if hasattr(self, "x2axis") and self.noxaxis == False:
# need to parse 2D outputs slightly different as they are effectively 2D matrices # need to parse 2D outputs slightly different as they are effectively 2D matrices
# written in linear form # written in linear form
x = data[0::(1+self.x2axis.steps),0] x = data[0::(1+self.x2axis.steps),0].squeeze()
y = data[0:(1+self.x2axis.steps),1] y = data[0:(1+self.x2axis.steps),1]
# get rows and columns lined up so that we can reshape a single column of all x/y data # get rows and columns lined up so that we can reshape a single column of all x/y data
# into a matrix # into a matrix
z = data[:,2:].transpose().reshape(data.shape[1]-2, 1+self.xaxis.steps, 1+self.x2axis.steps) z = data[:,2:].transpose().reshape(data.shape[1]-2, 1+self.xaxis.steps, 1+self.x2axis.steps).squeeze()
# once you do this the data for y and x axes need swapping # once you do this the data for y and x axes need swapping
z = z.swapaxes(1,2) z = z.swapaxes(1,2)
return [x, y, z, hdr] return [x, y, z, hdr]
...@@ -1314,19 +1413,22 @@ class kat(object): ...@@ -1314,19 +1413,22 @@ class kat(object):
rows,cols = data.shape rows,cols = data.shape
x = data[:,0] x = data[:,0].squeeze()
y = data[:,1:cols] y = data[:,1:cols]
return [x, y, hdr] return [x, y, hdr]
def removeLine(self, fragment) : def removeLine(self, fragment) :
""" """
This will search all blocks by default and search for the string This will search all blocks and search for the string
fragment specified and remove it. This will only remove non-parsed fragment specified and remove it.
commands, it will not remove commands that have already been parsed WARNING: This will only remove non-parsed commands, it will not
into the pykat structure, such as mirrors and beamsplitters, use the remove commands that have already been parsed
kat.remove(...) function for that purpose. into a pykat object, such as mirrors and beamsplitters, use
kat.remove or kat.component.remove() to delete parsed objects.
""" """
found = False
for key in self.__blocks: for key in self.__blocks:
objs = self.__blocks[key].contents objs = self.__blocks[key].contents
for obj in objs: for obj in objs:
...@@ -1334,6 +1436,11 @@ class kat(object): ...@@ -1334,6 +1436,11 @@ class kat(object):
if fragment in obj: if fragment in obj:
print (" ** removing line '{0}'".format(obj)) print (" ** removing line '{0}'".format(obj))
objs.remove(obj) objs.remove(obj)
found = True
if not found:
pkex.BasePyKatException("The command fragment '%s' is not an extra line added to this kat object. Please check that the item you are trying to remove has not been parsed as a pykat object." % fragment)
def addLine(self, line, block=NO_BLOCK) : def addLine(self, line, block=NO_BLOCK) :
""" """
...@@ -1475,6 +1582,168 @@ class kat(object): ...@@ -1475,6 +1582,168 @@ class kat(object):
return out return out
def optivis(self):
if not HAS_OPTIVIS:
print("Optivis is not installed")
return None
import optivis.scene as scene
import optivis.bench.links as links
import optivis.view.canvas as canvas
scene = scene.Scene(title="My pykat layout")
# Run through again to add links
for c in self.getComponents():
if not isinstance(c, pykat.components.space):
continue
a = c.connectingComponents()
# Need to handle where spaces don't connect two components but there is a loose
# node, which may or may not have detectors attached
if a[0] is None or a[1] is None:
continue
c1 = a[0].getOptivisComponent()
c2 = a[1].getOptivisComponent()
no = a[0].getOptivisNode("Output", c.nodes[0])
ni = a[1].getOptivisNode("Input", c.nodes[1])
if no is None or ni is None:
raise pkex.BasePyKatException("Optivis node is None")
c._optivis_component = links.Link(outputNode=no, inputNode=ni, length=c.L.value)
c.label_node1 = optivis_label(text="", position=optivis_coord(-0.5, 0), item=c._optivis_component)
c.label_node2 = optivis_label(text="", position=optivis_coord( 0.5, 0), item=c._optivis_component)
label_name = optivis_label(text="", position=optivis_coord(0, -0.5), item=c._optivis_component)
label_name.content["Name"] = c.name
c._optivis_component.labels.append(c.label_node1)
c._optivis_component.labels.append(c.label_node2)
c._optivis_component.labels.append(label_name)
scene.addLink(c._optivis_component)
gui = canvas.Full(scene=scene)
### get menu bar from Optivis
menubar = gui.qMainWindow.menuBar()
### add new Pykat menu and menu items
pykatMenu = menubar.addMenu('&Pykat')
# save
save = PyQt4.QtGui.QAction('Save', gui.qMainWindow)
save.setShortcut('Ctrl+S')
save.triggered.connect(lambda: self._optivis_doSave(gui))
pykatMenu.addAction(save)
# trace
trace = PyQt4.QtGui.QAction('Trace', gui.qMainWindow)
trace.setShortcut('Ctrl+T')
trace.triggered.connect(lambda: self._optivis_doTrace(gui))
pykatMenu.addAction(trace)
return gui
def _optivis_doTrace(self, gui, **kwargs):
"""
Change at some point to use a stored GUI reference
"""
if not HAS_OPTIVIS:
print("Optivis is not installed")
return None
prev = self.noxaxis
self.noxaxis = True
out, tdata = self.run(getTraceData=True, **kwargs)
self.noxaxis = prev
# For now just select the first trace computed
# Later we could add some gui list to show the different ones
tdata = tdata[0]
for c in self.getComponents():
if not isinstance(c, pykat.components.space):
continue
if not (hasattr(c, "label_node1") and hasattr(c, "label_node2")):
continue
c.label_node1.content["w0_x"] = tdata[c.nodes[0].name][0].w0
c.label_node1.content["w_x"] = tdata[c.nodes[0].name][0].w
c.label_node1.content["z_x"] = tdata[c.nodes[0].name][0].z
c.label_node1.content["Rc_x"] = tdata[c.nodes[0].name][0].Rc
c.label_node1.content["Zr_x"] = tdata[c.nodes[0].name][0].zr
c.label_node1.content["w0_y"] = tdata[c.nodes[0].name][1].w0
c.label_node1.content["w_y"] = tdata[c.nodes[0].name][1].w
c.label_node1.content["z_y"] = tdata[c.nodes[0].name][1].z
c.label_node1.content["Rc_y"] = tdata[c.nodes[0].name][1].Rc
c.label_node1.content["Zr_y"] = tdata[c.nodes[0].name][1].zr
c.label_node2.content["w0_x"] = tdata[c.nodes[1].name][0].w0
c.label_node2.content["w_x"] = tdata[c.nodes[1].name][0].w
c.label_node2.content["z_x"] = tdata[c.nodes[1].name][0].z
c.label_node2.content["Rc_x"] = tdata[c.nodes[1].name][0].Rc
c.label_node2.content["Zr_x"] = tdata[c.nodes[1].name][0].zr
c.label_node2.content["w0_y"] = tdata[c.nodes[1].name][1].w0
c.label_node2.content["w_y"] = tdata[c.nodes[1].name][1].w
c.label_node2.content["z_y"] = tdata[c.nodes[1].name][1].z
c.label_node2.content["Rc_y"] = tdata[c.nodes[1].name][1].Rc
c.label_node2.content["Zr_y"] = tdata[c.nodes[1].name][1].zr
gui.redraw()
def _optivis_doSave(self, gui, **kwargs):
"""
Save kat script from Optivis
"""
if not HAS_OPTIVIS:
print("Optivis is not installed")
return None
# generate file path
directory = os.path.join(os.path.expanduser('~'), '{0}.kat'.format(gui.scene.title))
# desired save path
path = None
# get path to file to export to
while True:
dialog = PyQt4.Qt.QFileDialog(parent=gui.qMainWindow, caption='Save Finesse Script', directory=directory)
dialog.setAcceptMode(PyQt4.Qt.QFileDialog.AcceptSave)
dialog.setFileMode(PyQt4.Qt.QFileDialog.AnyFile)
# show dialog
dialog.exec_()
if len(dialog.selectedFiles()) is 0:
# no filename specified
return
# get file path and format
path = str(dialog.selectedFiles()[0])
try:
# check if we can write to the path
open(path, 'w').close()
os.unlink(path)
# if we get this far, all is good so we can break out the infinite loop
break
except OSError:
PyQt4.Qt.QMessageBox.critical(gui.qMainWindow, 'Filename invalid', 'The specified filename is invalid')
except IOError:
PyQt4.Qt.QMessageBox.critical(gui.qMainWindow, 'Permission denied', 'You do not have permission to save the file to the specified location.')
# save kat file
self.saveScript(filename=path)
def openGUI(self): def openGUI(self):
if not USE_GUI: if not USE_GUI:
raise NoGUIException raise NoGUIException
...@@ -1615,7 +1884,7 @@ class kat(object): ...@@ -1615,7 +1884,7 @@ class kat(object):
name = com.__class__.__name__ name = com.__class__.__name__
print (getattr(self.__class__, name)) #print (getattr(self.__class__, name))
delattr(self.__class__, name) delattr(self.__class__, name)
delattr(self, '__com_' + name) delattr(self, '__com_' + name)
......
...@@ -23,6 +23,13 @@ from pykat.optics.gaussian_beams import beam_param ...@@ -23,6 +23,13 @@ from pykat.optics.gaussian_beams import beam_param
from copy import deepcopy from copy import deepcopy
class NodeNetwork(object): class NodeNetwork(object):
def __new__(cls, *args, **kwargs):
# This creates an instance specific class for the component
# this enables us to add properties to instances rather than
# all classes
return object.__new__(type(cls.__name__, (cls,), {}), *args, **kwargs)
def __init__(self, kat): def __init__(self, kat):
self.__nodes = {} self.__nodes = {}
self.__kat = kat self.__kat = kat
...@@ -31,9 +38,6 @@ class NodeNetwork(object): ...@@ -31,9 +38,6 @@ class NodeNetwork(object):
self.__componentCallback = {} self.__componentCallback = {}
self.__node_id = 1 self.__node_id = 1
cls = type(self)
self.__class__ = type(cls.__name__, (cls,), {})
@property @property
def kat(self): return self.__kat def kat(self): return self.__kat
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment