diff --git a/pykat/commands.py b/pykat/commands.py
index 241f7b7d971efec41b6e3f0d382845bb70c8613a..f146667019f1d6142fa7cf597341c5708c0d61ca 100644
--- a/pykat/commands.py
+++ b/pykat/commands.py
@@ -34,7 +34,23 @@ class Command(object):
         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.__dict__ = copy.deepcopy(self.__dict__, memo)
         
+        for _ in result._putters:
+            _._updateOwner(result)
+        
+        return result
+            
     def getFinesseText(self):
         """ Base class for individual finesse optical components """
         raise NotImplementedError("This function is not implemented")
@@ -48,10 +64,30 @@ class Command(object):
         Called when this component has been added to a kat object
         """
         self._kat = kat
+        
+        for _ in self._putters:
+            kat.registerVariable(_.name, _)
 
-    def remove(self):
-        self._kat.remove(self)
+    def _on_kat_remove(self):
         self.__removed = True
+        
+        for i in range(len(self._putters)):
+            _ = self._putters[i]
+            
+            self._kat.unregisterVariable(_.name)
+            _.clearPuts()
+        
+        for i in range(len(self._putters)):  
+            del self._putters[0]
+            
+        del self._putters[:]
+        
+        
+    def remove(self):
+        if self.__removed:
+            raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
+        else:
+            self._kat.remove(self)
     
     @property
     def name(self): return self.__name
@@ -95,14 +131,19 @@ class func(Command):
         
         self.value = value
         self.noplot = False
+        self.enabled = True
+        
+        self.output = putter(name, self)
+        self._putters.append(self.output)
         
     def getFinesseText(self):
         rtn = []
 
-        if self.noplot:
-            rtn.append("noplot " + self.name)
+        if self.enabled:
+            if self.noplot:
+                rtn.append("noplot " + self.name)
         
-        rtn.append("func {name} = {value}".format(name=self.name, value=str(self.value)))
+            rtn.append("func {name} = {value}".format(name=self.name, value=str(self.value)))
 
         return rtn
 
@@ -118,10 +159,7 @@ class func(Command):
             return func(v2[0].split()[1], v2[1]) 
         else:
             raise pkex.BasePyKatException("'{0}' not a valid Finesse func command".format(line))
-        
-        
-        
-
+            
 
 class lock(Command):
     def __init__(self, name, variable, gain, accuracy, singleLock=False):
@@ -132,6 +170,10 @@ class lock(Command):
         self.__accuracy = accuracy
         self.singleLock = singleLock
         self.enabled = True
+        
+        
+        self.output = putter(name, self)
+        self._putters.append(self.output)
 
 
     @staticmethod
@@ -278,7 +320,78 @@ class gauss(object):
             kat.nodes[node].setGauss(kat.components[component], gp)
         else:
             kat.nodes[node].setGauss(kat.components[component], gpx, gpy)
-            
+ 
+# class tf(Command):
+#
+#     class fQ(object):
+#         def __init__(self, f, Q, tf):
+#             assert(tf is not None)
+#             self._tf = tf
+#             self.__f = Param("f", self, None, canFsig=False, isPutable=True, isPutter=False, isTunable=True)
+#             self.__Q = Param("Q", self, None, canFsig=False, isPutable=True, isPutter=False, isTunable=True)
+#
+#         def _register_param(self, param):
+#             self._tf._params.append(param)
+#
+#         @property
+#         def f(self): return self.__f
+#         @f.setter
+#         def f(self,value): self.__f.value = SIfloat(value)
+#
+#         @property
+#         def Q(self): return self.__Q
+#         @Q.setter
+#         def Q(self,value): self.__Q.value = SIfloat(value)
+#
+#     def __init__(self, name):
+#         Command.__init__(self, name, False)
+#         self.zeros = []
+#         self.poles = []
+#         self.gain = 1
+#         self.phase = 0
+#         self._params = []
+#
+#     def addPole(self,f, Q):
+#         self.poles.append(tf.fQ(SIfloat(f), SIfloat(Q), self))
+#
+#     def addZero(self,f, Q):
+#         self.zeros.append(tf.fQ(SIfloat(f), SIfloat(Q), self))
+#
+#     @staticmethod
+#     def parseFinesseText(text):
+#         values = text.split()
+#
+#         if ((len(values)-4) % 3) != 0:
+#             raise pkex.BasePyKatException("Transfer function Finesse code format incorrect '{0}'".format(text))
+#
+#         _tf = tf(values[1])
+#
+#         _tf.gain = SIfloat(values[2])
+#         _tf.phase = SIfloat(values[3])
+#
+#         N = int((len(values)-4) / 3)
+#
+#         for i in range(1,N+1):
+#             if values[i*3+1] == 'p':
+#                 _tf.addPole(SIfloat(values[i*3+2]), SIfloat(values[i*3+3]))
+#             elif values[i*3+1] == 'z':
+#                 _tf.addZero(SIfloat(values[i*3+2]), SIfloat(values[i*3+3]))
+#             else:
+#                 raise pkex.BasePyKatException("Transfer function pole/zero Finesse code format incorrect '{0}'".format(text))
+#
+#         return _tf
+#
+#     def getFinesseText(self):
+#         rtn = "tf {name} {gain} {phase} ".format(name=self.name,gain=self.gain,phase=self.phase)
+#
+#         for p in self.poles:
+#             rtn += "p {f} {Q} ".format(f=p.f, Q=p.Q)
+#
+#         for z in self.zeros:
+#             rtn += "p {f} {Q} ".format(f=z.f, Q=z.Q)
+#
+#         return rtn
+                   
 class tf(Command):
     
     class fQ(object):
@@ -298,7 +411,7 @@ class tf(Command):
     
     def addZero(self,f, Q):
         self.zeros.append(tf.fQ(SIfloat(f), SIfloat(Q)))
-        
+    
     @staticmethod
     def parseFinesseText(text):
         values = text.split()
@@ -354,9 +467,12 @@ class xaxis(Command):
         
         self._axis_type = axis_type
 
-        self.x = putter("x1")
-        self.mx = putter("mx1")
+        self.x = putter("x1", self)
+        self.mx = putter("mx1", self)
 
+        self._putters.append(self.x)
+        self._putters.append(self.mx)
+        
         if scale == "lin":
             scale = Scale.linear
         elif scale == "log":
@@ -433,8 +549,11 @@ class xaxis(Command):
 class x2axis(xaxis):
     def __init__(self, scale, limits, param, steps, comp=None, axis_type="x2axis"):
         xaxis.__init__(self, scale, limits, param, steps, comp=comp, axis_type=axis_type)
-        self.x = putter("x2")
-        self.mx = putter("mx2")
+        self.x = putter("x2", self)
+        self.mx = putter("mx2", self)
+
+        self._putters.append(self.x)
+        self._putters.append(self.mx)
 
     @staticmethod
     def parseFinesseText(text):
diff --git a/pykat/components.py b/pykat/components.py
index da2aca3589843796d08e75acbc291754c4de4c42..7c5a6920553638384eb44a89362ff627f5844a1f 100644
--- a/pykat/components.py
+++ b/pykat/components.py
@@ -84,7 +84,7 @@ class NodeGaussSetter(object):
     def qy(self, value):
         self.__node().setGauss(self.__comp(), self.qx, complex(value))
         
-id___ = 0
+id_____pykat_class = 0
   
 class Component(object):
     __metaclass__ = abc.ABCMeta
@@ -93,9 +93,9 @@ class Component(object):
         # This creates an instance specific class for the component
         # this enables us to add properties to instances rather than
         # all classes
-        global id___
-        id___ += 1
-        cnew_name = str("%s.%s_%i" % (cls.__module__, cls.__name__, id___))
+        global id_____pykat_class
+        id_____pykat_class += 1
+        cnew_name = str("%s.%s_%i" % (cls.__module__, cls.__name__, id_____pykat_class))
         
         cnew = type(cnew_name, (cls,), {})
         
@@ -130,6 +130,9 @@ class Component(object):
         result = self.__class__.__new__(self.__class__.__base__)
         result.__dict__ = copy.deepcopy(self.__dict__, memo)
         
+        for _ in result._params:
+            _._updateOwner(result)
+        
         return result
         
     def _register_param(self, param):
@@ -162,7 +165,17 @@ class Component(object):
         self._kat = kat
         
         kat.nodes.registerComponentNodes(self, self._requested_node_names, self.__on_node_change)
+     
+    def _on_kat_remove(self):
+        # inform all parameters that we have removed its owner
+        # so that it can then warn about any puts/vars/xaxis
+        for p in self._params:
+            p._onOwnerRemoved()
         
+        del self._params[:]
+
+        self.__removed = True
+          
     def __on_node_change(self):
         # need to update the node gauss parameter setter members 
         self.__update_node_setters()
@@ -237,16 +250,10 @@ class Component(object):
     def __str__(self): return self.name
     
     def remove(self):
-        self._kat.remove(self)
-        
-        # inform all parameters that we have removed its owner
-        # so that it can then warn about any puts/vars/xaxis
-        for p in self._params:
-            p._onOwnerRemoved()
-        
-        del self._params[:]
-
-        self.__removed = True
+        if self.__removed:
+            raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
+        else:
+            self._kat.remove(self)
     
     def getOptivisParameterDict(self):
         if len(self._params) == 0:
diff --git a/pykat/detectors.py b/pykat/detectors.py
index 4b1b7db9da74b87992b12a4593debfd3955ee040..e652372326ff8e4cf885f5fcd9e365330de935f0 100644
--- a/pykat/detectors.py
+++ b/pykat/detectors.py
@@ -31,7 +31,7 @@ if USE_GUI:
     import pykat.gui.resources
     from pykat.gui.graphics import *
 
-id___ = 0
+id_____pykat_class = 0
 
 class BaseDetector(object) :
     """
