diff --git a/Framework/API/inc/MantidAPI/ComponentInfo.h b/Framework/API/inc/MantidAPI/ComponentInfo.h
index c326c90e4e6a328fbb07b77d74d669f7288cc720..6c1221d6818926d2165273445b8daf5cab1c12ec 100644
--- a/Framework/API/inc/MantidAPI/ComponentInfo.h
+++ b/Framework/API/inc/MantidAPI/ComponentInfo.h
@@ -55,8 +55,9 @@ private:
 
 public:
   ComponentInfo(const Mantid::Beamline::ComponentInfo &componentInfo,
-                std::vector<Mantid::Geometry::IComponent *> &&componentIds);
+                const std::vector<Mantid::Geometry::IComponent *> componentIds);
   std::vector<size_t> detectorIndices(size_t componentIndex) const;
+  std::vector<Mantid::Geometry::IComponent *> componentIds() const;
   size_t size() const;
   size_t indexOf(Geometry::IComponent *id) const;
 };
diff --git a/Framework/API/inc/MantidAPI/ExperimentInfo.h b/Framework/API/inc/MantidAPI/ExperimentInfo.h
index 538c42823090520dfbaf8068e9931bebcb6990e1..ade50cdc70fd750401833d7316f3900eaf1be3df 100644
--- a/Framework/API/inc/MantidAPI/ExperimentInfo.h
+++ b/Framework/API/inc/MantidAPI/ExperimentInfo.h
@@ -228,6 +228,7 @@ private:
 
   boost::shared_ptr<Beamline::ComponentInfo> m_componentInfo;
   std::unique_ptr<API::ComponentInfo> m_componentInfoWrapper;
+  std::vector<Geometry::ComponentID> m_componentIds;
 
   mutable std::unique_ptr<Beamline::SpectrumInfo> m_spectrumInfo;
   mutable std::unique_ptr<SpectrumInfo> m_spectrumInfoWrapper;
diff --git a/Framework/API/inc/MantidAPI/InfoComponentVisitor.h b/Framework/API/inc/MantidAPI/InfoComponentVisitor.h
index 88a877db30c0f1dbd9001aeaad8fa9f32a6a592f..3bc7653106c47c2d0c739590eb3f5864abd4c9b7 100644
--- a/Framework/API/inc/MantidAPI/InfoComponentVisitor.h
+++ b/Framework/API/inc/MantidAPI/InfoComponentVisitor.h
@@ -64,6 +64,9 @@ private:
   /// Only Assemblies and other NON-detectors yield ranges
   std::vector<std::pair<size_t, size_t>> m_ranges;
 
+  /// Counter for dropped detectors
+  size_t m_droppedDetectors = 0;
+
 public:
   InfoComponentVisitor(const size_t nDetectors,
                        std::function<size_t(Mantid::detid_t)> mapperFunc);
