From cc4f478ae864d64e3a3c9c1f87e1e2299eec82b9 Mon Sep 17 00:00:00 2001
From: Martyn Gigg <martyn.gigg@stfc.ac.uk>
Date: Fri, 6 May 2011 09:22:30 +0000
Subject: [PATCH] Refs #2898. Merged changes from iteration 29 branch back to
 the trunk.

---
 Code/Mantid/Framework/API/CMakeLists.txt      |   2 +-
 .../API/inc/MantidAPI/MatrixWorkspace.h       |   5 +-
 .../API/inc/MantidAPI/SpectraDetectorMap.h    |   2 -
 .../Framework/API/src/SpectraDetectorMap.cpp  |  27 +-
 .../Framework/Algorithms/CMakeLists.txt       |   5 +-
 .../CreateGroupingWorkspace.h                 |  50 +++
 .../src/CreateGroupingWorkspace.cpp           | 285 ++++++++++++++++++
 .../DiffractionEventCalibrateDetectors.cpp    |  40 ++-
 .../test/CreateGroupingWorkspaceTest.h        | 198 ++++++++++++
 Code/Mantid/Framework/Crystal/CMakeLists.txt  |   2 +-
 .../Framework/Crystal/src/LoadPeaksFile.cpp   |  20 +-
 .../Crystal/test/LoadPeaksFileTest.h          |  34 ++-
 .../Framework/CurveFitting/CMakeLists.txt     |   2 +-
 .../Framework/DataHandling/CMakeLists.txt     |   2 +-
 .../DataHandling/src/LoadInstrument.cpp       |  22 +-
 .../DataHandling/test/LoadInstrumentTest.h    | 106 ++++++-
 .../Framework/DataObjects/CMakeLists.txt      |   5 +-
 .../inc/MantidDataObjects/GroupingWorkspace.h |  54 ++++
 .../DataObjects/inc/MantidDataObjects/Peak.h  |   8 +-
 .../inc/MantidDataObjects/PeaksWorkspace.h    |  13 +-
 .../inc/MantidDataObjects/Workspace2D.h       |   8 +-
 .../DataObjects/src/GroupingWorkspace.cpp     |  77 +++++
 .../Mantid/Framework/DataObjects/src/Peak.cpp |  26 +-
 .../DataObjects/test/GroupingWorkspaceTest.h  |  53 ++++
 .../Framework/DataObjects/test/PeakTest.h     |  28 ++
 Code/Mantid/Framework/Geometry/CMakeLists.txt |   2 +-
 .../inc/MantidGeometry/ICompAssembly.h        |  17 +-
 .../Geometry/inc/MantidGeometry/IComponent.h  |   3 +
 .../MantidGeometry/Instrument/CompAssembly.h  |   4 +
 .../inc/MantidGeometry/Instrument/Component.h |   9 +-
 .../MantidGeometry/Instrument/DetectorGroup.h |   1 +
 .../Instrument/ObjCompAssembly.h              |   6 +
 .../Instrument/RectangularDetector.h          |   2 +
 .../Geometry/inc/MantidGeometry/Math/Matrix.h |   1 +
 .../Objects/InstrumentRayTracer.h             |   6 +-
 .../Geometry/inc/MantidGeometry/V3D.h         |   2 +
 .../Geometry/src/Crystal/OrientedLattice.cpp  |   3 +-
 .../Geometry/src/Instrument/CompAssembly.cpp  |  35 ++-
 .../Geometry/src/Instrument/Component.cpp     |  32 +-
 .../Geometry/src/Instrument/Instrument.cpp    |   1 +
 .../src/Instrument/RectangularDetector.cpp    | 119 ++++++--
 .../Geometry/src/InstrumentRayTracer.cpp      |  64 ++--
 .../Framework/Geometry/src/Math/Matrix.cpp    |  21 +-
 .../Framework/Geometry/src/Objects/Track.cpp  |   2 +-
 Code/Mantid/Framework/Geometry/src/V3D.cpp    |  10 +
 .../Framework/Geometry/test/ComponentTest.h   |  15 +
 .../Geometry/test/InstrumentRayTracerTest.h   | 161 +++++++++-
 .../Framework/Geometry/test/MatrixTest.h      |  10 +
 .../Geometry/test/RectangularDetectorTest.h   |   1 +
 Code/Mantid/Framework/Geometry/test/V3DTest.h |  14 +-
 Code/Mantid/Framework/ICat/CMakeLists.txt     |   2 +-
 Code/Mantid/Framework/Kernel/CMakeLists.txt   |   2 +-
 .../Framework/Kernel/inc/MantidKernel/Utils.h |   2 +-
 .../Framework/Kernel/src/ConfigService.cpp    |   8 +-
 .../Framework/MDAlgorithms/CMakeLists.txt     |   2 +-
 .../Framework/MDDataObjects/CMakeLists.txt    |   2 +-
 Code/Mantid/Framework/MDEvents/CMakeLists.txt |   2 +-
 .../inc/MantidMDEvents/BoxController.h        |   2 +
 .../MDEvents/inc/MantidMDEvents/IMDBox.h      |  20 +-
 .../MDEvents/inc/MantidMDEvents/MDBox.h       |   2 +
 .../inc/MantidMDEvents/MDEWPeakIntegration.h  |  13 +-
 .../MDEvents/inc/MantidMDEvents/MDEvent.h     |   9 +
 .../inc/MantidMDEvents/MDEventFactory.h       |  16 +-
 .../inc/MantidMDEvents/MDEventWorkspace.h     |  23 +-
 .../MDEvents/inc/MantidMDEvents/MDGridBox.h   |   6 +
 .../MDEvents/inc/MantidMDEvents/MDSplitBox.h  |   2 +
 .../MDEvents/src/FakeMDEventData.cpp          |   4 +-
 Code/Mantid/Framework/MDEvents/src/MDBox.cpp  |  40 ++-
 .../MDEvents/src/MDEWPeakIntegration.cpp      |  56 +++-
 .../MDEvents/src/MDEventWorkspace.cpp         | 226 --------------
 .../Framework/MDEvents/src/MDGridBox.cpp      | 156 ++++++++++
 .../MDEvents/test/BoxControllerTest.h         |  42 ++-
 .../Framework/MDEvents/test/IMDBoxTest.h      |  18 +-
 .../Framework/MDEvents/test/MDBoxTest.h       |  44 +++
 .../MDEvents/test/MDEWPeakIntegrationTest.h   |  10 +-
 .../Framework/MDEvents/test/MDEventTest.h     |   3 +
 .../MDEvents/test/MDEventWorkspaceTest.h      |  40 ++-
 .../MDEvents/test/MDEventsTestHelper.hh       |   2 +-
 .../Framework/MDEvents/test/MDGridBoxTest.h   | 217 +++++++++++--
 Code/Mantid/Framework/Nexus/CMakeLists.txt    |   2 +-
 .../Mantid/Framework/PythonAPI/CMakeLists.txt |   2 +-
 .../Framework/PythonAPI/MantidFramework.py    |  12 +-
 .../Framework/PythonAPI/src/api_exports.cpp   |   8 +
 .../src/ComponentCreationHelper.cpp           |  15 +-
 .../src/WorkspaceCreationHelper.cpp           |   7 +-
 .../Framework/UserAlgorithms/CMakeLists.txt   |   2 +-
 .../Mantid/MantidPlot/src/Mantid/MantidUI.cpp |  32 --
 Code/Mantid/MantidPlot/src/Mantid/MantidUI.h  |   1 -
 Code/Mantid/MantidPlot/src/qti.sip            |   1 -
 .../MantidQt/CustomDialogs/CMakeLists.txt     |   2 +-
 .../MantidQt/CustomInterfaces/CMakeLists.txt  |   2 +-
 .../MantidQt/DesignerPlugins/CMakeLists.txt   |   2 +-
 Code/Mantid/Vates/VatesAPI/CMakeLists.txt     |   2 +-
 .../VatesAPI/test/vtkDataSetFactoryTest.h     |   2 +-
 94 files changed, 2127 insertions(+), 551 deletions(-)
 create mode 100644 Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/CreateGroupingWorkspace.h
 create mode 100644 Code/Mantid/Framework/Algorithms/src/CreateGroupingWorkspace.cpp
 create mode 100644 Code/Mantid/Framework/Algorithms/test/CreateGroupingWorkspaceTest.h
 create mode 100644 Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/GroupingWorkspace.h
 create mode 100644 Code/Mantid/Framework/DataObjects/src/GroupingWorkspace.cpp
 create mode 100644 Code/Mantid/Framework/DataObjects/test/GroupingWorkspaceTest.h

diff --git a/Code/Mantid/Framework/API/CMakeLists.txt b/Code/Mantid/Framework/API/CMakeLists.txt
index 9cfbdc62f96..11ecaf3c3b9 100644
--- a/Code/Mantid/Framework/API/CMakeLists.txt
+++ b/Code/Mantid/Framework/API/CMakeLists.txt
@@ -216,7 +216,7 @@ set ( GMOCK_TEST_FILES
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(API SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(API SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Have to link to winsock library on Windows
diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/MatrixWorkspace.h b/Code/Mantid/Framework/API/inc/MantidAPI/MatrixWorkspace.h
index 51b6d69226f..21896827209 100644
--- a/Code/Mantid/Framework/API/inc/MantidAPI/MatrixWorkspace.h
+++ b/Code/Mantid/Framework/API/inc/MantidAPI/MatrixWorkspace.h
@@ -78,6 +78,7 @@ namespace Mantid
 
       // The Workspace Factory create-from-parent method needs direct access to the axes.
       friend class WorkspaceFactoryImpl;
+
       /// Typedef for the workspace_iterator to use with a Workspace
       typedef workspace_iterator<LocatedDataRef, MatrixWorkspace> iterator;
       /// Typedef for the const workspace_iterator to use with a Workspace
@@ -301,12 +302,14 @@ namespace Mantid
 
       /// The instrument used for this experiment
       boost::shared_ptr<Geometry::Instrument> sptr_instrument;
+
+    protected:
       /// The SpectraDetector table used for this experiment. Inside a copy-on-write pointer.
       Kernel::cow_ptr<SpectraDetectorMap> m_spectramap;
+
       /// The information on the sample environment
       Kernel::cow_ptr<Sample> m_sample;
 
-    protected:
       /// The run information
       Kernel::cow_ptr<Run> m_run;
 
diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/SpectraDetectorMap.h b/Code/Mantid/Framework/API/inc/MantidAPI/SpectraDetectorMap.h
index 267566e0cda..5f294fa7b07 100644
--- a/Code/Mantid/Framework/API/inc/MantidAPI/SpectraDetectorMap.h
+++ b/Code/Mantid/Framework/API/inc/MantidAPI/SpectraDetectorMap.h
@@ -97,8 +97,6 @@ public:
 private:
   /// Copy Contructor
   SpectraDetectorMap(const SpectraDetectorMap& copy);
-  /// Assignment operator
-  SpectraDetectorMap& operator=(const SpectraDetectorMap& rhs);
   /// internal spectra detector map instance
   smap m_s2dmap;
 
diff --git a/Code/Mantid/Framework/API/src/SpectraDetectorMap.cpp b/Code/Mantid/Framework/API/src/SpectraDetectorMap.cpp
index 323a5e8dfd2..f5c5db5191e 100644
--- a/Code/Mantid/Framework/API/src/SpectraDetectorMap.cpp
+++ b/Code/Mantid/Framework/API/src/SpectraDetectorMap.cpp
@@ -19,6 +19,14 @@ namespace Mantid
     SpectraDetectorMap::~SpectraDetectorMap()
     {}
 
+
+    //------------------------------------------------------------------------------------------------
+    /** Populate the map with 2 arrays; one detector per spectrum
+     *
+     * @param _spectable :: bare vector of the spectrum numbers
+     * @param _udettable :: bare vector of the detector ids (same length as spectable)
+     * @param nentries :: number of entries in the vectors
+     */
     void SpectraDetectorMap::populate(const int* _spectable, const int* _udettable, int nentries)
     {
       m_s2dmap.clear();
@@ -38,6 +46,12 @@ namespace Mantid
       return;
     }
 
+    //------------------------------------------------------------------------------------------------
+    /** Populate a simple spectrum-to-detector map, with a 1:1 correspondence
+     *
+     * @param start :: first spectrum number
+     * @param end :: last spectrum number (not inclusive)
+     */
     void SpectraDetectorMap::populateSimple(const int start, const int end)
     {
       m_s2dmap.clear();
@@ -55,11 +69,11 @@ namespace Mantid
     }
 
 
+    //------------------------------------------------------------------------------------------------
     /** Fill the SpectraDetectorMap with a simple list of pixel ids,
      * where the nth entry in the vector has a single detector, specified
      * by the value at that entry in the vector.
      * @param  udetList list of ints where the index = spectrum number; value = pixel ID.
-
      */
     void SpectraDetectorMap::populateWithVector(const std::vector<int>& udetList)
     {
@@ -69,6 +83,7 @@ namespace Mantid
       }
     }
 
+    //------------------------------------------------------------------------------------------------
     /** Links a list of UDETs to the given spectrum.
      *  THIS METHOD SHOULD BE USED WITH CARE - IT CAN LEAD TO AN INCONSISTENT MAP
      *  @param spectrum :: The spectrum number to which detectors should be added
@@ -84,6 +99,7 @@ namespace Mantid
     }
     
 
+    //------------------------------------------------------------------------------------------------
     /** Links a SET of detector IDs to the given spectrum.
      *  THIS METHOD SHOULD BE USED WITH CARE - IT CAN LEAD TO AN INCONSISTENT MAP
      *  @param spectrum :: The spectrum number to which detectors should be added
@@ -98,6 +114,7 @@ namespace Mantid
       }
     }
 
+    //------------------------------------------------------------------------------------------------
     /** Moves all detectors assigned to a particular spectrum number to a different one.
      *  Does nothing if the oldSpectrum number does not exist in the map.
      *  @param oldSpectrum :: The spectrum number to be removed and have its detectors reassigned
@@ -126,17 +143,22 @@ namespace Mantid
       m_s2dmap.erase(oldSpectrum);
     }
 
+    //------------------------------------------------------------------------------------------------
     /// Empties the map - use with care!
     void SpectraDetectorMap::clear()
     {
       m_s2dmap.clear();
     }
     
+    //------------------------------------------------------------------------------------------------
+    /** Return the number of detectors for the given spectrum number
+     * @param spectrum_number :: which spectrum number */
     int SpectraDetectorMap::ndet(const int spectrum_number) const
     {
       return m_s2dmap.count(spectrum_number);
     }
 
+    //------------------------------------------------------------------------------------------------
     /** Get a vector of detectors ids contributing to a spectrum
      * @param spectrum_number :: The # of the spectrum you are looking for.
      * @return list of detector ids in map
@@ -159,6 +181,7 @@ namespace Mantid
       return detectors;
     }
 
+    //------------------------------------------------------------------------------------------------
     /** Gets a list of spectra corresponding to a list of detector numbers.
     *  @param detectorList :: A list of detector Ids
     *  @return A vector where matching indices correspond to the relevant spectra id
@@ -194,6 +217,7 @@ namespace Mantid
       return spectraList;
     }
 
+    //------------------------------------------------------------------------------------------------
     /** Tests whether the present map matches another
      *  @param  other The other map against which to test
      *  @return True if the maps match
@@ -203,6 +227,7 @@ namespace Mantid
       return ( m_s2dmap == other.m_s2dmap );
     }
 
+    //------------------------------------------------------------------------------------------------
     /** Tests whether the present map does not match another
      *  @param  other The other map against which to test
      *  @return True if the maps do not match
diff --git a/Code/Mantid/Framework/Algorithms/CMakeLists.txt b/Code/Mantid/Framework/Algorithms/CMakeLists.txt
index 28c4dd06f64..a5632b0d816 100644
--- a/Code/Mantid/Framework/Algorithms/CMakeLists.txt
+++ b/Code/Mantid/Framework/Algorithms/CMakeLists.txt
@@ -27,6 +27,7 @@ set ( SRC_FILES
 	src/CorrectToFile.cpp
 	src/CreateCalFileByNames.cpp
 	src/CreateDummyCalFile.cpp
+	src/CreateGroupingWorkspace.cpp
 	src/CreatePSDBleedMask.cpp
 	src/CreatePeaksWorkspace.cpp
 	src/CreateSingleValuedWorkspace.cpp
@@ -174,6 +175,7 @@ set ( INC_FILES
 	inc/MantidAlgorithms/CorrectToFile.h
 	inc/MantidAlgorithms/CreateCalFileByNames.h
 	inc/MantidAlgorithms/CreateDummyCalFile.h
+	inc/MantidAlgorithms/CreateGroupingWorkspace.h
 	inc/MantidAlgorithms/CreatePSDBleedMask.h
 	inc/MantidAlgorithms/CreatePeaksWorkspace.h
 	inc/MantidAlgorithms/CreateSingleValuedWorkspace.h
@@ -322,6 +324,7 @@ set ( TEST_FILES
 	test/CorrectToFileTest.h
 	test/CreateCalFileByNamesTest.h
 	test/CreateDummyCalFileTest.h
+	test/CreateGroupingWorkspaceTest.h
 	test/CreatePSDBleedMaskTest.h
 	test/CreatePeaksWorkspaceTest.h
 	test/CreateSingleValuedWorkspaceTest.h
@@ -434,7 +437,7 @@ set(SRC_UNITY_IGNORE_FILES src/AlignDetectors.cpp
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(Algorithms SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(Algorithms SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Add the target for this directory
diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/CreateGroupingWorkspace.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/CreateGroupingWorkspace.h
new file mode 100644
index 00000000000..b89baaee5a2
--- /dev/null
+++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/CreateGroupingWorkspace.h
@@ -0,0 +1,50 @@
+#ifndef MANTID_ALGORITHMS_CREATEGROUPINGWORKSPACE_H_
+#define MANTID_ALGORITHMS_CREATEGROUPINGWORKSPACE_H_
+    
+#include "MantidKernel/System.h"
+#include "MantidAPI/Algorithm.h" 
+
+namespace Mantid
+{
+namespace Algorithms
+{
+
+  /** Creates a new GroupingWorkspace using an instrument from one of:
+   *  an input workspace,
+   *  an instrument name,
+   *  or an instrument IDF file.
+   *
+   *  Optionally uses bank names to create the groups.");
+   * 
+   * @author Janik Zikovsky
+   * @date 2011-05-02
+   */
+  class DLLExport CreateGroupingWorkspace  : public API::Algorithm
+  {
+  public:
+    CreateGroupingWorkspace();
+    ~CreateGroupingWorkspace();
+    
+    /// Algorithm's name for identification 
+    virtual const std::string name() const { return "CreateGroupingWorkspace";};
+    /// Algorithm's version for identification 
+    virtual int version() const { return 1;};
+    /// Algorithm's category for identification
+    virtual const std::string category() const { return "General";}
+    
+  private:
+    /// Sets documentation strings for this algorithm
+    virtual void initDocs();
+    /// Initialise the properties
+    void init();
+    /// Run the algorithm
+    void exec();
+
+
+  };
+
+
+} // namespace Mantid
+} // namespace Algorithms
+
+#endif  /* MANTID_ALGORITHMS_CREATEGROUPINGWORKSPACE_H_ */
diff --git a/Code/Mantid/Framework/Algorithms/src/CreateGroupingWorkspace.cpp b/Code/Mantid/Framework/Algorithms/src/CreateGroupingWorkspace.cpp
new file mode 100644
index 00000000000..61a3e897eb2
--- /dev/null
+++ b/Code/Mantid/Framework/Algorithms/src/CreateGroupingWorkspace.cpp
@@ -0,0 +1,285 @@
+#include "MantidAlgorithms/CreateGroupingWorkspace.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidDataObjects/GroupingWorkspace.h"
+#include "MantidGeometry/IDetector.h"
+#include "MantidKernel/Strings.h"
+#include "MantidKernel/System.h"
+#include <boost/algorithm/string/detail/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <queue>
+#include <fstream>
+#include "MantidAPI/FileProperty.h"
+
+namespace Mantid
+{
+namespace Algorithms
+{
+
+  // Register the algorithm into the AlgorithmFactory
+  DECLARE_ALGORITHM(CreateGroupingWorkspace)
+  
+  using namespace Mantid::Kernel;
+  using namespace Mantid::API;
+  using namespace Mantid::Geometry;
+  using namespace Mantid::DataObjects;
+
+
+  //----------------------------------------------------------------------------------------------
+  /** Constructor
+   */
+  CreateGroupingWorkspace::CreateGroupingWorkspace()
+  {
+  }
+    
+  //----------------------------------------------------------------------------------------------
+  /** Destructor
+   */
+  CreateGroupingWorkspace::~CreateGroupingWorkspace()
+  {
+  }
+  
+
+  //----------------------------------------------------------------------------------------------
+  /// Sets documentation strings for this algorithm
+  void CreateGroupingWorkspace::initDocs()
+  {
+    this->setWikiSummary("Creates a new GroupingWorkspace using an instrument from one of: an input workspace, an instrument name, or an instrument IDF file.\nOptionally uses bank names to create the groups.");
+    this->setOptionalMessage("Creates a new GroupingWorkspace using an instrument from one of: an input workspace, an instrument name, or an instrument IDF file.\Optionally uses bank names to create the groups.");
+  }
+
+  //----------------------------------------------------------------------------------------------
+  /** Initialize the algorithm's properties.
+   */
+  void CreateGroupingWorkspace::init()
+  {
+    declareProperty(new WorkspaceProperty<>("InputWorkspace","",Direction::Input, true),
+        "Optional: An input workspace with the instrument we want to use.");
+
+    declareProperty(new PropertyWithValue<std::string>("InstrumentName","",Direction::Input),
+        "Optional: Name of the instrument to base the GroupingWorkspace on which to base the GroupingWorkspace.");
+
+    declareProperty(new FileProperty("InstrumentFilename", "", FileProperty::OptionalLoad, ".xml"),
+        "Optional: Path to the instrument definition file on which to base the GroupingWorkspace.");
+
+    declareProperty(new FileProperty("OldCalFilename", "", FileProperty::OptionalLoad, ".cal"),
+        "Optional: Path to the old-style .cal grouping/calibration file (multi-column ASCII). You must also specify the instrument.");
+
+    declareProperty("GroupNames","",
+      "Optional: A string of the instrument component names to use as separate groups.\n"
+      "Use / or , to separate multiple groups.\n"
+      "If empty, then an empty GroupingWorkspace will be created.");
+
+    declareProperty(new WorkspaceProperty<GroupingWorkspace>("OutputWorkspace","",Direction::Output),
+        "An output GroupingWorkspace.");
+  }
+
+
+  //------------------------------------------------------------------------------------------------
+  /** Read old-style .cal file to get the grouping
+   *
+   * @param groupingFileName :: path to .cal multi-col ascii
+   * @param detIDtoGroup :: map of key=detectorID, value=group number.
+   * @param prog :: progress reporter
+   */
+  void readGroupingFile(const std::string& groupingFileName, IndexToIndexMap & detIDtoGroup, Progress & prog )
+  {
+    std::ifstream grFile(groupingFileName.c_str());
+    if (!grFile.is_open())
+    {
+      throw Exception::FileError("Error reading .cal file",groupingFileName);
+    }
+    detIDtoGroup.clear();
+    std::string str;
+    while(getline(grFile,str))
+    {
+      //Comment
+      if (str.empty() || str[0] == '#') continue;
+      std::istringstream istr(str);
+      int n,udet,sel,group;
+      double offset;
+      istr >> n >> udet >> offset >> sel >> group;
+      if ((sel) && (group>0))
+      {
+        detIDtoGroup[udet]=group; //Register this detector id
+      }
+      prog.report();
+    }
+    grFile.close();
+    return;
+  }
+
+
+  //------------------------------------------------------------------------------------------------
+  /** Use bank names to build grouping
+   *
+   * @param GroupNames :: comma-sep list of bank names
+   * @param inst :: instrument
+   * @param detIDtoGroup :: output: map of detID: to group number
+   * @param prog :: progress report
+   */
+  void makeGroupingByNames(std::string GroupNames, IInstrument_sptr inst, IndexToIndexMap & detIDtoGroup, Progress & prog)
+  {
+    // Split the names of the group and insert in a vector
+    std::vector<std::string> vgroups;
+    boost::split( vgroups, GroupNames, boost::algorithm::detail::is_any_ofF<char>(",/*"));
+
+    // Assign incremental number to each group
+    std::map<std::string,int> group_map;
+    int index=0;
+    for (std::vector<std::string>::const_iterator it=vgroups.begin();it!=vgroups.end();it++)
+      group_map[(*it)]=++index;
+
+    // Find Detectors that belong to groups
+    if (group_map.size() > 0)
+    {
+      // Find Detectors that belong to groups
+      typedef boost::shared_ptr<Geometry::ICompAssembly> sptr_ICompAss;
+      typedef boost::shared_ptr<Geometry::IComponent> sptr_IComp;
+      typedef boost::shared_ptr<Geometry::IDetector> sptr_IDet;
+      std::queue< std::pair<sptr_ICompAss,int> > assemblies;
+      sptr_ICompAss current=boost::dynamic_pointer_cast<Geometry::ICompAssembly>(inst);
+      sptr_IDet currentDet;
+      sptr_IComp currentIComp;
+      sptr_ICompAss currentchild;
+
+      int top_group, child_group;
+
+      if (current.get())
+      {
+        top_group=group_map[current->getName()]; // Return 0 if not in map
+        assemblies.push(std::make_pair<sptr_ICompAss,int>(current,top_group));
+      }
+
+      prog.setNumSteps( int(assemblies.size()) );
+
+      while(!assemblies.empty()) //Travel the tree from the instrument point
+      {
+        current=assemblies.front().first;
+        top_group=assemblies.front().second;
+        assemblies.pop();
+        int nchilds=current->nelements();
+        if (nchilds!=0)
+        {
+          for (int i=0;i<nchilds;++i)
+          {
+            currentIComp=(*(current.get()))[i]; // Get child
+            currentDet=boost::dynamic_pointer_cast<Geometry::IDetector>(currentIComp);
+            if (currentDet.get())// Is detector
+            {
+              if (top_group > 0)
+              {
+                detIDtoGroup[currentDet->getID()] = top_group;
+              }
+            }
+            else // Is an assembly, push in the queue
+            {
+              currentchild=boost::dynamic_pointer_cast<Geometry::ICompAssembly>(currentIComp);
+              if (currentchild.get())
+              {
+                child_group=group_map[currentchild->getName()];
+                if (child_group==0)
+                  child_group=top_group;
+                assemblies.push(std::make_pair<sptr_ICompAss,int>(currentchild,child_group));
+              }
+            }
+          }
+        }
+        prog.report();
+      }
+
+      return;
+    }
+  }
+
+
+
+  //----------------------------------------------------------------------------------------------
+  /** Execute the algorithm.
+   */
+  void CreateGroupingWorkspace::exec()
+  {
+    std::string InputWorkspace = getPropertyValue("InputWorkspace");
+    std::string InstrumentName = getPropertyValue("InstrumentName");
+    std::string InstrumentFilename = getPropertyValue("InstrumentFilename");
+    std::string OldCalFilename = getPropertyValue("OldCalFilename");
+    std::string GroupNames = getPropertyValue("GroupNames");
+
+    // Some validation
+    int numParams = 0;
+    if (!InputWorkspace.empty()) numParams++;
+    if (!InstrumentName.empty()) numParams++;
+    if (!InstrumentFilename.empty()) numParams++;
+
+    if (numParams != 1)
+      throw std::invalid_argument("You must specify exactly ONE way to get an instrument (workspace, instrument name, or IDF file).");
+
+    if (!OldCalFilename.empty() && !GroupNames.empty())
+      throw std::invalid_argument("You must specify either to use the OldCalFilename parameter OR GroupNames but not both!");
+
+    // ---------- Get the instrument one of 3 ways ---------------------------
+    IInstrument_sptr inst;
+    if (!InputWorkspace.empty())
+    {
+      MatrixWorkspace_sptr inWS = getProperty("InputWorkspace");
+      inst = inWS->getInstrument();
+    }
+    else
+    {
+      Algorithm_sptr childAlg = createSubAlgorithm("LoadInstrument",0.0,0.2);
+      MatrixWorkspace_sptr tempWS(new Workspace2D());
+      childAlg->setProperty<MatrixWorkspace_sptr>("Workspace", tempWS);
+      childAlg->setPropertyValue("Filename", InstrumentFilename);
+      childAlg->setPropertyValue("InstrumentName", InstrumentName);
+      childAlg->executeAsSubAlg();
+      inst = tempWS->getInstrument();
+    }
+
+
+    // --------------------------- Create the output --------------------------
+    GroupingWorkspace_sptr outWS(new GroupingWorkspace(inst));
+    this->setProperty("OutputWorkspace", outWS);
+
+    // This will get the grouping
+    IndexToIndexMap detIDtoGroup;
+
+    Progress prog(this,0.2,1.0, outWS->getNumberHistograms() );
+
+    // Make the grouping one of two ways:
+    if (GroupNames != "")
+      makeGroupingByNames(GroupNames, inst, detIDtoGroup, prog);
+    else if (OldCalFilename != "")
+      readGroupingFile(OldCalFilename, detIDtoGroup, prog);
+
+    if (detIDtoGroup.size() != 0)
+    {
+      // Make the groups, if any
+      // To put a detector ID with a workspace index
+      IndexToIndexMap * detID_to_WI_ptr = outWS->getDetectorIDToWorkspaceIndexMap(true);
+      IndexToIndexMap & detID_to_WI = *detID_to_WI_ptr;
+
+      // Now go through the map of results and put them in the workspace
+      IndexToIndexMap::const_iterator it_end = detIDtoGroup.end();
+      IndexToIndexMap::const_iterator it2_end = detID_to_WI.end();
+      for (IndexToIndexMap::const_iterator it = detIDtoGroup.begin(); it != it_end; ++it)
+      {
+        int detID = it->first;
+        int group = it->second;
+        IndexToIndexMap::const_iterator it2 = detID_to_WI.find(detID);
+        if (it2 != it2_end)
+        {
+          int wi = it2->second;
+          outWS->dataY(wi)[0] = double(group);
+        }
+      }
+
+      delete detID_to_WI_ptr;
+    }
+
+  }
+
+
+
+
+} // namespace Mantid
+} // namespace Algorithms
+
diff --git a/Code/Mantid/Framework/Algorithms/src/DiffractionEventCalibrateDetectors.cpp b/Code/Mantid/Framework/Algorithms/src/DiffractionEventCalibrateDetectors.cpp
index 388f7749210..7acaecb06c8 100644
--- a/Code/Mantid/Framework/Algorithms/src/DiffractionEventCalibrateDetectors.cpp
+++ b/Code/Mantid/Framework/Algorithms/src/DiffractionEventCalibrateDetectors.cpp
@@ -2,22 +2,23 @@
 // Includes
 //----------------------------------------------------------------------
 #include "MantidAlgorithms/DiffractionEventCalibrateDetectors.h"
