Commit fb0c2cb4 authored by Daniel Brown's avatar Daniel Brown
Browse files

More changes on how it all works. kat.run() now returns a runkat object which...

More changes on how it all works. kat.run() now returns a runkat object which contain all the varios information like timestamps, data, headers, version. Gui now has spaces connecting components up. Also added 'Export to SVG' option which is nice, however the SVG renderer mucks up the gradients on the components
parent 855c482b
......@@ -10,11 +10,26 @@ import exceptions
from components import *
from structs import *
class Command:
class Command(object):
def getFinesseText(self):
""" Base class for individual finesse optical components """
raise NotImplementedError("This function is not implemented")
class cavity(Command):
def __init__(self, kat, name, c1, n1, c2, n2):
self.__name = name
self.__c1 = c1
self.__c2 = c2
self.__n1 = n1
self.__n2 = n2
kat.add(self)
def getFinesseText(self):
return 'cav {0} {1} {2} {3} {4}'.format(
self.__name, self.__c1, self.__n1, self.__c2, self.__n2);
class xaxis(Command):
def __init__(self, kat, scale, limits, comp, param, steps):
......
......@@ -7,13 +7,14 @@ Created on Mon Jan 28 11:10:01 2013
import exceptions
import pykat.gui.resources
import pykat
import inspect
from pykat.gui.graphics import *
from pykat.node_network import *
from PyQt4.QtGui import *
from PyQt4.Qt import *
class Component() :
class Component(object) :
def __init__(self, name, kat):
self.__name = name
self._svgItem = None
......@@ -55,17 +56,15 @@ class Component() :
name = property(__getname)
class Param:
class Param(float):
def __new__(self,name,value):
return float.__new__(self,value)
def __init__(self,name,value):
self.value = value
self.__name = name
def getname(self):
return self.__name
name = property(getname)
name = property(lambda self: self.__name)
class mirror(Component):
def __init__(self,kat,name,node1,node2,R=0,T=0,phi=0,Rcx=0,Rcy=0,xbeta=0,ybeta=0):
......@@ -74,36 +73,71 @@ class mirror(Component):
self.node1 = self._addNode(node1)
self.node2 = self._addNode(node2)
self.R = Param('R',R)
self.T = Param('R',T)
self.phi = Param('phi',phi)
self.Rcx = Param('rcx',Rcx)
self.Rcy = Param('rcy',Rcy)
self.xbeta = Param('xbeta',xbeta)
self.ybeta = Param('ybeta',ybeta)
def _getRc(self):
self.__R = R
self.__T = T
self.__phi = phi
self.__Rcx = Rcx
self.__Rcy = Rcy
self.__xbeta = xbeta
self.__ybeta = ybeta
@property
def R(self):
return Param('R',self.__R)
@R.setter
def R(self,value):
self.__R = value
@property
def T(self): return Param('T', self.__T)
@T.setter
def T(self,value): self.__T = value
@property
def phi(self): return Param('phi', self.__phi)
@phi.setter
def phi(self,value): self.__phi = value
@property
def Rcx(self): return Param('Rcx', self.__Rcx)
@Rcx.setter
def Rcx(self,value): self.__Rcx = value
@property
def Rcy(self): return Param('Rcy', self.__Rcy)
@Rcy.setter
def Rcy(self,value): self.__Rcy = value
@property
def xbeta(self): return Param('xbeta', self.__xbeta)
@xbeta.setter
def xbeta(self,value): self.__xbeta = value
@property
def ybeta(self): return Param('ybeta', self.__ybeta)
@ybeta.setter
def ybeta(self,value): self.__ybeta = value
@property
def Rc(self):
if self.Rcx == self.Rcy:
return self.Rcx
else:
return [self.Rcx, self.Rcy]
def _setRc(self,value):
@Rc.setter
def Rc(self,value):
self.Rcx = value
self.Rcy = value
Rc = property(_getRc,_setRc)
def getFinesseText(self):
rtn = []
rtn.append('m {0} {1} {2} {3} {4} {5}'.format(
self.name, self.R.value, self.T.value, self.phi.value,
self.name, self.__R, self.__T, self.__phi,
self.node1.name, self.node2.name))
if self.Rcx != 0: rtn.append("attr {0} Rcx {1}".format(self.name,self.Rcx))
if self.Rcy != 0: rtn.append("attr {0} Rcy {1}".format(self.name,self.Rcy))
if self.xbeta != 0: rtn.append("attr {0} xbeta {1}".format(self.name,self.xbeta))
if self.ybeta != 0: rtn.append("attr {0} ybeta {1}".format(self.name,self.ybeta))
if self.Rcx != 0: rtn.append("attr {0} Rcx {1}".format(self.name,self.__Rcx))
if self.Rcy != 0: rtn.append("attr {0} Rcy {1}".format(self.name,self.__Rcy))
if self.xbeta != 0: rtn.append("attr {0} xbeta {1}".format(self.name,self.__xbeta))
if self.ybeta != 0: rtn.append("attr {0} ybeta {1}".format(self.name,self.__ybeta))
return rtn
......@@ -122,17 +156,31 @@ class space(Component):
self.node1 = self._addNode(node1)
self.node2 = self._addNode(node2)
self.length = Param('L',L)
self.refractive_index = Param('n',n)
self.__L = L
self.__n = n
self._QItem = None
@property
def L(self): return Param('L', self.__L)
@L.setter
def L(self,value): self.__L = value
@property
def n(self): return Param('n', self.__n)
@n.setter
def n(self,value): self.__n = value
def getFinesseText(self):
if self.refractive_index.value == 1:
return 's {0} {1} {2} {3}'.format(self.name, self.length.value, self.node1.name, self.node2.name)
if self.__n == 1:
return 's {0} {1} {2} {3}'.format(self.name, self.__L, self.node1.name, self.node2.name)
else:
return 's {0} {1} {2} {3} {4}'.format(self.name, self.length.value, self.refractive_index.value, self.node1.name, self.node2.name)
return 's {0} {1} {2} {3} {4}'.format(self.name, self.__L, self.__n, self.node1.name, self.node2.name)
def getQGraphicsItem(self):
if self._QItem == None:
self._QItem = SpaceQGraphicsItem(self)
return self._QItem
class laser(Component):
def __init__(self,kat,name,node,P=1,f_offset=0,phase=0):
......@@ -140,15 +188,30 @@ class laser(Component):
self.node = self._addNode(node)
self.power = Param('P', P)
self.f_offset = Param('f', f_offset)
self.phase = Param('phase',phase)
self.__power = P
self.__f_offset = f_offset
self.__phase = phase
@property
def power(self): return Param('P', self.__power)
@power.setter
def power(self,value): self.__power = value
@property
def f_offset(self): return Param('f', self.__f_offset)
@f_offset.setter
def f_offset(self,value): self.__f_offset = value
@property
def phase(self): return Param('phase', self.__phase)
@phase.setter
def phase(self,value): self.__phase = value
def getFinesseText(self):
if self.phase.value == 0 :
return 'l {0} {1} {2} {3}'.format(self.name, self.power.value, self.f_offset.value, self.node.name)
if self.__phase == 0 :
return 'l {0} {1} {2} {3}'.format(self.name, self.__power, self.__f_offset, self.node.name)
else :
return 'l {0} {1} {2} {4} {3}'.format(self.name, self.power.value, self.f_offset.value, self.phase.value, self.node.name)
return 'l {0} {1} {2} {4} {3}'.format(self.name, self.__power, self.__f_offset, self.__phase, self.node.name)
def getQGraphicsItem(self):
if self._svgItem == None:
......
......@@ -14,11 +14,13 @@ from pykat.node_network import *
from PyQt4.QtGui import *
from PyQt4.Qt import *
class Detector() :
class Detector(object) :
def __init__(self, name,node,kat):
self.__name = name
self._svgItem = None
self._kat = kat
self.noplot = False
self.enabled = True
kat.add(self)
......@@ -52,11 +54,21 @@ class photodiode(Detector):
def getFinesseText(self) :
if self._alternate_beam:
return "pd {0} {1}".format(self.name, self.__node.name)
else:
return "pd {0} {1}*".format(self.name, self.__node.name)
if self.enabled:
rtn = []
if self._alternate_beam:
rtn.append("pd {0} {1}".format(self.name, self.__node.name))
else:
rtn.append("pd {0} {1}*".format(self.name, self.__node.name))
if self.noplot:
rtn.append("noplot {0}".format(self.name))
return rtn
else:
return None
def getQGraphicsItem(self):
if self._svgItem == None:
self._svgItem = ComponentQGraphicsItem(":/resources/photodiode_red.svg",self,[(-20,0,self.node)])
......
......@@ -9,22 +9,55 @@ import exceptions
import subprocess
import tempfile
import numpy as np
import datetime
#from colorama import Fore
import pickle
from colorama import Fore
from pykat.node_network import NodeNetwork
from pykat.detectors import Detector
from pykat.components import Component
from pykat.commands import Command
from pykat.gui.gui import *
from pykat.commands import Command, xaxis
from pykat.gui.gui import openGUI
class MissingFinesseEnvVar(Exception) :
def __str__(self) :
return "The environment variable FINESSE_DIR was not defined"
class kat:
class MissingFinesse(Exception) :
def __str__(self) :
return "Could not find the finesse executable 'kat' in '{0}'," \
"or you do not have the permissions to run it." \
.format(os.environ.get('FINESSE_DIR'))
class katRun(object):
def __init__(self):
self.runDateTime = datetime.datetime.now()
self.x = None
self.y = None
self.xlabel = None
self.ylabels = None
self.katScript = None
self.katVersion = None
def saveKatRun(self, run, filename):
if not isinstance(run, katRun):
raise RuntimeError("run object must be a katRun type")
with open(filename,'w') as outfile:
pickle.dump(run, outfile, pickle.HIGHEST_PROTOCOL)
@staticmethod
def loadKatRun(filename):
with open(filename,'r') as infile:
return pickle.load(infile)
class kat(object):
def __init__(self):
self.__components = {}
self.__detectors = {}
self.__commands = {}
......@@ -32,28 +65,52 @@ class kat:
self.nodes = NodeNetwork(self)
# Various
self.phase = None
self.maxtem = None
self.noxaxis = None
self.__phase = None
self.__maxtem = None
self.__noxaxis = None
def run(self, printout=1, printerr=1, save_output=False, save_kat=False
,kat_name=None) :
""" Runs the current simulation """
@property
def maxtem(self): return self.__maxtem
@maxtem.setter
def maxtem(self,value): self.__maxtem = int(value)
@property
def phase(self): return self.__phase
@phase.setter
def phase(self,value): self.__phase = int(value)
@property
def noxaxis(self): return self.__noxaxis
@noxaxis.setter
def noxaxis(self,value): self.__noxaxis = bool(value)
def run(self, printout=1, printerr=1, save_output=False, save_kat=False,kat_name=None) :
"""
Runs the current simulation setup that has been built thus far.
It returns a katRun object which is populated with the various
data from the simulation run.
"""
# Get the environment variable for where Finesse is stored
self.__finesse_dir = os.environ.get('FINESSE_DIR')
if self.__finesse_dir == None :
raise exceptions.MissingFinesseEnvVar
raise MissingFinesseEnvVar()
katfile = tempfile.TemporaryFile(suffix=".kat")
katfile.writelines(self.generate())
r = katRun()
r.katScript = "".join(self.generateKatScript())
katfile = tempfile.TemporaryFile(suffix=".kat")
katfile.writelines(r.katScript)
katfile.flush()
kat_exec = os.path.join(self.__finesse_dir,'kat {0}'.format(
katfile.name))
kat_exec = os.path.join(self.__finesse_dir,'kat.exe')
if not (os.path.isfile(kat_exec) and os.access(kat_exec, os.X_OK)):
raise MissingFinesse()
kat_exec = "{0} {1}".format(kat_exec, katfile.name)
p=subprocess.Popen(kat_exec,
stdout=subprocess.PIPE,
......@@ -61,15 +118,27 @@ class kat:
[out,err] = p.communicate()
if printout == 1: print Fore.GREEN + out
if printerr == 1: print Fore.RED + err
ix = out.find('build ') + 6
ix2 = out.find(')',ix)
r.katVersion = out[ix:ix2]
r.runDateTime = datetime.datetime.now()
if p.returncode != 0:
print err
return None
if printout == 1: print out
if printerr == 1: print err
root = os.path.splitext(katfile.name)
base = os.path.basename(root[0])
outfile = root[0] + ".out"
[r.x,r.y,hdr] = self.readOutFile(outfile)
[root,ext] = os.path.splitext(katfile.name)
base = os.path.basename(root)
outfile = root + ".out"
[x,y,hdr] = self.readOutFile(outfile)
r.xlabel = hdr[0]
r.ylabels = hdr[1:]
if save_output:
......@@ -78,6 +147,9 @@ class kat:
cwd = os.path.os.getcwd()
newoutfile = os.path.join(cwd,newoutfile)
if os.path.isfile(newoutfile):
os.remove(newoutfile)
os.rename(outfile, newoutfile)
print "Output data saved to '{0}'".format(newoutfile)
......@@ -88,6 +160,10 @@ class kat:
cwd = os.path.os.getcwd()
newkatfile = os.path.join(cwd, kat_name + ".kat")
if os.path.isfile(newkatfile):
os.remove(newkatfile)
os.rename(katfile.name, newkatfile)
print "Kat file saved to '{0}'".format(newkatfile)
......@@ -95,11 +171,12 @@ class kat:
katfile.close()
return [x,y,hdr]
return r
def add(self, obj) :
if isinstance(obj, Component):
if obj.name in self.__components :
raise exceptions.ValueError("A component with name '{0}' has already been added".format([obj.name]))
......@@ -108,6 +185,7 @@ class kat:
elif isinstance(obj, Detector):
if obj.name in self.__detectors :
raise exceptions.ValueError("A detector '{0}' has already been added".format(obj.name))
......@@ -115,12 +193,10 @@ class kat:
self.__add_detector(obj)
elif isinstance(obj, Command):
# dont error when adding same command, just replace it
#if obj.__class__.__name__ in self.__commands :
# raise exceptions.ValueError("A command '{0}' has already been added".format([obj.__class__.__name__]))
self.__commands[obj.__class__.__name__] = obj
self.__add_command(obj)
else :
raise exceptions.ValueError("Object could not be added")
......@@ -141,13 +217,14 @@ class kat:
hdr = outfile.readline().replace('%','').replace('\n','').split(',')
data = np.loadtxt(filename,comments='%')
rows,cols = data.shape
x = data[:,0]
y = data[:,1:cols]
rows,cols = data.shape
return [x, y, hdr]
x = data[:,0]
y = data[:,1:cols].squeeze()
def generate(self) :
return [x, y, hdr]
def generateKatScript(self) :
""" Generates the kat file which can then be run """
if len(self.__components) == 0 :
raise exceptions.RuntimeError("No components have been added")
......@@ -164,15 +241,27 @@ class kat:
out.append(txt + "\n")
for key in self.__detectors:
out.append(self.__detectors[key].getFinesseText() + "\n")
for key in self.__detectors:
txt = self.__detectors[key].getFinesseText()
if txt != None:
if isinstance(txt,list):
for t in txt: out.append(t+ "\n")
else:
out.append(txt + "\n")
if self.noxaxis != None and self.noxaxis == True:
out.append("noxaxis\n")
for key in self.__commands:
if self.noxaxis == None or (self.noxaxis == True and isinstance(self.__commands[key], xaxis)):
out.append(self.__commands[key].getFinesseText() + "\n")
txt = self.__commands[key].getFinesseText()
if txt != None:
if isinstance(txt,list):
for t in txt: out.append(t+ "\n")
else:
out.append(txt + "\n")
if self.phase != None: out.append("phase {0}\n".format(self.phase))
if self.maxtem != None: out.append("maxtem {0}\n".format(self.maxtem))
......@@ -192,10 +281,10 @@ class kat:
def __add_detector(self, det):
if not isinstance(det, Detector):
raise exceptions.ValueError("Argument is not of type Command")
raise exceptions.ValueError("Argument is not of type Detector")
name = det.name
fget = lambda self: self.__get_command(name)
fget = lambda self: self.__get_detector(name)
setattr(self.__class__, name, property(fget))
setattr(self, '__det_' + name, det)
......
......@@ -7,21 +7,120 @@ Created on Fri Feb 01 09:13:03 2013
from PyQt4.QtGui import *
from PyQt4.Qt import *
import pykat.components
class NodeQGraphicItem(QGraphicsRectItem):
pass
nsize = 8
class NodeQGraphicItem(QGraphicsRectItem):
def __init__(self, node, x,y, *args, **kwargs):
QGraphicsRectItem.__init__(self, *args, **kwargs)
self.__node = node
self.setPos(x,y)
item = QGraphicsTextItem(node.name, self)
rect = item.boundingRect()
item.setPos(-0.5*rect.width(), 0)
class SpaceQGraphicsItem(QGraphicsLineItem):
def __init__(self, spaceComponent):
QGraphicsLineItem.__init__(self)
self.__n1 = None
self.__n2 = None
self.__space = spaceComponent
item = QGraphicsTextItem(self.__space.name, self)
rect = item.boundingRect()
item.setPos(-0.5*rect.width(),-0.5*rect.height())
self.refresh()
def refresh(self):
nodes = self.__space.getNodes()
if self.__n1 == None:
self.__n1 = NodeQGraphicItem(nodes[0],0,0,-nsize/2,-nsize/2,nsize,nsize,self)
self.__n1.setPen(QPen(Qt.black))
x1 = self.__n1.x
y1 = self.__n1.y
conn = nodes[0].amIConnected(self.__space)
if conn[0]:
self.__n1.setVisible(False)
# now check if a connected component was returned too
if conn[1] != None:
# so this node should be attached to something
# in this case we get the position of their node
# and draw the the line from their
itm=conn[1].getQGraphicsItem()
x1 = itm.x() + itm.nodedx[conn[2]][0]