diff --git a/bin/test_beam_trace.py b/bin/test_beam_trace.py new file mode 100644 index 0000000000000000000000000000000000000000..e5bf01167435805cb440da57b05801484906bc66 --- /dev/null +++ b/bin/test_beam_trace.py @@ -0,0 +1,42 @@ +import pykat +from pykat.utilities.plotting.beamtrace import plot_beam_trace +import numpy as np +import pylab +import copy + +kat = pykat.finesse.kat() + +cmds = """ +l l1 1 0 n0 +s s0 1000 n0 n1 +m m1 0.5 0.5 0 n1 n2 +s s1 10 n2 n3 +m m2 0.5 0.5 0 n3 n4 +s s2 20 n4 n5 +bs bs1 0.5 0.5 0 0 n5 n6 n7 n8 + +s s3 20 n6 n9 + +s s4 20 n7 n10 + +s s5 20 n8 n11 + +bs bs2 0.5 0.5 0 0 n9 n12 n13 n14 + +s s6 3 n12 n15 + +lens lens1 20 n15 n16 + +s s7 500 n16 n17 + +gouy g1 x s0 s1 s2 + +bp bp1 x w0 n5 +gauss g1 l1 n0 8e-3 -1000 4e-3 -1200 +noxaxis +maxtem 0 +""" + +kat.parseCommands(cmds) + +plot_beam_trace(kat, 'n0', 'n17') \ No newline at end of file diff --git a/bin/test_map.py b/bin/test_map.py new file mode 100644 index 0000000000000000000000000000000000000000..9d04a02bb3a6995c9f609ee65134ad8b795362ac --- /dev/null +++ b/bin/test_map.py @@ -0,0 +1,5 @@ +from pykat.utilities.maps import * + +smap = read_map('lens_map.txt') + +smap.plot() diff --git a/pykat/detectors.py b/pykat/detectors.py index 5a88447fee9cfb3a05359bbbe1e4466d2fa3e77b..004662179e73a9f5c946ff090b90c8d4a0a0874c 100644 --- a/pykat/detectors.py +++ b/pykat/detectors.py @@ -14,9 +14,10 @@ from pykat.param import Param import pykat.exceptions as pkex import warnings +import copy class Detector(object) : - def __init__(self, name,node): + def __init__(self, name, node=None): self.__name = name self._svgItem = None self._kat = None @@ -28,6 +29,7 @@ class Detector(object) : self._mask = {} self.__scale = None self.__removed = False + self.__requested_node = None if node != None: if node[-1]=='*': @@ -151,7 +153,111 @@ class ad(Detector): rtn.extend(p.getFinesseText()) return rtn + +class gouy(Detector): + + def __init__(self, name, direction, spaces): + Detector.__init__(self, name) + self.spaces = copy.copy(spaces) + self.direction = direction + self.alternate_beam = False + + @property + def direction(self): return self.__dir + @direction.setter + def direction(self, value): + if value == None or (value != 'x' and value != 'y'): + raise pkex.BasePyKatException('Direction must be either x or y') + + self.__dir = value + + @property + def spaces(self): return self.__spaces + @spaces.setter + def spaces(self, value): + + if value == None or len(value) < 1: + raise pkex.BasePyKatException('Must be a list of space names') + + self.__spaces = value + + @staticmethod + def parseFinesseText(text): + values = text.split() + + if len(values) > 3: + return gouy(str(values[1]), str(values[2]), values[3:]) + else: + raise pkex.BasePyKatException('Gouy detector code "{0}" is not a valid FINESSE command'.format(text)) + + def getFinesseText(self) : + rtn = [] + + rtn.append("gouy {name} {dir} {spaces}".format(name=self.name, dir=str(self.direction), spaces=" ".join(self.spaces))) + + for p in self._params: + rtn.extend(p.getFinesseText()) + + return rtn + + + +class bp(Detector): + acceptedParameters = ['w', 'w0', 'z', 'zr', 'g', 'r', 'q'] + + def __init__(self, name, direction, parameter, node, alternate_beam=False): + Detector.__init__(self, name, node) + self.parameter = parameter + self.direction = direction + self.alternate_beam = alternate_beam + @property + def direction(self): return self.__dir + @direction.setter + def direction(self, value): + if value == None or (value != 'x' and value != 'y'): + raise pkex.BasePyKatException('Direction must be either x or y') + + self.__dir = value + + @property + def parameter(self): return self.__param + @parameter.setter + def parameter(self, value): + + if value == None or (value not in self.acceptedParameters) : + raise pkex.BasePyKatException('Parameter must be one of: %s'%(", ".join(self.acceptedParameters))) + + self.__param = value + + @staticmethod + def parseFinesseText(text): + values = text.split() + + node=values[-1] + alt_beam = node[-1] == '*' + + if len(values) > 3: + return bp(str(values[1]), str(values[2]), str(values[3]), str(values[4]), alternate_beam=alt_beam) + else: + raise pkex.BasePyKatException('Gouy detector code "{0}" is not a valid FINESSE command'.format(text)) + + def getFinesseText(self) : + rtn = [] + + if self.alternate_beam: + alt = "*" + else: + alt = "" + + rtn.append("bp {name} {dir} {param} {node}{alt}".format(name=self.name, dir=str(self.direction), param=self.parameter, node=self.node.name, alt=alt)) + + for p in self._params: + rtn.extend(p.getFinesseText()) + + return rtn + + class pd(Detector): def __init__(self, name, num_demods, node_name, senstype=None, alternate_beam=False, pdtype=None, **kwargs): diff --git a/pykat/finesse.py b/pykat/finesse.py index 27512b2dffa9fcde4b27e9734feb5e3d0a1c6a8e..5cf8bc39320636abe95d4a9db54b1e66a69004fa 100644 --- a/pykat/finesse.py +++ b/pykat/finesse.py @@ -601,6 +601,10 @@ class kat(object): obj = pykat.components.modulator.parseFinesseText(line) elif(first[0:2] == "ad"): obj = pykat.detectors.ad.parseFinesseText(line) + elif(first[0:2] == "bp"): + obj = pykat.detectors.bp.parseFinesseText(line) + elif(first[0:4] == "gouy"): + obj = pykat.detectors.gouy.parseFinesseText(line) elif(first[0:2] == "pd" and first != "pdtype"): obj = pykat.detectors.pd.parseFinesseText(line) elif(first == "qshot" or first == "qshotS" or first == "qshotN"): diff --git a/pykat/node_network.py b/pykat/node_network.py index f2684c5a7471aa0b0f0314f2ec7624a483cc6592..e91d32ce9bb8d7c48a29a7a220c2795269c7a198 100644 --- a/pykat/node_network.py +++ b/pykat/node_network.py @@ -230,7 +230,147 @@ class NodeNetwork(object): def __contains__(self, value): return value in self.__nodes + + def __nodeSearch(self, fnode, currcomp, branches, tnode): + + if fnode == tnode: + branches[-1][0] = True + branches[-1][1] = True + return True # Hurrah, we have found a path to the node + elif fnode.isDump: + branches[-1][0] = True + return False # if the current node is a dump, we need to check another branch + + nextnode = None + + if isinstance(currcomp, pykat.components.beamSplitter): + # if we get to a beamsplitter then we need to + # create new branches to search: the rfelected + # and transmitted + + # set this branch as searched + branches[-1][0] = True + # add two new ones + + if fnode == currcomp.nodes[0]: + rn = currcomp.nodes[1] + tn = currcomp.nodes[2] + elif fnode == currcomp.nodes[1]: + rn = currcomp.nodes[0] + tn = currcomp.nodes[3] + elif fnode == currcomp.nodes[2]: + rn = currcomp.nodes[3] + tn = currcomp.nodes[0] + elif fnode == currcomp.nodes[3]: + rn = currcomp.nodes[2] + tn = currcomp.nodes[1] + else: + raise exceptions.ValueError("Node not attached in path find to BS") + + nextcomp = None + + if tn.components[0] == currcomp: + nextcomp = tn.components[1] + elif tn.components[1] == currcomp: + nextcomp = tn.components[0] + + if nextcomp != None: + branches.append([False, False, tn, nextcomp, []]) + + if rn.components[0] == currcomp: + nextcomp = rn.components[1] + elif rn.components[1] == currcomp: + nextcomp = rn.components[0] + + if nextcomp != None: + branches.append([False, False, rn, nextcomp, []]) + + branches[-1][-1].append(currcomp) + + return False + + elif isinstance(currcomp, pykat.components.isolator): + print "isol" + elif isinstance(currcomp, pykat.components.laser): + # if we are at a laser then we can't go any further + # and it isn;t this node as we checked before + branches[-1][0] = True + return False + elif len(currcomp.nodes) == 2: + if currcomp.nodes[0] == fnode: + nextnode = currcomp.nodes[1] + elif currcomp.nodes[1] == fnode: + nextnode = currcomp.nodes[0] + else: + raise pkex.BasePyKatException("Unexpeceted condition") + else: + raise pkex.BasePyKatException("Did not handle component {0} correctly, has more or less than 2 nodes.".format(currcomp)) + + if nextnode == None: + branches[-1][0] = True + return False + elif nextnode == tnode: + branches[-1][0] = True + branches[-1][1] = True + branches[-1][-1].append(currcomp) + return True + else: + # Now we have the next node, we need the next component + if nextnode.components[0] == currcomp: + nextcomp = nextnode.components[1] + elif nextnode.components[1] == currcomp: + nextcomp = nextnode.components[0] + else: + raise pkex.BasePyKatException("Unexpeceted condition") + + if nextcomp == None: + branches[-1][0] = True + return False + + branches[-1][-1].append(currcomp) + + return self.__nodeSearch(nextnode, nextcomp, branches, tnode) + + def getComponentsBetween(self, from_node, to_node): + + if from_node not in self.__nodes: + raise pkex.BasePyKatException("Node {0} cannot be found in this kat object".format(from_node)) + + if to_node not in self.__nodes: + raise pkex.BasePyKatException("Node {0} cannot be found in this kat object".format(to_node)) + + branches = [] + + fn = self.__nodes[from_node] + tn = self.__nodes[to_node] + + branches.append([False, False, fn, fn.components[1], []]) + branches.append([False, False, fn, fn.components[0], []]) + + while len(branches) > 0 and branches[-1][1] != True: + while branches[-1][0] == False: + branch = branches[-1] + + if not self.__nodeSearch(branch[2], branch[3], branches, tn): + if len(branches) > 0 and branches[-1][0] != False: + branches.pop() + + if branches[-1][1] != True: + while len(branches) > 0 and branches[-1][0] == True: + branches.pop() + + + comps = [] + + if len(branches) > 0 and branches[-1][0] == True and branches[-1][1] == True: + # select the branches that form the path from node to node + br = [b for b in branches if b[0] == True] + for b in br: + comps.extend(b[-1]) + + return comps + class Node(object): @@ -243,9 +383,13 @@ class Node(object): self.__q_y = None self.__q_comp = None self.__id = id - + self._isDump = False + def __str__(self): return self.__name - + + @property + def isDump(self): return self._isDump + @property def id(self): return self.__id @@ -350,13 +494,14 @@ class Node(object): @property def name(self): return self.__name - - + + class DumpNode(Node): __total_dump_node_id = 0 def __init__(self): DumpNode.__total_dump_node_id -= 1 Node.__init__(self, 'dump', None, DumpNode.__total_dump_node_id) + self._isDump = True diff --git a/pykat/utilities/plotting/beamtrace.py b/pykat/utilities/plotting/beamtrace.py new file mode 100644 index 0000000000000000000000000000000000000000..33e0f309078156ee88870e876790ec06db0461e6 --- /dev/null +++ b/pykat/utilities/plotting/beamtrace.py @@ -0,0 +1,108 @@ +import pykat +import pykat.exceptions as pkex +import copy +import numpy as np +import pylab + +def plot_beam_trace(_kat, from_node, to_node): + if _kat == None: + raise pkex.BasePyKatException('kat object in None') + + kat = copy.deepcopy(_kat) + + components = kat.nodes.getComponentsBetween(from_node, to_node) + + nodes = [] + + for cn in range(len(components)): + for n in components[cn].nodes: + + cs = np.array(n.components) + + if cn < len(components)-1 and components[cn] in cs and components[cn+1] in cs: + nodes.append(n) + break + elif cn == len(components)-1 and components[cn-1] not in cs and components[cn] in cs: + nodes.append(n) + break + + v = [c for c in zip(components, nodes) if isinstance(c[0], pykat.components.space)] + spaces = [d[0] for d in v] + nodes2 = [d[1] for d in v] + + print [n.name for n in spaces ] + + pylab.figure() + + if len(spaces) > 0: + print "Plotting beam along spaces", ", ".join([s.name for s in spaces]) + + for d in kat.detectors.values(): + d.remove() + + if hasattr(kat, "xaxis"): + kat.xaxis.remove() + + if hasattr(kat, "x2axis"): + kat.x2axis.remove() + + if hasattr(kat, "x3axis"): + kat.x3axis.remove() + + kat.noxaxis = False + kat.maxtem = 0 + + currL = 0 + + L = [] + wx = [] + gx = [] + wy = [] + gy = [] + + for n in range(len(spaces)): + s = spaces[n] + Lmax = s.L + N = 100 + node = None + + cmds = """ + gouy gx1 x {spaces} + bp bpx x w {node}* + gouy gy1 y {spaces} + bp bpy y w {node}* + xaxis {space} L lin 0 {Lmax} {N} + """.format(space=s.name, Lmax=Lmax, N=int(N), spaces=" ".join([s.name for s in spaces[0:n+1]]), node=nodes2[n]) + + k = copy.deepcopy(kat) + k.parseCommands(cmds) + k.verbose = False + out = k.run() + pylab.subplot(2,1,1) + + L.extend(currL + out.x) + wx.extend(out['bpx']) + wy.extend(out['bpy']) + gx.extend(out['gx1']) + gy.extend(out['gy1']) + currL += Lmax + + pylab.subplot(2,1,1) + wx = np.array(wx)/1e-2 + wy = np.array(wy)/1e-2 + pylab.plot(L, wx, 'b', L, wy, 'r', L, -wx, 'b', L, -wy, 'r') + pylab.title("Beam size between %s and %s" % (from_node, to_node)) + pylab.ylabel("Beam size [cm]") + pylab.xlabel("Distance from %s to %s [m]" % (from_node, to_node)) + pylab.xlim(min(L), max(L)) + + pylab.subplot(2,1,2) + pylab.plot(L, gx, 'b', L, gy, 'r') + pylab.title("Gouy phase accumulation between %s and %s" % (from_node, to_node)) + pylab.ylabel("Phase accumulation [deg]") + pylab.xlabel("Distance [m]") + pylab.xlim(min(L), max(L)) + pylab.legend(['x','y'], 0) + pylab.tight_layout() + pylab.show() + \ No newline at end of file