diff --git a/Framework/DataHandling/CMakeLists.txt b/Framework/DataHandling/CMakeLists.txt
index efc18bf54c669823107ad883bf17a3fec42cdc58..b187d2df60b2b3c23f661e523743126df10ab4e4 100644
--- a/Framework/DataHandling/CMakeLists.txt
+++ b/Framework/DataHandling/CMakeLists.txt
@@ -92,6 +92,7 @@ set(SRC_FILES
     src/LoadNexusProcessed.cpp
     src/LoadNexusProcessed2.cpp
     src/LoadOff.cpp
+    src/LoadNGEM.cpp
     src/LoadPDFgetNFile.cpp
     src/LoadPLN.cpp
     src/LoadPSIMuonBin.cpp
@@ -294,6 +295,7 @@ set(INC_FILES
     inc/MantidDataHandling/LoadNexusProcessed.h
     inc/MantidDataHandling/LoadNexusProcessed2.h
     inc/MantidDataHandling/LoadOff.h
+    inc/MantidDataHandling/LoadNGEM.h
     inc/MantidDataHandling/LoadPDFgetNFile.h
     inc/MantidDataHandling/LoadPLN.h
     inc/MantidDataHandling/LoadPSIMuonBin.h
@@ -484,6 +486,7 @@ set(TEST_FILES
     LoadNexusProcessed2Test.h
     LoadNexusProcessedTest.h
     LoadNexusTest.h
+    LoadNGEMTest.h
     LoadPDFgetNFileTest.h
     LoadPLNTest.h
     LoadPSIMuonBinTest.h
@@ -628,6 +631,8 @@ target_link_libraries(DataHandling
                       ${TCMALLOC_LIBRARIES_LINKTIME}
                       ${MANTIDLIBS}
                       Nexus
+                      HistogramData
+                      DataObjects
                       ${NEXUS_LIBRARIES}
                       ${HDF5_LIBRARIES}
                       ${HDF5_HL_LIBRARIES}
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadNGEM.h b/Framework/DataHandling/inc/MantidDataHandling/LoadNGEM.h
new file mode 100644
index 0000000000000000000000000000000000000000..33d17354812f619ce047a0f60ebe2644a6cb0ff5
--- /dev/null
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadNGEM.h
@@ -0,0 +1,142 @@
+// 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 +
+
+#ifndef MANTID_DATAHANDLING_LOADNGEM_H_
+#define MANTID_DATAHANDLING_LOADNGEM_H_
+
+#include "MantidAPI/IFileLoader.h"
+#include "MantidDataObjects/EventWorkspace.h"
+
+namespace Mantid {
+namespace DataHandling {
+
+static constexpr uint64_t CONTIN_ID_VALUE = 0x4F;
+
+/// Generic event to separate bits.
+struct GenericEvent {
+  uint64_t t0id : 24;      // T0 ID
+  uint64_t reserved2 : 32; // Reserved for non-generics
+  uint64_t contin : 8;     // 0x4F Continuation Code
+  uint64_t reserved1 : 56; // Reserved for non-generics
+  uint64_t id : 8;         // 0x4E Event ID
+};
+
+/// Indicate time 0, the start of a new frame.
+struct T0FrameEvent {
+  uint64_t t0id : 24;       // T0 ID
+  uint64_t eventCount : 32; // Event Count
+  uint64_t contin : 8;      // 0x4F Continuation Code
+  uint64_t totalLoss : 24;  // Total loss count
+  uint64_t eventLoss : 20;  // Event loss count
+  uint64_t frameLoss : 12;  // Frame loss count
+  uint64_t id : 8;          // 0x4E Event ID
+  static constexpr int T0_IDENTIFIER = 0x4E;
+  bool check() const {
+    return id == T0_IDENTIFIER && contin == CONTIN_ID_VALUE;
+  }
+};
+
+/// A detected neutron.
+struct CoincidenceEvent {
+  uint64_t t0id : 24;         // T0 ID
+  uint64_t clusterTimeY : 10; // Integrated time of the cluster on the Y side
+                              // (5ns pixel)
+  uint64_t timeDiffY : 6; // Time lag from first to last detection on Y (5ns)
+  uint64_t clusterTimeX : 10; // Integrated time of the cluster on the X side
+                              // (5ns pixel)
+  uint64_t timeDiffX : 6; // Time lag from first to last detection on X (5ns)
+  uint64_t contin : 8;    // 0x4F Continuation Code
+  uint64_t lastY : 7;     // Y position of pixel detected last
+  uint64_t firstY : 7;    // Y position of pixel detected first
+  uint64_t lastX : 7;     // X position of pixel detected last
+  uint64_t firstX : 7;    // X position of pixel detected first
+  uint64_t timeOfFlight : 28; // Difference between T0 and detection (1ns)
+  uint64_t id : 8;            // 0x47 Event ID.
+
+  uint64_t avgX() const { return (firstX + lastX) / 2; }
+  uint64_t avgY() const { return (firstY + lastY) / 2; }
+  static constexpr int COINCIDENCE_IDENTIFIER = 0x47;
+  bool check() {
+    return id == COINCIDENCE_IDENTIFIER && contin == CONTIN_ID_VALUE;
+  }
+  uint64_t getPixel() const {
+    return avgX() + (avgY() << 7); // Increase Y significance by 7 bits to
+                                   // account for 128x128 grid.
+  }
+};
+
+/// Holds the 128 bit words from the detector.
+struct DetectorWord {
+  uint64_t words[2]; // Array holding the word from the detector split in two.
+};
+
+/// Is able to hold all versions of the data words in the same memory location.
+union EventUnion {
+  GenericEvent generic;
+  T0FrameEvent tZero;
+  CoincidenceEvent coincidence;
+  DetectorWord splitWord;
+};
+
+class DLLExport LoadNGEM : public API::IFileLoader<Kernel::FileDescriptor> {
+public:
+  /// Algorithm's name for identification.
+  const std::string name() const override { return "LoadNGEM"; }
+  /// The purpose of the algorithm.
+  const std::string summary() const override {
+    return "Load a file or range of files created by the nGEM detector into a "
+           "workspace.";
+  };
+  /// Algorithm's Version for identification.
+  int version() const override { return 1; }
+  /// Algorithm's category for identification.
+  const std::string category() const override { return "DataHandling\\NGEM"; };
+  /// Should the loader load multiple files into one workspace.
+  bool loadMutipleAsOne() override { return true; }
+
+  /// The confidence that an algorithm is able to load the file.
+  int confidence(Kernel::FileDescriptor &descriptor) const override;
+
+private:
+  /// Initialise the algorithm.
+  void init() override;
+  /// Execute the algorithm.
+  void exec() override;
+  /// Load a file into the event lists.
+  void loadSingleFile(const std::vector<std::string> &filePath,
+                      int &eventCountInFrame, int &maxToF, int &minToF,
+                      int &rawFrames, int &goodFrames, const int &minEventsReq,
+                      const int &maxEventsReq, MantidVec &frameEventCounts,
+                      std::vector<DataObjects::EventList> &events,
+                      std::vector<DataObjects::EventList> &eventsInFrame,
+                      const size_t &totalFilePaths, int &fileCount);
+  /// Add some text information to the sample logs.
+  void addToSampleLog(const std::string &logName, const std::string &logText,
+                      DataObjects::EventWorkspace_sptr &ws);
+  /// Add some number information to the sample logs.
+  void addToSampleLog(const std::string &logName, const int &logNumber,
+                      DataObjects::EventWorkspace_sptr &ws);
+  /// Check that a file to be loaded is in 128 bit words.
+  size_t verifyFileSize(std::ifstream &file);
+  /// Reports progress and checks cancel flag.
+  bool reportProgressAndCheckCancel(size_t &numProcessedEvents,
+                                    int &eventCountInFrame,
+                                    const size_t &totalNumEvents,
+                                    const size_t &totalFilePaths,
+                                    const int &fileCount);
+  /// Create a workspace to store the number of counts per frame.
+  void createCountWorkspace(const std::vector<double> &frameEventCounts);
+  /// Load the instrument and attach to the data workspace.
+  void loadInstrument(DataObjects::EventWorkspace_sptr &dataWorkspace);
+  /// Validate the imputs into the algorithm, overrides.
+  std::map<std::string, std::string> validateInputs() override;
+};
+
+} // namespace DataHandling
+} // namespace Mantid
+
+#endif // MANTID_DATAHANDLING_LOADNGEM_H_
diff --git a/Framework/DataHandling/src/Load.cpp b/Framework/DataHandling/src/Load.cpp
index af7c416efdcd36b1c3b9e7c6695bf62e0285b6a8..6441366335df378a1597bd9146c7894f937963da 100644
--- a/Framework/DataHandling/src/Load.cpp
+++ b/Framework/DataHandling/src/Load.cpp
@@ -291,6 +291,7 @@ void Load::init() {
   exts.emplace_back(".sqw");
   exts.emplace_back(".fits");
   exts.emplace_back(".bin");
+  exts.emplace_back(".edb");
 
   declareProperty(
       std::make_unique<MultipleFileProperty>("Filename", exts),
diff --git a/Framework/DataHandling/src/LoadNGEM.cpp b/Framework/DataHandling/src/LoadNGEM.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb44c0de2fdb549adab2ea1fd92213e104313a9b
--- /dev/null
+++ b/Framework/DataHandling/src/LoadNGEM.cpp
@@ -0,0 +1,464 @@
+// 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 +
+
+#include "MantidDataHandling/LoadNGEM.h"
+#include "MantidAPI/Axis.h"
+#include "MantidAPI/MultipleFileProperty.h"
+#include "MantidAPI/RegisterFileLoader.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidKernel/BoundedValidator.h"
+#include "MantidKernel/MultiThreaded.h"
+#include "MantidKernel/OptionalBool.h"
+#include "MantidKernel/Unit.h"
+#include "MantidKernel/UnitFactory.h"
+
+#include <boost/algorithm/string.hpp>
+#include <fstream>
+
+namespace Mantid {
+namespace DataHandling {
+
+DECLARE_FILELOADER_ALGORITHM(LoadNGEM)
+
+// Constants and helper functions.
+namespace {
+constexpr int NUM_OF_SPECTRA = 16384;
+
+/**
+ * @brief Byte swap a 64 bit word as the nGEM detector outputs in big endian
+ * format. So must be swapped to have correct values on x86 and x64
+ * architectures.
+ *
+ * @param word The 64 bit word to swap.
+ * @return uint64_t The swapped word.
+ */
+uint64_t swapUint64(uint64_t word) {
+  word = ((word << 8) & 0xFF00FF00FF00FF00ULL) |
+         ((word >> 8) & 0x00FF00FF00FF00FFULL);
+  word = ((word << 16) & 0xFFFF0000FFFF0000ULL) |
+         ((word >> 16) & 0x0000FFFF0000FFFFULL);
+  return (word << 32) | (word >> 32);
+}
+
+/**
+ * @brief Correct a big endian event to be compatible with x64 and x86
+ * architecture.
+ *
+ * @param bigEndian The big endian formatted event.
+ * @param smallEndian The resulting small endian formatted event.
+ */
+void correctForBigEndian(EventUnion *&bigEndian, EventUnion &smallEndian) {
+  smallEndian.splitWord.words[0] = swapUint64(bigEndian->splitWord.words[1]);
+  smallEndian.splitWord.words[1] = swapUint64(bigEndian->splitWord.words[0]);
+}
+
+/**
+ * @brief Add a frame to the main set of events.
+ *
+ * @param rawFrames The number of T0 Events detected so far.
+ * @param goodFrames The number of good frames detected so far.
+ * @param eventCountInFrame The number of events in the current frame.
+ * @param minEventsReq The number of events required to be a good frame.
+ * @param maxEventsReq The max events allowed to be a good frame.
+ * @param frameEventCounts A vector of the number of events in each good frame.
+ * @param events The main set of events for the data so far.
+ * @param eventsInFrame The set of events for the current frame.
+ */
+void addFrameToOutputWorkspace(
+    int &rawFrames, int &goodFrames, const int &eventCountInFrame,
+    const int &minEventsReq, const int &maxEventsReq,
+    MantidVec &frameEventCounts, std::vector<DataObjects::EventList> &events,
+    std::vector<DataObjects::EventList> &eventsInFrame) {
+  ++rawFrames;
+  if (eventCountInFrame >= minEventsReq && eventCountInFrame <= maxEventsReq) {
+    // Add number of event counts to workspace.
+    frameEventCounts.emplace_back(eventCountInFrame);
+    ++goodFrames;
+
+    PARALLEL_FOR_NO_WSP_CHECK()
+    // Add events that match parameters to workspace
+    for (auto i = 0; i < NUM_OF_SPECTRA; ++i) {
+      if (eventsInFrame[i].getNumberEvents() > 0) {
+        events[i] += eventsInFrame[i];
+        eventsInFrame[i].clear();
+      }
+    }
+  }
+}
+
+/**
+ * @brief Creates an event workspace and fills it with the data.
+ *
+ * @param maxToF The largest ToF seen so far.
+ * @param binWidth The width of each bin.
+ * @param events The main events data.
+ * @param dataWorkspace The workspace to add the data to.
+ */
+void createEventWorkspace(const int &maxToF, const double &binWidth,
+                          std::vector<DataObjects::EventList> &events,
+                          DataObjects::EventWorkspace_sptr &dataWorkspace) {
+  std::vector<double> xAxis;
+  // Round up number of bins needed and reserve the space in the vector.
+  xAxis.reserve(int(std::ceil(maxToF / binWidth)));
+  for (auto i = 0; i < (maxToF / binWidth); i++) {
+    xAxis.push_back(i * binWidth);
+  }
+
+  dataWorkspace = DataObjects::create<DataObjects::EventWorkspace>(
+      NUM_OF_SPECTRA, HistogramData::Histogram(HistogramData::BinEdges(xAxis)));
+  PARALLEL_FOR_NO_WSP_CHECK()
+  for (auto i = 0u; i < events.size(); ++i) {
+    dataWorkspace->getSpectrum(i) = events[i];
+    dataWorkspace->getSpectrum(i).setSpectrumNo(i + 1);
+    dataWorkspace->getSpectrum(i).setDetectorID(i + 1);
+  }
+  dataWorkspace->setAllX(HistogramData::BinEdges{xAxis});
+  dataWorkspace->getAxis(0)->unit() =
+      Kernel::UnitFactory::Instance().create("TOF");
+  dataWorkspace->setYUnit("Counts");
+}
+} // namespace
+
+/**
+ * @brief The confidence that a file can be loaded.
+ *
+ * @param descriptor A description of the file.
+ * @return int The level of certainty that the file can be loaded with this
+ * loader.
+ */
+int LoadNGEM::confidence(Kernel::FileDescriptor &descriptor) const {
+  if (descriptor.extension() == ".edb") {
+    return 95;
+  } else {
+    return 0;
+  }
+}
+
+/**
+ * @brief Initialisation of the algorithm, setting up the properties.
+ */
+void LoadNGEM::init() {
+  // Filename property.
+  const std::vector<std::string> extentions{".edb"};
+  declareProperty(
+      std::make_unique<API::MultipleFileProperty>("Filename", extentions),
+      "The name of the nGEM file to load. Selecting multiple files will "
+      "combine them into one workspace.");
+  // Output workspace
+  declareProperty(std::make_unique<API::WorkspaceProperty<API::Workspace>>(
+                      "OutputWorkspace", "", Kernel::Direction::Output),
+                  "The output workspace");
+
+  auto mustBePositive = boost::make_shared<Kernel::BoundedValidator<int>>();
+  mustBePositive->setLower(0);
+
+  auto mustBePositiveDbl =
+      boost::make_shared<Kernel::BoundedValidator<double>>();
+  mustBePositiveDbl->setLower(0.0);
+
+  // Bin Width
+  declareProperty("BinWidth", 10.0, mustBePositiveDbl,
+                  "The width of the time bins in the output.");
+
+  declareProperty("MinEventsPerFrame", 0, mustBePositive,
+                  "The minimum number of events required in a frame before a "
+                  "it is considered 'good'.");
+  declareProperty("MaxEventsPerFrame", EMPTY_INT(), mustBePositive,
+                  "The maximum number of events allowed in a frame to be "
+                  "considered 'good'.");
+  declareProperty(
+      std::make_unique<Kernel::PropertyWithValue<bool>>(
+          "GenerateEventsPerFrame", false, Kernel::Direction::Input),
+      "Generate a workspace to show the number of events captured by each "
+      "frame. (optional, default False).");
+}
+
+/**
+ * @brief Execute the algorithm.
+ */
+void LoadNGEM::exec() {
+  progress(0);
+
+  std::vector<std::vector<std::string>> filePaths = getProperty("Filename");
+
+  const int minEventsReq(getProperty("MinEventsPerFrame"));
+  const int maxEventsReq(getProperty("MaxEventsPerFrame"));
+
+  int maxToF = -1;
+  int minToF = 2147483647;
+  const double binWidth(getProperty("BinWidth"));
+
+  int rawFrames = 0;
+  int goodFrames = 0;
+  std::vector<double> frameEventCounts;
+  int eventCountInFrame = 0;
+
+  std::vector<DataObjects::EventList> events, eventsInFrame;
+  events.resize(NUM_OF_SPECTRA);
+  eventsInFrame.resize(NUM_OF_SPECTRA);
+  progress(0.04);
+
+  size_t totalFilePaths(filePaths.size());
+  int counter(1);
+  for (const auto &filePath : filePaths) {
+    loadSingleFile(filePath, eventCountInFrame, maxToF, minToF, rawFrames,
+                   goodFrames, minEventsReq, maxEventsReq, frameEventCounts,
+                   events, eventsInFrame, totalFilePaths, counter);
+  }
+  // Add the final frame of events (as they are not followed by a T0 event)
+  addFrameToOutputWorkspace(rawFrames, goodFrames, eventCountInFrame,
+                            minEventsReq, maxEventsReq, frameEventCounts,
+                            events, eventsInFrame);
+  progress(0.90);
+
+  DataObjects::EventWorkspace_sptr dataWorkspace;
+  createEventWorkspace(maxToF, binWidth, events, dataWorkspace);
+
+  addToSampleLog("raw_frames", rawFrames, dataWorkspace);
+  addToSampleLog("good_frames", goodFrames, dataWorkspace);
+  addToSampleLog("max_ToF", maxToF, dataWorkspace);
+  addToSampleLog("min_ToF", minToF, dataWorkspace);
+
+  loadInstrument(dataWorkspace);
+
+  setProperty("OutputWorkspace", dataWorkspace);
+  if (this->getProperty("GenerateEventsPerFrame")) {
+    createCountWorkspace(frameEventCounts);
+  }
+  progress(1.00);
+}
+
+/**
+ * @brief Load a single file into the event lists.
+ *
+ * @param filePath The path to the file.
+ * @param eventCountInFrame The number of events in the current frame.
+ * @param maxToF The highest detected ToF
+ * @param minToF The lowest detected ToF
+ * @param rawFrames The number of T0 Events detected so far.
+ * @param goodFrames The number of good frames detected so far.
+ * @param minEventsReq The number of events required to be a good frame.
+ * @param maxEventsReq The max events allowed to be a good frame.
+ * @param frameEventCounts A vector of the number of events in each good frame.
+ * @param events The main set of events for the data so far.
+ * @param eventsInFrame The set of events for the current frame.
+ * @param totalFilePaths The total number of file paths.
+ * @param fileCount The number of file paths processed.
+ */
+void LoadNGEM::loadSingleFile(
+    const std::vector<std::string> &filePath, int &eventCountInFrame,
+    int &maxToF, int &minToF, int &rawFrames, int &goodFrames,
+    const int &minEventsReq, const int &maxEventsReq,
+    MantidVec &frameEventCounts, std::vector<DataObjects::EventList> &events,
+    std::vector<DataObjects::EventList> &eventsInFrame,
+    const size_t &totalFilePaths, int &fileCount) {
+  // Create file reader
+  if (filePath.size() > 1) {
+    throw std::runtime_error("Invalid filename parameter.");
+  }
+  std::ifstream file(filePath[0].c_str(), std::ifstream::binary);
+  if (!file.is_open()) {
+    throw std::runtime_error("File could not be found.");
+  }
+  std::array<char, 16> buffer;
+
+  const size_t totalNumEvents = verifyFileSize(file) / 16;
+  size_t numProcessedEvents = 0;
+
+  while (!file.eof()) {
+    // Load an event into the variable.
+    file.read(buffer.data(), 16);
+    auto eventBigEndian = reinterpret_cast<EventUnion *>(buffer.data());
+
+    // Correct for the big endian format.
+    EventUnion event;
+    correctForBigEndian(eventBigEndian, event);
+
+    if (event.coincidence.check()) { // Check for coincidence event.
+      ++eventCountInFrame;
+      uint64_t pixel = event.coincidence.getPixel();
+      int tof =
+          event.coincidence.timeOfFlight / 1000; // Convert to microseconds (us)
+
+      if (tof > maxToF) {
+        maxToF = tof;
+      } else if (tof < minToF) {
+        minToF = tof;
+      }
+      eventsInFrame[pixel].addEventQuickly(Types::Event::TofEvent(tof));
+
+    } else if (event.tZero.check()) { // Check for T0 event.
+      addFrameToOutputWorkspace(rawFrames, goodFrames, eventCountInFrame,
+                                minEventsReq, maxEventsReq, frameEventCounts,
+                                events, eventsInFrame);
+
+      if (reportProgressAndCheckCancel(numProcessedEvents, eventCountInFrame,
+                                       totalNumEvents, totalFilePaths,
+                                       fileCount)) {
+        return;
+      }
+    } else { // Catch all other events and notify.
+      g_log.warning() << "Unexpected event type loaded.\n";
+    }
+  }
+  g_log.information() << "Finished loading a file.\n";
+  ++fileCount;
+}
+
+/**
+ * @brief Add a string value to the sample logs.
+ *
+ * @param logName The name of the log.
+ * @param logText The content of the log.
+ * @param ws The workspace to add the log to.
+ */
+void LoadNGEM::addToSampleLog(const std::string &logName,
+                              const std::string &logText,
+                              DataObjects::EventWorkspace_sptr &ws) {
+  API::Algorithm_sptr sampLogAlg = createChildAlgorithm("AddSampleLog");
+  sampLogAlg->setProperty("Workspace", ws);
+  sampLogAlg->setProperty("LogType", "String");
+  sampLogAlg->setProperty("LogName", logName);
+  sampLogAlg->setProperty("LogText", logText);
+  sampLogAlg->executeAsChildAlg();
+}
+
+/**
+ * @brief Add a number value to the sample logs.
+ *
+ * @param logName Name of the log.
+ * @param logNumber The value of the log.
+ * @param ws The workspace to add the log to.
+ */
+void LoadNGEM::addToSampleLog(const std::string &logName, const int &logNumber,
+                              DataObjects::EventWorkspace_sptr &ws) {
+  API::Algorithm_sptr sampLogAlg = createChildAlgorithm("AddSampleLog");
+  sampLogAlg->setProperty("Workspace", ws);
+  sampLogAlg->setProperty("LogType", "Number");
+  sampLogAlg->setProperty("LogName", logName);
+  sampLogAlg->setProperty("LogText", std::to_string(logNumber));
+  sampLogAlg->executeAsChildAlg();
+}
+
+/**
+ * @brief Ensure that the file fits into 16, as the detector spits out 128 bit
+ * words (16 bytes)
+ *
+ * @param file The file to check.
+ * @return size_t The size of the file.
+ */
+size_t LoadNGEM::verifyFileSize(std::ifstream &file) {
+  // Check that the file fits into 16 byte sections.
+  file.seekg(0, file.end);
+  size_t size = file.tellg();
+  if (size % 16 != 0) {
+    g_log.warning()
+        << "Invalid file size. File is size is " << size
+        << " bytes which is not a multiple of 16. There may be some bytes "
+           "missing from the data. \n";
+  }
+  file.seekg(0);
+  return size;
+}
+
+/**
+ * @brief Report the progress of the loader through the current file.
+ *
+ * @param numProcessedEvents The number of events processed so far.
+ * @param eventCountInFrame The number of events in the current frame.
+ * @param totalNumEvents The total number of events in the file.
+ * @param totalFilePaths The total number of file paths to process.
+ * @param fileCount The number of files processed.
+ * @return true If user has cancelled the load.
+ * @return false If the user has not cancelled.
+ */
+bool LoadNGEM::reportProgressAndCheckCancel(size_t &numProcessedEvents,
+                                            int &eventCountInFrame,
+                                            const size_t &totalNumEvents,
+                                            const size_t &totalFilePaths,
+                                            const int &fileCount) {
+  numProcessedEvents += eventCountInFrame;
+  std::string message(std::to_string(fileCount) + "/" +
+                      std::to_string(totalFilePaths));
+  progress(double(numProcessedEvents) / double(totalNumEvents) / 1.11111,
+           message);
+  eventCountInFrame = 0;
+  // Check for cancel flag.
+  return this->getCancel();
+}
+
+/**
+ * @brief Create a count workspace to allow for the selection of "good"
+ * frames.
+ *
+ * @param frameEventCounts A Vector of the number of events per frame.
+ */
+void LoadNGEM::createCountWorkspace(
+    const std::vector<double> &frameEventCounts) {
+  std::vector<double> xAxisCounts(frameEventCounts.size() + 1);
+  std::generate(xAxisCounts.begin(),
+                xAxisCounts.end(), [n = 0.0]() mutable { return ++n; });
+
+  DataObjects::Workspace2D_sptr countsWorkspace =
+      DataObjects::create<DataObjects::Workspace2D>(
+          1, HistogramData::Histogram(HistogramData::BinEdges(xAxisCounts)));
+
+  countsWorkspace->mutableY(0) = frameEventCounts;
+  std::string countsWorkspaceName(this->getProperty("OutputWorkspace"));
+  countsWorkspaceName.append("_event_counts");
+  countsWorkspace->setYUnit("Counts");
+  boost::shared_ptr<Kernel::Units::Label> XLabel =
+      boost::dynamic_pointer_cast<Kernel::Units::Label>(
+          Kernel::UnitFactory::Instance().create("Label"));
+  XLabel->setLabel("Frame");
+  countsWorkspace->getAxis(0)->unit() = XLabel;
+
+  this->declareProperty(
+      std::make_unique<API::WorkspaceProperty<API::Workspace>>(
+          "CountsWorkspace", countsWorkspaceName, Kernel::Direction::Output),
+      "Counts of events per frame.");
+  progress(1.00);
+  this->setProperty("CountsWorkspace", countsWorkspace);
+}
+
+/**
+ * @brief Load the nGEM instrument into a workspace.
+ *
+ * @param dataWorkspace The workspace to load into.
+ */
+void LoadNGEM::loadInstrument(DataObjects::EventWorkspace_sptr &dataWorkspace) {
+  auto loadInstrument = this->createChildAlgorithm("LoadInstrument");
+  loadInstrument->setPropertyValue("InstrumentName", "NGEM");
+  loadInstrument->setProperty<API::MatrixWorkspace_sptr>("Workspace",
+                                                         dataWorkspace);
+  loadInstrument->setProperty("RewriteSpectraMap", Kernel::OptionalBool(false));
+  loadInstrument->execute();
+}
+
+/**
+ * @brief Validate inputs into the loader GUI.
+ *
+ * @return std::map<std::string, std::string> A map that is empty if there are
+ * no issues, and contains a key of the input field and a value of the error
+ * message otherwise.
+ */
+std::map<std::string, std::string> LoadNGEM::validateInputs() {
+  std::map<std::string, std::string> results;
+
+  int MinEventsPerFrame = getProperty("MinEventsPerFrame");
+  int MaxEventsPerFrame = getProperty("MaxEventsPerFrame");
+
+  if (MaxEventsPerFrame < MinEventsPerFrame) {
+    results["MaxEventsPerFrame"] =
+        "MaxEventsPerFrame is less than MinEvents per frame";
+  }
+  return results;
+}
+
+} // namespace DataHandling
+} // namespace Mantid
\ No newline at end of file
diff --git a/Framework/DataHandling/test/LoadNGEMTest.h b/Framework/DataHandling/test/LoadNGEMTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..1bffa9539f7349675a60ded55792ec455ac0ecdb
--- /dev/null
+++ b/Framework/DataHandling/test/LoadNGEMTest.h
@@ -0,0 +1,184 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef LOADNGEMTEST_H_
+#define LOADNGEMTEST_H_
+
+#include <MantidAPI/AnalysisDataService.h>
+#include <MantidAPI/FileFinder.h>
+#include <MantidDataHandling/LoadNGEM.h>
+#include <MantidDataObjects/EventWorkspace.h>
+#include <cxxtest/TestSuite.h>
+
+using namespace Mantid;
+using namespace Mantid::DataHandling;
+using namespace Mantid::API;
+
+class LoadNGEMTest : public CxxTest::TestSuite {
+public:
+  void test_init() {
+    LoadNGEM alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize());
+
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty(
+        "Filename", getTestFilePath("GEM000005_00_000_short.edb")));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("OutputWorkspace", "ws"));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("BinWidth", 10.0));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("MinEventsPerFrame", 10));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("MaxEventsPerFrame", 20));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("GenerateEventsPerFrame", false));
+  }
+
+  void test_exec_loads_data_to_ads() {
+    LoadNGEM alg;
+    alg.initialize();
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty(
+        "Filename", getTestFilePath("GEM000005_00_000_short.edb")));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("OutputWorkspace", "ws"));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("GenerateEventsPerFrame", false));
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+
+    TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().remove("ws"));
+  }
+
+  void test_exec_loads_event_counts_workspace() {
+    LoadNGEM alg;
+    alg.initialize();
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty(
+        "Filename", getTestFilePath("GEM000005_00_000_short.edb")));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("OutputWorkspace", "ws"));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("GenerateEventsPerFrame", true));
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+
+    TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().remove("ws"));
+    TS_ASSERT_THROWS_NOTHING(
+        AnalysisDataService::Instance().remove("ws_event_counts"));
+  }
+
+  void test_exec_not_load_event_counts_workspace() {
+    LoadNGEM alg;
+    alg.initialize();
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty(
+        "Filename", getTestFilePath("GEM000005_00_000_short.edb")));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("OutputWorkspace", "ws"));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("GenerateEventsPerFrame", false));
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+
+    TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().remove("ws"));
+    TS_ASSERT_THROWS_ANYTHING(
+        AnalysisDataService::Instance().retrieve("ws_event_counts"));
+  }
+
+  void test_init_fails_on_bad_binWidth() {
+    LoadNGEM alg;
+    alg.initialize();
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_ANYTHING(alg.setProperty("BinWidth", -10.0));
+  }
+
+  void test_init_fails_on_bad_MaxEventsPerFrame() {
+    LoadNGEM alg;
+    alg.initialize();
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_ANYTHING(alg.setProperty("MaxEventsPerFrame", -10));
+  }
+
+  void test_init_fails_on_bad_MinEventsPerFrame() {
+    LoadNGEM alg;
+    alg.initialize();
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_ANYTHING(alg.setProperty("MinEventsPerFrame", -10));
+  }
+
+  void test_init_fails_on_MaxEvents_is_less_than_MinEvents() {
+    LoadNGEM alg;
+    alg.initialize();
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty(
+        "Filename", getTestFilePath("GEM000005_00_000_short.edb")));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("OutputWorkspace", "ws"));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("MinEventsPerFrame", 20));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("MaxEventsPerFrame", 10));
+
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
+  }
+
+  void test_MinEventsPerFrame_removes_low_values() {
+    LoadNGEM alg;
+    alg.initialize();
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty(
+        "Filename", getTestFilePath("GEM000005_00_000_short.edb")));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("OutputWorkspace", "ws"));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("MinEventsPerFrame", 0));
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+
+    DataObjects::EventWorkspace_sptr ws;
+
+    ws =
+        AnalysisDataService::Instance().retrieveWS<DataObjects::EventWorkspace>(
+            "ws");
+    TS_ASSERT(ws);
+    const size_t rawNumEvents = ws->getNumberEvents();
+
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setProperty("MinEventsPerFrame", Mantid::EMPTY_INT()));
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    ws =
+        AnalysisDataService::Instance().retrieveWS<DataObjects::EventWorkspace>(
+            "ws");
+    TS_ASSERT(rawNumEvents > ws->getNumberEvents());
+  }
+
+  void test_MaxEventsPerFrame_removes_high_values() {
+    LoadNGEM alg;
+    alg.initialize();
+    TS_ASSERT(alg.isInitialized());
+
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty(
+        "Filename", getTestFilePath("GEM000005_00_000_short.edb")));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("OutputWorkspace", "ws"));
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+
+    DataObjects::EventWorkspace_sptr ws;
+    ws =
+        AnalysisDataService::Instance().retrieveWS<DataObjects::EventWorkspace>(
+            "ws");
+    TS_ASSERT(ws);
+    const size_t rawNumEvents = ws->getNumberEvents();
+
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("MaxEventsPerFrame", 0));
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    ws =
+        AnalysisDataService::Instance().retrieveWS<DataObjects::EventWorkspace>(
+            "ws");
+    TS_ASSERT(rawNumEvents > ws->getNumberEvents());
+  }
+
+private:
+  // Helper function to get the path of a specified file.
+  std::string getTestFilePath(const std::string &filename) {
+    const std::string filepath =
+        Mantid::API::FileFinder::Instance().getFullPath(filename);
+    TS_ASSERT_DIFFERS(filepath, "");
+    return filepath;
+  }
+};
+
+#endif // LOADNGEMTEST_H_
\ No newline at end of file
diff --git a/Testing/Data/UnitTest/GEM000005_00_000_short.edb.md5 b/Testing/Data/UnitTest/GEM000005_00_000_short.edb.md5
new file mode 100644
index 0000000000000000000000000000000000000000..7953cfbf0e1bec3b83dc69259b9010fd70be242f
--- /dev/null
+++ b/Testing/Data/UnitTest/GEM000005_00_000_short.edb.md5
@@ -0,0 +1 @@
+1010588fa5f3933b43ace958c201f93f
diff --git a/docs/source/algorithms/LoadNGEM-v1.rst b/docs/source/algorithms/LoadNGEM-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..e825dfe732b2c312548ffdb0e765db5d057e1144
--- /dev/null
+++ b/docs/source/algorithms/LoadNGEM-v1.rst
@@ -0,0 +1,34 @@
+.. algorithm::
+
+.. summary::
+
+.. relatedalgorithms::
+
+.. properties::
+
+Description
+-----------
+The LoadNGEM algorithm will read .edb files generated by the nGEM
+detector.
+
+The detector produces files that are up to 1GB in size, so if the
+collection produces more than 1GB of data, it will create a new file
+to write the rest of the data to. When all of the files are selected
+they are loaded into a single workspace containing all of the events.
+
+The loading process allows the option to include a count of the number
+of events in each frame (begun by a T0 event), which is loaded as a
+plottable workspace. This can then be used to determine what is considered
+a "good frame" so that only good frames are included in the final data.
+
+Child Algorithms used
+#####################
+
+The ChildAlgorithms used by LoadNGEM are:
+
+* :ref:`algm-AddSampleLog-v1` - Adds data to the Sample Log of the workspace
+* :ref:`algm-LoadInstrument-v1` - Loads the instrument associated with the data
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/release/v4.2.0/framework.rst b/docs/source/release/v4.2.0/framework.rst
index dd0a72879211e45749e032e908a00c6beb442a70..650606854d9afcba40be75012ac37d3067807ed7 100644
--- a/docs/source/release/v4.2.0/framework.rst
+++ b/docs/source/release/v4.2.0/framework.rst
@@ -14,6 +14,7 @@ Concepts
 
 Algorithms
 ----------