diff --git a/Framework/API/src/ComponentInfo.cpp b/Framework/API/src/ComponentInfo.cpp
index c221a31e9498396711da22ce303a8ed9209a2ff3..329fd63fae1d34f6afb2b7b022f373b166e78cc9 100644
--- a/Framework/API/src/ComponentInfo.cpp
+++ b/Framework/API/src/ComponentInfo.cpp
@@ -12,17 +12,19 @@ namespace API {
 
 /**
  * Constructor
- * @param componentInfo : Beamline wrapped ComponentInfo
- * @param componentIds : Component Ids ordered by component index
+ * @brief ComponentInfo::ComponentInfo
+ * @param componentInfo
+ * @param componentIds : ComponentIDs ordered by component
+ * index
  */
-ComponentInfo::ComponentInfo(const Beamline::ComponentInfo &componentInfo,
-                             std::vector<Geometry::ComponentID> &&componentIds)
+ComponentInfo::ComponentInfo(
+    const Mantid::Beamline::ComponentInfo &componentInfo,
+    std::vector<Mantid::Geometry::IComponent *> componentIds)
     : m_componentInfo(componentInfo),
-      m_componentIds(
-          boost::make_shared<std::vector<Geometry::ComponentID>>(componentIds)),
+      m_componentIds(boost::make_shared<std::vector<Geometry::ComponentID>>(
+          std::move(componentIds))),
       m_compIDToIndex(boost::make_shared<
           std::unordered_map<Geometry::IComponent *, size_t>>()) {
-
   /*
    * Ideally we would check here that componentIds.size() ==
    * m_componentInfo.size().
@@ -39,6 +41,10 @@ ComponentInfo::detectorIndices(size_t componentIndex) const {
   return m_componentInfo.detectorIndices(componentIndex);
 }
 
+std::vector<Geometry::IComponent *> ComponentInfo::componentIds() const {
+  return *m_componentIds;
+}
+
 size_t ComponentInfo::size() const { return m_componentInfo.size(); }
 
 size_t ComponentInfo::indexOf(Geometry::IComponent *id) const {
diff --git a/Framework/API/src/ExperimentInfo.cpp b/Framework/API/src/ExperimentInfo.cpp
index ec99f2f5170f15b08ecd9bc9cd531637a53b2950..36ae40ce718c98ed33f2f70fafc45cb1d0c1a27e 100644
--- a/Framework/API/src/ExperimentInfo.cpp
+++ b/Framework/API/src/ExperimentInfo.cpp
@@ -71,6 +71,7 @@ ExperimentInfo::ExperimentInfo()
       m_detectorInfo(boost::make_shared<Beamline::DetectorInfo>()),
       m_componentInfo(boost::make_shared<Beamline::ComponentInfo>()) {
   m_parmap->setDetectorInfo(m_detectorInfo);
+  m_parmap->setComponentInfo(m_componentInfo, std::vector<ComponentID>{});
   m_detectorInfoWrapper = Kernel::make_unique<DetectorInfo>(
       *m_detectorInfo, getInstrument(), m_parmap.get());
 }
@@ -102,7 +103,6 @@ void ExperimentInfo::copyExperimentInfoFrom(const ExperimentInfo *other) {
   for (const auto &chopper : other->m_choppers) {
     m_choppers.push_back(chopper->clone());
   }
-  *m_detectorInfo = *other->m_detectorInfo;
   // We do not copy Beamline::SpectrumInfo (which contains detector grouping
   // information) for now:
   // - For MatrixWorkspace, grouping information is still stored in ISpectrum
@@ -188,22 +188,33 @@ void checkDetectorInfoSize(const Instrument &instr,
 }
 
 boost::shared_ptr<Beamline::ComponentInfo>
-makeComponentInfo(const Instrument &oldInstr,
+makeComponentInfo(const Instrument &instrument,
                   const API::DetectorInfo &detectorInfo,
                   std::vector<Geometry::ComponentID> &componentIds) {
 
-  InfoComponentVisitor visitor(
-      detectorInfo.size(),
-      std::bind(&DetectorInfo::indexOf, &detectorInfo, std::placeholders::_1));
+  if (instrument.hasComponentInfo()) {
+    const auto &componentInfo = instrument.componentInfo();
+    componentIds = instrument.componentIds();
+    return boost::make_shared<Beamline::ComponentInfo>(componentInfo);
+  } else {
+    InfoComponentVisitor visitor(
+        detectorInfo.size(), std::bind(&DetectorInfo::indexOf, &detectorInfo,
+                                       std::placeholders::_1));
 
-  // Register everything via visitor
-  oldInstr.registerContents(visitor);
-  // Extract component ids. We need this for the ComponentInfo wrapper.
-  componentIds = visitor.componentIds();
+    if (instrument.isParametrized()) {
+      // Register everything via visitor
+      instrument.baseInstrument()->registerContents(visitor);
+    } else {
+      instrument.registerContents(visitor);
+    }
 
-  return boost::make_shared<Mantid::Beamline::ComponentInfo>(
-      visitor.assemblySortedDetectorIndices(),
-      visitor.componentDetectorRanges());
+    // Extract component ids. We need this for the ComponentInfo wrapper.
+    componentIds = visitor.componentIds();
+
+    return boost::make_shared<Mantid::Beamline::ComponentInfo>(
+        visitor.assemblySortedDetectorIndices(),
+        visitor.componentDetectorRanges());
+  }
 }
 
 void clearPositionAndRotationsParameters(ParameterMap &pmap,
@@ -285,11 +296,10 @@ void ExperimentInfo::setInstrument(const Instrument_const_sptr &instr) {
   m_detectorInfoWrapper = Kernel::make_unique<DetectorInfo>(
       *m_detectorInfo, getInstrument(), m_parmap.get());
 
-  std::vector<Geometry::ComponentID> componentIds;
-  m_componentInfo =
-      makeComponentInfo(*sptr_instrument, detectorInfo(), componentIds);
-  m_componentInfoWrapper = Kernel::make_unique<ComponentInfo>(
-      *m_componentInfo, std::move(componentIds));
+  m_componentInfo = makeComponentInfo(*instr, detectorInfo(), m_componentIds);
+  m_parmap->setComponentInfo(m_componentInfo, m_componentIds);
+  m_componentInfoWrapper =
+      Kernel::make_unique<ComponentInfo>(*m_componentInfo, m_componentIds);
   // Detector IDs that were previously dropped because they were not part of the
   // instrument may now suddenly be valid, so we have to reinitialize the
   // detector grouping. Also the index corresponding to specific IDs may have
@@ -308,6 +318,7 @@ Instrument_const_sptr ExperimentInfo::getInstrument() const {
   auto instrument = Geometry::ParComponentFactory::createInstrument(
       sptr_instrument, m_parmap);
   instrument->setDetectorInfo(m_detectorInfo);
+  instrument->setComponentInfo(m_componentInfo, m_componentIds);
   return instrument;
 }
 
diff --git a/Framework/API/src/InfoComponentVisitor.cpp b/Framework/API/src/InfoComponentVisitor.cpp
index 8043a2202ca54545085739680da10b4e2f217c32..71ef479bf0aa87871c845c9579e4172c59254263 100644
--- a/Framework/API/src/InfoComponentVisitor.cpp
+++ b/Framework/API/src/InfoComponentVisitor.cpp
@@ -63,8 +63,17 @@ void InfoComponentVisitor::registerGenericComponent(
  */
 void InfoComponentVisitor::registerDetector(const IDetector &detector) {
 
-  const auto detectorIndex =
-      m_detectorIdToIndexMapperFunction(detector.getID());
+  size_t detectorIndex = 0;
+  try {
+    detectorIndex = m_detectorIdToIndexMapperFunction(detector.getID());
+  } catch (std::out_of_range &) {
+    /*
+     Do not register a detector with an invalid id. if we can't determine
+     the index, we cannot register it in the right place!
+    */
+    ++m_droppedDetectors;
+    return;
+  }
 
   /* Unfortunately Mantid supports having detectors attached to an
    * instrument that have an an invalid or duplicate detector id.
@@ -124,7 +133,9 @@ InfoComponentVisitor::componentIds() const {
  * @return The total size of the components visited.
  * This will be the same as the number of IDs.
  */
-size_t InfoComponentVisitor::size() const { return m_componentIds.size(); }
+size_t InfoComponentVisitor::size() const {
+  return m_componentIds.size() - m_droppedDetectors;
+}
 
 } // namespace API
 } // namespace Mantid
diff --git a/Framework/API/test/ExperimentInfoTest.h b/Framework/API/test/ExperimentInfoTest.h
index f00fbfb9d97ef830dc56302e325bcec50f6b3ac9..f95ecd7902094b18d24dad0b708e2a3eaa40e41b 100644
--- a/Framework/API/test/ExperimentInfoTest.h
+++ b/Framework/API/test/ExperimentInfoTest.h
@@ -964,4 +964,48 @@ private:
   }
 };
 
