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