diff --git a/Framework/DataHandling/CMakeLists.txt b/Framework/DataHandling/CMakeLists.txt
index 7db38254628aa5ce3be44399c4166a4a2b0e6c63..d1d6b69016858201fda69f7e2d8d1e792a314352 100644
--- a/Framework/DataHandling/CMakeLists.txt
+++ b/Framework/DataHandling/CMakeLists.txt
@@ -47,18 +47,17 @@ set(SRC_FILES
     src/LoadDetectorsGroupingFile.cpp
     src/LoadDiffCal.cpp
     src/LoadDspacemap.cpp
-    src/LoadEmptyInstrument.cpp
     src/LoadEMU.cpp
-    src/LoadOff.cpp
-    src/LoadPLN.cpp
+    src/LoadEmptyInstrument.cpp
     src/LoadEventNexus.cpp
     src/LoadEventNexusIndexSetup.cpp
     src/LoadEventPreNexus2.cpp
     src/LoadFITS.cpp
     src/LoadFullprofResolution.cpp
-    src/LoadGeometry.cpp
     src/LoadGSASInstrumentFile.cpp
     src/LoadGSS.cpp
+    src/LoadGeometry.cpp
+    src/LoadHFIRSANS.cpp
     src/LoadHelper.cpp
     src/LoadIDFFromNexus.cpp
     src/LoadILLDiffraction.cpp
@@ -91,11 +90,13 @@ set(SRC_FILES
     src/LoadNexusMonitors.cpp
     src/LoadNexusMonitors2.cpp
     src/LoadNexusProcessed.cpp
+    src/LoadOff.cpp
     src/LoadPDFgetNFile.cpp
+    src/LoadPLN.cpp
+    src/LoadPSIMuonBin.cpp
     src/LoadParameterFile.cpp
     src/LoadPreNexus.cpp
     src/LoadPreNexusMonitors.cpp
-    src/LoadPSIMuonBin.cpp
     src/LoadQKK.cpp
     src/LoadRKH.cpp
     src/LoadRaw/byte_rel_comp.cpp
@@ -107,21 +108,20 @@ set(SRC_FILES
     src/LoadRawBin0.cpp
     src/LoadRawHelper.cpp
     src/LoadRawSpectrum0.cpp
-    src/LoadSampleShape.cpp
-    src/LoadSampleEnvironment.cpp
     src/LoadSESANS.cpp
     src/LoadSINQFocus.cpp
     src/LoadSNSspec.cpp
     src/LoadSPE.cpp
     src/LoadSampleDetailsFromRaw.cpp
+    src/LoadSampleEnvironment.cpp
+    src/LoadSampleShape.cpp
     src/LoadSassena.cpp
     src/LoadSpec.cpp
     src/LoadSpice2D.cpp
-    src/LoadHFIRSANS.cpp
     src/LoadSpiceAscii.cpp
     src/LoadSpiceXML2DDet.cpp
-    src/LoadSwans.cpp
     src/LoadStl.cpp
+    src/LoadSwans.cpp
     src/LoadTBL.cpp
     src/LoadTOFRawNexus.cpp
     src/LoadVulcanCalFile.cpp
@@ -170,6 +170,7 @@ set(SRC_FILES
     src/SaveNXTomo.cpp
     src/SaveNXcanSAS.cpp
     src/SaveNexus.cpp
+    src/SaveNexusGeometry.cpp
     src/SaveNexusProcessed.cpp
     src/SaveOpenGenieAscii.cpp
     src/SavePAR.cpp
@@ -177,12 +178,12 @@ set(SRC_FILES
     src/SavePHX.cpp
     src/SaveParameterFile.cpp
     src/SaveRKH.cpp
-    src/SaveReflectometryAscii.cpp
     src/SaveReflCustomAscii.cpp
     src/SaveReflThreeColumnAscii.cpp
-    src/SaveSampleEnvironmentAndShape.cpp
+    src/SaveReflectometryAscii.cpp
     src/SaveSESANS.cpp
     src/SaveSPE.cpp
+    src/SaveSampleEnvironmentAndShape.cpp
     src/SaveStl.cpp
     src/SaveTBL.cpp
     src/SaveToSNSHistogramNexus.cpp
@@ -246,18 +247,17 @@ set(INC_FILES
     inc/MantidDataHandling/LoadDetectorsGroupingFile.h
     inc/MantidDataHandling/LoadDiffCal.h
     inc/MantidDataHandling/LoadDspacemap.h
-    inc/MantidDataHandling/LoadEmptyInstrument.h
     inc/MantidDataHandling/LoadEMU.h
-    inc/MantidDataHandling/LoadOff.h
-    inc/MantidDataHandling/LoadPLN.h
+    inc/MantidDataHandling/LoadEmptyInstrument.h
     inc/MantidDataHandling/LoadEventNexus.h
     inc/MantidDataHandling/LoadEventNexusIndexSetup.h
     inc/MantidDataHandling/LoadEventPreNexus2.h
     inc/MantidDataHandling/LoadFITS.h
     inc/MantidDataHandling/LoadFullprofResolution.h
-    inc/MantidDataHandling/LoadGeometry.h
     inc/MantidDataHandling/LoadGSASInstrumentFile.h
     inc/MantidDataHandling/LoadGSS.h
+    inc/MantidDataHandling/LoadGeometry.h
+    inc/MantidDataHandling/LoadHFIRSANS.h
     inc/MantidDataHandling/LoadHelper.h
     inc/MantidDataHandling/LoadIDFFromNexus.h
     inc/MantidDataHandling/LoadILLDiffraction.h
@@ -290,29 +290,30 @@ set(INC_FILES
     inc/MantidDataHandling/LoadNexusMonitors.h
     inc/MantidDataHandling/LoadNexusMonitors2.h
     inc/MantidDataHandling/LoadNexusProcessed.h
+    inc/MantidDataHandling/LoadOff.h
     inc/MantidDataHandling/LoadPDFgetNFile.h
+    inc/MantidDataHandling/LoadPLN.h
+    inc/MantidDataHandling/LoadPSIMuonBin.h
     inc/MantidDataHandling/LoadParameterFile.h
     inc/MantidDataHandling/LoadPreNexus.h
     inc/MantidDataHandling/LoadPreNexusMonitors.h
-    inc/MantidDataHandling/LoadPSIMuonBin.h
     inc/MantidDataHandling/LoadQKK.h
     inc/MantidDataHandling/LoadRKH.h
     inc/MantidDataHandling/LoadRaw3.h
     inc/MantidDataHandling/LoadRawBin0.h
     inc/MantidDataHandling/LoadRawHelper.h
     inc/MantidDataHandling/LoadRawSpectrum0.h
-    inc/MantidDataHandling/LoadSampleShape.h
-    inc/MantidDataHandling/LoadSampleEnvironment.h
     inc/MantidDataHandling/LoadSESANS.h
     inc/MantidDataHandling/LoadSINQFocus.h
     inc/MantidDataHandling/LoadSNSspec.h
     inc/MantidDataHandling/LoadSPE.h
     inc/MantidDataHandling/LoadSampleDetailsFromRaw.h
+    inc/MantidDataHandling/LoadSampleEnvironment.h
+    inc/MantidDataHandling/LoadSampleShape.h
     inc/MantidDataHandling/LoadSassena.h
     inc/MantidDataHandling/LoadShape.h
     inc/MantidDataHandling/LoadSpec.h
     inc/MantidDataHandling/LoadSpice2D.h
-    inc/MantidDataHandling/LoadHFIRSANS.h
     inc/MantidDataHandling/LoadSpiceAscii.h
     inc/MantidDataHandling/LoadSpiceXML2DDet.h
     inc/MantidDataHandling/LoadStl.h
@@ -366,6 +367,7 @@ set(INC_FILES
     inc/MantidDataHandling/SaveNXTomo.h
     inc/MantidDataHandling/SaveNXcanSAS.h
     inc/MantidDataHandling/SaveNexus.h
+    inc/MantidDataHandling/SaveNexusGeometry.h
     inc/MantidDataHandling/SaveNexusProcessed.h
     inc/MantidDataHandling/SaveOpenGenieAscii.h
     inc/MantidDataHandling/SavePAR.h
@@ -373,12 +375,12 @@ set(INC_FILES
     inc/MantidDataHandling/SavePHX.h
     inc/MantidDataHandling/SaveParameterFile.h
     inc/MantidDataHandling/SaveRKH.h
-    inc/MantidDataHandling/SaveReflectometryAscii.h
     inc/MantidDataHandling/SaveReflCustomAscii.h
     inc/MantidDataHandling/SaveReflThreeColumnAscii.h
-    inc/MantidDataHandling/SaveSampleEnvironmentAndShape.h
+    inc/MantidDataHandling/SaveReflectometryAscii.h
     inc/MantidDataHandling/SaveSESANS.h
     inc/MantidDataHandling/SaveSPE.h
+    inc/MantidDataHandling/SaveSampleEnvironmentAndShape.h
     inc/MantidDataHandling/SaveStl.h
     inc/MantidDataHandling/SaveTBL.h
     inc/MantidDataHandling/SaveToSNSHistogramNexus.h
@@ -427,8 +429,8 @@ set(TEST_FILES
     InstrumentRayTracerTest.h
     JoinISISPolarizationEfficienciesTest.h
     LoadAscii2Test.h
-    LoadAsciiTest.h
     LoadAsciiStlTest.h
+    LoadAsciiTest.h
     LoadBBYTest.h
     LoadBinaryStlTest.h
     LoadCalFileTest.h
@@ -438,8 +440,8 @@ set(TEST_FILES
     LoadDetectorsGroupingFileTest.h
     LoadDiffCalTest.h
     LoadDspacemapTest.h
-    LoadEmptyInstrumentTest.h
     LoadEMUauTest.h
+    LoadEmptyInstrumentTest.h
     LoadEventNexusIndexSetupTest.h
     LoadEventNexusTest.h
     LoadEventPreNexus2Test.h
@@ -447,6 +449,7 @@ set(TEST_FILES
     LoadFullprofResolutionTest.h
     LoadGSASInstrumentFileTest.h
     LoadGSSTest.h
+    LoadHFIRSANSTest.h
     LoadIDFFromNexusTest.h
     LoadILLDiffractionTest.h
     LoadILLIndirect2Test.h
@@ -477,32 +480,31 @@ set(TEST_FILES
     LoadNexusProcessedTest.h
     LoadNexusTest.h
     LoadPDFgetNFileTest.h
-    LoadParameterFileTest.h
     LoadPLNTest.h
+    LoadPSIMuonBinTest.h
+    LoadParameterFileTest.h
     LoadPreNexusMonitorsTest.h
     LoadPreNexusTest.h
-    LoadPSIMuonBinTest.h
     LoadQKKTest.h
     LoadRKHTest.h
     LoadRaw3Test.h
     LoadRawBin0Test.h
     LoadRawSaveNxsLoadNxsTest.h
     LoadRawSpectrum0Test.h
-    LoadStlTest.h
-    LoadSampleShapeTest.h
-    LoadSampleEnvironmentTest.h
     LoadSESANSTest.h
     LoadSINQFocusTest.h
     LoadSNSspecTest.h
     LoadSPETest.h
     LoadSampleDetailsFromRawTest.h
+    LoadSampleEnvironmentTest.h
+    LoadSampleShapeTest.h
     LoadSassenaTest.h
     LoadSaveAsciiTest.h
     LoadSpecTest.h
     LoadSpice2dTest.h
-    LoadHFIRSANSTest.h
     LoadSpiceAsciiTest.h
     LoadSpiceXML2DDetTest.h
+    LoadStlTest.h
     LoadSwansTest.h
     LoadTBLTest.h
     LoadTOFRawNexusTest.h
@@ -547,6 +549,7 @@ set(TEST_FILES
     SaveNXSPETest.h
     SaveNXTomoTest.h
     SaveNXcanSASTest.h
+    SaveNexusGeometryTest.h
     SaveNexusProcessedTest.h
     SaveNexusTest.h
     SaveOpenGenieAsciiTest.h
@@ -555,12 +558,12 @@ set(TEST_FILES
     SavePHXTest.h
     SaveParameterFileTest.h
     SaveRKHTest.h
-    SaveReflectometryAsciiTest.h
     SaveReflCustomAsciiTest.h
     SaveReflThreeColumnAsciiTest.h
-    SaveSampleEnvironmentAndShapeTest.h
+    SaveReflectometryAsciiTest.h
     SaveSESANSTest.h
     SaveSPETest.h
+    SaveSampleEnvironmentAndShapeTest.h
     SaveStlTest.h
     SaveTBLTest.h
     SaveToSNSHistogramNexusTest.h
diff --git a/Framework/DataHandling/inc/MantidDataHandling/SaveNexusGeometry.h b/Framework/DataHandling/inc/MantidDataHandling/SaveNexusGeometry.h
new file mode 100644
index 0000000000000000000000000000000000000000..fff3604f30a91021c3b66368caaaa7052d8c569d
--- /dev/null
+++ b/Framework/DataHandling/inc/MantidDataHandling/SaveNexusGeometry.h
@@ -0,0 +1,40 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright © 2019 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+
+/* SaveNexusGeometry : A thin Algorithm wrapper over
+ * NexusGeometry::saveInstrument allowing user to save the geometry from
+ * instrument attached to a workspace.
+ *
+ * @author Takudzwa Makoni, RAL (UKRI), ISIS
+ * @date 16/08/2019
+ */
+#ifndef MANTID_DATAHANDLING_SAVENEXUSGEOMETRY_H_
+#define MANTID_DATAHANDLING_SAVENEXUSGEOMETRY_H_
+
+#include "MantidAPI/Algorithm.h"
+#include "MantidDataHandling/DllConfig.h"
+
+namespace Mantid {
+
+namespace DataHandling {
+
+class MANTID_DATAHANDLING_DLL SaveNexusGeometry : public API::Algorithm {
+public:
+  const std::string name() const override;
+  int version() const override;
+  const std::string category() const override;
+  const std::string summary() const override;
+
+private:
+  void init() override;
+  void exec() override;
+};
+
+} // namespace DataHandling
+} // namespace Mantid
+
+#endif /* MANTID_DATAHANDLING_SAVENEXUSGEOMETRY_H_ */
\ No newline at end of file
diff --git a/Framework/DataHandling/src/SaveNexusGeometry.cpp b/Framework/DataHandling/src/SaveNexusGeometry.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..440c88b799855a5553b3a22a1bf60be8d417d544
--- /dev/null
+++ b/Framework/DataHandling/src/SaveNexusGeometry.cpp
@@ -0,0 +1,100 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright © 2019 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+
+/* SaveNexusGeometry : A thin Algorithm wrapper over
+ * NexusGeometry::saveInstrument allowing user to save the geometry from
+ * instrument attached to a workspace.
+ *
+ * @author Takudzwa Makoni, RAL (UKRI), ISIS
+ * @date 16/08/2019
+ */
+#include "MantidDataHandling/SaveNexusGeometry.h"
+#include "MantidAPI/ExperimentInfo.h"
+#include "MantidAPI/FileProperty.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceProperty.h"
+#include "MantidGeometry/Instrument/ComponentInfo.h"
+#include "MantidGeometry/Instrument/DetectorInfo.h"
+#include "MantidGeometry/Instrument/InstrumentVisitor.h"
+#include "MantidNexusGeometry/NexusGeometrySave.h"
+
+#include <memory>
+#include <utility>
+
+namespace Mantid {
+namespace DataHandling {
+using Mantid::API::WorkspaceProperty;
+using Mantid::Kernel::Direction;
+
+// Register the algorithm into the AlgorithmFactory
+DECLARE_ALGORITHM(SaveNexusGeometry)
+
+//----------------------------------------------------------------------------------------------
+
+/// Algorithms name for identification. @see Algorithm::name
+
+const std::string SaveNexusGeometry::name() const {
+  return "SaveNexusGeometry";
+}
+
+/// Algorithm's version for identification. @see Algorithm::version
+
+int SaveNexusGeometry::version() const { return 1; }
+
+/// Algorithm's category for identification. @see Algorithm::category
+
+const std::string SaveNexusGeometry::category() const {
+  return "DataHandling\\Instrument";
+}
+
+/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
+
+const std::string SaveNexusGeometry::summary() const {
+  return "Save the instrument from a workspace to a Nexus-format"
+         " HDF file. WARNING: shapes are NOT saved in the present version "
+         "(1.0).";
+}
+
+//----------------------------------------------------------------------------------------------
+
+/** Initialize the algorithm's properties.
+ */
+void SaveNexusGeometry::init() {
+
+  // TODO resolve linkererror for experimentinfo, replace MatrixWorkspace with
+  // base class ExperimentInfo.
+  declareProperty(std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>(
+                      "InputWorkspace", "", Direction::Input),
+                  "Workspace containing the Instrument.");
+
+  declareProperty(std::make_unique<API::FileProperty>(
+                      "Filename", "", API::FileProperty::OptionalSave),
+                  "Full path to save destination file");
+
+  declareProperty("H5Path", "entry" /*default*/,
+                  "(optional) Name of the H5 root group in which the "
+                  "Instrument is to be saved. Default name: 'entry'.");
+}
+
+//----------------------------------------------------------------------------------------------
+/** Execute the algorithm.
+ */
+void SaveNexusGeometry::exec() {
+  API::MatrixWorkspace_const_sptr workspace = getProperty("InputWorkspace");
+  std::string destinationFile = getPropertyValue("FileName");
+  std::string rootFileName = getPropertyValue("H5Path");
+
+  auto ws = workspace.get();
+  const auto &compInfo = ws->componentInfo();
+  const auto &detInfo = ws->detectorInfo();
+
+  Mantid::NexusGeometry::NexusGeometrySave::saveInstrument(
+      compInfo, detInfo, destinationFile, rootFileName);
+}
+
+} // namespace DataHandling
+} // namespace Mantid
diff --git a/Framework/DataHandling/test/CMakeLists.txt b/Framework/DataHandling/test/CMakeLists.txt
index 036e8017ef87c69410f1355989c691b55dc189ec..6bfa6330a242b431357a7791bb5840a0562cf9fa 100644
--- a/Framework/DataHandling/test/CMakeLists.txt
+++ b/Framework/DataHandling/test/CMakeLists.txt
@@ -1,5 +1,6 @@
 if(CXXTEST_FOUND)
-  include_directories(SYSTEM ${CXXTEST_INCLUDE_DIR})
+  include_directories(SYSTEM 
+				      ${CXXTEST_INCLUDE_DIR})
 
   include_directories(../../TestHelpers/inc)
   # This variable is used within the cxxtest_add_test macro to build this helper
diff --git a/Framework/DataHandling/test/SaveNexusGeometryTest.h b/Framework/DataHandling/test/SaveNexusGeometryTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..ffe5edebda30d18103542ba98feb040f81268c23
--- /dev/null
+++ b/Framework/DataHandling/test/SaveNexusGeometryTest.h
@@ -0,0 +1,193 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2019 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef MANTID_DATAHANDLING_SAVENEXUSGEOMETRYTEST_H_
+#define MANTID_DATAHANDLING_SAVENEXUSGEOMETRYTEST_H_
+
+#include "MantidAPI/IEventWorkspace.h"
+#include "MantidAPI/ITableWorkspace.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceProperty.h"
+#include "MantidDataHandling/LoadEmptyInstrument.h"
+#include "MantidDataHandling/SaveNexusGeometry.h"
+#include "MantidKernel/ProgressBase.h"
+#include "MantidTestHelpers/FileResource.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+
+#include <H5Cpp.h>
+#include <boost/filesystem.hpp>
+#include <cxxtest/TestSuite.h>
+
+using Mantid::DataHandling::SaveNexusGeometry;
+
+class SaveNexusGeometryTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static SaveNexusGeometryTest *createSuite() {
+    return new SaveNexusGeometryTest();
+  }
+  static void destroySuite(SaveNexusGeometryTest *suite) { delete suite; }
+
+  void test_Init() {
+    SaveNexusGeometry alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+  }
+
+  void test_exec() {
+
+    ScopedFileHandle fileResource("algorithm_test_file.hdf5");
+    auto destinationFile = fileResource.fullPath();
+    // Create test input if necessary
+    Mantid::API::IEventWorkspace_sptr inputWS =
+        WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument2(1, 5);
+
+    TS_ASSERT_THROWS_NOTHING(
+        Mantid::API::AnalysisDataService::Instance().addOrReplace("testWS",
+                                                                  inputWS));
+    SaveNexusGeometry alg;
+
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", "testWS"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("FileName", destinationFile));
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("H5Path", "algorithm_test_data"));
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+
+    TS_ASSERT_THROWS_NOTHING(
+        Mantid::API::AnalysisDataService::Instance().remove("testWS"));
+  }
+
+  void
+  test_execution_succesful_when_no_h5_root_provided_and_default_root_is_used() {
+
+    ScopedFileHandle fileResource("algorithm_no_h5_root_file.hdf5");
+    auto destinationFile = fileResource.fullPath();
+    // Create test input if necessary
+    Mantid::API::IEventWorkspace_sptr inputWS =
+        WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument2(1, 5);
+
+    TS_ASSERT_THROWS_NOTHING(
+        Mantid::API::AnalysisDataService::Instance().addOrReplace("testWS",
+                                                                  inputWS));
+    SaveNexusGeometry alg;
+
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", "testWS"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("FileName", destinationFile));
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+
+    TS_ASSERT_THROWS_NOTHING(
+        Mantid::API::AnalysisDataService::Instance().remove("testWS"));
+  }
+
+  void test_invalid_workspace_throws() {
+
+    /*
+    test runtime error is thrown when a workspae without an Instrument is passed
+    into the Input workspace property.
+    */
+
+    ScopedFileHandle fileResource(
+        "algorithm_no_instrument_in_workspace_provided_test_file.hdf5");
+    auto destinationFile = fileResource.fullPath();
+    // Create test input if necessary
+
+    WorkspaceCreationHelper::EPPTableRow row(
+        1, 1, 1, WorkspaceCreationHelper::EPPTableRow::FitStatus::SUCCESS);
+    std::vector<WorkspaceCreationHelper::EPPTableRow> rows{row};
+    Mantid::API::ITableWorkspace_sptr inputWS =
+        WorkspaceCreationHelper::createEPPTableWorkspace(rows);
+
+    TS_ASSERT_THROWS_NOTHING(
+        Mantid::API::AnalysisDataService::Instance().addOrReplace("testWS",
+                                                                  inputWS));
+    SaveNexusGeometry alg;
+    // Don't put output in ADS by default
+
+    alg.setChild(false);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize());
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS(alg.setProperty("InputWorkspace", "testWS"),
+                     std::invalid_argument &);
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("FileName", destinationFile));
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error &);
+    TS_ASSERT(!alg.isExecuted());
+
+    TS_ASSERT_THROWS_NOTHING(
+        Mantid::API::AnalysisDataService::Instance().remove("testWS"));
+  }
+
+  void test_valid_fileName_with_invalid_extension_propagates_throw() {
+    /*
+    test saveInstrument propagates invalid_argument in executuion of algorithm
+    when invalid file extension is passed into fileName property.
+    */
+
+    ScopedFileHandle fileResource(
+        "algorithm_invalid_extension_provided_test_file.txt");
+    auto destinationFile = fileResource.fullPath();
+    // Create test workspace
+    Mantid::API::IEventWorkspace_sptr inputWS =
+        WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument2(5, 5);
+
+    TS_ASSERT_THROWS_NOTHING(
+        Mantid::API::AnalysisDataService::Instance().addOrReplace("testWS",
+                                                                  inputWS));
+    SaveNexusGeometry alg;
+    // Don't put output in ADS by default
+
+    alg.setChild(false);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize());
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", "testWS"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("FileName", destinationFile));
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument &);
+    TS_ASSERT(!alg.isExecuted());
+
+    TS_ASSERT_THROWS_NOTHING(
+        Mantid::API::AnalysisDataService::Instance().remove("testWS"));
+  }
+
+  void test_characterise_eight_pack_bug() {
+
+    // Bilby contains eight-packs, though other instrument features could still
+    // be problematic
+    Mantid::DataHandling::LoadEmptyInstrument alg;
+    alg.setChild(true);
+    alg.initialize();
+    alg.setProperty("Filename", "BILBY_Definition.xml");
+    alg.setPropertyValue("OutputWorkspace", "ws");
+    alg.execute();
+    Mantid::API::MatrixWorkspace_sptr ws = alg.getProperty("OutputWorkspace");
+
+    // problem actually in
+    // Mantid::NexusGeometry::NexusGeometrySave::saveInstrument /
+    // ComponentInfoBankHelpers::isSaveableBank but demonstrated here via save
+    // algorithm.
+
+    Mantid::DataHandling::SaveNexusGeometry saver;
+    saver.setChild(true);
+    saver.setRethrows(true);
+    saver.initialize();
+    saver.setProperty("Filename", "output.nxs");
+    saver.setProperty("InputWorkspace", ws);
+    TS_ASSERT_THROWS(saver.execute(), H5::Exception &);
+    TS_ASSERT(!saver.isExecuted());
+  }
+};
+
+#endif /* MANTID_DATAHANDLING_SAVENEXUSGEOMETRYTEST_H_ */
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/ComponentInfo.h b/Framework/Geometry/inc/MantidGeometry/Instrument/ComponentInfo.h
index 15fefd005c235c0769389b66b7d49d69437ca8a2..7c17d7096289c58e58fe604c65a03e7d617726d2 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument/ComponentInfo.h
+++ b/Framework/Geometry/inc/MantidGeometry/Instrument/ComponentInfo.h
@@ -116,6 +116,7 @@ public:
   Kernel::V3D samplePosition() const;
   bool hasSource() const;
   bool hasSample() const;
+  bool hasDetectors(const size_t componentIndex) const;
   size_t source() const;
   size_t sample() const;
   double l1() const;
diff --git a/Framework/Geometry/src/Instrument/ComponentInfo.cpp b/Framework/Geometry/src/Instrument/ComponentInfo.cpp
index 9fd94e440fca8323f1ccae35490c61fa9ec9f679..b33d2a9b449d29ebc9400d1d61bed12f4134eb03 100644
--- a/Framework/Geometry/src/Instrument/ComponentInfo.cpp
+++ b/Framework/Geometry/src/Instrument/ComponentInfo.cpp
@@ -223,6 +223,13 @@ bool ComponentInfo::hasSource() const { return m_componentInfo->hasSource(); }
 
 bool ComponentInfo::hasSample() const { return m_componentInfo->hasSample(); }
 
+bool ComponentInfo::hasDetectors(const size_t componentIndex) const {
+  if (isDetector(componentIndex))
+    return false;
+  const auto range = m_componentInfo->detectorRangeInSubtree(componentIndex);
+  return range.begin() < range.end();
+}
+
 size_t ComponentInfo::source() const { return m_componentInfo->source(); }
 
 size_t ComponentInfo::sample() const { return m_componentInfo->sample(); }
diff --git a/Framework/Geometry/src/Instrument/ComponentInfoBankHelpers.cpp b/Framework/Geometry/src/Instrument/ComponentInfoBankHelpers.cpp
index 77028710fd2b75c06844d13b04435ccd97fca114..32f08be6f6db2c4269cf4811e8495e191ad6b568 100644
--- a/Framework/Geometry/src/Instrument/ComponentInfoBankHelpers.cpp
+++ b/Framework/Geometry/src/Instrument/ComponentInfoBankHelpers.cpp
@@ -54,6 +54,8 @@ bool isSaveableBank(const ComponentInfo &compInfo, const size_t idx) {
   // needs to ignore if index is the source
   if (compInfo.source() == idx)
     return false;
+  if (!compInfo.hasDetectors(idx))
+    return false;
   // a bank must have a parent, skip this block if the component does not.
   if (compInfo.hasParent(idx)) {
     size_t parent = compInfo.parent(idx);
diff --git a/Framework/Geometry/test/ComponentInfoTest.h b/Framework/Geometry/test/ComponentInfoTest.h
index 075706fffad0ac4d54c5aa96a926bd43c35d6680..3f0f5d89a1e020b437fa03099beb64b083bd414b 100644
--- a/Framework/Geometry/test/ComponentInfoTest.h
+++ b/Framework/Geometry/test/ComponentInfoTest.h
@@ -704,6 +704,19 @@ public:
     TS_ASSERT_EQUALS(panel.topLeft, 3);
     TS_ASSERT_EQUALS(panel.topRight, 15);
   }
+
+  void test_has_detectors() {
+    auto instrument = ComponentCreationHelper::createTestInstrumentRectangular(
+        1 /*1 bank*/, 4 /*4 by 4 pixels*/);
+    auto wrappers = InstrumentVisitor::makeWrappers(*instrument);
+    const auto &componentInfo = std::get<0>(wrappers);
+
+    TS_ASSERT(componentInfo->hasDetectors(componentInfo->root()));
+    TS_ASSERT(!componentInfo->hasDetectors(0));
+    TS_ASSERT(!componentInfo->hasDetectors(componentInfo->sample()));
+    TS_ASSERT(!componentInfo->hasDetectors(componentInfo->source()));
+    TS_ASSERT(componentInfo->hasDetectors(componentInfo->indexOfAny("bank1")));
+  }
 };
 
 #endif /* MANTID_GEOMETRY_COMPONENTINFOTEST_H_ */
diff --git a/Framework/NexusGeometry/inc/MantidNexusGeometry/NexusGeometrySave.h b/Framework/NexusGeometry/inc/MantidNexusGeometry/NexusGeometrySave.h
index 90b1a6ffaef306bcbfcaeff82023d7d37745b8e7..cc0593b02d7498c274d059a4baebbec4dba30244 100644
--- a/Framework/NexusGeometry/inc/MantidNexusGeometry/NexusGeometrySave.h
+++ b/Framework/NexusGeometry/inc/MantidNexusGeometry/NexusGeometrySave.h
@@ -39,6 +39,12 @@ class DetectorInfo;
 namespace NexusGeometry {
 namespace NexusGeometrySave {
 
+MANTID_NEXUSGEOMETRY_DLL void
+saveInstrument(const Geometry::ComponentInfo &compInfo,
+               const Geometry::DetectorInfo &detInfo,
+               const std::string &fullPath, const std::string &rootPath,
+               Kernel::ProgressBase *reporter = nullptr);
+
 MANTID_NEXUSGEOMETRY_DLL void saveInstrument(
     const std::pair<std::unique_ptr<Geometry::ComponentInfo>,
                     std::unique_ptr<Geometry::DetectorInfo>> &instrPair,
diff --git a/Framework/NexusGeometry/src/NexusGeometrySave.cpp b/Framework/NexusGeometry/src/NexusGeometrySave.cpp
index 2273cd92a1f167868c32ef52e3ed3c2c07753914..1e511ee20dc32eb23b51aebae8ea960d25801fd3 100644
--- a/Framework/NexusGeometry/src/NexusGeometrySave.cpp
+++ b/Framework/NexusGeometry/src/NexusGeometrySave.cpp
@@ -709,17 +709,15 @@ void saveNXDetector(const H5::Group &parentGroup,
  * Produces a Nexus format file containing the Instrument geometry and metadata.
  *
  * @param compInfo : componentInfo object.
+ * @param detInfo : detectorInfo object.
  * @param fullPath : save destination as full path.
+ * @param rootPath : name of root entry
  * @param reporter : (optional) report to progressBase.
  */
-void saveInstrument(
-    const std::pair<std::unique_ptr<Geometry::ComponentInfo>,
-                    std::unique_ptr<Geometry::DetectorInfo>> &instrPair,
-    const std::string &fullPath, const std::string &rootPath,
-    Kernel::ProgressBase *reporter) {
-
-  const Geometry::ComponentInfo &compInfo = (*instrPair.first);
-  const Geometry::DetectorInfo &detInfo = (*instrPair.second);
+void saveInstrument(const Geometry::ComponentInfo &compInfo,
+                    const Geometry::DetectorInfo &detInfo,
+                    const std::string &fullPath, const std::string &rootPath,
+                    Kernel::ProgressBase *reporter) {
 
   // Exception handling.
   boost::filesystem::path tmp(fullPath);
@@ -808,6 +806,29 @@ void saveInstrument(
   file.close(); // close file
 
 } // saveInstrument
+
+/*
+ * Function: saveInstrument (overload)
+ * calls the save methods to write components to file after exception checking.
+ * Produces a Nexus format file containing the Instrument geometry and metadata.
+ *
+ * @param instrPair : instrument 2.0  object.
+ * @param fullPath : save destination as full path.
+ * @param rootPath : name of root entry
+ * @param reporter : (optional) report to progressBase.
+ */
+void saveInstrument(
+    const std::pair<std::unique_ptr<Geometry::ComponentInfo>,
+                    std::unique_ptr<Geometry::DetectorInfo>> &instrPair,
+    const std::string &fullPath, const std::string &rootPath,
+    Kernel::ProgressBase *reporter) {
+
+  const Geometry::ComponentInfo &compInfo = (*instrPair.first);
+  const Geometry::DetectorInfo &detInfo = (*instrPair.second);
+
+  return saveInstrument(compInfo, detInfo, fullPath, rootPath, reporter);
+} // saveInstrument
+
 } // namespace NexusGeometrySave
 } // namespace NexusGeometry
 } // namespace Mantid
diff --git a/Framework/NexusGeometry/test/NexusGeometrySaveTest.h b/Framework/NexusGeometry/test/NexusGeometrySaveTest.h
index 39ebed2a11cb7f9eca84c7c52a7f7fa2fcd156c3..d0722e652fdd11290a319d9f2b486c8c6ae39963 100644
--- a/Framework/NexusGeometry/test/NexusGeometrySaveTest.h
+++ b/Framework/NexusGeometry/test/NexusGeometrySaveTest.h
@@ -7,7 +7,6 @@
 #ifndef MANTID_NEXUSGEOMETRY_NEXUSGEOMETRYSAVETEST_H_
 #define MANTID_NEXUSGEOMETRY_NEXUSGEOMETRYSAVETEST_H_
 
-#include "FileResource.h"
 #include "MantidGeometry/Instrument/ComponentInfo.h"
 #include "MantidGeometry/Instrument/ComponentInfoBankHelpers.h"
 #include "MantidGeometry/Instrument/DetectorInfo.h"
@@ -18,7 +17,8 @@
 #include "MantidNexusGeometry/NexusGeometryDefinitions.h"
 #include "MantidNexusGeometry/NexusGeometrySave.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
-#include "NexusFileReader.h"
+#include "MantidTestHelpers/FileResource.h"
+#include "MantidTestHelpers/NexusFileReader.h"
 
 #include <cxxtest/TestSuite.h>
 #include <gmock/gmock.h>
@@ -340,7 +340,8 @@ used.
         V3D(0, 0, 10) /*bank position*/);
     auto instr = Mantid::Geometry::InstrumentVisitor::makeWrappers(*instrument);
 
-    auto const &compInfo = (*instr.first);
+    // instrument cache
+    auto &compInfo = (*instr.first);
 
     NexusGeometrySave::saveInstrument(instr, destinationFile,
                                       DEFAULT_ROOT_PATH);
@@ -994,8 +995,8 @@ Instrument cache.
         non-zero translation in source. Expected behaviour is: (dataset)
        'depends_on' has value "/absoulute/path/to/orientation", (dataset)
        'orientation' has dAttribute (AKA attribute of dataset) 'depends_on' with
-       value "/absoulute/path/to/location", and (dataset) 'location' has
-       dAttribute 'depends_on' with value "."
+        value "/absoulute/path/to/location", and (dataset) 'location' has
+        dAttribute 'depends_on' with value "."
          */
 
     // Geometry for test instrument
@@ -1109,7 +1110,7 @@ Instrument cache.
 
     // assert the group NXtransformations doesnt exist in file
     TS_ASSERT_THROWS(tester.openfullH5Path(transformationsPath),
-                     H5::GroupIException &)
+                     H5::GroupIException &);
   }
 };
 
diff --git a/Framework/NexusGeometry/test/FileResource.h b/Framework/TestHelpers/inc/MantidTestHelpers/FileResource.h
similarity index 89%
rename from Framework/NexusGeometry/test/FileResource.h
rename to Framework/TestHelpers/inc/MantidTestHelpers/FileResource.h
index 51594cf291a9516d336bd13ef98698c78d44a77f..c5b0bb68f8007623127c379376cc04fc9ebff95e 100644
--- a/Framework/NexusGeometry/test/FileResource.h
+++ b/Framework/TestHelpers/inc/MantidTestHelpers/FileResource.h
@@ -5,20 +5,20 @@
 //     & Institut Laue - Langevin
 // SPDX - License - Identifier: GPL - 3.0 +
 
+/*
+ * RAII: Gives a clean file destination and removes the file when
+ * handle is out of scope. Must be stack allocated.
+ *
+ * @author Takudzwa Makoni, RAL (UKRI), ISIS
+ * @date 06/08/2019
+ */
+
 #ifndef MANTID_NEXUSGEOMETRY_FILERESOURCE_H_
 #define MANTID_NEXUSGEOMETRY_FILERESOURCE_H_
 
 #include <boost/filesystem.hpp>
 #include <string>
 
-/*
- RAII: Gives a clean file destination and removes the file when
- handle is out of scope. Must be stack allocated.
-
- TODO: DOCUMENTATION
- *@author Takudzwa Makoni, RAL (UKRI), ISIS
- *@date 06/08/2019
-*/
 class ScopedFileHandle {
 
 public:
diff --git a/Framework/NexusGeometry/test/NexusFileReader.h b/Framework/TestHelpers/inc/MantidTestHelpers/NexusFileReader.h
similarity index 79%
rename from Framework/NexusGeometry/test/NexusFileReader.h
rename to Framework/TestHelpers/inc/MantidTestHelpers/NexusFileReader.h
index 5f3300aead3ab95c4be58f7d5e99984099c25b8f..08e198e05f197b23ffc16a0616ad8239581bb7f6 100644
--- a/Framework/NexusGeometry/test/NexusFileReader.h
+++ b/Framework/TestHelpers/inc/MantidTestHelpers/NexusFileReader.h
@@ -10,17 +10,19 @@
 
 #include "MantidNexusGeometry/NexusGeometryDefinitions.h"
 
+#include <Eigen/Dense>
 #include <H5Cpp.h>
 #include <boost/filesystem.hpp>
 #include <string>
 #include <vector>
 
 /*
- TODO: DOCUMENTATION
-
- *@author Takudzwa Makoni, RAL (UKRI), ISIS
- *@date 06/08/2019
-*/
+ * NexusFileReader: Test utility for unit testing in
+ * NexusGeometrySave::saveInstrument.
+ *
+ * @author Takudzwa Makoni, RAL (UKRI), ISIS
+ * @date 06/08/2019
+ */
 
 namespace Mantid {
 namespace NexusGeometry {
@@ -34,6 +36,40 @@ std::string toNXPathString(FullNXPath &path) {
   return pathString;
 }
 
+// ported from NexusGeometryParser, for validating storage type of dataset
+// before reading its contents into a container
+template <typename ExpectedT>
+void validateStorageType(const H5::DataSet &data) {
+
+  const auto typeClass = data.getTypeClass();
+  const size_t sizeOfType = data.getDataType().getSize();
+  // Early check to prevent reinterpretation of underlying data.
+  if (std::is_floating_point<ExpectedT>::value) {
+    if (H5T_FLOAT != typeClass) {
+      throw std::runtime_error("Storage type mismatch. Expecting to extract a "
+                               "floating point number");
+    }
+    if (sizeOfType != sizeof(ExpectedT)) {
+      throw std::runtime_error(
+          "Storage type mismatch for floats. This operation "
+          "is dangerous. Nexus stored has byte size:" +
+          std::to_string(sizeOfType));
+    }
+  } else if (std::is_integral<ExpectedT>::value) {
+    if (H5T_INTEGER != typeClass) {
+      throw std::runtime_error(
+          "Storage type mismatch. Expecting to extract a integer");
+    }
+    if (sizeOfType > sizeof(ExpectedT)) {
+      // endianness not checked
+      throw std::runtime_error(
+          "Storage type mismatch for integer. Result "
+          "would result in truncation. Nexus stored has byte size:" +
+          std::to_string(sizeOfType));
+    }
+  }
+}
+
 // test utility used for validation of the structure of a nexus file as needed
 // for unit tests in Nexus Geometry.
 class NexusFileReader {
@@ -49,6 +85,25 @@ public:
     }
   }
 
+  // read a multidimensional dataset and returns vector containing the data
+  template <typename T>
+  std::vector<T> readDataSetMultidimensional(FullNXPath &pathToGroup,
+                                             std::string dataSetName) {
+
+    std::vector<T> dataInFile;
+
+    // open dataset and read.
+    H5::Group parentGroup = openfullH5Path(pathToGroup);
+    H5::DataSet dataset = parentGroup.openDataSet(dataSetName);
+
+    validateStorageType<T>(dataset);
+    auto space = dataset.getSpace();
+
+    dataInFile.resize(space.getSelectNpoints());
+    dataset.read(dataInFile.data(), dataset.getDataType(), space);
+    return dataInFile;
+  }
+
   /* safely open a HDF5 group path with additional helpful
    debug information to output where open fails) */
   H5::Group openfullH5Path(const FullNXPath &pathList) const {
@@ -75,7 +130,7 @@ public:
     // file structure only. (dont take extra step to look for parent group)
     if (parentNX_CLASS_TYPE == NX_ENTRY) {
 
-      for (hsize_t i = 0; i < rootGroup.getNumObjs(); ++i) {
+      for (size_t i = 0; i < rootGroup.getNumObjs(); ++i) {
         if (rootGroup.getObjTypeByIdx(i) == GROUP_TYPE) {
           std::string childPath = rootGroup.getObjnameByIdx(i);
           // Open the sub group
@@ -92,7 +147,7 @@ public:
     }
 
     // Iterate over children of root group, and determine if a group
-    for (hsize_t i = 0; i < rootGroup.getNumObjs(); ++i) {
+    for (size_t i = 0; i < rootGroup.getNumObjs(); ++i) {
       if (rootGroup.getObjTypeByIdx(i) == GROUP_TYPE) {
         std::string childPath = rootGroup.getObjnameByIdx(i);
         // Open the sub group
@@ -103,7 +158,7 @@ public:
         std::string parentAttrVal;
         parentAttribute.read(parentAttribute.getDataType(), parentAttrVal);
         if (parentAttrVal == parentNX_CLASS_TYPE) {
-          for (hsize_t i = 0; i < childGroup.getNumObjs(); ++i) {
+          for (size_t i = 0; i < childGroup.getNumObjs(); ++i) {
             if (childGroup.getObjTypeByIdx(i) == GROUP_TYPE) {
               std::string grandchildPath = childGroup.getObjnameByIdx(i);
               // Open the sub group
@@ -130,10 +185,10 @@ public:
                                const FullNXPath &pathToGroup) {
     double value;
     int rank = 1;
-    hsize_t dims[(hsize_t)1];
-    dims[0] = (hsize_t)1;
+    hsize_t dims[static_cast<hsize_t>(1)];
+    dims[0] = static_cast<hsize_t>(1);
 
-    H5::DataSpace space = H5Screate_simple(rank, dims, NULL);
+    H5::DataSpace space = H5Screate_simple(rank, dims, nullptr);
 
     // open dataset and read.
     H5::Group parentGroup = openfullH5Path(pathToGroup);
@@ -171,7 +226,7 @@ public:
 
     H5::Group parentGroup = m_file.openGroup(pathToGroup);
     auto numOfChildren = parentGroup.getNumObjs();
-    for (hsize_t i = 0; i < numOfChildren; i++) {
+    for (size_t i = 0; i < numOfChildren; i++) {
       if (parentGroup.getObjTypeByIdx(i) == DATASET_TYPE) {
         std::string dSetName = parentGroup.getObjnameByIdx(i);
         H5::DataSet dSet = parentGroup.openDataSet(dSetName);
@@ -194,7 +249,7 @@ public:
 
     H5::Group parentGroup = m_file.openGroup(pathToGroup);
     auto numOfChildren = parentGroup.getNumObjs();
-    for (hsize_t i = 0; i < numOfChildren; i++) {
+    for (size_t i = 0; i < numOfChildren; i++) {
       if (parentGroup.getObjTypeByIdx(i) == DATASET_TYPE) {
         std::string dSetName = parentGroup.getObjnameByIdx(i);
         H5::DataSet dSet = parentGroup.openDataSet(dSetName);
@@ -215,7 +270,7 @@ public:
     H5::Group parentGroup = openfullH5Path(pathToGroup);
 
     auto numOfChildren = parentGroup.getNumObjs();
-    for (hsize_t i = 0; i < numOfChildren; i++) {
+    for (size_t i = 0; i < numOfChildren; i++) {
       if (parentGroup.getObjTypeByIdx(i) == DATASET_TYPE) {
         std::string dataSetName = parentGroup.getObjnameByIdx(i);
         if (dsetName == dataSetName) {
diff --git a/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h b/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h
index b321c592bbaafcdc4b0ac8977f474ac42a8e8923..071c5d03cdef3d37af897cc4072c810dcc8843a3 100644
--- a/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h
+++ b/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h
@@ -273,6 +273,12 @@ Mantid::DataObjects::EventWorkspace_sptr
 createEventWorkspaceWithFullInstrument(int numBanks, int numPixels,
                                        bool clearEvents = true);
 
+/** Create an Eventworkspace with instrument 2.0 that contains
+ * RectangularDetector's */
+Mantid::DataObjects::EventWorkspace_sptr
+createEventWorkspaceWithFullInstrument2(int numBanks, int numPixels,
+                                        bool clearEvents = true);
+
 /**
  * Creates an event workspace with instrument which consists of cylindrical
  *detectors.
diff --git a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp
index 8a43fd33b205a2f6be22b42cf6645467aa72b692..d204f31e7fb5984254b42adb0d7ffefa6f602255 100644
--- a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp
+++ b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp
@@ -497,6 +497,47 @@ createEventWorkspaceWithFullInstrument(int numBanks, int numPixels,
   return ws;
 }
 
+/** Create an Eventworkspace with  instrument 2.0 that contains
+ *RectangularDetector's.
+ * X axis = 100 histogrammed bins from 0.0 in steps of 1.0.
+ * 200 events per pixel.
+ *
+ * @param numBanks :: number of rectangular banks
+ * @param numPixels :: each bank will be numPixels*numPixels
+ * @param clearEvents :: if true, erase the events from list
+ * @return The EventWorkspace
+ */
+Mantid::DataObjects::EventWorkspace_sptr
+createEventWorkspaceWithFullInstrument2(int numBanks, int numPixels,
+                                        bool clearEvents) {
+  Instrument_sptr inst =
+      ComponentCreationHelper::createTestInstrumentRectangular2(numBanks,
+                                                                numPixels);
+  EventWorkspace_sptr ws =
+      createEventWorkspace2(numBanks * numPixels * numPixels, 100);
+  ws->setInstrument(inst);
+
+  // Set the X axes
+  const auto &xVals = ws->x(0);
+  const size_t xSize = xVals.size();
+  auto ax0 = std::make_unique<NumericAxis>(xSize);
+  ax0->setUnit("dSpacing");
+  for (size_t i = 0; i < xSize; i++) {
+    ax0->setValue(i, xVals[i]);
+  }
+  ws->replaceAxis(0, std::move(ax0));
+
+  // re-assign detector IDs to the rectangular detector
+  const auto detIds = inst->getDetectorIDs();
+  for (int wi = 0; wi < static_cast<int>(ws->getNumberHistograms()); ++wi) {
+    ws->getSpectrum(wi).clearDetectorIDs();
+    if (clearEvents)
+      ws->getSpectrum(wi).clear(true);
+    ws->getSpectrum(wi).setDetectorID(detIds[wi]);
+  }
+  return ws;
+}
+
 Mantid::DataObjects::EventWorkspace_sptr
 createEventWorkspaceWithNonUniformInstrument(int numBanks, bool clearEvents) {
   // Number of detectors in a bank as created by createTestInstrumentCylindrical
diff --git a/docs/source/algorithms/SaveNexusGeometry-v1.rst b/docs/source/algorithms/SaveNexusGeometry-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..5f30cbb4e4a9798d7508aa413a4185d5d48fa878
--- /dev/null
+++ b/docs/source/algorithms/SaveNexusGeometry-v1.rst
@@ -0,0 +1,104 @@
+
+.. algorithm::
+
+.. summary::
+
+.. relatedalgorithms::
+
+.. properties::
+
+Description
+-----------
+
+Saves the Instrument geometry from the workspace to a Nexus file. Saves detector positions and rotations.
+Current version (1.0) does NOT save instrument shapes of instrument components. file is compliant to Nexus standards.
+For more information on the Nexus format, see https://www.nexusformat.org/
+
+the Instrument will be extracted from the specified workspace, and written to the specified location.
+
+The (optional) H5 root group name is the parent group in which the Instrument and sample data are stored.
+If no name is given, the root group will have a default nme of 'entry'
+
+
+Usage
+-----
+
+**Example - basic example using SaveNexusGeometry, with default H5 root group**
+
+.. testcode:: SaveNexusGeometryExampleDefault
+
+	import os
+
+	ws = CreateSampleWorkspace()
+	compInfo = ws.componentInfo()
+	detInfo = ws.detectorInfo()
+	file_name  = "example_save_Nexus_geometry_1.nxs"
+	path = os.path.join(os.path.expanduser("~"), file_name)
+
+	SaveNexusGeometry(ws, path)
+	print(os.path.isfile(path))
+
+
+
+Output:
+
+.. testoutput:: SaveNexusGeometryExampleDefault
+	
+	True
+
+.. testcleanup:: SaveNexusGeometryExampleDefault
+
+    import os
+    def removeFiles(files):
+      for ws in files:
+        try:
+          path = os.path.join(os.path.expanduser("~"), ws)
+          os.remove(path)
+        except:
+          pass
+
+    removeFiles([file_name])
+
+
+**Example - basic example using SaveNexusGeometry, with specific H5 root group**
+
+.. testcode:: SaveNexusGeometryExampleOption
+
+	import os
+
+	ws = CreateSampleWorkspace()
+	compInfo = ws.componentInfo()
+	detInfo = ws.detectorInfo()
+	file_name  = "example_save_Nexus_geometry_2.hdf5"
+	path = os.path.join(os.path.expanduser("~"), file_name)
+
+	SaveNexusGeometry(ws, path)
+	print(os.path.isfile(path))
+
+
+
+Output:
+
+.. testoutput:: SaveNexusGeometryExampleOption
+	
+	True
+
+.. testcleanup:: SaveNexusGeometryExampleOption
+
+    import os
+    def removeFiles(files):
+      for ws in files:
+        try:
+          path = os.path.join(os.path.expanduser("~"), ws)
+          os.remove(path)
+        except:
+          pass
+
+    removeFiles([file_name])
+
+
+
+.. categories::
+
+.. sourcelink::
+
diff --git a/instrument/unit_testing/nicos_00000489_agg_with_monitor.nxs.md5 b/instrument/unit_testing/nicos_00000489_agg_with_monitor.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..b73b11fc526a2f0d83ea93fc5c4fe5e6f0b0fa2a
--- /dev/null
+++ b/instrument/unit_testing/nicos_00000489_agg_with_monitor.nxs.md5
@@ -0,0 +1 @@
+5ec36a1dbff0d68ca200b072232953cd