+class ExperimentInfoTestPerformance : public CxxTest::TestSuite {
+private:
+  boost::shared_ptr<Mantid::Geometry::Instrument> m_bareInstrument;
+  boost::shared_ptr<const Mantid::Geometry::Instrument> m_provisionedInstrument;
+
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static ExperimentInfoTestPerformance *createSuite() {
+    return new ExperimentInfoTestPerformance();
+  }
+  static void destroySuite(ExperimentInfoTestPerformance *suite) {
+    delete suite;
+  }
+
+  ExperimentInfoTestPerformance() {
+
+    const int nPixels = 1000;
+    m_bareInstrument = ComponentCreationHelper::createTestInstrumentRectangular(
+        1 /*n banks*/, nPixels, 1 /*sample-bank distance*/);
+
+    ExperimentInfo tmp;
+    tmp.setInstrument(m_bareInstrument);
+    m_provisionedInstrument = tmp.getInstrument();
+  }
+
+  void
+  test_setInstrument_when_instrument_lacks_detectorInfo_and_componentInfo() {
+    /*
+     * This is similar to what will happen during LoadEmptyInstrument
+     */
+    ExperimentInfo expInfo;
+    expInfo.setInstrument(m_bareInstrument);
+  }
+  void test_setInstrument_when_new_instrument_is_fully_provisioned() {
+    /*
+     * This should be the case for any workspaces after they have initially had
+     * an instrument
+     * set upon them via setInstrument.
+     */
+    ExperimentInfo expInfo;
+    expInfo.setInstrument(m_provisionedInstrument);
+  }
+};
 #endif /* MANTID_API_EXPERIMENTINFOTEST_H_ */
