From a26152bf2bb5a13f75e65e01f74d52ea813677b5 Mon Sep 17 00:00:00 2001
From: Karl Palmen <karl.palmen@stfc.ac.uk>
Date: Mon, 27 Nov 2017 17:13:08 +0000
Subject: [PATCH] Increase IObject usage via clone method re #12827

Signed-off-by: Karl Palmen <karl.palmen@stfc.ac.uk>
---
 Framework/API/inc/MantidAPI/Sample.h          |  6 +++---
 Framework/API/src/Sample.cpp                  | 17 +++++++++--------
 Framework/API/src/SampleShapeValidator.cpp    |  1 -
 .../MantidAlgorithms/AbsorptionCorrection.h   |  2 +-
 .../MantidAlgorithms/AnnularRingAbsorption.h  |  3 ---
 .../inc/MantidAlgorithms/AnyShapeAbsorption.h |  2 +-
 .../SampleCorrections/MCInteractionVolume.h   |  5 +++--
 .../Algorithms/src/AbsorptionCorrection.cpp   |  8 ++++----
 .../Algorithms/src/AnyShapeAbsorption.cpp     | 19 ++++++-------------
 Framework/Algorithms/src/CopySample.cpp       |  9 +++++----
 .../Algorithms/src/HRPDSlabCanAbsorption.cpp  |  4 ++--
 .../MultipleScatteringCylinderAbsorption.cpp  |  4 ++--
 .../SampleCorrections/MCInteractionVolume.cpp | 12 ++++++------
 .../MayersSampleCorrection.cpp                |  3 ++-
 .../Algorithms/src/SphericalAbsorption.cpp    |  4 ++--
 Framework/Crystal/src/AnvredCorrection.cpp    |  4 ++--
 Framework/Crystal/src/LoadHKL.cpp             |  4 ++--
 Framework/Crystal/src/SaveHKL.cpp             |  4 ++--
 .../inc/MantidGeometry/Objects/CSGObject.h    |  6 ++++--
 .../inc/MantidGeometry/Objects/IObject.h      |  9 +++++++++
 .../Quantification/CachedExperimentInfo.cpp   |  2 +-
 21 files changed, 66 insertions(+), 62 deletions(-)

diff --git a/Framework/API/inc/MantidAPI/Sample.h b/Framework/API/inc/MantidAPI/Sample.h
index aaedcfb79a0..61d71c5b802 100644
--- a/Framework/API/inc/MantidAPI/Sample.h
+++ b/Framework/API/inc/MantidAPI/Sample.h
@@ -69,9 +69,9 @@ public:
   /// Set the name of the sample
   void setName(const std::string &name);
   /// Return the sample shape
-  const Geometry::CSGObject &getShape() const;
+  const Geometry::IObject &getShape() const;
   /// Update the shape of the object
-  void setShape(const Geometry::CSGObject &shape);
+  void setShape(const Geometry::IObject_sptr &shape);
 
   /** @name Material properties.*/
   //@{
@@ -138,7 +138,7 @@ private:
   /// The sample name
   std::string m_name;
   /// The sample shape object
-  Geometry::CSGObject m_shape;
+  Geometry::IObject_sptr m_shape;
   /// An owned pointer to the SampleEnvironment object
   boost::shared_ptr<Geometry::SampleEnvironment> m_environment;
   /// Pointer to the OrientedLattice of the sample, NULL if not set.