-#include "MantidGeometry/Instrument/RectangularDetector.h"
-#include "MantidAPI/TableRow.h"
-#include "MantidDataObjects/Workspace2D.h"
-#include "MantidDataObjects/EventWorkspace.h"
-#include "MantidDataObjects/EventList.h"
 #include "MantidAlgorithms/GSLFunctions.h"
+#include "MantidAPI/FileProperty.h"
+#include "MantidAPI/TableRow.h"
 #include "MantidAPI/TextAxis.h"
-#include "MantidKernel/UnitFactory.h"
+#include "MantidDataObjects/EventList.h"
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidGeometry/Instrument/RectangularDetector.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/CPUTimer.h"
 #include "MantidKernel/Exception.h"
-#include "MantidAPI/FileProperty.h"
-#include <Poco/File.h>
-#include <sstream>
-#include <numeric>
+#include "MantidKernel/UnitFactory.h"
 #include <cmath>
 #include <iomanip>
+#include <numeric>
+#include <Poco/File.h>
+#include <sstream>
 
 namespace Mantid
 {
@@ -110,6 +111,7 @@ namespace Algorithms
       throw std::runtime_error("Error while executing MoveInstrumentComponent as a sub algorithm.");
     }
 
+
     IAlgorithm_sptr algx = createSubAlgorithm("RotateInstrumentComponent");
     algx->setProperty<MatrixWorkspace_sptr>("Workspace", inputW);
     algx->setPropertyValue("ComponentName", detname);
@@ -128,6 +130,7 @@ namespace Algorithms
       throw std::runtime_error("Error while executing RotateInstrumentComponent as a sub algorithm.");
     }
 
+
     IAlgorithm_sptr algy = createSubAlgorithm("RotateInstrumentComponent");
     algy->setProperty<MatrixWorkspace_sptr>("Workspace", inputW);
     algy->setPropertyValue("ComponentName", detname);
@@ -185,6 +188,9 @@ namespace Algorithms
     MatrixWorkspace_sptr inputW = boost::dynamic_pointer_cast<MatrixWorkspace>
             (AnalysisDataService::Instance().retrieve(inname));
 
+    bool debug = true;
+    CPUTimer tim;
+
     movedetector(x, y, z, rotx, roty, rotz, detname, inputW);
     IAlgorithm_sptr alg2 = createSubAlgorithm("CreateCalFileByNames");
     alg2->setProperty<MatrixWorkspace_sptr>("InstrumentWorkspace", inputW);
@@ -202,6 +208,8 @@ namespace Algorithms
       throw std::runtime_error("Error while executing CreateCalFileByNames as a sub algorithm.");
     }
 
+    if (debug) std::cout << tim << " to CreateCalFileByNames" << std::endl;
+
     IAlgorithm_sptr alg3 = createSubAlgorithm("ConvertUnits");
     alg3->setProperty<MatrixWorkspace_sptr>("InputWorkspace", inputW);
     alg3->setPropertyValue("OutputWorkspace", outname);
@@ -218,6 +226,8 @@ namespace Algorithms
     }
     MatrixWorkspace_sptr outputW=alg3->getProperty("OutputWorkspace");
 
+    if (debug) std::cout << tim << " to ConvertUnits" << std::endl;
+
     IAlgorithm_sptr alg4 = createSubAlgorithm("DiffractionFocussing");
     alg4->setProperty<MatrixWorkspace_sptr>("InputWorkspace", outputW);
     alg4->setProperty<MatrixWorkspace_sptr>("OutputWorkspace", outputW);
@@ -233,7 +243,10 @@ namespace Algorithms
     }
     outputW=alg4->getProperty("OutputWorkspace");
     //Remove file
-    Poco::File(outputFile).remove();
+    if (Poco::File(outputFile).exists())
+      Poco::File(outputFile).remove();
+
+    if (debug) std::cout << tim << " to DiffractionFocussing" << std::endl;
 
     IAlgorithm_sptr alg5 = createSubAlgorithm("Rebin");
     alg5->setProperty<MatrixWorkspace_sptr>("InputWorkspace", outputW);
@@ -250,6 +263,7 @@ namespace Algorithms
     }
     outputW=alg5->getProperty("OutputWorkspace");
 
+    if (debug) std::cout << tim << " to Rebin" << std::endl;
 
   // Find point of peak centre
     const MantidVec & yValues = outputW->readY(0);
@@ -294,12 +308,16 @@ namespace Algorithms
       throw std::runtime_error("Unable to successfully run Fit sub-algorithm");
     }
 
+    if (debug) std::cout << tim << " to Fit" << std::endl;
+
     std::vector<double> params = fit_alg->getProperty("Parameters");
     peakHeight = params[0];
     peakLoc = params[1];
 
     movedetector(-x, -y, -z, -rotx, -roty, -rotz, detname, inputW);
 
+    if (debug) std::cout << tim << " to movedetector()" << std::endl;
+
     //Optimize C/peakheight + |peakLoc-peakOpt|  where C is scaled by number of events
     EventWorkspace_const_sptr inputE = boost::dynamic_pointer_cast<const EventWorkspace>( inputW );
     return (inputE->getNumberEvents()/1.e6)/peakHeight+std::fabs(peakLoc-boost::lexical_cast<double>(peakOpt));