@@ -45,9 +45,9 @@ class BaseDetector(object) :
         # This creates an instance specific class for the component
         # this enables us to add properties to instances rather than
         # all classes
-        global id___
-        id___ += 1
-        cnew_name = str("%s.%s_%i" % (cls.__module__, cls.__name__, id___))
+        global id_____pykat_class
+        id_____pykat_class += 1
+        cnew_name = str("%s.%s_%i" % (cls.__module__, cls.__name__, id_____pykat_class))
         
         cnew = type(cnew_name, (cls,), {})
         
@@ -120,6 +120,9 @@ class BaseDetector(object) :
             if rn != None:
                 self._nodes.append(kat.nodes.createNode(rn))
     
+    def _on_kat_remove(self):
+        self.__removed = True
+        
     def remove(self):
         if self.__removed:
             raise pkex.BasePyKatException("{0} has already been marked as removed".format(self.name))
diff --git a/pykat/finesse.py b/pykat/finesse.py
index c1ea4e70b7e82d794bc5d5b519e541e8f2337c79..83bf3b32babb2efc1cb914d148581ee6e8763c67 100644
--- a/pykat/finesse.py
+++ b/pykat/finesse.py
@@ -753,6 +753,7 @@ class kat(object):
         self.vacuum = []
         self.__prevrunfilename = None
         self.printmatrix = None