+* :ref:`LoadNGEM <algm-LoadNGEM>` added as a loader for the .edb files generated by the nGEM detector used for diagnostics. Generates an event workspace. 
 * :ref:`MaskAngle <algm-MaskAngle>` has an additional option of ``Angle='InPlane'``
 * :ref:`FitIncidentSpectrum <algm-FitIncidentSpectrum>` will fit a curve to an incident spectrum returning the curve and it's first derivative.
 * Whitespace is now ignored anywhere in the string when setting the Filename parameter in :ref:`Load <algm-Load>`.
diff --git a/instrument/Facilities.xml b/instrument/Facilities.xml
index 7ba5baee6fe35b8ccdf5f0400cbfda798f7f7d9e..61a2438d497af2e360984ba911ec75ff346a4d17 100644
--- a/instrument/Facilities.xml
+++ b/instrument/Facilities.xml
@@ -157,6 +157,14 @@
     </livedata>
   </instrument>
 
+  <instrument name="NGEM">
+    <technique>Neutron Diffraction</technique>
+    <zeropadding size="8"/>
+    <livedata>
+      <connection name="histo" address="NDXGEM:6789" listener="ISISHistoDataListener" />
+    </livedata>
+  </instrument>
+
   <instrument name="OSIRIS" shortname="OSI" beamline="N6">
     <zeropadding size="8" startRunNumber="99780" prefix="OSIRIS"/>
     <technique>Neutron Diffraction</technique>