diff --git a/Code/Mantid/Framework/Algorithms/test/CreateGroupingWorkspaceTest.h b/Code/Mantid/Framework/Algorithms/test/CreateGroupingWorkspaceTest.h
new file mode 100644
index 00000000000..d1863e4da4f
--- /dev/null
+++ b/Code/Mantid/Framework/Algorithms/test/CreateGroupingWorkspaceTest.h
@@ -0,0 +1,198 @@
+#ifndef MANTID_ALGORITHMS_CREATEGROUPINGWORKSPACETEST_H_
+#define MANTID_ALGORITHMS_CREATEGROUPINGWORKSPACETEST_H_
+
+#include "MantidAlgorithms/CreateGroupingWorkspace.h"
+#include "MantidDataObjects/GroupingWorkspace.h"
+#include "MantidKernel/System.h"
+#include "MantidKernel/Timer.h"
+#include "MantidTestHelpers/AlgorithmHelper.h"
+#include <cxxtest/TestSuite.h>
+#include <iomanip>
+#include <iostream>
+
+using namespace Mantid::Algorithms;
+using namespace Mantid::API;
+using namespace Mantid::DataObjects;
+
+class CreateGroupingWorkspaceTest : public CxxTest::TestSuite
+{
+public:
+
+    
+  void test_Init()
+  {
+    CreateGroupingWorkspace alg;
+    TS_ASSERT_THROWS_NOTHING( alg.initialize() )
+    TS_ASSERT( alg.isInitialized() )
+  }
+  
+  void doTest(std::string outWSName)
+  {
+
+    // Retrieve the workspace from data service.
+    GroupingWorkspace_sptr ws;
+    TS_ASSERT_THROWS_NOTHING( ws = boost::dynamic_pointer_cast<GroupingWorkspace>(AnalysisDataService::Instance().retrieve(outWSName)) );
+    TS_ASSERT(ws);
+    if (!ws) return;
+
+    TS_ASSERT_EQUALS( ws->getNumberHistograms(), 24794);
+    TS_ASSERT_EQUALS( ws->blocksize(), 1);
+    // All zero.
+    TS_ASSERT_EQUALS( ws->dataY(0)[0], 0.0);
+    TS_ASSERT_EQUALS( ws->dataY(100)[0], 0.0);
+    TS_ASSERT_EQUALS( ws->dataY(10000)[0], 0.0);
+
+    // Remove workspace from the data service.
+    AnalysisDataService::Instance().remove(outWSName);
+  }
+
+  
+  void test_exec_withInstrumentName()
+  {
+    // Name of the output workspace.
+    std::string outWSName("CreateGroupingWorkspaceTest_OutputWS");
+    CreateGroupingWorkspace alg;
+    TS_ASSERT_THROWS_NOTHING( alg.initialize() )
+    TS_ASSERT( alg.isInitialized() )
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("InstrumentName", "POWGEN") );
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("OutputWorkspace", outWSName) );
+    TS_ASSERT_THROWS_NOTHING( alg.execute(); );
+    TS_ASSERT( alg.isExecuted() );
+    doTest(outWSName);
+  }
+
+
+  void test_exec_withInstrumentFileName()
+  {
+    // Name of the output workspace.
+    std::string outWSName("CreateGroupingWorkspaceTest_OutputWS");
+    CreateGroupingWorkspace alg;
+    TS_ASSERT_THROWS_NOTHING( alg.initialize() )
+    TS_ASSERT( alg.isInitialized() )
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("InstrumentFilename", "POWGEN_Definition_2011-02-25.xml") );
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("OutputWorkspace", outWSName) );
+    TS_ASSERT_THROWS_NOTHING( alg.execute(); );
+    TS_ASSERT( alg.isExecuted() );
+    doTest(outWSName);
+  }
+  
+
+
+  void test_exec_WithBankNames()
+  {
+    // Name of the output workspace.
+    std::string outWSName("CreateGroupingWorkspaceTest_OutputWS");
+
+    CreateGroupingWorkspace alg;
+    TS_ASSERT_THROWS_NOTHING( alg.initialize() )
+    TS_ASSERT( alg.isInitialized() )
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("InstrumentFilename", "CNCS_Definition.xml") );
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("GroupNames", "bank1,bank2,bank3,bank4") );
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("OutputWorkspace", outWSName) );
+    TS_ASSERT_THROWS_NOTHING( alg.execute(); );
+    TS_ASSERT( alg.isExecuted() );
+
+    // Retrieve the workspace from data service.
+    GroupingWorkspace_sptr ws;
+    TS_ASSERT_THROWS_NOTHING( ws = boost::dynamic_pointer_cast<GroupingWorkspace>(AnalysisDataService::Instance().retrieve(outWSName)) );
+    TS_ASSERT(ws);
+    if (!ws) return;
+
+    TS_ASSERT_EQUALS( ws->getNumberHistograms(), 51200);
+    TS_ASSERT_EQUALS( ws->blocksize(), 1);
+    for (int i = 1; i <= 4; ++i)
+    {
+      TS_ASSERT_EQUALS( ws->dataY((i-1)*1024)[0], double(i)*1.0);
+      TS_ASSERT_EQUALS( ws->dataY((i-1)*1024 + 1023)[0], double(i)*1.0);
+    }
+    // The rest is zero
+    TS_ASSERT_EQUALS( ws->dataY(5*1024)[0], 0.0);
+
+    // Remove workspace from the data service.
+    AnalysisDataService::Instance().remove(outWSName);
+    AnalysisDataService::Instance().remove("CNCS_7860_event");
+  }
+
+  void test_exec_WithOldCalFile()
+  {
+    // Name of the output workspace.
+    std::string outWSName("CreateGroupingWorkspaceTest_OutputWS");
+
+    CreateGroupingWorkspace alg;
+    TS_ASSERT_THROWS_NOTHING( alg.initialize() )
+    TS_ASSERT( alg.isInitialized() )
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("InstrumentFilename", "POWGEN_Definition_2010.xml") );
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("OldCalFilename", "pg3_mantid_det.cal") );
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("OutputWorkspace", outWSName) );
+    TS_ASSERT_THROWS_NOTHING( alg.execute(); );
+    TS_ASSERT( alg.isExecuted() );
+
+    // Retrieve the workspace from data service.
+    GroupingWorkspace_sptr ws;
+    TS_ASSERT_THROWS_NOTHING( ws = boost::dynamic_pointer_cast<GroupingWorkspace>(AnalysisDataService::Instance().retrieve(outWSName)) );
+    TS_ASSERT(ws);
+    if (!ws) return;
+
+    AnalysisDataService::Instance().remove(outWSName);
+  }
+
+
+};
+
+
+/* Test the performance when creating groups with very large
+ * instruments, i.e. TOPAZ
+ */
+class CreateGroupingWorkspaceTestPerformance : public CxxTest::TestSuite
+{
+public:
+  std::string outWSName;
+
+  void setUp()
+  {
+    outWSName = "CreateGroupingWorkspaceTestPerformance_OutputWS";
+    // Load a small test file
+    AlgorithmHelper::runAlgorithm("LoadEmptyInstrument", 4,
+        "Filename", "TOPAZ_Definition_2010.xml",
+        "OutputWorkspace", "TOPAZ_2010");
+
+  }
+
+  void tearDown()
+  {
+    // Remove workspace from the data service.
+    AnalysisDataService::Instance().remove(outWSName);
+    AnalysisDataService::Instance().remove("TOPAZ_2010");
+  }
+
+  /* Test creating a grouping workspace with bank names */
+  void test_TOPAZ_2010()
+  {
+    CreateGroupingWorkspace alg;
+    TS_ASSERT_THROWS_NOTHING( alg.initialize() )
+    TS_ASSERT( alg.isInitialized() )
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("InputWorkspace", "TOPAZ_2010") );
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("GroupNames", "bank1,bank2,bank3,bank4,bank5,bank6,bank7,bank8,bank9,bank10,bank11,bank12,bank13,bank14,bank15") );
+    TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("OutputWorkspace", outWSName) );
+    TS_ASSERT_THROWS_NOTHING( alg.execute(); );
+    TS_ASSERT( alg.isExecuted() );
+
+    // Retrieve the workspace from data service.
+    GroupingWorkspace_sptr ws;
+    TS_ASSERT_THROWS_NOTHING( ws = boost::dynamic_pointer_cast<GroupingWorkspace>(AnalysisDataService::Instance().retrieve(outWSName)) );
+    TS_ASSERT(ws);
+    if (!ws) return;
+
+    TS_ASSERT_EQUALS( ws->getNumberHistograms(), 65536 * 15+1);
+    TS_ASSERT_EQUALS( ws->blocksize(), 1);
+    // Check one entry in each group
+    for (int i = 0; i < 15; ++i)
+    {
+      TS_ASSERT_EQUALS( ws->dataY(i*65536)[0], double(i)*1.0);
+    }
+  }
+
+};
+
+#endif /* MANTID_ALGORITHMS_CREATEGROUPINGWORKSPACETEST_H_ */
+
diff --git a/Code/Mantid/Framework/Crystal/CMakeLists.txt b/Code/Mantid/Framework/Crystal/CMakeLists.txt
index 562f8a06c3e..db45ce120f1 100644
--- a/Code/Mantid/Framework/Crystal/CMakeLists.txt
+++ b/Code/Mantid/Framework/Crystal/CMakeLists.txt
@@ -21,7 +21,7 @@ set ( TEST_FILES
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(Crystal SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(Crystal SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Add the target for this directory
diff --git a/Code/Mantid/Framework/Crystal/src/LoadPeaksFile.cpp b/Code/Mantid/Framework/Crystal/src/LoadPeaksFile.cpp
index ab4afb783a4..84ae3696976 100644
--- a/Code/Mantid/Framework/Crystal/src/LoadPeaksFile.cpp
+++ b/Code/Mantid/Framework/Crystal/src/LoadPeaksFile.cpp
@@ -1,7 +1,9 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidCrystal/LoadPeaksFile.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
+#include "MantidGeometry/Crystal/OrientedLattice.h"
 #include "MantidGeometry/IComponent.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidGeometry/Instrument/RectangularDetector.h"
 #include "MantidKernel/System.h"
 #include <algorithm>
@@ -352,6 +354,12 @@ namespace Crystal
     int run, bankNum;
     double chi , phi , omega , monCount;
 
+    // Build the universal goniometer that will build the rotation matrix.
+    Mantid::Geometry::Goniometer uniGonio;
+    uniGonio.pushAxis("phi",   0., 1., 0.,   0., Mantid::Geometry::CCW, Mantid::Geometry::angDegrees);
+    uniGonio.pushAxis("chi",   1., 0., 0.,   0., Mantid::Geometry::CCW, Mantid::Geometry::angDegrees);
+    uniGonio.pushAxis("omega", 0., 1., 0.,   0., Mantid::Geometry::CCW, Mantid::Geometry::angDegrees);
+
     while( in.good() )
     {
       // Read the header if necessary
@@ -369,13 +377,13 @@ namespace Crystal
         // Read the peak
         Peak peak = readPeak(outWS, s, in, seqNum, bankName);
 
-        // Convert to radians
-        chi *= M_PI/180;
-        phi *= M_PI/180;
-        omega *= M_PI/180;
+        // Build the Rotation matrix using phi,chi,omega
+        uniGonio.setRotationAngle(0, phi);
+        uniGonio.setRotationAngle(1, chi);
+        uniGonio.setRotationAngle(2, omega);
 
-        // TODO: Make the goniometer matrix using phi,chi,omega
-        Matrix<double> gonMat(3,3,true);
+        // Get the calculated goniometer matrix
+        Matrix<double> gonMat = uniGonio.getR();
 
         peak.setGoniometerMatrix(gonMat);
         peak.setRunNumber(run);
diff --git a/Code/Mantid/Framework/Crystal/test/LoadPeaksFileTest.h b/Code/Mantid/Framework/Crystal/test/LoadPeaksFileTest.h
index 5f9103d8f41..da938611ffa 100644
--- a/Code/Mantid/Framework/Crystal/test/LoadPeaksFileTest.h
+++ b/Code/Mantid/Framework/Crystal/test/LoadPeaksFileTest.h
@@ -1,21 +1,22 @@
 #ifndef MANTID_CRYSTAL_LOADPEAKSFILETEST_H_
 #define MANTID_CRYSTAL_LOADPEAKSFILETEST_H_
 
-#include <cxxtest/TestSuite.h>
-#include "MantidKernel/Timer.h"
-#include "MantidKernel/System.h"
 #include "MantidAPI/AnalysisDataService.h"
-#include "MantidDataObjects/PeaksWorkspace.h"
+#include "MantidCrystal/LoadPeaksFile.h"
 #include "MantidDataObjects/Peak.h"
-#include <iostream>
+#include "MantidDataObjects/PeaksWorkspace.h"
+#include "MantidGeometry/Math/Matrix.h"
+#include "MantidKernel/System.h"
+#include "MantidKernel/Timer.h"
+#include <cxxtest/TestSuite.h>
 #include <iomanip>
+#include <iostream>
 
-#include "MantidCrystal/LoadPeaksFile.h"
-
-using namespace Mantid::Kernel;
 using namespace Mantid::API;
-using namespace Mantid::DataObjects;
 using namespace Mantid::Crystal;
+using namespace Mantid::DataObjects;
+using namespace Mantid::Geometry;
+using namespace Mantid::Kernel;
 
 class LoadPeaksFileTest : public CxxTest::TestSuite
 {
@@ -72,7 +73,7 @@ public:
 
 
   /* Test for the newer TOPAZ geometry */
-  void xtest_exec_TOPAZ_2479()
+  void test_exec_TOPAZ_2479()
   {
     LoadPeaksFile alg;
     TS_ASSERT_THROWS_NOTHING( alg.initialize() )
@@ -107,10 +108,21 @@ public:
     TS_ASSERT_DELTA( p.getL2(), 0.461, 1e-3);
     TS_ASSERT_DELTA( p.getTOF(), 3560., 10.); // channel number is about TOF
 
-    // TODO: This does not match - needs the goniometer matrix set!
     TS_ASSERT_DELTA( p.getDSpacing(), 0.4723, 0.001);
     TS_ASSERT_DELTA( ws->getPeaks()[1].getDSpacing(), 0.6425, 0.001);
     TS_ASSERT_DELTA( ws->getPeaks()[2].getDSpacing(), 0.8138, 0.001);
+
+    // Now test the goniometer matrix
+    Matrix<double> r1(3,3,true);
+    // First peak has 0,0,0 angles so identity matrix
+    TS_ASSERT( p.getGoniometerMatrix().equals(r1, 1e-5) );
+
+    // Peak 3 is phi,chi,omega of 90,0,0; giving this matrix:
+    Matrix<double> r2(3,3,false);
+    r2[0][2] = 1;
+    r2[1][1] = 1;
+    r2[2][0] = -1;
+    TS_ASSERT( ws->getPeaks()[2].getGoniometerMatrix().equals(r2, 1e-5) );
   }
 
 
diff --git a/Code/Mantid/Framework/CurveFitting/CMakeLists.txt b/Code/Mantid/Framework/CurveFitting/CMakeLists.txt
index 5e23f6f7d0c..46874da01e8 100644
--- a/Code/Mantid/Framework/CurveFitting/CMakeLists.txt
+++ b/Code/Mantid/Framework/CurveFitting/CMakeLists.txt
@@ -111,7 +111,7 @@ set ( TEST_FILES
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(CurveFitting SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(CurveFitting SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Add the target for this directory
diff --git a/Code/Mantid/Framework/DataHandling/CMakeLists.txt b/Code/Mantid/Framework/DataHandling/CMakeLists.txt
index 38585acb931..34a7bd7e5c2 100644
--- a/Code/Mantid/Framework/DataHandling/CMakeLists.txt
+++ b/Code/Mantid/Framework/DataHandling/CMakeLists.txt
@@ -196,7 +196,7 @@ set ( TEST_FILES
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(CurveFitting SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(CurveFitting SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Add the target for this directory
diff --git a/Code/Mantid/Framework/DataHandling/src/LoadInstrument.cpp b/Code/Mantid/Framework/DataHandling/src/LoadInstrument.cpp
index 83e077b9529..be27fca7751 100644
--- a/Code/Mantid/Framework/DataHandling/src/LoadInstrument.cpp
+++ b/Code/Mantid/Framework/DataHandling/src/LoadInstrument.cpp
@@ -774,17 +774,21 @@ namespace Mantid
         //Loop through all detectors in the newly created bank and mark those in the instrument.
         try
         {
-          for (int i=0; i < bank->nelements(); i++)
+          for (int x=0; x < bank->nelements(); x++)
           {
-            boost::shared_ptr<Geometry::Detector> detector = boost::dynamic_pointer_cast<Geometry::Detector>((*bank)[i]);
-            if (detector)
+            boost::shared_ptr<Geometry::ICompAssembly> xColumn = boost::dynamic_pointer_cast<Geometry::ICompAssembly>((*bank)[x]);
+            for (int y=0; y < xColumn->nelements(); y++)
             {
-              //Make default facing for the pixel
-              Geometry::IComponent* comp = (Geometry::IComponent*) detector.get();
-              if (m_haveDefaultFacing)
-                makeXYplaneFaceComponent(comp, m_defaultFacing);
-              //Mark it as a detector (add to the instrument cache)
-              m_instrument->markAsDetector(detector.get());
+              boost::shared_ptr<Geometry::Detector> detector = boost::dynamic_pointer_cast<Geometry::Detector>((*xColumn)[y]);
+              if (detector)
+              {
+                //Make default facing for the pixel
+                Geometry::IComponent* comp = (Geometry::IComponent*) detector.get();
+                if (m_haveDefaultFacing)
+                  makeXYplaneFaceComponent(comp, m_defaultFacing);
+                //Mark it as a detector (add to the instrument cache)
+                m_instrument->markAsDetector(detector.get());
+              }
             }
           }
         }
diff --git a/Code/Mantid/Framework/DataHandling/test/LoadInstrumentTest.h b/Code/Mantid/Framework/DataHandling/test/LoadInstrumentTest.h
index 17ef0add6f0..208e249aa5e 100644
--- a/Code/Mantid/Framework/DataHandling/test/LoadInstrumentTest.h
+++ b/Code/Mantid/Framework/DataHandling/test/LoadInstrumentTest.h
@@ -1,25 +1,25 @@
 #ifndef LOADINSTRUMENTTEST_H_
 #define LOADINSTRUMENTTEST_H_
 
-#include <cxxtest/TestSuite.h>
-
-#include "MantidDataHandling/LoadInstrument.h"
-#include "MantidAPI/InstrumentDataService.h"
-#include "MantidGeometry/Instrument/FitParameter.h"
-#include "MantidAPI/WorkspaceFactory.h"
-#include "MantidGeometry/Instrument/Instrument.h"
-#include "MantidDataObjects/Workspace2D.h"
+#include "MantidAPI/Algorithm.h"
 #include "MantidAPI/AnalysisDataService.h"
-#include "MantidKernel/Exception.h"
 #include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/InstrumentDataService.h"
 #include "MantidAPI/Workspace.h"
-#include "MantidAPI/Algorithm.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidDataHandling/LoadInstrument.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument/Component.h"
-#include "MantidGeometry/Instrument/RectangularDetector.h"
 #include "MantidGeometry/Instrument/FitParameter.h"
-#include "MantidGeometry/IDetector.h"
-#include <vector>
+#include "MantidGeometry/Instrument/FitParameter.h"
+#include "MantidGeometry/Instrument/Instrument.h"
+#include "MantidGeometry/Instrument/RectangularDetector.h"
+#include "MantidKernel/Exception.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include <cxxtest/TestSuite.h>
 #include <iostream>
+#include <vector>
 
 using namespace Mantid;
 using namespace Mantid::API;
@@ -702,8 +702,8 @@ public:
       TS_ASSERT( bank1 );
       if (!bank1) return;
 
-      //Right # of elements?
-      TS_ASSERT_EQUALS( bank1->nelements(), 100*200);
+      //Right # of x columns?
+      TS_ASSERT_EQUALS( bank1->nelements(), 100);
 
       //Positions according to formula
       TS_ASSERT_DELTA( bank1->getAtXY(0,0)->getPos().X(), -0.1, 1e-4 );
@@ -882,5 +882,81 @@ private:
 
 };
 
+
+
+class LoadInstrumentTestPerformance : public CxxTest::TestSuite
+{
+public:
+  MatrixWorkspace_sptr ws;
+
+  void setUp()
+  {
+    ws = WorkspaceCreationHelper::Create2DWorkspace(1,2);
+  }
+
+  void doTest(std::string filename, size_t numTimes = 1)
+  {
+    for (size_t i=0; i < numTimes; ++i)
+    {
+      // Remove any existing instruments, so each time they are loaded.
+      InstrumentDataService::Instance().clear();
+      // Load it fresh
+      LoadInstrument loader;
+      loader.initialize();
+      loader.setProperty("Workspace", ws);
+      loader.setPropertyValue("Filename", filename);
+      loader.execute();
+      TS_ASSERT( loader.isExecuted() );
+    }
+  }
+
+  void test_GEM()
+  {
+    doTest("GEM_Definition.xml", 10);
+  }
+
+  void test_WISH()
+  {
+    doTest("WISH_Definition.xml", 1);
+  }
+
+  void test_BASIS()
+  {
+    doTest("BASIS_Definition.xml", 5);
+  }
+
+  void test_CNCS()
+  {
+    doTest("CNCS_Definition.xml", 5);
+  }
+
+  void test_SEQUOIA()
+  {
+    doTest("SEQUOIA_Definition.xml", 5);
+  }
+
+  void test_POWGEN_2011()
+  {
+    doTest("POWGEN_Definition_2011-02-25.xml", 10);
+  }
+
+  void test_TOPAZ_2010()
+  {
+    doTest("TOPAZ_Definition_2010.xml", 1);
+  }
+
+  void test_TOPAZ_2011()
+  {
+    doTest("TOPAZ_Definition_2011-01-01.xml", 1);
+  }
+
+  void test_SNAP()
+  {
+    doTest("SNAP_Definition.xml", 1);
+  }
+
+};
+
+
 #endif /*LOADINSTRUMENTTEST_H_*/
 
diff --git a/Code/Mantid/Framework/DataObjects/CMakeLists.txt b/Code/Mantid/Framework/DataObjects/CMakeLists.txt
index e2d91e17833..928e38e7108 100644
--- a/Code/Mantid/Framework/DataObjects/CMakeLists.txt
+++ b/Code/Mantid/Framework/DataObjects/CMakeLists.txt
@@ -5,6 +5,7 @@ set ( SRC_FILES
 	src/EventWorkspace.cpp
 	src/EventWorkspaceHelpers.cpp
 	src/Events.cpp
+	src/GroupingWorkspace.cpp
 	src/Histogram1D.cpp
 	src/ManagedDataBlock2D.cpp
 	src/ManagedWorkspace2D.cpp
@@ -31,6 +32,7 @@ set ( INC_FILES
 	inc/MantidDataObjects/EventWorkspace.h
 	inc/MantidDataObjects/EventWorkspaceHelpers.h
 	inc/MantidDataObjects/Events.h
+	inc/MantidDataObjects/GroupingWorkspace.h
 	inc/MantidDataObjects/Histogram1D.h
 	inc/MantidDataObjects/ManagedDataBlock2D.h
 	inc/MantidDataObjects/ManagedWorkspace2D.h
@@ -49,6 +51,7 @@ set ( TEST_FILES
 	test/CompressedWorkspace2DTest.h
 	test/EventListTest.h
 	test/EventWorkspaceTest.h
+	test/GroupingWorkspaceTest.h
 	test/Histogram1DTest.h
 	test/LibraryManagerTest.h
 	test/ManagedDataBlock2DTest.h
@@ -70,7 +73,7 @@ set ( TEST_FILES
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(DataObjects SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(DataObjects SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Add the target for this directory
diff --git a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/GroupingWorkspace.h b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/GroupingWorkspace.h
new file mode 100644
index 00000000000..626639fd552
--- /dev/null
+++ b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/GroupingWorkspace.h
@@ -0,0 +1,54 @@
+#ifndef MANTID_DATAOBJECTS_GROUPINGWORKSPACE_H_
+#define MANTID_DATAOBJECTS_GROUPINGWORKSPACE_H_
+    
+#include "MantidKernel/System.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectraDetectorMap.h"
+#include "MantidDataObjects/Workspace2D.h"
+
+
+namespace Mantid
+{
+namespace DataObjects
+{
+
+  /** A GroupingWorkspace is a subclass of Workspace2D
+   * where each spectrum has a single number entry, the value
+   * of which signifies to which group that workspace index belongs.
+   * 
+   * @author Janik Zikovsky
+   * @date 2011-05-02 10:46:43.466993
+   */
+  class DLLExport GroupingWorkspace : public Workspace2D
+  {
+  public:
+    GroupingWorkspace(Mantid::Geometry::IInstrument_sptr inst);
+    GroupingWorkspace();
+    ~GroupingWorkspace();
+    
+    /** Gets the name of the workspace type
+    @return Standard string name  */
+    virtual const std::string id() const {return "GroupingWorkspace";}
+
+  private:
+    /// Private copy constructor. NO COPY ALLOWED
+    GroupingWorkspace(const GroupingWorkspace&);
+    /// Private copy assignment operator. NO ASSIGNMENT ALLOWED
+    GroupingWorkspace& operator=(const GroupingWorkspace&);
+
+    virtual void init(const int &NVectors, const int &XLength, const int &YLength);
+
+  };
+
+
+  ///shared pointer to the GroupingWorkspace class
+  typedef boost::shared_ptr<GroupingWorkspace> GroupingWorkspace_sptr;
+
+  ///shared pointer to a const GroupingWorkspace
+  typedef boost::shared_ptr<const GroupingWorkspace> GroupingWorkspace_const_sptr;
+
+
+} // namespace Mantid
+} // namespace DataObjects
+
+#endif  /* MANTID_DATAOBJECTS_GROUPINGWORKSPACE_H_ */
diff --git a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/Peak.h b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/Peak.h
index 6a556daa2ce..c28d295f787 100644
--- a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/Peak.h
+++ b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/Peak.h
@@ -88,6 +88,9 @@ namespace DataObjects
     /// Detector pointed to
     Mantid::Geometry::IDetector_sptr m_det;
 
+    /// Name of the parent bank
+    std::string m_BankName;
+
     /// ID of the detector
     int m_DetectorID;
 
@@ -116,7 +119,10 @@ namespace DataObjects
     double m_FinalEnergy;
 
     /// Orientation matrix of the goniometer angles.
-    Mantid::Geometry::Matrix<double> m_GoniometerMatrix; //TODO: Set as identity 3x3 matrix by default
+    Mantid::Geometry::Matrix<double> m_GoniometerMatrix;
+
+    /// Inverse of the goniometer rotation matrix; used to go from Q in lab frame to Q in sample frame
+    Mantid::Geometry::Matrix<double> m_InverseGoniometerMatrix;
 
     /// Originating run number for this peak
     int m_RunNumber;
diff --git a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/PeaksWorkspace.h b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/PeaksWorkspace.h
index b4ccb70935f..1c2b8ad6b59 100644
--- a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/PeaksWorkspace.h
+++ b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/PeaksWorkspace.h
@@ -94,7 +94,7 @@ namespace DataObjects
      */
     void removePeak(const int peakNum)
     {
-      if (peakNum >= static_cast<int>(peaks.size()) ) throw std::invalid_argument("PeaksWorkspace::removePeak(): peakNum is out of range.");
+      if (peakNum >= static_cast<int>(peaks.size()) || peakNum < 0 ) throw std::invalid_argument("PeaksWorkspace::removePeak(): peakNum is out of range.");
       peaks.erase(peaks.begin()+peakNum);
     }
 
@@ -107,6 +107,17 @@ namespace DataObjects
       peaks.push_back(peak);
     }
 
+    //---------------------------------------------------------------------------------------------
+    /** Return a reference to the Peak
+     * @param peakNum :: index of the peak to get.
+     * @return a reference to a Peak object.
+     */
+    Peak & getPeak(const int peakNum)
+    {
+      if (peakNum >= static_cast<int>(peaks.size()) || peakNum < 0 ) throw std::invalid_argument("PeaksWorkspace::getPeak(): peakNum is out of range.");
+      return peaks[peakNum];
+    }
+
     //---------------------------------------------------------------------------------------------
     /** Return a reference to the Peaks vector */
     std::vector<Peak> & getPeaks()
diff --git a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/Workspace2D.h b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/Workspace2D.h
index c9d417f71c6..3f75c69f726 100644
--- a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/Workspace2D.h
+++ b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/Workspace2D.h
@@ -110,16 +110,16 @@ protected:
   /// The number of vectors in the workspace
   int m_noVectors;
   /// a vector holding monitors in the workspace
-   std::vector<int> m_monitorList;
-  
+  std::vector<int> m_monitorList;
+
+  virtual void init(const int &NVectors, const int &XLength, const int &YLength);
+
 private:
   /// Private copy constructor. NO COPY ALLOWED
   Workspace2D(const Workspace2D&);
   /// Private copy assignment operator. NO ASSIGNMENT ALLOWED
   Workspace2D& operator=(const Workspace2D&);
 
-  virtual void init(const int &NVectors, const int &XLength, const int &YLength);
-
   virtual int getHistogramNumberHelper() const;
 
   /// A vector that holds the 1D histograms
diff --git a/Code/Mantid/Framework/DataObjects/src/GroupingWorkspace.cpp b/Code/Mantid/Framework/DataObjects/src/GroupingWorkspace.cpp
new file mode 100644
index 00000000000..5329c571ca3
--- /dev/null
+++ b/Code/Mantid/Framework/DataObjects/src/GroupingWorkspace.cpp
@@ -0,0 +1,77 @@
+#include "MantidDataObjects/GroupingWorkspace.h"
+#include "MantidKernel/System.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/SpectraDetectorMap.h"
+#include "MantidAPI/SpectraAxis.h"
+
+using Mantid::API::SpectraAxis;
+
+namespace Mantid
+{
+namespace DataObjects
+{
+
+  //Register the workspace
+  DECLARE_WORKSPACE(GroupingWorkspace)
+
+
+  //----------------------------------------------------------------------------------------------
+  /** Constructor
+   */
+  GroupingWorkspace::GroupingWorkspace()
+  {
+  }
+
+  //----------------------------------------------------------------------------------------------
+  /** Constructor, building from an instrument
+   *
+   * @param inst :: input instrument that is the base for this workspace
+   * @return created GroupingWorkspace
+   */
+  GroupingWorkspace::GroupingWorkspace(Mantid::Geometry::IInstrument_sptr inst)
+  {
+    // Get all the detectors IDs
+    std::vector<int> detIDs = inst->getDetectorIDs(true);
+
+    // Init the Workspace2D with one spectrum per detector
+    this->init(detIDs.size(), 1, 1);
+
+    // Copy the instrument
+    this->setInstrument( inst );
+
+    // Initialize the spectra-det-map
+    this->mutableSpectraMap().populateWithVector(detIDs);
+
+    // Make a simple 1-1 workspaceIndex to spectrumNumber axis.
+    SpectraAxis * ax1 = dynamic_cast<SpectraAxis *>(this->m_axes[1]);
+    ax1->populateSimple(detIDs.size());
+  }
+
+  //----------------------------------------------------------------------------------------------
+  /** Destructor
+   */
+  GroupingWorkspace::~GroupingWorkspace()
+  {
+  }
+  
+
+  //----------------------------------------------------------------------------------------------
+  /** Sets the size of the workspace and initializes arrays to zero
+  *  @param NVectors :: The number of vectors/histograms/detectors in the workspace
+  *  @param XLength :: Must be 1
+  *  @param YLength :: Must be 1
+  */
+  void GroupingWorkspace::init(const int &NVectors, const int &XLength, const int &YLength)
+  {
+    if ((XLength != 1) || (YLength != 1))
+      throw std::invalid_argument("GroupingWorkspace must have 'spectra' of length 1 only.");
+    // Continue with standard initialization
+    Workspace2D::init(NVectors, XLength, YLength);
+  }
+
+
+
+
+} // namespace Mantid
+} // namespace DataObjects
+
diff --git a/Code/Mantid/Framework/DataObjects/src/Peak.cpp b/Code/Mantid/Framework/DataObjects/src/Peak.cpp
index 3abaa76a0ef..834ec60e685 100644
--- a/Code/Mantid/Framework/DataObjects/src/Peak.cpp
+++ b/Code/Mantid/Framework/DataObjects/src/Peak.cpp
@@ -24,11 +24,14 @@ namespace DataObjects
     : m_inst(m_inst),
       m_H(0), m_K(0), m_L(0),
       m_Intensity(0), m_SigmaIntensity(0),
-      m_GoniometerMatrix(3,3),
+      m_GoniometerMatrix(3,3,true),
       m_RunNumber(0)
   {
     this->setDetectorID(m_DetectorID);
     this->setWavelength(m_Wavelength);
+    // Calc the inverse rotation matrix
+    m_InverseGoniometerMatrix = m_GoniometerMatrix;
+    m_InverseGoniometerMatrix.Invert();
   }
 
 //  /** Copy constructor
@@ -74,7 +77,6 @@ namespace DataObjects
     this->m_det = m_inst->getDetector(this->m_DetectorID);
     if (!m_det) throw std::runtime_error("No detector was found!");
 
-
     // Cache some positions
     const Geometry::IObjComponent_sptr sourceObj = m_inst->getSource();
     if (sourceObj == NULL)
@@ -90,9 +92,17 @@ namespace DataObjects
     // We now look for the row/column. -1 if not found.
     m_Row = -1;
     m_Col = -1;
-    if (!m_det->getParent()) return;
-    RectangularDetector_const_sptr retDet = boost::dynamic_pointer_cast<const RectangularDetector>(m_det->getParent());
+
+    // Go up 2 parents to find the rectangular detector
+    IComponent_const_sptr parent = m_det->getParent();
+    if (!parent) return;
+    m_BankName = parent->getName(); // Use the parent by default
+    parent = parent->getParent();
+    if (!parent) return;
+    RectangularDetector_const_sptr retDet = boost::dynamic_pointer_cast<const RectangularDetector>(parent);
     if (!retDet) return;
+    m_BankName = retDet->getName(); // Use the grand-parent for rectangular detectors
+
     std::pair<int,int> xy = retDet->getXYForDetectorID(m_DetectorID);
     m_Row = xy.second;
     m_Col = xy.first;
@@ -325,14 +335,12 @@ namespace DataObjects
 
   // -------------------------------------------------------------------------------------
   /** Find the name of the bank that is the parent of the detector. This works
-   * best for RectangularDetector instruments (goes up one level)
+   * best for RectangularDetector instruments (goes up two levels)
    * @return name of the bank.
    */
   std::string Peak::getBankName() const
   {
-    if (!m_det) return "";
-    if (!m_det->getParent()) return "";
-    return m_det->getParent()->getName();
+    return m_BankName;
   }
 
   // -------------------------------------------------------------------------------------
@@ -354,12 +362,14 @@ namespace DataObjects
     return detPos;
   }
 
+  // -------------------------------------------------------------------------------------
   /** Return the L1 flight path length (source to sample), in meters. */
   double Peak::getL1() const
   {
     return (samplePos - sourcePos).norm();
   }
 
+  // -------------------------------------------------------------------------------------
   /** Return the L2 flight path length (sample to detector), in meters. */
   double Peak::getL2() const
   {
diff --git a/Code/Mantid/Framework/DataObjects/test/GroupingWorkspaceTest.h b/Code/Mantid/Framework/DataObjects/test/GroupingWorkspaceTest.h
new file mode 100644
index 00000000000..14693f9501e
--- /dev/null
+++ b/Code/Mantid/Framework/DataObjects/test/GroupingWorkspaceTest.h
@@ -0,0 +1,53 @@
+#ifndef MANTID_DATAOBJECTS_GROUPINGWORKSPACETEST_H_
+#define MANTID_DATAOBJECTS_GROUPINGWORKSPACETEST_H_
+
+#include "MantidDataObjects/GroupingWorkspace.h"
+#include "MantidKernel/System.h"
+#include "MantidKernel/Timer.h"
+#include "MantidTestHelpers/AlgorithmHelper.h"
+#include "MantidTestHelpers/ComponentCreationHelper.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include <cxxtest/TestSuite.h>
+#include <iomanip>
+#include <iostream>
+
+using namespace Mantid::DataObjects;
+using namespace Mantid::Geometry;
+using namespace Mantid::API;
+
+class GroupingWorkspaceTest : public CxxTest::TestSuite
+{
+public:
+
+  void test_default_constructor()
+  {
+    GroupingWorkspace_sptr ws(new GroupingWorkspace());
+    TSM_ASSERT_THROWS_ANYTHING("Can't init with > 1 X or Y entries.",  ws->initialize(100, 2, 1));
+    TSM_ASSERT_THROWS_ANYTHING("Can't init with > 1 X or Y entries.",  ws->initialize(100, 1, 2));
+    TS_ASSERT_THROWS_NOTHING( ws->initialize(100, 1, 1) );
+
+    TS_ASSERT_EQUALS( ws->getNumberHistograms(), 100);
+    TS_ASSERT_EQUALS( ws->blocksize(), 1);
+  }
+
+  void test_constructor_from_Instrument()
+  {
+    // Fake instrument with 5*9 pixels
+    IInstrument_sptr inst = ComponentCreationHelper::createTestInstrumentCylindrical(5);
+
+    GroupingWorkspace_sptr ws(new GroupingWorkspace(inst));
+
+    TS_ASSERT_EQUALS( ws->getNumberHistograms(), 45);
+    TS_ASSERT_EQUALS( ws->blocksize(), 1);
+    TS_ASSERT_EQUALS( ws->getInstrument()->getName(), "basic"); // Name of the test instrument
+    TS_ASSERT_EQUALS( ws->spectraMap().nElements(), 45);
+    std::vector<int> dets = ws->spectraMap().getDetectors(0);
+    TS_ASSERT_EQUALS(dets.size(), 1);
+  }
+
+
+};
+
+
+#endif /* MANTID_DATAOBJECTS_GROUPINGWORKSPACETEST_H_ */
+
diff --git a/Code/Mantid/Framework/DataObjects/test/PeakTest.h b/Code/Mantid/Framework/DataObjects/test/PeakTest.h
index 201eb173dc2..afdcff8808b 100644
--- a/Code/Mantid/Framework/DataObjects/test/PeakTest.h
+++ b/Code/Mantid/Framework/DataObjects/test/PeakTest.h
@@ -112,6 +112,11 @@ public:
     TS_ASSERT_EQUALS( p.getH(), 5.0);
     TS_ASSERT_EQUALS( p.getK(), 6.0);
     TS_ASSERT_EQUALS( p.getL(), 7.0);
+    p.setHKL(V3D(1.0, 2.0, 3.0));
+    TS_ASSERT_EQUALS( p.getH(), 1.0);
+    TS_ASSERT_EQUALS( p.getK(), 2.0);
+    TS_ASSERT_EQUALS( p.getL(), 3.0);
+    TS_ASSERT_EQUALS( p.getHKL(), V3D(1.0, 2.0, 3.0));
   }
 
   void test_getBank_and_row()
@@ -128,6 +133,29 @@ public:
     TS_ASSERT_EQUALS(p.getCol(), 1)
   }
 
+  void test_getQSampleFrame()
+  {
+
+    // Peak 3 is phi,chi,omega of 90,0,0; giving this matrix:
+    Matrix<double> r2(3,3,false);
+    r2[0][2] = 1;
+    r2[1][1] = 1;
+    r2[2][0] = -1;
+
+    Peak p(inst, 10000, 2.0);
+    p.setGoniometerMatrix(r2);
+
+    // Q in the lab frame
+    V3D qLab = p.getQLabFrame();
+    // q in the sample frame.
+    V3D qSample = p.getQSampleFrame();
+    // If we re-rotate q in the sample frame by the gonio matrix, we should get q in the lab frame
+    V3D qSampleRotated = r2 * qSample;
+
+    // Did the peak properly invert the rotation matrix?
+    TS_ASSERT_EQUALS(qLab, qSampleRotated);
+  }
+
 };
 
 
diff --git a/Code/Mantid/Framework/Geometry/CMakeLists.txt b/Code/Mantid/Framework/Geometry/CMakeLists.txt
index 94d422c9893..28d77a40b08 100644
--- a/Code/Mantid/Framework/Geometry/CMakeLists.txt
+++ b/Code/Mantid/Framework/Geometry/CMakeLists.txt
@@ -215,7 +215,7 @@ set ( TEST_FILES
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(Geometry SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(Geometry SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Find 'local' dependencies
diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/ICompAssembly.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/ICompAssembly.h
index ff5659b62b0..d3c18e7d70d 100644
--- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/ICompAssembly.h
+++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/ICompAssembly.h
@@ -1,15 +1,20 @@
-#ifndef ICOMPONENT_ASSEMBLY_
-#define ICOMPONENT_ASSEMBLY_
-#include <string> 
-#include <vector>
+#ifndef MANTID_GEOMETRY_ICOMPASSEMBLY_
+#define MANTID_GEOMETRY_ICOMPASSEMBLY_
+
 #include "MantidGeometry/IComponent.h"
 #include "MantidKernel/System.h"
 #include <boost/shared_ptr.hpp>
+#include <deque>
+#include <string>
+#include <vector>
 
 namespace Mantid
 {
   namespace Geometry
   {
+    // Forward declaration
+    class Track;
+
     /** @class ICompAssembly 
     @brief Class for Assembly of geometric components. 
     @version A
@@ -72,6 +77,9 @@ namespace Mantid
       */
       virtual void printTree(std::ostream&) const = 0;
 
+      /** Test the intersection of the ray with the children of the component assembly  */
+      virtual void testIntersectionWithChildren(Track & testRay, std::deque<IComponent_sptr> & searchQueue) const = 0;
+
     private:
       /// Private copy assignment operator
       ICompAssembly& operator=(const ICompAssembly&);
@@ -86,4 +94,5 @@ namespace Mantid
   } //Namespace Geometry
 } //Namespace Mantid
 
+
 #endif
diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/IComponent.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/IComponent.h
index 7c040f63b7d..431551f2357 100644
--- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/IComponent.h
+++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/IComponent.h
@@ -80,6 +80,8 @@ namespace Mantid
       virtual void setParent(IComponent*)= 0;
       //! Return a pointer to the current parent.
       virtual boost::shared_ptr<const IComponent> getParent() const = 0;
+      /** Returns the bare pointer to the IComponent parent */
+      virtual const IComponent* getBareParent() const = 0;
       //! Return an array of all ancestors, the nearest first
       virtual std::vector<boost::shared_ptr<const IComponent> > getAncestors() const = 0;
       //! Set the IComponent name
@@ -142,6 +144,7 @@ namespace Mantid
       /** Prints a text representation of itself
       */
       virtual void printSelf(std::ostream&) const = 0;
+
     };
 
     ///Typedef of a shared pointer to a IComponent
diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/CompAssembly.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/CompAssembly.h
index 35aa6f0da11..cab84f5de53 100644
--- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/CompAssembly.h
+++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/CompAssembly.h
@@ -91,6 +91,10 @@ public:
   void printChildren(std::ostream&) const;
   void printTree(std::ostream&) const;
 
+  /** Test the intersection of the ray with the children of the component assembly, for InstrumentRayTracer  */
+  virtual void testIntersectionWithChildren(Track & testRay,
+      std::deque<IComponent_sptr> & searchQueue) const;
+
 private:
   /// Private copy assignment operator
   CompAssembly& operator=(const ICompAssembly&);
diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/Component.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/Component.h
index 270ebeec84d..40bfc2fdd05 100644
--- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/Component.h
+++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/Component.h
@@ -84,6 +84,8 @@ namespace Mantid
       //! Return an array of all ancestors
       std::vector<boost::shared_ptr<const IComponent> > getAncestors() const;
 
+      bool isParentNamed(const std::string & expectedName, int maxDepth=-1) const;
+
       //! Set the IComponent name
       void setName(const std::string&);
 
@@ -190,7 +192,12 @@ namespace Mantid
       /// Returns the ScaleFactor
       virtual V3D getScaleFactor() const;
 
+      /** Returns the bare pointer to the IComponent parent */
+      const IComponent* getBareParent() const { return m_parent; }
+
     protected:
+      /// Parent component in the tree
+      const IComponent* m_parent;
       /// The base component - this is the unmodifed component (without the parameters). Stored
       /// as a pointer to Component so that it's properties can be accessed without casting each time
       const Component* m_base;
@@ -205,8 +212,6 @@ namespace Mantid
       V3D m_pos;
       //! Orientation
       Quat m_rot;
-      /// Parent component in the tree
-      const IComponent* m_parent;
 
       /**
       *  Get a parameter from the parameter map
diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/DetectorGroup.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/DetectorGroup.h
index 805c0217320..443ce8ab301 100644
--- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/DetectorGroup.h
+++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/DetectorGroup.h
@@ -141,6 +141,7 @@ namespace Mantid
       {
         return boost::shared_ptr<const IComponent>();
       }
+      virtual const IComponent* getBareParent() const { return NULL; }
       std::vector<boost::shared_ptr<const IComponent> > getAncestors() const
       {
         return std::vector<boost::shared_ptr<const IComponent> >();
diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/ObjCompAssembly.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/ObjCompAssembly.h
index 3df3e21ddbb..b677a366989 100644
--- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/ObjCompAssembly.h
+++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/ObjCompAssembly.h
@@ -87,6 +87,12 @@ public:
   //! Set the outline of the assembly
   boost::shared_ptr<Object> createOutline();
   void setOutline(boost::shared_ptr<const Object> obj);
+
+  /** Test the intersection of the ray with the children of the component assembly  */
+  virtual void testIntersectionWithChildren(Track & /*testRay*/, std::deque<IComponent_sptr> & /*searchQueue*/) const
+  { throw std::runtime_error("Not implemented."); }
+
+
 private:
   /// Private copy assignment operator
   ObjCompAssembly& operator=(const ICompAssembly&);
diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/RectangularDetector.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/RectangularDetector.h
index b093190158a..043d0fc393b 100644
--- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/RectangularDetector.h
+++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Instrument/RectangularDetector.h
@@ -105,6 +105,8 @@ public:
   // the multiple inheritance seems to confuse it so we'll explicityly tell it that here
   using CompAssembly::getBoundingBox;
 
+  virtual void testIntersectionWithChildren(Track & testRay, std::deque<IComponent_sptr> & searchQueue) const;
+
   // ------------ IObjComponent methods ----------------
 
   /// Does the point given lie within this object component?
diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Math/Matrix.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Math/Matrix.h
index 40bb8514ba9..ab3d926c708 100644
--- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Math/Matrix.h
+++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Math/Matrix.h
@@ -85,6 +85,7 @@ namespace Mantid
 
       bool operator!=(const Matrix<T>&) const;
       bool operator==(const Matrix<T>&) const;
+      bool equals(const Matrix<T>& A, const double Tolerance) const;
       T item(const int a,const int b) const { return V[a][b]; }   ///< disallows access
 
       void print() const;
diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Objects/InstrumentRayTracer.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Objects/InstrumentRayTracer.h
index 3ce704ed5bf..3fff7dd2047 100644
--- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Objects/InstrumentRayTracer.h
+++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Objects/InstrumentRayTracer.h
@@ -59,6 +59,7 @@ namespace Mantid
       /// Trace a given track from the instrument source in the given direction 
       /// and compile a list of results that this track intersects.
       void trace(const V3D & direction) const;
+      void traceFromSample(const V3D & direction) const;
       /// Get the results of the intersection tests that have been updated 
       /// since the previous call to trace
       Links getResults() const;
@@ -67,10 +68,7 @@ namespace Mantid
       /// Default constructor
       InstrumentRayTracer();
       /// Fire the given track at the instrument
-      void fireRay(Track & testRay) const;
-      /// Test the physical intersection of a track and any component children
-      void testIntersectionWithChildren(Track & testRay, ICompAssembly_sptr assembly, 
-					std::deque<IComponent_sptr> & searchQueue) const;
+      void fireRay(Track & testRay, bool checkInstrumentBB = true) const;
 
       /// Pointer to the instrument
       IInstrument_sptr m_instrument;
diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/V3D.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/V3D.h
index b6039475e4a..503c88e553f 100644
--- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/V3D.h
+++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/V3D.h
@@ -95,6 +95,8 @@ namespace Mantid
       //      void rotate(const V3D&,const V3D&,const double);
       void rotate(const Matrix<double>&);
 
+      void round();
+
       /// Make a normalized vector (return norm value)
       double normalize();            // Vec3D::makeUnit
       double norm() const;
diff --git a/Code/Mantid/Framework/Geometry/src/Crystal/OrientedLattice.cpp b/Code/Mantid/Framework/Geometry/src/Crystal/OrientedLattice.cpp
index 7c7221e8ead..55b82cf87d4 100644
--- a/Code/Mantid/Framework/Geometry/src/Crystal/OrientedLattice.cpp
+++ b/Code/Mantid/Framework/Geometry/src/Crystal/OrientedLattice.cpp
@@ -1,4 +1,5 @@
-#include <MantidGeometry/Crystal/OrientedLattice.h>
+#include "MantidGeometry/Crystal/OrientedLattice.h"
+
 namespace Mantid
 {
 namespace Geometry
diff --git a/Code/Mantid/Framework/Geometry/src/Instrument/CompAssembly.cpp b/Code/Mantid/Framework/Geometry/src/Instrument/CompAssembly.cpp
index 103b5f6f88c..746d0df0ec0 100644
--- a/Code/Mantid/Framework/Geometry/src/Instrument/CompAssembly.cpp
+++ b/Code/Mantid/Framework/Geometry/src/Instrument/CompAssembly.cpp
@@ -1,9 +1,11 @@
 #include "MantidGeometry/Instrument/CompAssembly.h"
-#include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidGeometry/Instrument/ParComponentFactory.h"
+#include "MantidGeometry/IObjComponent.h"
+#include "MantidGeometry/Objects/BoundingBox.h"
 #include <algorithm>
-#include <stdexcept> 
 #include <ostream>
+#include <stdexcept> 
+
 namespace Mantid
 {
 namespace Geometry
@@ -295,6 +297,35 @@ void CompAssembly::getBoundingBox(BoundingBox & assemblyBox) const
   }
 }
 
+
+
+//------------------------------------------------------------------------------------------------
+/** Test the intersection of the ray with the children of the component assembly, for InstrumentRayTracer.
+ *
+ * @param testRay :: Track under test. The results are stored here.
+ * @param searchQueue :: If a child is a sub-assembly then it is appended for later searching
+ */
+void CompAssembly::testIntersectionWithChildren(Track & testRay, std::deque<IComponent_sptr> & searchQueue) const
+{
+  int nchildren = this->nelements();
+  for( int i = 0; i < nchildren; ++i )
+  {
+    boost::shared_ptr<Geometry::IComponent> comp = this->getChild(i);
+    if( ICompAssembly_sptr childAssembly = boost::dynamic_pointer_cast<ICompAssembly>(comp) )
+    {
+      searchQueue.push_back(comp);
+    }
+    // Check the physical object intersection
+    else if( IObjComponent *physicalObject = dynamic_cast<IObjComponent*>(comp.get()) )
+    {
+       physicalObject->interceptSurface(testRay);
+    }
+    else {}
+  }
+}
+
+
+//------------------------------------------------------------------------------------------------
 /** Print information about elements in the assembly to a stream
  * @param os :: output stream 
  * 
diff --git a/Code/Mantid/Framework/Geometry/src/Instrument/Component.cpp b/Code/Mantid/Framework/Geometry/src/Instrument/Component.cpp
index 9e6db44085e..7e783e508d3 100644
--- a/Code/Mantid/Framework/Geometry/src/Instrument/Component.cpp
+++ b/Code/Mantid/Framework/Geometry/src/Instrument/Component.cpp
@@ -40,8 +40,7 @@ namespace Geometry
    *  @param parent :: parent Component (optional)
    */
   Component::Component(const std::string& name, IComponent* parent)
-  : m_base(NULL), m_map(NULL), m_isParametrized(false), m_name(name), m_pos(), m_rot(),
-    m_parent(parent)
+  : m_base(NULL), m_map(NULL), m_isParametrized(false), m_name(name), m_pos(), m_rot(), m_parent(parent)
   {
   }
 
@@ -52,8 +51,7 @@ namespace Geometry
    *  @param parent :: parent Component
    */
   Component::Component(const std::string& name, const V3D& position, IComponent* parent)
-  : m_base(NULL), m_map(NULL), m_isParametrized(false), m_name(name), m_pos(position),
-    m_rot(), m_parent(parent)
+  : m_base(NULL), m_map(NULL), m_isParametrized(false), m_name(name), m_pos(position), m_rot(), m_parent(parent)
   {
   }
 
@@ -64,8 +62,7 @@ namespace Geometry
    *  @param parent :: parent Component (optional)
    */
   Component::Component(const std::string& name, const V3D& position, const Quat& rotation, IComponent* parent)
-  : m_base(NULL), m_map(NULL), m_isParametrized(false), m_name(name),m_pos(position),
-    m_rot(rotation),m_parent(parent)
+  : m_base(NULL), m_map(NULL), m_isParametrized(false), m_name(name),m_pos(position), m_rot(rotation), m_parent(parent)
   {
   }
 
@@ -130,6 +127,28 @@ namespace Geometry
       return boost::shared_ptr<const IComponent>(m_parent, NoDeleting());
   }
 
+  //--------------------------------------------------------------------------------------------
+  /** Return true if one of the parents of this component is named something
+   *
+   * @param expectedName :: case-sensitive name to look for.
+   * @param maxDepth :: levels of recursion to look into, -1 for no limit (default)
+   * @return true if a parent matches, false otherwise
+   */
+  bool Component::isParentNamed(const std::string & expectedName, int maxDepth) const
+  {
+    int depth = 0;
+    const IComponent * parent = m_parent;
+    while (parent && (depth < maxDepth || maxDepth < 0))
+    {
+      // Correct name? stop searching
+      if (parent->getName() == expectedName)
+        return true;
+      parent = parent->getBareParent();
+      depth++;
+    }
+    return false;
+  }
+
   //--------------------------------------------------------------------------------------------
   /** Returns an array of all ancestors of this component,
    *  starting with the direct parent and moving up
@@ -161,6 +180,7 @@ namespace Geometry
     return ancs;
   }
 
+
   //--------------------------------------------------------------------------------------------
   /** Set the name of the Component (currently does nothing)
    *  @param s :: name string
diff --git a/Code/Mantid/Framework/Geometry/src/Instrument/Instrument.cpp b/Code/Mantid/Framework/Geometry/src/Instrument/Instrument.cpp
index 92261e9034e..8266cbbcf0a 100644
--- a/Code/Mantid/Framework/Geometry/src/Instrument/Instrument.cpp
+++ b/Code/Mantid/Framework/Geometry/src/Instrument/Instrument.cpp
@@ -92,6 +92,7 @@ namespace Mantid
     }
 
 
+    //------------------------------------------------------------------------------------------
     /** Return a vector of detector IDs in this instrument */
     std::vector<int> Instrument::getDetectorIDs(bool skipMonitors) const
     {
diff --git a/Code/Mantid/Framework/Geometry/src/Instrument/RectangularDetector.cpp b/Code/Mantid/Framework/Geometry/src/Instrument/RectangularDetector.cpp
index 4860916bc69..9fb1bebfb47 100644
--- a/Code/Mantid/Framework/Geometry/src/Instrument/RectangularDetector.cpp
+++ b/Code/Mantid/Framework/Geometry/src/Instrument/RectangularDetector.cpp
@@ -1,14 +1,15 @@
-#include "MantidGeometry/Instrument/RectangularDetector.h"
 #include "MantidGeometry/Instrument/Detector.h"
+#include "MantidGeometry/Instrument/RectangularDetector.h"
+#include "MantidGeometry/Math/Matrix.h"
+#include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidGeometry/Objects/Object.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
-#include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidGeometry/Rendering/BitmapGeometryHandler.h"
 #include "MantidKernel/Exception.h"
-
 #include <algorithm>
-#include <stdexcept> 
 #include <ostream>
+#include <stdexcept> 
+
 namespace Mantid
 {
 namespace Geometry
@@ -34,7 +35,6 @@ m_minDetId(0),m_maxDetId(0)
 RectangularDetector::RectangularDetector(const RectangularDetector* base, const ParameterMap * map)
  : CompAssembly(base,map), IObjComponent(NULL), m_rectBase(base),m_minDetId(0),m_maxDetId(0)
 {
-
   setGeometryHandler(new BitmapGeometryHandler(this));
 }
 
@@ -93,10 +93,14 @@ boost::shared_ptr<Detector> RectangularDetector::getAtXY(const int X, const int
     throw std::runtime_error("RectangularDetector::getAtXY: Y specified is out of range.");
 
   //Find the index and return that.
-  int i = X*ypixels() + Y;
+  //int i = X*ypixels() + Y;
+  //return boost::dynamic_pointer_cast<Detector>( this->operator[](i) );
 
-  //Use the [] operator to return it (or create the parametrized version if needed)
-  return boost::dynamic_pointer_cast<Detector>( this->operator[](i) );
+  // Get to column
+  ICompAssembly_sptr xCol = boost::dynamic_pointer_cast<ICompAssembly>(this->getChild(X));
+  if (!xCol)
+    throw std::runtime_error("RectangularDetector::getAtXY: X specified is out of range.");
+  return boost::dynamic_pointer_cast<Detector>( xCol->getChild(Y) );
 }
 
 //-------------------------------------------------------------------------------------------------
@@ -258,7 +262,6 @@ void RectangularDetector::initialize(boost::shared_ptr<Object> shape,
   if (m_isParametrized)
     throw std::runtime_error("RectangularDetector::initialize() called for a parametrized RectangularDetector");
 
-
   m_xpixels = xpixels;
   m_ypixels = ypixels;
   m_xsize = xpixels * xstep;
@@ -284,6 +287,12 @@ void RectangularDetector::initialize(boost::shared_ptr<Object> shape,
   //Loop through all the pixels
   int ix, iy;
   for (ix=0; ix<m_xpixels; ix++)
+  {
+    // Create an ICompAssembly for each x-column
+    std::ostringstream oss_col;
+    oss_col << name << "(x=" << ix << ")";
+    CompAssembly * xColumn = new CompAssembly(oss_col.str(), this);
+
     for (iy=0; iy<m_ypixels; iy++)
     {
       //Make the name
@@ -307,8 +316,8 @@ void RectangularDetector::initialize(boost::shared_ptr<Object> shape,
       {
         maxDetId=id;
       }
-      //Create the detector from the given id & shape and with THIS as the parent.
-      Detector* detector = new Detector(oss.str(), id, shape, this);
+      //Create the detector from the given id & shape and with xColumn as the parent.
+      Detector* detector = new Detector(oss.str(), id, shape, xColumn);
 
       //Calculate the x,y position
       double x = xstart + ix * xstep;
@@ -317,12 +326,14 @@ void RectangularDetector::initialize(boost::shared_ptr<Object> shape,
       //Translate (relative to parent)
       detector->translate(pos);
 
-      //Add it to this assembly
-      this->add(detector);
+      //Add it to the x-colum
+      xColumn->add(detector);
+//      this->add(detector);
 
     }
-    m_minDetId=minDetId;
-    m_maxDetId=maxDetId;
+  }
+  m_minDetId=minDetId;
+  m_maxDetId=maxDetId;
 
    
 }
@@ -351,8 +362,68 @@ int RectangularDetector::maxDetectorID()
 
 
 
+//------------------------------------------------------------------------------------------------
+/** Test the intersection of the ray with the children of the component assembly, for InstrumentRayTracer.
+ * Uses the knowledge of the RectangularDetector shape to significantly speed up tracking.
+ *
+ * @param testRay :: Track under test. The results are stored here.
+ * @param searchQueue :: If a child is a sub-assembly then it is appended for later searching. Unused.
+ */
+void RectangularDetector::testIntersectionWithChildren(Track & testRay, std::deque<IComponent_sptr> & /*searchQueue*/) const
+{
+  /// Base point (x,y,z) = position of pixel 0,0
+  V3D basePoint;
+
+  /// Vertical (y-axis) basis vector of the detector
+  V3D vertical;
+
+  /// Horizontal (x-axis) basis vector of the detector
+  V3D horizontal;
+
+  basePoint = getAtXY(0,0)->getPos();
+  horizontal = getAtXY(xpixels()-1, 0)->getPos() - basePoint;
+  vertical   = getAtXY(0, ypixels()-1)->getPos() - basePoint;
+
+  // The beam direction
+  V3D beam = testRay.direction();
+
+  // From: http://en.wikipedia.org/wiki/Line-plane_intersection (taken on May 4, 2011),
+  // We build a matrix to solve the linear equation:
+  Matrix<double> mat(3,3);
+  mat.setColumn(0, beam*-1.0);
+  mat.setColumn(1, horizontal);
+  mat.setColumn(2, vertical);
+  mat.Invert();
+
+  // Multiply by the inverted matrix to find t,u,v
+  V3D tuv = mat * (testRay.startPoint() - basePoint);
+//  std::cout << tuv << "\n";
+
+  // Intersection point
+  V3D intersec = beam; intersec *= tuv[0];
+
+  // t = coordinate along the line
+  // u,v = coordinates along horizontal, vertical
+  // (and correct for it being between 0, xpixels-1).  The +0.5 is because the base point is at the CENTER of pixel 0,0.
+  double u = (double(xpixels()-1) * tuv[1] + 0.5);
+  double v = (double(ypixels()-1) * tuv[2] + 0.5);
+
+//  std::cout << u << ", " << v << "\n";
+
+  // In indices
+  int xIndex = int(u);
+  int yIndex = int(v);
 
+  // Out of range?
+  if (xIndex < 0) return;
+  if (yIndex < 0) return;
+  if (xIndex >= xpixels()) return;
+  if (yIndex >= ypixels()) return;
 
+  // TODO: Do I need to put something smart here for the first 3 parameters?
+  testRay.addLink(intersec, intersec, 0.0,
+      getAtXY(xIndex, yIndex)->getComponentID());
+}
 
 
 
@@ -463,6 +534,7 @@ void RectangularDetector::getBoundingBox(BoundingBox & assemblyBox) const
     getAtXY(0, this->ypixels()-1)->getBoundingBox(compBox);
     m_cachedBoundingBox->grow(compBox);
   }
+
   // Use cached box
   assemblyBox = *m_cachedBoundingBox;
 }
@@ -549,10 +621,6 @@ void RectangularDetector::initDraw() const
 /// Returns the shape of the Object
 const boost::shared_ptr<const Object> RectangularDetector::shape() const
 {
-  //std::cout << "RectangularDetector::Shape() called.\n";
-  //throw Kernel::Exception::NotImplementedError("RectangularDetector::Shape() is not implemented.");
-
-
   // --- Create a cuboid shape for your pixels ----
   double szX=m_xpixels;
   double szY=m_ypixels;
@@ -570,19 +638,6 @@ const boost::shared_ptr<const Object> RectangularDetector::shape() const
   Geometry::ShapeFactory shapeCreator;
   boost::shared_ptr<Geometry::Object> cuboidShape = shapeCreator.createShape(xmlCuboidShape);
 
-  //TODO: Create the object of the right shape
-  //Geometry::Object baseObj();
-  //Looks like the object doesn't really contain any shape data; that is all in the GeometryHandler (i think)!
-
-  //TODO: Create a shared pointer to this base object.
-
-  //TODO: Here create the real shape of the detector and somehow get the texture on there.
-
-
-  //TODO: Write a special geometry handler for RectangularDetector
-//  boost::shared_ptr<GeometryHandler> handler(new GluGeometryHandler(Obj));
-//  Obj->setGeometryHandler(handler);
-
   return cuboidShape;
 }
 
diff --git a/Code/Mantid/Framework/Geometry/src/InstrumentRayTracer.cpp b/Code/Mantid/Framework/Geometry/src/InstrumentRayTracer.cpp
index 93fe66c0f56..6f768e6760b 100644
--- a/Code/Mantid/Framework/Geometry/src/InstrumentRayTracer.cpp
+++ b/Code/Mantid/Framework/Geometry/src/InstrumentRayTracer.cpp
@@ -54,7 +54,20 @@ namespace Mantid
       m_resultsTrack.reset(m_instrument->getSource()->getPos(), dir);
       //m_resultsTrack.reset(m_instrument->getSample()->getPos() + V3D(1.0,0.0,0.0), dir);
       // The intersection results are accumulated within the ray object
-      fireRay(m_resultsTrack);
+      fireRay(m_resultsTrack, true);
+    }
+
+    /**
+     * Trace a given track from the sample position in the given direction. For performance reasons the
+     * results are accumulated within the object and can be returned using getResults.
+     * @param dir :: A directional vector. The starting point is defined by the instrument source.
+     */
+    void InstrumentRayTracer::traceFromSample(const V3D & dir) const
+    {
+      // Define the track with the sample position and the given direction.
+      m_resultsTrack.reset(m_instrument->getSample()->getPos(), dir);
+      // The intersection results are accumulated within the ray object
+      fireRay(m_resultsTrack, false);
     }
 
     /**
@@ -75,16 +88,29 @@ namespace Mantid
      * Fire the test ray at the instrument and perform a bread-first search of the 
      * object tree to find the objects that were intersected.
      * @param testRay :: An input/output parameter that defines the track and accumulates the
-     * intersection results
+     *        intersection results
+     * @param checkInstrumentBB :: set to true (default) to check that the ray intersects the
+     *        overall instruement BoundingBox. If the ray emanantes from WITHIN the instrument,
+     *        then the tracing fails, so set this to false then.
      */
-    void InstrumentRayTracer::fireRay(Track & testRay) const
+    void InstrumentRayTracer::fireRay(Track & testRay, bool checkInstrumentBB) const
     {
       // Go through the instrument tree and see if we get any hits by
       // (a) first testing the bounding box and if we're inside that then
       // (b) test the lower components.
       std::deque<IComponent_sptr> nodeQueue;
-      //Start at the root of the tree
-      nodeQueue.push_back(m_instrument);
+
+      if (checkInstrumentBB)
+      {
+        //Start at the root of the tree
+        nodeQueue.push_back(m_instrument);
+      }
+      else
+      {
+        // Skip the instrument (assume it DOES intersect) and do all its children
+        m_instrument->testIntersectionWithChildren(testRay, nodeQueue);
+      }
+
       IComponent_sptr node;
       while( !nodeQueue.empty() )
       {
@@ -97,7 +123,7 @@ namespace Mantid
         {
           if( ICompAssembly_sptr assembly = boost::dynamic_pointer_cast<ICompAssembly>(node) )
           {
-            testIntersectionWithChildren(testRay, assembly, nodeQueue);
+            assembly->testIntersectionWithChildren(testRay, nodeQueue);
           }
           else
           {
@@ -108,32 +134,6 @@ namespace Mantid
 
     }
 
-    /**
-    * Test the intersection of the ray with the children of the component assembly
-    * @param testRay :: Track under test. The results are stored here.
-    * @param assembly :: The children of this assembly will be tested
-    * @param searchQueue :: If a child is a sub-assembly then it is appended for later searching
-    */
-    void InstrumentRayTracer::testIntersectionWithChildren(Track & testRay, 
-      ICompAssembly_sptr assembly, std::deque<IComponent_sptr> & searchQueue) const
-    {
-      int nchildren = assembly->nelements();
-      for( int i = 0; i < nchildren; ++i )
-      {
-        boost::shared_ptr<Geometry::IComponent> comp = assembly->getChild(i);
-        if( ICompAssembly_sptr childAssembly = boost::dynamic_pointer_cast<ICompAssembly>(comp) )
-        {
-          searchQueue.push_back(comp);
-        }
-        // Check the physical object intersection
-        else if( IObjComponent *physicalObject = dynamic_cast<IObjComponent*>(comp.get()) ) 
-        {
-           physicalObject->interceptSurface(testRay);
-        }
-        else {}
-      }
-
-    }
 
 
     ///** 
diff --git a/Code/Mantid/Framework/Geometry/src/Math/Matrix.cpp b/Code/Mantid/Framework/Geometry/src/Math/Matrix.cpp
index e17f647db8d..5c5c958191f 100644
--- a/Code/Mantid/Framework/Geometry/src/Math/Matrix.cpp
+++ b/Code/Mantid/Framework/Geometry/src/Math/Matrix.cpp
@@ -424,8 +424,7 @@ Element by Element comparison
 }
 
 template<typename T>
-bool
-Matrix<T>::operator==(const Matrix<T>& A) const
+bool Matrix<T>::operator==(const Matrix<T>& A) const
 /** 
 Element by element comparison within tolerance.
 Tolerance means that the value must be > tolerance
@@ -436,7 +435,23 @@ Always returns 0 if the Matrix have different sizes
 @return true on success 
 */
 {
-  const double Tolerance(1e-8);
+  return this->equals(A, 1e-8);
+}
+
+
+template<typename T>
+bool Matrix<T>::equals(const Matrix<T>& A, const double Tolerance) const
+/**
+Element by element comparison within tolerance.
+Tolerance means that the value must be > tolerance
+and less than (diff/max)>tolerance
+
+Always returns 0 if the Matrix have different sizes
+@param A :: matrix to check.
+@param Tolerance :: tolerance in comparing elements
+@return true on success
+*/
+{
   if (&A!=this)       // this == A == always true
   {
     if(A.nx!=nx || A.ny!=ny)
diff --git a/Code/Mantid/Framework/Geometry/src/Objects/Track.cpp b/Code/Mantid/Framework/Geometry/src/Objects/Track.cpp
index 167e78c0653..7f9e4f80826 100644
--- a/Code/Mantid/Framework/Geometry/src/Objects/Track.cpp
+++ b/Code/Mantid/Framework/Geometry/src/Objects/Track.cpp
@@ -62,7 +62,7 @@ namespace Mantid
     /**
      * Resets the track starting point and direction. 
      * @param startPoint :: The new starting point
-     * @param direction :: The new direction
+     * @param direction :: The new direction. Must be a unit vector!
      */
     void Track::reset(const V3D& startPoint, const V3D& direction)
     {
diff --git a/Code/Mantid/Framework/Geometry/src/V3D.cpp b/Code/Mantid/Framework/Geometry/src/V3D.cpp
index da5fdaaf002..b39a6e8df88 100644
--- a/Code/Mantid/Framework/Geometry/src/V3D.cpp
+++ b/Code/Mantid/Framework/Geometry/src/V3D.cpp
@@ -1,5 +1,6 @@
 #include <iostream>
 #include <cmath>
+#include <math.h>
 #include <vector>
 #include <cstdlib>
 
@@ -454,6 +455,15 @@ V3D::normalize()
   return ND;
 }
 
+
+/** Round each component to the nearest integer */
+void V3D::round()
+{
+  x = double(long(x + (x<0?-0.5:+0.5)));
+  y = double(long(y + (y<0?-0.5:+0.5)));
+  z = double(long(z + (z<0?-0.5:+0.5)));
+}
+
   /**
     Calculates the scalar product
     @param V :: The second vector to include in the calculation
diff --git a/Code/Mantid/Framework/Geometry/test/ComponentTest.h b/Code/Mantid/Framework/Geometry/test/ComponentTest.h
index 0c523624686..0b6cd4d8c1d 100644
--- a/Code/Mantid/Framework/Geometry/test/ComponentTest.h
+++ b/Code/Mantid/Framework/Geometry/test/ComponentTest.h
@@ -122,6 +122,21 @@ public:
     TS_ASSERT_EQUALS(q.getParent()->getRelativeRot(),Quat(1,1,1,1));
   }
 
+  void test_isParentNamed()
+  {
+    Component grandParent("GrandParent",V3D(1,1,1),Quat(1,1,1,1));
+    Component parent("Parent",V3D(1,1,1),Quat(1,1,1,1), &grandParent);
+    Component q("Child",V3D(5,6,7),&parent);
+
+    TS_ASSERT(q.isParentNamed("Parent"));
+    TS_ASSERT(q.isParentNamed("GrandParent"));
+    TS_ASSERT(!q.isParentNamed("GrandParent", 1)); // not deep enough
+    TS_ASSERT(q.isParentNamed("GrandParent", 2)); // that reaches it
+    TS_ASSERT(!q.isParentNamed("DeadbeatDad"));
+    TS_ASSERT(!q.isParentNamed("Child"));
+
+  }
+
   void testGetAncestors()
   {
     Component parent("Parent",V3D(1,1,1),Quat(1,1,1,1));
diff --git a/Code/Mantid/Framework/Geometry/test/InstrumentRayTracerTest.h b/Code/Mantid/Framework/Geometry/test/InstrumentRayTracerTest.h
index 91d20e1bdc0..dac5a566166 100644
--- a/Code/Mantid/Framework/Geometry/test/InstrumentRayTracerTest.h
+++ b/Code/Mantid/Framework/Geometry/test/InstrumentRayTracerTest.h
@@ -1,17 +1,21 @@
 #ifndef INSTRUMENTRAYTRACERTEST_H_
 #define INSTRUMENTRAYTRACERTEST_H_
 
-//-------------------------------------------------------------
-// Includes
-//-------------------------------------------------------------
-#include <cxxtest/TestSuite.h>
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidGeometry/Instrument/RectangularDetector.h"
 #include "MantidGeometry/Objects/InstrumentRayTracer.h"
 #include "MantidGeometry/V3D.h"
 #include "MantidKernel/ConfigService.h"
+#include "MantidTestHelpers/AlgorithmHelper.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include <cxxtest/TestSuite.h>
 #include <iterator>
 
 using namespace Mantid::Geometry;
+using Mantid::DataObjects::Workspace2D_sptr;
+using Mantid::API::AnalysisDataService;
 
 //-------------------------------------------------------------
 // Test suite
@@ -136,6 +140,81 @@ public:
     TS_ASSERT_EQUALS(results.size(), 0);
   }
 
+
+  /** Test ray tracing into a rectangular detector
+   *
+   * @param inst :: instrument with 1 rect
+   * @param testDir :: direction of track
+   * @param expectX :: expected x index, -1 if off
+   * @param expectY :: expected y index, -1 if off
+   */
+  void doTestRectangularDetector(std::string message, IInstrument_sptr inst, V3D testDir, int expectX, int expectY)
+  {
+//    std::cout << message << std::endl;
+    InstrumentRayTracer tracker(inst);
+    testDir.normalize(); // Force to be unit vector
+    tracker.traceFromSample(testDir);
+
+    Links results = tracker.getResults();
+    if (expectX == -1)
+    { // Expect no intersection
+      TSM_ASSERT_LESS_THAN(message, results.size(), 2);
+      return;
+    }
+
+    TSM_ASSERT_EQUALS(message, results.size(), 2);
+    if (results.size() < 2)
+      return;
+
+    // Get the first result
+    Link res = *results.begin();
+    IDetector_sptr det = boost::dynamic_pointer_cast<IDetector>( inst->getComponentByID( res.componentID ) );
+    // Parent bank
+    RectangularDetector_const_sptr rect = boost::dynamic_pointer_cast<const RectangularDetector>( det->getParent()->getParent() );
+    // Find the xy index from the detector ID
+    std::pair<int,int> xy = rect->getXYForDetectorID( det->getID() );
+    TSM_ASSERT_EQUALS( message, xy.first, expectX);
+    TSM_ASSERT_EQUALS( message, xy.second, expectY);
+  }
+
+
+  void test_RectangularDetector()
+  {
+    IInstrument_sptr inst;
+    inst = ComponentCreationHelper::createTestInstrumentRectangular(1, 100);
+
+    // Towards the detector lower-left corner
+    double w = 0.008;
+    doTestRectangularDetector("Pixel (0,0)", inst, V3D(0.0, 0.0, 5.0), 0, 0);
+    // Move over some pixels
+    doTestRectangularDetector("Pixel (1,0)", inst, V3D(w*1, w*0, 5.0), 1, 0);
+    doTestRectangularDetector("Pixel (1,2)", inst, V3D(w*1, w*2, 5.0), 1, 2);
+    doTestRectangularDetector("Pixel (0.95, 0.95)", inst, V3D(w*0.45, w*0.45, 5.0), 0, 0);
+    doTestRectangularDetector("Pixel (1.05, 2.05)", inst, V3D(w*0.55, w*1.55, 5.0), 1, 2);
+    doTestRectangularDetector("Pixel (99,99)", inst, V3D(w*99, w*99, 5.0), 99, 99);
+
+    doTestRectangularDetector("Off to left",   inst, V3D(-w, 0, 5.0), -1, -1);
+    doTestRectangularDetector("Off to bottom", inst, V3D(0, -w, 5.0), -1, -1);
+    doTestRectangularDetector("Off to top", inst, V3D(0, w*100, 5.0), -1, -1);
+    doTestRectangularDetector("Off to right", inst, V3D(w*100, w, 5.0), -1, -1);
+
+    doTestRectangularDetector("Beam parallel to panel", inst, V3D(1.0, 0.0, 0.0), -1, -1);
+    doTestRectangularDetector("Beam parallel to panel", inst, V3D(0.0, 1.0, 0.0), -1, -1);
+    doTestRectangularDetector("Zero-beam", inst, V3D(0.0, 0.0, 0.0), -1, -1);
+  }
+
+
+  static void showResults(Links & results, IInstrument_sptr inst)
+  {
+    Links::const_iterator resultItr = results.begin();
+    for (; resultItr != results.end(); resultItr++)
+    {
+      IComponent_sptr component = inst->getComponentByID(resultItr->componentID);
+      std::cout << component->getName() << ", ";
+    }
+    std::cout << "\n";
+  }
+
 private:
   /// Setup the shared test instrument
   IInstrument_sptr setupInstrument()
@@ -154,4 +233,78 @@ private:
 };
 
 
+
+
+
+
+
+
+
+
+/** Performance test for large rectangular detectors */
+class InstrumentRayTracerTestPerformance : public CxxTest::TestSuite
+{
+public:
+  /// Test instrument
+  IInstrument_sptr m_inst;
+  Workspace2D_sptr topazWS;
+
+  void setUp()
+  {
+    m_inst = ComponentCreationHelper::createTestInstrumentRectangular(2, 100);
+
+    topazWS = WorkspaceCreationHelper::Create2DWorkspace(1, 2);
+    AnalysisDataService::Instance().add("TOPAZ_2010", topazWS);
+    // Load a small test file
+    AlgorithmHelper::runAlgorithm("LoadInstrument", 4,
+        "Filename", "TOPAZ_Definition_2010.xml",
+        "Workspace", "TOPAZ_2010");
+  }
+
+  void tearDown()
+  {
+    AnalysisDataService::Instance().remove("TOPAZ_2010");
+  }
+
+  void test_RectangularDetector()
+  {
+    // Directly in Z+ = towards the detector center
+    V3D testDir(0.0, 0.0, 1.0);
+    for (size_t i=0; i < 100; i++)
+    {
+      InstrumentRayTracer tracker(m_inst);
+      tracker.traceFromSample(testDir);
+      Links results = tracker.getResults();
+      TS_ASSERT_EQUALS(results.size(), 3);
+      //InstrumentRayTracerTest::showResults(results, m_inst);
+    }
+  }
+
+  void test_TOPAZ()
+  {
+    bool verbose=false;
+    IInstrument_sptr inst = topazWS->getInstrument();
+    // Directly in Z+ = towards the detector center
+    for (int azimuth=0; azimuth < 360; azimuth += 2)
+      for (int elev=-89; elev < 89; elev += 2)
+      {
+        // Make a vector pointing in every direction
+        V3D testDir;
+        testDir.spherical(1, double(elev), double(azimuth));
+        if (verbose) std::cout << testDir << " : ";
+        // Track it
+        InstrumentRayTracer tracker(inst);
+        tracker.traceFromSample(testDir);
+        Links results = tracker.getResults();
+
+        if (verbose)
+          InstrumentRayTracerTest::showResults(results, inst);
+      }
+  }
+
+
+
+};
+
+
 #endif //InstrumentRayTracerTEST_H_
diff --git a/Code/Mantid/Framework/Geometry/test/MatrixTest.h b/Code/Mantid/Framework/Geometry/test/MatrixTest.h
index e12a9b66936..4af4090fbdd 100644
--- a/Code/Mantid/Framework/Geometry/test/MatrixTest.h
+++ b/Code/Mantid/Framework/Geometry/test/MatrixTest.h
@@ -72,6 +72,16 @@ public:
     TS_ASSERT_EQUALS(Ident,A);
   }
 
+  /** Test of equals with a user-specified tolerance */
+  void test_equals()
+  {
+    Matrix<double> A(3,3, true);
+    Matrix<double> B(3,3, true);
+    B[1][1] = 1.1;
+    TS_ASSERT( !A.equals(B, 0.05) );
+    TS_ASSERT( A.equals(B, 0.15) );
+  }
+
   /**
   Check that we can swap rows and columns
   */
diff --git a/Code/Mantid/Framework/Geometry/test/RectangularDetectorTest.h b/Code/Mantid/Framework/Geometry/test/RectangularDetectorTest.h
index 2e08f9e30a5..8eb8f376fb2 100644
--- a/Code/Mantid/Framework/Geometry/test/RectangularDetectorTest.h
+++ b/Code/Mantid/Framework/Geometry/test/RectangularDetectorTest.h
@@ -146,6 +146,7 @@ public:
 
     //Name
     TS_ASSERT_EQUALS(det->getAtXY(1,2)->getName(), "MyRectangle(1,2)");
+    TS_ASSERT_EQUALS(det->getChild(1)->getName(), "MyRectangle(x=1)");
 
     BoundingBox box;
     det->getBoundingBox(box);
diff --git a/Code/Mantid/Framework/Geometry/test/V3DTest.h b/Code/Mantid/Framework/Geometry/test/V3DTest.h
index 896b060f8f3..c9f425e8871 100644
--- a/Code/Mantid/Framework/Geometry/test/V3DTest.h
+++ b/Code/Mantid/Framework/Geometry/test/V3DTest.h
@@ -31,7 +31,7 @@ public:
 		TS_ASSERT_EQUALS(d.Y(),2.0);
 		TS_ASSERT_EQUALS(d.Z(),3.0);
 	}
-	void testAssignement()
+	void testAssignment()
 	{
 		a(1.0,1.0,1.0);
 		TS_ASSERT_EQUALS(a.X(),1.0);
@@ -355,6 +355,18 @@ public:
     TS_ASSERT(a == V3D(sqrt(2.0), sqrt(2.0), 0) );
   }
 
+  /** Round each component to the nearest integer */
+  void test_round()
+  {
+    a(1.2, 0.9, 4.34);
+    a.round();
+    TS_ASSERT(a == V3D(1.0, 1.0, 4.0) );
+
+    a(-1.2, -1.9, -3.9);
+    a.round();
+    TS_ASSERT(a == V3D(-1.0, -2.0, -4.0) );
+  }
+
 };
 
 #endif
diff --git a/Code/Mantid/Framework/ICat/CMakeLists.txt b/Code/Mantid/Framework/ICat/CMakeLists.txt
index 908a9d86540..d50edc84f65 100644
--- a/Code/Mantid/Framework/ICat/CMakeLists.txt
+++ b/Code/Mantid/Framework/ICat/CMakeLists.txt
@@ -53,7 +53,7 @@ set ( TEST_FILES
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(ICat SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(ICat SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Add ssl dependency
diff --git a/Code/Mantid/Framework/Kernel/CMakeLists.txt b/Code/Mantid/Framework/Kernel/CMakeLists.txt
index 3388190fde0..18710c0ce29 100644
--- a/Code/Mantid/Framework/Kernel/CMakeLists.txt
+++ b/Code/Mantid/Framework/Kernel/CMakeLists.txt
@@ -213,7 +213,7 @@ set ( TEST_FILES
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(Kernel SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(Kernel SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Add the target for this directory
diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/Utils.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/Utils.h
index 2bdfbfc1309..b6db285e51c 100644
--- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/Utils.h
+++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/Utils.h
@@ -58,7 +58,7 @@ namespace Utils
    *        The minimum must be 0 in each dimension for the algorithm to work
    * @return an array of linear_index, set to 0, of the right size.
    */
-  inline size_t * nestedForLoopSetUpIndexMaker(const size_t numDims, size_t * index_max)
+  inline size_t * nestedForLoopSetUpIndexMaker(const size_t numDims, const size_t * index_max)
   {
     // Allocate and start at 1
     size_t * out = new size_t[numDims];
diff --git a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp
index a22bae3c10f..c1f582cd8b3 100644
--- a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp
+++ b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp
@@ -320,17 +320,21 @@ void ConfigServiceImpl::configureLogging()
   {
     //Ensure that the logging directory exists
     m_logFilePath = getString("logging.channels.fileChannel.path");
-
     Poco::Path logpath(m_logFilePath);
 
     // Undocumented way to override the mantid.log path
     if (Poco::Environment::has("MANTIDLOGPATH"))
+    {
       logpath = Poco::Path(Poco::Environment::get("MANTIDLOGPATH"));
+      logpath = logpath.absolute();
+      m_logFilePath = logpath.toString();
+    }
 
     // An absolute path makes things simpler
     logpath = logpath.absolute();
 
-    // First, try the logpath give
+
+    // First, try the logpath given
     if (!m_logFilePath.empty())
     {
       try
diff --git a/Code/Mantid/Framework/MDAlgorithms/CMakeLists.txt b/Code/Mantid/Framework/MDAlgorithms/CMakeLists.txt
index c14c0ab29bb..eb13fd687e7 100644
--- a/Code/Mantid/Framework/MDAlgorithms/CMakeLists.txt
+++ b/Code/Mantid/Framework/MDAlgorithms/CMakeLists.txt
@@ -141,7 +141,7 @@ test/UpParameterTest.h
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(MDAlgorithms SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(MDAlgorithms SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Add the target for this directory
diff --git a/Code/Mantid/Framework/MDDataObjects/CMakeLists.txt b/Code/Mantid/Framework/MDDataObjects/CMakeLists.txt
index 1cce51ab7f6..3140a3641b7 100644
--- a/Code/Mantid/Framework/MDDataObjects/CMakeLists.txt
+++ b/Code/Mantid/Framework/MDDataObjects/CMakeLists.txt
@@ -68,7 +68,7 @@ test/MDWorkspaceIteratorTest.h
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(MDDataObjects SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(MDDataObjects SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 
diff --git a/Code/Mantid/Framework/MDEvents/CMakeLists.txt b/Code/Mantid/Framework/MDEvents/CMakeLists.txt
index 50c76ba390b..0c8bf1af8bc 100644
--- a/Code/Mantid/Framework/MDEvents/CMakeLists.txt
+++ b/Code/Mantid/Framework/MDEvents/CMakeLists.txt
@@ -80,7 +80,7 @@ set ( GMOCK_TEST_FILES
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(MDEvents SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(MDEvents SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Add the target for this directory
diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/BoxController.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/BoxController.h
index 51cbf949dd1..fa6446bf45d 100644
--- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/BoxController.h
+++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/BoxController.h
@@ -38,6 +38,7 @@ namespace MDEvents
       m_maxDepth = 5;
       m_addingEvents_eventsPerTask = 1000;
       m_addingEvents_numTasksPerBlock = Kernel::ThreadPool::getNumPhysicalCores() * 5;
+      m_splitInto.resize(this->nd, 1);
       resetNumBoxes();
     }
 
@@ -303,6 +304,7 @@ namespace MDEvents
       m_numMDBoxes.resize(m_maxDepth + 1, 0); // Reset to 0
       m_numMDGridBoxes.resize(m_maxDepth + 1, 0); // Reset to 0
       m_numMDBoxes[0] = 1; // Start at 1 at depth 0.
+      resetMaxNumBoxes(); // Also the maximums
       m_mutexNumMDBoxes.unlock();
     }
 
diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/IMDBox.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/IMDBox.h
index 778f2d1bb87..c165a5a2d89 100644
--- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/IMDBox.h
+++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/IMDBox.h
@@ -4,6 +4,7 @@
 #include "MantidAPI/IMDWorkspace.h"
 #include "MantidKernel/System.h"
 #include "MantidMDEvents/BoxController.h"
+#include "MantidMDEvents/CoordTransform.h"
 #include "MantidMDEvents/MDBin.h"
 #include "MantidMDEvents/MDDimensionExtents.h"
 #include "MantidMDEvents/MDEvent.h"
@@ -96,6 +97,9 @@ namespace MDEvents
      */
     virtual void centerpointBin(MDBin<MDE,nd> & bin, bool * fullyContained) const = 0;
 
+    /** Sphere (peak) integration */
+    virtual void integrateSphere(CoordTransform & radiusTransform, const CoordType radiusSquared, double & signal, double & errorSquared) const = 0;
+
     // -------------------------------------------------------------------------------------------
     /** Split sub-boxes, if this is possible and neede for this box */
     virtual void splitAllIfNeeded(Mantid::Kernel::ThreadScheduler * /*ts*/ = NULL)
@@ -151,6 +155,16 @@ namespace MDEvents
       return extents[dim];
     }
 
+    //-----------------------------------------------------------------------------------------------
+    /** Get the center of the box
+     * @param center :: bare array of size[nd] that will get set with the mid-point of each dimension.
+     */
+    void getCenter(CoordType * center) const
+    {
+      for (size_t d=0; d<nd; ++d)
+        center[d] = (extents[d].max + extents[d].min) / 2.0;
+    }
+
     //-----------------------------------------------------------------------------------------------
     /** Compute the volume of the box by simply multiplying each dimension range.
      * Call this after setExtents() is set for all dimensions.
@@ -221,21 +235,21 @@ namespace MDEvents
     /** For testing, mostly: return the recursion depth of this box.
      * e.g. 1: means this box is in a MDGridBox, which is the top level.
      *      2: this box's parent MDGridBox is itself a MDGridBox. */
-    size_t getDepth()
+    size_t getDepth() const
     {
       return m_depth;
     }
 
     //-----------------------------------------------------------------------------------------------
     /** Return the volume of the cell */
-    double getVolume()
+    double getVolume() const
     {
       return 1.0 / m_inverseVolume;
     }
 
     //-----------------------------------------------------------------------------------------------
     /** Return the inverse of the volume of the cell */
-    double getInverseVolume()
+    double getInverseVolume() const
     {
       return m_inverseVolume;
     }
diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDBox.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDBox.h
index 0914ea280dd..d4e6a914d74 100644
--- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDBox.h
+++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDBox.h
@@ -61,6 +61,8 @@ namespace MDEvents
 
     void calculateDimensionStats(MDDimensionStats * stats) const;
 
+    void integrateSphere(CoordTransform & radiusTransform, const CoordType radiusSquared, double & signal, double & errorSquared) const;
+
 //    void runMDBoxTask(MDBoxTask<MDE,nd> * task, const bool fullyContained);
 
   protected:
diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEWPeakIntegration.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEWPeakIntegration.h
index e608307f129..8f357793e59 100644
--- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEWPeakIntegration.h
+++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEWPeakIntegration.h
@@ -1,8 +1,11 @@
 #ifndef MANTID_MDEVENTS_MDEWPEAKINTEGRATION_H_
 #define MANTID_MDEVENTS_MDEWPEAKINTEGRATION_H_
     
-#include "MantidKernel/System.h"
 #include "MantidAPI/Algorithm.h" 
+#include "MantidAPI/IMDEventWorkspace.h"
+#include "MantidDataObjects/PeaksWorkspace.h"
+#include "MantidKernel/System.h"
+#include "MantidMDEvents/MDEventWorkspace.h"
 
 namespace Mantid
 {
@@ -35,6 +38,14 @@ namespace MDEvents
     /// Run the algorithm
     void exec();
 
+    template<typename MDE, size_t nd>
+    void integrate(typename MDEventWorkspace<MDE, nd>::sptr ws);
+
+    /// Input MDEventWorkspace
+    Mantid::API::IMDEventWorkspace_sptr inWS;
+
+    /// Peak workspace to integrate
+    Mantid::DataObjects::PeaksWorkspace_sptr peakWS;
 
   };
 
diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEvent.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEvent.h
index c54019c167f..2f13cbbb80b 100644
--- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEvent.h
+++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEvent.h
@@ -132,6 +132,15 @@ namespace MDEvents
       return center[n];
     }
 
+    //---------------------------------------------------------------------------------------------
+    /** Returns the array of coordinates
+     * @return pointer to the fixed-size array.
+     * */
+    const CoordType * getCenter() const
+    {
+      return center;
+    }
+
     //---------------------------------------------------------------------------------------------
     /** Sets the n-th coordinate axis value.
      * @param n :: index (0-based) of the dimension you want to set
diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventFactory.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventFactory.h
index f77e8b7d432..8e952c3560c 100644
--- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventFactory.h
+++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventFactory.h
@@ -32,9 +32,19 @@ namespace MDEvents
   //### BEGIN AUTO-GENERATED CODE #################################################################
   
   /** Macro that makes it possible to call a templated method for
-   * a MDEventWorkspace using a IMDEventWorkspace_sptr as the input.
-   * @param funcname :: name of the function that will be called.
-   * @param workspace :: IMDEventWorkspace_sptr input workspace.
+    a MDEventWorkspace using a IMDEventWorkspace_sptr as the input.
+
+    The function should be declared in this way:
+
+    template<typename MDE, size_t nd>
+    void Algorithm::MyFunctionName(typename MDEventWorkspace<MDE, nd>::sptr ws)
+
+    ... which you the call with
+
+    CALL_MDEVENT_FUNCTION(this->MyFunctionName, imdEventWorkspace)
+
+    @param funcname :: name of the function that will be called.
+    @param workspace :: IMDEventWorkspace_sptr input workspace.
    */
    
   #define CALL_MDEVENT_FUNCTION(funcname, workspace) \
diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventWorkspace.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventWorkspace.h
index ee37ddb25d9..133190b66ce 100644
--- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventWorkspace.h
+++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventWorkspace.h
@@ -4,13 +4,15 @@
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/IMDWorkspace.h"
 #include "MantidAPI/ImplicitFunction.h"
+#include "MantidDataObjects/Peak.h"
 #include "MantidKernel/ProgressBase.h"
 #include "MantidKernel/System.h"
 #include "MantidMDEvents/BoxController.h"
+#include "MantidMDEvents/BoxController.h"
+#include "MantidMDEvents/CoordTransform.h"
 #include "MantidMDEvents/IMDBox.h"
 #include "MantidMDEvents/MDEvent.h"
 #include "MantidMDEvents/MDGridBox.h"
-#include "MantidMDEvents/BoxController.h"
 #include "MantidMDEvents/MDHistoWorkspace.h"
 
 namespace Mantid
@@ -91,14 +93,18 @@ namespace MDEvents
       return (dynamic_cast<MDGridBox<MDE,nd> *>(data) != NULL);
     }
 
-    /** Returns a pointer to the box (MDBox or MDGridBox) contained
-     * within.
-     */
+    /** Returns a pointer to the box (MDBox or MDGridBox) contained within, */
     IMDBox<MDE,nd> * getBox()
     {
       return data;
     }
 
+    /** Returns a pointer to the box (MDBox or MDGridBox) contained within, const version.  */
+    const IMDBox<MDE,nd> * getBox() const
+    {
+      return data;
+    }
+
 
   protected:
 
@@ -108,15 +114,6 @@ namespace MDEvents
     /// Box controller in use
     BoxController_sptr m_BoxController;
 
-
-    //    /** Typedef of the basic MDEvent data type used in this MDEventWorkspace.
-    //     * This is for convenience; an algorithm can declare
-    //     *  MyWorkspace::Event someEvent;
-    //     * without having to look up template parameters...
-    //     */
-    //    //typedef MDEvent<nd> Event;
-
-
   public:
     /// Typedef for a shared pointer of this kind of event workspace
     typedef boost::shared_ptr<MDEventWorkspace<MDE, nd> > sptr;
diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDGridBox.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDGridBox.h
index 864aba8c5d1..8b4a351a290 100644
--- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDGridBox.h
+++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDGridBox.h
@@ -59,6 +59,8 @@ namespace MDEvents
 
     void centerpointBin(MDBin<MDE,nd> & bin, bool * fullyContained) const;
 
+    void integrateSphere(CoordTransform & radiusTransform, const CoordType radiusSquared, double & signal, double & errorSquared) const;
+
     void splitContents(size_t index, Kernel::ThreadScheduler * ts = NULL);
 
     void splitAllIfNeeded(Kernel::ThreadScheduler * ts = NULL);
@@ -101,6 +103,10 @@ namespace MDEvents
     /// Size of each box size in the i^th dimension
     CoordType boxSize[nd];
 
+    /** Length (squared) of the diagonal through every dimension = sum( boxSize[i]^2 )
+     * Used in some calculations like peak integration */
+    CoordType diagonalSquared;
+
     /// Cached number of points contained (including all sub-boxes)
     size_t nPoints;
 
diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDSplitBox.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDSplitBox.h
index 58018b8241d..a5b3376bcab 100644
--- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDSplitBox.h
+++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDSplitBox.h
@@ -54,6 +54,8 @@ namespace MDEvents
 
     virtual void centerpointBin(MDBin<MDE,nd> & bin, bool * fullyContained) const;
 
+    void integrateSphere(CoordTransform & /*radiusTransform*/, const CoordType /*radiusSquared*/, double & /*signal*/, double & /*errorSquared*/) const
+    { throw std::runtime_error("Not implemented."); }
 
     // --------------------------------------------------------------------------------------------
 
diff --git a/Code/Mantid/Framework/MDEvents/src/FakeMDEventData.cpp b/Code/Mantid/Framework/MDEvents/src/FakeMDEventData.cpp
index 7bcf92505db..f877a083ab2 100644
--- a/Code/Mantid/Framework/MDEvents/src/FakeMDEventData.cpp
+++ b/Code/Mantid/Framework/MDEvents/src/FakeMDEventData.cpp
@@ -40,8 +40,8 @@ namespace MDEvents
   /// Sets documentation strings for this algorithm
   void FakeMDEventData::initDocs()
   {
-    this->setWikiSummary("Adds fake multi-dimensional event data to a MDEventWorkspace, for use in testing.");
-    this->setOptionalMessage("Adds fake multi-dimensional event data to a MDEventWorkspace, for use in testing.");
+    this->setWikiSummary("Adds fake multi-dimensional event data to an existing MDEventWorkspace, for use in testing.\nYou can create a blank MDEventWorkspace with CreateMDEventWorkspace.");
+    this->setOptionalMessage("Adds fake multi-dimensional event data to an existing MDEventWorkspace, for use in testing.\nYou can create a blank MDEventWorkspace with CreateMDEventWorkspace.");
   }
 
 
diff --git a/Code/Mantid/Framework/MDEvents/src/MDBox.cpp b/Code/Mantid/Framework/MDEvents/src/MDBox.cpp
index f5dabbc3f18..ef4d9482249 100644
--- a/Code/Mantid/Framework/MDEvents/src/MDBox.cpp
+++ b/Code/Mantid/Framework/MDEvents/src/MDBox.cpp
@@ -195,15 +195,37 @@ namespace MDEvents
     }
   }
 
-//
-//  //-----------------------------------------------------------------------------------------------
-//  /** Run a MDBox task inside this box */
-//  TMDE(
-//  void MDBox)::runMDBoxTask(MDBoxTask<MDE,nd> * task, const bool fullyContained)
-//  {
-//    // Fully evaluate this MD Box
-//    task->evaluateMDBox(this, fullyContained);
-//  }
+
+  /** Integrate the signal within a sphere; for example, to perform single-crystal
+   * peak integration.
+   * The CoordTransform object could be used for more complex shapes, e.g. "lentil" integration, as long
+   * as it reduces the dimensions to a single value.
+   *
+   * @param radiusTransform :: nd-to-1 coordinate transformation that converts from these
+   *        dimensions to the distance (squared) from the center of the sphere.
+   * @param radiusSquared :: radius^2 below which to integrate
+   * @param[out] signal :: set to the integrated signal
+   * @param[out] errorSquared :: set to the integrated squared error.
+   */
+  TMDE(
+  void MDBox)::integrateSphere(CoordTransform & radiusTransform, const CoordType radiusSquared, double & signal, double & errorSquared) const
+  {
+    typename std::vector<MDE>::const_iterator it = data.begin();
+    typename std::vector<MDE>::const_iterator it_end = data.end();
+
+    // For each MDEvent
+    for (; it != it_end; ++it)
+    {
+      CoordType out[nd];
+      radiusTransform.apply(it->getCenter(), out);
+      if (out[0] < radiusSquared)
+      {
+        signal += it->getSignal();
+        errorSquared += it->getErrorSquared();
+      }
+    }
+  }
+
 
 }//namespace MDEvents
 
diff --git a/Code/Mantid/Framework/MDEvents/src/MDEWPeakIntegration.cpp b/Code/Mantid/Framework/MDEvents/src/MDEWPeakIntegration.cpp
index 153879ce927..65687e1fe91 100644
--- a/Code/Mantid/Framework/MDEvents/src/MDEWPeakIntegration.cpp
+++ b/Code/Mantid/Framework/MDEvents/src/MDEWPeakIntegration.cpp
@@ -1,5 +1,9 @@
-#include "MantidMDEvents/MDEWPeakIntegration.h"
+#include "MantidAPI/IMDEventWorkspace.h"
+#include "MantidDataObjects/PeaksWorkspace.h"
 #include "MantidKernel/System.h"
+#include "MantidMDEvents/MDEventFactory.h"
+#include "MantidMDEvents/MDEWPeakIntegration.h"
+#include "MantidMDEvents/CoordTransformDistance.h"
 
 namespace Mantid
 {
@@ -11,6 +15,9 @@ namespace MDEvents
   
   using namespace Mantid::Kernel;
   using namespace Mantid::API;
+  using namespace Mantid::MDEvents;
+  using namespace Mantid::DataObjects;
+  using namespace Mantid::Geometry;
 
 
   //----------------------------------------------------------------------------------------------
@@ -41,8 +48,46 @@ namespace MDEvents
    */
   void MDEWPeakIntegration::init()
   {
-    declareProperty(new WorkspaceProperty<>("InputWorkspace","",Direction::Input), "An input MDEventWorkspace.");
-    declareProperty(new WorkspaceProperty<>("OutputWorkspace","",Direction::Output), "An output workspace.");
+    declareProperty(new WorkspaceProperty<IMDEventWorkspace>("InputWorkspace","",Direction::Input), "An input MDEventWorkspace.");
+    declareProperty(new WorkspaceProperty<PeaksWorkspace>("PeaksWorkspace","",Direction::InOut),
+        "A PeaksWorkspace containing the peaks to integrate. The peaks' integrated intensities will be updated"
+        "with the new values.");
+  }
+
+  //----------------------------------------------------------------------------------------------
+  template<typename MDE, size_t nd>
+  void MDEWPeakIntegration::integrate(typename MDEventWorkspace<MDE, nd>::sptr ws)
+  {
+    if (nd != 3)
+      throw std::invalid_argument("For now, we expect the input MDEventWorkspace to have 3 dimensions only.");
+
+    for (int i=0; i < int(peakWS->getNumberPeaks()); ++i)
+    {
+      // Get a direct ref to that peak.
+      Peak & p = peakWS->getPeak(i);
+
+      // Convert to a position in the dimensions of the workspace
+      V3D pos = p.getQLabFrame();
+
+      // Build the sphere transformation
+      bool dimensionsUsed[nd];
+      CoordType center[nd];
+      for (size_t d=0; d<nd; ++d)
+      {
+        dimensionsUsed[d] = true; // Use all dimensions
+        center[d] = pos[d];
+      }
+      CoordTransformDistance sphere(nd, center, dimensionsUsed);
+
+      // TODO: Determine a radius that makes sense!
+      CoordType radius = 1.0;
+
+      // Perform the integration into whatever box is contained within.
+      double signal = 0;
+      double errorSquared = 0;
+      ws->getBox()->integrateSphere(sphere, radius*radius, signal, errorSquared);
+    }
+
   }
 
   //----------------------------------------------------------------------------------------------
@@ -50,7 +95,10 @@ namespace MDEvents
    */
   void MDEWPeakIntegration::exec()
   {
-    // TODO Auto-generated execute stub
+    inWS = getProperty("InputWorkspace");
+//    peakWS = getProperty("PeaksWorkspace");
+
+    CALL_MDEVENT_FUNCTION(this->integrate, inWS);
   }
 
 
diff --git a/Code/Mantid/Framework/MDEvents/src/MDEventWorkspace.cpp b/Code/Mantid/Framework/MDEvents/src/MDEventWorkspace.cpp
index db3e3dd8662..745d58fc7b0 100644
--- a/Code/Mantid/Framework/MDEvents/src/MDEventWorkspace.cpp
+++ b/Code/Mantid/Framework/MDEvents/src/MDEventWorkspace.cpp
@@ -496,232 +496,6 @@ namespace MDEvents
 
 
 
-
-
-//  // =============================================================================================
-//  /** Task for creating MDBin's and integrating them.
-//   * Multitudes of these will be created by binToMDHistoWorkspace() to do a
-//   * dense histogram bin.
-//   */
-//  TMDE_CLASS
-//  class MDEventWorkspaceCenterpointBinTask : public Task
-//  {
-//  public:
-//    /** Constructor
-//     *
-//     * @param inBox :: pointer to the INPUT MDBox containing MDEvents
-//     * @param outWS :: pointer to the OUTPUT MDHistoWorkspace containing the result
-//     * @param binDimensions :: vector of MDHistoDimensions giving the dimension
-//     *        of the OUTPUT MDHistoWorkspace.
-//     * @param dimensionToBinFrom :: vector where dimensionToBinFrom[n] =
-//     *        the dimension in the INPUT MDEventWorkspace that goes to the nth dimension in the OUTPUT MDHistoWorkspace.
-//     * @param linearIndexStart :: Start generating bins at this linear index of the output workspace.
-//     * @param linearIndexStop :: Stop generating bins before this linear index.
-//     * @param index_max :: array of the maximum index in each OUTPUT dimension.
-//     * @param index_maker :: linear index maker array (from Utils::nestedForLoop)
-//     * @param implicitFunction :: limiting implicit function, can be NULL
-//     */
-//    MDEventWorkspaceCenterpointBinTask(IMDBox<MDE,nd> * inBox,
-//        MDHistoWorkspace_sptr outWS,
-//        const std::vector<MDHistoDimension_sptr> & binDimensions,
-//        const std::vector<size_t> & dimensionToBinFrom,
-//        const size_t linearIndexStart, const size_t linearIndexStop,
-//        const size_t * index_max,
-//        const size_t * index_maker,
-//        const Mantid::API::ImplicitFunction * implicitFunction)
-//    :
-//      Task(), inBox(inBox), outWS(outWS),
-//      binDimensions(binDimensions),
-//      dimensionToBinFrom(dimensionToBinFrom),
-//      linearIndexStart(linearIndexStart),
-//      linearIndexStop(linearIndexStop),
-//      index_max(index_max),
-//      index_maker(index_maker),
-//      implicitFunction(implicitFunction)
-//    {
-//    }
-//
-//    /** - Make a certain number of MDBin's
-//     *  - Run the centerpointBinning.
-//     *  - Store the result in the output workspace. */
-//    void run()
-//    {
-//      // Number of output binning dimensions found
-//      size_t numBD = binDimensions.size();
-//      // Counter in each dimension
-//      size_t * index = Utils::nestedForLoopSetUp(numBD);
-//
-//      // Do each bin in this task
-//      for (size_t linear_index=linearIndexStart; linear_index<linearIndexStop; linear_index++)
-//      {
-//        // Get the index at each dimension for this bin.
-//        Utils::nestedForLoopGetIndicesFromLinearIndex(numBD, linear_index, index_maker, index_max, index);
-//
-//        // Construct the bin and its coordinates
-//        MDBin<MDE,nd> bin;
-//        for (size_t bd=0; bd<numBD; bd++)
-//        {
-//          // Index in this binning dimension (i_x, i_y, etc.)
-//          size_t idx = index[bd];
-//          // Dimension in the MDEventWorkspace
-//          size_t d = dimensionToBinFrom[bd];
-//          // Corresponding extents
-//          bin.m_min[d] = binDimensions[bd]->getX(idx);
-//          bin.m_max[d] = binDimensions[bd]->getX(idx+1);
-//        }
-//        bin.m_index = linear_index;
-//
-//        // Check if the bin is in the ImplicitFunction (if any)
-//        bool binContained = true;
-//        if (implicitFunction)
-//        {
-//          binContained = implicitFunction->evaluate(makePoint3D(bin));
-//        }
-//
-//        if (binContained)
-//        {
-//          // Array of bools set to true when a dimension is fully contained (binary splitting only)
-//          bool fullyContained[nd];
-//          for (size_t d=0; d<nd; d++)
-//            fullyContained[d] = false;
-//
-//          // This will recursively bin into the sub grids
-//          inBox->centerpointBin(bin, fullyContained);
-//
-//          // Save the data into the dense histogram
-//          outWS->setSignalAt(linear_index, bin.m_signal);
-//          outWS->setErrorAt(linear_index, bin.m_errorSquared);
-//        }
-//
-//      } // (for each linear index)
-//
-//      // Cleanup
-//      delete [] index;
-//
-//    }
-//
-//  private:
-//    /// pointer to the MDBox containing MDEvents
-//    IMDBox<MDE,nd> * inBox;
-//    /// pointer to the MDHistoWorkspace containing the result
-//    MDHistoWorkspace_sptr outWS;
-//    const std::vector<MDHistoDimension_sptr> & binDimensions;
-//    const std::vector<size_t> & dimensionToBinFrom;
-//    const size_t linearIndexStart;
-//    const size_t linearIndexStop;
-//    const size_t * index_max;
-//    const size_t * index_maker;
-//    const Mantid::API::ImplicitFunction * implicitFunction;
-//
-//  };
-//
-//
-//  //-----------------------------------------------------------------------------------------------
-//  /** Bin a MDEventWorkspace into a dense histogram in a MDHistoWorkspace, using the MDBox's
-//   * centerpointBin routine.
-//   * You must give 4 dimensions, with names matching those in the MDEventWorkspace.
-//   *
-//   * @param dimX :: X dimension binning parameters
-//   * @param dimY :: Y dimension binning parameters
-//   * @param dimZ :: Z dimension binning parameters
-//   * @param dimT :: T (time) dimension binning parameters
-//   * @param implicitFunction :: a ImplicitFunction defining which bins to calculate. NULL if all bins will be calculated.
-//   * @param prog :: Progress reporter, can be NULL.
-//   * @return a shared ptr to MDHistoWorkspace created.
-//   */
-//  TMDE(
-//  IMDWorkspace_sptr MDEventWorkspace)::centerpointBinToMDHistoWorkspace(Mantid::Geometry::MDHistoDimension_sptr dimX, Mantid::Geometry::MDHistoDimension_sptr dimY,
-//      Mantid::Geometry::MDHistoDimension_sptr dimZ, Mantid::Geometry::MDHistoDimension_sptr dimT,
-//      Mantid::API::ImplicitFunction * implicitFunction, Mantid::Kernel::ProgressBase * prog) const
-//  {
-//    bool DODEBUG = true;
-//    CPUTimer tim;
-//
-//    // Create the dense histogram. This allocates the memory
-//    MDHistoWorkspace_sptr ws(new MDHistoWorkspace(dimX, dimY, dimZ, dimT));
-//
-//    if (DODEBUG) std::cout << tim << " to create the MDHistoWorkspace.\n";
-//
-//    // Make it into a vector of dimensions to which to bin.
-//    std::vector<MDHistoDimension_sptr> binDimensionsIn;
-//    binDimensionsIn.push_back(dimX);
-//    binDimensionsIn.push_back(dimY);
-//    binDimensionsIn.push_back(dimZ);
-//    binDimensionsIn.push_back(dimT);
-//
-//    // Thin it down for invalid dimensions
-//    std::vector<MDHistoDimension_sptr> binDimensions;
-//    std::vector<size_t> dimensionToBinFrom;
-//    for (size_t i = 0; i < binDimensionsIn.size(); ++i)
-//    {
-//      if (binDimensionsIn[i]->getNBins() == 0)
-//        throw std::runtime_error("Dimension " + binDimensionsIn[i]->getName() + " was set to have 0 bins. Cannot continue.");
-//
-//      try {
-//        size_t dim_index = this->getDimensionIndexByName(binDimensionsIn[i]->getName());
-//        dimensionToBinFrom.push_back(dim_index);
-//        binDimensions.push_back(binDimensionsIn[i]);
-//      }
-//      catch (std::runtime_error & e)
-//      {
-//        // The dimension was not found, so we are not binning across it. TODO: Log message?
-//        if (binDimensionsIn[i]->getNBins() > 1)
-//          throw std::runtime_error("Dimension " + binDimensionsIn[i]->getName() + " was not found in the MDEventWorkspace and has more than one bin! Cannot continue.");
-//      }
-//    }
-//    // Number of output binning dimensions found
-//    size_t numBD = binDimensions.size();
-//
-//    if (numBD == 0)
-//      throw std::runtime_error("No output dimensions were found in the MDEventWorkspace. Cannot bin!");
-//
-//    if (DODEBUG) std::cout << tim << " to cache the binning results.\n";
-//
-//    //Since the costs are not known ahead of time, use a simple FIFO buffer.
-//    ThreadScheduler * ts = new ThreadSchedulerFIFO();
-//
-//    // Create the threadpool with: all CPUs, a progress reporter
-//    ThreadPool tp(ts, 0, prog);
-//
-//    // Big efficiency gain is obtained by grouping a few bins per task.
-//    size_t binsPerTask = 100;
-//
-//    // For progress reporting, the approx  # of tasks
-//    if (prog)
-//      prog->setNumSteps( int(ws->getNPoints() / binsPerTask) );
-//
-//    // This is the limit to loop over in each dimension
-//    size_t * index_max = Utils::nestedForLoopSetUp(numBD);
-//    for (size_t bd=0; bd<numBD; bd++) index_max[bd] = binDimensions[bd]->getNBins();
-//    // Cache a calculation to convert indices x,y,z,t into a linear index.
-//    size_t * index_maker = Utils::nestedForLoopSetUpIndexMaker(numBD, index_max);
-//
-//    // Set up a bunch of tasks
-//    size_t numPoints = ws->getNPoints();
-//    for (size_t start=0; start < numPoints; start += binsPerTask)
-//    {
-//      size_t stop = start + binsPerTask;
-//      if (stop > numPoints) stop = numPoints;
-//      ts->push(  new MDEventWorkspaceCenterpointBinTask<MDE,nd>(data, ws, binDimensions,
-//                        dimensionToBinFrom, start, stop, index_max, index_maker, implicitFunction) );
-//    }
-//
-//    if (DODEBUG) std::cout << tim << " to fill up the ThreadPool with all the tasks\n";
-//
-//    // OK, all that was just to fill the ThreadScheduler
-//    // So now we actually run these.
-//    tp.joinAll();
-//
-//    if (DODEBUG) std::cout << tim << " to run all the tasks\n";
-//
-//    delete index_max;
-//    delete index_maker;
-//    return ws;
-//  }
-//
-
-
-
 }//namespace MDEvents
 
 }//namespace Mantid
diff --git a/Code/Mantid/Framework/MDEvents/src/MDGridBox.cpp b/Code/Mantid/Framework/MDEvents/src/MDGridBox.cpp
index bd259dfb764..5140debc4e8 100644
--- a/Code/Mantid/Framework/MDEvents/src/MDGridBox.cpp
+++ b/Code/Mantid/Framework/MDEvents/src/MDGridBox.cpp
@@ -48,6 +48,7 @@ namespace MDEvents
     // Do some computation based on how many splits per each dim.
     size_t tot = 1;
     double volume = 1;
+    diagonalSquared = 0;
     for (size_t d=0; d<nd; d++)
     {
       // Cumulative multiplier, for indexing
@@ -57,6 +58,9 @@ namespace MDEvents
       tot *= split[d];
       // Length of the side of a box in this dimension
       boxSize[d] = (this->extents[d].max - this->extents[d].min) / double(split[d]);
+      // Accumulate the squared diagonal length.
+      diagonalSquared += boxSize[d] * boxSize[d];
+      // Calculate the volume
       volume *= boxSize[d];
     }
 
@@ -531,6 +535,158 @@ namespace MDEvents
   }
 
 
+  /** Integrate the signal within a sphere; for example, to perform single-crystal
+   * peak integration.
+   * The CoordTransform object could be used for more complex shapes, e.g. "lentil" integration, as long
+   * as it reduces the dimensions to a single value.
+   *
+   * @param radiusTransform :: nd-to-1 coordinate transformation that converts from these
+   *        dimensions to the distance (squared) from the center of the sphere.
+   * @param radiusSquared :: radius^2 below which to integrate
+   * @param[out] signal :: set to the integrated signal
+   * @param[out] errorSquared :: set to the integrated squared error.
+   */
+  TMDE(
+  void MDGridBox)::integrateSphere(CoordTransform & radiusTransform, const CoordType radiusSquared, double & signal, double & errorSquared) const
+  {
+    // We start by looking at the vertices at every corner of every box contained,
+    // to see which boxes are partially contained/fully contained.
+
+    // One entry with the # of vertices in this box contained; start at 0.
+    size_t * verticesContained = new size_t[numBoxes];
+    memset( verticesContained, 0, numBoxes * sizeof(size_t) );
+
+    // Set to true if there is a possibility of the box at least partly touching the integration volume.
+    bool * boxMightTouch = new bool[numBoxes];
+    memset( boxMightTouch, 0, numBoxes * sizeof(bool) );
+
+    // How many vertices does one box have? 2^nd, or bitwise shift left 1 by nd bits
+    size_t maxVertices = 1 << nd;
+
+    // The number of vertices in each dimension is the # split[d] + 1
+    size_t * vertices_max = Utils::nestedForLoopSetUp(nd, 0);
+    for (size_t d=0; d<nd; ++d)
+      vertices_max[d] = split[d]+1;
+
+    // The index to the vertex in each dimension
+    size_t * vertexIndex = Utils::nestedForLoopSetUp(nd, 0);
+    size_t * boxIndex = Utils::nestedForLoopSetUp(nd, 0);
+    size_t * indexMaker = Utils::nestedForLoopSetUpIndexMaker(nd, split);
+
+    bool allDone = false;
+    while (!allDone)
+    {
+      // Coordinates of this vertex
+      CoordType vertexCoord[nd];
+      for (size_t d=0; d<nd; ++d)
+        vertexCoord[d] = double(vertexIndex[d]) * boxSize[d];
+
+      // Is this vertex contained?
+      CoordType out[nd];
+      radiusTransform.apply(vertexCoord, out);
+      if (out[0] < radiusSquared)
+      {
+        // Yes, this vertex is contained within the integration volume!
+        //std::cout << "vertex at " << vertexCoord[0] << ", " << vertexCoord[1] << " is contained\n";
+
+        // This vertex is shared by up to 2^nd adjacent boxes (left-right along each dimension).
+        for (size_t neighb=0; neighb<maxVertices; ++neighb)
+        {
+          // The index of the box is the same as the vertex, but maybe - 1 in each possible combination of dimensions
+          bool badIndex = false;
+          // Build the index of the neighbor
+          for (size_t d=0; d<nd;d++)
+          {
+            boxIndex[d] = vertexIndex[d] - ((neighb & (1 << d)) >> d); //(this does a bitwise and mask, shifted back to 1 to subtract 1 to the dimension)
+            // Taking advantage of the fact that unsigned(0)-1 = some large POSITIVE number.
+            if (boxIndex[d] >= split[d])
+            {
+              badIndex = true;
+              break;
+            }
+          }
+          if (!badIndex)
+          {
+            // Convert to linear index
+            size_t linearIndex = Utils::nestedForLoopGetLinearIndex(nd, boxIndex, indexMaker);
+            // So we have one more vertex touching this box that is contained in the integration volume. Whew!
+            verticesContained[linearIndex]++;
+          }
+        }
+      }
+
+      // Increment the counter(s) in the nested for loops.
+      allDone = Utils::nestedForLoopIncrement(nd, vertexIndex, vertices_max);
+    }
+
+    // OK, we've done all the vertices. Now we go through and check each box.
+    size_t numFullyContained = 0;
+    size_t numPartiallyContained = 0;
+
+    for (size_t i=0; i < numBoxes; ++i)
+    {
+      IMDBox<MDE, nd> * box = boxes[i];
+      // Box partially contained?
+      bool partialBox = false;
+
+      // Is this box fully contained?
+      if (verticesContained[i] >= maxVertices)
+      {
+        //std::cout << "box at " << i << " is fully contained\n";
+        // Use the integrated sum of signal in the box
+        signal += box->getSignal();
+        errorSquared += box->getErrorSquared();
+        numFullyContained++;
+        // Go on to the next box
+        continue;
+      }
+
+      if (verticesContained[i] == 0)
+      {
+        // There is a chance that this part of the box is within integration volume,
+        // even if no vertex of it is.
+
+        IMDBox<MDE, nd> * box = boxes[i];
+        CoordType boxCenter[nd];
+        box->getCenter(boxCenter);
+
+        // Distance from center to the peak integration center
+        CoordType out[nd];
+        radiusTransform.apply(boxCenter, out);
+
+        if (out[0] < diagonalSquared*0.72 + radiusSquared)
+        {
+          // If the center is closer than the size of the box, then it MIGHT be touching.
+          // (We multiply by 0.72 (about sqrt(2)) to look for half the diagonal).
+          // NOTE! Watch out for non-spherical transforms!
+          //std::cout << "box at " << i << " is maybe touching\n";
+          partialBox = true;
+        }
+      }
+      else
+      {
+        partialBox = true;
+        //std::cout << "box at " << i << " has a vertex touching\n";
+      }
+
+      // We couldn't rule out that the box might be partially contained.
+      if (partialBox)
+      {
+        // Use the detailed integration method.
+        box->integrateSphere(radiusTransform, radiusSquared, signal, errorSquared);
+        numPartiallyContained++;
+      }
+    } // (for each box)
+
+//    std::cout << "Depth " << this->getDepth() << " with " << numFullyContained << " fully contained; " << numPartiallyContained << " partial.\n";
+
+    delete [] verticesContained;
+    delete [] boxMightTouch;
+    delete [] vertexIndex;
+    delete [] vertices_max;
+    delete [] boxIndex;
+    delete [] indexMaker;
+  }
 
 
 //
diff --git a/Code/Mantid/Framework/MDEvents/test/BoxControllerTest.h b/Code/Mantid/Framework/MDEvents/test/BoxControllerTest.h
index 422dce05396..a18ac862e41 100644
--- a/Code/Mantid/Framework/MDEvents/test/BoxControllerTest.h
+++ b/Code/Mantid/Framework/MDEvents/test/BoxControllerTest.h
@@ -80,34 +80,52 @@ public:
     }
   }
 
-  void test_trackNumBoxes()
+
+
+  void doTest_numBoxes(BoxController & bc, size_t expectedNumEntries)
   {
-    BoxController sc(2);
-    sc.setSplitInto(10);
-    sc.setMaxDepth(4);
-    const std::vector<size_t> & num = sc.getNumMDBoxes();
-    TS_ASSERT_EQUALS( num.size(), 5);
+    const std::vector<size_t> & num = bc.getNumMDBoxes();
+    TS_ASSERT_EQUALS( num.size(), expectedNumEntries);
     TS_ASSERT_EQUALS( num[0], 1);
     TS_ASSERT_EQUALS( num[1], 0);
 
     // Average depth is 0 = all at level 0.
-    TS_ASSERT_DELTA( sc.getAverageDepth(), 0.0, 1e-5 );
+    TS_ASSERT_DELTA( bc.getAverageDepth(), 0.0, 1e-5 );
 
-    sc.trackNumBoxes(0);
+    bc.trackNumBoxes(0);
     TS_ASSERT_EQUALS( num[0], 0);
     TS_ASSERT_EQUALS( num[1], 100);
 
     // All at depth 1.0
-    TS_ASSERT_DELTA( sc.getAverageDepth(), 1.0, 1e-5 );
+    TS_ASSERT_DELTA( bc.getAverageDepth(), 1.0, 1e-5 );
 
-    sc.trackNumBoxes(1);
-    sc.trackNumBoxes(1);
+    bc.trackNumBoxes(1);
+    bc.trackNumBoxes(1);
     TS_ASSERT_EQUALS( num[0], 0);
     TS_ASSERT_EQUALS( num[1], 98);
     TS_ASSERT_EQUALS( num[2], 200);
 
     // Mostly at depth 1.0
-    TS_ASSERT_DELTA( sc.getAverageDepth(), 1.02, 1e-5 );
+    TS_ASSERT_DELTA( bc.getAverageDepth(), 1.02, 1e-5 );
+  }
+
+  /* Try setting these values in different orders */
+  void test_trackNumBoxes1()
+  {
+    BoxController bc(2);
+    bc.setSplitInto(10);
+    bc.setMaxDepth(4);
+    doTest_numBoxes(bc, 5);
+  }
+
+  /* This used to give wrong values */
+  void test_trackNumBoxes2()
+  {
+    BoxController bc(2);
+    bc.setMaxDepth(4);
+    bc.setSplitInto(10);
+    bc.setMaxDepth(10);
+    doTest_numBoxes(bc, 11);
   }
 
 
diff --git a/Code/Mantid/Framework/MDEvents/test/IMDBoxTest.h b/Code/Mantid/Framework/MDEvents/test/IMDBoxTest.h
index 70aceda53c1..00e5470918b 100644
--- a/Code/Mantid/Framework/MDEvents/test/IMDBoxTest.h
+++ b/Code/Mantid/Framework/MDEvents/test/IMDBoxTest.h
@@ -53,6 +53,8 @@ class IMDBoxTester : public IMDBox<MDE,nd>
   virtual void centerpointBin(MDBin<MDE,nd> & /*bin*/, bool * ) const
   {}
 
+  virtual void integrateSphere(CoordTransform & radiusTransform, const CoordType radiusSquared, double & signal, double & errorSquared) const {};
+
 };
 
 
@@ -78,19 +80,25 @@ public:
     TS_ASSERT_EQUALS( box.getErrorSquared(), 456.0);
   }
 
-  /** Setting and getting the extents */
+  /** Setting and getting the extents;
+   * also, getting the center */
   void test_setExtents()
   {
     IMDBoxTester<MDEvent<2>,2> b;
-    b.setExtents(0, -10.0, 10.0);
-    TS_ASSERT_DELTA(b.getExtents(0).min, -10.0, 1e-6);
+    b.setExtents(0, -8.0, 10.0);
+    TS_ASSERT_DELTA(b.getExtents(0).min, -8.0, 1e-6);
     TS_ASSERT_DELTA(b.getExtents(0).max, +10.0, 1e-6);
 
-    b.setExtents(1, -4.0, 6.0);
+    b.setExtents(1, -4.0, 12.0);
     TS_ASSERT_DELTA(b.getExtents(1).min, -4.0, 1e-6);
-    TS_ASSERT_DELTA(b.getExtents(1).max, +6.0, 1e-6);
+    TS_ASSERT_DELTA(b.getExtents(1).max, +12.0, 1e-6);
 
     TS_ASSERT_THROWS( b.setExtents(2, 0, 1.0), std::invalid_argument);
+
+    CoordType center[2];
+    b.getCenter(center);
+    TS_ASSERT_DELTA( center[0], +1.0, 1e-6);
+    TS_ASSERT_DELTA( center[1], +4.0, 1e-6);
   }
 
   void test_copy_constructor()
diff --git a/Code/Mantid/Framework/MDEvents/test/MDBoxTest.h b/Code/Mantid/Framework/MDEvents/test/MDBoxTest.h
index 99491de1725..6df47cfd059 100644
--- a/Code/Mantid/Framework/MDEvents/test/MDBoxTest.h
+++ b/Code/Mantid/Framework/MDEvents/test/MDBoxTest.h
@@ -9,6 +9,7 @@
 #include "MantidMDEvents/BoxController.h"
 #include <memory>
 #include <map>
+#include "MantidMDEvents/CoordTransformDistance.h"
 
 using namespace Mantid;
 using namespace Mantid::MDEvents;
@@ -215,6 +216,49 @@ public:
     TS_ASSERT_DELTA( bin.m_errorSquared, 6.0, 1e-4);
   }
 
+
+  /** For test_integrateSphere,
+   *
+   * @param box
+   * @param radius :: radius to integrate
+   * @param numExpected :: how many events should be in there
+   */
+  void dotest_integrateSphere(MDBox<MDEvent<3>,3> & box, CoordType x, CoordType y, CoordType z, const CoordType radius, double numExpected)
+  {
+    // The sphere transformation
+    bool dimensionsUsed[3] = {true,true,true};
+    CoordType center[3] = {x,y,z};
+    CoordTransformDistance sphere(3, center, dimensionsUsed);
+
+    double signal = 0;
+    double errorSquared = 0;
+    box.integrateSphere(sphere, radius*radius, signal, errorSquared);
+    TS_ASSERT_DELTA( signal, 1.0*numExpected, 1e-5);
+    TS_ASSERT_DELTA( errorSquared, 1.5*numExpected, 1e-5);
+  }
+
+  void test_integrateSphere()
+  {
+    // One event at each integer coordinate value between 1 and 9
+    MDBox<MDEvent<3>,3> box;
+    for (CoordType x=1.0; x < 10.0; x += 1.0)
+      for (CoordType y=1.0; y < 10.0; y += 1.0)
+        for (CoordType z=1.0; z < 10.0; z += 1.0)
+        {
+          MDEvent<3> ev(1.0, 1.5);
+          ev.setCenter(0, x);
+          ev.setCenter(1, y);
+          ev.setCenter(2, z);
+          box.addEvent(ev);
+        }
+
+    TS_ASSERT_EQUALS( box.getNPoints(), 9*9*9);
+
+    dotest_integrateSphere(box, 5.0,5.0,5.0,  0.5,   1.0);
+    dotest_integrateSphere(box, 0.5,0.5,0.5,  0.5,   0.0);
+    dotest_integrateSphere(box, 5.0,5.0,5.0,  1.1,   7.0);
+    dotest_integrateSphere(box, 5.0,5.0,5.0,  10., 9*9*9);
+  }
 };
 
 
diff --git a/Code/Mantid/Framework/MDEvents/test/MDEWPeakIntegrationTest.h b/Code/Mantid/Framework/MDEvents/test/MDEWPeakIntegrationTest.h
index ad6594789fb..456deb5e8a8 100644
--- a/Code/Mantid/Framework/MDEvents/test/MDEWPeakIntegrationTest.h
+++ b/Code/Mantid/Framework/MDEvents/test/MDEWPeakIntegrationTest.h
@@ -8,8 +8,10 @@
 #include <iomanip>
 
 #include "MantidMDEvents/MDEWPeakIntegration.h"
+#include "MantidAPI/IMDEventWorkspace.h"
 
 using namespace Mantid::MDEvents;
+using Mantid::API::IMDEventWorkspace_sptr;
 
 class MDEWPeakIntegrationTest : public CxxTest::TestSuite
 {
@@ -23,8 +25,14 @@ public:
     TS_ASSERT( alg.isInitialized() )
   }
   
-  void test_Something()
+  void test_exec()
   {
+//    IMDEventWorkspace_sptr inWS;
+
+    MDEWPeakIntegration alg;
+    TS_ASSERT_THROWS_NOTHING( alg.initialize() )
+    TS_ASSERT( alg.isInitialized() )
+//    TS_ASSERT_THROWS_NOTHING( alg.setProperty("InputWorkspace", inWS ) );
   }
 
 
diff --git a/Code/Mantid/Framework/MDEvents/test/MDEventTest.h b/Code/Mantid/Framework/MDEvents/test/MDEventTest.h
index 12fe4ef6eec..c80a9925379 100644
--- a/Code/Mantid/Framework/MDEvents/test/MDEventTest.h
+++ b/Code/Mantid/Framework/MDEvents/test/MDEventTest.h
@@ -78,6 +78,9 @@ public:
     TS_ASSERT_EQUALS( a.getCenter(0), 0.123);
     TS_ASSERT_EQUALS( a.getCenter(1), 1.234);
     TS_ASSERT_EQUALS( a.getCenter(2), 2.345);
+    TS_ASSERT_EQUALS( a.getCenter()[0], 0.123);
+    TS_ASSERT_EQUALS( a.getCenter()[1], 1.234);
+    TS_ASSERT_EQUALS( a.getCenter()[2], 2.345);
   }
 
   void test_setCenter_array()
diff --git a/Code/Mantid/Framework/MDEvents/test/MDEventWorkspaceTest.h b/Code/Mantid/Framework/MDEvents/test/MDEventWorkspaceTest.h
index df96b39a4ce..3bb33308256 100644
--- a/Code/Mantid/Framework/MDEvents/test/MDEventWorkspaceTest.h
+++ b/Code/Mantid/Framework/MDEvents/test/MDEventWorkspaceTest.h
@@ -7,6 +7,7 @@
 #include "MantidKernel/Timer.h"
 #include "MantidGeometry/MDGeometry/MDHistoDimension.h"
 #include "MantidMDEvents/BoxController.h"
+#include "MantidMDEvents/CoordTransformDistance.h"
 #include "MantidMDEvents/MDBox.h"
 #include "MantidMDEvents/MDEvent.h"
 #include "MantidMDEvents/MDEventFactory.h"
@@ -140,8 +141,8 @@ public:
 
     TS_ASSERT_THROWS_NOTHING( b->addManyEvents( events, prog ); );
     TS_ASSERT_EQUALS( b->getNPoints(), 100*num_repeat);
-    TS_ASSERT_EQUALS( b->getBox()->getSignal(), 100*num_repeat*2.0);
-    TS_ASSERT_EQUALS( b->getBox()->getErrorSquared(), 100*num_repeat*2.0);
+    TS_ASSERT_EQUALS( b->getBox()->getSignal(), 100*double(num_repeat)*2.0);
+    TS_ASSERT_EQUALS( b->getBox()->getErrorSquared(), 100*double(num_repeat)*2.0);
 
     box_t * gridBox = dynamic_cast<box_t *>(b->getBox());
     std::vector<IMDBox<MDEvent<2>,2>*> boxes = gridBox->getBoxes();
@@ -235,16 +236,16 @@ public:
       size_t expected_events_per_bin, bool unevenSizes = false)
   {
     size_t len = 10; // Make the box split into this many per size
-    double size = len * 1.0;  // Make each grid box 1.0 in size
+    double size = double(len) * 1.0;  // Make each grid box 1.0 in size
     size_t binlen = 5; // And bin more coarsely
 
     // 10x10x10 eventWorkspace
     MDEventWorkspace3::sptr ws = MDEventsHelper::makeMDEW<3>(len, 0.0, size);
 
     // Put one event per bin
-    for (size_t x=0; x<len; x++)
-      for (size_t y=0; y<len; y++)
-        for (size_t z=0; z<len; z++)
+    for (double x=0; x<len; x++)
+      for (double y=0; y<len; y++)
+        for (double z=0; z<len; z++)
         {
           CoordType centers[3] = {x+0.5,y+0.5,z+0.5};
           ws->addEvent( MDEvent<3>(1.0, 2.0, centers) );
@@ -283,8 +284,8 @@ public:
 
     for (size_t i=0; i < out->getNPoints(); i++)
     {
-      TS_ASSERT_DELTA( out->getSignalAt(i), expected_events_per_bin * 1.0, 1e-5 );
-      TS_ASSERT_DELTA( out->getErrorAt(i), expected_events_per_bin * 2.0, 1e-5 );
+      TS_ASSERT_DELTA( out->getSignalAt(i), double(expected_events_per_bin) * 1.0, 1e-5 );
+      TS_ASSERT_DELTA( out->getErrorAt(i), double(expected_events_per_bin) * 2.0, 1e-5 );
     }
 
 
@@ -317,6 +318,29 @@ public:
 //  }
 
 
+
+  void test_integrateSphere()
+  {
+    // 10x10x10 eventWorkspace
+    MDEventWorkspace3::sptr ws = MDEventsHelper::makeMDEW<3>(10, 0.0, 10.0, 1 /*event per box*/);
+    TS_ASSERT_EQUALS( ws->getNPoints(), 1000);
+
+    // The sphere transformation
+    CoordType center[3] = {0,0,0};
+    bool dimensionsUsed[3] = {true,true,true};
+    CoordTransformDistance sphere(3, center, dimensionsUsed);
+
+    double signal = 0;
+    double errorSquared = 0;
+    ws->getBox()->integrateSphere(sphere, 1.0, signal, errorSquared);
+
+    //TODO:
+//    TS_ASSERT_DELTA( signal, 1.0, 1e-5);
+//    TS_ASSERT_DELTA( errorSquared, 1.0, 1e-5);
+
+
+  }
+
 };
 
 #endif
diff --git a/Code/Mantid/Framework/MDEvents/test/MDEventsTestHelper.hh b/Code/Mantid/Framework/MDEvents/test/MDEventsTestHelper.hh
index b3015b9643b..32ee1245863 100644
--- a/Code/Mantid/Framework/MDEvents/test/MDEventsTestHelper.hh
+++ b/Code/Mantid/Framework/MDEvents/test/MDEventsTestHelper.hh
@@ -59,7 +59,7 @@ namespace MDEventsHelper
           // Put an event in the middle of each box
           Mantid::MDEvents::CoordType centers[nd];
           for (size_t d=0; d<nd; d++)
-            centers[d] = min + (index[d]+0.5)*(max-min)/splitInto;
+            centers[d] = min + (double(index[d])+0.5)*(max-min)/double(splitInto);
           out->addEvent( Mantid::MDEvents::MDEvent<nd>(1.0, 1.0, centers) );
         }
 
diff --git a/Code/Mantid/Framework/MDEvents/test/MDGridBoxTest.h b/Code/Mantid/Framework/MDEvents/test/MDGridBoxTest.h
index 63b7ec5cc58..ca383fc15aa 100644
--- a/Code/Mantid/Framework/MDEvents/test/MDGridBoxTest.h
+++ b/Code/Mantid/Framework/MDEvents/test/MDGridBoxTest.h
@@ -20,6 +20,7 @@
 #include <boost/random/uniform_int.hpp>
 #include <boost/random/uniform_real.hpp>
 #include <boost/random/variate_generator.hpp>
+#include "MantidMDEvents/CoordTransformDistance.h"
 
 using namespace Mantid;
 using namespace Mantid::Kernel;
@@ -75,25 +76,28 @@ public:
 
 
   //-------------------------------------------------------------------------------------
-  /** Generate an empty MDBox with nd dimensions, splitting in 10x10 boxes
+  /** Generate an empty MDBox with 2 dimensions, splitting in (default) 10x10 boxes.
+   * Box size is 10x10.
+   *
    * @param numEventsPerBox :: each sub-box will get this many events (all
-   *        placed in the middle of each sub-box.
+   *        placed in the middle of each sub-box, aka 0.5, 1.5, 2.5 etc.)
+   * @param split0, split1 :: for uneven splitting
    * */
-  template<size_t nd>
-  static MDGridBox<MDEvent<nd>,nd> * makeMDGridBox(size_t numEventsPerBox)
+  static MDGridBox<MDEvent<2>,2> * makeMDGridBox2(size_t numEventsPerBox, size_t split0=10, size_t split1=10)
   {
     // Split at 5 events
-    BoxController_sptr splitter(new BoxController(nd));
+    BoxController_sptr splitter(new BoxController(2));
     splitter->setSplitThreshold(5);
     // Splits into 10x10x.. boxes
-    splitter->setSplitInto(10);
+    splitter->setSplitInto(0, split0);
+    splitter->setSplitInto(1, split1);
     // Set the size to 10.0 in all directions
-    MDBox<MDEvent<nd>,nd> * box = new MDBox<MDEvent<nd>,nd>(splitter);
-    for (size_t d=0; d<nd; d++)
+    MDBox<MDEvent<2>,2> * box = new MDBox<MDEvent<2>,2>(splitter);
+    for (size_t d=0; d<2; d++)
       box->setExtents(d, 0.0, 10.0);
 
     // Split
-    MDGridBox<MDEvent<nd>,nd> * out = new MDGridBox<MDEvent<nd>,nd>(box);
+    MDGridBox<MDEvent<2>,2> * out = new MDGridBox<MDEvent<2>,2>(box);
 
     // Make an event in the middle of each box
     for (size_t i=0; i < numEventsPerBox; i++)
@@ -158,7 +162,7 @@ public:
     // Set the size to splitInto*1.0 in all directions
     MDBox<MDEvent<nd>,nd> * box = new MDBox<MDEvent<nd>,nd>(splitter);
     for (size_t d=0; d<nd; d++)
-      box->setExtents(d, 0.0, splitInto*1.0);
+      box->setExtents(d, 0.0, double(splitInto));
     // Split into the gridbox.
     MDGridBox<MDEvent<nd>,nd> * gridbox = new MDGridBox<MDEvent<nd>,nd>(box);
 
@@ -174,7 +178,7 @@ public:
   static std::vector<MDEvent<1> > makeMDEvents1(size_t num)
   {
     std::vector<MDEvent<1> > out;
-    for (size_t i=0; i<num; i++)
+    for (double i=0; i<num; i++)
     {
       CoordType coords[1] = {i*1.0+0.5};
       out.push_back( MDEvent<1>(1.0, 1.0, coords) );
@@ -244,12 +248,12 @@ public:
     for (size_t i=0; i<boxes.size(); i++)
     {
       MDBox<MDEvent<1>,1> * box = dynamic_cast<MDBox<MDEvent<1>,1> *>(boxes[i]);
-      TS_ASSERT_DELTA(box->getExtents(0).min, i*1.0, 1e-6);
-      TS_ASSERT_DELTA(box->getExtents(0).max, (i+1)*1.0, 1e-6);
+      TS_ASSERT_DELTA(box->getExtents(0).min, double(i)*1.0, 1e-6);
+      TS_ASSERT_DELTA(box->getExtents(0).max, double(i+1)*1.0, 1e-6);
       // Look at the single event in there
       TS_ASSERT_EQUALS(box->getNPoints(), 1);
       MDEvent<1> ev = box->getEvents()[0];
-      TS_ASSERT_DELTA(ev.getCenter(0), i*1.0 + 0.5, 1e-5);
+      TS_ASSERT_DELTA(ev.getCenter(0), double(i)*1.0 + 0.5, 1e-5);
       // Its depth level should be 1 (deeper than parent)
       TS_ASSERT_EQUALS(box->getDepth(), 1);
       // The volume was set correctly
@@ -306,7 +310,7 @@ public:
   /** Start with a grid box, split some of its contents into sub-gridded boxes. */
   void test_splitContents()
   {
-    MDGridBox<MDEvent<2>,2> * superbox = makeMDGridBox<2>(0);
+    MDGridBox<MDEvent<2>,2> * superbox = makeMDGridBox2(0);
     MDGridBox<MDEvent<2>,2> * gb;
     MDBox<MDEvent<2>,2> * b;
 
@@ -352,7 +356,7 @@ public:
     std::vector<IMDBox<MDEvent<2>,2>*> boxes;
 
     // 10x10 box, extents 0-10.0
-    MDGridBox<MDEvent<2>,2> * superbox = makeMDGridBox<2>(0);
+    MDGridBox<MDEvent<2>,2> * superbox = makeMDGridBox2(0);
     // And the 0-th box is further split (
     TS_ASSERT_THROWS_NOTHING(superbox->splitContents(0));
 
@@ -411,8 +415,8 @@ public:
     {
       std::cout << " --- Recursion Level " << recurseLevels << " --- " << std::endl;
       Timer tim1;
-      double boxes_per_side = pow(numSplit*1.0, recurseLevels*1.0);
-      double spacing = (numSplit*1.0)/boxes_per_side;
+      double boxes_per_side = pow(double(numSplit), double(recurseLevels));
+      double spacing = double(numSplit)/boxes_per_side;
       // How many times to add the same event
       size_t num_to_repeat = size_t(1e7 / (boxes_per_side*boxes_per_side));
 
@@ -433,7 +437,7 @@ public:
 
       double sec = tim1.elapsed();
       std::cout << sec << " seconds to add " << box->getNPoints() << " events. Each box had " << num_to_repeat << " events." << std::endl;
-      std::cout << "equals " << 1e6*sec/box->getNPoints() << " seconds per million events." << std::endl;
+      std::cout << "equals " << 1e6*sec/double(box->getNPoints()) << " seconds per million events." << std::endl;
     }
 
   }
@@ -447,7 +451,7 @@ public:
    * */
   void test_addEvents_2D()
   {
-    MDGridBox<MDEvent<2>,2> * b = makeMDGridBox<2>(0);
+    MDGridBox<MDEvent<2>,2> * b = makeMDGridBox2(0);
     std::vector< MDEvent<2> > events;
 
     // Make an event in the middle of each box
@@ -506,7 +510,7 @@ public:
    * */
   void test_addEvents_start_stop()
   {
-    MDGridBox<MDEvent<2>,2> * b = makeMDGridBox<2>(0);
+    MDGridBox<MDEvent<2>,2> * b = makeMDGridBox2(0);
     std::vector< MDEvent<2> > events;
 
     // Make an event in the middle of each box
@@ -533,7 +537,7 @@ public:
    * */
   void do_test_addEvents_inParallel(ThreadScheduler * ts)
   {
-    MDGridBox<MDEvent<2>,2> * b = makeMDGridBox<2>(0);
+    MDGridBox<MDEvent<2>,2> * b = makeMDGridBox2(0);
     int num_repeat = 1000;
 
     PARALLEL_FOR_NO_WSP_CHECK()
@@ -582,7 +586,7 @@ public:
     typedef MDBox<MDEvent<2>,2> box_t;
     typedef IMDBox<MDEvent<2>,2> ibox_t;
 
-    gbox_t * b = makeMDGridBox<2>(0);
+    gbox_t * b = makeMDGridBox2(0);
     b->getBoxController()->setSplitThreshold(100);
     b->getBoxController()->setMaxDepth(4);
 
@@ -643,7 +647,7 @@ public:
     typedef MDBox<MDEvent<2>,2> box_t;
     typedef IMDBox<MDEvent<2>,2> ibox_t;
 
-    gbox_t * b = makeMDGridBox<2>(0);
+    gbox_t * b = makeMDGridBox2(0);
     b->getBoxController()->setSplitThreshold(100);
     b->getBoxController()->setMaxDepth(4);
 
@@ -700,6 +704,7 @@ public:
     return bin;
   }
 
+  //------------------------------------------------------------------------------------------------
   /** Helper to test the binning of a 2D bin */
   void doTestMDBin2(MDGridBox<MDEvent<2>,2> * b,
       const std::string & message,
@@ -722,7 +727,7 @@ public:
     typedef IMDBox<MDEvent<2>,2> ibox_t;
 
     // 10x10 bins, 2 events per bin, each weight of 2.0
-    gbox_t * b = makeMDGridBox<2>(2);
+    gbox_t * b = makeMDGridBox2(2);
     TS_ASSERT_DELTA( b->getSignal(), 400.0, 1e-5);
 
     MDBin<MDEvent<2>,2> bin;
@@ -773,32 +778,114 @@ public:
 
 
 
+
+
+  //------------------------------------------------------------------------------------------------
+  /** For test_integrateSphere
+   *
+   * @param box
+   * @param radius :: radius to integrate
+   * @param numExpected :: how many events should be in there
+   */
+  void do_check_integrateSphere(MDGridBox<MDEvent<2>,2> & box, CoordType x, CoordType y, const CoordType radius, double numExpected, std::string message)
+  {
+    //std::cout << "Sphere of radius " << radius << " at " << x << "," << y << "------" << message << "--\n";
+    // The sphere transformation
+    bool dimensionsUsed[2] = {true,true};
+    CoordType center[2] = {x,y};
+    CoordTransformDistance sphere(2, center, dimensionsUsed);
+
+    double signal = 0;
+    double errorSquared = 0;
+    box.integrateSphere(sphere, radius*radius, signal, errorSquared);
+    TSM_ASSERT_DELTA( message, signal, 2.0*numExpected, 1e-5);
+    TSM_ASSERT_DELTA( message, errorSquared, 2.0*numExpected, 1e-5);
+  }
+
+  /** Re-used suite of tests */
+  void do_test_integrateSphere(MDGridBox<MDEvent<2>,2> * box_ptr)
+  {
+    // Events are at 0.5, 1.5, etc.
+    MDGridBox<MDEvent<2>,2> & box = *box_ptr;
+    TS_ASSERT_EQUALS( box.getNPoints(), 10*10);
+
+    do_check_integrateSphere(box, 4.5,4.5,  0.5,   1.0, "Too small to contain any vertices");
+    do_check_integrateSphere(box, 4.5, 4.5, 0.001, 1.0, "Tiny but still has an event.");
+    do_check_integrateSphere(box, 4.51,4.5, 0.001, 0.0, "Tiny but off the event.");
+    do_check_integrateSphere(box, 2.0,2.0,  0.49,  0.0, "At a corner but grabbing nothing");
+    do_check_integrateSphere(box, 4.8,4.5,  0.35,  1.0, "Too small to contain any vertices");
+    do_check_integrateSphere(box, 5.0,5.0,  1.0,   4.0, "Contains a box completely");
+    do_check_integrateSphere(box, 4.5,4.5,  0.9,   1.0, "Contains one box completely");
+    do_check_integrateSphere(box, 0.5,0.5,  0.9,   1.0, "Contains one box completely, at the edges");
+    do_check_integrateSphere(box, 9.5,0.5,  0.9,   1.0, "Contains one box completely, at the edges");
+    do_check_integrateSphere(box, 0.5,9.5,  0.9,   1.0, "Contains one box completely, at the edges");
+    do_check_integrateSphere(box, 4.5,9.5,  0.9,   1.0, "Contains one box completely, at the edges");
+    do_check_integrateSphere(box, 9.5,9.5,  0.9,   1.0, "Contains one box completely, at the edges");
+    do_check_integrateSphere(box, 1.5,1.5,  1.95,  9.0, "Contains 5 boxes completely, and 4 boxes with a point");
+    do_check_integrateSphere(box, -1.0,0.5, 1.55,  1.0, "Off an edge but enough to get an event");
+
+    // Now I add an event very near an edge
+    CoordType center[2] = {0.001, 0.5};
+    box.addEvent(MDEvent<2>(2.0, 2.0, center));
+    do_check_integrateSphere(box, -1.0,0.5, 1.01,  1.0, "Off an edge but just barely enough to get an event");
+    do_check_integrateSphere(box, 0.0,0.5, 0.01,  1.0, "Tiny, but just barely enough to get an event");
+  }
+
+  /** Test of sphere integration with even splitting*/
+  void test_integrateSphere()
+  {
+    // 10x10 sized box
+    MDGridBox<MDEvent<2>,2> * box_ptr = makeMDGridBox2(1);
+    do_test_integrateSphere(box_ptr);
+  }
+
+  void test_integrateSphere_unevenSplit()
+  {
+    // 10x5 sized box
+    MDGridBox<MDEvent<2>,2> * box_ptr = makeMDGridBox2(1, 10,5);
+    do_test_integrateSphere(box_ptr);
+  }
+
+  void test_integrateSphere_unevenSplit2()
+  {
+    // Funnier splitting: 3x7 sized box
+    MDGridBox<MDEvent<2>,2> * box_ptr = makeMDGridBox2(1, 3,7);
+    do_test_integrateSphere(box_ptr);
+  }
+
+
+
 private:
   std::string message;
 };
 
 
 
+
+
 //=====================================================================================
-//===================================== Performance Test ================================
+//===================================== Performance Test ==============================
 //=====================================================================================
 class MDGridBoxTestPerformance : public CxxTest::TestSuite
 {
 public:
 
   MDGridBox<MDEvent<3>,3> * box3;
+  MDGridBox<MDEvent<3>,3> * box3b;
   std::vector<MDEvent<3> > events;
 
   void setUp()
   {
     // Split 5x5x5, 2 deep.
     box3 = MDGridBoxTest::makeRecursiveMDGridBox<3>(5,1);
+    box3b = MDGridBoxTest::makeRecursiveMDGridBox<3>(5,1);
 
     // Make the list of fake events, random dist.
-    size_t num = 5e6;
+    size_t num = 1e6;
+    events.clear();
 
     boost::mt19937 rng;
-    boost::uniform_real<double> u(0, 10.0); // Range
+    boost::uniform_real<double> u(0, 5.0); // Range
     boost::variate_generator<boost::mt19937&, boost::uniform_real<double> > gen(rng, u);
     for (size_t i=0; i<num; ++i)
     {
@@ -809,11 +896,14 @@ public:
       events.push_back( MDEvent<3>( 1.0, 1.0, centers) );
     }
 
+    box3b->addEvents(events);
+    box3b->refreshCache();
   }
 
   void tearDown()
   {
     delete box3;
+    delete box3b;
   }
 
 
@@ -824,10 +914,77 @@ public:
   {
     // We built this many MDBoxes
     TS_ASSERT_EQUALS( box3->getBoxController()->getTotalNumMDBoxes(), 125*125+1); // +1 might be a test issue
-    TS_ASSERT_EQUALS( events.size(), 5e6);
+    TS_ASSERT_EQUALS( events.size(), 1e6);
 
     // Add them!
-    box3->addEvents(events);
+    for(size_t i=0; i<5; ++i)
+    {
+      box3->addEvents(events);
+    }
+  }
+
+  /** Smallish sphere in the middle goes partially through lots of boxes */
+  void test_sphereIntegrate_inTheMiddle()
+  {
+    // The sphere transformation
+    bool dimensionsUsed[3] = {true,true,true};
+    CoordType center[3] = {2.5, 2.5, 2.5};
+    CoordTransformDistance sphere(3, center, dimensionsUsed);
+
+    double signal, errorSquared;
+
+    for (size_t i=0; i < 1000; i++)
+    {
+      signal = 0;
+      errorSquared = 0;
+      box3b->integrateSphere(sphere, 1.0, signal, errorSquared);
+    }
+
+    // The expected number of events, given a sphere of radius 1.0
+    TS_ASSERT_DELTA(signal, (1e6/125)*(4.0*3.14159/3.0), 2000);
+    TS_ASSERT_DELTA(signal, errorSquared, 1e-3);
+  }
+
+  /** Huge sphere containing all within */
+  void test_sphereIntegrate_inTheMiddle_largeSphere()
+  {
+    // The sphere transformation
+    bool dimensionsUsed[3] = {true,true,true};
+    CoordType center[3] = {2.5, 2.5, 2.5};
+    CoordTransformDistance sphere(3, center, dimensionsUsed);
+
+    double signal, errorSquared;
+
+    for (size_t i=0; i < 1000; i++)
+    {
+      signal = 0;
+      errorSquared = 0;
+      box3b->integrateSphere(sphere, 5.0*5.0, signal, errorSquared);
+    }
+    // Contains everything
+    TS_ASSERT_DELTA(signal, 1e6, 10);
+    TS_ASSERT_DELTA(signal, errorSquared, 1e-3);
+  }
+
+  /** Peak that is off the box entirely */
+  void test_sphereIntegrate_OffTheBox()
+  {
+    // The sphere transformation
+    bool dimensionsUsed[3] = {true,true,true};
+    CoordType center[3] = {11., 5., 5.};
+    CoordTransformDistance sphere(3, center, dimensionsUsed);
+
+    double signal, errorSquared;
+
+    for (size_t i=0; i < 1000; i++)
+    {
+      signal = 0;
+      errorSquared = 0;
+      box3b->integrateSphere(sphere, 1.0, signal, errorSquared);
+    }
+
+    TS_ASSERT_EQUALS(signal, 0.0);
+    TS_ASSERT_DELTA(signal, errorSquared, 1e-3);
   }
 
 };
diff --git a/Code/Mantid/Framework/Nexus/CMakeLists.txt b/Code/Mantid/Framework/Nexus/CMakeLists.txt
index 7ac819b9eb6..53ec8d5c48b 100644
--- a/Code/Mantid/Framework/Nexus/CMakeLists.txt
+++ b/Code/Mantid/Framework/Nexus/CMakeLists.txt
@@ -78,7 +78,7 @@ set ( TEST_FILES
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(Nexus SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(Nexus SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Add the dependency on the nexus library
diff --git a/Code/Mantid/Framework/PythonAPI/CMakeLists.txt b/Code/Mantid/Framework/PythonAPI/CMakeLists.txt
index 641e13520bb..99e8926b489 100644
--- a/Code/Mantid/Framework/PythonAPI/CMakeLists.txt
+++ b/Code/Mantid/Framework/PythonAPI/CMakeLists.txt
@@ -55,7 +55,7 @@ set ( TEST_PY_FILES test/ImportTest.py
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(PythonAPI SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(PythonAPI SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 ###########################################################################
diff --git a/Code/Mantid/Framework/PythonAPI/MantidFramework.py b/Code/Mantid/Framework/PythonAPI/MantidFramework.py
index c495a4677a5..6ebb48d7e73 100644
--- a/Code/Mantid/Framework/PythonAPI/MantidFramework.py
+++ b/Code/Mantid/Framework/PythonAPI/MantidFramework.py
@@ -11,6 +11,7 @@ import __builtin__
 import __main__
 try:
     import qti
+    import PyQt4.QtCore as qtcore
 except:
     pass # ignore this error as you are probably running without the gui
 
@@ -891,8 +892,15 @@ class IAlgorithmProxy(ProxyObject):
 
         if mtd.__gui__:
             name = self._getHeldObject().name()
-            result = qti.app.mantidUI.runAlgorithmAsync_PyCallback(name)
-            if result == False:
+            result = self.executeAsync()
+            while not result.available():
+                qtcore.QCoreApplication.processEvents()
+            try:
+                success = result.data()
+            except:
+                success = false
+
+            if success == False:
                 sys.exit('An error occurred while running %s. See results log for details.' % name)
         else:
             self._getHeldObject().execute()
diff --git a/Code/Mantid/Framework/PythonAPI/src/api_exports.cpp b/Code/Mantid/Framework/PythonAPI/src/api_exports.cpp
index d69978fd6b0..e2c4e78facc 100644
--- a/Code/Mantid/Framework/PythonAPI/src/api_exports.cpp
+++ b/Code/Mantid/Framework/PythonAPI/src/api_exports.cpp
@@ -23,6 +23,8 @@
 #include "MantidGeometry/MDGeometry/IMDDimension.h"
 
 #include "MantidPythonAPI/PyAlgorithmWrapper.h"
+//Poco
+#include <Poco/ActiveResult.h>
 
 namespace Mantid
 {
@@ -111,6 +113,12 @@ using namespace boost::python;
   void export_ialgorithm()
   {
     
+    class_<Poco::ActiveResult<bool> >("ActiveResult_bool", no_init)
+      .def("available", &Poco::ActiveResult<bool>::available)
+      .def("wait", (void (Poco::ActiveResult<bool>::*)())&Poco::ActiveResult<bool>::wait)
+      .def("data", (bool& (Poco::ActiveResult<bool>::*)() const)&Poco::ActiveResult<bool>::data,return_value_policy< copy_non_const_reference >())
+      ;
+
     register_ptr_to_python<API::IAlgorithm*>();
     register_ptr_to_python<boost::shared_ptr<API::IAlgorithm> >();
 
diff --git a/Code/Mantid/Framework/TestHelpers/src/ComponentCreationHelper.cpp b/Code/Mantid/Framework/TestHelpers/src/ComponentCreationHelper.cpp
index a4ecfcae097..6b7b2233239 100644
--- a/Code/Mantid/Framework/TestHelpers/src/ComponentCreationHelper.cpp
+++ b/Code/Mantid/Framework/TestHelpers/src/ComponentCreationHelper.cpp
@@ -268,7 +268,7 @@ namespace ComponentCreationHelper
    * Create an test instrument with n panels of rectangular detectors, pixels*pixels in size,
    * a source and spherical sample shape.
    *
-   * Banks are centered at position (0,0,5*banknum)
+   * Banks' lower-left corner is at position (0,0,5*banknum) and they go up to (pixels*0.008, pixels*0.008, Z)
    * Pixels are 4 mm wide.
    *
    * @param num_banks: number of rectangular banks to create
@@ -296,15 +296,14 @@ namespace ComponentCreationHelper
           banknum*pixels*pixels, true, pixels);
 
       // Mark them all as detectors
-      for (int i=0; i < bank->nelements(); i++)
-      {
-        boost::shared_ptr<Detector> detector = boost::dynamic_pointer_cast<Detector>((*bank)[i]);
-        if (detector)
+      for (int x=0; x<pixels; x++)
+        for (int y=0; y<pixels; y++)
         {
-          //Mark it as a detector (add to the instrument cache)
-          testInst->markAsDetector(detector.get());
+          boost::shared_ptr<Detector> detector = bank->getAtXY(x,y);
+          if (detector)
+            //Mark it as a detector (add to the instrument cache)
+            testInst->markAsDetector(detector.get());
         }
-      }
 
       testInst->add(bank);
       bank->setPos(V3D(0.0, 0.0, 5.0*banknum));
diff --git a/Code/Mantid/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp b/Code/Mantid/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp
index f4b71056366..8a324acf8dd 100644
--- a/Code/Mantid/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp
+++ b/Code/Mantid/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp
@@ -1,13 +1,12 @@
 //------------------------------------------------------------------------------
 // Includes
 //------------------------------------------------------------------------------
-#include "MantidTestHelpers/WorkspaceCreationHelper.h"
-// Other Helper
-#include "MantidTestHelpers/ComponentCreationHelper.h"
-#include <cmath>
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
+#include "MantidTestHelpers/ComponentCreationHelper.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include <cmath>
 
 namespace WorkspaceCreationHelper
 {
diff --git a/Code/Mantid/Framework/UserAlgorithms/CMakeLists.txt b/Code/Mantid/Framework/UserAlgorithms/CMakeLists.txt
index 16528d84994..cf341e315f6 100644
--- a/Code/Mantid/Framework/UserAlgorithms/CMakeLists.txt
+++ b/Code/Mantid/Framework/UserAlgorithms/CMakeLists.txt
@@ -16,7 +16,7 @@ set ( INC_FILES HelloWorldAlgorithm.h
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(UserAlgorithms SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(UserAlgorithms SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # Add the target for this directory
diff --git a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp
index e5d24740203..f85178d1fab 100644
--- a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp
+++ b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp
@@ -1689,38 +1689,6 @@ MantidMatrix* MantidUI::newMantidMatrix(const QString& wsName, int start, int en
   return importMatrixWorkspace(wsName, false, false, start, end);
 }
 
-/**
- * Run the named algorithm asynchronously
- */
-bool MantidUI::runAlgorithmAsync_PyCallback(const QString & alg_name)
-{
-  Mantid::API::IAlgorithm_sptr alg = findAlgorithmPointer(alg_name);
-
-  if( !alg )
-  {
-    return false;
-  }
-  if( m_algMonitor ) 
-  {
-    m_algMonitor->add(alg);
-  }
-  Poco::ActiveResult<bool> result(alg->executeAsync());
-  while( !result.available() )
-  {
-    QCoreApplication::processEvents();
-  }
-  result.wait();
-
-  try
-  {
-    return result.data();
-  }
-  catch( Poco::NullPointerException& )
-  {
-    return false;
-  }
-}
-
 void MantidUI::cancelAllRunningAlgorithms()
 {
   if( m_algMonitor ) m_algMonitor->cancelAll();
diff --git a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.h b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.h
index 582ccc533ce..77ca41138e6 100644
--- a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.h
+++ b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.h
@@ -222,7 +222,6 @@ public:
   MantidMatrix* getMantidMatrix(const QString& wsName);
   MantidMatrix* newMantidMatrix(const QString& name, int start=-1, int end=-1);
   MultiLayer* plotBin(const QString& wsName, int bin, bool errors = false);
-  bool runAlgorithmAsync_PyCallback(const QString & algName);
   void setIsRunning(bool running);
   bool createPropertyInputDialog(const QString & alg_name, const QString & preset_values,
 				 const QString & optional_msg,  const QString & enabled_names);
diff --git a/Code/Mantid/MantidPlot/src/qti.sip b/Code/Mantid/MantidPlot/src/qti.sip
index e16c4139c04..65156fbb7d2 100644
--- a/Code/Mantid/MantidPlot/src/qti.sip
+++ b/Code/Mantid/MantidPlot/src/qti.sip
@@ -1736,7 +1736,6 @@ public:
   MultiLayer* plotBin(const QString&,int,bool = false);  
   MantidMatrix* importMatrixWorkspace(const QString&,int = -1, int = -1, bool = false, bool = false);
   Table* importTableWorkspace(const QString&, bool = false, bool = false);	
-  bool runAlgorithmAsync_PyCallback(const QString &);
   bool createPropertyInputDialog(const QString &, const QString &, const QString&, const QString&);
   QString getSelectedWorkspaceName();
   InstrumentWindow* getInstrumentView(const QString &);
diff --git a/Code/Mantid/MantidQt/CustomDialogs/CMakeLists.txt b/Code/Mantid/MantidQt/CustomDialogs/CMakeLists.txt
index 5cc93af8d6c..79d1598fffc 100644
--- a/Code/Mantid/MantidQt/CustomDialogs/CMakeLists.txt
+++ b/Code/Mantid/MantidQt/CustomDialogs/CMakeLists.txt
@@ -52,7 +52,7 @@ include_directories ( ${CMAKE_CURRENT_BINARY_DIR} )
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(CustomDialogs SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(CustomDialogs SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/CMakeLists.txt b/Code/Mantid/MantidQt/CustomInterfaces/CMakeLists.txt
index 28dc5ad5433..c0704536456 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/CMakeLists.txt
+++ b/Code/Mantid/MantidQt/CustomInterfaces/CMakeLists.txt
@@ -70,7 +70,7 @@ include_directories ( ${CMAKE_CURRENT_BINARY_DIR} )
 
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(CustomInterfaces SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(CustomInterfaces SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 add_library ( CustomInterfaces ${SRC_FILES} ${INC_FILES} ${MOCCED_FILES} ${UI_HDRS} )
diff --git a/Code/Mantid/MantidQt/DesignerPlugins/CMakeLists.txt b/Code/Mantid/MantidQt/DesignerPlugins/CMakeLists.txt
index 01e517a5e7a..5a3572a9306 100644
--- a/Code/Mantid/MantidQt/DesignerPlugins/CMakeLists.txt
+++ b/Code/Mantid/MantidQt/DesignerPlugins/CMakeLists.txt
@@ -30,7 +30,7 @@ add_definitions( -DLIBRARY_NAME=${LIB_NAME} )
 set ( SRC_UNITY_IGNORE_FILES )
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(DesignerPlugins SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(DesignerPlugins SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 add_library ( DesignerPlugins ${SRC_FILES} ${INC_FILES} ${MOCCED_FILES} )
diff --git a/Code/Mantid/Vates/VatesAPI/CMakeLists.txt b/Code/Mantid/Vates/VatesAPI/CMakeLists.txt
index 1f1bd8c542f..198a6ccb531 100644
--- a/Code/Mantid/Vates/VatesAPI/CMakeLists.txt
+++ b/Code/Mantid/Vates/VatesAPI/CMakeLists.txt
@@ -90,7 +90,7 @@ include_directories (inc)
 set ( SRC_UNITY_IGNORE_FILES )
 if(UNITY_BUILD)
   include(UnityBuild)
-  enable_unity_build(VatesAPI SRC_FILES SRC_UNITY_IGNORE_FILES 1000)
+  enable_unity_build(VatesAPI SRC_FILES SRC_UNITY_IGNORE_FILES 10)
 endif(UNITY_BUILD)
 
 # For Windows:
diff --git a/Code/Mantid/Vates/VatesAPI/test/vtkDataSetFactoryTest.h b/Code/Mantid/Vates/VatesAPI/test/vtkDataSetFactoryTest.h
index b6c6e69d192..5da57e9dd67 100644
--- a/Code/Mantid/Vates/VatesAPI/test/vtkDataSetFactoryTest.h
+++ b/Code/Mantid/Vates/VatesAPI/test/vtkDataSetFactoryTest.h
@@ -91,6 +91,6 @@ protected:
     GeometryPolicy m_geometry;
   };
 
-}
+};
 
 #endif
-- 
GitLab