+        self.__variables = {}
         
         # initialise default block
         self.__currentTag= NO_BLOCK
@@ -1004,8 +1005,8 @@ class kat(object):
                 sys.exit(1)
             else:
                 return
-                
-        for o in self.__blocks[name].contents:
+        
+        for o in self.__blocks[name].contents.copy():
             self.remove(o)
         
         del self.__blocks[name]
@@ -1013,6 +1014,31 @@ class kat(object):
     def __str__(self):
          return "".join(self.generateKatScript())
          
+    def getVariable(self, name):
+        if name not in self.__variables:
+            raise pkex.BasePyKatException("Finesse variable `$%s` does not exist." % name)
+            
+        return self.__variables[name]
+    
+    def registerVariable(self, name, putter):
+        if '$' in name:
+            raise pkex.BasePyKatException("Finesse variable name `%s` should not include the `$` symbol as it is added internally." % name)
+            
+        assert(putter is not None)
+        assert(name == putter.name)
+        
+        if name in self.__variables:
+            raise pkex.BasePyKatException("Finesse variable name `%s` already exists." % name)
+            
+        self.__variables[name] = putter
+        
+    def unregisterVariable(self, name):
+        del self.__variables[name]
+    
+    def printVariables(self):
+        for key in self.__variables:
+            print("$" + key, "::::", "owner =", self.__variables[key].owner.name, ", use count =", self.__variables[key].putCount)
+    
     def parseCommands(self, commands, blocks=None, addToBlock=None):
         try:
             if addToBlock is not None and blocks is not None:
@@ -1190,6 +1216,8 @@ class kat(object):
                         after_process.append((line, self.__currentTag))
                     elif(first == "noplot"):
                         after_process.append((line, self.__currentTag))
+                    elif(first == "put" or first == "put*"):
+                        after_process.append((line, self.__currentTag))
                     else:
                         if self.verbose:
                             print ("Parsing `{0}` into pykat object not implemented yet, added as extra line.".format(line))
@@ -1239,7 +1267,41 @@ class kat(object):
                         raise pkex.BasePyKatException("noplot command `{0}` refers to non-existing detector".format(line))
                         
                     getattr(self, rest).noplot = True
+                
+                elif (first == "put" or first =="put*"):
+                    alt = first == "put*"
                     
+                    values = line.split()
+                    obj = values[1]
+                    target = values[2]
+                    variable = values[3]
+                    
+                    try:
+                        if not hasattr(self, obj):
+                            raise pkex.BasePyKatException("put command `{0}` refers to non-existing component".format(line))
+                    
+                        obj = getattr(self, obj)
+                    
+                        if not hasattr(obj, target):
+                            raise pkex.BasePyKatException("put command component `{0}` does not have a parameter `{1}`".format(line, target))
+                        
+                        target = getattr(obj, target)
+                    
+                        if not target.isPutable:
+                            raise pkex.BasePyKatException("put command `{0}` parameter `{1}` cannot be put to".format(line, target))
+                        
+                        target.put(self.getVariable(variable.replace('$', '')), alt)
+                        
+                    except pkex.BasePyKatException as ex:
+                        if self.verbose:
+                            print("Warning: ", ex.msg)
+                            print ("Parsing `{0}` into pykat object not implemented yet, added as extra line.".format(line))
+                    
+                        obj = line
+                        # manually add the line to the block contents
+                        self.__blocks[block].contents.append(line)
+                        
+                 
                 elif (first == "scale"):
                     v = line.split()
                     accepted = ["psd","psd_hf","asd","asd_hf","meter", "ampere", "deg", "rad", "1/deg", "1/rad",]
@@ -1376,7 +1438,7 @@ class kat(object):
         
 
         except pkex.BasePyKatException as ex:
-            pkex.PrintError("Error parsing line: '%s':"%  line, ex)
+            pkex.PrintError("Pykat error parsing line: '%s':"%  line, ex)
             sys.exit(1)
             
     def saveScript(self, filename=None):
@@ -1649,14 +1711,14 @@ class kat(object):
             #if len(self.detectors.keys()) > 0: 
             
             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)
             
                 r.xlabel = hdr[0]
                 r.ylabel = hdr[1]
                 r.zlabels = [s.strip() for s in hdr[2:]]
                 #r.zlabels = map(str.strip, hdr[2:])
             else:
-                [r.x,r.y,hdr] = self.readOutFile(outfile)
+                [r.x, r.y, hdr] = self.readOutFile(outfile)
                 
                 r.xlabel = hdr[0]
                 r.ylabels = [s.strip() for s in hdr[1:]]
@@ -1767,6 +1829,9 @@ class kat(object):
     
             del nodes
         
+            if hasattr(obj, "_on_kat_remove"):
+                obj._on_kat_remove()
+            
             #import gc
             #print (gc.get_referrers(obj))
             
diff --git a/pykat/param.py b/pykat/param.py
index 264de77b1e3e13d2f01da656a3fb3b04b7ab474d..6644407a2a00d859ef9b6e9d9ad52257b88b2cc3 100644
--- a/pykat/param.py
+++ b/pykat/param.py
@@ -12,7 +12,8 @@ class putable(object):
     Objects that inherit this should be able to have something `put` to it.
     Essentially this means you could write Finesse commands like
     
