diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp
index c1be652ce1893086dde17f8be70bff29af6f2bf9..10c42a32c5867dcb7f7a617adea1f1523b80f563 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp
+++ b/Code/Mantid/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp
@@ -920,10 +920,16 @@ bool SANSRunWindow::loadUserFile()
   // from the ticket #5942 both detectors have center coordinates
   dbl_param = runReduceScriptFunction(
     "print i.ReductionSingleton().get_beam_center('rear')[0]").toDouble();
-  m_uiForm.rear_beam_x->setText(QString::number(dbl_param*1000.0));
+  // get the scale factor1 for the beam centre to scale it correctly
+  double dbl_paramsf = runReduceScriptFunction(
+    "print i.ReductionSingleton().get_beam_center_scale_factor1()").toDouble();
+  m_uiForm.rear_beam_x->setText(QString::number(dbl_param*dbl_paramsf));
+  // get scale factor2 for the beam centre to scale it correctly
+  dbl_paramsf = runReduceScriptFunction(
+    "print i.ReductionSingleton().get_beam_center_scale_factor2()").toDouble();
   dbl_param = runReduceScriptFunction(
     "print i.ReductionSingleton().get_beam_center('rear')[1]").toDouble();
-  m_uiForm.rear_beam_y->setText(QString::number(dbl_param*1000.0));
+  m_uiForm.rear_beam_y->setText(QString::number(dbl_param*dbl_paramsf));
   // front
   dbl_param = runReduceScriptFunction(
     "print i.ReductionSingleton().get_beam_center('front')[0]").toDouble();
diff --git a/Code/Mantid/instrument/LARMOR_Parameters.xml b/Code/Mantid/instrument/LARMOR_Parameters.xml
index 7d8452b19e2cddf0ce2ec8da034e230ae67f2147..269f48964a125ff254df06f2e4735dfcac7475c5 100644
--- a/Code/Mantid/instrument/LARMOR_Parameters.xml
+++ b/Code/Mantid/instrument/LARMOR_Parameters.xml
@@ -46,10 +46,32 @@
 
 
 <parameter name="centre-finder-step-size">
-<!-- this is the initial step for the beam centre finder in metres -->
+<!-- this is the initial step for the beam centre finder degrees (X value)-->
+<!-- 5mm at 4m = 0.07deg -->
+  <value val="0.07"/>
+</parameter>
+
+<parameter name="beam-centre-scale-factor1">
+<!-- This is a scale factor to allow the beam centre coordinates to be set in meaningful units (X value)-->
+<!-- e.g. mm in the mask file means this should be 1000.0 -->
+<!-- If no value is supplied then a default of 1000.0 is assumed for backward compatibility -->
+<!-- For Larmor X is in degrees so does not need a multiplier -->
+  <value val="1000.0"/>
+</parameter>
+
+<parameter name="centre-finder-step-size2">
+<!-- this is the second initial step for the beam centre finder if using angle and displacement (Y value)-->
   <value val="0.005"/>
 </parameter>
 
+<parameter name="beam-centre-scale-factor2">
+<!-- This is a scale factor to allow the beam centre coordinates to be set in meaningful units (Y value)-->
+<!-- e.g. mm in the mask file means this should be 1000.0 -->
+<!-- If no value is supplied then a default of 1000.0 is assumed for backward compatibility -->
+<!-- For Larmor Y is in mm -->
+  <value val="1000.0"/>
+</parameter>
+
 </component-link>
 
 </parameter-file>
diff --git a/Code/Mantid/scripts/SANS/ISISCommandInterface.py b/Code/Mantid/scripts/SANS/ISISCommandInterface.py
index b453bb6065b28543b8198a481c2e35285e5a2163..127cc5410f9793efc32eb66af44bf6a30f0c2379 100644
--- a/Code/Mantid/scripts/SANS/ISISCommandInterface.py
+++ b/Code/Mantid/scripts/SANS/ISISCommandInterface.py
@@ -316,9 +316,12 @@ def SetCentre(xcoord, ycoord, bank = 'rear'):
     Introduced #5942
     """
     _printMessage('SetCentre(' + str(xcoord) + ', ' + str(ycoord) + ')')
+    # use the scale factors from the parameter file to scale correctly
+    XSF = ReductionSingleton().inst.beam_centre_scale_factor1
+    YSF = ReductionSingleton().inst.beam_centre_scale_factor2
 
     ReductionSingleton().set_beam_finder(isis_reduction_steps.BaseBeamFinder(\
-                                float(xcoord)/1000.0, float(ycoord)/1000.0), bank)
+                                float(xcoord)/XSF, float(ycoord)/YSF), bank)
 
 def GetMismatchedDetList():
     """
@@ -561,56 +564,56 @@ def _fitRescaleAndShift(rAnds, frontData, rearData):
         Fit rear data to FRONTnew(Q) = ( FRONT(Q) + SHIFT )xRESCALE,
         FRONT(Q) is the frontData argument. Returns scale and shift
 
