diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/IFileLoader.h b/Code/Mantid/Framework/API/inc/MantidAPI/IFileLoader.h index f7a2ae647015a1df92137e599c4724848e86c037..538d6748c970fd0b375b86fdc3289556eaa6893f 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/IFileLoader.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/IFileLoader.h @@ -42,6 +42,8 @@ namespace Mantid virtual ~IFileLoader() {} /// Returns a confidence value that this algorithm can load a file virtual int confidence(DescriptorType & descriptor) const = 0; + /// Returns a value indicating whether or not loader wants to load multiple files into a single workspace + virtual bool loadMutipleAsOne() { return false; } }; } // namespace API diff --git a/Code/Mantid/Framework/DataHandling/CMakeLists.txt b/Code/Mantid/Framework/DataHandling/CMakeLists.txt index 5527225abe33e05a853eada285820d7a4a770133..f16da216487050b55c854abc7fc8e19f6b1b3bc1 100644 --- a/Code/Mantid/Framework/DataHandling/CMakeLists.txt +++ b/Code/Mantid/Framework/DataHandling/CMakeLists.txt @@ -22,7 +22,7 @@ set ( SRC_FILES src/Load.cpp src/LoadAscii.cpp src/LoadAscii2.cpp - src/LoadBBY.cpp + src/LoadBBY.cpp src/LoadCalFile.cpp src/LoadCanSAS1D.cpp src/LoadCanSAS1D2.cpp @@ -315,6 +315,7 @@ set ( TEST_FILES LoadEventNexusTest.h LoadEventPreNexus2Test.h LoadEventPreNexusTest.h + LoadFITSTest.h LoadFullprofResolutionTest.h LoadGSASInstrumentFileTest.h LoadGSSTest.h diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFITS.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFITS.h index a69c68f755835ef0e2c47de71e24f622da2cd4a2..1ed0521b9067aa7862769ec7bf1a13561197bd84 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFITS.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadFITS.h @@ -88,6 +88,9 @@ namespace DataHandling /// Returns a confidence value that this algorithm can load a file virtual int confidence(Kernel::FileDescriptor & descriptor) const; + /// Returns a value indicating whether or not loader wants to load multiple files into a single workspace + virtual bool loadMutipleAsOne() { return true; } + private: /// Initialisation code void init(); diff --git a/Code/Mantid/Framework/DataHandling/src/Load.cpp b/Code/Mantid/Framework/DataHandling/src/Load.cpp index 3e9be99234919b47dbbe9671a253d7d65d5961e4..0ee51f8d0b4baa40c8ce61aefccee042f831e06e 100644 --- a/Code/Mantid/Framework/DataHandling/src/Load.cpp +++ b/Code/Mantid/Framework/DataHandling/src/Load.cpp @@ -170,12 +170,29 @@ namespace Mantid // ... store it's name and version and check that all other files have loaders with the same name and version. std::string name = loader->name(); int version = loader->version(); + + std::string ext = fileNames[0].substr(fileNames[0].find_last_of(".")); + + auto ifl = boost::dynamic_pointer_cast<IFileLoader<Kernel::FileDescriptor>>(loader); + auto iflNexus = boost::dynamic_pointer_cast<IFileLoader<Kernel::NexusDescriptor>>(loader); + for(size_t i = 1; i < fileNames.size(); ++i) { - loader = getFileLoader(fileNames[i]); - - if( name != loader->name() || version != loader->version() ) - throw std::runtime_error("Cannot load multiple files when more than one Loader is needed."); + // If it's loading into a single file, perform a cursory check on file extensions only. + if((ifl && ifl->loadMutipleAsOne()) || (iflNexus && iflNexus->loadMutipleAsOne())) + { + if( fileNames[i].substr(fileNames[i].find_last_of(".")) != ext) + { + throw std::runtime_error("Cannot load multiple files when more than one Loader is needed."); + } + } + else + { + loader = getFileLoader(fileNames[i]); + + if( name != loader->name() || version != loader->version() ) + throw std::runtime_error("Cannot load multiple files when more than one Loader is needed."); + } } } @@ -224,11 +241,18 @@ namespace Mantid // Use the first file property as the main Filename const auto & props = loader->getProperties(); for(auto it = props.begin(); it != props.end(); ++it) - { - if(auto *fp = dynamic_cast<API::FileProperty*>(*it)) + { + auto *fp = dynamic_cast<API::MultipleFileProperty*>(*it); + auto *fp2 = dynamic_cast<API::FileProperty*>(*it); + if(fp) { m_filenamePropName = fp->name(); break; + } + if(fp2) + { + m_filenamePropName = fp2->name(); + break; } } if(m_filenamePropName.empty()) @@ -324,10 +348,15 @@ namespace Mantid */ void Load::exec() { - std::vector<std::vector<std::string> > fileNames = getProperty("Filename"); + std::vector<std::vector<std::string> > fileNames = getProperty("Filename"); + + // Test for loading as a single file + IAlgorithm_sptr loader = getFileLoader(fileNames[0][0]); + auto ifl = boost::dynamic_pointer_cast<IFileLoader<Kernel::FileDescriptor>>(loader); + auto iflNexus = boost::dynamic_pointer_cast<IFileLoader<Kernel::NexusDescriptor>>(loader); - if(isSingleFile(fileNames)) - { + if(isSingleFile(fileNames) || (ifl && ifl->loadMutipleAsOne()) || (iflNexus && iflNexus->loadMutipleAsOne())) + { // This is essentially just the same code that was called before multiple files were supported. loadSingleFile(); } diff --git a/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp b/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp index a8f364979d86d8c3f12b32a465e256f4a54111b4..5b200bba28a6851f532420d2a199d66232d574f7 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp @@ -46,9 +46,8 @@ namespace DataHandling exts.push_back(".fits"); exts.push_back(".fit"); - // Specify as a MultipleFileProperty to alert loader we want multiple selected files to be loaded into a single workspace. declareProperty(new MultipleFileProperty("Filename", exts), "The input filename of the stored data"); - declareProperty(new PropertyWithValue<int>("FileChunkSize", 100, Direction::Input), "Number of files to read into memory at a time - use lower values for machines with low memory"); + declareProperty(new PropertyWithValue<size_t>("FileChunkSize", 100, Direction::Input), "Number of files to read into memory at a time - use lower values for machines with low memory"); declareProperty(new API::WorkspaceProperty<API::MatrixWorkspace>("OutputWorkspace", "", Kernel::Direction::Output)); } @@ -60,7 +59,7 @@ namespace DataHandling { // Create FITS file information for each file selected std::vector<std::string> paths; - string fName = getPropertyValue("Filename"); + string fName = getPropertyValue("Filename"); boost::split(paths, fName, boost::is_any_of(",")); m_binChunkSize = getProperty("FileChunkSize"); @@ -163,7 +162,7 @@ namespace DataHandling bool ranSuccessfully = true; try { - ifstream istr(headerInfo.filePath.c_str(), ios::binary); + 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 @@ -335,8 +334,7 @@ namespace DataHandling buffer8 = static_cast<uint8_t*>(bufferAny); buffer16 = static_cast<uint16_t*>(bufferAny); buffer32 = static_cast<uint32_t*>(bufferAny); - - + for(size_t i=binChunkStartIndex; i < binChunkStartIndex+binsThisChunk ; ++i) { // Read Data diff --git a/Code/Mantid/Framework/DataHandling/test/LoadFITSTest.h b/Code/Mantid/Framework/DataHandling/test/LoadFITSTest.h new file mode 100644 index 0000000000000000000000000000000000000000..73d34cf0209ffd30a382524a6683ff98f9200004 --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/test/LoadFITSTest.h @@ -0,0 +1,61 @@ +#ifndef LOADFITSTEST_H_ +#define LOADFITSTEST_H_ + +#include <cxxtest/TestSuite.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() + { + TS_ASSERT_THROWS_NOTHING(algToBeTested.initialize()); + 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); + } + + void testPerformAssertions() + { + TS_ASSERT_THROWS_NOTHING(algToBeTested.execute()); + TS_ASSERT( algToBeTested.isExecuted() ); + // get workspace generated + MatrixWorkspace_sptr output = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(outputSpace); + TS_ASSERT_EQUALS( output->blocksize(), 2); // Number of time bins should equal number of files + TS_ASSERT_EQUALS( output->getNumberHistograms(), SPECTRA_COUNT); // Number of spectra + // Sum the two bins from the last spectra - should be 70400 + double sumY = output->readY(SPECTRA_COUNT-1)[0] + output->readY(SPECTRA_COUNT-1)[1]; + TS_ASSERT_EQUALS(sumY, 70400); + // Check the sum of the error values for the last spectra in each file - should be 375.183 + double sumE = output->readE(SPECTRA_COUNT-1)[0] + output->readE(SPECTRA_COUNT-1)[1]; + TS_ASSERT_LESS_THAN(abs(sumE-375.1830), 0.0001); // Include a small tolerance check with the assert - not exactly 375.183 + } + + void testSingleChunkSize() + { + algToBeTested.setPropertyValue("FileChunkSize", "1"); + testPerformAssertions(); + } + +private: + LoadFITS algToBeTested; + std::string inputFile; + std::string outputSpace; + const static size_t SPECTRA_COUNT = 262144; +}; + + +#endif \ No newline at end of file diff --git a/Test/AutoTestData/FITS_small_01.fits b/Test/AutoTestData/FITS_small_01.fits new file mode 100644 index 0000000000000000000000000000000000000000..c3fc7f2ac7deb3845882be2ae60fd33ccc53afa9 Binary files /dev/null and b/Test/AutoTestData/FITS_small_01.fits differ diff --git a/Test/AutoTestData/FITS_small_02.fits b/Test/AutoTestData/FITS_small_02.fits new file mode 100644 index 0000000000000000000000000000000000000000..34c6325ec1787eeb653eae836f72fe66525c8cfe Binary files /dev/null and b/Test/AutoTestData/FITS_small_02.fits differ