diff --git a/Framework/API/test/InfoComponentVisitorTest.h b/Framework/API/test/InfoComponentVisitorTest.h
index 3b64c5c3a1132e681c7895ba1145ec8ded865018..1f9cb1c1f7f673b76a88ad0c778ca8ea67b148a6 100644
--- a/Framework/API/test/InfoComponentVisitorTest.h
+++ b/Framework/API/test/InfoComponentVisitorTest.h
@@ -36,7 +36,14 @@ public:
     // Visit everything
     visitee->registerContents(visitor);
 
-    TSM_ASSERT_EQUALS("Should have registered 4 components", visitor.size(), 4);
+    size_t expectedSize = 0;
+    ++expectedSize; // source
+    ++expectedSize; // sample
+    ++expectedSize; // Detector
+    ++expectedSize; // instrument
+
+    TSM_ASSERT_EQUALS("Should have registered 4 components", visitor.size(),
+                      expectedSize);
   }
 
   void test_visitor_detector_indexes_check() {
@@ -129,6 +136,66 @@ public:
     TS_ASSERT_EQUALS(ranges[2].first, 0);
     TS_ASSERT_EQUALS(ranges[2].second, 1);
   }
+
+  void test_visitor_drops_detectors_without_id() {
+    /*
+     We have to go via DetectorInfo::indexOf to get the index of a detector.
+     if this throws because the detector has an invalid id, we are forced to
+     drop it.
+
+     Some IDFs i.e. SNAP have montiors with detector ids <  0.
+    */
+
+    // Create a very basic instrument to visit
+    auto visitee = createMinimalInstrument(V3D(0, 0, 0) /*source pos*/,
+                                           V3D(10, 0, 0) /*sample pos*/
+                                           ,
+                                           V3D(11, 0, 0) /*detector position*/);
+
+    // Create the visitor. Note any access to the indexOf lambda will throw for
+    // detectors.
+    InfoComponentVisitor visitor(1, [](const Mantid::detid_t) -> size_t {
+      throw std::out_of_range("");
+    });
+
+    // Visit everything
+    visitee->registerContents(visitor);
+
+    size_t expectedSize = 0;
+    ++expectedSize; // source
+    ++expectedSize; // sample
+    ++expectedSize; // instrument
+    // Note no detector counted
+    TS_ASSERT_EQUALS(visitor.size(), expectedSize);
+  }
 };
 
+class InfoComponentVisitorTestPerformance : public CxxTest::TestSuite {
+private:
+  const int m_nPixels = 1000;
+  boost::shared_ptr<Mantid::Geometry::Instrument> m_instrument;
+
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static InfoComponentVisitorTestPerformance *createSuite() {
+    return new InfoComponentVisitorTestPerformance();
+  }
+  static void destroySuite(InfoComponentVisitorTestPerformance *suite) {
+    delete suite;
+  }
+
+  InfoComponentVisitorTestPerformance() {
+    m_instrument = ComponentCreationHelper::createTestInstrumentRectangular(
+        1 /*n banks*/, m_nPixels, 1 /*sample-bank distance*/);
+  }
+
+  void test_process_rectangular_instrument() {
+    InfoComponentVisitor visitor(
+        m_nPixels * m_nPixels,
+        [](const Mantid::detid_t id) { return static_cast<size_t>(id); });
+    m_instrument->registerContents(visitor);
+    TS_ASSERT(visitor.size() >= size_t(m_nPixels * m_nPixels));
+  }
+};
 #endif /* MANTID_API_INFOCOMPONENTVISITORTEST_H_ */