-        Note SHIFT is shift of a constant back, not the Shift parameter in
-        TabulatedFunction.
-
         @param rAnds: A DetectorBank -> _RescaleAndShift structure
         @param frontData: Reduced front data
         @param rearData: Reduced rear data
     """
     if rAnds.fitScale==False and rAnds.fitShift==False:
         return rAnds.scale, rAnds.shift
-
+    #TODO: we should allow the user to add constraints?
     if rAnds.fitScale==False:
         if rAnds.qRangeUserSelected:
             Fit(InputWorkspace=rearData,
                 Function='name=TabulatedFunction, Workspace="'+str(frontData)+'"'
-                +";name=FlatBackground",
-                Ties='f0.Scaling='+str(rAnds.scale)+',f0.Shift=0.0',
+                +";name=FlatBackground", Ties='f0.Scaling='+str(rAnds.scale),
                 Output="__fitRescaleAndShift", StartX=rAnds.qMin, EndX=rAnds.qMax)
         else:
             Fit(InputWorkspace=rearData,
                 Function='name=TabulatedFunction, Workspace="'+str(frontData)+'"'
-                +";name=FlatBackground",
-                Ties='f0.Scaling='+str(rAnds.scale)+',f0.Shift=0.0',
+                +";name=FlatBackground", Ties='f0.Scaling='+str(rAnds.scale),
                 Output="__fitRescaleAndShift")
     elif rAnds.fitShift==False:
         if rAnds.qRangeUserSelected:
+            function_input = 'name=TabulatedFunction, Workspace="'+str(frontData)+'"' +";name=FlatBackground"
+            ties = 'f1.A0='+str(rAnds.shift*rAnds.scale)
+            logger.warning('function input ' + str(function_input))
+
             Fit(InputWorkspace=rearData,
                 Function='name=TabulatedFunction, Workspace="'+str(frontData)+'"'
-                +";name=FlatBackground",
-                Ties='f1.A0='+str(rAnds.shift*rAnds.scale)+',f0.Shift=0.0',
+                +";name=FlatBackground", Ties='f1.A0='+str(rAnds.shift*rAnds.scale),
                 Output="__fitRescaleAndShift", StartX=rAnds.qMin, EndX=rAnds.qMax)
         else:
             Fit(InputWorkspace=rearData,
                 Function='name=TabulatedFunction, Workspace="'+str(frontData)+'"'
-                +";name=FlatBackground",
-                Ties='f1.A0='+str(rAnds.shift*rAnds.scale)+',f0.Shift=0.0',
+                +";name=FlatBackground", Ties='f1.A0='+str(rAnds.shift*rAnds.scale),
                 Output="__fitRescaleAndShift")
     else:
         if rAnds.qRangeUserSelected:
             Fit(InputWorkspace=rearData,
                 Function='name=TabulatedFunction, Workspace="'+str(frontData)+'"'
-                +";name=FlatBackground", Ties=',f0.Shift=0.0',
+                +";name=FlatBackground",
                 Output="__fitRescaleAndShift", StartX=rAnds.qMin, EndX=rAnds.qMax)
         else:
             Fit(InputWorkspace=rearData, Function='name=TabulatedFunction, Workspace="'+str(frontData)+'"'
-                +";name=FlatBackground", Ties=',f0.Shift=0.0', Output="__fitRescaleAndShift")
+                +";name=FlatBackground",Output="__fitRescaleAndShift")
 
     param = mtd['__fitRescaleAndShift_Parameters']
 
-    scale = param.row(0).items()[1][1]
-    chiSquared = param.row(3).items()[1][1]
+    row1 = param.row(0).items()
+    row2 = param.row(1).items()
+    row3 = param.row(2).items()
+    scale = row1[1][1]
+    chiSquared = row3[1][1]
 
     fitSuccess = True
     if not chiSquared > 0:
@@ -623,7 +626,7 @@ def _fitRescaleAndShift(rAnds, frontData, rearData):
     if fitSuccess == False:
         return rAnds.scale, rAnds.shift
 
-    shift =  param.row(2).items()[1][1] / scale
+    shift = row2[1][1] / scale
 
     delete_workspaces('__fitRescaleAndShift_Parameters')
     delete_workspaces('__fitRescaleAndShift_NormalisedCovarianceMatrix')
@@ -823,7 +826,8 @@ def SetPhiLimit(phimin, phimax, use_mirror=True):
     #a beam centre of [0,0,0] makes sense if the detector has been moved such that beam centre is at [0,0,0]
     ReductionSingleton().mask.set_phi_limit(phimin, phimax, use_mirror)
 
-def SetDetectorOffsets(bank, x, y, z, rot, radius, side):
+def SetDetectorOffsets(bank, x, y, z, rot, radius, side, xtilt=0.0, ytilt=0.0 ):
+    # 10/03/15 RKH added 2 more parameters - xtilt & ytilt
     """
         Adjust detector position away from position defined in IDF. On SANS2D the detector
         banks can be moved around. This method allows fine adjustments of detector bank position
@@ -841,10 +845,12 @@ def SetDetectorOffsets(bank, x, y, z, rot, radius, side):
         @param rot: shift in degrees
         @param radius: shift in mm
         @param side: shift in mm