diff --git a/Framework/API/src/Sample.cpp b/Framework/API/src/Sample.cpp
index f5fa5eeb52c..66ff4c1adbc 100644
--- a/Framework/API/src/Sample.cpp
+++ b/Framework/API/src/Sample.cpp
@@ -16,7 +16,8 @@ namespace Mantid {
 
 namespace API {
 using namespace Mantid::Kernel;
-using Geometry::CSGObject;
+using Geometry::IObject;
+using Geometry::IObject_sptr;
 using Geometry::OrientedLattice;
 using Geometry::SampleEnvironment;
 using Geometry::ShapeFactory;
@@ -101,18 +102,18 @@ void Sample::setName(const std::string &name) { m_name = name; }
  * its own coordinate system with its centre at [0,0,0]
  * @return A reference to the object describing the shape
  */
-const CSGObject &Sample::getShape() const { return m_shape; }
+const IObject &Sample::getShape() const { return *m_shape; }
 
 /** Set the object that describes the sample shape. The object is defined within
  * its own coordinate system
  * @param shape :: The object describing the shape
  */
-void Sample::setShape(const CSGObject &shape) { m_shape = shape; }
+void Sample::setShape(const IObject_sptr &shape) { m_shape = shape; }
 
 /** Return the material.
  * @return A reference to the material the sample is composed of
  */
-const Material Sample::getMaterial() const { return m_shape.material(); }
+const Material Sample::getMaterial() const { return m_shape->material(); }
 
 /**
  * Return a reference to the sample environment that this sample is attached to
@@ -291,9 +292,9 @@ void Sample::saveNexus(::NeXus::File *file, const std::string &group) const {
   file->makeGroup(group, "NXsample", true);
   file->putAttr("name", m_name);
   file->putAttr("version", 1);
-  file->putAttr("shape_xml", m_shape.getShapeXML());
+  file->putAttr("shape_xml", m_shape->getShapeXML());
 
-  m_shape.material().saveNexus(file, "material");
+  m_shape->material().saveNexus(file, "material");
   // Write out the other (indexes 1+) samples
   file->writeData("num_other_samples", int(m_samples.size()));
   for (size_t i = 0; i < m_samples.size(); i++)
@@ -351,12 +352,12 @@ int Sample::loadNexus(::NeXus::File *file, const std::string &group) {
     shape_xml = Strings::strip(shape_xml);
     if (!shape_xml.empty()) {
       ShapeFactory shapeMaker;
-      m_shape = *shapeMaker.createShape(shape_xml,
+      m_shape = shapeMaker.createShape(shape_xml,
                                         false /*Don't wrap with <type> tag*/);
     }
     Kernel::Material material;
     material.loadNexus(file, "material");
-    m_shape.setMaterial(material);
+    m_shape->setMaterial(material);
 
     // Load other samples
     int num_other_samples;
diff --git a/Framework/API/src/SampleShapeValidator.cpp b/Framework/API/src/SampleShapeValidator.cpp
index cd0ad6589db..430ad60b73d 100644
--- a/Framework/API/src/SampleShapeValidator.cpp
+++ b/Framework/API/src/SampleShapeValidator.cpp
@@ -1,6 +1,5 @@
 #include "MantidAPI/SampleShapeValidator.h"
 #include "MantidAPI/Sample.h"
-#include "MantidGeometry/Objects/CSGObject.h"
 #include <boost/make_shared.hpp>
 
 namespace Mantid {
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/AbsorptionCorrection.h b/Framework/Algorithms/inc/MantidAlgorithms/AbsorptionCorrection.h
index 623acb8cd46..f2f821832c8 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/AbsorptionCorrection.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/AbsorptionCorrection.h
@@ -115,7 +115,7 @@ protected:
   virtual void initialiseCachedDistances() = 0;
 
   API::MatrixWorkspace_sptr m_inputWS; ///< A pointer to the input workspace
-  const Geometry::CSGObject *m_sampleObject; ///< Local cache of sample object.
+  const Geometry::IObject *m_sampleObject; ///< Local cache of sample object.
   Kernel::V3D m_beamDirection;               ///< The direction of the beam.
   std::vector<double> m_L1s,                 ///< Cached L1 distances
       m_elementVolumes;                      ///< Cached element volumes
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/AnnularRingAbsorption.h b/Framework/Algorithms/inc/MantidAlgorithms/AnnularRingAbsorption.h
index d84d6448bf9..8da2489d4b9 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/AnnularRingAbsorption.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/AnnularRingAbsorption.h
@@ -11,9 +11,6 @@ namespace Kernel {
 class Material;
 class V3D;
 }
-namespace Geometry {
-class CSGObject;
-}
 
 namespace Algorithms {
 
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/AnyShapeAbsorption.h b/Framework/Algorithms/inc/MantidAlgorithms/AnyShapeAbsorption.h
index 77052bdde2d..8e387758a60 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/AnyShapeAbsorption.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/AnyShapeAbsorption.h
@@ -107,7 +107,7 @@ private:
   std::string sampleXML() override;
   void initialiseCachedDistances() override;
   /// Create the gague volume for the correction
-  Geometry::CSGObject constructGaugeVolume();
+  boost::shared_ptr<const Geometry::IObject> constructGaugeVolume();
 
   double m_cubeSide; ///< The length of the side of an element cube in m
 };
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h
index 3a5c0bf45ef..c5c823d17c1 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h
@@ -9,9 +9,10 @@ namespace API {
 class Sample;
 }
 namespace Geometry {
-class CSGObject;
+class IObject;
 class SampleEnvironment;
 }
+
 namespace Kernel {
 class PseudoRandomNumberGenerator;
 class V3D;
@@ -62,7 +63,7 @@ public:
                              double lambdaAfter) const;
 
 private:
-  const Geometry::CSGObject &m_sample;
+  const boost::shared_ptr<Geometry::IObject> m_sample;
   const Geometry::SampleEnvironment *m_env;
   const Geometry::BoundingBox m_activeRegion;
   const size_t m_maxScatterAttempts;
diff --git a/Framework/Algorithms/src/AbsorptionCorrection.cpp b/Framework/Algorithms/src/AbsorptionCorrection.cpp
index b593e661680..e49831bd730 100644
--- a/Framework/Algorithms/src/AbsorptionCorrection.cpp
+++ b/Framework/Algorithms/src/AbsorptionCorrection.cpp
@@ -244,8 +244,8 @@ void AbsorptionCorrection::retrieveBaseProperties() {
                         static_cast<uint16_t>(0), 0.0, 0.0, sigma_s, 0.0,
                         sigma_s, sigma_atten);
 
-    CSGObject shape = m_inputWS->sample().getShape(); // copy
-    shape.setMaterial(Material("SetInAbsorptionCorrection", neutron, rho));
+    auto shape = boost::shared_ptr<IObject>(m_inputWS->sample().getShape().clone());
+    shape->setMaterial(Material("SetInAbsorptionCorrection", neutron, rho));
     m_inputWS->mutableSample().setShape(shape);
   }
   rho *= 100; // Needed to get the units right