-    put this parameter value
+    param.put(kat.xaxis.x)
+    
     """
     __metaclass__ = abc.ABCMeta
     
@@ -20,45 +21,96 @@ class putable(object):
         self._parameter_name = parameter_name
         self._component_name = component_name
         self._putter = None
+        self._alt = False
         self._isPutable  = isPutable
     
     @property
     def isPutable(self): return self._isPutable
     
-    def put(self, var):
-    
-        if not isinstance(var, putter):
-            raise pkex.BasePyKatException("var was not something that can be `put` as a value")
+    def put(self, var, alt=False):
+        if not self._isPutable:
+            raise pkex.BasePyKatException("Can't put to this object")
+            
+        if var is not None and not isinstance(var, putter):
+            raise pkex.BasePyKatException("`%s` was not something that can be `put` to a parameter" % str(var))
         
-        if self._putter != None:
-            self._putter.put_count -= 1
-            self._putter.putees.remove(self)
+        # Remove existing puts
+        if self._putter is not None:
+            self._putter.unregister(self)
         
         self._putter = var
+            
+        self._alt = alt
         
-        if var != None:
-            self._putter.put_count += 1
-            self._putter.putees.append(self)
+        if var is not None:
+            self._putter.register(self)
         
     def _getPutFinesseText(self):
         rtn = []
-        # if something is being put to this 
-        if self._putter != None:
-            rtn.append("put {comp} {param} ${value}".format(comp=self._component_name, param=self._parameter_name, value=self._putter.put_name()))
+
+        if self._isPutable and self._putter is not None:
+            putter_enabled = True
+                
+            if hasattr(self._putter.owner, 'enabled'):
+                putter_enabled = self._putter.owner.enabled
+                                
+            if putter_enabled:
+                if self._alt:
+                    alt = '*'
+                else:
+                    alt = ''
+    
+                # if something is being put to this 
+                rtn.append("put{alt} {comp} {param} ${value}".format(alt=alt, comp=self._component_name, param=self._parameter_name, value=self._putter.put_name()))
         
         return rtn
-            
+        
+        
 class putter(object):
     """
     If an object can be put to something that is putable it should inherit this
     object.
     """
     
-    def __init__(self, put_name, isPutter=True):
+    def __init__(self, put_name, owner, isPutter=True):
         self._put_name = put_name
         self.put_count = 0
         self._isPutter = isPutter
         self.putees = [] # list of params that this puts to
+        
+        assert(owner is not None)
+        self.__owner = weakref.ref(owner)
+    
+    def _updateOwner(self, newOwner):
+        del self.__owner
+        self.__owner = weakref.ref(newOwner)
+        
+    def clearPuts(self):
+        for _ in self.putees.copy():
+            _.put(None)
+    
+    def register(self, toput):
+        if not self._isPutter:
+            raise pkex.BasePyKatException("This object can't put")
+            
+        self.put_count += 1
+        self.putees.append(toput)
+    
+    def unregister(self, item):
+        if not self._isPutter:
+            raise pkex.BasePyKatException("This object can't put")
+            
+        self.put_count -= 1
+        self.putees.remove(item)
+        
+    @property
+    def owner(self): return self.__owner()
+    
+    @property
+    def name(self): return self._put_name
+    
+    @property
+    def putCount(self): return self.put_count
     
     @property
     def isPutter(self): return self._isPutter
@@ -68,39 +120,33 @@ class putter(object):
         
 class Param(putable, putter):
 
-    def __init__(self, name, owner, value, canFsig=False, fsig_name=None, isPutable=True, isPutter=True, isTunable=True, var_name=None):
+    def __init__(self, name, owner, value, canFsig=False, fsig_name=None, isPutable=True, isPutter=True, isTunable=True, var_name=None, register=True):
         self._name = name
+        self._registered = register
         self._owner = weakref.ref(owner)
         self._value = value
         self._isPutter = isPutter
         self._isTunable = isTunable
-        self._owner()._register_param(self)
         self._canFsig = False
         
+        if self._registered:
+            self._owner()._register_param(self)
+        
         if canFsig:
             self._canFsig = True
-
+            
             if fsig_name is None:
                 raise pkex.BasePyKatException("If parameter is a possible fsig target the fsig_name argument must be set")
-
+                
             self.__fsig_name = fsig_name
         
         if isPutter:
             if var_name is None:
                 var_name = "var_{0}_{1}".format(owner.name, name)
                 
-        putter.__init__(self, var_name, isPutter)
+        putter.__init__(self, var_name, owner, isPutter)
             
         putable.__init__(self, owner.name, name, isPutable)
-
-    def _updateOwner(self, newOwner):
-        """
-        This updates the internal weak reference to link a parameter to who owns it.
-        Should only be called by the __deepcopy__ component method to ensure things
-        are kept up to date.
-        """
-        del self._owner
-        self._owner = weakref.ref(newOwner)
         
     @property
     def canFsig(self): return self._canFsig
@@ -162,7 +208,16 @@ class Param(putable, putter):
             rtn.append("set {put_name} {comp} {param}".format(put_name=self.put_name(), comp=self._owner().name, param=self.name))
         
         return rtn
-    
+        
+    def _updateOwner(self, newOwner):
+        """
+        This updates the internal weak reference to link a parameter to who owns it.
+        Should only be called by the __deepcopy__ component method to ensure things
+        are kept up to date.
+        """
+        del self._owner
+        self._owner = weakref.ref(newOwner)
+        
     def _onOwnerRemoved(self):
         #if this param can be put somewhere we need to check if it is
         if self.isPutable:
diff --git a/test/test_scripts/random/test_unicode_printing.py b/test/test_scripts/random/test_unicode_printing.py
index 2afb8c3fc2c3720af478ac8d67d7859aad9fb364..42b544852bb341ddbca14611c2b7c1288f7a5773 100644
--- a/test/test_scripts/random/test_unicode_printing.py
+++ b/test/test_scripts/random/test_unicode_printing.py
@@ -13,9 +13,11 @@ kat.loadKatFile("LHO_IFO_maxtem2.kat") # load the conf
 kat.parseKatCode( "fsig sig1 ETMXHR 10 180")
 kat.parseKatCode( "fsig sig1 ETMYHR 10 0")
 kat.parseKatCode( "pd1 myomc 10  nOMC_HROC_trans")
-kat.parseKatCode( "put myomc f1 $x1") # to follow
 kat.parseKatCode( "xaxis sig1 f log 10 1k 10")
+kat.parseKatCode( "put myomc f1 $x1") # to follow
 kat.parseKatCode( "yaxis abs:deg")
 kat.verbose = True
 out = kat.run()    # do the computation
-result.append(out['myomc'])   # append the result
\ No newline at end of file
+result.append(out['myomc'])   # append the result
+
+print("PASSED")
\ No newline at end of file
diff --git a/test/test_scripts/structural/test_deepcopying_references.py b/test/test_scripts/structural/test_deepcopying_references.py
index a82b0613cc47eac50f8ba3897899a513286e5d6c..2d3fc7f41ed55a947966d56388d9dbe9c3a8ccf4 100644
--- a/test/test_scripts/structural/test_deepcopying_references.py
+++ b/test/test_scripts/structural/test_deepcopying_references.py
@@ -25,6 +25,9 @@ assert(kat0.nodes.n0 != kat1.nodes.n0)
 assert(kat0.o1 != kat1.o1)
 assert(kat0.o1.__class__ != kat1.o1.__class__)
 
+assert(kat0.m1.phi.owner == kat0.m1)
+assert(kat1.m1.phi.owner == kat1.m1)
+
 # use is to compare if two params are the same object as equals is override to compare the value
 assert(kat0.o1.f1 is not kat1.o1.f1)
 assert(kat0.o1.f1 == kat1.o1.f1)
diff --git a/work_in_progress/optivis_ex.py b/work_in_progress/optivis_ex.py
index a0806ee1153766503aa12d129b3f553aa12730e3..d291127588a872dc2af9783077db9b3bd383836e 100644
--- a/work_in_progress/optivis_ex.py
+++ b/work_in_progress/optivis_ex.py
@@ -22,6 +22,7 @@ attr m1 Rc -500
 attr m2 Rc 500
 cav c1 m1 n4b m2 n7a
 
+pd P n5b
 maxtem 0
 noxaxis
 """)