+        @param side: xtilt in degrees
+        @param side: ytilt in degrees
     """
     _printMessage("SetDetectorOffsets(" + str(bank) + ', ' + str(x)
                   + ','+str(y) + ',' + str(z) + ',' + str(rot)
-                  + ',' + str(radius) + ',' + str(side) + ')')
+                  + ',' + str(radius) + ',' + str(side) + ',' + str(xtilt)+ ',' + str(ytilt) +')')
 
     detector = ReductionSingleton().instrument.getDetector(bank)
     detector.x_corr = x
@@ -853,7 +859,24 @@ def SetDetectorOffsets(bank, x, y, z, rot, radius, side):
     detector.rot_corr = rot
     detector.radius_corr = radius
     detector.side_corr = side
+	# 10/03/15 RKH add 2 more
+    detector.x_tilt = xtilt
+    detector.y_tilt = ytilt
 
+def SetCorrectionFile(bank, filename):
+    # 10/03/15 RKH, create a new routine that allows change of "direct beam file" = correction file, for a given 
+    # detector, this simplify the iterative process used to adjust it. Will still have to keep changing the name of the file
+    # for each iteratiom to avoid Mantid using a cached version, but can then use only a single user (=mask) file for each set of iterations.
+    # Modelled this on SetDetectorOffsets above ...
+    """
+        @param bank: Must be either 'front' or 'rear' (not case sensitive)
+        @param filename: self explanatory
+    """
+    _printMessage("SetCorrectionFile(" + str(bank) + ', ' + filename +')')
+
+    detector = ReductionSingleton().instrument.getDetector(bank)
+    detector.correction_file = filename
+    
 def LimitsR(rmin, rmax, quiet=False, reducer=None):
     if reducer == None:
         reducer = ReductionSingleton().reference()
@@ -1038,7 +1061,10 @@ def FindBeamCentre(rlow, rupp, MaxIter = 10, xstart = None, ystart = None, toler
         @return: the best guess for the beam centre point
     """
     XSTEP = ReductionSingleton().inst.cen_find_step
-    YSTEP = ReductionSingleton().inst.cen_find_step
+    YSTEP = ReductionSingleton().inst.cen_find_step2
+
+    XSF = ReductionSingleton().inst.beam_centre_scale_factor1
+    YSF = ReductionSingleton().inst.beam_centre_scale_factor2
 
     original = ReductionSingleton().get_instrument().cur_detector_position(ReductionSingleton().get_sample().get_wksp_name())
 
