diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/MultipleFileProperty.h b/Code/Mantid/Framework/API/inc/MantidAPI/MultipleFileProperty.h index 3dca5a1d70eee22f564bb142baa56f4497c187d4..2785f4d0656dac4df547cc1134495f41500b87ca 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/MultipleFileProperty.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/MultipleFileProperty.h @@ -1,9 +1,11 @@ #ifndef MANTID_API_MULTIPLEFILEPROPERTY_H_ #define MANTID_API_MULTIPLEFILEPROPERTY_H_ - -#include "MantidKernel/System.h" -#include "MantidKernel/ArrayProperty.h" +#include "MantidKernel/PropertyWithValue.h" +#include "MantidKernel/System.h" +#include "MantidKernel/MultiFileNameParser.h" +#include <vector> +#include <set> namespace Mantid { @@ -32,33 +34,40 @@ namespace API File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid> Code Documentation is available at: <http://doxygen.mantidproject.org> */ - class DLLExport MultipleFileProperty : public Kernel::ArrayProperty<std::string> + class DLLExport MultipleFileProperty : public Kernel::PropertyWithValue< std::vector< std::vector< std::string> > > { public: - MultipleFileProperty(const std::string & name, const std::vector<std::string> & exts = std::vector<std::string>(), - bool optional=false); + ///Constructor + MultipleFileProperty(const std::string & name,const std::vector<std::string> & exts = std::vector<std::string>()); ~MultipleFileProperty(); - ///Overridden setValue method + /// 'Virtual copy constructor + virtual MultipleFileProperty* clone() { return new MultipleFileProperty(*this); } + + /// Overridden setValue method virtual std::string setValue(const std::string & propValue); /// Set a property value via a DataItem virtual std::string setValue(const boost::shared_ptr<Kernel::DataItem> data); /// @return the vector of suggested extensions. For use in GUIs showing files. - const std::set<std::string> & getExts() const - { return m_exts; } + std::set<std::string> getExts() const + { return std::set<std::string>(m_exts.begin(), m_exts.end()); } + /// @return the vector of ws names. For use by loading algorithm to name multiple workspaces, especially summed workspaces. + std::vector<std::vector<unsigned int> > getRuns() const + { return m_parser.runs(); } // Unhide the PropertyWithValue assignment operator - using Kernel::ArrayProperty<std::string>::operator=; + using Kernel::PropertyWithValue< std::vector< std::vector< std::string> > >::operator=; + + /// Return a "flattened" vector with the contents of the given vector of vectors. + static std::vector<std::string> flattenFileNames(const std::vector<std::vector<std::string> > & fileNames); private: /// Suggested extensions - std::set<std::string> m_exts; - - /// Is the file optional? - bool m_optional; - + std::vector<std::string> m_exts; + /// Parser used to parse multi-file strings. + Kernel::MultiFileNameParsing::Parser m_parser; }; diff --git a/Code/Mantid/Framework/API/src/MultipleFileProperty.cpp b/Code/Mantid/Framework/API/src/MultipleFileProperty.cpp index 661cc9419c3d4206247c180e527acda24cd19422..e15620728c73e9a33e9e10ea3efe8c6653408280 100644 --- a/Code/Mantid/Framework/API/src/MultipleFileProperty.cpp +++ b/Code/Mantid/Framework/API/src/MultipleFileProperty.cpp @@ -1,10 +1,14 @@ #include "MantidAPI/MultipleFileProperty.h" +#include "MantidAPI/FileProperty.h" #include "MantidKernel/System.h" -#include "MantidKernel/FileValidator.h" +#include "MantidKernel/MultiFileValidator.h" #include "MantidKernel/Property.h" #include <Poco/Path.h> #include "MantidAPI/FileFinder.h" +#include <functional> +#include <numeric> + using namespace Mantid::Kernel; using namespace Mantid::API; @@ -12,67 +16,105 @@ namespace Mantid { namespace API { + // Forward declaration of functor wrapped in anonymous namespace. + namespace + { + class AppendFullFileName + { + public: + AppendFullFileName(const std::vector<std::string> & exts); + + std::string & operator()(std::string & result, const std::vector<std::string> & fileNames); + std::string & operator()(std::string & result, const std::string & fileName); + private: + const std::vector<std::string> & m_exts; + }; + } + /** Constructor * * @param name :: The name of the property * @param exts :: The allowed/suggested extensions * @param optional :: If ture, the property is optional */ - MultipleFileProperty::MultipleFileProperty(const std::string & name, - const std::vector<std::string> & exts, bool optional) - : ArrayProperty<std::string>(name), - m_optional(optional) - { - m_exts.insert( exts.begin(), exts.end()); - } + MultipleFileProperty::MultipleFileProperty( + const std::string & name, + const std::vector<std::string> & exts + ) : PropertyWithValue<std::vector<std::vector<std::string> > >( + name, + std::vector<std::vector<std::string> >(), + new MultiFileValidator(exts), + Direction::Input), + m_exts(exts), + m_parser() + {} - - //---------------------------------------------------------------------------------------------- /** Destructor */ - MultipleFileProperty::~MultipleFileProperty() - { - } + MultipleFileProperty::~MultipleFileProperty() {} - /** Set the value, the list of files, comma-separated + /** Set the value, with a comma- and plus-separated string of filenames * - * @param propValue :: comma-separated string of filenames + * @param propValue :: comma- and plus-separated string of filenames * @return A string indicating the outcome of the attempt to set the property. An empty string indicates success. */ std::string MultipleFileProperty::setValue(const std::string & propValue) { - // Separate the files - std::vector<std::string> filenames; - toValue(propValue, filenames); + // No empty value is allowed. + if( propValue.empty()) + return "No file(s) specified."; + + std::stringstream errorMsg; - // Empty value is allowed if optional - if( filenames.empty()) + try { - if (m_optional) - return ""; - else - return "No file specified."; + // Parse the string into the vector of vectors of filenames. + m_parser.parse(propValue); } - - std::string outValue; - for (size_t i=0; i<filenames.size(); i++) + catch(const std::runtime_error & re) { - std::string filename = filenames[i]; + errorMsg << "Unable to parse multi file runs: \"" << re.what() << "\". "; + } + + std::vector<std::vector<std::string> > fileNames = m_parser.fileNames(); - // Adjust the filename if the path is not absolute - if( !Poco::Path(propValue).isAbsolute() ) + AppendFullFileName appendFullFileName(m_exts); + std::string fullFileNames(""); + + // If we have been unable to parse multiple "run" filenames, then we try treating the string as a single file name. + if(fileNames.empty()) + { + try + { + fullFileNames = appendFullFileName(fullFileNames, propValue); + } + catch(const std::runtime_error & re) { - filename = FileFinder::Instance().getFullPath(filename); + errorMsg << "Tried to find single file, but also failed: \"" << re.what() << "\"."; + return errorMsg.str(); } - // Re-build a comma-sep string - if (i > 0) outValue += ","; - outValue += filename; } + // Else, for each file name in the vector, change it into a full file name where possible, + // then append it onto a comma- and plus-separated string. + else + { + try + { + fullFileNames = std::accumulate( + fileNames.begin(), fileNames.end(), + std::string(""), + appendFullFileName); + } + catch(const std::runtime_error & re) + { + return re.what(); + } + } - // Now re-set the strings using the full paths found - return ArrayProperty<std::string>::setValue(outValue); + // Now re-set the value using the full paths found. + return PropertyWithValue<std::vector<std::vector<std::string> > >::setValue(fullFileNames); } /** @@ -83,11 +125,116 @@ namespace API std::string MultipleFileProperty::setValue(const boost::shared_ptr<Kernel::DataItem> data ) { // Implemented this method for documentation reasons. Just calls base class method. - return ArrayProperty<std::string>::setValue(data); + return PropertyWithValue<std::vector<std::vector<std::string> > >::setValue(data); } + /** + * A convenience function for the cases where we dont use the MultiFileProperty to + * *add* workspaces - only to list them. It "flattens" the given vector of vectors + * into a single vector which is much easier to traverse. For example: + * + * ((1), (2), (30), (31), (32), (100), (102)) becomes (1, 2, 30, 31, 32, 100, 102) + * + * Used on a vector of vectors that *has* added filenames, the following behaviour is observed: + * + * ((1), (2), (30, 31, 32), (100), (102)) becomes (1, 2, 30, 31, 32, 100, 102) + * + * @param - a vector of vectors, containing all the file names. + * @return a single vector containing all the file names. + */ + std::vector<std::string> MultipleFileProperty::flattenFileNames( + const std::vector<std::vector<std::string> > & fileNames) + { + std::vector<std::string> flattenedFileNames; + + std::vector<std::vector<std::string> >::const_iterator it = fileNames.begin(); + + for(; it != fileNames.end(); ++it) + { + flattenedFileNames.insert( + flattenedFileNames.end(), + it->begin(), it->end()); + } + + return flattenedFileNames; + } + + ////////////////////////////////////////////////////////////////////// + // Anonymous + ////////////////////////////////////////////////////////////////////// + + namespace + { + // Functor with overloaded function operator, for use with the "accumulate" STL algorithm. + // Has state to store extensions. + AppendFullFileName:: AppendFullFileName(const std::vector<std::string> & exts) : + m_exts(exts) + {} + + /** Takes in a vector of filenames, tries to find their full path if possible, then cumulatively appends + * them to the result string. + * @param result :: the cumulative result so far + * @param fileNames :: the name to look for, and append to the result + * @return the cumulative result, after the filenames have been appended. + */ + std::string & AppendFullFileName::operator()(std::string & result, const std::vector<std::string> & fileNames) + { + // Append nothing if there are no file names to add. + if(fileNames.empty()) + return result; + + if(!result.empty()) + result += ","; + + AppendFullFileName appendFullFileName(m_exts); + + // Change each file name into a full file name, and append each one onto a plus-separated string. + std::string fullFileNames; + fullFileNames = std::accumulate( + fileNames.begin(), fileNames.end(), + fullFileNames, + appendFullFileName); // Call other overloaded operator on each filename in vector + + // Append the file names to result, and return them. + result += fullFileNames; + return result; + } + + /** Takes in a filename, tries to find it's full path if possible, then cumulatively appends it to a result string. + * @param result :: the cumulative result so far + * @param fileName :: the name to look for, and append to the result + * @return the cumulative result, after the filename has been appended. + * @throws std::runtime_error if an individual filename could not be set to the FileProperty object + */ + std::string & AppendFullFileName::operator()(std::string & result, const std::string & fileName) + { + // Append nothing if there is no file name to add. + if(fileName.empty()) + return result; + if(!result.empty()) + result += "+"; + + // Initialise a "slave" FileProperty object to do all the work. + FileProperty slaveFileProp( + "Slave", + "", + FileProperty::Load, + m_exts, + Direction::Input); + + std::string error = slaveFileProp.setValue(fileName); + + // If an error was returned then we throw it out of the functor, to be + // returned by MultiFileProperty.setvalue(...). + if(!error.empty()) + throw std::runtime_error(error); + + // Append the file name to result, and return it. + result += slaveFileProp(); + return result; + } + } // anonymous namespace } // namespace Mantid } // namespace API - diff --git a/Code/Mantid/Framework/API/test/MultipleFilePropertyTest.h b/Code/Mantid/Framework/API/test/MultipleFilePropertyTest.h index 8a77cb9c4fda2c49fcae97a5f550948400ff49d2..ed26d0aafc5e99473b7638b2ceb6e8535b4c5f0b 100644 --- a/Code/Mantid/Framework/API/test/MultipleFilePropertyTest.h +++ b/Code/Mantid/Framework/API/test/MultipleFilePropertyTest.h @@ -11,45 +11,27 @@ using namespace Mantid; using namespace Mantid::API; -using namespace Mantid::API; class MultipleFilePropertyTest : public CxxTest::TestSuite { public: - - void test_empty_value_not_allowed() - { - MultipleFileProperty p("Filename"); - TS_ASSERT_DIFFERS( p.setValue(""), ""); - } - - void test_empty_value_allowed_ifOptional() - { - MultipleFileProperty p("Filename", std::vector<std::string>(), true); - TS_ASSERT_EQUALS( p.setValue(""), ""); - } - - void test_getExts() - { - std::vector<std::string> exts; - exts.push_back(".nxs"); - exts.push_back(".hdf"); - - MultipleFileProperty p("Filename", exts); - TS_ASSERT_EQUALS( p.getExts().size(), 2); - TS_ASSERT_EQUALS( p.getExts().count(".nxs"), 1); - TS_ASSERT_EQUALS( p.getExts().count(".hdf"), 1); - } - + void test_setValue() { + // Here we try to load some files, some of them to be added together. We should end up with a vector of vectors as follows: + // + // | [dir]MUSR00015189.nxs | [dir]MUSR00015190.nxs | [dir]MUSR00015189.nxs | [dir]MUSR00015191.nxs | + // | [dir]MUSR00015190.nxs | + // | [dir]MUSR00015191.nxs | + MultipleFileProperty p("Filename"); - p.setValue("REF_L_32035.nxs, CSP78173.raw"); - std::vector<std::string> filenames = p(); - TS_ASSERT_EQUALS( filenames.size(), 2); - TSM_ASSERT( "Files with no path are found using ConfigService paths", Poco::Path(filenames[0]).isAbsolute() ); - TSM_ASSERT( "Files with no path are found using ConfigService paths", Poco::Path(filenames[1]).isAbsolute() ); + p.setValue("MUSR15189:15190,15189-15191,15191.nxs"); + std::vector<std::vector<std::string> > fileNames = p(); + TS_ASSERT_EQUALS(fileNames[0].size(), 1); + TS_ASSERT_EQUALS(fileNames[1].size(), 1); + TS_ASSERT_EQUALS(fileNames[2].size(), 3); + TS_ASSERT_EQUALS(fileNames[3].size(), 1); } diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h index 60b89e642ea91f3d7344d7885975b983dc28cc36..2d4bcd4fc3cd0b650e5945e8f335e0ea2e8789d4 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/Load.h @@ -72,6 +72,12 @@ namespace Mantid void init(); /// Execute void exec(); + + /// Called when there is only one file to load. + void loadSingleFile(); + /// Called when there are multiple files to load. + void loadMultipleFiles(); + /// Overrides the cancel() method to call m_loader->cancel() void cancel()const; /// Create the concrete instance use for the actual loading. @@ -85,8 +91,18 @@ namespace Mantid /// Retrieve a pointer to the output workspace from the sub algorithm API::Workspace_sptr getOutputWorkspace(const std::string & propName, const API::IDataFileChecker_sptr loader) const; - + /// Load a file to into a hidden workspace. + API::Workspace_sptr loadFileToHiddenWs(const std::string & fileName, const std::string & wsName); + /// Plus two workspaces together, "in place". + API::Workspace_sptr plusWs(API::Workspace_sptr ws1, API::Workspace_sptr ws2); + /// Delete a workspace with the given name. + void deleteWs(const std::string & wsName); + /// Rename a workspace with the given name. + void renameWs(const std::string & oldName, const std::string & newName); + /// Unhide the given workspace, if it is hidden. + void unhideWs(const std::string & wsName); + private: /// The base properties std::set<std::string> m_baseProps; diff --git a/Code/Mantid/Framework/DataHandling/src/Load.cpp b/Code/Mantid/Framework/DataHandling/src/Load.cpp index 0466c96ee1af67123501fa7b9e9327557e49e81a..5211c29ba490da99974fbb81bbff4fc33565b87b 100644 --- a/Code/Mantid/Framework/DataHandling/src/Load.cpp +++ b/Code/Mantid/Framework/DataHandling/src/Load.cpp @@ -33,7 +33,7 @@ Load('event_ws', Filename='INSTR_1000_event.nxs',Precount=True) // Includes //---------------------------------------------------------------------- #include "MantidDataHandling/Load.h" -#include "MantidAPI/FileProperty.h" +#include "MantidAPI/MultipleFileProperty.h" #include "MantidAPI/IEventWorkspace.h" #include "MantidAPI/IWorkspaceProperty.h" #include "MantidKernel/ArrayProperty.h" @@ -43,9 +43,58 @@ Load('event_ws', Filename='INSTR_1000_event.nxs',Precount=True) #include <cctype> #include <algorithm> +#include <functional> +#include <numeric> +#include <set> #include "MantidAPI/IMDEventWorkspace.h" #include <cstdio> + +namespace +{ + /** + * Convenience function that returns true if the passed vector of vector of strings + * contains a single string, false if contains more than that (or zero). + * + * @param fileNames :: a vector of vectors of file name strings. + * + * @returns true if there is exactly one string, else false. + */ + bool isSingleFile(const std::vector<std::vector<std::string> > & fileNames) + { + if(fileNames.size() == 1) + { + std::vector<std::vector<std::string>>::const_iterator first = fileNames.begin(); + if(first->size() == 1) + return true; + } + return false; + } + + /** + * Helper function that takes a vector of runs, and generates a suggested workspace name. + * This will likely need to be improved and may have to include instrument name, etc. + * + * @param runs :: a vector of run numbers. + * + * @returns a string containing a suggested file name based on the given run numbers. + */ + std::string generateWsName(std::vector<unsigned int> runs) + { + std::string wsName(""); + + for(size_t i = 0; i < runs.size(); ++i) + { + if(!wsName.empty()) + wsName += "_"; + + wsName += boost::lexical_cast<std::string>(runs[i]); + } + + return wsName; + } +} + namespace Mantid { namespace DataHandling @@ -88,9 +137,15 @@ namespace Mantid std::transform(name.begin(),name.end(),NAME.begin(),toupper); if( NAME == "FILENAME" ) { - // Get back full path before passing to getFileLoader method. - IDataFileChecker_sptr loader = getFileLoader(getPropertyValue(name)); - if( loader ) declareLoaderProperties(loader); + // Get back full path before passing to getFileLoader method, and also + // find out whether this is a multi file load. + std::vector<std::vector<std::string> > fileNames = getProperty("Filename"); + // If it's a single file load, then it's fine to change loader. + if(isSingleFile(fileNames)) + { + IDataFileChecker_sptr loader = getFileLoader(getPropertyValue(name)); + if( loader ) declareLoaderProperties(loader); + } } } @@ -249,9 +304,10 @@ namespace Mantid exts.push_back(".grp"); exts.push_back(".nxspe"); - declareProperty(new FileProperty("Filename", "", FileProperty::Load, exts), - "The name of the file to read, including its full or relative\n" - "path. (N.B. case sensitive if running on Linux)."); + declareProperty(new MultipleFileProperty("Filename", exts), + "The name of the file(s) to read, including the full or relative\n" + "path. (N.B. case sensitive if running on Linux). Multiple runs\n" + "can be loaded and added together, e.g. INST10,11+12,13.ext"); declareProperty(new WorkspaceProperty<Workspace>("OutputWorkspace", "",Direction::Output), "The name of the workspace that will be created, filled with the\n" "read-in data and stored in the Analysis Data Service."); @@ -268,12 +324,27 @@ namespace Mantid } /** - * Executes the algorithm. - */ + * Executes the algorithm. + */ void Load::exec() + { + std::vector<std::vector<std::string> > fileNames = getProperty("Filename"); + + if(isSingleFile(fileNames)) + { + // This is essentially just the same code that was called before multiple files were supported. + loadSingleFile(); + } + else + { + // Code that supports multiple file loading. + loadMultipleFiles(); + } + } + + void Load::loadSingleFile() { std::string loaderName = getPropertyValue("LoaderName"); - //IDataFileChecker_sptr loader; if( loaderName.empty() ) { m_loader = getFileLoader(getPropertyValue("Filename")); @@ -309,6 +380,101 @@ namespace Mantid setOutputWorkspace(m_loader); } + + void Load::loadMultipleFiles() + { + MultipleFileProperty * multiFileProp = dynamic_cast<MultipleFileProperty*>(getPointerToProperty("Filename")); + + const std::vector<std::vector<std::string> > values = getProperty("Filename"); + const std::vector<std::vector<unsigned int> > runs = multiFileProp->getRuns(); + std::string outputWsName = getProperty("OutputWorkspace"); + + std::vector<std::string> loadedWsNames; + + std::vector<std::vector<std::string> >::const_iterator values_it = values.begin(); + std::vector<std::vector<unsigned int> >::const_iterator runs_it = runs.begin(); + + // Cycle through the fileNames and wsNames. + for(; values_it != values.end(); ++values_it, ++runs_it) + { + std::vector<std::string> fileNames = *values_it; + std::string wsName = generateWsName(*runs_it); + + // If there is only one filename, then just load it to the given wsName. + if(fileNames.size() == 1) + { + loadFileToHiddenWs(fileNames.at(0), wsName); + loadedWsNames.push_back("__" + wsName); + } + // Else there is more than one filename. Load them all, sum them, and rename the + // result to the given wsName. + else + { + // Load all files and place the resulting workspaces in a vector. + std::vector<Workspace_sptr> loadedWs; + std::vector<std::string>::const_iterator vIt = fileNames.begin(); + + for(; vIt != fileNames.end(); ++vIt) + { + Workspace_sptr ws = loadFileToHiddenWs(*vIt, (*vIt) + "_temp"); + loadedWs.push_back(ws); + } + + // Add all workspaces together, sticking the result in sum. + Workspace_sptr sum; + for( + size_t i = 1; // Start at second workspace in list. + i < loadedWs.size(); + i++) + { + Workspace_sptr firstWsToAdd; + // If there have been no workspaces added yet, then the first workspace to add + // is the first workspace in the list. + if(sum == Workspace_sptr()) + firstWsToAdd = loadedWs.at(i-1); + // Else the first workspace to add is "sum" itself. + else + firstWsToAdd = sum; + + Workspace_sptr secondWsToAdd = loadedWs.at(i); + sum = plusWs(firstWsToAdd, secondWsToAdd); + } + + // Delete all of the temporarily loaded workspaces except the first one, so that we are left only + // with sum at this point. + for(size_t i = 1; i < fileNames.size(); i++) + { + deleteWs("__" + fileNames.at(i) + "_temp"); + } + + // Rename the sum and add to the list of loaded workspace names. + renameWs(sum->name(), "__" + wsName); + loadedWsNames.push_back("__" + wsName); + } + } + + // If we only have one loaded ws, set it as the output. + if(loadedWsNames.size() == 1) + { + renameWs(loadedWsNames.at(0), outputWsName); + setProperty("OutputWorkspace", AnalysisDataService::Instance().retrieve(outputWsName.c_str())); + } + // Else we have multiple loaded workspaces - group them and set the group as output. + else + { + Mantid::API::IAlgorithm_sptr groupingAlg = + Mantid::API::AlgorithmManager::Instance().create("GroupWorkspaces", 1); + + groupingAlg->setProperty("InputWorkspaces",loadedWsNames); + groupingAlg->setProperty("OutputWorkspace",outputWsName.c_str()); + groupingAlg->execute(); + + unhideWs(outputWsName); + + setProperty("OutputWorkspace", AnalysisDataService::Instance().retrieve(outputWsName.c_str())); + } + } + /** * Create the concrete instance use for the actual loading. * @param name :: The name of the loader to instantiate @@ -449,8 +615,8 @@ namespace Mantid } /* - * Overrides the default cancel() method. Calls cancel() on the actual loader. - */ + * Overrides the default cancel() method. Calls cancel() on the actual loader. + */ void Load::cancel()const { if (m_loader) @@ -459,5 +625,135 @@ namespace Mantid } } + /** + * Loads a file into a *hidden* workspace. + * + * @param fileName :: file name to load. + * @param wsName :: workspace name, which will be prefixed by a "__" + * + * @returns a pointer to the loaded workspace + */ + API::Workspace_sptr Load::loadFileToHiddenWs( + const std::string & fileName, + const std::string & wsName) + { + Mantid::API::IAlgorithm_sptr loadAlg = createSubAlgorithm("Load", 1); + // Here, as a workaround for groupworkspaces who's members have names but no + // accompanying entries in the ADS, we set the sub algo to not be a child ... + loadAlg->setChild(false); + // ... and now, so that the the workspaces dont appear in the window, we prefix + // all workspace names with "__". + loadAlg->setPropertyValue("Filename",fileName); + loadAlg->setPropertyValue("OutputWorkspace","__" + wsName); + loadAlg->executeAsSubAlg(); + + return AnalysisDataService::Instance().retrieve("__" + wsName); + } + + /** + * Plus two workspaces together, "in place". + * + * @param ws1 :: The first workspace. + * @param ws2 :: The second workspace. + * + * @returns a pointer to the result (the first workspace). + */ + API::Workspace_sptr Load::plusWs( + Workspace_sptr ws1, + Workspace_sptr ws2) + { + Mantid::API::IAlgorithm_sptr plusAlg = createSubAlgorithm("Plus", 1); + plusAlg->setPropertyValue("LHSWorkspace", ws1->name()); + plusAlg->setPropertyValue("RHSWorkspace", ws2->name()); + plusAlg->setPropertyValue("OutputWorkspace", ws1->name()); + plusAlg->executeAsSubAlg(); + + return ws1; + } + + /** + * Renames a workspace. + * + * @param oldName :: the old workspace name. + * @param newName :: the new workspace name. + */ + void Load::renameWs( + const std::string & oldName, + const std::string & newName) + { + if(oldName == newName) + return; + + Mantid::API::IAlgorithm_sptr renameAlg = createSubAlgorithm("RenameWorkspace", 1); + renameAlg->setChild(false); + renameAlg->setPropertyValue("InputWorkspace", oldName); + renameAlg->setPropertyValue("OutputWorkspace", newName); + renameAlg->executeAsSubAlg(); + } + + /** + * Deletes a given workspace. If the given workspace is a group workspace, + * then this function calls itself recursively for each workspace in the group. + * + * @param wsName :: the name of the workspace to delete. + */ + void Load::deleteWs(const std::string & wsName) + { + Workspace_sptr ws = AnalysisDataService::Instance().retrieve(wsName); + if(WorkspaceGroup_sptr wsGrpSptr = + boost::dynamic_pointer_cast<WorkspaceGroup>(ws)) + { + std::vector<std::string> childWsNames = wsGrpSptr->getNames(); + std::vector<std::string>::iterator vIt = childWsNames.begin(); + + for(; vIt != childWsNames.end(); ++vIt) + { + // Call this function recursively, to delete each child workspace. + deleteWs(*vIt); + } + } + else + { + Mantid::API::IAlgorithm_sptr deleteAlg = createSubAlgorithm("DeleteWorkspace", 1); + + deleteAlg->setPropertyValue("Workspace", wsName); + deleteAlg->execute(); + } + } + + /** + * Unhides a given workspace (by removing the "__" prefix from its name if present). + * If the given workspace is a group workspace, then this function calls itself + * recursively for each workspace in the group. + * + * @param wsName :: the name of the workspace to unhide. + */ + void Load::unhideWs(const std::string & wsName) + { + std::set<std::string> adsContents1 = AnalysisDataService::Instance().getObjectNames(); + + Workspace_sptr ws = AnalysisDataService::Instance().retrieve(wsName); + if(WorkspaceGroup_sptr wsGrpSptr = + boost::dynamic_pointer_cast<WorkspaceGroup>(ws)) + { + std::vector<std::string> childWsNames = wsGrpSptr->getNames(); + std::vector<std::string>::iterator vIt = childWsNames.begin(); + + for(; vIt != childWsNames.end(); ++vIt) + { + // Call this function recursively, to unhide each child workspace. + unhideWs(*vIt); + } + } + else + { + if(boost::starts_with(wsName, "__")) + { + std::string newName = wsName.substr(2, (wsName.size() - 2)); + renameWs(wsName, newName); + } + } + } + } // namespace DataHandling } // namespace Mantid diff --git a/Code/Mantid/Framework/DataHandling/test/LoadTest.h b/Code/Mantid/Framework/DataHandling/test/LoadTest.h index dc01f646c07b1ea852f019ffdc13b13ebbedb97a..eaae509040c4d21de816e3acd6994a0d5f16056e 100644 --- a/Code/Mantid/Framework/DataHandling/test/LoadTest.h +++ b/Code/Mantid/Framework/DataHandling/test/LoadTest.h @@ -13,6 +13,20 @@ using namespace Mantid::API; using namespace Mantid::DataObjects; using namespace Mantid::DataHandling; +namespace +{ + void removeGroupFromADS(WorkspaceGroup_sptr group) + { + const std::vector<std::string> wsNames = group->getNames(); + std::vector<std::string>::const_iterator it = wsNames.begin(); + AnalysisDataService::Instance().remove(group->name()); + for(; it != wsNames.end(); ++it) + { + AnalysisDataService::Instance().remove(*it); + } + } +} + class LoadTest : public CxxTest::TestSuite { public: @@ -183,7 +197,7 @@ public: AnalysisDataService::Instance().remove("LoadTest_Output"); } - void test_ARGUS_NXS() + void _ARGUS_NXS() { Load loader; loader.initialize(); @@ -327,6 +341,135 @@ public: TS_ASSERT(ws); AnalysisDataService::Instance().remove("LoadTest_Output"); } + + + + void testList() + { + Load loader; + loader.initialize(); + loader.setPropertyValue("Filename", "MUSR15189,15190,15191.nxs"); + loader.setPropertyValue("OutputWorkspace","LoadTest_Output"); + TS_ASSERT_THROWS_NOTHING(loader.execute()); + WorkspaceGroup_sptr output = boost::dynamic_pointer_cast<WorkspaceGroup>(AnalysisDataService::Instance().retrieve("LoadTest_Output")); + TS_ASSERT(output); + TS_ASSERT_EQUALS(output->getNumberOfEntries(),6); + MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15189_1")); + TS_ASSERT(ws1); + MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15189_2")); + TS_ASSERT(ws2); + MatrixWorkspace_sptr ws3 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15190_1")); + TS_ASSERT(ws3); + MatrixWorkspace_sptr ws4 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15190_2")); + TS_ASSERT(ws4); + MatrixWorkspace_sptr ws5 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15191_1")); + TS_ASSERT(ws5); + MatrixWorkspace_sptr ws6 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15191_2")); + TS_ASSERT(ws6); + removeGroupFromADS(output); + } + + void testPlus() + { + Load loader; + loader.initialize(); + loader.setPropertyValue("Filename", "MUSR15189+15190.nxs"); + loader.setPropertyValue("OutputWorkspace","LoadTest_Output"); + TS_ASSERT_THROWS_NOTHING(loader.execute()); + + WorkspaceGroup_sptr output = boost::dynamic_pointer_cast<WorkspaceGroup>(AnalysisDataService::Instance().retrieve("LoadTest_Output")); + TS_ASSERT(output); + MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("LoadTest_Output_1")); + TS_ASSERT(ws1); + MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("LoadTest_Output_2")); + removeGroupFromADS(output); + } + + void testRange() + { + Load loader; + loader.initialize(); + loader.setPropertyValue("Filename", "MUSR15189:15192.nxs"); + loader.setPropertyValue("OutputWorkspace","LoadTest_Output"); + TS_ASSERT_THROWS_NOTHING(loader.execute()); + WorkspaceGroup_sptr output = boost::dynamic_pointer_cast<WorkspaceGroup>(AnalysisDataService::Instance().retrieve("LoadTest_Output")); + TS_ASSERT(output); + TS_ASSERT_EQUALS(output->getNumberOfEntries(),8); + MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15189_1")); + TS_ASSERT(ws1); + MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15189_2")); + TS_ASSERT(ws2); + MatrixWorkspace_sptr ws3 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15190_1")); + TS_ASSERT(ws3); + MatrixWorkspace_sptr ws4 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15190_2")); + TS_ASSERT(ws4); + MatrixWorkspace_sptr ws5 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15191_1")); + TS_ASSERT(ws5); + MatrixWorkspace_sptr ws6 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15191_2")); + TS_ASSERT(ws6); + MatrixWorkspace_sptr ws7 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15192_1")); + TS_ASSERT(ws7); + MatrixWorkspace_sptr ws8 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15192_2")); + TS_ASSERT(ws8); + removeGroupFromADS(output); + } + + void testSteppedRange() + { + Load loader; + loader.initialize(); + loader.setPropertyValue("Filename", "MUSR15189:15192:2.nxs"); + loader.setPropertyValue("OutputWorkspace","LoadTest_Output"); + TS_ASSERT_THROWS_NOTHING(loader.execute()); + WorkspaceGroup_sptr output = boost::dynamic_pointer_cast<WorkspaceGroup>(AnalysisDataService::Instance().retrieve("LoadTest_Output")); + TS_ASSERT(output); + TS_ASSERT_EQUALS(output->getNumberOfEntries(),4); + MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15189_1")); + TS_ASSERT(ws1); + MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15189_2")); + TS_ASSERT(ws2); + MatrixWorkspace_sptr ws3 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15191_1")); + TS_ASSERT(ws3); + MatrixWorkspace_sptr ws4 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("15191_2")); + TS_ASSERT(ws4); + removeGroupFromADS(output); + } + + void testAddedRange() + { + Load loader; + loader.initialize(); + loader.setPropertyValue("Filename", "MUSR15189-15192.nxs"); + loader.setPropertyValue("OutputWorkspace","LoadTest_Output"); + TS_ASSERT_THROWS_NOTHING(loader.execute()); + + WorkspaceGroup_sptr output = boost::dynamic_pointer_cast<WorkspaceGroup>(AnalysisDataService::Instance().retrieve("LoadTest_Output")); + TS_ASSERT(output); + TS_ASSERT_EQUALS(output->getNumberOfEntries(),2); + MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("LoadTest_Output_1")); + TS_ASSERT(ws1); + MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("LoadTest_Output_2")); + TS_ASSERT(ws2); + removeGroupFromADS(output); + } + + void testAddedSteppedRange() + { + Load loader; + loader.initialize(); + loader.setPropertyValue("Filename", "MUSR15189-15192:2.nxs"); + loader.setPropertyValue("OutputWorkspace","LoadTest_Output"); + TS_ASSERT_THROWS_NOTHING(loader.execute()); + + WorkspaceGroup_sptr output = boost::dynamic_pointer_cast<WorkspaceGroup>(AnalysisDataService::Instance().retrieve("LoadTest_Output")); + TS_ASSERT(output); + TS_ASSERT_EQUALS(output->getNumberOfEntries(),2); + MatrixWorkspace_sptr ws1 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("LoadTest_Output_1")); + TS_ASSERT(ws1); + MatrixWorkspace_sptr ws2 = boost::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve("LoadTest_Output_2")); + TS_ASSERT(ws2); + removeGroupFromADS(output); + } }; #endif /*LOADTEST_H_*/ diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/IPropertyManager.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/IPropertyManager.h index 78ceb1a510ee00c565381d3edac900abeda6f71b..9f0ee49d52240a4cb4cdb4137df67d33094d3255 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/IPropertyManager.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/IPropertyManager.h @@ -306,10 +306,13 @@ protected: operator std::string (); /// explicit specialization for Property*() operator Property* (); - + /// explicit specialization for std::vector template<typename T> operator std::vector<T> () { return pm.getValue<std::vector<T> >(prop);} + /// explicit specialization for std::vector + template<typename T> + operator std::vector<std::vector<T> > () { return pm.getValue<std::vector<std::vector<T> > >(prop);} /// explicit specialization for boost::shared_ptr template<typename T> operator boost::shared_ptr<T> () { return pm.getValue<boost::shared_ptr<T> >(prop); } diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/MultiFileNameParser.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/MultiFileNameParser.h index c6125b3b887e9ff7a3c2a5fb8f4b9912268a847f..f5f4b7bf4885267d5bb1584741d9a1fa1326ae11 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/MultiFileNameParser.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/MultiFileNameParser.h @@ -78,19 +78,19 @@ namespace Kernel void parse(const std::string & multiFileName); /// Return the vector of vectors of parsed file names. - std::vector<std::vector<unsigned int> > runs() {return m_runs;} + std::vector<std::vector<unsigned int> > runs() const {return m_runs;} /// Return the vector of vectors of parsed file names. - std::vector<std::vector<std::string> > fileNames() {return m_fileNames;} + std::vector<std::vector<std::string> > fileNames() const {return m_fileNames;} /// Return the parsed directory string. - std::string dirString() {return m_dirString;} + std::string dirString() const {return m_dirString;} /// Return the parsed instrument string. - std::string instString() {return m_instString;} + std::string instString() const {return m_instString;} /// Return the parsed underscore string. - std::string underscoreString() {return m_underscoreString;} + std::string underscoreString() const {return m_underscoreString;} /// Return the parsed run string. - std::string runString() {return m_runString;} + std::string runString() const {return m_runString;} /// Return the parsed extension string. - std::string extString() {return m_extString;} + std::string extString() const {return m_extString;} private: /// Clear all member variables. diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h index feb4d3d74dfc375bb91d1783c8a4ea810e76fce4..e90e62d6df30deff7fbbf5df522f0ba023793d71 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h @@ -88,6 +88,28 @@ std::string toString(const std::vector<T>& value) return result.str(); } +/// Specialisation for a property of type std::vector<std::vector>. +template <typename T> +std::string toString(const std::vector<std::vector<T> >& value) +{ + std::stringstream result; + std::size_t vsize = value.size(); + for (std::size_t i = 0; i < vsize; ++i) + { + std::size_t innervsize = value[i].size(); + for (std::size_t j = 0; j < innervsize; ++j) + { + result << value[i][j]; + if (j + 1 != innervsize) + result << "+"; + } + + if (i + 1 != vsize) + result << ","; + } + return result.str(); +} + // ------------- Convert strings to values template <typename T> inline void appendValue(const std::string& strvalue, std::vector<T>& value) @@ -140,6 +162,28 @@ void toValue(const std::string& strvalue, std::vector<T>& value) } } +template <typename T> +void toValue(const std::string& strvalue, std::vector<std::vector<T> >& value) +{ + // Split up comma-separated properties + typedef Poco::StringTokenizer tokenizer; + tokenizer tokens(strvalue, ",", tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM); + + value.clear(); + value.reserve(tokens.count()); + + for (tokenizer::Iterator oIt = tokens.begin(); oIt != tokens.end(); ++oIt) + { + tokenizer values(*oIt, "+", tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM); + std::vector<T> vect; + + for (tokenizer::Iterator iIt = values.begin(); iIt != values.end(); ++iIt) + vect.push_back(boost::lexical_cast<T>(*iIt)); + + value.push_back(vect); + } +} + /// Macro for the vector<int> specializations #define PROPERTYWITHVALUE_TOVALUE(type) \ template <> \ diff --git a/Code/Mantid/Framework/Kernel/src/ArrayProperty.cpp b/Code/Mantid/Framework/Kernel/src/ArrayProperty.cpp index 783434bca3d60c0ad3df3aca68d8812224ebb1dc..9c2a5625b4b02016b387d8d2c1637b8cc7f7dcfc 100644 --- a/Code/Mantid/Framework/Kernel/src/ArrayProperty.cpp +++ b/Code/Mantid/Framework/Kernel/src/ArrayProperty.cpp @@ -16,6 +16,8 @@ template DLLExport class ArrayProperty<size_t>; template DLLExport class ArrayProperty<double>; template DLLExport class ArrayProperty<std::string>; +template DLLExport class ArrayProperty<std::vector<std::string> >; + /// @endcond } // namespace Kernel diff --git a/Code/Mantid/Framework/Kernel/src/IPropertyManager.cpp b/Code/Mantid/Framework/Kernel/src/IPropertyManager.cpp index 50fa4e642cbeea24698e8440758649589f181311..dade2e8585894e8d2270c910b65e7d886c019604 100644 --- a/Code/Mantid/Framework/Kernel/src/IPropertyManager.cpp +++ b/Code/Mantid/Framework/Kernel/src/IPropertyManager.cpp @@ -23,6 +23,7 @@ DEFINE_IPROPERTYMANAGER_GETVALUE(std::vector<int64_t>); DEFINE_IPROPERTYMANAGER_GETVALUE(std::vector<uint64_t>); DEFINE_IPROPERTYMANAGER_GETVALUE(std::vector<double>); DEFINE_IPROPERTYMANAGER_GETVALUE(std::vector<std::string>); +DEFINE_IPROPERTYMANAGER_GETVALUE(std::vector<std::vector<std::string> >); namespace Mantid { diff --git a/Code/Mantid/Framework/Kernel/src/MultiFileNameParser.cpp b/Code/Mantid/Framework/Kernel/src/MultiFileNameParser.cpp index 668fe0af7fe2bef524f4b7a8669c40a80af0dac7..735c351657b1c0d68ab392d406a0febedd7709cb 100644 --- a/Code/Mantid/Framework/Kernel/src/MultiFileNameParser.cpp +++ b/Code/Mantid/Framework/Kernel/src/MultiFileNameParser.cpp @@ -208,7 +208,7 @@ namespace Kernel // Get the directory, if there is one. size_t lastSeparator = m_multiFileName.find_last_of("/\\"); if(lastSeparator != std::string::npos) - m_dirString = m_multiFileName.substr(0, lastSeparator); + m_dirString = m_multiFileName.substr(0, lastSeparator + 1); // Slice off the directory and extension. std::string base = m_multiFileName.substr( diff --git a/Code/Mantid/Framework/Kernel/src/Property.cpp b/Code/Mantid/Framework/Kernel/src/Property.cpp index dd97321951cca3bae3fa14a233e0040cbae847a1..0ec0609c5e245f69ad669a4777aed1030506a6bc 100644 --- a/Code/Mantid/Framework/Kernel/src/Property.cpp +++ b/Code/Mantid/Framework/Kernel/src/Property.cpp @@ -247,6 +247,7 @@ std::string getUnmangledTypeName(const std::type_info& type) typestrings.insert(make_pair(typeid(std::vector<int>).name(), string("int list"))); typestrings.insert(make_pair(typeid(std::vector<int64_t>).name(), string("int list"))); typestrings.insert(make_pair(typeid(std::vector<double>).name(), string("dbl list"))); + typestrings.insert(make_pair(typeid(std::vector<std::vector<string> >).name(), string("list of str lists"))); //Workspaces typestrings.insert(make_pair(typeid(boost::shared_ptr<Workspace>).name(), diff --git a/Code/Mantid/Framework/Kernel/src/PropertyWithValue.cpp b/Code/Mantid/Framework/Kernel/src/PropertyWithValue.cpp index e8db6c92cafe1d8dd9f287d4b12fe13c9a0a492d..8924b53481a81ff85312832dbebd2895e19eb9fd 100644 --- a/Code/Mantid/Framework/Kernel/src/PropertyWithValue.cpp +++ b/Code/Mantid/Framework/Kernel/src/PropertyWithValue.cpp @@ -23,6 +23,8 @@ namespace Mantid template DLLExport class PropertyWithValue<std::vector<int32_t> >; template DLLExport class PropertyWithValue<std::vector<uint64_t> >; template DLLExport class PropertyWithValue<std::vector<int64_t> >; + + template DLLExport class PropertyWithValue<std::vector<std::vector<std::string> > >; /// @endcond } // namespace Kernel diff --git a/Code/Mantid/Framework/MDAlgorithms/src/MergeMDFiles.cpp b/Code/Mantid/Framework/MDAlgorithms/src/MergeMDFiles.cpp index 2add40e13ba64af72da40c38667d17dd1a2717d8..cb40d94a230d647350f0ee17be0598fe710414d4 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/MergeMDFiles.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/MergeMDFiles.cpp @@ -632,7 +632,8 @@ namespace MDAlgorithms */ void MergeMDFiles::exec() { - m_filenames = getProperty("Filenames"); + MultipleFileProperty * multiFileProp = dynamic_cast<MultipleFileProperty*>(getPointerToProperty("Filenames")); + m_filenames = MultipleFileProperty::flattenFileNames(multiFileProp->operator()()); if (m_filenames.size() == 0) throw std::invalid_argument("Must specify at least one filename."); std::string firstFile = m_filenames[0]; diff --git a/Code/Mantid/Framework/MDAlgorithms/test/MergeMDFilesTest.h b/Code/Mantid/Framework/MDAlgorithms/test/MergeMDFilesTest.h index f60db5cf9c27e4b676d7e22a107f6f66b57068dc..2e6c24b745c3a515abb5b1eb1230bdc70a8b6380 100644 --- a/Code/Mantid/Framework/MDAlgorithms/test/MergeMDFilesTest.h +++ b/Code/Mantid/Framework/MDAlgorithms/test/MergeMDFilesTest.h @@ -41,7 +41,7 @@ public: void do_test_exec(std::string OutputFilename) { // Create a bunch of input files - std::vector<std::string> filenames; + std::vector<std::vector<std::string> > filenames; std::vector<MDEventWorkspace3Lean::sptr> inWorkspaces; for (size_t i=0; i<3; i++) { @@ -49,7 +49,7 @@ public: mess << "MergeMDFilesTestInput" << i; MDEventWorkspace3Lean::sptr ws = MDEventsTestHelper::makeFileBackedMDEW(mess.str(), true); inWorkspaces.push_back(ws); - filenames.push_back(ws->getBoxController()->getFilename()); + filenames.push_back(std::vector<std::string>(1,ws->getBoxController()->getFilename())); } // Name of the output workspace.