diff --git a/Framework/CMakeLists.txt b/Framework/CMakeLists.txt
index 3d5d8354bc366fa40c7812c609a4c7feca49c552..6d1f4447c79cf546f8b5f51f7ed52a0141cb74f7 100644
--- a/Framework/CMakeLists.txt
+++ b/Framework/CMakeLists.txt
@@ -74,6 +74,9 @@ add_subdirectory (Types)
 include_directories (Kernel/inc)
 add_subdirectory (Kernel)
 
+include_directories (MPI/inc)
+add_subdirectory (MPI)
+
 include_directories (HistogramData/inc)
 add_subdirectory (HistogramData)
 
diff --git a/Framework/MPI/CMakeLists.txt b/Framework/MPI/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..007d491a376aa09646ab923c6599854bd52d2fc5
--- /dev/null
+++ b/Framework/MPI/CMakeLists.txt
@@ -0,0 +1,59 @@
+set ( SRC_FILES
+	src/Communicator.cpp
+	src/CommunicatorBackend.cpp
+	src/ParallelRunner.cpp
+	src/Request.cpp
+	src/Status.cpp
+)
+
+set ( INC_FILES
+	inc/MantidMPI/Communicator.h
+	inc/MantidMPI/CommunicatorBackend.h
+	inc/MantidMPI/ParallelRunner.h
+	inc/MantidMPI/Request.h
+	inc/MantidMPI/Status.h
+)
+
+set ( TEST_FILES
+	CommunicatorBackendTest.h
+	CommunicatorTest.h
+	ParallelRunnerTest.h
+	RequestTest.h
+	StatusTest.h
+)
+
+if (COVERALLS)
+  foreach( loop_var ${SRC_FILES} ${INC_FILES})
+    set_property(GLOBAL APPEND PROPERTY COVERAGE_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/${loop_var}")
+  endforeach(loop_var)
+endif()
+
+if(UNITY_BUILD)
+  include(UnityBuild)
+  enable_unity_build(MPI SRC_FILES SRC_UNITY_IGNORE_FILES 10)
+endif(UNITY_BUILD)
+
+# Add the target for this directory
+add_library ( MPI ${SRC_FILES} ${INC_FILES} )
+# Set the name of the generated library
+set_target_properties ( MPI PROPERTIES OUTPUT_NAME MantidMPI
+  COMPILE_DEFINITIONS IN_MANTID_MPI )
+
+if (OSX_VERSION VERSION_GREATER 10.8)
+  set_target_properties ( MPI PROPERTIES INSTALL_RPATH "@loader_path/../MacOS")
+endif ()
+
+# Add to the 'Framework' group in VS
+set_property ( TARGET MPI PROPERTY FOLDER "MantidFramework" )
+
+target_link_libraries ( MPI LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME} 
+                        ${GSL_LIBRARIES} ${MANTIDLIBS} )
+
+# Add the unit tests directory
+add_subdirectory ( test )
+
+###########################################################################
+# Installation settings
+###########################################################################
+
+install ( TARGETS MPI ${SYSTEM_PACKAGE_TARGET} DESTINATION ${LIB_DIR} )
diff --git a/Framework/MPI/inc/MantidMPI/Communicator.h b/Framework/MPI/inc/MantidMPI/Communicator.h
new file mode 100644
index 0000000000000000000000000000000000000000..e0edf9933fa29380c0c961c34e571f97738eab43
--- /dev/null
+++ b/Framework/MPI/inc/MantidMPI/Communicator.h
@@ -0,0 +1,106 @@
+#ifndef MANTID_MPI_COMMUNICATOR_H_
+#define MANTID_MPI_COMMUNICATOR_H_
+
+#include "MantidMPI/CommunicatorBackend.h"
+#include "MantidMPI/DllConfig.h"
+#include "MantidMPI/Status.h"
+
+#include <boost/make_shared.hpp>
+#ifdef MPI_EXPERIMENTAL
+#include <boost/mpi/communicator.hpp>
+#endif
+
+namespace Mantid {
+namespace MPI {
+
+/** Wrapper for boost::mpi::communicator. For non-MPI builds an equivalent
+  implementation is provided.
+
+  @author Simon Heybrock
+  @date 2017
+
+  Copyright &copy; 2017 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+  National Laboratory & European Spallation Source
+
+  This file is part of Mantid.
+
+  Mantid is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  Mantid is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+  File change history is stored at: <https://github.com/mantidproject/mantid>
+  Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class MANTID_MPI_DLL Communicator {
+public:
+  Communicator() = default;
+#ifdef MPI_EXPERIMENTAL
+  explicit Communicator(const boost::mpi::communicator &comm);
+#else
+  Communicator(boost::shared_ptr<CommunicatorBackend> backend, const int rank);
+#endif
+
+  int rank() const;
+  int size() const;
+  template <typename... T> void send(T &&... args) const;
+  template <typename... T> void recv(T &&... args) const;
+  template <typename... T> Request isend(T &&... args) const;
+  template <typename... T> Request irecv(T &&... args) const;
+
+private:
+#ifdef MPI_EXPERIMENTAL
+  boost::mpi::communicator m_communicator;
+#else
+  boost::shared_ptr<CommunicatorBackend> m_backend{
+      boost::make_shared<CommunicatorBackend>()};
+  const int m_rank{0};
+#endif
+};
+
+template <typename... T> void Communicator::send(T &&... args) const {
+#ifdef MPI_EXPERIMENTAL
+  m_communicator.send(std::forward<T>(args)...);
+#else
+  m_backend->send(m_rank, std::forward<T>(args)...);
+#endif
+}
+
+template <typename... T> void Communicator::recv(T &&... args) const {
+#ifdef MPI_EXPERIMENTAL
+  // Not returning a status since it would usually not get initialized. See
+  // http://mpi-forum.org/docs/mpi-1.1/mpi-11-html/node35.html#Node35.
+  static_cast<void>(m_communicator.recv(std::forward<T>(args)...));
+#else
+  return m_backend->recv(m_rank, std::forward<T>(args)...);
+#endif
+}
+
+template <typename... T> Request Communicator::isend(T &&... args) const {
+#ifdef MPI_EXPERIMENTAL
+  return m_communicator.isend(std::forward<T>(args)...);
+#else
+  return m_backend->isend(m_rank, std::forward<T>(args)...);
+#endif
+}
+
+template <typename... T> Request Communicator::irecv(T &&... args) const {
+#ifdef MPI_EXPERIMENTAL
+  return m_communicator.irecv(std::forward<T>(args)...);
+#else
+  return m_backend->irecv(m_rank, std::forward<T>(args)...);
+#endif
+}
+
+} // namespace MPI
+} // namespace Mantid
+
+#endif /* MANTID_MPI_COMMUNICATOR_H_ */
diff --git a/Framework/MPI/inc/MantidMPI/CommunicatorBackend.h b/Framework/MPI/inc/MantidMPI/CommunicatorBackend.h
new file mode 100644
index 0000000000000000000000000000000000000000..d82a6cb532cb084ebf698c54187988d946ec9787
--- /dev/null
+++ b/Framework/MPI/inc/MantidMPI/CommunicatorBackend.h
@@ -0,0 +1,125 @@
+#ifndef MANTID_MPI_COMMUNICATORBACKEND_H_
+#define MANTID_MPI_COMMUNICATORBACKEND_H_
+
+#include "MantidMPI/DllConfig.h"
+#include "MantidMPI/Request.h"
+#include "MantidKernel/make_unique.h"
+
+#include <boost/archive/binary_oarchive.hpp>
+#include <boost/archive/binary_iarchive.hpp>
+
+#include <functional>
+#include <istream>
+#include <map>
+#include <mutex>
+#include <ostream>
+#include <sstream>
+#include <tuple>
+
+namespace Mantid {
+namespace MPI {
+
+/** CommunicatorBackend provides a backend for data exchange between
+  Communicators in the case of non-MPI builds when communication between threads
+  is used to mimic MPI calls.
+
+  @author Simon Heybrock
+  @date 2017
+
+  Copyright &copy; 2017 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+  National Laboratory & European Spallation Source
+
+  This file is part of Mantid.
+
+  Mantid is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  Mantid is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+  File change history is stored at: <https://github.com/mantidproject/mantid>
+  Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class MANTID_MPI_DLL CommunicatorBackend {
+public:
+  CommunicatorBackend() = default;
+  explicit CommunicatorBackend(const int size);
+
+  CommunicatorBackend(const CommunicatorBackend &) = delete;
+  const CommunicatorBackend &operator=(const CommunicatorBackend &) = delete;
+
+  int size() const;
+
+  template <typename... T>
+  void send(int source, int dest, int tag, T &&... args);
+
+  template <typename... T>
+  void recv(int dest, int source, int tag, T &&... args);
+
+  template <typename... T>
+  Request isend(int source, int dest, int tag, T &&... args);
+
+  template <typename... T>
+  Request irecv(int dest, int source, int tag, T &&... args);
+
+private:
+  int m_size{1};
+  std::map<std::tuple<int, int, int>, std::vector<std::stringbuf>> m_buffer;
+  std::mutex m_mutex;
+};
+
+template <typename... T>
+void CommunicatorBackend::send(int source, int dest, int tag, T &&... args) {
+  std::stringbuf buf;
+  std::ostream os(&buf);
+  boost::archive::binary_oarchive oa(os);
+  oa.operator<<(std::forward<T>(args)...);
+  std::lock_guard<std::mutex> lock(m_mutex);
+  m_buffer[std::make_tuple(source, dest, tag)].push_back(std::move(buf));
+}
+
+template <typename... T>
+void CommunicatorBackend::recv(int dest, int source, int tag, T &&... args) {
+  const auto key = std::make_tuple(source, dest, tag);
+  while (true) {
+    std::lock_guard<std::mutex> lock(m_mutex);
+    auto it = m_buffer.find(key);
+    if (it == m_buffer.end())
+      continue;
+    auto &queue = it->second;
+    if (queue.empty())
+      continue;
+    std::istream is(&queue.front());
+    boost::archive::binary_iarchive ia(is);
+    ia.operator>>(std::forward<T>(args)...);
+    queue.erase(queue.begin());
+    std::cout.operator<<(args...) << std::endl;
+    return;
+  }
+}
+
+template <typename... T>
+Request CommunicatorBackend::isend(int source, int dest, int tag,
+                                   T &&... args) {
+  send(source, dest, tag, std::forward<T>(args)...);
+  return Request{};
+}
+
+template <typename... T>
+Request CommunicatorBackend::irecv(int dest, int source, int tag,
+                                   T &&... args) {
+  return Request(std::bind(&CommunicatorBackend::recv<T...>, this, dest, source,
+                           tag, std::ref(std::forward<T>(args)...)));
+}
+
+} // namespace MPI
+} // namespace Mantid
+
+#endif /* MANTID_MPI_COMMUNICATORBACKEND_H_ */
diff --git a/Framework/MPI/inc/MantidMPI/DllConfig.h b/Framework/MPI/inc/MantidMPI/DllConfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..d689081f7872224394b720a00ff05ffe49c6d7c9
--- /dev/null
+++ b/Framework/MPI/inc/MantidMPI/DllConfig.h
@@ -0,0 +1,37 @@
+#ifndef MANTID_MPI_DLLCONFIG_H_
+#define MANTID_MPI_DLLCONFIG_H_
+
+/*
+  This file contains the DLLExport/DLLImport linkage configuration for the
+  MPI library
+
+  Copyright &copy; 2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+  National Laboratory & European Spallation Source
+
+  This file is part of Mantid.
+
+  Mantid is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  Mantid is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+  File change history is stored at: <https://github.com/mantidproject/mantid>
+  Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+#include "MantidKernel/System.h"
+
+#ifdef IN_MANTID_MPI
+#define MANTID_MPI_DLL DLLExport
+#else
+#define MANTID_MPI_DLL DLLImport
+#endif // IN_MANTID_MPI
+
+#endif // MANTID_MPI_DLLCONFIG_H_
diff --git a/Framework/MPI/inc/MantidMPI/ParallelRunner.h b/Framework/MPI/inc/MantidMPI/ParallelRunner.h
new file mode 100644
index 0000000000000000000000000000000000000000..d5c26d3c36ec6641372a717e4063744c21a05d55
--- /dev/null
+++ b/Framework/MPI/inc/MantidMPI/ParallelRunner.h
@@ -0,0 +1,82 @@
+#ifndef MANTID_MPI_PARALLELRUNNER_H_
+#define MANTID_MPI_PARALLELRUNNER_H_
+
+#include "MantidMPI/CommunicatorBackend.h"
+#include "MantidMPI/Communicator.h"
+#include "MantidMPI/DllConfig.h"
+
+#include <functional>
+#include <thread>
+
+namespace Mantid {
+namespace MPI {
+
+/** Runs a callable in parallel. This is mainly a helper for testing code with
+  MPI calls. ParallelRunner passes a Communicator as first argument to the
+  callable. In a non-MPI build the callable is executed in threads ot mimic MPI
+  ranks.
+
+  Copyright &copy; 2017 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+  National Laboratory & European Spallation Source
+
+  This file is part of Mantid.
+
+  Mantid is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  Mantid is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+  File change history is stored at: <https://github.com/mantidproject/mantid>
+  Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class MANTID_MPI_DLL ParallelRunner {
+public:
+  ParallelRunner();
+  ParallelRunner(const int threads);
+
+  int size() const;
+
+  template <class Function, class... Args>
+  void run(Function &&f, Args &&... args);
+
+private:
+#ifndef MPI_EXPERIMENTAL
+  boost::shared_ptr<CommunicatorBackend> m_backend;
+#endif
+};
+
+template <class Function, class... Args>
+void ParallelRunner::run(Function &&f, Args &&... args) {
+#ifdef MPI_EXPERIMENTAL
+  Communicator comm;
+  f(comm, std::forward<Args>(args)...);
+#else
+  std::vector<std::thread> threads;
+  for (int t = 0; t < m_backend->size(); ++t) {
+    Communicator comm(m_backend, t);
+    threads.emplace_back(std::forward<Function>(f), comm,
+                         std::forward<Args>(args)...);
+  }
+  for (auto &t : threads) {
+    t.join();
+  }
+#endif
+}
+
+template <class... Args> void runParallel(Args &&... args) {
+  ParallelRunner runner;
+  runner.run(std::forward<Args>(args)...);
+}
+
+} // namespace MPI
+} // namespace Mantid
+
+#endif /* MANTID_MPI_PARALLELRUNNER_H_ */
diff --git a/Framework/MPI/inc/MantidMPI/Request.h b/Framework/MPI/inc/MantidMPI/Request.h
new file mode 100644
index 0000000000000000000000000000000000000000..b45c7fcff1df7d3e7d7ba9b627421871920ad2ef
--- /dev/null
+++ b/Framework/MPI/inc/MantidMPI/Request.h
@@ -0,0 +1,70 @@
+#ifndef MANTID_MPI_REQUEST_H_
+#define MANTID_MPI_REQUEST_H_
+
+#include "MantidMPI/DllConfig.h"
+
+#ifdef MPI_EXPERIMENTAL
+#include <boost/mpi/request.hpp>
+#else
+#include <thread>
+#endif
+
+namespace Mantid {
+namespace MPI {
+
+/** Wrapper for boost::mpi::request. For non-MPI builds an equivalent
+  implementation is provided.
+
+  @author Simon Heybrock
+  @date 2017
+
+  Copyright &copy; 2017 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+  National Laboratory & European Spallation Source
+
+  This file is part of Mantid.
+
+  Mantid is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  Mantid is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+  File change history is stored at: <https://github.com/mantidproject/mantid>
+  Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class MANTID_MPI_DLL Request {
+public:
+  Request() = default;
+#ifdef MPI_EXPERIMENTAL
+  Request(const boost::mpi::request &request);
+#else
+  template <class Function> explicit Request(Function &&f);
+#endif
+
+  void wait();
+
+private:
+#ifdef MPI_EXPERIMENTAL
+  boost::mpi::request m_request;
+#else
+  std::thread m_thread;
+#endif
+};
+
+#ifndef MPI_EXPERIMENTAL
+template <class Function>
+Request::Request(Function &&f)
+    : m_thread(std::forward<Function>(f)) {}
+#endif
+
+} // namespace MPI
+} // namespace Mantid
+
+#endif /* MANTID_MPI_REQUEST_H_ */
diff --git a/Framework/MPI/inc/MantidMPI/Status.h b/Framework/MPI/inc/MantidMPI/Status.h
new file mode 100644
index 0000000000000000000000000000000000000000..a5a79933da9c8aa9badc4a42a9a9edf9e707ea85
--- /dev/null
+++ b/Framework/MPI/inc/MantidMPI/Status.h
@@ -0,0 +1,65 @@
+#ifndef MANTID_MPI_STATUS_H_
+#define MANTID_MPI_STATUS_H_
+
+#include "MantidMPI/DllConfig.h"
+
+#ifdef MPI_EXPERIMENTAL
+#include <boost/mpi/status.hpp>
+#endif
+
+namespace Mantid {
+namespace MPI {
+
+/** Wrapper for boost::mpi::status. For non-MPI builds an equivalent
+  implementation is provided.
+
+  @author Simon Heybrock
+  @date 2017
+
+  Copyright &copy; 2017 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+  National Laboratory & European Spallation Source
+
+  This file is part of Mantid.
+
+  Mantid is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  Mantid is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+  File change history is stored at: <https://github.com/mantidproject/mantid>
+  Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class MANTID_MPI_DLL Status {
+public:
+#ifdef MPI_EXPERIMENTAL
+  Status(const boost::mpi::status &status);
+#else
+  Status(int source, int tag, int error);
+#endif
+
+  int source() const;
+  int tag() const;
+  int error() const;
+
+private:
+#ifdef MPI_EXPERIMENTAL
+  boost::mpi::status m_status;
+#else
+  int m_source;
+  int m_tag;
+  int m_error;
+#endif
+};
+
+} // namespace MPI
+} // namespace Mantid
+
+#endif /* MANTID_MPI_STATUS_H_ */
diff --git a/Framework/MPI/src/Communicator.cpp b/Framework/MPI/src/Communicator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..06ffacd45bc64372510aad4805775b02e2f223e4
--- /dev/null
+++ b/Framework/MPI/src/Communicator.cpp
@@ -0,0 +1,32 @@
+#include "MantidMPI/Communicator.h"
+
+namespace Mantid {
+namespace MPI {
+
+#ifdef MPI_EXPERIMENTAL
+Communicator::Communicator(const boost::mpi::communicator &comm)
+    : m_communicator(comm) {}
+#else
+Communicator::Communicator(boost::shared_ptr<CommunicatorBackend> backend,
+                           const int rank)
+    : m_backend(backend), m_rank(rank) {}
+#endif
+
+int Communicator::rank() const {
+#ifdef MPI_EXPERIMENTAL
+  return m_communicator.rank();
+#else
+  return m_rank;
+#endif
+}
+
+int Communicator::size() const {
+#ifdef MPI_EXPERIMENTAL
+  return m_communicator.size();
+#else
+  return m_backend->size();
+#endif
+}
+
+} // namespace MPI
+} // namespace Mantid
diff --git a/Framework/MPI/src/CommunicatorBackend.cpp b/Framework/MPI/src/CommunicatorBackend.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..23a79d74cafdfde898d43a02d61a1c88962d5a8e
--- /dev/null
+++ b/Framework/MPI/src/CommunicatorBackend.cpp
@@ -0,0 +1,11 @@
+#include "MantidMPI/CommunicatorBackend.h"
+
+namespace Mantid {
+namespace MPI {
+
+CommunicatorBackend::CommunicatorBackend(const int size) : m_size(size) {}
+
+int CommunicatorBackend::size() const { return m_size; }
+
+} // namespace MPI
+} // namespace Mantid
diff --git a/Framework/MPI/src/ParallelRunner.cpp b/Framework/MPI/src/ParallelRunner.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9a2c77799c457c3bc19846a2cbf8b760ecc337c5
--- /dev/null
+++ b/Framework/MPI/src/ParallelRunner.cpp
@@ -0,0 +1,36 @@
+#include "MantidMPI/ParallelRunner.h"
+
+#include <omp.h>
+
+namespace Mantid {
+namespace MPI {
+
+ParallelRunner::ParallelRunner() {
+#ifndef MPI_EXPERIMENTAL
+  m_backend = boost::make_shared<CommunicatorBackend>(omp_get_max_threads());
+#endif
+}
+
+ParallelRunner::ParallelRunner(const int threads) {
+#ifdef MPI_EXPERIMENTAL
+  Communicator comm;
+  if (comm.size() != threads)
+    throw(
+        "ParallelRunner: number of requested threads does not match number of "
+        "MPI ranks");
+#else
+  m_backend = boost::make_shared<CommunicatorBackend>(threads);
+#endif
+}
+
+int ParallelRunner::size() const {
+#ifdef MPI_EXPERIMENTAL
+  Communicator comm;
+  return comm.size();
+#else
+  return m_backend->size();
+#endif
+}
+
+} // namespace MPI
+} // namespace Mantid
diff --git a/Framework/MPI/src/Request.cpp b/Framework/MPI/src/Request.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c37ce1db3be85c116fe85cf28aab0e9dfb06c0de
--- /dev/null
+++ b/Framework/MPI/src/Request.cpp
@@ -0,0 +1,26 @@
+#include "MantidMPI/Request.h"
+
+#ifdef MPI_EXPERIMENTAL
+#include <boost/mpi/status.hpp>
+#endif
+
+namespace Mantid {
+namespace MPI {
+
+#ifdef MPI_EXPERIMENTAL
+Request::Request(const boost::mpi::request &request) : m_request(request) {}
+#endif
+
+void Request::wait() {
+// Not returning a status since it would usually not get initialized. See
+// http://mpi-forum.org/docs/mpi-1.1/mpi-11-html/node35.html#Node35.
+#ifdef MPI_EXPERIMENTAL
+  static_cast<void>(m_request.wait());
+#else
+  if (m_thread.joinable())
+    m_thread.join();
+#endif
+}
+
+} // namespace MPI
+} // namespace Mantid
diff --git a/Framework/MPI/src/Status.cpp b/Framework/MPI/src/Status.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e3311af865b8c98a2d9fa7493f3c545312a338ef
--- /dev/null
+++ b/Framework/MPI/src/Status.cpp
@@ -0,0 +1,38 @@
+#include "MantidMPI/Status.h"
+
+namespace Mantid {
+namespace MPI {
+
+#ifdef MPI_EXPERIMENTAL
+Status::Status(const boost::mpi::status &status) : m_status(status) {}
+#else
+Status::Status(int source, int tag, int error)
+    : m_source(source), m_tag(tag), m_error(error) {}
+#endif
+
+int Status::source() const {
+#ifdef MPI_EXPERIMENTAL
+  return m_status.source();
+#else
+  return m_source;
+#endif
+}
+
+int Status::tag() const {
+#ifdef MPI_EXPERIMENTAL
+  return m_status.tag();
+#else
+  return m_tag;
+#endif
+}
+
+int Status::error() const {
+#ifdef MPI_EXPERIMENTAL
+  return m_status.error();
+#else
+  return m_error;
+#endif
+}
+
+} // namespace MPI
+} // namespace Mantid
diff --git a/Framework/MPI/test/CMakeLists.txt b/Framework/MPI/test/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0cbe1d7e48dfc659afae82d01c94bc1f3d6b2970
--- /dev/null
+++ b/Framework/MPI/test/CMakeLists.txt
@@ -0,0 +1,18 @@
+if ( CXXTEST_FOUND )
+  include_directories ( SYSTEM ${CXXTEST_INCLUDE_DIR} ${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR} ../../TestHelpers/inc)
+
+  # This variable is used within the cxxtest_add_test macro to build these helper classes into the test executable.
+  # It will go out of scope at the end of this file so doesn't need un-setting
+  set ( TESTHELPER_SRCS EnvironmentSetup.cpp )
+
+  cxxtest_add_test ( MPITest ${TEST_FILES} ${GMOCK_TEST_FILES})
+  target_link_libraries( MPITest LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME} ${MANTIDLIBS}
+    MPI
+    ${Boost_LIBRARIES}
+    ${GMOCK_LIBRARIES}
+    ${GTEST_LIBRARIES} )
+
+  add_dependencies ( FrameworkTests MPITest )
+  # Add to the 'FrameworkTests' group in VS
+  set_property ( TARGET MPITest PROPERTY FOLDER "UnitTests" )
+endif ()
diff --git a/Framework/MPI/test/CommunicatorBackendTest.h b/Framework/MPI/test/CommunicatorBackendTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..60ca4ac9768dd9147c8e549d1f7ffadbd69e993e
--- /dev/null
+++ b/Framework/MPI/test/CommunicatorBackendTest.h
@@ -0,0 +1,30 @@
+#ifndef MANTID_MPI_COMMUNICATORBACKENDTEST_H_
+#define MANTID_MPI_COMMUNICATORBACKENDTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidMPI/CommunicatorBackend.h"
+
+using Mantid::MPI::CommunicatorBackend;
+
+class CommunicatorBackendTest : 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 CommunicatorBackendTest *createSuite() {
+    return new CommunicatorBackendTest();
+  }
+  static void destroySuite(CommunicatorBackendTest *suite) { delete suite; }
+
+  void test_default_constructor() {
+    CommunicatorBackend comm;
+    TS_ASSERT_EQUALS(comm.size(), 1);
+  }
+
+  void test_size_constructor() {
+    CommunicatorBackend comm{2};
+    TS_ASSERT_EQUALS(comm.size(), 2);
+  }
+};
+
+#endif /* MANTID_MPI_COMMUNICATORBACKENDTEST_H_ */
diff --git a/Framework/MPI/test/CommunicatorTest.h b/Framework/MPI/test/CommunicatorTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..3d8518fd651856aef1c89d58f8e9b0d8a3b2aef6
--- /dev/null
+++ b/Framework/MPI/test/CommunicatorTest.h
@@ -0,0 +1,101 @@
+#ifndef MANTID_MPI_COMMUNICATORTEST_H_
+#define MANTID_MPI_COMMUNICATORTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidMPI/Communicator.h"
+#include "MantidMPI/ParallelRunner.h"
+
+using namespace Mantid::MPI;
+
+namespace {
+void send_recv(const Communicator &comm) {
+  if (comm.size() < 2)
+    return;
+
+  double data = 3.14;
+
+  if (comm.rank() == 0)
+    TS_ASSERT_THROWS_NOTHING(comm.send(1, 123, data));
+  if (comm.rank() == 1) {
+    double result;
+    TS_ASSERT_THROWS_NOTHING(comm.recv(0, 123, result));
+    TS_ASSERT_EQUALS(result, data);
+  }
+}
+
+void isend_recv(const Communicator &comm) {
+  int64_t data = 123456789 + comm.rank();
+  int dest = (comm.rank() + 1) % comm.size();
+  int src = (comm.rank() + comm.size() - 1) % comm.size();
+  int tag = 123;
+  int64_t result;
+  int64_t expected = comm.rank() == 0 ? data + comm.size() - 1 : data - 1;
+
+  auto request = comm.isend(dest, tag, data);
+  TS_ASSERT_THROWS_NOTHING(comm.recv(src, tag, result));
+  TS_ASSERT_EQUALS(result, expected);
+  TS_ASSERT_THROWS_NOTHING(request.wait());
+}
+
+void send_irecv(const Communicator &comm) {
+  int64_t data = 123456789 + comm.rank();
+  int dest = (comm.rank() + 1) % comm.size();
+  int src = (comm.rank() + comm.size() - 1) % comm.size();
+  int tag = 123;
+  int64_t result;
+  int64_t expected = comm.rank() == 0 ? data + comm.size() - 1 : data - 1;
+
+  auto request = comm.irecv(src, tag, result);
+  TS_ASSERT_THROWS_NOTHING(comm.send(dest, tag, data));
+  TS_ASSERT_THROWS_NOTHING(request.wait());
+  TS_ASSERT_EQUALS(result, expected);
+}
+
+void isend_irecv(const Communicator &comm) {
+  int64_t data = 123456789 + comm.rank();
+  int dest = (comm.rank() + 1) % comm.size();
+  int src = (comm.rank() + comm.size() - 1) % comm.size();
+  int tag = 123;
+  int64_t result;
+  int64_t expected = comm.rank() == 0 ? data + comm.size() - 1 : data - 1;
+
+  auto send_req = comm.irecv(src, tag, result);
+  auto recv_req = comm.isend(dest, tag, data);
+  TS_ASSERT_THROWS_NOTHING(send_req.wait());
+  TS_ASSERT_THROWS_NOTHING(recv_req.wait());
+  TS_ASSERT_EQUALS(result, expected);
+}
+}
+
+class CommunicatorTest : 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 CommunicatorTest *createSuite() { return new CommunicatorTest(); }
+  static void destroySuite(CommunicatorTest *suite) { delete suite; }
+
+  void test_construct_default() { TS_ASSERT_THROWS_NOTHING(Communicator{}); }
+
+  void test_defaults() {
+    Communicator comm;
+#ifdef MPI_EXPERIMENTAL
+    boost::mpi::communicator world;
+    TS_ASSERT_EQUALS(comm.size(), world.size());
+    TS_ASSERT_EQUALS(comm.rank(), world.rank());
+#else
+    TS_ASSERT_EQUALS(comm.size(), 1);
+    TS_ASSERT_EQUALS(comm.rank(), 0);
+#endif
+  }
+
+  void test_send_recv() { runParallel(send_recv); }
+
+  void test_isend_recv() { runParallel(isend_recv); }
+
+  void test_send_irecv() { runParallel(send_irecv); }
+
+  void test_isend_irecv() { runParallel(isend_irecv); }
+};
+
+#endif /* MANTID_MPI_COMMUNICATORTEST_H_ */
diff --git a/Framework/MPI/test/EnvironmentSetup.cpp b/Framework/MPI/test/EnvironmentSetup.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5fa2467672baffffce717911785be8bca2ee78cc
--- /dev/null
+++ b/Framework/MPI/test/EnvironmentSetup.cpp
@@ -0,0 +1,9 @@
+#ifndef MANTID_MPI_ENVIRONMENTSETUP_H_
+#define MANTID_MPI_ENVIRONMENTSETUP_H_
+
+#ifdef MPI_EXPERIMENTAL
+#include <boost/mpi/environment.hpp>
+boost::mpi::environment env;
+#endif
+
+#endif /* MANTID_MPI_ENVIRONMENTSETUP_H_ */
diff --git a/Framework/MPI/test/ParallelRunnerTest.h b/Framework/MPI/test/ParallelRunnerTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..5035f4ac8220ec398cdae1014ff12443209d615d
--- /dev/null
+++ b/Framework/MPI/test/ParallelRunnerTest.h
@@ -0,0 +1,53 @@
+#ifndef MANTID_MPI_PARALLELRUNNERTEST_H_
+#define MANTID_MPI_PARALLELRUNNERTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidMPI/ParallelRunner.h"
+
+#include <mutex>
+#include <vector>
+
+using namespace Mantid::MPI;
+
+namespace {
+void check_size(const Communicator &comm, const int expected) {
+  TS_ASSERT_EQUALS(comm.size(), expected);
+}
+
+void get_ranks(const Communicator &comm, std::mutex &mutex,
+               std::set<int> &ranks) {
+  std::lock_guard<std::mutex> lock(mutex);
+  ranks.insert(comm.rank());
+}
+}
+
+class ParallelRunnerTest : 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 ParallelRunnerTest *createSuite() { return new ParallelRunnerTest(); }
+  static void destroySuite(ParallelRunnerTest *suite) { delete suite; }
+
+  void test_size() {
+    ParallelRunner parallel;
+    parallel.run(check_size, parallel.size());
+  }
+
+  void test_rank() {
+    std::mutex mutex;
+    std::set<int> ranks;
+    ParallelRunner parallel;
+    parallel.run(get_ranks, std::ref(mutex), std::ref(ranks));
+#ifdef MPI_EXPERIMENTAL
+    boost::mpi::communicator world;
+    TS_ASSERT_EQUALS(ranks.size(), 1);
+    TS_ASSERT_EQUALS(ranks.count(world.rank()), 1);
+#else
+    for (int rank = 0; rank < parallel.size(); ++rank)
+      TS_ASSERT_EQUALS(ranks.count(rank), 1);
+#endif
+  }
+};
+
+#endif /* MANTID_MPI_PARALLELRUNNERTEST_H_ */
diff --git a/Framework/MPI/test/RequestTest.h b/Framework/MPI/test/RequestTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..a98190350dd8998973b184c5c920f179806108c7
--- /dev/null
+++ b/Framework/MPI/test/RequestTest.h
@@ -0,0 +1,24 @@
+#ifndef MANTID_MPI_REQUESTTEST_H_
+#define MANTID_MPI_REQUESTTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidMPI/Request.h"
+
+using Mantid::MPI::Request;
+
+class RequestTest : 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 RequestTest *createSuite() { return new RequestTest(); }
+  static void destroySuite(RequestTest *suite) { delete suite; }
+
+  void test_default() {
+    TS_ASSERT_THROWS_NOTHING(Request());
+    Request req;
+    TS_ASSERT_THROWS_NOTHING(req.wait());
+  }
+};
+
+#endif /* MANTID_MPI_REQUESTTEST_H_ */
diff --git a/Framework/MPI/test/StatusTest.h b/Framework/MPI/test/StatusTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..49c67cdbb07d44da0c2e74c9f0380916226294da
--- /dev/null
+++ b/Framework/MPI/test/StatusTest.h
@@ -0,0 +1,32 @@
+#ifndef MANTID_MPI_STATUSTEST_H_
+#define MANTID_MPI_STATUSTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidMPI/Status.h"
+
+using Mantid::MPI::Status;
+
+class StatusTest : 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 StatusTest *createSuite() { return new StatusTest(); }
+  static void destroySuite(StatusTest *suite) { delete suite; }
+
+  void test_constructor() {
+#ifdef MPI_EXPERIMENTAL
+    Status status(boost::mpi::status{});
+    TS_ASSERT_EQUALS(status.source(), 0);
+    TS_ASSERT_EQUALS(status.tag(), 0);
+    TS_ASSERT_EQUALS(status.error(), 0);
+#else
+    Status status(1, 2, 3);
+    TS_ASSERT_EQUALS(status.source(), 1);
+    TS_ASSERT_EQUALS(status.tag(), 2);
+    TS_ASSERT_EQUALS(status.error(), 3);
+#endif
+  }
+};
+
+#endif /* MANTID_MPI_STATUSTEST_H_ */