17#include <boost/algorithm/string/predicate.hpp>
18#include <boost/algorithm/string/split.hpp>
19#include <boost/algorithm/string/trim.hpp>
20#include <boost/regex.hpp>
33bool space(
const char &c) {
return isspace(c) != 0; }
39bool notSpace(
const char &c) {
return !space(c); }
45bool allSpaces(
const std::string &str) {
return std::all_of(str.begin(), str.end(), space); }
54std::string repeatAndJoin(
const std::string &str,
const std::string &delim,
const int &
n) {
55 std::string result =
"";
56 for (
int i = 0; i <
n - 1; i++) {
57 result += str + delim;
97 auto &file = descriptor.
data();
101 std::getline(file, line);
102 bool ffvFound = boost::starts_with(line,
"FileFormatVersion");
105 boost::regex kvPair(R
"([\w_]+\s+[\w\d\.\-]+(\s+[\w\d\.\-\$]+)*)");
106 int kvPairsFound = 0;
108 for (
int i = 0; i < 3 && !line.empty(); i++) {
109 if (boost::regex_match(line, kvPair)) {
112 std::getline(file, line);
118 if (kvPairsFound < 10)
122 while (std::getline(file, line) && line.empty())
129 return 15 + 3 * ffvFound + 3 * beginFound;
137 "Name of the SESANS file to load");
139 "The name to use for the output workspace");
147 std::ifstream infile(filename);
151 g_log.
error(
"Unable to open file " + filename);
159 std::getline(infile, line);
162 if (!boost::starts_with(line,
"FileFormatVersion"))
163 throwFormatError(line,
"File must begin by providing FileFormatVersion", lineNum);
182 newWorkspace->setTitle(attributes[
"DataFileTitle"]);
183 newWorkspace->mutableSample().setName(attributes[
"Sample"]);
184 newWorkspace->mutableSample().setThickness(std::stod(attributes[
"Thickness"]));
200 std::pair<std::string, std::string> attr;
204 if (!allSpaces(line)) {
208 attributes.insert(attr);
210 }
while (std::getline(infile, line) && !boost::starts_with(line,
m_beginData));
226 std::getline(infile, line);
227 std::vector<std::string> columnHeaders;
229 boost::split(columnHeaders, line, isspace, boost::token_compress_on);
233 if (std::find(columnHeaders.begin(), columnHeaders.end(), header) == columnHeaders.end())
234 throwFormatError(line,
"Failed to supply mandatory column header: \"" + header +
"\"", lineNum);
236 std::string numberRegex = R
"((-?\d+(\.\d+)?([Ee][-\+]?\d+)?))";
239 std::string rawRegex =
"^\\s*" + repeatAndJoin(numberRegex,
"\\s+",
static_cast<int>(columnHeaders.size())) +
"\\s*$";
240 boost::regex lineRegex(rawRegex);
245 while (std::getline(infile, line)) {
249 std::vector<std::string> tokens;
251 if (boost::regex_match(line, lineRegex)) {
253 boost::split(tokens, line, isspace, boost::token_compress_on);
255 for (
size_t i = 0; i < tokens.size(); i++)
256 columns[columnHeaders[i]].emplace_back(std::stod(tokens[i]));
259 std::to_string(columnHeaders.size()) +
" numbers, but got \"" + line +
"\"");
276 std::pair<std::string, std::string> attribute;
277 const auto &line = boost::trim_copy(untrimmedLine);
279 auto i = line.begin();
281 auto j = find_if(i, line.end(), space);
286 attribute.first = std::string(i, j);
289 i = find_if(j, line.end(), notSpace);
294 attribute.second = std::string(i, line.end());
306 std::string output =
"Badly formed line at line " +
std::to_string(lineNum) +
": \"" + line +
"\"\n(" + message +
")";
308 throw std::runtime_error(output);
316 if (!attributes.count(attr)) {
317 std::string err =
"Failed to supply parameter: \"" + attr +
"\"";
319 throw std::runtime_error(err);
337 auto &dataX = newWorkspace->mutableX(0);
338 auto &dataY = newWorkspace->mutableY(0);
339 auto &dataE = newWorkspace->mutableE(0);
341 for (
size_t i = 0; i < histogramLength; i++) {
342 dataX[i] = xValues[i];
343 dataY[i] = yValues[i];
344 dataE[i] = eValues[i];
std::unordered_map< std::string, Column > ColumnMap
std::unordered_map< std::string, std::string > AttributeMap
#define DECLARE_FILELOADER_ALGORITHM(classname)
DECLARE_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro when wri...
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
@ Load
allowed here which will be passed to the algorithm
A property class for workspaces.
LoadSESANS : Load a workspace in the SESANS file format.
void throwFormatError(const std::string &line, const std::string &message, const int &lineNum)
Helper function to throw an error relating to the format of the file.
ColumnMap consumeData(std::ifstream &infile, std::string &line, int &lineNum)
Read numerical data from the file into a map of the form [column name] -> [column data].
const std::vector< std::string > m_mandatoryAttributes
const std::string m_beginData
const std::vector< std::string > m_mandatoryColumnHeaders
const std::string m_depolarisationError
void init() override
Initialise the algorithm.
API::MatrixWorkspace_sptr makeWorkspace(ColumnMap columns)
Create a new workspace with the columns read from the file.
const std::string category() const override
Get algorithm's category.
std::pair< std::string, std::string > splitHeader(const std::string &line, const int &lineNum)
Split a header into a key-value pair delimited by whitespace, where the first token is the key and th...
AttributeMap consumeHeaders(std::ifstream &infile, std::string &line, int &lineNum)
Read headers from the input file into the attribute map, until BEGIN_DATA is found.
const std::vector< std::string > m_fileExtensions
void exec() override
Execute the algorithm.
const std::string m_spinEchoLength
int confidence(Kernel::FileDescriptor &descriptor) const override
Get the confidence that this algorithm can load a file.
int version() const override
Get algorithm's version number.
const std::string m_depolarisation
void checkMandatoryHeaders(const AttributeMap &attributes)
Make sure that all mandatory headers are supplied in the file.
const std::string summary() const override
Get summary of algorithm.
Records the filename and the description of failure.
Defines a wrapper around an open file.
static bool isAscii(const std::string &filename, const size_t nbytes=256)
Returns true if the file is considered ascii.
std::istream & data()
Access the open file stream.
const std::string & extension() const
Access the file extension.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Output
An output workspace.