@@ -1077,6 +1103,7 @@ def FindBeamCentre(rlow, rupp, MaxIter = 10, xstart = None, ystart = None, toler
     XNEW = xstart + XSTEP
     YNEW = ystart + YSTEP
     graph_handle = None
+    it = 0
     for i in range(1, MaxIter+1):
         it = i
 
@@ -1123,7 +1150,7 @@ def FindBeamCentre(rlow, rupp, MaxIter = 10, xstart = None, ystart = None, toler
 
     ReductionSingleton().set_beam_finder(
         isis_reduction_steps.BaseBeamFinder(XNEW, YNEW), det_bank)
-    centre.logger.notice("Centre coordinates updated: [" + str(XNEW)+ ", "+ str(YNEW) + ']')
+    centre.logger.notice("Centre coordinates updated: [" + str(XNEW*XSF) + ", " + str(YNEW*YSF) + ']')
 
     return XNEW, YNEW
 
diff --git a/Code/Mantid/scripts/SANS/centre_finder.py b/Code/Mantid/scripts/SANS/centre_finder.py
index a3f2e4ca4658fcde0f1f2e1ce244e11dcd9e063e..b179ee8328d451445d135384b4818756b3e47ab3 100644
--- a/Code/Mantid/scripts/SANS/centre_finder.py
+++ b/Code/Mantid/scripts/SANS/centre_finder.py
@@ -21,6 +21,8 @@ class CentreFinder(object):
         self.logger = Logger("CentreFinder")
         self._last_pos = guess_centre
         self.detector = None
+        self.XSF = 1.0
+        self.YSF = 1.0
 
     def SeekCentre(self, setup, trial):
         """
@@ -33,6 +35,10 @@ class CentreFinder(object):
 
         self.detector = setup.instrument.cur_detector().name()
 
+        # populate the x and y scale factor values at this point for the text box
+        self.XSF = setup.instrument.beam_centre_scale_factor1
+        self.YSF = setup.instrument.beam_centre_scale_factor2
+
         self.move(setup, trial[0]-self._last_pos[0], trial[1]-self._last_pos[1])
 
         #phi masking will remove areas of the detector that we need
@@ -83,8 +89,9 @@ class CentreFinder(object):
             @param y_res: asymmetry in y
             @return: a human readable string
         """
-        x_str = str(self._last_pos[0]*1000.).ljust(10)[0:9]
-        y_str = str(self._last_pos[1]*1000.).ljust(10)[0:9]
+
+        x_str = str(self._last_pos[0] * self.XSF).ljust(10)[0:9]
+        y_str = str(self._last_pos[1] * self.YSF).ljust(10)[0:9]
         x_res = '    SX='+str(x_res).ljust(7)[0:6]
         y_res = '    SY='+str(y_res).ljust(7)[0:6]
         return 'Itr '+str(iter)+':  ('+x_str+',  '+y_str+')'+x_res+y_res
diff --git a/Code/Mantid/scripts/SANS/isis_instrument.py b/Code/Mantid/scripts/SANS/isis_instrument.py
index 743145fa0b79f6349c077742193b01cdf73872b2..088d87dd5f3481a27bb9cc82a476b8dc892dd9c0 100644
--- a/Code/Mantid/scripts/SANS/isis_instrument.py
+++ b/Code/Mantid/scripts/SANS/isis_instrument.py
@@ -10,6 +10,7 @@ import xml.dom.minidom
 from mantid.simpleapi import *
 from mantid.api import WorkspaceGroup, Workspace, ExperimentInfo
 from mantid.kernel import Logger
+from mantid.kernel import V3D
 import SANSUtility as su
 
 sanslog = Logger("SANS")
@@ -219,6 +220,9 @@ class DetectorBank(object):
         #23/3/12 RKH add 2 more variables
         self._radius_corr = 0.0
         self._side_corr =0.0
+		# 10/03/15 RKH add 2 more, valid for all detectors.  WHY do some of the above have an extra leading underscore?? Seems they are the optional ones sorted below
+        self.x_tilt = 0.0
+        self.y_tilt = 0.0
 
         # hold rescale and shift object _RescaleAndShift
         self.rescaleAndShift = self._RescaleAndShift()
@@ -427,8 +431,28 @@ class ISISInstrument(BaseInstrument):
         #the spectrum with this number is used to normalize the workspace data
         self._incid_monitor = int(self.definition.getNumberParameter(
             'default-incident-monitor-spectrum')[0])
-        self.cen_find_step = float(self.definition.getNumberParameter(
-            'centre-finder-step-size')[0])
+        self.cen_find_step = float(self.definition.getNumberParameter('centre-finder-step-size')[0])
+        # see if a second step size is defined. If not set the second value to the first for compatibility
+        #logger.warning("Trying to find centre-finder-step-size2")
+        try:
+           self.cen_find_step2 = float(self.definition.getNumberParameter('centre-finder-step-size2')[0])
+        except:
+           #logger.warning("Failed to find centre-finder-step-size2")
+           self.cen_find_step2 = self.cen_find_step
+
+        logger.warning("Trying to find beam-centre-scale-factor1")
+        try:
+           self.beam_centre_scale_factor1 = float(self.definition.getNumberParameter('beam-centre-scale-factor1')[0])
+        except:
+           logger.warning("Failed to find beam-centre-scale-factor1")
+           self.beam_centre_scale_factor1 = 1000.0
+
+        logger.warning("Trying to find beam-centre-scale-factor2")
+        try:
+           self.beam_centre_scale_factor2 = float(self.definition.getNumberParameter('beam-centre-scale-factor2')[0])
+        except:
+           logger.warning("Failed to find beam-centre-scale-factor2")
+           self.beam_centre_scale_factor2 = 1000.0
 
         firstDetect = DetectorBank(self.definition, 'low-angle')
         #firstDetect.disable_y_and_rot_corrs()
@@ -463,6 +487,10 @@ class ISISInstrument(BaseInstrument):
         self.REAR_DET_Z = 0.0
         self.REAR_DET_X = 0
 
+        # LOG files for Larmor will have these encoder readings
+        # why are these not defined in Larmor
+        self.BENCH_ROT = 0.0
+
         #spectrum number of the monitor used to as the incidient in the transmission calculations
         self.default_trans_spec = int(self.definition.getNumberParameter(
             'default-transmission-monitor-spectrum')[0])
@@ -896,7 +924,15 @@ class SANS2D(ISISInstrument):
         FRONT_DET_Z, FRONT_DET_X, FRONT_DET_ROT, REAR_DET_Z, REAR_DET_X = self.getDetValues(ws)
 
         # Deal with front detector
-        # 9/1/2  this all dates to Richard Heenan & Russell Taylor's original python development for SANS2d
+        # 10/03/15 RKH need to add tilt of detector, in degrees, with respect to the horizontal or vertical of the detector plane 
+        # this time we can rotate about the detector's own axis so can use RotateInstrumentComponent, ytilt rotates about x axis, xtilt rotates about z axis
+        #
+        if frontDet.y_tilt != 0.0:
+            RotateInstrumentComponent(Workspace=ws,ComponentName= self.getDetector('front').name(), X = "1.", Y = "0.", Z = "0.", Angle = frontDet.y_tilt)
+        if frontDet.x_tilt != 0.0:
+            RotateInstrumentComponent(Workspace=ws,ComponentName= self.getDetector('front').name(), X = "0.", Y = "0.", Z = "1.", Angle = frontDet.x_tilt)
+        #		
+        # 9/1/12  this all dates to Richard Heenan & Russell Taylor's original python development for SANS2d
     	# the rotation axis on the SANS2d front detector is actually set front_det_radius = 306mm behind the detector.
     	# Since RotateInstrumentComponent will only rotate about the centre of the detector, we have to to the rest here.
         # rotate front detector according to value in log file and correction value provided in user file
@@ -925,6 +961,14 @@ class SANS2D(ISISInstrument):
 
         # deal with rear detector
 
+        # 10/03/15 RKH need to add tilt of detector, in degrees, with respect to the horizontal or vertical of the detector plane 
+        # Best to do the tilts first, while the detector is still centred on the z axis, ytilt rotates about x axis, xtilt rotates about z axis
+        # NOTE the beam centre coordinates may change
+        if rearDet.y_tilt != 0.0:
+            RotateInstrumentComponent(Workspace=ws,ComponentName= rearDet.name(), X = "1.", Y = "0.", Z = "0.", Angle = rearDet.y_tilt)
+        if rearDet.x_tilt != 0.0:
+            RotateInstrumentComponent(Workspace=ws,ComponentName= rearDet.name(), X = "0.", Y = "0.", Z = "1.", Angle = rearDet.x_tilt)
+
         xshift = -xbeam
         yshift = -ybeam
         zshift = (REAR_DET_Z + rearDet.z_corr)/1000.
@@ -1140,10 +1184,16 @@ class SANS2D(ISISInstrument):
 
 class LARMOR(ISISInstrument):
     _NAME = 'LARMOR'
-    WAV_RANGE_MIN = 2.2
-    WAV_RANGE_MAX = 10.0
+    WAV_RANGE_MIN = 0.5
+    WAV_RANGE_MAX = 13.5
     def __init__(self):
         super(LARMOR,self).__init__('LARMOR_Definition.xml')
+        self._marked_dets = []
+        # set to true once the detector positions have been moved to the locations given in the sample logs
+        self.corrections_applied = False
+        # a warning is issued if the can logs are not the same as the sample
+        self._can_logs = {}
+
         self.monitor_names = dict()
 
         for i in range(1,6):
@@ -1161,82 +1211,259 @@ class LARMOR(ISISInstrument):
         second.set_orien('Horizontal')
         second.place_after(first)
 
-    def move_components(self, ws, xbeam, ybeam):
-        self.move_all_components(ws)
+    def getDetValues(self, ws_name):
+        """
+        Retrive the values of Bench_Rot from the workspace. If it does not find the value at the run info,
+        it takes as default value the self.BENCH_ROT, which are extracted from the sample workspace
+        at apply_detector_log.
+        This is done to allow the function move_components to use the correct values and not to use
+        all the values for TRANS ans SAMPLE the same, as sometimes, this assumption is not valid.
+        The reason for this method is explained at the ticket http://trac.mantidproject.org/mantid/ticket/7314.
+        """
+        # set the default value for these variables
+        values = [self.BENCH_ROT]
+        # get these variables from the workspace run
+        run_info = mtd[str(ws_name)].run()
+        ind = 0
+        name = 'Bench_Rot'
+        try:
+            var = run_info.get(name).value
+            if hasattr(var, '__iter__'):
+                var = var[-1]
+            values[ind] = float(var)
+        except:
+            pass # ignore, because we do have a default value
+        ind += 1
+        #return these variables
+        return tuple(values)
 
-        detBanch = self.getDetector('rear')
+    def get_detector_log(self, wksp):
+        """
+            Reads information about the state of the instrument on the information
+            stored in the sample
+            @param logs: a workspace pointer
+            @return the values that were read as a dictionary
+        """
+        #logger.warning("Entering get_detector_log")
+        self._marked_dets = []
+        wksp = su.getWorkspaceReference(wksp)
+        #assume complete log information is stored in the first entry, it isn't stored in the group workspace itself
+        if isinstance(wksp, WorkspaceGroup):
+            wksp = wksp[0]
 
-        xshift = -xbeam
-        yshift = -ybeam
-        #zshift = ( detBanch.z_corr)/1000.
-        #zshift -= self.REAR_DET_DEFAULT_SD_M
-        zshift = 0
-        sanslog.notice("Setup move " + str(xshift*1000) + " " + str(yshift*1000) + " " + str(zshift*1000))
-        MoveInstrumentComponent(ws, ComponentName=detBanch.name(), X=xshift,
-                                Y=yshift, Z=zshift)
-        # beam centre, translation
-        return [0.0, 0.0], [-xbeam, -ybeam]
+        samp = wksp.getRun()
 
-    def cur_detector_position(self, ws_name):
-        """Return the position of the center of the detector bank"""
-        ws = mtd[ws_name]
-        pos = ws.getInstrument().getComponentByName(self.cur_detector().name()).getPos()
+        logvalues = {}
+        logvalues['Bench_Rot'] = self._get_const_num(samp, 'Bench_Rot')
+        #logger.warning(str(logvalues))
 
-        return [-pos.getX(), -pos.getY()]
+        return logvalues
 
+    def _get_const_num(self, log_data, log_name):
+        """
+            Get a the named entry from the log object. If the entry is a
+            time series it's assumed to contain unchanging data and the first
+            value is used. The answer must be convertible to float otherwise
+            this throws.
+            @param log_data: the sample object from a workspace
+            @param log_name: a string with the name of the individual entry to load
+            @return: the floating point number
+            @raise TypeError: if that log entry can't be converted to a float
+        """
+        try:
+            # return the log value if it stored as a single number
+            return float(log_data.getLogData(log_name).value)
+        except TypeError:
+            # Python 2.4 doesn't have datetime.strptime...
+            def format_date(date_string, format, date_str_len):
+                if len(date_string)>date_str_len:
+                    date_string = date_string[:date_str_len]
+                from datetime import datetime
+                if sys.version_info[0] == 2 and sys.version_info[1] <  5:
+                    import time
+                    return datetime(*(time.strptime(date_string, format)[0:6]))
+                else:
+                    return datetime.strptime(date_string, format)
 
-class LARMOR(ISISInstrument):
-    _NAME = 'LARMOR'
-    WAV_RANGE_MIN = 2.2
-    WAV_RANGE_MAX = 10.0
-    def __init__(self):
-        super(LARMOR,self).__init__('LARMOR_Definition.xml')
-        self.monitor_names = dict()
+            # if the value was stored as a time series we have an array here
+            property = log_data.getLogData(log_name)
 
-        for i in range(1,6):
-            self.monitor_names[i] = 'monitor'+str(i)
+            size = len(property.value)
+            if size == 1:
+                return float(log_data.getLogData(log_name).value[0])
 
-    def set_up_for_run(self, base_runno):
+            start = log_data.getLogData('run_start')
+            dt_0 = format_date(start.value,"%Y-%m-%dT%H:%M:%S",19)
+            for i in range(0, size):
+                dt = format_date(str(property.times[i]),"%Y-%m-%dT%H:%M:%S",19)
+                if dt > dt_0:
+                    if i == 0:
+                        return float(log_data.getLogData(log_name).value[0])
+                    else:
+                        return float(log_data.getLogData(log_name).value[i-1])
+
+            # this gets executed if all entries is before the start-time
+            return float(log_data.getLogData(log_name).value[size-1])
+
+    def apply_detector_logs(self, logvalues):
+        #apply the corrections that came from the logs
+        self.BENCH_ROT = float(logvalues['Bench_Rot'])
+        self.corrections_applied = True
+        if len(self._can_logs) > 0:
+            self.check_can_logs(self._can_logs)
+
+    def check_can_logs(self, new_logs):
         """
-            Needs to run whenever a sample is loaded
+            Tests if applying the corrections from the passed logvalues
+            would give the same result as the corrections that were
+            already made
+            @param new_logs: the new values to check are equivalent
+            @return: True if the are the same False if not
         """
-        first = self.DETECTORS['low-angle']
-        second = self.DETECTORS['high-angle']
+        #logger.warning("Entering check_can_logs")
 
-        first.set_orien('Horizontal')
-        first.set_first_spec_num(10)
-        second.set_orien('Horizontal')
-        second.place_after(first)
+        if not self.corrections_applied:
+            #the check needs to wait until there's something to compare against
+            self._can_logs = new_logs
+
+        if len(new_logs) == 0:
+            return False
+
+        existing_values = []
+        existing_values.append(self.BENCH_ROT)
+
+        new_values = []
+        new_values.append(float(new_logs['Bench_Rot']))
+
+        errors = 0
+        corr_names = ['Bench_Rot']
+        for i in range(0, len(existing_values)):
+            if math.fabs(existing_values[i] - new_values[i]) > 5e-04:
+                sanslog.warning('values differ between sample and can runs: Sample ' + corr_names[i] + ' = ' + str(existing_values[i]) + \
+                    ', can value is ' + str(new_values[i]))
+                errors += 1
+
+                self.append_marked(corr_names[i])
+
+        #the check has been done clear up
+        self._can_logs = {}
+
+        return errors == 0
 
     def move_components(self, ws, xbeam, ybeam):
+        #logger.warning("Entering move_components")
         self.move_all_components(ws)
+        #logger.warning("Back from move_all_components")
 
-        detBanch = self.getDetector('rear')
+        detBench = self.getDetector('rear')
 
-        xshift = -xbeam
+        # get the bench rotation value from the instrument log
+        BENCH_ROT = self.getDetValues(ws)[0]
+
+        # use the scale factors from the parameter file to scale appropriately
+        XSF = self.beam_centre_scale_factor1
+        YSF = self.beam_centre_scale_factor2
+
+        # in this case the x shift is actually a value of 2theta rotated about the sample stack centre
+        # so... we need to do two moves first a shift in y and then a rotation
         yshift = -ybeam
         #zshift = ( detBanch.z_corr)/1000.
         #zshift -= self.REAR_DET_DEFAULT_SD_M
+        xshift = 0
         zshift = 0
-        sanslog.notice("Setup move " + str(xshift*1000) + " " + str(yshift*1000) + " " + str(zshift*1000))
-        MoveInstrumentComponent(ws, ComponentName=detBanch.name(), X=xshift,
-                                Y=yshift, Z=zshift)
+        sanslog.notice("Setup move " + str(xshift*XSF) + " " + str(yshift*YSF) + " " + str(zshift*1000))
+        MoveInstrumentComponent(ws, ComponentName=detBench.name(), X=xshift, Y=yshift, Z=zshift)
+        # in order to avoid rewriting old mask files from initial commisioning during 2014.
+        ws_ref=mtd[ws]
+        try:
+            run_num = ws_ref.getRun().getLogData('run_number').value
+        except:
+            run_num = int(re.findall(r'\d+',str(ws_name))[-1])
+
+        # The angle value
+        # Note that the x position gets converted from mm to m when read from the user file so we need to reverse this if X is now an angle
+        if(int(run_num) < 2217):
+            # Initial commisioning before run 2217 did not pay much attention to making sure the bench_rot value was meaningful
+            xshift = -xbeam
+            sanslog.notice("Setup move " + str(xshift*XSF) + " " + str(0.0) + " " + str(0.0))
+            MoveInstrumentComponent(ws, ComponentName=detBench.name(), X=xshift, Y=0.0, Z=0.0)
+        else:
+            xshift = BENCH_ROT-xbeam*XSF
+            sanslog.notice("Setup move " + str(xshift*XSF) + " " + str(0.0) + " " + str(0.0))
+            RotateInstrumentComponent(ws, ComponentName=detBench.name(), X=0, Y=1, Z=0, Angle=xshift)
+            #logger.warning("Back from RotateInstrumentComponent")
+
         # beam centre, translation
         return [0.0, 0.0], [-xbeam, -ybeam]
 
+    def append_marked(self, detNames):
+        self._marked_dets.append(detNames)
+
+    def get_marked_dets(self):
+        return self._marked_dets
+
     def load_transmission_inst(self, ws_trans, ws_direct, beamcentre):
         """
-            Not required for SANS2D
+        Larmor requires centralisation of the detectors of the transmission
+        as well as the sample and can.
         """
-        pass
+        self.move_components(ws_trans, beamcentre[0], beamcentre[1])
+        if ws_trans != ws_direct:
+            self.move_components(ws_direct, beamcentre[0], beamcentre[1])
 
     def cur_detector_position(self, ws_name):
         """Return the position of the center of the detector bank"""
+        """Unforunately getting the angle of the bench does not work so we have to get bench and detector"""
+
+        #logger.warning("Entering cur_detector_position")
         ws = mtd[ws_name]
-        pos = ws.getInstrument().getComponentByName(self.cur_detector().name()).getPos()
+        # define the vector along the beam axis
+        a1 = V3D(0,0,1)
+        # position of the detector itself
+        pos = ws.getInstrument().getComponentByName('LARMORSANSDetector').getPos()
+        # position of the bench
+        pos2 = ws.getInstrument().getComponentByName(self.cur_detector().name()).getPos()
+        # take the difference
+        posdiff = pos-pos2
+        deg2rad = 4.0*math.atan(1.0)/180.0
+        # now finally find the angle between the vector for the difference and the beam axis
+        angle = posdiff.angle(a1)/deg2rad
+
+        # return the angle and the y displacement
+        #logger.warning("Blah: angle=" + str(angle) + " Y displacement=" +str(-pos2.getY()) )
+        return [-angle, -pos2.getY()]
 
-        return [-pos.getX(), -pos.getY()]
+    def on_load_sample(self, ws_name, beamcentre, isSample):
+        """For Larmor in addition to the operations defined in on_load_sample of ISISInstrument
+        it has to deal with the log, which defines some offsets for the movement of the
+        detector bank.
+        """
+        #logger.warning("Entering on_load_sample")
+        ws_ref = mtd[str(ws_name)]
+        # in order to avoid problems with files from initial commisioning during 2014.
+        # these didn't have the required log entries for the detector position
+        try:
+            run_num = ws_ref.getRun().getLogData('run_number').value
+        except:
+            run_num = int(re.findall(r'\d+',str(ws_name))[-1])
+        if(int(run_num) >= 2217):
+            try:
+                #logger.warning("Trying get_detector_log")
+                log = self.get_detector_log(ws_ref)
+                if log == "":
+                    raise "Invalid log"
+            except:
+                if isSample:
+                    raise RuntimeError('Sample logs cannot be loaded, cannot continue')
+                else:
+                    logger.warning("Can logs could not be loaded, using sample values.")
+
+            if isSample:
+                self.apply_detector_logs(log)
+            else:
+                self.check_can_logs(log)
 
+        ISISInstrument.on_load_sample(self, ws_name, beamcentre,  isSample)
 
 if __name__ == '__main__':
     pass
diff --git a/Code/Mantid/scripts/SANS/isis_reducer.py b/Code/Mantid/scripts/SANS/isis_reducer.py
index d22422c814008ebce2db02e81f23b520e081d81b..8b9195ee640a7dce0f32a1119cbd9efa08d64533 100644
--- a/Code/Mantid/scripts/SANS/isis_reducer.py
+++ b/Code/Mantid/scripts/SANS/isis_reducer.py
@@ -622,6 +622,18 @@ class ISISReducer(Reducer):
             else:
                 return self._beam_finder.get_beam_center()
 
+    def get_beam_center_scale_factor1(self):
+        """
+        Return the beam center scale factor 1 defined in the parameter file.
+        """
+        return self.instrument.beam_centre_scale_factor1
+
+    def get_beam_center_scale_factor2(self):
+        """
+        Return the beam center scale factor 2 defined in the parameter file.
+        """
+        return self.instrument.beam_centre_scale_factor2
+
     def getCurrSliceLimit(self):
         if not self._slices_def:
             self._slices_def = su.sliceParser("")
diff --git a/Code/Mantid/scripts/SANS/isis_reduction_steps.py b/Code/Mantid/scripts/SANS/isis_reduction_steps.py
index 308d8e5e8ec0becac8cbb06ce0879eef0bb94e9a..65bf57953fed2fbf5700accf26ae28a7c81927c0 100644
--- a/Code/Mantid/scripts/SANS/isis_reduction_steps.py
+++ b/Code/Mantid/scripts/SANS/isis_reduction_steps.py
@@ -1533,9 +1533,9 @@ class CalculateNormISIS(object):
         """
         detector = detector.upper()
 
-        if detector in ("FRONT","HAB","FRONT-DETECTOR-BANK"):
+        if detector in ("FRONT", "HAB", "FRONT-DETECTOR-BANK"):
             self._high_angle_pixel_file = filename
-        if detector in ("REAR","MAIN","","MAIN-DETECTOR-BANK"):
+        if detector in ("REAR", "MAIN", "", "MAIN-DETECTOR-BANK", "DETECTORBENCH"):
             self._low_angle_pixel_file = filename
 
     def getPixelCorrFile(self, detector ):
@@ -1546,9 +1546,9 @@ class CalculateNormISIS(object):
 
         """
         detector = detector.upper()
-        if detector in ("FRONT","HAB","FRONT-DETECTOR-BANK", "FRONT-DETECTOR"):
+        if detector in ("FRONT", "HAB", "FRONT-DETECTOR-BANK", "FRONT-DETECTOR"):
             return self._high_angle_pixel_file
-        elif detector in ("REAR","MAIN","MAIN-DETECTOR-BANK","", "REAR-DETECTOR"):
+        elif detector in ("REAR","MAIN", "MAIN-DETECTOR-BANK", "", "REAR-DETECTOR", "DETECTORBENCH"):
             return self._low_angle_pixel_file
         else :
             logger.warning("Request of pixel correction file with unknown detector ("+ str(detector)+")")
@@ -1998,19 +1998,23 @@ class UserFile(ReductionStep):
             hab_str_pos = upper_line.find('HAB')
             x_pos = 0.0
             y_pos = 0.0
+            # use the scale factors supplied in the parameter file
+            XSF = reducer.inst.beam_centre_scale_factor1
+            YSF = reducer.inst.beam_centre_scale_factor2
+
             if main_str_pos > 0:
                 values = upper_line[main_str_pos+5:].split() #remov the SET CENTRE/MAIN
-                x_pos = float(values[0])/1000.0
-                y_pos = float(values[1])/1000.0
+                x_pos = float(values[0])/XSF
+                y_pos = float(values[1])/YSF
             elif hab_str_pos > 0:
                 values = upper_line[hab_str_pos+4:].split() # remove the SET CENTRE/HAB
                 print ' convert values ',values
-                x_pos = float(values[0])/1000.0
-                y_pos = float(values[1])/1000.0
+                x_pos = float(values[0])/XSF
+                y_pos = float(values[1])/YSF
             else:
                 values = upper_line.split()
-                x_pos = float(values[2])/1000.0
-                y_pos = float(values[3])/1000.0
+                x_pos = float(values[2])/XSF
+                y_pos = float(values[3])/YSF
             if hab_str_pos > 0:
                 print 'Front values = ',x_pos,y_pos
                 reducer.set_beam_finder(BaseBeamFinder(x_pos, y_pos),'front')
@@ -2085,7 +2089,7 @@ class UserFile(ReductionStep):
                 else:
                     _issueWarning('FIT/MONITOR line specific to LOQ instrument. Line ignored')
 
-        elif upper_line == 'SANS2D' or upper_line == 'LOQ':
+        elif upper_line == 'SANS2D' or upper_line == 'LOQ' or upper_line == 'LARMOR':
             self._check_instrument(upper_line, reducer)
 
         elif upper_line.startswith('PRINT '):
@@ -2338,6 +2342,11 @@ class UserFile(ReductionStep):
             detector.radius_corr = shift
         elif det_axis == 'SIDE':
             detector.side_corr = shift
+		# 10/03/15 RKH add 2 more variables
+        elif det_axis == 'XTILT':
+            detector.x_tilt = shift
+        elif det_axis == 'YTILT':
+            detector.y_tilt = shift
         else:
             raise NotImplemented('Detector correction on "'+det_axis+'" is not supported')