diff --git a/Code/Mantid/Framework/DataHandling/CMakeLists.txt b/Code/Mantid/Framework/DataHandling/CMakeLists.txt index 61ddb8a9674aed907ddd1d1c0740ebea012b5b27..996bc833ca6149de3fe03ca82fe0e8cb65a8ba41 100644 --- a/Code/Mantid/Framework/DataHandling/CMakeLists.txt +++ b/Code/Mantid/Framework/DataHandling/CMakeLists.txt @@ -76,6 +76,7 @@ set ( SRC_FILES src/LoadRawBin0.cpp src/LoadRawHelper.cpp src/LoadRawSpectrum0.cpp + src/LoadReflTBL.cpp src/LoadSINQFocus.cpp src/LoadSNSspec.cpp src/LoadSPE.cpp @@ -122,6 +123,7 @@ set ( SRC_FILES src/SaveNexusProcessed.cpp src/SavePAR.cpp src/SavePHX.cpp + src/SaveReflTBL.cpp src/SaveRKH.cpp src/SaveSPE.cpp src/SaveToSNSHistogramNexus.cpp @@ -204,6 +206,7 @@ set ( INC_FILES inc/MantidDataHandling/LoadRawBin0.h inc/MantidDataHandling/LoadRawHelper.h inc/MantidDataHandling/LoadRawSpectrum0.h + inc/MantidDataHandling/LoadReflTBL.h inc/MantidDataHandling/LoadSINQFocus.h inc/MantidDataHandling/LoadSNSspec.h inc/MantidDataHandling/LoadSPE.h @@ -250,6 +253,7 @@ set ( INC_FILES inc/MantidDataHandling/SaveNexusProcessed.h inc/MantidDataHandling/SavePAR.h inc/MantidDataHandling/SavePHX.h + inc/MantidDataHandling/SaveReflTBL.h inc/MantidDataHandling/SaveRKH.h inc/MantidDataHandling/SaveSPE.h inc/MantidDataHandling/SaveToSNSHistogramNexus.h @@ -328,6 +332,7 @@ set ( TEST_FILES LoadRawSaveNxsLoadNxsTest.h LoadRawSpectrum0Test.h LoadRawTest.h + LoadReflTBLTest.h LoadSINQFocusTest.h LoadSNSspecTest.h LoadSPETest.h @@ -373,6 +378,7 @@ set ( TEST_FILES SavePARTest.h SavePHXTest.h SaveRKHTest.h + SaveReflTBLTest.h SaveSPETest.h SaveToSNSHistogramNexusTest.h SetSampleMaterialTest.h diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadReflTBL.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadReflTBL.h new file mode 100644 index 0000000000000000000000000000000000000000..6e9a164c3b5acf290e5982d95a10089bc6bef7ff --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadReflTBL.h @@ -0,0 +1,73 @@ +#ifndef MANTID_DATAHANDLING_LOADREFLTBL_H_ +#define MANTID_DATAHANDLING_LOADREFLTBL_H_ + +//---------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------- +#include "MantidAPI/IFileLoader.h" +#include "MantidDataObjects/TableWorkspace.h" + +namespace Mantid +{ + namespace DataHandling + { + /** + Loads a table workspace from an ascii file in reflectometry tbl format. Rows must be no longer than 17 cells. + + Copyright © 2007-2014 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://github.com/mantidproject/mantid>. + Code Documentation is available at: <http://doxygen.mantidproject.org> + */ + class DLLExport LoadReflTBL :public API::IFileLoader<Kernel::FileDescriptor> + { + public: + /// Default constructor + LoadReflTBL(); + /// The name of the algorithm + virtual const std::string name() const { return "LoadReflTBL"; } + /// The version number + virtual int version() const { return 1; } + /// The category + virtual const std::string category() const { return "DataHandling\\Text"; } + /// Returns a confidence value that this algorithm can load a file + virtual int confidence(Kernel::FileDescriptor & descriptor) const; + + private: + /// Sets documentation strings for this algorithm + virtual void initDocs(); + /// Declare properties + void init(); + /// Execute the algorithm + void exec(); + /// Split into columns with respect to the comma delimiters + size_t getCells(std::string line, std::vector<std::string> & cols) const; + /// count the number of commas in the line + size_t countCommas (std::string line) const; + /// find all pairs of quotes in the line + size_t findQuotePairs (std::string line, std::vector<std::vector<size_t>> & quoteBounds) const; + /// Parse more complex CSV, used when the data involves commas in the data and quoted values + void csvParse(std::string line, std::vector<std::string> & cols, std::vector<std::vector<size_t>> & quoteBounds) const; + /// the perfect number of commas expected in a single line. more is fine, less is not (set to 16) + const size_t m_expectedCommas; + }; + + } // namespace DataHandling +} // namespace Mantid + +#endif /* MANTID_DATAHANDLING_LOADREFLTBL_H_ */ diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflTBL.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflTBL.h new file mode 100644 index 0000000000000000000000000000000000000000..ac8903c6f61ee875e174b52948a3e7dec50e6391 --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflTBL.h @@ -0,0 +1,74 @@ +#ifndef MANTID_DATAHANDLING_SAVEREFLTBL_H_ +#define MANTID_DATAHANDLING_SAVEREFLTBL_H_ + +//---------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------- +#include "MantidAPI/Algorithm.h" +#include "MantidAPI/ITableWorkspace.h" + +namespace Mantid +{ + namespace DataHandling + { + /** @class SaveReflTBL SaveReflTBL.h DataHandling/SaveReflTBL.h + + Saves a table workspace to a reflectometry tbl format ascii file. + Rows are 17 cells long and this save algorithm will throw if the workspace has stitch groups of longer than 3 runs. + + Copyright © 2007-2014 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://github.com/mantidproject/mantid>. + Code Documentation is available at: <http://doxygen.mantidproject.org> + */ + class DLLExport SaveReflTBL : public API::Algorithm + { + public: + /// Default constructor + SaveReflTBL(); + /// Destructor + ~SaveReflTBL() {} + /// Algorithm's name for identification overriding a virtual method + virtual const std::string name() const { return "SaveReflTBL"; } + /// Algorithm's version for identification overriding a virtual method + virtual int version() const { return 1; } + /// Algorithm's category for identification overriding a virtual method + virtual const std::string category() const { return "DataHandling\\Text"; } + + private: + /// Sets documentation strings for this algorithm + virtual void initDocs(); + /// Overwrites Algorithm method. + void init(); + /// Overwrites Algorithm method + void exec(); + /// Writes a value to the file + void writeVal(std::string & val,std::ofstream & file, bool endsep = true, bool endline = false); + /// the separator + const char m_sep; + //populates the map and vector containing grouping information + void findGroups(API::ITableWorkspace_sptr ws); + /// Map the separator options to their string equivalents + std::map<int,std::vector<size_t>> m_stichgroups; + std::vector<size_t> m_nogroup; + + }; + } // namespace DataHandling +} // namespace Mantid + +#endif /* MANTID_DATAHANDLING_SAVEREFLTBL_H_ */ diff --git a/Code/Mantid/Framework/DataHandling/src/Load.cpp b/Code/Mantid/Framework/DataHandling/src/Load.cpp index da2106b76c425c3bb823eeb3379a3a800d939b5c..367d15471cbbd6bbe0bafb7d4e0a9e49a31f0ed3 100644 --- a/Code/Mantid/Framework/DataHandling/src/Load.cpp +++ b/Code/Mantid/Framework/DataHandling/src/Load.cpp @@ -649,6 +649,15 @@ namespace Mantid catch(std::runtime_error&) { } + // ITableWorkspace? + try + { + ITableWorkspace_sptr childWS = loader->getProperty(propName); + return childWS; + } + catch(std::runtime_error&) + { } + // Just workspace? try { diff --git a/Code/Mantid/Framework/DataHandling/src/LoadLog.cpp b/Code/Mantid/Framework/DataHandling/src/LoadLog.cpp index 6387a2bb9f34b96f4c3fd0f3af358ee3fdb3d1a2..cd7e3145c5c74e3b7deee6125f6b939b8fc2b4f3 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadLog.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadLog.cpp @@ -184,7 +184,7 @@ namespace Mantid // figure out if second column is a number or a string std::string aLine; - if( Mantid::Kernel::extractToEOL(logFileStream,aLine) ) + if( Mantid::Kernel::Strings::extractToEOL(logFileStream,aLine) ) { if ( !isDateTimeString(aLine) ) { @@ -243,7 +243,7 @@ namespace Mantid throw std::invalid_argument("Unable to open file " + m_filename); } - while(Mantid::Kernel::extractToEOL(logFileStream,str)) + while(Mantid::Kernel::Strings::extractToEOL(logFileStream,str)) { if ( !isDateTimeString(str) ) { @@ -377,7 +377,7 @@ namespace Mantid // Get the first line std::string aLine; - if (!Mantid::Kernel::extractToEOL(inLogFile,aLine)) + if (!Mantid::Kernel::Strings::extractToEOL(inLogFile,aLine)) return false; std::vector<double> cols; @@ -403,7 +403,7 @@ namespace Mantid } // Go back to start inLogFile.seekg(0); - while(Mantid::Kernel::extractToEOL(inLogFile,aLine)) + while(Mantid::Kernel::Strings::extractToEOL(inLogFile,aLine)) { if (aLine.size() == 0) break; @@ -554,7 +554,7 @@ namespace Mantid kind l_kind(LoadLog::empty); //extract first line of file - Mantid::Kernel::extractToEOL(logFileStream,str); + Mantid::Kernel::Strings::extractToEOL(logFileStream,str); if ( !isDateTimeString(str) ) { diff --git a/Code/Mantid/Framework/DataHandling/src/LoadRawHelper.cpp b/Code/Mantid/Framework/DataHandling/src/LoadRawHelper.cpp index 779ae601f528f545d1155638fa1e34e1a4376cfa..7a4dfcc7af0782831c7c1d02034fcf0b730ccad4 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadRawHelper.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadRawHelper.cpp @@ -1247,7 +1247,7 @@ namespace Mantid { path = pathToRawFile.substr(0,pos); } - while (Mantid::Kernel::extractToEOL(adstream,str)) + while (Mantid::Kernel::Strings::extractToEOL(adstream,str)) { std::string fileName; pos = str.find("*"); diff --git a/Code/Mantid/Framework/DataHandling/src/LoadReflTBL.cpp b/Code/Mantid/Framework/DataHandling/src/LoadReflTBL.cpp new file mode 100644 index 0000000000000000000000000000000000000000..990b1470712805dd7bfcda882da100141d3864c7 --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/src/LoadReflTBL.cpp @@ -0,0 +1,383 @@ +/*WIKI* +LoadReflTBl is loads ascii files in Reflectometry TBL format into a tableworkspace. Format accepted is strict to only allow 17 columns of data. + +The 17 columns are split up into rows of 8, so a single row in the TBL file would be split into 3 colums like so: (Where Z is the newly created stitch group index) +A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q + +becomes + +A, B, C, D, E, P, Q, Z +F, G, H, I, J, P, Q, Z +K, L, M, N, O, P, Q, Z +*WIKI*/ +//---------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------- +#include "MantidDataHandling/LoadReflTBL.h" +#include "MantidAPI/FileProperty.h" +#include "MantidAPI/RegisterFileLoader.h" +#include "MantidKernel/Strings.h" +#include "MantidAPI/TableRow.h" +#include <fstream> + +#include <boost/tokenizer.hpp> +#include <Poco/StringTokenizer.h> +// String utilities +#include <boost/algorithm/string.hpp> + +namespace Mantid +{ + namespace DataHandling + { + DECLARE_FILELOADER_ALGORITHM(LoadReflTBL); + + /// Sets documentation strings for this algorithm + void LoadReflTBL::initDocs() + { + this->setWikiSummary("Loads data from a reflectometry table file and stores it in a table [[workspace]] ([[TableWorkspace]] class). "); + this->setOptionalMessage("Loads data from a reflectometry table file and stores it in a table workspace (TableWorkspace class)."); + } + + using namespace Kernel; + using namespace API; + + /// Empty constructor + LoadReflTBL::LoadReflTBL(): m_expectedCommas(16) + { + } + + + /** + * Return the confidence with with this algorithm can load the file + * @param descriptor A descriptor for the file + * @returns An integer specifying the confidence level. 0 indicates it will not be used + */ + int LoadReflTBL::confidence(Kernel::FileDescriptor & descriptor) const + { + const std::string & filePath = descriptor.filename(); + const size_t filenameLength = filePath.size(); + + // Avoid some known file types that have different loaders + int confidence(0); + if( filePath.compare(filenameLength - 12,12,"_runinfo.xml") == 0 || + filePath.compare(filenameLength - 6,6,".peaks") == 0 || + filePath.compare(filenameLength - 10,10,".integrate") == 0 ) + { + confidence = 0; + } + else if(descriptor.isAscii()) + { + std::istream & stream = descriptor.data(); + std::string firstLine; + Kernel::Strings::extractToEOL(stream, firstLine); + std::vector<std::string> columns; + try + { + if (getCells(firstLine, columns) == 17) //right ammount of columns + { + if (filePath.compare(filenameLength - 4,4,".tbl") == 0 ) + { + confidence = 40; + } + else + { + confidence = 20; + } + } + else //incorrect amount of columns + { + confidence = 0; + } + } + catch (std::length_error) + { + confidence = 0; + } + } + return confidence; + } + + + /** + * counte the commas in the line + * @param line the line to count from + * @returns a size_t of how many commas were in line + */ + size_t LoadReflTBL::countCommas (std::string line) const + { + size_t found = 0; + size_t pos=line.find(',',0); + if (pos!=std::string::npos) + { + ++found; + } + while (pos!=std::string::npos) + { + pos=line.find(',',pos+1); + if (pos!=std::string::npos) + { + ++found; + } + } + return found; + } + + + /** + * find pairs of qutoes and store them in a vector + * @param line the line to count from + * @param quoteBounds a vector<vector<size_t>> which will contain the locations of pairs of quotes + * @returns a size_t of how many pairs of quotes were in line + */ + size_t LoadReflTBL::findQuotePairs (std::string line, std::vector<std::vector<size_t>> & quoteBounds) const + { + size_t quoteOne = 0; + size_t quoteTwo = 0; + while (quoteOne!=std::string::npos && quoteTwo!=std::string::npos) + { + if (quoteTwo == 0) + { + quoteOne=line.find('"'); + } + else + { + quoteOne=line.find('"', quoteTwo + 1); + } + if (quoteOne!=std::string::npos) + { + quoteTwo=line.find('"', quoteOne + 1); + if (quoteTwo!=std::string::npos) + { + std::vector<size_t> quotepair; + quotepair.push_back(quoteOne); + quotepair.push_back(quoteTwo); + quoteBounds.push_back(quotepair); + } + } + } + return quoteBounds.size(); + } + + + /** + * parse the CSV format if it's not a simple case of splitting 16 commas + * @param line the line to parse + * @param cols The vector to parse into + * @param quoteBounds a vector<vector<size_t>> containing the locations of pairs of quotes + * @throws std::length_error if anything other than 17 columns (or 16 cell-delimiting commas) is found + */ + void LoadReflTBL::csvParse(std::string line, std::vector<std::string> & cols, std::vector<std::vector<size_t>> & quoteBounds) const + { + size_t pairID = 0; + size_t valsFound = 0; + size_t lastComma = 0; + size_t pos = 0; + bool firstCheck = true; + bool firstCell = true; + cols.clear(); + while (pos!=std::string::npos) + { + if (firstCheck) + { + pos=line.find(','); + firstCheck = false; + //lastpos = pos; + } + else + { + pos=line.find(',',pos+1); + //lastpos = pos; + } + if (pos!=std::string::npos) + { + if (pairID < quoteBounds.size() && pos>quoteBounds.at(pairID).at(0)) + { + if (pos>quoteBounds.at(pairID).at(1)) + { + //use the quote indexes to get the substring + cols.push_back(line.substr(quoteBounds.at(pairID).at(0) + 1, + quoteBounds.at(pairID).at(1) - (quoteBounds.at(pairID).at(0) + 1))); + ++pairID; + ++valsFound; + } + } + else + { + if (firstCell) + { + cols.push_back(line.substr(0,pos)); + firstCell = false; + } + else + { + cols.push_back(line.substr(lastComma + 1,pos - (lastComma + 1))); + } + ++valsFound; + } + lastComma = pos; + } + else + { + if (lastComma + 1 < line.length()) + { + cols.push_back(line.substr(lastComma + 1)); + } + else + { + cols.push_back(""); + } + } + } + if (cols.size() != 17) + { + std::string message = "A line must contain 16 cell-delimiting commas. Found " + boost::lexical_cast<std::string>(cols.size() - 1) + "."; + throw std::length_error(message); + } + } + + + /** + * Return the confidence with with this algorithm can load the file + * @param line the line to parse + * @param cols The vector to parse into + * @returns An integer specifying how many columns were parsed into. This should always be 17. + * @throws std::length_error if anything other than 17 columns (or 16 cell-delimiting commas) is found + */ + size_t LoadReflTBL::getCells(std::string line, std::vector<std::string> & cols) const + { + //first check the number of commas in the line. + size_t found = countCommas(line); + if (found == m_expectedCommas) + { + //If there are 16 that simplifies things and i can get boost to do the hard work + boost::split(cols, line, boost::is_any_of(","), boost::token_compress_off); + } + else if (found < m_expectedCommas) + { + //less than 16 means the line isn't properly formatted. So Throw + std::string message = "A line must contain 16 cell-delimiting commas. Found " + boost::lexical_cast<std::string>(found) + "."; + throw std::length_error(message); + } + else + { + //More than 16 will need further checks as more is only ok when pairs of quotes surround a comma, meaning it isn't a delimiter + std::vector<std::vector<size_t>> quoteBounds; + findQuotePairs(line, quoteBounds); + //if we didn't find any quotes, then there are too many commas and we definitely have too many delimiters + if (quoteBounds.size() == 0) + { + std::string message = "A line must contain 16 cell-delimiting commas. Found " + boost::lexical_cast<std::string>(found) + "."; + throw std::length_error(message); + } + //now go through and split it up manually. Throw if we find ourselves in a positon where we'd add a 18th value to the vector + csvParse(line, cols, quoteBounds); + } + return cols.size(); + } + //-------------------------------------------------------------------------- + // Private methods + //-------------------------------------------------------------------------- + /// Initialisation method. + void LoadReflTBL::init() + { + std::vector<std::string> exts; + exts.push_back(".tbl"); + + declareProperty(new FileProperty("Filename", "", FileProperty::Load, exts), + "The name of the table file to read, including its full or relative path. The file extension must be .tbl"); + declareProperty(new WorkspaceProperty<ITableWorkspace>("OutputWorkspace","",Direction::Output), + "The name of the workspace that will be created."); + } + + /** + * Executes the algorithm. + */ + void LoadReflTBL::exec() + { + std::string filename = getProperty("Filename"); + std::ifstream file(filename.c_str()); + if (!file) + { + throw Exception::FileError("Unable to open file: " , filename); + } + std::string line = ""; + + ITableWorkspace_sptr ws = WorkspaceFactory::Instance().createTable(); + + auto colRuns = ws->addColumn("str","Run(s)"); + auto colTheta = ws->addColumn("str","ThetaIn"); + auto colTrans = ws->addColumn("str","TransRun(s)"); + auto colQmin = ws->addColumn("str","Qmin"); + auto colQmax = ws->addColumn("str","Qmax"); + auto colDqq = ws->addColumn("str","dq/q"); + auto colScale = ws->addColumn("str","Scale"); + auto colStitch = ws->addColumn("int","StitchGroup"); + + colRuns->setPlotType(0); + colTheta->setPlotType(0); + colTrans->setPlotType(0); + colQmin->setPlotType(0); + colQmax->setPlotType(0); + colDqq->setPlotType(0); + colScale->setPlotType(0); + colStitch->setPlotType(0); + + std::vector<std::string> columns; + + int stitchID = 1; + while(Kernel::Strings::extractToEOL(file, line)) + { + //ignore the row if the line is blank + if (line == "" || line == ",,,,,,,,,,,,,,,,") + { + continue; + } + getCells(line, columns); + + //check if the first run in the row has any data associated with it + // 0 = runs, 1 = theta, 2 = trans, 3 = qmin, 4 = qmax + if (columns[0] != "" || columns[1] != "" || columns[2] != "" || columns[3] != "" || columns[4] != "") + { + TableRow row = ws->appendRow(); + for (int i = 0; i < 5; ++i) + { + row << columns.at(i); + } + row << columns.at(15); + row << columns.at(16); + row << stitchID; + } + + //check if the second run in the row has any data associated with it + // 5 = runs, 6 = theta, 7 = trans, 8 = qmin, 9 = qmax + if (columns[5] != "" || columns[6] != "" || columns[7] != "" || columns[8] != "" || columns[9] != "") + { + TableRow row = ws->appendRow(); + for (int i = 5; i < 10; ++i) + { + row << columns.at(i); + } + row << columns.at(15); + row << columns.at(16); + row << stitchID; + } + + //check if the third run in the row has any data associated with it + // 10 = runs, 11 = theta, 12 = trans, 13 = qmin, 14 = qmax + if (columns[10] != "" || columns[11] != "" || columns[12] != "" || columns[13] != "" || columns[14] != "") + { + TableRow row = ws->appendRow(); + for (int i = 10; i < 17; ++i) + { + row << columns.at(i); + } + row << stitchID; + } + ++stitchID; + } + + setProperty("OutputWorkspace", ws); + } + + } // namespace DataHandling +} // namespace Mantid diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflTBL.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflTBL.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06005ddb6401ebb4655f897ad89dd50adcfd778b --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflTBL.cpp @@ -0,0 +1,191 @@ +/*WIKI* +Saves a TableWorkspace at least 8 colunms wide into an ascii file in 17-column Reflectometry TBL format compatible with the old ISIS reflectometry Interface. + +The 8 columns are grouped into rows of 17 according to stitch index, so up to 3 rows int he table would become a single row in the TBL file like so: +(Where Z is an identical stitch group index, and - is ignored as only the first instance of P and Q are used in the file) + +A, B, C, D, E, P, Q, Z +F, G, H, I, J, -, -, Z +K, L, M, N, O, -, -, Z + +becomes + +A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q +==== Limitations ==== +The Algorithm will fail if any stitch index appears more than 3 times, as the old interface does not support more than 3 runs per row. + +Stitch groups of index 0 are treated as non-grouped, and will not be grouped with one another (and by extension can be larger than 3 members). They will however be moved to the end of the file +*WIKI*/ +//---------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------- + +#include "MantidDataHandling/SaveReflTBL.h" +#include "MantidAPI/FileProperty.h" +#include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/TableRow.h" +#include "MantidDataObjects/TableWorkspace.h" +#include <fstream> +#include <boost/tokenizer.hpp> + +namespace Mantid +{ + namespace DataHandling + { + // Register the algorithm into the algorithm factory + DECLARE_ALGORITHM(SaveReflTBL) + + /// Sets documentation strings for this algorithm + void SaveReflTBL::initDocs() + { + this->setWikiSummary("Saves a table [[workspace]] to a reflectometry tbl format ascii file. "); + this->setOptionalMessage("Saves a table workspace to a reflectometry tbl format ascii file."); + } + + using namespace Kernel; + using namespace API; + + /// Empty constructor + SaveReflTBL::SaveReflTBL() : m_sep(','), m_stichgroups(), m_nogroup() + { + } + + /// Initialisation method. + void SaveReflTBL::init() + { + std::vector<std::string> exts; + exts.push_back(".tbl"); + + declareProperty(new FileProperty("Filename", "", FileProperty::Save, exts), + "The filename of the output TBL file."); + + declareProperty(new WorkspaceProperty<ITableWorkspace>("InputWorkspace", "", Direction::Input), + "The name of the workspace containing the data you want to save to a TBL file."); + } + + + /** + * Finds the stitch groups that need to be on the same line + * @param ws : a pointer to a tableworkspace + */ + void SaveReflTBL::findGroups(ITableWorkspace_sptr ws) + { + size_t rowCount = ws->rowCount(); + for (size_t i = 0; i < rowCount; ++i) + { + TableRow row = ws->getRow(i); + if (row.cell<int>(7) != 0) + { + //it was part of a group + m_stichgroups[row.cell<int>(7)].push_back(i); + if (m_stichgroups[row.cell<int>(7)].size() > 3) + { + std::string message = "Cannot save a table with stitch groups that are larger than three runs to Reflectometry .tbl format."; + throw std::length_error(message); + } + } + else + { + //it wasn't part of a group + m_nogroup.push_back(i); + } + } + } + + + /** + * Executes the algorithm. + */ + void SaveReflTBL::exec() + { + // Get the workspace + ITableWorkspace_sptr ws = getProperty("InputWorkspace"); + + findGroups(ws); + + std::string filename = getProperty("Filename"); + std::ofstream file(filename.c_str()); + + if (!file) + { + throw Exception::FileError("Unable to create file: " , filename); + } + + typedef std::map<int, std::vector<size_t>>::iterator map_it_type; + for(map_it_type iterator = m_stichgroups.begin(); iterator != m_stichgroups.end(); ++iterator) + { + std::vector<size_t> & rowNos = iterator->second; + size_t i = 0; + for (; i < rowNos.size(); ++i) + { + //for each row in the group print the first 5 columns to file + TableRow row = ws->getRow(rowNos[i]); + for (int j = 0; j < 5; ++j) + { + writeVal(row.cell<std::string>(j),file); + } + } + //if i comes out of that loop as less than 3, then we need to add the blank runs + for (; i < 3; ++i) + { + for (int j = 0; j < 5; ++j) + { + file << m_sep; + } + } + //now add dq/q and scale from the first row in the group + TableRow row = ws->getRow(rowNos[0]); + writeVal(row.cell<std::string>(5),file); + writeVal(row.cell<std::string>(6),file, false, true); + } + + //now do the same for the ungrouped + + typedef std::vector<size_t>::iterator vec_it_type; + for(vec_it_type iterator = m_nogroup.begin(); iterator != m_nogroup.end(); ++iterator) + { + TableRow row = ws->getRow(*iterator); + for (int j = 0; j < 5; ++j) + { + writeVal(row.cell<std::string>(j),file); + } + for (int k = 0; k < 10; ++k) + { + file << m_sep; + } + //now add dq/q and scale + writeVal(row.cell<std::string>(5),file); + writeVal(row.cell<std::string>(6),file, false, true); + } + file.close(); + } + + /** + * Writes the given value to file, checking if it needs to be surrounded in quotes due to a comma being included + * @param val : the string to be written + * @param file : the ouput file stream + * @param endsep : boolean true to include a comma after the data + * @param endline : boolean true to put an EOL at the end of this data value + */ + void SaveReflTBL::writeVal(std::string & val,std::ofstream & file, bool endsep, bool endline) + { + size_t comPos = val.find(','); + if (comPos != std::string::npos) + { + file << '"' << val << '"'; + } + else + { + file << val; + } + if (endsep) + { + file << m_sep; + } + if (endline) + { + file << std::endl; + } + } + } // namespace DataHandling +} // namespace Mantid diff --git a/Code/Mantid/Framework/DataHandling/test/LoadReflTBLTest.h b/Code/Mantid/Framework/DataHandling/test/LoadReflTBLTest.h new file mode 100644 index 0000000000000000000000000000000000000000..306e42e5c92a3bf58832785e78e9b3a5010f94a6 --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/test/LoadReflTBLTest.h @@ -0,0 +1,300 @@ +#ifndef LOADREFLTBLTEST_H_ +#define LOADREFLTBLTEST_H_ + +#include "cxxtest/TestSuite.h" +#include "MantidDataHandling/LoadReflTBL.h" +#include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/TableRow.h" +#include <Poco/File.h> +#include <fstream> + +using namespace Mantid::API; +using namespace Mantid::DataHandling; +using namespace Mantid::Kernel; +using namespace Mantid::DataObjects; + +class LoadReflTBLTest : public CxxTest::TestSuite +{ +public: + static LoadReflTBLTest *createSuite() { return new LoadReflTBLTest(); } + static void destroySuite(LoadReflTBLTest *suite) { delete suite; } + + LoadReflTBLTest(): m_filename("LoadReflTBLTest.tbl"), m_wsName("LoadReflTBLTestWS"), m_abspath() + { + } + + ~LoadReflTBLTest() + { + } + + void testFileNoQuotes() + { + //create a file with each line containing different but valid data format + std::ofstream file(m_filename.c_str()); + file << "13460,0.7,13463,0.01,0.06,,,,,,,,,,,0.04,2" << std::endl; + file << "13469,0.7,13463,0.01,0.06,13470,2.3,13463,0.035,0.3,,,,,,0.04,2" << std::endl; + file << "13460,0.7,13463,0.01,0.06,13462,2.3,13463,0.035,0.3,13470,2.3,13463,0.035,0.3,0.04,2" << std::endl; + file << "13460,0.7,13463,0.01,0.06,,,,,,13470,2.3,13463,0.035,0.3,0.04,2" << std::endl; + file << ",,,,,13470,2.3,13463,0.035,0.3,,,,,,0.04,2" << std::endl; + file << ",,,,,,,,,,13462,2.3,13463,0.035,0.3,0.04,2" << std::endl; + file.close(); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("LoadReflTBL"); + alg->setRethrows(true); + TS_ASSERT(alg->isInitialized()); + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("Filename", m_filename)); + m_abspath = alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("OutputWorkspace", m_wsName)); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + TS_ASSERT(alg->isExecuted()); + + TS_ASSERT_EQUALS(AnalysisDataService::Instance().doesExist(m_wsName), true); + Workspace_sptr output; + TS_ASSERT_THROWS_NOTHING(output = AnalysisDataService::Instance().retrieve(m_wsName)); + TableWorkspace_sptr outputWS = boost::dynamic_pointer_cast<TableWorkspace>(output); + TS_ASSERT_EQUALS(outputWS->columnCount(),8); + TS_ASSERT_EQUALS(outputWS->rowCount(),10); + + //test the first three rows, equivalent to the first two rows of the file. + TableRow row = outputWS->getRow(0); + TS_ASSERT_EQUALS(row.cell<std::string>(0),"13460"); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(1)),0.7,0.01); + TS_ASSERT_EQUALS(row.cell<std::string>(2),"13463"); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(3)),0.01,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(4)),0.06,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(5)),0.04,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(6)),2,0.01); + TS_ASSERT_EQUALS(row.cell<int>(7),1); + + row = outputWS->getRow(1); + TS_ASSERT_EQUALS(row.cell<std::string>(0),"13469"); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(1)),0.7,0.01); + TS_ASSERT_EQUALS(row.cell<std::string>(2),"13463"); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(3)),0.01,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(4)),0.06,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(5)),0.04,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(6)),2,0.01); + TS_ASSERT_EQUALS(row.cell<int>(7),2); + + row = outputWS->getRow(2); + TS_ASSERT_EQUALS(row.cell<std::string>(0),"13470"); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(1)),2.3,0.01); + TS_ASSERT_EQUALS(row.cell<std::string>(2),"13463"); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(3)),0.035,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(4)),0.3,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(5)),0.04,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(6)),2,0.01); + TS_ASSERT_EQUALS(row.cell<int>(7),2); + + cleanupafterwards(); + } + + void testQuotedFile() + { + //create a file with each line containing different but valid data format + std::ofstream file(m_filename.c_str()); + file << "13460,0.7,\"13463,13464\",0.01,0.06,,,,,,,,,,,0.04,2" << std::endl; + file << "13469,0.7,\"13463,13464\",0.01,0.06,13470,2.3,\"13463,13464\",0.035,0.3,,,,,,0.04,2" << std::endl; + file << "13460,0.7,\"13463,13464\",0.01,0.06,13462,2.3,\"13463,13464\",0.035,0.3,13470,2.3,\"13463,13464\",0.035,0.3,0.04,2" << std::endl; + file << "13460,0.7,\"13463,13464\",0.01,0.06,,,,,,13470,2.3,\"13463,13464\",0.035,0.3,0.04,2" << std::endl; + file << ",,,,,13470,2.3,\"13463,13464\",0.035,0.3,,,,,,0.04,2" << std::endl; + file << ",,,,,,,,,,13462,2.3,\"13463,13464\",0.035,0.3,0.04,2" << std::endl; + file.close(); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("LoadReflTBL"); + alg->setRethrows(true); + TS_ASSERT(alg->isInitialized()); + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("Filename", m_filename)); + m_abspath = alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("OutputWorkspace", m_wsName)); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + TS_ASSERT(alg->isExecuted()); + + TS_ASSERT_EQUALS(AnalysisDataService::Instance().doesExist(m_wsName), true); + Workspace_sptr output; + TS_ASSERT_THROWS_NOTHING(output = AnalysisDataService::Instance().retrieve(m_wsName)); + TableWorkspace_sptr outputWS = boost::dynamic_pointer_cast<TableWorkspace>(output); + TS_ASSERT_EQUALS(outputWS->columnCount(),8); + TS_ASSERT_EQUALS(outputWS->rowCount(),10); + + //test the first three rows, equivalent to the first two rows of the file. + TableRow row = outputWS->getRow(0); + TS_ASSERT_EQUALS(row.cell<std::string>(0),"13460"); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(1)),0.7,0.01); + TS_ASSERT_EQUALS(row.cell<std::string>(2),"13463,13464"); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(3)),0.01,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(4)),0.06,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(5)),0.04,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(6)),2,0.01); + TS_ASSERT_EQUALS(row.cell<int>(7),1); + + row = outputWS->getRow(1); + TS_ASSERT_EQUALS(row.cell<std::string>(0),"13469"); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(1)),0.7,0.01); + TS_ASSERT_EQUALS(row.cell<std::string>(2),"13463,13464"); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(3)),0.01,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(4)),0.06,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(5)),0.04,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(6)),2,0.01); + TS_ASSERT_EQUALS(row.cell<int>(7),2); + + row = outputWS->getRow(2); + TS_ASSERT_EQUALS(row.cell<std::string>(0),"13470"); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(1)),2.3,0.01); + TS_ASSERT_EQUALS(row.cell<std::string>(2),"13463,13464"); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(3)),0.035,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(4)),0.3,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(5)),0.04,0.001); + TS_ASSERT_DELTA(boost::lexical_cast<double>(row.cell<std::string>(6)),2,0.01); + TS_ASSERT_EQUALS(row.cell<int>(7),2); + + cleanupafterwards(); + } + + void testFewColumns() + { + //create a file with each line containing too few columns + std::ofstream file(m_filename.c_str()); + file << "13460,0.7,\"13463,13464\",0.01,0.06,,,,,,,0.04,2" << std::endl; + file << "13469,0.7,\"13463,13464\",0.01,0.06,13470,2.3,\"13463,13464\",0.035,0.3,,0.04,2" << std::endl; + file << "13460,0.7,\"13463,13464\",,\"13463,13464\",,13470,2.3,\"13463,13464\",0.035,0.04,2" << std::endl; + file << "13460,0.7,\"13463,13464\",0.01,0.06,,13470,2.3,\"13463,13464\",0.035,0.3,0.04,2" << std::endl; + file << "13470,2.3,\"13463,13464\",0.035,0.3,,0.04,2" << std::endl; + file << ",,,,13462,2.3,\"13463,13464\",0.035,0.3,0.04,2" << std::endl; + file.close(); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("LoadReflTBL"); + alg->setRethrows(true); + TS_ASSERT(alg->isInitialized()); + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("Filename", m_filename)); + m_abspath= alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("OutputWorkspace", m_wsName)); + TS_ASSERT_THROWS_ANYTHING(alg->execute()); + + TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove()); + } + + void testManyColumns() + { + //create a file with each line containing too many columns + std::ofstream file(m_filename.c_str()); + file << "13460,0.7,13463,0.01,0.06,,,,,,,,,,,0.04,2,,,,0.04,2" << std::endl; + file << "13469,0.7,13463,0.01,0.06,13470,2.3,13463,0.035,0.3,,,,,,0.04,2,,,,0.04,2" << std::endl; + file << "13460,0.7,13463,0.01,0.06,13462,2.3,13463,0.035,0.3,13470,2.3,13463,0.035,0.3,0.04,2,,,,0.04,2" << std::endl; + file << "13460,0.7,13463,0.01,0.06,,,,,,13470,2.3,13463,0.035,0.3,0.04,2,,,,0.04,2" << std::endl; + file << ",,,,,13470,2.3,13463,0.035,0.3,,,,,,0.04,2,,,,0.04,2" << std::endl; + file << ",,,,,,,,,13462,2.3,13463,0.035,0.3,0.04,2,,,,0.04,2" << std::endl; + file.close(); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("LoadReflTBL"); + alg->setRethrows(true); + TS_ASSERT(alg->isInitialized()); + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("Filename", m_filename)); + m_abspath= alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("OutputWorkspace", m_wsName)); + TS_ASSERT_THROWS_ANYTHING(alg->execute()); + + TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove()); + } + + void testManyColumnsTwo() + { + //create a file with each line containing too many columns + std::ofstream file(m_filename.c_str()); + file << "13460,0.7,\"13463,0.01\",0.06,,,,,,,,,,,0.04,2,,,,0.04,2" << std::endl; + file << "13469,0.7,13463,\"0.01,0.06\",13470,2.3,13463,0.06,\"13470,0.06,13470\",2.3,13463,0.035,0.3,,,,,,,,,0.04,2,,,,0.04,2" << std::endl; + file << "13460,0.7,13463,0.01,0.06,13462,2.3,13463,0.035,0.3,13470,2.3,13463,0.035,0.3,0.04,2,,,,0.04,2" << std::endl; + file << "13460,0.7,\"13463,0.01\",0.06,,,,,,,,,,13470,2.3,\"13463,0.035\",0.3,0.04,2,,,,0.04,2" << std::endl; + file << ",,,,,13470,2.3,\"13463,0.035\",0.3,,,,,,,,,0.04,2,,,,0.04,2" << std::endl; + file << ",,,,,,,,,,,,13462,2.3,\"13463,0.035\",0.3,0.04,2,,,,0.04,2" << std::endl; + file.close(); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("LoadReflTBL"); + alg->setRethrows(true); + TS_ASSERT(alg->isInitialized()); + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("Filename", m_filename)); + m_abspath= alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("OutputWorkspace", m_wsName)); + TS_ASSERT_THROWS_ANYTHING(alg->execute()); + + TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove()); + } + + void testBlankFile() + { + std::ofstream file(m_filename.c_str()); + file.close(); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("LoadReflTBL"); + alg->setRethrows(true); + TS_ASSERT(alg->isInitialized()); + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("Filename", m_filename)); + m_abspath = alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("OutputWorkspace", m_wsName)); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + TS_ASSERT(alg->isExecuted()); + + TS_ASSERT_EQUALS(AnalysisDataService::Instance().doesExist(m_wsName), true); + Workspace_sptr output; + TS_ASSERT_THROWS_NOTHING(output = AnalysisDataService::Instance().retrieve(m_wsName)); + TableWorkspace_sptr outputWS = boost::dynamic_pointer_cast<TableWorkspace>(output); + + //the columns should be there, but no rows + TS_ASSERT_EQUALS(outputWS->columnCount(),8); + TS_ASSERT_EQUALS(outputWS->rowCount(),0); + + cleanupafterwards(); + } + + void testNoDataFile() + { + //create a file with content, and the right amount of delimiters, but no valid data + std::ofstream file(m_filename.c_str()); + file << ",,,,,,,,,,,,,,,," << std::endl; + file << ",,,,,,,,,,,,,,,," << std::endl; + file << ",,,,,,,,,,,,,,,," << std::endl; + file << ",,,,,,,,,,,,,,,," << std::endl; + file << ",,,,,,,,,,,,,,,," << std::endl; + file << ",,,,,,,,,,,,,,,," << std::endl; + file << ",,,,,,,,,,,,,,,," << std::endl; + file.close(); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("LoadReflTBL"); + alg->setRethrows(true); + TS_ASSERT(alg->isInitialized()); + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("Filename", m_filename)); + m_abspath = alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("OutputWorkspace", m_wsName)); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + TS_ASSERT(alg->isExecuted()); + + TS_ASSERT_EQUALS(AnalysisDataService::Instance().doesExist(m_wsName), true); + Workspace_sptr output; + TS_ASSERT_THROWS_NOTHING(output = AnalysisDataService::Instance().retrieve(m_wsName)); + TableWorkspace_sptr outputWS = boost::dynamic_pointer_cast<TableWorkspace>(output); + + //the columns should be there, but no rows + TS_ASSERT_EQUALS(outputWS->columnCount(),8); + TS_ASSERT_EQUALS(outputWS->rowCount(),0); + + cleanupafterwards(); + } + +private: + const std::string m_filename; + const std::string m_wsName; + std::string m_abspath; + void cleanupafterwards() + { + TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().remove(m_wsName)); + TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove()); + } +}; + + +#endif //LOADREFLTBLTEST_H_ diff --git a/Code/Mantid/Framework/DataHandling/test/SaveReflTBLTest.h b/Code/Mantid/Framework/DataHandling/test/SaveReflTBLTest.h new file mode 100644 index 0000000000000000000000000000000000000000..ea927d34744131dea44013e156fbb78bdadc0b6b --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/test/SaveReflTBLTest.h @@ -0,0 +1,264 @@ +#ifndef SAVEREFLTBLTEST_H_ +#define SAVEREFLTBLTEST_H_ + +#include <cxxtest/TestSuite.h> +#include "MantidDataHandling/SaveReflTBL.h" +#include "MantidDataObjects/Workspace2D.h" +#include "MantidAPI/FrameworkManager.h" +#include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/TableRow.h" +#include <fstream> +#include <Poco/File.h> + +using namespace Mantid::API; +using namespace Mantid::DataHandling; +using namespace Mantid::DataObjects; + +class SaveReflTBLTest : public CxxTest::TestSuite +{ + +public: + + static SaveReflTBLTest *createSuite() { return new SaveReflTBLTest(); } + static void destroySuite(SaveReflTBLTest *suite) { delete suite; } + + SaveReflTBLTest(): m_name("SaveReflTBLTestWS"), m_filename("SaveReflTBLTest.tbl"), m_abspath() + { + } + + ~SaveReflTBLTest() + { + } + + void testNoQuotes() + { + ITableWorkspace_sptr ws = CreateWorkspace(); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflTBL"); + alg->setRethrows(true); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + m_abspath = alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflTBL"); + } + + TS_ASSERT( Poco::File(m_abspath).exists() ); + std::ifstream file(m_abspath.c_str()); + std::string line = ""; + getline(file,line); + TS_ASSERT_EQUALS(line,"13460,0.7,13463,0.01,0.06,13462,2.3,13463,0.035,0.3,13470,2.3,13463,0.035,0.3,0.04,2"); + getline(file,line); + TS_ASSERT_EQUALS(line,"13460,0.7,13463,0.01,0.06,13462,2.3,13463,0.035,0.3,,,,,,0.04,2"); + getline(file,line); + TS_ASSERT_EQUALS(line,"13470,2.3,13463,0.035,0.3,13462,2.3,13463,0.035,0.3,,,,,,0.04,2"); + getline(file,line); + TS_ASSERT_EQUALS(line,"13470,2.3,13463,0.035,0.3,,,,,,,,,,,0.04,2"); + getline(file,line); + TS_ASSERT_EQUALS(line,"13460,0.7,13463,0.01,0.06,,,,,,,,,,,0.04,2"); + + file.close(); + cleanupafterwards(); + } + + void testQuotes() + { + ITableWorkspace_sptr ws = CreateWorkspace(); + + TableRow row = ws->appendRow(); + row << "13460" << "0.7" << "13463,13464" << "0.01" << "0.06" << "0.04" << "2" << 4; + + row = ws->appendRow(); + row << "13470" << "2.3" << "13463,13464" << "0.035" << "0.3" << "0.04" << "2" << 5; + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflTBL"); + alg->setRethrows(true); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + m_abspath = alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflTBL"); + } + + TS_ASSERT( Poco::File(m_abspath).exists() ); + std::ifstream file(m_abspath.c_str()); + std::string line = ""; + getline(file,line); + TS_ASSERT_EQUALS(line,"13460,0.7,13463,0.01,0.06,13462,2.3,13463,0.035,0.3,13470,2.3,13463,0.035,0.3,0.04,2"); + getline(file,line); + TS_ASSERT_EQUALS(line,"13460,0.7,13463,0.01,0.06,13462,2.3,13463,0.035,0.3,,,,,,0.04,2"); + getline(file,line); + TS_ASSERT_EQUALS(line,"13470,2.3,13463,0.035,0.3,13462,2.3,13463,0.035,0.3,,,,,,0.04,2"); + getline(file,line); + TS_ASSERT_EQUALS(line,"13470,2.3,13463,0.035,0.3,13460,0.7,\"13463,13464\",0.01,0.06,,,,,,0.04,2"); + getline(file,line); + TS_ASSERT_EQUALS(line,"13470,2.3,\"13463,13464\",0.035,0.3,,,,,,,,,,,0.04,2"); + getline(file,line); + TS_ASSERT_EQUALS(line,"13460,0.7,13463,0.01,0.06,,,,,,,,,,,0.04,2"); + + file.close(); + cleanupafterwards(); + } + + void testFourGroupFail() + { + ITableWorkspace_sptr ws = CreateWorkspace(); + + TableRow row = ws->appendRow(); + row << "13460" << "0.7" << "13463" << "0.01" << "0.06" << "0.04" << "2" << 1; + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflTBL"); + alg->setRethrows(true); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + m_abspath = alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_ANYTHING(alg->execute()); + + // the algorithm shouldn't have written a file to disk + TS_ASSERT( !Poco::File(m_abspath).exists() ); + TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().remove(m_name)); + } + + void testNotEnoughColumns() + { + ITableWorkspace_sptr ws = WorkspaceFactory::Instance().createTable(); + AnalysisDataService::Instance().addOrReplace(m_name, ws); + auto colRuns = ws->addColumn("str","Run(s)"); + auto colTheta = ws->addColumn("str","ThetaIn"); + auto colTrans = ws->addColumn("str","TransRun(s)"); + auto colQmin = ws->addColumn("str","Qmin"); + auto colQmax = ws->addColumn("str","Qmax"); + auto colDqq = ws->addColumn("str","dq/q"); + auto colScale = ws->addColumn("str","Scale"); + + colRuns->setPlotType(0); + colTheta->setPlotType(0); + colTrans->setPlotType(0); + colQmin->setPlotType(0); + colQmax->setPlotType(0); + colDqq->setPlotType(0); + colScale->setPlotType(0); + + TableRow row = ws->appendRow(); + row << "13460" << "0.7" << "13463" << "0.01" << "0.06" << "0.04" << "2"; + + row = ws->appendRow(); + row << "13462" << "2.3" << "13463" << "0.035" << "0.3" << "0.04" << "2"; + + row = ws->appendRow(); + row << "13470" << "2.3" << "13463" << "0.035" << "0.3" << "0.04" << "2"; + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflTBL"); + alg->setRethrows(true); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + m_abspath = alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_ANYTHING(alg->execute()); + + // the algorithm shouldn't have written a file to disk + TS_ASSERT( !Poco::File(m_abspath).exists() ); + TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().remove(m_name)); + } + + void testLoadWithLoadReflTBL() + { + ITableWorkspace_sptr ws = CreateWorkspace(); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflTBL"); + alg->setRethrows(true); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + m_abspath = alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_NOTHING(alg->execute()); + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflTBL"); + } + + TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().remove(m_name)); + + Mantid::API::IAlgorithm_sptr algLoad = Mantid::API::AlgorithmManager::Instance().create("LoadReflTBL"); + algLoad->setRethrows(true); + algLoad->setPropertyValue("OutputWorkspace", m_name); + algLoad->setPropertyValue("Filename", m_abspath); + TS_ASSERT_THROWS_NOTHING(algLoad->execute()); + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run LoadReflTBL"); + } + + cleanupafterwards(); + } + +private: + + void cleanupafterwards() + { + TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().remove(m_name)); + TS_ASSERT_THROWS_NOTHING(Poco::File(m_abspath).remove()); + } + + ITableWorkspace_sptr CreateWorkspace() + { + ITableWorkspace_sptr ws = WorkspaceFactory::Instance().createTable(); + AnalysisDataService::Instance().addOrReplace(m_name, ws); + auto colRuns = ws->addColumn("str","Run(s)"); + auto colTheta = ws->addColumn("str","ThetaIn"); + auto colTrans = ws->addColumn("str","TransRun(s)"); + auto colQmin = ws->addColumn("str","Qmin"); + auto colQmax = ws->addColumn("str","Qmax"); + auto colDqq = ws->addColumn("str","dq/q"); + auto colScale = ws->addColumn("str","Scale"); + auto colStitch = ws->addColumn("int","StitchGroup"); + + colRuns->setPlotType(0); + colTheta->setPlotType(0); + colTrans->setPlotType(0); + colQmin->setPlotType(0); + colQmax->setPlotType(0); + colDqq->setPlotType(0); + colScale->setPlotType(0); + colStitch->setPlotType(0); + + TableRow row = ws->appendRow(); + row << "13460" << "0.7" << "13463" << "0.01" << "0.06" << "0.04" << "2" << 1; + + row = ws->appendRow(); + row << "13462" << "2.3" << "13463" << "0.035" << "0.3" << "0.04" << "2" << 1; + + row = ws->appendRow(); + row << "13470" << "2.3" << "13463" << "0.035" << "0.3" << "0.04" << "2" << 1; + + row = ws->appendRow(); + row << "13460" << "0.7" << "13463" << "0.01" << "0.06" << "0.04" << "2" << 2; + + row = ws->appendRow(); + row << "13462" << "2.3" << "13463" << "0.035" << "0.3" << "0.04" << "2" << 2; + + row = ws->appendRow(); + row << "13470" << "2.3" << "13463" << "0.035" << "0.3" << "0.04" << "2" << 3; + + row = ws->appendRow(); + row << "13460" << "0.7" << "13463" << "0.01" << "0.06" << "0.04" << "2" << 0; + + //this row's last two cells will show in the tableworkspace, but the first row in stich group 3's will take priority when saving + row = ws->appendRow(); + row << "13462" << "2.3" << "13463" << "0.035" << "0.3" << "0.4" << "3" << 3; + + row = ws->appendRow(); + row << "13470" << "2.3" << "13463" << "0.035" << "0.3" << "0.04" << "2" << 4; + + return ws; + } + + std::string m_name; + std::string m_filename; + std::string m_abspath; +}; +#endif /*SAVEREFLTBLTEST_H_*/ diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/LogParser.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/LogParser.h index 5a2fc42770f7bc8c9b339fc41915028975a756bb..fa4e86e99f37865c2952850c3f9d57e8e9da1530 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/LogParser.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/LogParser.h @@ -123,11 +123,6 @@ namespace Mantid /// Returns the mean value if the property is TimeSeriesProperty<double> MANTID_KERNEL_DLL double timeMean(const Kernel::Property* p); - /// Extract a line from input stream, discarding any EOL characters encountered - MANTID_KERNEL_DLL std::istream& extractToEOL(std::istream& is, std::string& str); - - - } // namespace Kernel } // namespace Mantid diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/Strings.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/Strings.h index c9aa68e5f33ed5c8a06429350bf404a80ed4e4c1..e5862388102d9f2229d3bbceadbbd03220bc30df 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/Strings.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/Strings.h @@ -173,6 +173,9 @@ namespace Mantid MANTID_KERNEL_DLL std::vector<int> parseRange(const std::string& str, const std::string& elemSep = ",", const std::string& rangeSep = "-"); + /// Extract a line from input stream, discarding any EOL characters encountered + MANTID_KERNEL_DLL std::istream& extractToEOL(std::istream& is, std::string& str); + } // NAMESPACE Strings } // NAMESPACE Kernel diff --git a/Code/Mantid/Framework/Kernel/src/LogParser.cpp b/Code/Mantid/Framework/Kernel/src/LogParser.cpp index d38e68bb65c6568388afcaf6d332ff49a4edfb2d..52cccf1bcb25c4355eca02264b0d039b020a4bb5 100644 --- a/Code/Mantid/Framework/Kernel/src/LogParser.cpp +++ b/Code/Mantid/Framework/Kernel/src/LogParser.cpp @@ -2,9 +2,9 @@ // Includes //---------------------------------------------------------------------- #include "MantidKernel/LogParser.h" +#include "MantidKernel/Strings.h" #include "MantidKernel/Logger.h" #include "MantidKernel/PropertyWithValue.h" - #include "MantidKernel/TimeSeriesProperty.h" #include <algorithm> @@ -64,7 +64,7 @@ namespace Mantid // MG 22/09/09: If the log file was written on a Windows machine and then read on a Linux machine, std::getline will // leave CR at the end of the string and this causes problems when reading out the log values. Mantid::extractTOEOL // extracts all EOL characters - while(Mantid::Kernel::extractToEOL(file,str)) + while(Mantid::Kernel::Strings::extractToEOL(file,str)) { if( str.empty() || str[0]=='#') {continue;} @@ -375,48 +375,6 @@ namespace Mantid } - - - /** - * Extract a string until an EOL character is reached. There are 3 scenarios that we need to deal with - * 1) Windows-style - CRLF ('\\r\\n'); - * 2) Unix-style - LF ('\\n'); - * 3) Old MAC style - CR ('\\r'). - * This function will give the string preceding any of these sequences - * @param is :: The input stream to read from - * @param str :: The output string to use to accumulate the line - * @returns A reference to the input stream - */ - std::istream& extractToEOL(std::istream& is, std::string& str) - { - // Empty the string - str = ""; - char c('\0'); - while( is.get(c) ) - { - if( c == '\r' ) - { - c = static_cast<char>(is.peek()); - if( c == '\n' ) - { - //Extract this as well - is.get(); - } - break; - } - else if( c == '\n') - { - break; - } - else - { - //Accumulate the string - str += c; - } - } - return is; - } - } // namespace Geometry } // namespace Mantid diff --git a/Code/Mantid/Framework/Kernel/src/Strings.cpp b/Code/Mantid/Framework/Kernel/src/Strings.cpp index 88a39b6b41330d1dcc361832b5c111c666111cee..0b85c1a4d0434eac04bec12adce25f3a37f5e172 100644 --- a/Code/Mantid/Framework/Kernel/src/Strings.cpp +++ b/Code/Mantid/Framework/Kernel/src/Strings.cpp @@ -1161,6 +1161,46 @@ namespace Mantid return result; } + /** + * Extract a string until an EOL character is reached. There are 3 scenarios that we need to deal with + * 1) Windows-style - CRLF ('\\r\\n'); + * 2) Unix-style - LF ('\\n'); + * 3) Old MAC style - CR ('\\r'). + * This function will give the string preceding any of these sequences + * @param is :: The input stream to read from + * @param str :: The output string to use to accumulate the line + * @returns A reference to the input stream + */ + std::istream& extractToEOL(std::istream& is, std::string& str) + { + // Empty the string + str = ""; + char c('\0'); + while( is.get(c) ) + { + if( c == '\r' ) + { + c = static_cast<char>(is.peek()); + if( c == '\n' ) + { + //Extract this as well + is.get(); + } + break; + } + else if( c == '\n') + { + break; + } + else + { + //Accumulate the string + str += c; + } + } + return is; + } + /// \cond TEMPLATE template MANTID_KERNEL_DLL int section(std::string&,double&); template MANTID_KERNEL_DLL int section(std::string&,float&);