diff --git a/instrument/NGEM_Definition.xml b/instrument/NGEM_Definition.xml
new file mode 100644
index 0000000000000000000000000000000000000000..17a9172e710f91969bdd4a4512a2ebb199a56e0b
--- /dev/null
+++ b/instrument/NGEM_Definition.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- For help on the notation used to specify an Instrument Definition File 
+     see http://www.mantidproject.org/IDF -->
+<instrument xmlns="http://www.mantidproject.org/IDF/1.0" 
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 http://schema.mantidproject.org/IDF/1.0/IDFSchema.xsd"
+ name="NGEM" valid-from   ="2019-05-30 00:00:00"
+                       valid-to     ="2100-10-17 09:29:59"
+		       last-modified="2019-05-30 11:40:00">
+
+  <defaults>
+    <length unit="meter"/>
+    <angle unit="degree"/>
+    <reference-frame>
+      <!-- The z-axis is set parallel to and in the direction of the beam. the 
+           y-axis points up and the coordinate system is right handed. -->
+      <along-beam axis="z"/>
+      <pointing-up axis="y"/>
+      <handedness val="right"/>
+    </reference-frame>
+    <default-view axis-view="z-"/>
+  </defaults>
+  
+  <!-- LIST OF PHYSICAL COMPONENTS (which the instrument consists of) -->
+  
+  <!-- source and sample-position components -->
+
+  <component type="source">
+    <location z="-40.0"> <facing val="none"/> </location>
+  </component>
+  <type name="source" is="Source" />
+  
+  <component type="some-sample-holder">
+    <location><facing val="none"/> </location>
+  </component>
+  
+<type name="some-sample-holder" is="SamplePos">
+     <properties />
+     <sphere id="some-shape">
+       <centre x="0.0"  y="0.0" z="0.0" />
+       <radius val="0.03" />
+     </sphere>
+     <algebra val="some-shape" />
+</type>
+  
+  
+  <component type="main-detector-bank" idstart="1" idfillbyfirst="x" idstepbyrow="128">
+    <location z="1.5" name="main-detector-bank"/>
+  </component>
+ 
+  <type name="main-detector-bank" is="rectangular_detector" type="main-detector-pixel" 
+    xpixels="128" xstart="-0.05" xstep="+0.000787402"
+    ypixels="128" ystart="-0.05" ystep="+0.000787402" > 
+  </type>
+    
+  <type name="main-detector-pixel" is="detector">
+    <cuboid id="shape"> 
+      <left-front-bottom-point x="0.000393701" y="-0.000393701" z="0.0"  />
+      <left-front-top-point  x="0.000393701" y="-0.000393701" z="0.00000005"  />
+      <left-back-bottom-point  x="-0.000393701" y="-0.000393701" z="0.0"  />
+      <right-front-bottom-point  x="0.000393701" y="0.000393701" z="0.0"  />
+    </cuboid>
+    <algebra val="shape" /> 
+  </type>    
+
+
+</instrument>