diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFITS.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFITS.h
index f22452fabd9ea914788f816653977a21060090dc..474446b003ca01542ab1f1f8a38aba38bf33f20e 100644
--- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFITS.h
+++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFITS.h
@@ -15,7 +15,7 @@ using namespace std;
 
 struct FITSInfo {
   vector<string> headerItems;
-  map<string, string> headerKeys;
+  std::map<string, string> headerKeys;
   int bitsPerPixel;
   int numberOfAxis;
   int offset;
@@ -24,54 +24,44 @@ struct FITSInfo {
   double tof;
   double timeBin;
   double scale;
-  int imageKey;
+  std::string imageKey;
   long int countsInImage;
   long int numberOfTriggers;
-  string extension;
-  string filePath;
+  std::string extension;
+  std::string filePath;
   bool isFloat;
 };
 
 namespace Mantid {
 namespace DataHandling {
 /**
-  LoadFITS : Load a number of FITS files into a histogram Workspace
+LoadFITS: Load one or more of FITS files into a Workspace2D. The FITS
+format, normally used for images, is described for example here:
+http://www.fileformat.info/format/fits/egff.htm
 
-  File format is described here: http://www.fileformat.info/format/fits/egff.htm
-  This loader doesn't support the full specification, caveats are:
-    Support for unsigned 8, 16, 32 bit values only
-    Support only for 2 data axis
-    No support for format extensions
+At the moment this algorithm only supports 2 data axis and the
+following data types: unsigned 8, 16, 32 bits per pixel.
 
-  Loader is designed to work with multiple files, loading into a single
-  workspace.
-  At points there are assumptions that all files in a batch use the same number
-  of bits per pixel,
-  and that the number of spectra in each file are the same.
+Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
+Oak Ridge National Laboratory & European Spallation Source
 
-  @author John R Hill, RAL
-  @date 29/08/2014
+This file is part of Mantid.
 
-  Copyright &copy; 2014 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
-  National Laboratory & European Spallation Source
+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.
 
-  This file is part of Mantid.
+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.
 
-  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.
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-  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>
+File change history is stored at: <https://github.com/mantidproject/mantid>
+Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
 
 class DLLExport LoadFITS : public API::IFileLoader<Kernel::FileDescriptor> {
@@ -84,7 +74,7 @@ public:
 
   /// Summary of algorithms purpose
   virtual const std::string summary() const {
-    return "Load data from FITS files.";
+    return "Load FITS files into workspaces of type Workspace2D.";
   }
 
   /// Algorithm's version for identification overriding a virtual method
@@ -105,51 +95,80 @@ private:
   void init();
   /// Execution code
   void exec();
-  /// Parses the header values for the FITS file
-  bool parseHeader(FITSInfo &headerInfo);
 
-  /// Creates a vector of all rotations from a file
-  std::vector<double> readRotations(std::string rotFilePath, size_t fileCount);
+  /// Loads files into workspace(s)
+  void doLoadFiles(const std::vector<std::string> &paths);
+
+  /// Loads the FITS header(s) into a struct
+  void doLoadHeaders(const std::vector<std::string> &paths,
+                     std::vector<FITSInfo> &headers);
+
+  /// Parses the header values for the FITS file
+  void parseHeader(FITSInfo &headerInfo);
 
   /// Initialises a workspace with IDF and fills it with data
   DataObjects::Workspace2D_sptr
-  addWorkspace(const FITSInfo &fileInfo, size_t &newFileNumber,
-               void *&bufferAny, API::MantidImage &imageY,
-               API::MantidImage &imageE, double rotation,
-               const DataObjects::Workspace2D_sptr parent);
+  makeWorkspace(const FITSInfo &fileInfo, size_t &newFileNumber,
+                std::vector<char> &buffer, API::MantidImage &imageY,
+                API::MantidImage &imageE,
+                const DataObjects::Workspace2D_sptr parent);
+
+  // Reads the data from a single FITS file into a workspace
+  void readDataToWorkspace2D(DataObjects::Workspace2D_sptr ws,
+                             const FITSInfo &fileInfo, API::MantidImage &imageY,
+                             API::MantidImage &imageE,
+                             std::vector<char> &buffer);
+
+  /// Once loaded, check against standard and limitations of this algorithm
+  void headerSanityCheck(const FITSInfo &hdr, const FITSInfo &hdrFirst);
+
+  void setupDefaultKeywordNames();
 
   /// Returns the trailing number from a string minus leading 0's (so 25 from
   /// workspace_00025)
-  size_t fetchNumber(std::string name);
+  size_t fetchNumber(const std::string &name);
 
   // Adds a number of leading 0's to another number up to the totalDigitCount.
-  std::string padZeros(size_t number, size_t totalDigitCount);
-
-  // Reads the data from a single FITS file into a workspace
-  void readFileToWorkspace(DataObjects::Workspace2D_sptr ws,
-                           const FITSInfo &fileInfo, API::MantidImage &imageY,
-                           API::MantidImage &imageE, void *&bufferAny);
+  std::string padZeros(const size_t number, const size_t totalDigitCount);
 
   // Maps the header keys to specified values
   void mapHeaderKeys();
 
   // Strings used to map header keys
-  string m_headerScaleKey;
-  string m_headerOffsetKey;
-  string m_headerBitDepthKey;
-  string m_headerRotationKey;
-  string m_headerImageKeyKey;
-  string m_mapFile;
+  std::string m_headerScaleKey;
+  std::string m_headerOffsetKey;
+  std::string m_headerBitDepthKey;
+  std::string m_headerRotationKey;
+  std::string m_headerImageKeyKey;
+  std::string m_headerNAxisNameKey;
   std::vector<std::string> m_headerAxisNameKeys;
+  std::string m_mapFile;
 
-  string m_baseName;
+  static const std::string m_defaultImgType;
+
+  // names of extension headers
+  std::string m_sampleRotation;
+  std::string m_imageType;
+
+  std::string m_baseName;
   size_t m_spectraCount;
   API::Progress *m_progress;
 
-  // Number of digits which will be appended to a workspace name, i.e. 4 =
-  // workspace_0001
-  static const size_t DIGIT_SIZE_APPEND = 4;
+  // Number of digits for the fixed width appendix number added to
+  // workspace names, i.e. 3=> workspace_001; 5 => workspace_00001
+  static const size_t DIGIT_SIZE_APPEND = 5;
+  /// size of a FITS header block (room for 36 entries, of 80
+  /// characters each), in bytes. A FITS header always comes in
+  /// multiples of this block.
   static const int BASE_HEADER_SIZE = 2880;
+
+  // names for several options that can be given in a "FITS" header
+  // setup file
+  static const std::string m_BIT_DEPTH_NAME;
+  static const std::string m_AXIS_NAMES_NAME;
+  static const std::string m_ROTATION_NAME;
+  static const std::string m_IMAGE_KEY_NAME;
+  static const std::string m_HEADER_MAP_NAME;
 };
 
 } // namespace DataHandling
diff --git a/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp b/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp
index c147984dc309b96d04e74125cca22c1dd1bf87b3..f8c6571370091b98e9640f6f84fe2905b468c9b8 100644
--- a/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp
+++ b/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp
@@ -1,12 +1,14 @@
-#include "MantidDataHandling/LoadFITS.h"
 #include "MantidAPI/MultipleFileProperty.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/RegisterFileLoader.h"
+#include "MantidDataHandling/LoadFITS.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/UnitFactory.h"
+
 #include <boost/algorithm/string.hpp>
 #include <Poco/BinaryReader.h>
-#include <fstream>
+#include <Poco/FileStream.h>
+
 
 using namespace Mantid::DataHandling;
 using namespace Mantid::DataObjects;
@@ -14,40 +16,30 @@ using namespace Mantid::API;
 using namespace Mantid::Kernel;
 using namespace std;
 using namespace boost;
-using Poco::BinaryReader;
 
-namespace {
-static const std::string BIT_DEPTH_NAME = "BitDepthName";
-static const std::string ROTATION_NAME = "RotationName";
-static const std::string AXIS_NAMES_NAME = "AxisNames";
-static const std::string IMAGE_KEY_NAME = "ImageKeyName";
-static const std::string HEADER_MAP_NAME = "HeaderMapFile";
-
-/**
-* Used with find_if to check a string isn't a fits file (by checking extension)
-* @param s string to check for extension
-* @returns bool Value indicating if the string ends with .fits or not
-*/
-bool IsNotFits(std::string s) {
-  std::string tmp = s;
-  to_lower(tmp);
-  return !ends_with(tmp, ".fits");
-}
-}
+namespace {}
 
 namespace Mantid {
 namespace DataHandling {
 // Register the algorithm into the AlgorithmFactory
 DECLARE_FILELOADER_ALGORITHM(LoadFITS)
 
+const std::string LoadFITS::m_BIT_DEPTH_NAME = "BitDepthName";
+const std::string LoadFITS::m_ROTATION_NAME = "RotationName";
+const std::string LoadFITS::m_AXIS_NAMES_NAME = "AxisNames";
+const std::string LoadFITS::m_IMAGE_KEY_NAME = "ImageKeyName";
+const std::string LoadFITS::m_HEADER_MAP_NAME = "HeaderMapFile";
+
+const std::string LoadFITS::m_defaultImgType = "SAMPLE";
+
 /**
  * Constructor. Just initialize everything to prevent issues.
  */
-LoadFITS::LoadFITS(): m_headerScaleKey(), m_headerOffsetKey(),
-                      m_headerBitDepthKey(), m_headerRotationKey(),
-                      m_headerImageKeyKey(), m_mapFile(),
-                      m_headerAxisNameKeys(),  m_baseName(),
-                      m_spectraCount(0), m_progress(NULL) {
+LoadFITS::LoadFITS()
+    : m_headerScaleKey(), m_headerOffsetKey(), m_headerBitDepthKey(),
+      m_headerRotationKey(), m_headerImageKeyKey(), m_headerAxisNameKeys(),
+      m_mapFile(), m_baseName(), m_spectraCount(0), m_progress(NULL) {
+  setupDefaultKeywordNames();
 }
 
 /**
@@ -64,6 +56,31 @@ int LoadFITS::confidence(Kernel::FileDescriptor &descriptor) const {
              : 0;
 }
 
+/**
+ * Sets several keyword names with default (and standard) values. You
+ * don't want to change these unless you want to break compatibility
+ * with the FITS standard.
+ */
+void LoadFITS::setupDefaultKeywordNames() {
+  // Inits all the absolutely necessary keywords
+  // standard headers (If SIMPLE=T)
+  m_headerScaleKey = "BSCALE";
+  m_headerOffsetKey = "BZERO";
+  m_headerBitDepthKey = "BITPIX";
+  m_headerImageKeyKey = "IMAGE_TYPE"; // This is a "HIERARCH Image/Type= "
+  m_headerRotationKey = "ROTATION";
+
+  m_headerNAxisNameKey = "NAXIS";
+  m_headerAxisNameKeys.push_back("NAXIS1");
+  m_headerAxisNameKeys.push_back("NAXIS2");
+
+  m_mapFile = "";
+
+  // extensions
+  m_sampleRotation = "HIERARCH Sample/Tomo_Angle";
+  m_imageType = "HIERARCH Image/Type";
+}
+
 /**
 * Initialise the algorithm. Declare properties which can be set before execution
 * (input) or
@@ -82,308 +99,325 @@ void LoadFITS::init() {
   exts2.push_back(".*");
 
   declareProperty(new MultipleFileProperty("Filename", exts),
-                  "The input filename of the stored data");
+                  "The name of the input file (you can give "
+                  "multiple file names separated by commas).");
 
   declareProperty(new API::WorkspaceProperty<API::Workspace>(
       "OutputWorkspace", "", Kernel::Direction::Output));
 
   declareProperty(
-      new PropertyWithValue<int>("ImageKey", 0, Kernel::Direction::Input),
-      "Image type to set these files as. 0=data image, 1=flat field, 2=open "
-      "field, -1=use the value from FITS header. At present, if this is not "
-      "specified and an IMAGEKEY entry is not found in the FITS header, the "
-      "loader will show an error message and stop.");
-
-  declareProperty(new PropertyWithValue<string>(BIT_DEPTH_NAME, "BITPIX",
-                                                Kernel::Direction::Input),
-                  "Name for the pixel bit depth header key.");
-  declareProperty(new PropertyWithValue<string>(ROTATION_NAME, "ROTATION",
-                                                Kernel::Direction::Input),
-                  "Name for the rotation header key.");
-  declareProperty(
-      new PropertyWithValue<string>(AXIS_NAMES_NAME, "NAXIS1,NAXIS2",
-                                    Kernel::Direction::Input),
-      "Names for the axis header keys, comma separated string of all axis.");
-  declareProperty(new PropertyWithValue<string>(IMAGE_KEY_NAME, "IMAGEKEY",
-                                                Kernel::Direction::Input),
-                  "Names for the image type, key.");
-
-  declareProperty(
-      new FileProperty(HEADER_MAP_NAME, "", FileProperty::OptionalDirectory, "",
-                       Kernel::Direction::Input),
-      "A file mapping header keys to the ones used by ISIS [line separated "
-      "values in the format KEY=VALUE, e.g. BitDepthName=BITPIX ");
+      new FileProperty(m_HEADER_MAP_NAME, "", FileProperty::OptionalDirectory,
+                       "", Kernel::Direction::Input),
+      "A file mapping header key names to non-standard names [line separated "
+      "values in the format KEY=VALUE, e.g. BitDepthName=BITPIX] - do not use "
+      "this if you want to keep compatibility with standard FITS files.");
 }
 
 /**
-* Execute the algorithm.
-*/
+ * Execute the algorithm.
+ */
 void LoadFITS::exec() {
-  // Init header info - setup some defaults just in case
-  m_headerScaleKey = "BSCALE";
-  m_headerOffsetKey = "BZERO";
-  m_headerBitDepthKey = "BITPIX";
-  m_headerImageKeyKey = "IMAGEKEY";
-  m_headerRotationKey = "ROTATION";
-  m_mapFile = "";
-  m_headerAxisNameKeys.push_back("NAXIS1");
-  m_headerAxisNameKeys.push_back("NAXIS2");
-
+  // for non-standard headers, by default won't do anything
   mapHeaderKeys();
 
-  // Create FITS file information for each file selected
-  std::vector<std::string> paths;
   string fName = getPropertyValue("Filename");
-  boost::split(paths, fName, boost::is_any_of(","));
 
-  // If paths contains a non fits file, assume (for now) that it contains
-  // information about the rotations
-  std::string rotFilePath = "";
-  std::vector<std::string>::iterator it =
-      std::find_if(paths.begin(), paths.end(), IsNotFits);
-  if (it != paths.end()) {
-    rotFilePath = *it;
-    paths.erase(it);
-  }
-  vector<FITSInfo> allHeaderInfo;
-  allHeaderInfo.resize(paths.size());
-
-  // Check each header is valid for this loader, - standard (no extension to
-  // FITS), and has two axis
-  bool headerValid = true;
+  std::vector<std::string> paths;
+  boost::split(paths, fName, boost::is_any_of(","));
+  doLoadFiles(paths);
+}
 
-  for (size_t i = 0; i < paths.size(); ++i) {
-    allHeaderInfo[i].extension = "";
-    allHeaderInfo[i].filePath = paths[i];
-    // Get various pieces of information from the file header which are used to
-    // create the workspace
-    if (parseHeader(allHeaderInfo[i])) {
-      // Get and convert specific standard header values which will help when
-      // parsing the data
-      // BITPIX, NAXIS, NAXISi (where i = 1..NAXIS, e.g. NAXIS2 for two axis),
-      // TOF, TIMEBIN, N_COUNTS, N_TRIGS
-      try {
-        string tmpBitPix = allHeaderInfo[i].headerKeys[m_headerBitDepthKey];
-        if (boost::contains(tmpBitPix, "-")) {
-          boost::erase_all(tmpBitPix, "-");
-          allHeaderInfo[i].isFloat = true;
-        } else {
-          allHeaderInfo[i].isFloat = false;
-        }
+/**
+ * Create FITS file information for each file selected. Loads headers
+ * and data from the files and fills the output workspace(s).
+ *
+ * @param paths File names as given in the algorithm input property
+ */
+void LoadFITS::doLoadFiles(const std::vector<std::string> &paths) {
+  std::vector<FITSInfo> headers;
 
-        // Add the image key, use the property if it's not -1, otherwise use the
-        // header value
-        allHeaderInfo[i].imageKey =
-            boost::lexical_cast<int>(getPropertyValue("ImageKey"));
-        if (allHeaderInfo[i].imageKey == -1) {
-          allHeaderInfo[i].imageKey = boost::lexical_cast<int>(
-              allHeaderInfo[i].headerKeys[m_headerImageKeyKey]);
-        }
+  doLoadHeaders(paths, headers);
 
-        allHeaderInfo[i].bitsPerPixel = lexical_cast<int>(tmpBitPix);
-        allHeaderInfo[i].numberOfAxis =
-            static_cast<int>(m_headerAxisNameKeys.size());
+  // No extension is set -> it's the standard format which we can parse.
+  if (headers[0].numberOfAxis > 0)
+    m_spectraCount += headers[0].axisPixelLengths[0];
 
-        for (int j = 0;
-             allHeaderInfo.size() > i && j < allHeaderInfo[i].numberOfAxis;
-             ++j) {
-          allHeaderInfo[i].axisPixelLengths.push_back(lexical_cast<size_t>(
-              allHeaderInfo[i].headerKeys[m_headerAxisNameKeys[j]]));
-        }
+  // Presumably 2 axis, but futureproofing.
+  for (int i = 1; i < headers[0].numberOfAxis; ++i) {
+    m_spectraCount *= headers[0].axisPixelLengths[i];
+  }
 
-        // m_allHeaderInfo[i].tof =
-        // lexical_cast<double>(m_allHeaderInfo[i].headerKeys["TOF"]);
-        // m_allHeaderInfo[i].timeBin =
-        // lexical_cast<double>(m_allHeaderInfo[i].headerKeys["TIMEBIN"]);
-        // m_allHeaderInfo[i].countsInImage = lexical_cast<long
-        // int>(m_allHeaderInfo[i].headerKeys["N_COUNTS"]);
-        // m_allHeaderInfo[i].numberOfTriggers = lexical_cast<long
-        // int>(m_allHeaderInfo[i].headerKeys["N_TRIGS"]);
-        allHeaderInfo[i].extension =
-            allHeaderInfo[i].headerKeys["XTENSION"]; // Various extensions are
-                                                     // available to the FITS
-                                                     // format, and must be
-                                                     // parsed differently if
-                                                     // this is present. Loader
-                                                     // doesn't support this.
-
-      } catch (std::exception &) {
-        // todo write error and fail this load with invalid data in file.
-        throw std::runtime_error("Unable to locate one or more valid BITPIX, "
-                                 "NAXIS or IMAGEKEY values in the FITS file "
-                                 "header.");
-      }
+  MantidImage imageY(headers[0].axisPixelLengths[0],
+                     vector<double>(headers[0].axisPixelLengths[1]));
+  MantidImage imageE(headers[0].axisPixelLengths[0],
+                     vector<double>(headers[0].axisPixelLengths[1]));
 
-      allHeaderInfo[i].scale =
-          (allHeaderInfo[i].headerKeys[m_headerScaleKey] == "")
-              ? 1
-              : lexical_cast<double>(
-                    allHeaderInfo[i].headerKeys[m_headerScaleKey]);
-      allHeaderInfo[i].offset =
-          (allHeaderInfo[i].headerKeys[m_headerOffsetKey] == "")
-              ? 0
-              : lexical_cast<int>(
-                    allHeaderInfo[i].headerKeys[m_headerOffsetKey]);
-
-      if (allHeaderInfo[i].extension != "")
-        headerValid = false;
-      if (allHeaderInfo[i].numberOfAxis != 2)
-        headerValid = false;
-
-      // Test current item has same axis values as first item.
-      if (allHeaderInfo[0].axisPixelLengths[0] !=
-          allHeaderInfo[i].axisPixelLengths[0])
-        headerValid = false;
-      if (allHeaderInfo[0].axisPixelLengths[1] !=
-          allHeaderInfo[i].axisPixelLengths[1])
-        headerValid = false;
-    } else {
-      // Unable to parse the header, throw.
-      throw std::runtime_error("Unable to open the FITS file.");
-    }
+  size_t bytes = (headers[0].bitsPerPixel / 8) * m_spectraCount;
+  std::vector<char> buffer;
+  try {
+    buffer.resize(bytes);
+  } catch (std::exception &) {
+    throw std::runtime_error(
+        "Could not allocate enough memory to run when trying to allocate " +
+        boost::lexical_cast<std::string>(bytes) + " bytes.");
   }
 
-  // Check that the files use bit depths of either 8, 16 or 32
-  if (allHeaderInfo[0].bitsPerPixel != 8 &&
-      allHeaderInfo[0].bitsPerPixel != 16 &&
-      allHeaderInfo[0].bitsPerPixel != 32 &&
-      allHeaderInfo[0].bitsPerPixel != 64)
-    throw std::runtime_error(
-        "FITS loader only supports 8, 16, 32 or 64 bits per pixel.");
+  // Create a group for these new workspaces, if the group already exists, add
+  // to it.
+  string groupName = getPropertyValue("OutputWorkspace");
 
-  // Check the format is correct and create the Workspace
-  if (headerValid) {
-    // No extension is set, therefore it's the standard format which we can
-    // parse.
+  // This forms the name of the group
+  m_baseName = getPropertyValue("OutputWorkspace") + "_";
 
-    if (allHeaderInfo[0].numberOfAxis > 0)
-      m_spectraCount += allHeaderInfo[0].axisPixelLengths[0];
+  size_t fileNumberInGroup = 0;
+  WorkspaceGroup_sptr wsGroup;
 
-    // Presumably 2 axis, but futureproofing.
-    for (int i = 1; i < allHeaderInfo[0].numberOfAxis; ++i) {
-      m_spectraCount *= allHeaderInfo[0].axisPixelLengths[i];
-    }
+  if (!AnalysisDataService::Instance().doesExist(groupName)) {
+    wsGroup = WorkspaceGroup_sptr(new WorkspaceGroup);
+    wsGroup->setTitle(groupName);
+  } else {
+    // Get the name of the latest file in group to start numbering from
+    if (AnalysisDataService::Instance().doesExist(groupName))
+      wsGroup =
+          AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(groupName);
+
+    std::string latestName = wsGroup->getNames().back();
+    // Set next file number
+    fileNumberInGroup = fetchNumber(latestName) + 1;
+  }
 
-    MantidImage imageY(allHeaderInfo[0].axisPixelLengths[0],
-                       vector<double>(allHeaderInfo[0].axisPixelLengths[1]));
-    MantidImage imageE(allHeaderInfo[0].axisPixelLengths[0],
-                       vector<double>(allHeaderInfo[0].axisPixelLengths[1]));
-    ;
+  // Create a progress reporting object
+  m_progress = new Progress(this, 0, 1, headers.size() + 1);
 
-    void *bufferAny = NULL;
-    bufferAny = malloc((allHeaderInfo[0].bitsPerPixel / 8) * m_spectraCount);
-    if (bufferAny == NULL) {
-      throw std::runtime_error(
-          "FITS loader couldn't allocate enough memory to run.");
-    }
+  // Create first workspace (with instrument definition). This is also used as
+  // a template for creating others
+  Workspace2D_sptr latestWS;
+  latestWS = makeWorkspace(headers[0], fileNumberInGroup, buffer, imageY,
+                           imageE, latestWS);
 
-    // Set info in WS log to hold rotational information
-    vector<double> rotations;
-    if (rotFilePath != "")
-      rotations = readRotations(rotFilePath, paths.size());
+  map<size_t, Workspace2D_sptr> wsOrdered;
+  wsOrdered[0] = latestWS;
+  try {
+    IAlgorithm_sptr loadInst = createChildAlgorithm("LoadInstrument");
+    std::string directoryName =
+        Kernel::ConfigService::Instance().getInstrumentDirectory();
+    directoryName = directoryName + "/IMAT_Definition.xml";
+    loadInst->setPropertyValue("Filename", directoryName);
+    loadInst->setProperty<MatrixWorkspace_sptr>(
+        "Workspace", dynamic_pointer_cast<MatrixWorkspace>(latestWS));
+    loadInst->execute();
+  } catch (std::exception &ex) {
+    g_log.information("Cannot load the instrument definition. " +
+                      string(ex.what()));
+  }
 
-    // Create a group for these new workspaces, if the group already exists, add
-    // to it.
-    string groupName = getPropertyValue("OutputWorkspace");
+  PARALLEL_FOR_NO_WSP_CHECK()
+  for (int64_t i = 1; i < static_cast<int64_t>(headers.size()); ++i) {
+    latestWS = makeWorkspace(headers[i], fileNumberInGroup, buffer, imageY,
+                             imageE, latestWS);
+    wsOrdered[i] = latestWS;
+  }
 
-    // This forms the name of the group
-    m_baseName = getPropertyValue("OutputWorkspace") + "_";
+  // Add to group - done here to maintain sequence
+  for (auto it = wsOrdered.begin(); it != wsOrdered.end(); ++it) {
+    wsGroup->addWorkspace(it->second);
+  }
 
-    size_t fileNumberInGroup = 0;
-    WorkspaceGroup_sptr wsGroup;
+  setProperty("OutputWorkspace", wsGroup);
+}
 
-    if (!AnalysisDataService::Instance().doesExist(groupName)) {
-      wsGroup = WorkspaceGroup_sptr(new WorkspaceGroup);
-      wsGroup->setTitle(groupName);
-    } else {
-      // Get the name of the latest file in group to start numbering from
-      if (AnalysisDataService::Instance().doesExist(groupName))
-        wsGroup = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(
-            groupName);
-
-      std::string latestName = wsGroup->getNames().back();
-      // Set next file number
-      fileNumberInGroup = fetchNumber(latestName) + 1;
-    }
+/**
+ * Load header(s) from FITS file(s) into FITSInfo header
+ * struct(s). This is usually the first step when loading FITS files
+ * into workspaces or anything else. In the simplest case, paths has
+ * only one string and only one header struct is added in headers.
+ *
+ * @param paths File name(s)
+ * @param headers Vector where to store the header struct(s)
+ *
+ * @throws std::runtime_error if issues are found in the headers
+ */
+void LoadFITS::doLoadHeaders(const std::vector<std::string> &paths,
+                             std::vector<FITSInfo> &headers) {
+  headers.resize(paths.size());
 
-    // Create a progress reporting object
-    m_progress = new Progress(this, 0, 1, allHeaderInfo.size() + 1);
+  for (size_t i = 0; i < paths.size(); ++i) {
+    headers[i].extension = "";
+    headers[i].filePath = paths[i];
+    // Get various pieces of information from the file header which are used to
+    // create the workspace
+    try {
+      parseHeader(headers[i]);
+    } catch (std::exception &e) {
+      // Unable to parse the header, throw.
+      throw std::runtime_error(
+          "Severe problem found while parsing the header of "
+          "this FITS file (" +
+          paths[i] +
+          "). This file may not be standard FITS. Error description: " +
+          e.what());
+    }
 
-    // Create First workspace with instrument definition, also used as a
-    // template for creating others
-    Workspace2D_sptr latestWS;
-    double rot = (rotations.size() > 0) ? rotations[0] : -1;
-    map<size_t, Workspace2D_sptr> wsOrdered;
+    // Get and convert specific standard header values which will are
+    // needed to know how to load the data: BITPIX, NAXIS, NAXISi (where i =
+    // 1..NAXIS, e.g. NAXIS2 for two axis).
+    try {
+      string tmpBitPix = headers[i].headerKeys[m_headerBitDepthKey];
+      if (boost::contains(tmpBitPix, "-")) {
+        boost::erase_all(tmpBitPix, "-");
+        headers[i].isFloat = true;
+      } else {
+        headers[i].isFloat = false;
+      }
 
-    latestWS = addWorkspace(allHeaderInfo[0], fileNumberInGroup, bufferAny,
-                            imageY, imageE, rot, latestWS);
-    wsOrdered[0] = latestWS;
+      headers[i].bitsPerPixel = lexical_cast<int>(tmpBitPix);
+      // Check that the files use bit depths of either 8, 16 or 32
+      if (headers[i].bitsPerPixel != 8 && headers[i].bitsPerPixel != 16 &&
+          headers[i].bitsPerPixel != 32 && headers[i].bitsPerPixel != 64)
+        throw std::runtime_error(
+            "This algorithm only supports 8, 16, 32 or 64 "
+            "bits per pixel. The header of file '" +
+            paths[i] + "' says that its bit depth is: " +
+            boost::lexical_cast<std::string>(headers[i].bitsPerPixel));
+    } catch (std::exception &e) {
+      throw std::runtime_error(
+          "Failed to process the '" + m_headerBitDepthKey +
+          "' entry (bits per pixel) in the header of this file: " + paths[i] +
+          ". Error description: " + e.what());
+    }
 
     try {
-      IAlgorithm_sptr loadInst = createChildAlgorithm("LoadInstrument");
-      std::string directoryName =
-          Kernel::ConfigService::Instance().getInstrumentDirectory();
-      directoryName = directoryName + "/IMAT_Definition.xml";
-      loadInst->setPropertyValue("Filename", directoryName);
-      loadInst->setProperty<MatrixWorkspace_sptr>(
-          "Workspace", dynamic_pointer_cast<MatrixWorkspace>(latestWS));
-      loadInst->execute();
-    } catch (std::exception &ex) {
-      g_log.information("Cannot load the instrument definition. " +
-                        string(ex.what()));
+      // Add the image key, use the value in the FITS header if found,
+      // otherwise default (to SAMPLE).
+      auto it = headers[i].headerKeys.find(m_headerImageKeyKey);
+      if (headers[i].headerKeys.end() != it) {
+        headers[i].imageKey = it->second;
+      } else {
+        headers[i].imageKey = m_defaultImgType;
+      }
+    } catch (std::exception &e) {
+      throw std::runtime_error("Failed to process the '" + m_headerImageKeyKey +
+                               "' entry (type of image: sample, dark, open) in "
+                               "the header of this file: " +
+                               paths[i] + ". Error description: " + e.what());
     }
 
-    PARALLEL_FOR_NO_WSP_CHECK()
-    for (int64_t i = 1; i < static_cast<int64_t>(allHeaderInfo.size()); ++i) {
-      double rot =
-          (static_cast<int64_t>(rotations.size()) > i) ? rotations[i] : -1;
-      latestWS = addWorkspace(allHeaderInfo[i], fileNumberInGroup, bufferAny,
-                              imageY, imageE, rot, latestWS);
-      wsOrdered[i] = latestWS;
-    }
+    try {
+      headers[i].numberOfAxis = static_cast<int>(m_headerAxisNameKeys.size());
+
+      for (int j = 0; headers.size() > i && j < headers[i].numberOfAxis; ++j) {
+        headers[i].axisPixelLengths.push_back(lexical_cast<size_t>(
+            headers[i].headerKeys[m_headerAxisNameKeys[j]]));
+      }
 
-    // Add to group - Done here to maintain order
-    for (auto it = wsOrdered.begin(); it != wsOrdered.end(); ++it) {
-      wsGroup->addWorkspace(it->second);
+      // Various extensions to the FITS format are used elsewhere, and
+      // must be parsed differently if used. This loader Loader
+      // doesn't support this.
+      headers[i].extension = headers[i].headerKeys["XTENSION"];
+    } catch (std::exception &e) {
+      throw std::runtime_error(
+          "Failed to process the '" + m_headerNAxisNameKey +
+          "' entries (dimensions) in the header of this file: " + paths[i] +
+          ". Error description: " + e.what());
     }
 
-    free(bufferAny);
+    headers[i].scale =
+        (headers[i].headerKeys[m_headerScaleKey] == "")
+            ? 1
+            : lexical_cast<double>(headers[i].headerKeys[m_headerScaleKey]);
+    headers[i].offset =
+        (headers[i].headerKeys[m_headerOffsetKey] == "")
+            ? 0
+            : lexical_cast<int>(headers[i].headerKeys[m_headerOffsetKey]);
+
+    // Check each header is valid/supported: standard (no extension to
+    // FITS), and has two axis
+    headerSanityCheck(headers[i], headers[0]);
+  }
+}
 
-    setProperty("OutputWorkspace", wsGroup);
-  } else {
-    // Invalid files, record error
-    throw std::runtime_error("Loader currently doesn't support FITS files with "
-                             "non-standard extensions, greater than two axis "
-                             "of data, or has detected that all the files are "
-                             "not similar.");
+/**
+ * Read a single files header and populate an object with the information.
+ *
+ * @param headerInfo A FITSInfo file object to parse header
+ * information into. This object must have its field filePath set to
+ * the input file
+ *
+ * @throws various std::runtime_error etc. on read failure
+*/
+void LoadFITS::parseHeader(FITSInfo &headerInfo) {
+  headerInfo.headerSizeMultiplier = 0;
+  ifstream istr(headerInfo.filePath.c_str(), ios::binary);
+  Poco::BinaryReader reader(istr);
+
+  // Iterate 80 bytes at a time until header is parsed | 2880 bytes is the
+  // fixed header length of FITS
+  // 2880/80 = 36 iterations required
+  bool endFound = false;
+  while (!endFound) {
+    headerInfo.headerSizeMultiplier++;
+    for (int i = 0; i < 36; ++i) {
+      // Keep vect of each header item, including comments, and also keep a
+      // map of individual keys.
+      string part;
+      reader.readRaw(80, part);
+      headerInfo.headerItems.push_back(part);
+
+      // Add key/values - these are separated by the = symbol.
+      // If it doesn't have an = it's a comment to ignore. All keys should be
+      // unique
+      auto eqPos = part.find('=');
+      if (eqPos > 0) {
+        string key = part.substr(0, eqPos);
+        string value = part.substr(eqPos + 1);
+
+        // Comments are added after the value separated by a / symbol. Remove.
+        auto slashPos = value.find('/');
+        if (slashPos > 0)
+          value = value.substr(0, slashPos);
+
+        boost::trim(key);
+        boost::trim(value);
+
+        if (key == "END")
+          endFound = true;
+
+        if (key != "")
+          headerInfo.headerKeys[key] = value;
+      }
+    }
   }
+
+  istr.close();
 }
 
 /**
- * Initialises a workspace with IDF and fills it with data
+ * Creates and initialises a workspace with instrument definition and fills it
+ * with data
+ *
  * @param fileInfo information for the current file
  * @param newFileNumber number for the new file when added into ws group
- * @param bufferAny Presized buffer to contain data values
+ * @param buffer pre-allocated buffer to contain data values
  * @param imageY Object to set the Y data values in
  * @param imageE Object to set the E data values in
- * @param rotation Value for the rotation of the current file
  * @param parent A workspace which can be used to copy initialisation
  * information from (size/instrument def etc)
- * @returns A pointer to the workspace created
+ *
+ * @returns A newly created Workspace2D, as a shared pointer
  */
-Workspace2D_sptr LoadFITS::addWorkspace(const FITSInfo &fileInfo,
-                                        size_t &newFileNumber, void *&bufferAny,
-                                        MantidImage &imageY,
-                                        MantidImage &imageE, double rotation,
-                                        const Workspace2D_sptr parent) {
+Workspace2D_sptr
+LoadFITS::makeWorkspace(const FITSInfo &fileInfo, size_t &newFileNumber,
+                        std::vector<char> &buffer, MantidImage &imageY,
+                        MantidImage &imageE, const Workspace2D_sptr parent) {
   // Create ws
   Workspace2D_sptr ws;
-  if (!parent)
+  if (!parent) {
     ws = dynamic_pointer_cast<Workspace2D>(WorkspaceFactory::Instance().create(
         "Workspace2D", m_spectraCount, 2, 1));
-  else
+  } else {
     ws = dynamic_pointer_cast<Workspace2D>(
         WorkspaceFactory::Instance().create(parent));
+  }
 
   string currNumberS = padZeros(newFileNumber, DIGIT_SIZE_APPEND);
   ++newFileNumber;
@@ -393,21 +427,26 @@ Workspace2D_sptr LoadFITS::addWorkspace(const FITSInfo &fileInfo,
   ws->setTitle(baseName);
 
   // set data
-  readFileToWorkspace(ws, fileInfo, imageY, imageE, bufferAny);
+  readDataToWorkspace2D(ws, fileInfo, imageY, imageE, buffer);
 
   // Add all header info to log.
   for (auto it = fileInfo.headerKeys.begin(); it != fileInfo.headerKeys.end();
        ++it) {
-    ws->mutableRun().removeLogData("_" + it->first, true);
+    ws->mutableRun().removeLogData(it->first, true);
     ws->mutableRun().addLogData(
-        new PropertyWithValue<string>("_" + it->first, it->second));
+        new PropertyWithValue<string>(it->first, it->second));
   }
 
   // Add rotational data to log. Clear first from copied WS
+  auto it = fileInfo.headerKeys.find(m_sampleRotation);
   ws->mutableRun().removeLogData("Rotation", true);
-  if (rotation != -1)
-    ws->mutableRun().addLogData(
-        new PropertyWithValue<double>("Rotation", rotation));
+  if (fileInfo.headerKeys.end() != it) {
+    double rot = boost::lexical_cast<double>(it->second);
+    if (rot >= 0) {
+      ws->mutableRun().addLogData(
+          new PropertyWithValue<double>("Rotation", rot));
+    }
+  }
 
   // Add axis information to log. Clear first from copied WS
   ws->mutableRun().removeLogData("Axis1", true);
@@ -419,8 +458,8 @@ Workspace2D_sptr LoadFITS::addWorkspace(const FITSInfo &fileInfo,
 
   // Add image key data to log. Clear first from copied WS
   ws->mutableRun().removeLogData("ImageKey", true);
-  ws->mutableRun().addLogData(new PropertyWithValue<int>(
-      "ImageKey", static_cast<int>(fileInfo.imageKey)));
+  ws->mutableRun().addLogData(
+      new PropertyWithValue<std::string>("ImageKey", fileInfo.imageKey));
 
   m_progress->report();
 
@@ -428,84 +467,58 @@ Workspace2D_sptr LoadFITS::addWorkspace(const FITSInfo &fileInfo,
 }
 
 /**
- * Returns the trailing number from a string minus leading 0's (so 25 from
- * workspace_00025)the confidence with with this algorithm can load the file
- * @param name string with a numerical suffix
- * @returns A numerical representation of the string minus leading characters
- * and leading 0's
- */
-size_t LoadFITS::fetchNumber(std::string name) {
-  string tmpStr = "";
-  for (auto it = name.end() - 1; isdigit(*it); --it) {
-    tmpStr.insert(0, 1, *it);
-  }
-  while (tmpStr.length() > 0 && tmpStr[0] == '0') {
-    tmpStr.erase(tmpStr.begin());
-  }
-  return (tmpStr.length() > 0) ? lexical_cast<size_t>(tmpStr) : 0;
-}
-
-// Adds 0's to the front of a number to create a string of size totalDigitCount
-// including number
-std::string LoadFITS::padZeros(size_t number, size_t totalDigitCount) {
-  std::ostringstream ss;
-  ss << std::setw(static_cast<int>(totalDigitCount)) << std::setfill('0')
-     << static_cast<int>(number);
-
-  return ss.str();
-}
-
-/**
- * Reads the data from a single FITS file into a workspace
+ * Reads the data (matrix) from a single FITS file into a workspace
+ *
  * @param ws Workspace to populate with the data
  * @param fileInfo information pertaining to the FITS file to load
  * @param imageY Object to set the Y data values in
  * @param imageE Object to set the E data values in
- * @param bufferAny Presized buffer to contain data values
+ * @param buffer pre-allocated buffer to contain data values
+ *
+ * @throws std::runtime_error if there are file input issues
  */
-void LoadFITS::readFileToWorkspace(Workspace2D_sptr ws,
-                                   const FITSInfo &fileInfo,
-                                   MantidImage &imageY, MantidImage &imageE,
-                                   void *&bufferAny) {
-  uint8_t *buffer8 = NULL;
-
-  // create pointer of correct data type to void pointer of the buffer:
-  buffer8 = static_cast<uint8_t *>(bufferAny);
-
-  // Read Data
-  bool fileErr = false;
-  FILE *currFile = fopen(fileInfo.filePath.c_str(), "rb");
-  if (currFile == NULL)
-    fileErr = true;
-
-  size_t result = 0;
-  if (!fileErr) {
-    if (fseek(currFile, BASE_HEADER_SIZE * fileInfo.headerSizeMultiplier,
-              SEEK_CUR) == 0)
-      result = fread(buffer8, 1, m_spectraCount * (fileInfo.bitsPerPixel / 8),
-                     currFile);
+void LoadFITS::readDataToWorkspace2D(Workspace2D_sptr ws,
+                                     const FITSInfo &fileInfo,
+                                     MantidImage &imageY, MantidImage &imageE,
+                                     std::vector<char> &buffer) {
+  std::string filename = fileInfo.filePath;
+  Poco::FileStream file(filename, std::ios::in);
+
+  size_t bytespp = (fileInfo.bitsPerPixel / 8);
+  size_t len = m_spectraCount * bytespp;
+  file.seekg(BASE_HEADER_SIZE * fileInfo.headerSizeMultiplier);
+  file.read(&buffer[0], len);
+  if (!file) {
+    throw std::runtime_error(
+        "Error while reading file: " + filename + ". Tried to read " +
+        boost::lexical_cast<std::string>(len) + " bytes but got " +
+        boost::lexical_cast<std::string>(file.gcount()) +
+        " bytes. The file and/or its headers may be wrong.");
   }
+  // all is loaded
+  file.close();
 
-  if (result != m_spectraCount * (fileInfo.bitsPerPixel / 8))
-    fileErr = true;
-
-  if (fileErr)
-    throw std::runtime_error("Error reading file; possibly invalid data.");
-
-  std::vector<char> buf(fileInfo.bitsPerPixel / 8);
-  char* tmp = &buf.front();
+  // create pointer of correct data type to void pointer of the buffer:
+  uint8_t *buffer8 = reinterpret_cast<uint8_t *>(&buffer[0]);
 
+  std::vector<char> buf(bytespp);
+  char *tmp = &buf.front();
+  size_t start = 0;
   for (size_t i = 0; i < fileInfo.axisPixelLengths[0]; ++i) {
     for (size_t j = 0; j < fileInfo.axisPixelLengths[1]; ++j) {
-      double val = 0;
-      size_t start =
-          ((i * (fileInfo.bitsPerPixel / 8)) * fileInfo.axisPixelLengths[1]) +
-          (j * (fileInfo.bitsPerPixel / 8));
+      // If you wanted to PARALLEL_...ize these loops (which doesn't
+      // seem to provide any speed up, you cannot use the
+      // start+=bytespp at the end of this loop. You'd need something
+      // like this:
+      //
+      // size_t start =
+      //   ((i * (bytespp)) * fileInfo.axisPixelLengths[1]) +
+      //  (j * (bytespp));
 
       // Reverse byte order of current value
-      std::reverse_copy(buffer8 + start,
-                        buffer8 + start + (fileInfo.bitsPerPixel / 8), tmp);
+      std::reverse_copy(buffer8 + start, buffer8 + start + bytespp, tmp);
 
+      double val = 0;
       if (fileInfo.bitsPerPixel == 8)
         val = static_cast<double>(*reinterpret_cast<uint8_t *>(tmp));
       if (fileInfo.bitsPerPixel == 16)
@@ -529,187 +542,160 @@ void LoadFITS::readFileToWorkspace(Workspace2D_sptr ws,
 
       imageY[i][j] = val;
       imageE[i][j] = sqrt(val);
+
+      start += bytespp;
     }
   }
 
   // Set in WS
   ws->setImageYAndE(imageY, imageE, 0, false);
-
-  // Clear memory associated with the file load
-  fclose(currFile);
 }
 
 /**
-* Read a single files header and populate an object with the information
-* @param headerInfo A FITSInfo file object to parse header information into
-* @returns A bool specifying succes of the operation
-*/
-bool LoadFITS::parseHeader(FITSInfo &headerInfo) {
-  bool ranSuccessfully = true;
-  headerInfo.headerSizeMultiplier = 0;
-  try {
-    ifstream istr(headerInfo.filePath.c_str(), ios::binary);
-    Poco::BinaryReader reader(istr);
-
-    // Iterate 80 bytes at a time until header is parsed | 2880 bytes is the
-    // fixed header length of FITS
-    // 2880/80 = 36 iterations required
-    bool endFound = false;
-    while (!endFound) {
-      headerInfo.headerSizeMultiplier++;
-      for (int i = 0; i < 36; ++i) {
-        // Keep vect of each header item, including comments, and also keep a
-        // map of individual keys.
-        string part;
-        reader.readRaw(80, part);
-        headerInfo.headerItems.push_back(part);
-
-        // Add key/values - these are separated by the = symbol.
-        // If it doesn't have an = it's a comment to ignore. All keys should be
-        // unique
-        auto eqPos = part.find('=');
-        if (eqPos > 0) {
-          string key = part.substr(0, eqPos);
-          string value = part.substr(eqPos + 1);
-
-          // Comments are added after the value separated by a / symbol. Remove.
-          auto slashPos = value.find('/');
-          if (slashPos > 0)
-            value = value.substr(0, slashPos);
-
-          boost::trim(key);
-          boost::trim(value);
-
-          if (key == "END")
-            endFound = true;
-
-          if (key != "")
-            headerInfo.headerKeys[key] = value;
-        }
-      }
-    }
+ * Checks that a FITS header (once loaded) is valid/supported:
+ * standard (no extension to FITS), and has two axis with the expected
+ * dimensions.
+ *
+ * @param hdr FITS header struct loaded from a file - to check
+ *
+ * @param hdr FITS header struct loaded from a (first) reference file - to
+ * compare against
+ *
+ * @throws std::exception if there's any issue or unsupported entry in the
+ * header
+ */
+void LoadFITS::headerSanityCheck(const FITSInfo &hdr,
+                                 const FITSInfo &hdrFirst) {
+  bool valid = true;
+  if (hdr.extension != "") {
+    valid = false;
+    g_log.error() << "File " << hdr.filePath
+                  << ": extensions found in the header." << std::endl;
+  }
+  if (hdr.numberOfAxis != 2) {
+    valid = false;
+    g_log.error() << "File " << hdr.filePath
+                  << ": the number of axes is not 2 but: " << hdr.numberOfAxis
+                  << std::endl;
+  }
 
-    istr.close();
-  } catch (...) {
-    // Unable to read the file
-    ranSuccessfully = false;
+  // Test current item has same axis values as first item.
+  if (hdr.axisPixelLengths[0] != hdrFirst.axisPixelLengths[0]) {
+    valid = false;
+    g_log.error() << "File " << hdr.filePath
+                  << ": the number of pixels in the first dimension differs "
+                     "from the first file loaded (" << hdrFirst.filePath
+                  << "): " << hdr.axisPixelLengths[0]
+                  << " != " << hdrFirst.axisPixelLengths[0] << std::endl;
+  }
+  if (hdr.axisPixelLengths[1] != hdrFirst.axisPixelLengths[1]) {
+    valid = false;
+    g_log.error() << "File " << hdr.filePath
+                  << ": the number of pixels in the second dimension differs"
+                     "from the first file loaded (" << hdrFirst.filePath
+                  << "): " << hdr.axisPixelLengths[0]
+                  << " != " << hdrFirst.axisPixelLengths[0] << std::endl;
   }
 
-  return ranSuccessfully;
+  // Check the format is correct and create the Workspace
+  if (!valid) {
+    // Invalid files, record error
+    throw std::runtime_error(
+        "An issue has been found in the header of this FITS file: " +
+        hdr.filePath +
+        ". This algorithm currently doesn't support FITS files with "
+        "non-standard extensions, more than two axis "
+        "of data, or has detected that all the files are "
+        "not similar.");
+  }
 }
 
 /**
- * Reads a file containing rotation values for each image into a vector of
- *doubles
- * @param rotFilePath The path to a file containing rotation values
- * @param fileCount number of images which should have corresponding rotation
- *values in the file
+ * Returns the trailing number from a string minus leading 0's (so 25 from
+ * workspace_00025)the confidence with with this algorithm can load the file
+ *
+ * @param name string with a numerical suffix
  *
- * @returns vector<double> A vector of all the rotation values
+ * @returns A numerical representation of the string minus leading characters
+ * and leading 0's
  */
-std::vector<double> LoadFITS::readRotations(std::string rotFilePath,
-                                            size_t fileCount) {
-  std::vector<double> allRotations;
-  ifstream fStream(rotFilePath.c_str());
-
-  try {
-    // Ensure valid file
-    if (fStream.good()) {
-      // Get lines, split words, verify and add to map.
-      string line;
-      vector<string> lineSplit;
-      size_t ind = -1;
-      while (getline(fStream, line)) {
-        ind++;
-        boost::split(lineSplit, line, boost::is_any_of("\t"));
-
-        if (ind == 0 || lineSplit[0] == "")
-          continue; // Skip first iteration or where rotation value is empty
-
-        allRotations.push_back(lexical_cast<double>(lineSplit[1]));
-      }
-
-      // Check the number of rotations in file matches number of files
-      if (ind != fileCount)
-        throw std::runtime_error("File error, throw higher up.");
-
-      fStream.close();
-    } else {
-      throw std::runtime_error("File error, throw higher up.");
-    }
-  } catch (...) {
-    throw std::runtime_error("Invalid file path or file format: Expected a "
-                             "file with a line separated list of rotations "
-                             "with the same number of entries as other files.");
+size_t LoadFITS::fetchNumber(const std::string &name) {
+  string tmpStr = "";
+  for (auto it = name.end() - 1; isdigit(*it); --it) {
+    tmpStr.insert(0, 1, *it);
+  }
+  while (tmpStr.length() > 0 && tmpStr[0] == '0') {
+    tmpStr.erase(tmpStr.begin());
   }
+  return (tmpStr.length() > 0) ? lexical_cast<size_t>(tmpStr) : 0;
+}
 
-  return allRotations;
+/**
+ * Adds 0's to the front of a number to create a string of size totalDigitCount
+ * including number
+ *
+ * @param number input number to add padding to
+ * @parm totalDigitCount width of the resulting string with 0s followed by
+ * number
+ *
+ * @return A string with the 0-padded number
+ */
+std::string LoadFITS::padZeros(const size_t number,
+                               const size_t totalDigitCount) {
+  std::ostringstream ss;
+  ss << std::setw(static_cast<int>(totalDigitCount)) << std::setfill('0')
+     << static_cast<int>(number);
+
+  return ss.str();
 }
 
 /**
  *  Maps the header keys to specified values
  */
 void LoadFITS::mapHeaderKeys() {
-  bool useProperties = true;
+  if ("" == getPropertyValue(m_HEADER_MAP_NAME))
+    return;
 
   // If a map file is selected, use that.
-  if (getPropertyValue(HEADER_MAP_NAME) != "") {
-    // std::vector<double> allRotations;
-    ifstream fStream(getPropertyValue(HEADER_MAP_NAME).c_str());
+  std::string name = getPropertyValue(m_HEADER_MAP_NAME);
+  ifstream fStream(name.c_str());
 
-    try {
-      // Ensure valid file
-      if (fStream.good()) {
-        // Get lines, split words, verify and add to map.
-        string line;
-        vector<string> lineSplit;
-        while (getline(fStream, line)) {
-          boost::split(lineSplit, line, boost::is_any_of("="));
-
-          if (lineSplit[0] == ROTATION_NAME && lineSplit[1] != "")
-            m_headerRotationKey = lineSplit[1];
-
-          if (lineSplit[0] == BIT_DEPTH_NAME && lineSplit[1] != "")
-            m_headerBitDepthKey = lineSplit[1];
-
-          if (lineSplit[0] == AXIS_NAMES_NAME && lineSplit[1] != "") {
-            m_headerAxisNameKeys.clear();
-            std::string propVal = getProperty(AXIS_NAMES_NAME);
-            boost::split(m_headerAxisNameKeys, propVal, boost::is_any_of(","));
-          }
-
-          if (lineSplit[0] == IMAGE_KEY_NAME && lineSplit[1] != "") {
-            m_headerImageKeyKey = lineSplit[1];
-          }
+  try {
+    // Ensure valid file
+    if (fStream.good()) {
+      // Get lines, split words, verify and add to map.
+      std::string line;
+      vector<std::string> lineSplit;
+      while (getline(fStream, line)) {
+        boost::split(lineSplit, line, boost::is_any_of("="));
+
+        if (lineSplit[0] == m_ROTATION_NAME && lineSplit[1] != "")
+          m_headerRotationKey = lineSplit[1];
+
+        if (lineSplit[0] == m_BIT_DEPTH_NAME && lineSplit[1] != "")
+          m_headerBitDepthKey = lineSplit[1];
+
+        if (lineSplit[0] == m_AXIS_NAMES_NAME && lineSplit[1] != "") {
+          m_headerAxisNameKeys.clear();
+          boost::split(m_headerAxisNameKeys, lineSplit[1],
+                       boost::is_any_of(","));
         }
 
-        fStream.close();
-        useProperties = false;
-      } else {
-        throw std::runtime_error("File error, throw higher up.");
+        if (lineSplit[0] == m_IMAGE_KEY_NAME && lineSplit[1] != "") {
+          m_headerImageKeyKey = lineSplit[1];
+        }
       }
-    } catch (...) {
-      g_log.information("Cannot load specified map file, using property values "
-                        "and/or defaults.");
-      useProperties = true;
-    }
-  }
 
-  if (useProperties) {
-    // Try and set from the loader properties if present and didn't load map
-    // file
-    if (getPropertyValue(BIT_DEPTH_NAME) != "")
-      m_headerBitDepthKey = getPropertyValue(BIT_DEPTH_NAME);
-    if (getPropertyValue(ROTATION_NAME) != "")
-      m_headerRotationKey = getPropertyValue(ROTATION_NAME);
-    if (getPropertyValue(AXIS_NAMES_NAME) != "") {
-      m_headerAxisNameKeys.clear();
-      std::string propVal = getProperty(AXIS_NAMES_NAME);
-      boost::split(m_headerAxisNameKeys, propVal, boost::is_any_of(","));
+      fStream.close();
+    } else {
+      throw std::runtime_error(
+          "Error while trying to read header keys mapping file: " + name);
     }
-    if (getPropertyValue(IMAGE_KEY_NAME) != "")
-      m_headerImageKeyKey = getPropertyValue(IMAGE_KEY_NAME);
+  } catch (...) {
+    g_log.error("Cannot load specified map file, using property values "
+                "and/or defaults.");
   }
 }
-}
-}
+
+} // namespace DataHandling
+} // namespace Mantid
diff --git a/Code/Mantid/Framework/DataHandling/test/LoadFITSTest.h b/Code/Mantid/Framework/DataHandling/test/LoadFITSTest.h
index 01cd6d92e88d84d328fad2818251bcfbaa42d8f0..95ff18df83794367f217b95328e8b6de93e03882 100644
--- a/Code/Mantid/Framework/DataHandling/test/LoadFITSTest.h
+++ b/Code/Mantid/Framework/DataHandling/test/LoadFITSTest.h
@@ -1,61 +1,178 @@
-#ifndef LOADFITSTEST_H_
-#define LOADFITSTEST_H_
+#ifndef MANTID_DATAHANDLING_LOADFITSTEST_H_
+#define MANTID_DATAHANDLING_LOADFITSTEST_H_
 
 #include <cxxtest/TestSuite.h>
+
+#include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidDataHandling/LoadFITS.h"
 
 using namespace Mantid::API;
 using namespace Mantid::DataHandling;
-using namespace Mantid::Kernel;
 
-class LoadFITSTest : public CxxTest::TestSuite
-{
-public: 
-  void testInit()
-  {
+class LoadFITSTest : 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 LoadFITSTest *createSuite() { return new LoadFITSTest(); }
+  static void destroySuite(LoadFITSTest *suite) { delete suite; }
+
+  void test_algorithm() {
+    std::string name = "LoadFITS";
+    int version = 1;
+    testAlg =
+        Mantid::API::AlgorithmManager::Instance().create(name /*, version*/);
+    TS_ASSERT(testAlg);
+    TS_ASSERT_EQUALS(testAlg->name(), name);
+    TS_ASSERT_EQUALS(testAlg->version(), version);
+  }
+
+  void test_castAlgorithm() {
+    // can create
+    boost::shared_ptr<LoadFITS> a;
+    TS_ASSERT(a = boost::make_shared<LoadFITS>());
+    // can cast to inherited interfaces and base classes
+
+    TS_ASSERT(dynamic_cast<Mantid::DataHandling::LoadFITS *>(a.get()));
+    TS_ASSERT(dynamic_cast<Mantid::API::Algorithm *>(a.get()));
+    TS_ASSERT(dynamic_cast<Mantid::Kernel::PropertyManagerOwner *>(a.get()));
+    TS_ASSERT(dynamic_cast<Mantid::API::IAlgorithm *>(a.get()));
+    TS_ASSERT(dynamic_cast<Mantid::Kernel::IPropertyManager *>(a.get()));
+  }
+
+  void test_initAlgorithm() {
+    LoadFITS lf;
+    TS_ASSERT_THROWS_NOTHING(lf.initialize());
+  }
+
+  void test_propertiesMissing() {
+    LoadFITS lf;
+    TS_ASSERT_THROWS_NOTHING(lf.initialize());
+    TS_ASSERT_THROWS_NOTHING(lf.setPropertyValue("Filename", smallFname1));
+    TS_ASSERT_THROWS(lf.execute(), std::runtime_error);
+    TS_ASSERT(!lf.isExecuted());
+
+    LoadFITS lf2;
+    TS_ASSERT_THROWS_NOTHING(lf2.initialize());
+    TS_ASSERT_THROWS_NOTHING(
+        lf2.setPropertyValue("OutputWorkspace", "out_ws_name"));
+    TS_ASSERT_THROWS(lf2.execute(), std::runtime_error);
+    TS_ASSERT(!lf2.isExecuted());
+  }
+
+  void test_wrongProp() {
+    LoadFITS lf;
+    TS_ASSERT_THROWS_NOTHING(lf.initialize());
+    TS_ASSERT_THROWS(lf.setPropertyValue("file", "anything"),
+                     std::runtime_error);
+    TS_ASSERT_THROWS(lf.setPropertyValue("output", "anything"),
+                     std::runtime_error);
+    TS_ASSERT_THROWS(lf.setPropertyValue("FITS", "anything"),
+                     std::runtime_error);
+
+    TS_ASSERT_THROWS(lf.setPropertyValue("ImageKey", "anything"),
+                     Mantid::Kernel::Exception::NotFoundError);
+    TS_ASSERT_THROWS(lf.setPropertyValue("BITPIX", "anything"),
+                     std::runtime_error);
+    TS_ASSERT_THROWS(lf.setPropertyValue("NAXIS", "anything"),
+                     std::runtime_error);
+    TS_ASSERT_THROWS(lf.setPropertyValue("NAXIS1", "anything"),
+                     std::runtime_error);
+  }
+
+  void test_init() {
     TS_ASSERT_THROWS_NOTHING(algToBeTested.initialize());
-    TS_ASSERT( algToBeTested.isInitialized() );
-    
-    if ( !algToBeTested.isInitialized() ) algToBeTested.initialize();
-  
-    outputSpace="LoadFITSTest";
-    algToBeTested.setPropertyValue("OutputWorkspace", outputSpace);     
-    
+    TS_ASSERT(algToBeTested.isInitialized());
+
+    if (!algToBeTested.isInitialized())
+      algToBeTested.initialize();
+
+    outputSpace = "LoadFITSTest";
+    algToBeTested.setPropertyValue("OutputWorkspace", outputSpace);
+
     // Should fail because mandatory parameter has not been set
-    TS_ASSERT_THROWS(algToBeTested.execute(),std::runtime_error);
-    
-    inputFile = "FITS_small_01.fits,FITS_small_02.fits";
-    algToBeTested.setPropertyValue("Filename", inputFile);  
-
-    // Set the ImageKey to be 0 (as it is missing from the test file and is required);
-    algToBeTested.setProperty<int>("ImageKey", 0);
-  }    
- 
-  void testPerformAssertions()
-  {
-    TS_ASSERT_THROWS_NOTHING(algToBeTested.execute());    
-    TS_ASSERT( algToBeTested.isExecuted() );
+    TS_ASSERT_THROWS(algToBeTested.execute(), std::runtime_error);
+
+    inputFile = smallFname1 + ", " + smallFname2;
+    algToBeTested.setPropertyValue("Filename", inputFile);
+
+    // Set the ImageKey to be 0 (this used to be required, but the key
+    // should not be there any longer);
+    TS_ASSERT_THROWS( algToBeTested.setProperty<int>("ImageKey", 0),
+                      Mantid::Kernel::Exception::NotFoundError);
+  }
+
+  void test_performAssertions() {
+    TS_ASSERT_THROWS_NOTHING(algToBeTested.execute());
+    TS_ASSERT(algToBeTested.isExecuted());
     //  get workspace generated
-    WorkspaceGroup_sptr output = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(outputSpace);   
-    TS_ASSERT_EQUALS( output->getNumberOfEntries(), 2);  // Number of time bins should equal number of files
-    MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast<MatrixWorkspace>(output->getItem(0));
-    MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast<MatrixWorkspace>(output->getItem(1));
-    
-    TS_ASSERT_EQUALS(ws1->getNumberHistograms(), SPECTRA_COUNT);  // Number of spectra
+    WorkspaceGroup_sptr out;
+    TS_ASSERT(AnalysisDataService::Instance().doesExist(outputSpace));
+    TS_ASSERT_THROWS_NOTHING(
+        out = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(
+            outputSpace));
+    TS_ASSERT_EQUALS(out->getNumberOfEntries(),
+                     2); // Number of time bins should equal number of files
+    MatrixWorkspace_sptr ws1;
+    TS_ASSERT_THROWS_NOTHING(
+        ws1 = boost::dynamic_pointer_cast<MatrixWorkspace>(out->getItem(0)));
+    MatrixWorkspace_sptr ws2;
+    TS_ASSERT_THROWS_NOTHING(
+        ws2 = boost::dynamic_pointer_cast<MatrixWorkspace>(out->getItem(1)));
+
+    // basic FITS headers
+    const auto run = ws1->run();
+    TS_ASSERT_EQUALS(run.getLogData("SIMPLE")->value(), hdrSIMPLE);
+    TS_ASSERT_EQUALS(run.getLogData("BITPIX")->value(), hdrBITPIX);
+    TS_ASSERT_EQUALS(run.getLogData("NAXIS")->value(), hdrNAXIS);
+    TS_ASSERT_EQUALS(run.getLogData("NAXIS1")->value(), hdrNAXIS1);
+    TS_ASSERT_EQUALS(run.getLogData("NAXIS2")->value(), hdrNAXIS2);
+
+    // Number of spectra
+    TS_ASSERT_EQUALS(ws1->getNumberHistograms(), SPECTRA_COUNT);
+    TS_ASSERT_EQUALS(ws2->getNumberHistograms(), SPECTRA_COUNT);
+
     // Sum the two bins from the last spectra - should be 70400
-    double sumY = ws1->readY(SPECTRA_COUNT-1)[0] + ws2->readY(SPECTRA_COUNT-1)[0];   
-    TS_ASSERT_EQUALS(sumY, 275);   
-    // Check the sum of the error values for the last spectra in each file - should be 375.183
-    double sumE = ws1->readE(SPECTRA_COUNT-1)[0] + ws2->readE(SPECTRA_COUNT-1)[0];
-    TS_ASSERT_LESS_THAN(abs(sumE-23.4489), 0.0001);  // Include a small tolerance check with the assert - not exactly 375.183
+    double sumY =
+        ws1->readY(SPECTRA_COUNT - 1)[0] + ws2->readY(SPECTRA_COUNT - 1)[0];
+    TS_ASSERT_EQUALS(sumY, 275);
+    // Check the sum of the error values for the last spectra in each file -
+    // should be 375.183
+    double sumE =
+        ws1->readE(SPECTRA_COUNT - 1)[0] + ws2->readE(SPECTRA_COUNT - 1)[0];
+    TS_ASSERT_LESS_THAN(abs(sumE - 23.4489), 0.0001); // Include a small
+                                                      // tolerance check with
+                                                      // the assert - not
+                                                      // exactly 375.183
   }
 
 private:
+  Mantid::API::IAlgorithm_sptr testAlg;
   LoadFITS algToBeTested;
+
   std::string inputFile;
   std::string outputSpace;
-  const static size_t SPECTRA_COUNT = 262144; // Based on the 512*512 test image
+  static const std::string smallFname1;
+  static const std::string smallFname2;
+
+  const static size_t xdim = 512;
+  const static size_t ydim = 512;
+  const static size_t SPECTRA_COUNT = xdim * ydim;
+  // FITS headers
+  const static std::string hdrSIMPLE;
+  const static std::string hdrBITPIX;
+  const static std::string hdrNAXIS;
+  const static std::string hdrNAXIS1;
+  const static std::string hdrNAXIS2;
 };
 
+const std::string LoadFITSTest::smallFname1 = "FITS_small_01.fits";
+const std::string LoadFITSTest::smallFname2 = "FITS_small_02.fits";
+
+const std::string LoadFITSTest::hdrSIMPLE = "T";
+const std::string LoadFITSTest::hdrBITPIX = "16";
+const std::string LoadFITSTest::hdrNAXIS = "2";
+const std::string LoadFITSTest::hdrNAXIS1 = "512";
+const std::string LoadFITSTest::hdrNAXIS2 = "512";
 
-#endif
\ No newline at end of file
+#endif // MANTID_DATAHANDLING_LOADFITSTEST_H_
diff --git a/Code/Mantid/docs/source/algorithms/LoadFITS-v1.rst b/Code/Mantid/docs/source/algorithms/LoadFITS-v1.rst
index 1184957082ea3bb9cc5fcd8427abafca0877988f..dfeae5b13f7f708ab961b2d2f3ac96cdc33508b7 100644
--- a/Code/Mantid/docs/source/algorithms/LoadFITS-v1.rst
+++ b/Code/Mantid/docs/source/algorithms/LoadFITS-v1.rst
@@ -62,15 +62,15 @@ Usage
     ws = wsg.getItem(0)
 
     # A couple of standard FITS header entries
-    bpp_log = '_BITPIX'
+    bpp_log = 'BITPIX'
     try:
         log = ws.getRun().getLogData(bpp_log).value
         print "Bits per pixel: %s" % int(log)
     except RuntimeError:
         print "Could not find the keyword '%s' in this FITS file" % bpp_log
 
-    axis1_log = '_NAXIS1'
-    axis2_log = '_NAXIS2'
+    axis1_log = 'NAXIS1'
+    axis2_log = 'NAXIS2'
     try:
         log1 = ws.getRun().getLogData(axis1_log).value
         log2 = ws.getRun().getLogData(axis2_log).value