diff --git a/Framework/Algorithms/test/DiffractionFocussing2Test.h b/Framework/Algorithms/test/DiffractionFocussing2Test.h
index 7f8cb32fdfe1e9cc5d015dfa147344e835e498f9..df4762852c2a30c380907bb6c5963c17a17b77cc 100644
--- a/Framework/Algorithms/test/DiffractionFocussing2Test.h
+++ b/Framework/Algorithms/test/DiffractionFocussing2Test.h
@@ -262,6 +262,7 @@ public:
     IAlgorithm_sptr alg =
         AlgorithmFactory::Instance().create("LoadEmptyInstrument", 1);
     alg->initialize();
+    alg->setRethrows(true);
     alg->setPropertyValue("Filename", "SNAP_Definition.xml");
     alg->setPropertyValue("OutputWorkspace", "SNAP_empty");
     alg->setPropertyValue("MakeEventWorkspace", "1");
diff --git a/Framework/Beamline/inc/MantidBeamline/ComponentInfo.h b/Framework/Beamline/inc/MantidBeamline/ComponentInfo.h
index f37243f8ae84054557fb1874a2090f666bfbb62a..b0296fd79ca72602f8b28b6ec93617b523b5723c 100644
--- a/Framework/Beamline/inc/MantidBeamline/ComponentInfo.h
+++ b/Framework/Beamline/inc/MantidBeamline/ComponentInfo.h
@@ -40,7 +40,7 @@ class MANTID_BEAMLINE_DLL ComponentInfo {
 private:
   boost::shared_ptr<std::vector<size_t>> m_assemblySortedDetectorIndices;
   boost::shared_ptr<const std::vector<std::pair<size_t, size_t>>> m_ranges;
-  const size_t m_size = 0;
+  size_t m_size = 0;
 
 public:
   ComponentInfo();
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument.h b/Framework/Geometry/inc/MantidGeometry/Instrument.h
index 5297cd70c1024a5593966b3b0ab67858e96fc455..8d04eed3b585f73b542dc96002fc3299292401f1 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument.h
+++ b/Framework/Geometry/inc/MantidGeometry/Instrument.h
@@ -19,6 +19,7 @@ namespace Mantid {
 typedef std::map<detid_t, Geometry::IDetector_const_sptr> detid2det_map;
 
 namespace Beamline {
+class ComponentInfo;
 class DetectorInfo;
 }
 namespace Geometry {
@@ -243,10 +244,16 @@ public:
 
   bool hasDetectorInfo() const;
   const Beamline::DetectorInfo &detectorInfo() const;
+  bool hasComponentInfo() const;
+  const Beamline::ComponentInfo &componentInfo() const;
+
   size_t detectorIndex(const detid_t detID) const;
   void
   setDetectorInfo(boost::shared_ptr<const Beamline::DetectorInfo> detectorInfo);
-
+  void setComponentInfo(
+      boost::shared_ptr<const Beamline::ComponentInfo> componentInfo,
+      std::vector<Geometry::ComponentID> componentIds);
+  const std::vector<Geometry::ComponentID> &componentIds() const;
   boost::shared_ptr<ParameterMap> makeLegacyParameterMap() const;
 
 private:
@@ -327,6 +334,9 @@ private:
   /// Pointer to the DetectorInfo object. NULL unless the instrument is
   /// associated with an ExperimentInfo object.
   boost::shared_ptr<const Beamline::DetectorInfo> m_detectorInfo{nullptr};
+
+  boost::shared_ptr<const Beamline::ComponentInfo> m_componentInfo{nullptr};
+  std::vector<Geometry::ComponentID> m_componentIds;
 };
 namespace Conversion {
 
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterMap.h b/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterMap.h
index 87a8b77d562b7afe92d6469d0063829b1a44230d..e9d449b5db8a71941f65b22c54dd731b60f189bc 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterMap.h
+++ b/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterMap.h
@@ -18,6 +18,7 @@ namespace Kernel {
 template <class KEYTYPE, class VALUETYPE> class Cache;
 }
 namespace Beamline {
+class ComponentInfo;
 class DetectorInfo;
 }
 namespace Geometry {
@@ -346,9 +347,15 @@ public:
 
   bool hasDetectorInfo() const;
   const Beamline::DetectorInfo &detectorInfo() const;
+  bool hasComponentInfo() const;
+  const Beamline::ComponentInfo &componentInfo() const;
   size_t detectorIndex(const detid_t detID) const;
+  const std::vector<Geometry::ComponentID> &componentIds() const;
   void
   setDetectorInfo(boost::shared_ptr<const Beamline::DetectorInfo> detectorInfo);
+  void setComponentInfo(
+      boost::shared_ptr<const Beamline::ComponentInfo> componentInfo,
+      std::vector<Geometry::ComponentID> componentIds);
   void setInstrument(const Instrument *instrument);
 
 private:
@@ -381,8 +388,13 @@ private:
   /// Pointer to the DetectorInfo object. NULL unless the instrument is
   /// associated with an ExperimentInfo object.
   boost::shared_ptr<const Beamline::DetectorInfo> m_detectorInfo{nullptr};
+  /// Pointer to the ComponentInfo object. NULL unless the instrument is
+  /// associated with an ExperimentInfo object.
+  boost::shared_ptr<const Beamline::ComponentInfo> m_componentInfo{nullptr};
+  /// Component ids.
+  std::vector<Geometry::ComponentID> m_componentIds;
   /// Pointer to the owning instrument for translating detector IDs into
-  /// detector indices when accessing the DetectorInfo object.
+  /// detector indices when accessing the DetectorInfo object
   const Instrument *m_instrument{nullptr};
 };
 
diff --git a/Framework/Geometry/src/Instrument.cpp b/Framework/Geometry/src/Instrument.cpp
index caa2d371f591101b426fa05e9aaaebc0b6ebf260..f7309b4999b58081f400cb6eafad475229d44d14 100644
--- a/Framework/Geometry/src/Instrument.cpp
+++ b/Framework/Geometry/src/Instrument.cpp
@@ -5,6 +5,7 @@
 #include "MantidGeometry/Instrument/RectangularDetector.h"
 #include "MantidGeometry/Instrument/RectangularDetectorPixel.h"
 #include "MantidBeamline/DetectorInfo.h"
+#include "MantidBeamline/ComponentInfo.h"
 #include "MantidKernel/EigenConversionHelpers.h"
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/Logger.h"
@@ -50,7 +51,8 @@ Instrument::Instrument(const boost::shared_ptr<const Instrument> instr,
       m_defaultViewAxis(instr->m_defaultViewAxis), m_instr(instr),
       m_map_nonconst(map), m_ValidFrom(instr->m_ValidFrom),
       m_ValidTo(instr->m_ValidTo), m_referenceFrame(new ReferenceFrame),
-      m_detectorInfo(instr->m_detectorInfo) {
+      m_detectorInfo(instr->m_detectorInfo),
+      m_componentInfo(instr->m_componentInfo) {
   m_map_nonconst->setInstrument(m_instr.get());
 }
 
@@ -69,7 +71,10 @@ Instrument::Instrument(const Instrument &instr)
       m_map_nonconst(), /* Should not be parameterized */
       m_ValidFrom(instr.m_ValidFrom), m_ValidTo(instr.m_ValidTo),
       m_referenceFrame(instr.m_referenceFrame),
-      m_detectorInfo(instr.m_detectorInfo) {
+      m_detectorInfo(instr.m_detectorInfo),
+      m_componentInfo(instr.m_componentInfo)
+
+{
   // Now we need to fill the detector, source and sample caches with pointers
   // into the new instrument
   std::vector<IComponent_const_sptr> children;
@@ -1233,12 +1238,57 @@ const Beamline::DetectorInfo &Instrument::detectorInfo() const {
   return *m_detectorInfo;
 }
 
+/**
+ * @brief Instrument::hasComponentInfo
+ * @return True only if a ComponentInfo has been set
+ */
+bool Instrument::hasComponentInfo() const {
+  return static_cast<bool>(m_componentInfo);
+}
+
+/**
+ * @brief Instrument::componentInfo
+ * @return const ref to a ComponentInfo. Throws a std::runtime_error if
+ * not set.
+ */
+const Beamline::ComponentInfo &Instrument::componentInfo() const {
+  if (!hasComponentInfo()) {
+    throw std::runtime_error("Cannot return reference to NULL ComponentInfo");
+  }
+  return *m_componentInfo;
+}
+
+/**
+ * @brief Instrument::componentIds
+ * @return const ref to a vector of ComponentIds. Throws a std::runtime_error if
+ * Component Info not set.
+ */
+const std::vector<Geometry::ComponentID> &Instrument::componentIds() const {
+  if (!hasComponentInfo()) {
+    throw std::runtime_error(
+        "Cannot return component ids with a NULL ComponentInfo");
+  }
+  return m_componentIds;
+}
+
 /// Only for use by ExperimentInfo. Sets the pointer to the DetectorInfo.
 void Instrument::setDetectorInfo(
     boost::shared_ptr<const Beamline::DetectorInfo> detectorInfo) {
   m_detectorInfo = std::move(detectorInfo);
 }
 
+/**
+ * @brief Instrument::setComponentInfo
+ * @param componentInfo : ComponentInfo to store
+ * @param componentIds : ComponentIds to store
+ */
+void Instrument::setComponentInfo(
+    boost::shared_ptr<const Beamline::ComponentInfo> componentInfo,
+    std::vector<Geometry::ComponentID> componentIds) {
+  m_componentInfo = std::move(componentInfo);
+  m_componentIds = std::move(componentIds);
+}
+
 /// Returns the index for a detector ID. Used for accessing DetectorInfo.
 size_t Instrument::detectorIndex(const detid_t detID) const {
   const auto &baseInstr = m_map ? *m_instr : *this;
diff --git a/Framework/Geometry/src/Instrument/ParameterMap.cpp b/Framework/Geometry/src/Instrument/ParameterMap.cpp
index 7b157c7d3723d9ca4cb0ac7dc493f0546c6a9823..b8b820d02280a70de5b18771c5006273dc83b575 100644
--- a/Framework/Geometry/src/Instrument/ParameterMap.cpp
+++ b/Framework/Geometry/src/Instrument/ParameterMap.cpp
@@ -2,6 +2,8 @@
 #include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidKernel/Cache.h"
+#include "MantidBeamline/ComponentInfo.h"
+#include "MantidBeamline/DetectorInfo.h"
 #include "MantidKernel/MultiThreaded.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/ParameterFactory.h"
@@ -1162,6 +1164,41 @@ const Beamline::DetectorInfo &ParameterMap::detectorInfo() const {
   return *m_detectorInfo;
 }
 
+/**
+ * @brief ParameterMap::hasComponentInfo
+ * @return True if a ComponentInfo is stored.
+ */
+bool ParameterMap::hasComponentInfo() const {
+  return static_cast<bool>(m_componentInfo);
+}
+
+/**
+ * @brief ParameterMap::componentInfo
+ * @return A const ref to the ComponentInfo if stored. Throws a
+ * std::runtime_error
+ * exception otherwise.
+ */
+const Beamline::ComponentInfo &ParameterMap::componentInfo() const {
+  if (!hasComponentInfo()) {
+    throw std::runtime_error("Cannot return reference to NULL ComponentInfo");
+  }
+  return *m_componentInfo;
+}
+
+/**
+ * @brief ParameterMap::componentIds
+ * @return const ref to vector of component ids. Throws a std::runtime_error if
+ * the ComponentInfo has not been set.
+ */
+const std::vector<Geometry::ComponentID> &ParameterMap::componentIds() const {
+  // Component ids do not make sense without a ComponentInfo
+  if (!hasComponentInfo()) {
+    throw std::runtime_error(
+        "Cannot return component ids when ComponentInfo is NULL");
+  }
+  return m_componentIds;
+}
+
 /// Only for use by Detector. Returns a detector index for a detector ID.
 size_t ParameterMap::detectorIndex(const detid_t detID) const {
   return m_instrument->detectorIndex(detID);
@@ -1173,6 +1210,14 @@ void ParameterMap::setDetectorInfo(
   m_detectorInfo = std::move(detectorInfo);
 }
 
+/// Only for use by ExperimentInfo. Sets the pointer to the ComponentInfo.
+void ParameterMap::setComponentInfo(
+    boost::shared_ptr<const Beamline::ComponentInfo> componentInfo,
+    std::vector<Geometry::ComponentID> componentIds) {
+  m_componentInfo = std::move(componentInfo);
+  m_componentIds = std::move(componentIds);
+}
+
 /// Only for use by Instrument. Sets the pointer to the owning instrument.
 void ParameterMap::setInstrument(const Instrument *instrument) {
   m_instrument = instrument;