@@ -296,8 +296,8 @@ void AbsorptionCorrection::constructSample(API::Sample &sample) {
       throw std::invalid_argument(mess);
     }
   } else {
-    boost::shared_ptr<CSGObject> shape = ShapeFactory().createShape(xmlstring);
-    sample.setShape(*shape);
+    boost::shared_ptr<IObject> shape = ShapeFactory().createShape(xmlstring);
+    sample.setShape(shape);
     m_sampleObject = &sample.getShape();
 
     g_log.information("Successfully constructed the sample object");
diff --git a/Framework/Algorithms/src/AnyShapeAbsorption.cpp b/Framework/Algorithms/src/AnyShapeAbsorption.cpp
index d70a643493f..fe0d5b0ea6d 100644
--- a/Framework/Algorithms/src/AnyShapeAbsorption.cpp
+++ b/Framework/Algorithms/src/AnyShapeAbsorption.cpp
@@ -43,7 +43,7 @@ std::string AnyShapeAbsorption::sampleXML() {
 void AnyShapeAbsorption::initialiseCachedDistances() {
   // First, check if a 'gauge volume' has been defined. If not, it's the same as
   // the sample.
-  CSGObject integrationVolume = *m_sampleObject;
+  auto integrationVolume = boost::shared_ptr<const IObject>(m_sampleObject->clone());
   if (m_inputWS->run().hasProperty("GaugeVolume")) {
     integrationVolume = constructGaugeVolume();
   }
@@ -52,7 +52,7 @@ void AnyShapeAbsorption::initialiseCachedDistances() {
   const double big(10.0); // Seems like bounding box code searches inwards, 10m
                           // should be enough!
   double minX(-big), maxX(big), minY(-big), maxY(big), minZ(-big), maxZ(big);
-  integrationVolume.getBoundingBox(maxX, maxY, maxZ, minX, minY, minZ);
+  integrationVolume->getBoundingBox();
   assert(maxX > minX);
   assert(maxY > minY);
   assert(maxZ > minZ);
@@ -92,7 +92,7 @@ void AnyShapeAbsorption::initialiseCachedDistances() {
         // Set the current position in the sample in Cartesian coordinates.
         const V3D currentPosition(x, y, z);
         // Check if the current point is within the object. If not, skip.
-        if (integrationVolume.isValid(currentPosition)) {
+        if (integrationVolume->isValid(currentPosition)) {
           // Create track for distance in sample before scattering point
           Track incoming(currentPosition, m_beamDirection * -1.0);
           // We have an issue where occasionally, even though a point is within
@@ -120,23 +120,16 @@ void AnyShapeAbsorption::initialiseCachedDistances() {
                    YSliceThickness * ZSliceThickness;
 }
 
-Geometry::CSGObject AnyShapeAbsorption::constructGaugeVolume() {
+boost::shared_ptr<const Geometry::IObject> AnyShapeAbsorption::constructGaugeVolume() {
   g_log.information("Calculating scattering within the gauge volume defined on "
                     "the input workspace");
 
   // Retrieve and create the gauge volume shape
-  boost::shared_ptr<const Geometry::CSGObject> volume =
+  boost::shared_ptr<const Geometry::IObject> volume =
       ShapeFactory().createShape(
           m_inputWS->run().getProperty("GaugeVolume")->value());
-  // Although DefineGaugeVolume algorithm will have checked validity of XML, do
-  // so again here
-  if (!(volume->topRule()) && volume->getSurfacePtr().empty()) {
-    g_log.error("Invalid gauge volume definition. Unable to construct "
-                "integration volume.");
-    throw std::invalid_argument("Invalid gauge volume definition.");
-  }
 
-  return *volume;
+  return volume;
 }
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/src/CopySample.cpp b/Framework/Algorithms/src/CopySample.cpp
index 8b2c50f0740..8380d5bcb4b 100644
--- a/Framework/Algorithms/src/CopySample.cpp
+++ b/Framework/Algorithms/src/CopySample.cpp
@@ -14,6 +14,7 @@ DECLARE_ALGORITHM(CopySample)
 using namespace Mantid::API;
 using namespace Mantid::Kernel;
 using Geometry::SampleEnvironment;
+using Geometry::IObject;
 
 //----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
@@ -163,11 +164,11 @@ void CopySample::copyParameters(Sample &from, Sample &to, bool nameFlag,
   if (environmentFlag)
     to.setEnvironment(new SampleEnvironment(from.getEnvironment()));
   if (shapeFlag) {
-    auto rhsObject = from.getShape(); // copy
+    auto rhsObject = boost::shared_ptr<IObject>(from.getShape().clone());
     const auto lhsMaterial = to.getMaterial();
     // reset to original lhs material
     if (!materialFlag) {
-      rhsObject.setMaterial(lhsMaterial);
+      rhsObject->setMaterial(lhsMaterial);
     }
     to.setShape(rhsObject);
     to.setGeometryFlag(from.getGeometryFlag());
@@ -175,8 +176,8 @@ void CopySample::copyParameters(Sample &from, Sample &to, bool nameFlag,
     to.setThickness(from.getThickness());
     to.setWidth(from.getWidth());
   } else if (materialFlag) {
-    auto lhsObject = to.getShape(); // copy
-    lhsObject.setMaterial(from.getMaterial());
+    auto lhsObject = boost::shared_ptr<IObject>(to.getShape().clone());
+    lhsObject->setMaterial(from.getMaterial());
     to.setShape(lhsObject);
   }
 
diff --git a/Framework/Algorithms/src/HRPDSlabCanAbsorption.cpp b/Framework/Algorithms/src/HRPDSlabCanAbsorption.cpp
index 553bc8bacc0..a38987bf3a2 100644
--- a/Framework/Algorithms/src/HRPDSlabCanAbsorption.cpp
+++ b/Framework/Algorithms/src/HRPDSlabCanAbsorption.cpp
@@ -167,8 +167,8 @@ API::MatrixWorkspace_sptr HRPDSlabCanAbsorption::runFlatPlateAbsorption() {
     NeutronAtom neutron(static_cast<uint16_t>(EMPTY_DBL()),
                         static_cast<uint16_t>(0), 0.0, 0.0, sigma_s, 0.0,
                         sigma_s, sigma_atten);
-    CSGObject shape = m_inputWS->sample().getShape(); // copy
-    shape.setMaterial(Material("SetInSphericalAbsorption", neutron, rho));
+    auto shape = boost::shared_ptr<IObject>(m_inputWS->sample().getShape().clone());
+    shape->setMaterial(Material("SetInSphericalAbsorption", neutron, rho));
     m_inputWS->mutableSample().setShape(shape);
   }
 
diff --git a/Framework/Algorithms/src/MultipleScatteringCylinderAbsorption.cpp b/Framework/Algorithms/src/MultipleScatteringCylinderAbsorption.cpp
index 095b2c0ea0a..2db0d23cde3 100644
--- a/Framework/Algorithms/src/MultipleScatteringCylinderAbsorption.cpp
+++ b/Framework/Algorithms/src/MultipleScatteringCylinderAbsorption.cpp
@@ -140,8 +140,8 @@ void MultipleScatteringCylinderAbsorption::exec() {
     NeutronAtom neutron(static_cast<uint16_t>(EMPTY_DBL()),
                         static_cast<uint16_t>(0), 0.0, 0.0, coeff3, 0.0, coeff3,
                         coeff1);
-    CSGObject shape = in_WS->sample().getShape(); // copy
-    shape.setMaterial(Material("SetInMultipleScattering", neutron, coeff2));
+    auto shape = boost::shared_ptr<IObject>(in_WS->sample().getShape().clone()); 
+    shape->setMaterial(Material("SetInMultipleScattering", neutron, coeff2));
     in_WS->mutableSample().setShape(shape);
   }
   g_log.debug() << "radius=" << radius << " coeff1=" << coeff1
diff --git a/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp b/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp
index b9cca245400..61961f8776a 100644
--- a/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp
+++ b/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp
@@ -40,9 +40,9 @@ double attenuation(double rho, double sigma, double length) {
 MCInteractionVolume::MCInteractionVolume(
     const API::Sample &sample, const Geometry::BoundingBox &activeRegion,
     const size_t maxScatterAttempts)
-    : m_sample(sample.getShape()), m_env(nullptr), m_activeRegion(activeRegion),
+    : m_sample(sample.getShape().clone()), m_env(nullptr), m_activeRegion(activeRegion),
       m_maxScatterAttempts(maxScatterAttempts) {
-  if (!m_sample.hasValidShape()) {
+  if (!m_sample->hasValidShape()) {
     throw std::invalid_argument(
         "MCInteractionVolume() - Sample shape does not have a valid shape.");
   }
@@ -62,7 +62,7 @@ MCInteractionVolume::MCInteractionVolume(
  * @return A reference to the bounding box
  */
 const Geometry::BoundingBox &MCInteractionVolume::getBoundingBox() const {
-  return m_sample.getBoundingBox();
+  return m_sample->getBoundingBox();
 }
 
 /**
@@ -92,13 +92,13 @@ double MCInteractionVolume::calculateAbsorption(
     scatterPos =
         m_env->generatePoint(rng, m_activeRegion, m_maxScatterAttempts);
   } else {
-    scatterPos = m_sample.generatePointInObject(rng, m_activeRegion,
+    scatterPos = m_sample->generatePointInObject(rng, m_activeRegion,
                                                 m_maxScatterAttempts);
   }
   auto toStart = startPos - scatterPos;
   toStart.normalize();
   Track beforeScatter(scatterPos, toStart);
-  int nlinks = m_sample.interceptSurface(beforeScatter);
+  int nlinks = m_sample->interceptSurface(beforeScatter);
   if (m_env) {
     nlinks += m_env->interceptSurfaces(beforeScatter);
   }
@@ -127,7 +127,7 @@ double MCInteractionVolume::calculateAbsorption(
   V3D scatteredDirec = endPos - scatterPos;
   scatteredDirec.normalize();
   Track afterScatter(scatterPos, scatteredDirec);
-  m_sample.interceptSurface(afterScatter);
+  m_sample->interceptSurface(afterScatter);
   if (m_env) {
     m_env->interceptSurfaces(afterScatter);
   }
diff --git a/Framework/Algorithms/src/SampleCorrections/MayersSampleCorrection.cpp b/Framework/Algorithms/src/SampleCorrections/MayersSampleCorrection.cpp
index 028887381a8..1d91d196373 100644
--- a/Framework/Algorithms/src/SampleCorrections/MayersSampleCorrection.cpp
+++ b/Framework/Algorithms/src/SampleCorrections/MayersSampleCorrection.cpp
@@ -8,6 +8,7 @@
 #include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
+#include "MantidGeometry/Objects/IObject.h"
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/Material.h"
 
@@ -102,7 +103,7 @@ void MayersSampleCorrection::exec() {
   // something better for the time being
   const double big(100.); // seems to be a sweet spot...
   double minX(-big), maxX(big), minY(-big), maxY(big), minZ(-big), maxZ(big);
-  sampleShape.getBoundingBox(maxX, maxY, maxZ, minX, minY, minZ);
+  sampleShape.getBoundingBox();
   V3D boxWidth(maxX - minX, maxY - minY, maxZ - minZ);
   const double radius(0.5 * boxWidth[frame->pointingHorizontal()]),
       height(boxWidth[frame->pointingUp()]);
diff --git a/Framework/Algorithms/src/SphericalAbsorption.cpp b/Framework/Algorithms/src/SphericalAbsorption.cpp
index 1b6a35c5aee..7ce1520282e 100644
--- a/Framework/Algorithms/src/SphericalAbsorption.cpp
+++ b/Framework/Algorithms/src/SphericalAbsorption.cpp
@@ -124,8 +124,8 @@ void SphericalAbsorption::retrieveBaseProperties() {
     NeutronAtom neutron(static_cast<uint16_t>(EMPTY_DBL()),
                         static_cast<uint16_t>(0), 0.0, 0.0, sigma_s, 0.0,
                         sigma_s, sigma_atten);
-    CSGObject shape = m_inputWS->sample().getShape(); // copy
-    shape.setMaterial(Material("SetInSphericalAbsorption", neutron, rho));
+    auto shape = boost::shared_ptr<IObject>(m_inputWS->sample().getShape().clone());
+    shape->setMaterial(Material("SetInSphericalAbsorption", neutron, rho));
     m_inputWS->mutableSample().setShape(shape);
   }
 
diff --git a/Framework/Crystal/src/AnvredCorrection.cpp b/Framework/Crystal/src/AnvredCorrection.cpp
index a625d9fc26f..a7e717b293f 100644
--- a/Framework/Crystal/src/AnvredCorrection.cpp
+++ b/Framework/Crystal/src/AnvredCorrection.cpp
@@ -359,8 +359,8 @@ void AnvredCorrection::retrieveBaseProperties() {
     NeutronAtom neutron(static_cast<uint16_t>(EMPTY_DBL()),
                         static_cast<uint16_t>(0), 0.0, 0.0, m_smu, 0.0, m_smu,
                         m_amu);
-    CSGObject shape = m_inputWS->sample().getShape(); // copy
-    shape.setMaterial(Material("SetInAnvredCorrection", neutron, 1.0));
+    auto shape = boost::shared_ptr<IObject>(m_inputWS->sample().getShape().clone());
+    shape->setMaterial(Material("SetInAnvredCorrection", neutron, 1.0));
     m_inputWS->mutableSample().setShape(shape);
   }
   if (m_smu != EMPTY_DBL() && m_amu != EMPTY_DBL())
diff --git a/Framework/Crystal/src/LoadHKL.cpp b/Framework/Crystal/src/LoadHKL.cpp
index 93c96b020bb..3e6ee8b3009 100644
--- a/Framework/Crystal/src/LoadHKL.cpp
+++ b/Framework/Crystal/src/LoadHKL.cpp
@@ -168,8 +168,8 @@ void LoadHKL::exec() {
   mrun.addProperty<double>("Radius", radius, true);
   NeutronAtom neutron(static_cast<uint16_t>(EMPTY_DBL()),
                       static_cast<uint16_t>(0), 0.0, 0.0, smu, 0.0, smu, amu);
-  CSGObject shape = ws->sample().getShape(); // copy
-  shape.setMaterial(Material("SetInLoadHKL", neutron, 1.0));
+  auto shape = boost::shared_ptr<IObject>(ws->sample().getShape().clone()); 
+  shape->setMaterial(Material("SetInLoadHKL", neutron, 1.0));
   ws->mutableSample().setShape(shape);
 
   setProperty("OutputWorkspace",
diff --git a/Framework/Crystal/src/SaveHKL.cpp b/Framework/Crystal/src/SaveHKL.cpp
index f6150507663..e8da7923265 100644
--- a/Framework/Crystal/src/SaveHKL.cpp
+++ b/Framework/Crystal/src/SaveHKL.cpp
@@ -258,8 +258,8 @@ void SaveHKL::exec() {
     NeutronAtom neutron(static_cast<uint16_t>(EMPTY_DBL()),
                         static_cast<uint16_t>(0), 0.0, 0.0, m_smu, 0.0, m_smu,
                         m_amu);
-    CSGObject shape = peaksW->sample().getShape(); // copy
-    shape.setMaterial(Material("SetInSaveHKL", neutron, 1.0));
+    auto shape = boost::shared_ptr<IObject>(peaksW->sample().getShape().clone()); 
+    shape->setMaterial(Material("SetInSaveHKL", neutron, 1.0));
     peaksW->mutableSample().setShape(shape);
   }
   if (m_smu != EMPTY_DBL() && m_amu != EMPTY_DBL())
diff --git a/Framework/Geometry/inc/MantidGeometry/Objects/CSGObject.h b/Framework/Geometry/inc/MantidGeometry/Objects/CSGObject.h
index 3e4abe667f6..d860ab32002 100644
--- a/Framework/Geometry/inc/MantidGeometry/Objects/CSGObject.h
+++ b/Framework/Geometry/inc/MantidGeometry/Objects/CSGObject.h
@@ -74,6 +74,8 @@ public:
   CSGObject &operator=(const CSGObject &);
   /// Destructor
   virtual ~CSGObject();
+  /// Clone
+  IObject* clone() const override { return new CSGObject(*this); }
 
   /// Return the top rule
   const Rule *topRule() const { return TopRule.get(); }
@@ -167,7 +169,7 @@ public:
                                     const size_t) const;
   Kernel::V3D generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng,
                                     const BoundingBox &activeRegion,
-                                    const size_t) const;
+                                    const size_t) const override;
 
   // Rendering member functions
   void draw() const override;
@@ -187,7 +189,7 @@ public:
   void GetObjectGeom(int &type, std::vector<Kernel::V3D> &vectors,
                      double &myradius, double &myheight) const override;
   /// Getter for the shape xml
-  std::string getShapeXML() const;
+  std::string getShapeXML() const override;
 
 private:
   int procPair(std::string &Ln, std::map<int, std::unique_ptr<Rule>> &Rlist,
diff --git a/Framework/Geometry/inc/MantidGeometry/Objects/IObject.h b/Framework/Geometry/inc/MantidGeometry/Objects/IObject.h
index b45d3cadfcc..48ee1c2d142 100644
--- a/Framework/Geometry/inc/MantidGeometry/Objects/IObject.h
+++ b/Framework/Geometry/inc/MantidGeometry/Objects/IObject.h
@@ -12,6 +12,7 @@ namespace Mantid {
 // Forward declarations
 //----------------------------------------------------------------------
 namespace Kernel {
+class PseudoRandomNumberGenerator;
 class Material;
 class V3D;
 }
@@ -58,6 +59,7 @@ public:
   virtual bool hasValidShape() const = 0;
   virtual int setObject(const int ON, const std::string &Ln) = 0;
   virtual int populate(const std::map<int, boost::shared_ptr<Surface>> &) = 0;
+  virtual IObject* clone() const = 0;
 
   virtual int getName() const = 0;
   virtual void setName(const int nx) = 0;
@@ -72,10 +74,17 @@ public:
   virtual const BoundingBox &getBoundingBox() const = 0;
 
   virtual int getPointInObject(Kernel::V3D &point) const = 0;
+  virtual Kernel::V3D generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng,
+    const BoundingBox &activeRegion,
+    const size_t) const = 0;
+
   virtual void GetObjectGeom(int &type, std::vector<Kernel::V3D> &vectors,
                              double &myradius, double &myheight) const = 0;
   virtual boost::shared_ptr<GeometryHandler> getGeometryHandler() = 0;
 
+  /// Getter for the shape xml
+  virtual std::string getShapeXML() const = 0;
+
   // Rendering
   virtual void draw() const = 0;
   virtual void initDraw() const = 0;
diff --git a/Framework/MDAlgorithms/src/Quantification/CachedExperimentInfo.cpp b/Framework/MDAlgorithms/src/Quantification/CachedExperimentInfo.cpp
index c09a1b05041..165423ef00b 100644
--- a/Framework/MDAlgorithms/src/Quantification/CachedExperimentInfo.cpp
+++ b/Framework/MDAlgorithms/src/Quantification/CachedExperimentInfo.cpp
@@ -173,7 +173,7 @@ void CachedExperimentInfo::initCaches(
 
   // Sample volume
   const API::Sample &sampleDescription = m_exptInfo.sample();
-  const Geometry::CSGObject &shape = sampleDescription.getShape();
+  const Geometry::IObject &shape = sampleDescription.getShape();
   m_sampleWidths = shape.getBoundingBox().width();
 
   // Detector volume
-- 
GitLab