Mantid
Loading...
Searching...
No Matches
PDLoadCharacterizations.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
11#include "MantidAPI/TableRow.h"
19#include <boost/algorithm/string.hpp>
20#include <boost/regex.hpp>
21#include <filesystem>
22#include <fstream>
23#include <set>
24
25using namespace Mantid::API;
26using namespace Mantid::Kernel;
27
28namespace Mantid::DataHandling {
29
30// Register the algorithm into the AlgorithmFactory
32
33namespace {
35static const std::string IPARM_KEY("Instrument parameter file:");
36static const std::string L1_KEY("L1");
37static const std::string ZERO("0.");
38static const std::string EXP_INI_VAN_KEY("Vana");
39static const std::string EXP_INI_EMPTY_KEY("VanaBg");
40static const std::string EXP_INI_CAN_KEY("MTc");
43static const size_t INFO_OFFSET_V1(6);
44// in the filenames vector, each index has a unique location
45static const int F_INDEX_V0 = 0;
46static const int F_INDEX_V1 = 1;
47static const int F_INDEX_EXPINI = 2;
48static const int F_INDEX_SIZE = 3;
50const boost::regex V1_TABLE_REG_EXP{"^freq.*\\s+w.*l.*\\s+"
51 "van\\s+van_back\\s+"
52 "mt_env\\s+mt_instr(.+)"};
53const boost::regex VERSION_REG_EXP{"^version=([0-9]+)"};
54
59std::vector<std::string> extra_columns(const std::vector<std::string> &filenames) {
60 // only version1 files generate extra columns
61 if (filenames[F_INDEX_V1].empty())
62 return std::vector<std::string>();
63
64 std::set<std::string> columnSet;
65
66 // parse the version1 file
67 std::ifstream file(filenames[F_INDEX_V1].c_str(), std::ios_base::binary);
68 if (!file) {
69 throw Exception::FileError("Unable to open file", filenames[F_INDEX_V1]);
70 }
71
72 for (std::string line = Strings::getLine(file); !file.eof(); Strings::getLine(file, line)) {
73 boost::smatch result;
74 // all instances of table headers
75 if (boost::regex_search(line, result, V1_TABLE_REG_EXP)) {
76 if (result.size() == 2) {
77 line = Strings::strip(result[1]);
79 for (const auto &token : tokenizer) {
80 columnSet.insert(token);
81 }
82 }
83 }
84 // TODO need to get the "extras" line
85 }
86 file.close();
87
88 // convert the result to a sorted vector
89 std::vector<std::string> columnnames;
90 std::copy(columnSet.begin(), columnSet.end(), std::back_inserter(columnnames));
91 std::sort(columnnames.begin(), columnnames.end());
92
93 return columnnames;
94}
95} // namespace
96
97//----------------------------------------------------------------------------------------------
99const std::string PDLoadCharacterizations::name() const { return "PDLoadCharacterizations"; }
100
102int PDLoadCharacterizations::version() const { return 1; }
103
105const std::string PDLoadCharacterizations::category() const { return "Workflow\\DataHandling"; }
106
107//----------------------------------------------------------------------------------------------
111 const auto exts = std::vector<std::string>({".txt"});
112 declareProperty(std::make_unique<MultipleFileProperty>("Filename", exts), "Characterizations file");
113 declareProperty(std::make_unique<FileProperty>("ExpIniFilename", "", FileProperty::OptionalLoad, "ini"),
114 "(Optional) exp.ini file used at NOMAD");
115
116 declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>("OutputWorkspace", "", Direction::Output),
117 "Output for the information of characterizations and runs");
118
119 declareProperty("IParmFilename", std::string(""), "Name of the gsas instrument parameter file.", Direction::Output);
120 declareProperty("PrimaryFlightPath", EMPTY_DBL(), "Primary flight path L1 of the powder diffractomer. ",
122 declareProperty(std::make_unique<ArrayProperty<int32_t>>("SpectrumIDs", Direction::Output),
123 "Spectrum Nos (note that it is not detector ID or workspace "
124 "indices). The list must be either empty or have a size "
125 "equal to input workspace's histogram number. ");
127 "Secondary flight (L2) paths for each detector. Number of L2 "
128 "given must be same as number of histogram.");
129 declareProperty(std::make_unique<ArrayProperty<double>>("Polar", Direction::Output),
130 "Polar angles (two thetas) for detectors. Number of 2theta "
131 "given must be same as number of histogram.");
132 declareProperty(std::make_unique<ArrayProperty<double>>("Azimuthal", Direction::Output),
133 "Azimuthal angles (out-of-plane) for detectors. "
134 "Number of azimuthal angles given must be same as number of histogram.");
135}
136
137//----------------------------------------------------------------------------------------------
141 auto filenames = this->getFilenames();
142 const std::vector<std::string> canColumnNames = extra_columns(filenames);
143
144 // setup the default table workspace for the characterization runs
146 wksp->addColumn("double", "frequency");
147 wksp->addColumn("double", "wavelength");
148 wksp->addColumn("int", "bank");
149 wksp->addColumn("str", "vanadium");
150 wksp->addColumn("str", "vanadium_background");
151 wksp->addColumn("str", "container");
152 wksp->addColumn("str", "empty_environment");
153 wksp->addColumn("str", "empty_instrument");
154 wksp->addColumn("str", "d_min"); // b/c it is an array for NOMAD
155 wksp->addColumn("str", "d_max"); // b/c it is an array for NOMAD
156 wksp->addColumn("double", "tof_min");
157 wksp->addColumn("double", "tof_max");
158 wksp->addColumn("double", "wavelength_min");
159 wksp->addColumn("double", "wavelength_max");
160 for (const auto &canColumnName : canColumnNames) {
161 wksp->addColumn("str", canColumnName); // all will be strings
162 }
163
164 // first file is assumed to be version 0
165 this->readVersion0(filenames[F_INDEX_V0], wksp);
166
167 // optional second file has container dependent information
168 this->readVersion1(filenames[F_INDEX_V1], wksp);
169
170 // optional exp.ini file for NOMAD
171 this->readExpIni(filenames[F_INDEX_EXPINI], wksp);
172
173 this->setProperty("OutputWorkspace", wksp);
174}
175
176namespace {
177int getVersion(const std::string &filename) {
178 std::ifstream file(filename.c_str(), std::ios_base::binary);
179 if (!file.is_open()) {
180 throw Exception::FileError("Unable to open file", filename);
181 }
182 // first line must be version string
183 std::string line = Strings::getLine(file);
184 file.close(); // cleanup
185
186 boost::smatch result;
187 if (boost::regex_search(line, result, VERSION_REG_EXP) && result.size() == 2) {
188 return boost::lexical_cast<int>(result[1]);
189 }
190
191 // otherwise it is a version=0
192 return 0;
193}
194
195template <typename T>
196T lexical_cast(const std::string &value, const std::string &filename, const int linenum,
197 const std::string &label = "") {
198 try {
199 return boost::lexical_cast<T>(value);
200 } catch (boost::bad_lexical_cast &e) {
201 // check for lexical cast and rethrow as parse error
202 if (label.empty())
203 throw Exception::ParseError("While converting \"" + value + "\": " + e.what(), filename, linenum);
204 else
205 throw Exception::ParseError("In " + label + " while converting \"" + value + "\": " + e.what(), filename,
206 linenum);
207 }
208}
209} // anonymous namespace
210
216std::vector<std::string> PDLoadCharacterizations::getFilenames() {
217 // get the values from the "Filename" property
218 std::vector<std::string> filenamesFromPropertyUnraveld;
219 std::vector<std::vector<std::string>> filenamesFromProperty = this->getProperty("Filename");
220 for (const auto &outer : filenamesFromProperty) {
221 filenamesFromPropertyUnraveld.insert(filenamesFromPropertyUnraveld.end(), outer.cbegin(), outer.cend());
222 }
223 // error check that something sensible was supplied
224 if (filenamesFromPropertyUnraveld.size() > 2) {
225 throw std::runtime_error("Can only specify up to 2 characterization files");
226 }
227
228 // sort out which file is which
229 int v0_index = -1;
230 int v1_index = -1;
231 for (size_t i = 0; i < filenamesFromPropertyUnraveld.size(); ++i) {
232 const int versionFromFile = getVersion(filenamesFromPropertyUnraveld[i]);
233 g_log.debug() << "Found version " << versionFromFile << " in \"" << filenamesFromPropertyUnraveld[i] << "\"\n";
234 if (versionFromFile == 0)
235 v0_index = static_cast<int>(i);
236 else if (versionFromFile == 1)
237 v1_index = static_cast<int>(i);
238 }
239
240 // fill the output array
241 std::vector<std::string> filenames(F_INDEX_SIZE);
242 if (v0_index >= 0)
243 filenames[F_INDEX_V0] = filenamesFromPropertyUnraveld[v0_index];
244 if (v1_index >= 0)
245 filenames[F_INDEX_V1] = filenamesFromPropertyUnraveld[v1_index];
246
247 // optional exp.ini file for NOMAD
248 std::string iniFilename = this->getProperty("ExpIniFilename");
249 if (!iniFilename.empty()) {
250 filenames[F_INDEX_EXPINI] = iniFilename;
251 }
252
253 // check that things exist
254 for (const auto &filename : filenames) {
255 if (filename.empty())
256 continue;
257
258 std::filesystem::path file(filename);
259 if (!std::filesystem::exists(file))
260 throw Exception::FileError("File does not exist", filename);
261 std::filesystem::path path(filename);
262 if (!std::filesystem::is_regular_file(path))
263 throw Exception::FileError("File is not a regular file", filename);
264 }
265 return filenames;
266}
267
276int PDLoadCharacterizations::readFocusInfo(std::ifstream &file, const std::string &filename) {
277 // end early if already at the end of the file
278 if (file.eof())
279 return 0;
280 // look at the first line available now
281 // start of the scan indicator means there are no focused positions
282 const auto peek = Strings::peekLine(file).substr(0, 2);
283 if (peek == "#S" || peek == "#L")
284 return 0;
285
286 std::vector<int32_t> specIds;
287 std::vector<double> l2;
288 std::vector<double> polar;
289 std::vector<double> azi;
290
291 // parse the file
292 // Strings::getLine skips blank lines and lines that start with #
293 int linenum = 1; // first line of file was a keyword that this existed
294 for (std::string line = Strings::getLine(file); !file.eof(); Strings::getLine(file, line)) {
295 linenum += 1;
296 line = Strings::strip(line);
297 // skip empty lines and "comments"
298 if (line.empty())
299 continue;
300 if (line.substr(0, 1) == "#")
301 continue;
302
303 std::vector<std::string> splitted;
304 boost::split(splitted, line, boost::is_any_of("\t "), boost::token_compress_on);
305 if (splitted[0] == L1_KEY) {
306 this->setProperty("PrimaryFlightPath", lexical_cast<double>(splitted[1], filename, linenum, "l1"));
307 break;
308 } else if (splitted.size() >= 3) { // specid, L2, theta
309 specIds.emplace_back(lexical_cast<int32_t>(splitted[0], filename, linenum, "spectrum number"));
310 l2.emplace_back(lexical_cast<double>(splitted[1], filename, linenum, "l2"));
311 polar.emplace_back(lexical_cast<double>(splitted[2], filename, linenum, "polar"));
312 if (splitted.size() >= 4 && (!splitted[3].empty())) { // azimuthal was specified
313 azi.emplace_back(lexical_cast<double>(splitted[3], filename, linenum, "azimuthal"));
314 } else { // just set it to zero
315 azi.emplace_back(0.);
316 }
317 }
318 }
319 // confirm that everything is the same length
320 if (specIds.size() != l2.size() || specIds.size() != polar.size() || specIds.size() != azi.size())
321 throw Exception::FileError("Found different number of spectra, L2 and polar angles", filename);
322
323 // set the values
324 this->setProperty("SpectrumIDs", specIds);
325 this->setProperty("L2", l2);
326 this->setProperty("Polar", polar);
327 this->setProperty("Azimuthal", azi);
328
329 return linenum;
330}
331
342void PDLoadCharacterizations::readCharInfo(std::ifstream &file, ITableWorkspace_sptr &wksp, const std::string &filename,
343 int linenum) {
344 // end early if already at the end of the file
345 if (file.eof())
346 return;
347
348 g_log.debug() << "readCharInfo(file, wksp)\n";
349
350 const size_t num_of_columns = wksp->columnCount();
351
352 // parse the file
353 for (std::string line = Strings::getLine(file); !file.eof(); Strings::getLine(file, line)) {
354 linenum += 1;
355 line = Strings::strip(line);
356 // skip empty lines and "comments"
357 if (line.empty())
358 continue;
359 if (line.substr(0, 1) == "#")
360 continue;
361 g_log.debug(line);
362 // parse the line
363 std::vector<std::string> splitted;
364 boost::split(splitted, line, boost::is_any_of("\t "), boost::token_compress_on);
365 while (splitted.size() < 12)
366 splitted.emplace_back(ZERO); // extra values default to zero
367
368 // add the row
369 API::TableRow row = wksp->appendRow();
370 row << lexical_cast<double>(splitted[0], filename, linenum, "frequency");
371 row << lexical_cast<double>(splitted[1], filename, linenum, "wavelength");
372 row << lexical_cast<int32_t>(splitted[2], filename, linenum, "bank");
373 row << splitted[3]; // vanadium
374 row << splitted[5]; // vanadium_background
375 row << splitted[4]; // container
376 row << "0"; // empty_environment
377 row << "0"; // empty_instrument
378 row << splitted[6]; // d_min
379 row << splitted[7]; // d_max
380 row << lexical_cast<double>(splitted[8], filename, linenum, "tof_min");
381 row << lexical_cast<double>(splitted[9], filename, linenum, "tof_max");
382 row << lexical_cast<double>(splitted[10], filename, linenum, "wavelength_min");
383 row << lexical_cast<double>(splitted[11], filename, linenum, "wavelength_max");
384 // pad all extras with empty string - the 14 required columns have
385 // already been added to the row
386 for (size_t i = 14; i < num_of_columns; ++i) {
387 row << "0";
388 }
389 }
390}
391
392void PDLoadCharacterizations::readVersion0(const std::string &filename, API::ITableWorkspace_sptr &wksp) {
393 // don't bother if there isn't a filename
394 if (filename.empty())
395 return;
396
397 g_log.debug() << "readVersion0(" << filename << ", wksp)\n";
398
399 std::ifstream file(filename.c_str(), std::ios_base::binary);
400 if (!file.is_open()) {
401 throw Exception::FileError("Unable to open version 0 file", filename);
402 }
403
404 // read the first line and decide what to do
405 int linenum = 0;
406 std::string firstLine = Strings::getLine(file);
407 if (firstLine.substr(0, IPARM_KEY.size()) == IPARM_KEY) {
408 firstLine = Strings::strip(firstLine.substr(IPARM_KEY.size()));
409 this->setProperty("IParmFilename", firstLine);
410 linenum = this->readFocusInfo(file, filename);
411 } else {
412 // things expect the L1 to be zero if it isn't set
413 this->setProperty("PrimaryFlightPath", 0.);
414 }
415
416 // now the rest of the file
417 this->readCharInfo(file, wksp, filename, linenum);
418
419 file.close();
420}
421
422namespace {
423bool closeEnough(const double left, const double right) { return Kernel::withinRelativeDifference(left, right, 0.05); }
424
425int findRow(API::ITableWorkspace_sptr &wksp, const std::vector<std::string> &values) {
426 // don't have a good way to mark error location in these casts
427 const auto frequency = boost::lexical_cast<double>(values[0]);
428 const auto wavelength = boost::lexical_cast<double>(values[1]);
429
430 // find the correct row
431 const size_t numRows = wksp->rowCount();
432 for (size_t i = 0; i < numRows; ++i) {
433 const double frequencyRow = wksp->getRef<double>("frequency", i);
434 const double wavelengthRow = wksp->getRef<double>("wavelength", i);
435 if (closeEnough(frequency, frequencyRow) && closeEnough(wavelength, wavelengthRow)) {
436 return static_cast<int>(i);
437 }
438 }
439 // fall through behavior is -1
440 return -1;
441}
442
443void updateRow(API::ITableWorkspace_sptr &wksp, const size_t rowNum, const std::vector<std::string> &names,
444 const std::vector<std::string> &values) {
445 wksp->getRef<std::string>("vanadium", rowNum) = values[2];
446 wksp->getRef<std::string>("vanadium_background", rowNum) = values[3];
447 wksp->getRef<std::string>("empty_environment", rowNum) = values[4];
448 wksp->getRef<std::string>("empty_instrument", rowNum) = values[5];
449 for (size_t i = 0; i < names.size(); ++i) {
450 const auto name = names[i];
451 wksp->getRef<std::string>(name, rowNum) = values[i + INFO_OFFSET_V1];
452 }
453}
454} // namespace
455
456void PDLoadCharacterizations::readVersion1(const std::string &filename, API::ITableWorkspace_sptr &wksp) {
457 // don't bother if there isn't a filename
458 if (filename.empty())
459 return;
460
461 g_log.debug() << "readVersion1(" << filename << ", wksp)\n";
462
463 g_log.information() << "Opening \"" << filename << "\" as a version 1 file\n";
464 std::ifstream file(filename.c_str(), std::ios_base::binary);
465 if (!file.is_open()) {
466 throw Exception::FileError("Unable to open version 1 file", filename);
467 }
468
469 // first line must be version string
470 std::string line = Strings::getLine(file);
471 boost::smatch versionSearch;
472 if (boost::regex_search(line, versionSearch, VERSION_REG_EXP) && versionSearch.size() == 2) {
473 g_log.debug() << "Found version " << versionSearch[1] << "\n";
474 } else {
475 file.close();
476 throw Exception::ParseError("file must have \"version=1\" as the first line", filename, 0);
477 }
478
479 // store the names of the columns in order
480 int linenum = 0;
481 std::vector<std::string> columnNames;
482 for (Strings::getLine(file, line); !file.eof(); Strings::getLine(file, line)) {
483 linenum += 1;
484 line = Strings::strip(line);
485 if (line.empty())
486 continue;
487 if (line.substr(0, 1) == "#")
488 continue;
489 g_log.debug(line);
490
491 boost::smatch v1TableSearch;
492 // all instances of table headers
493 if (boost::regex_search(line, v1TableSearch, V1_TABLE_REG_EXP)) {
494 if (v1TableSearch.size() == 2) {
495 line = Strings::strip(v1TableSearch[1]);
497 std::move(tokenizer.begin(), tokenizer.end(), std::back_inserter(columnNames));
498 }
499 } else {
500 if (columnNames.empty()) // should never happen
501 throw Exception::FileError("file missing column names", filename);
502
503 line = Strings::strip(line);
505 std::vector<std::string> valuesAsStr;
506 std::move(tokenizer.begin(), tokenizer.end(), std::back_inserter(valuesAsStr));
507 if (valuesAsStr.size() < columnNames.size() + INFO_OFFSET_V1) {
508 std::stringstream msg;
509 msg << "Number of data columns (" << valuesAsStr.size() << ") not compatible with number of column labels ("
510 << (columnNames.size() + INFO_OFFSET_V1) << ")";
511 throw Exception::ParseError(msg.str(), filename, linenum);
512 }
513
514 const int rowIndex = findRow(wksp, valuesAsStr);
515
516 if (rowIndex >= 0) {
517 updateRow(wksp, static_cast<size_t>(rowIndex), columnNames, valuesAsStr);
518 } else {
519 // add the row
520 API::TableRow row = wksp->appendRow();
521 row << lexical_cast<double>(valuesAsStr[0], filename, linenum, "frequency");
522 row << lexical_cast<double>(valuesAsStr[1], filename, linenum, "wavelength");
523 row << boost::lexical_cast<int32_t>(1); // bank
524 row << valuesAsStr[2]; // vanadium
525 row << valuesAsStr[3]; // vanadium_background
526 row << "0"; // container
527 row << valuesAsStr[4]; // empty_environment
528 row << valuesAsStr[5]; // empty_instrument
529 row << "0"; // d_min
530 row << "0"; // d_max
531 row << 0.; // tof_min
532 row << 0.; // tof_max
533 row << 0.; // wavelength_min
534 row << 0.; // wavelength_max
535 // insert all the extras
536 for (size_t i = INFO_OFFSET_V1; i < valuesAsStr.size(); ++i) {
537 row << valuesAsStr[i];
538 }
539 }
540 }
541 // TODO need to get the extras line
542 }
543
544 file.close();
545}
546
552void PDLoadCharacterizations::readExpIni(const std::string &filename, API::ITableWorkspace_sptr &wksp) {
553 // don't bother if there isn't a filename
554 if (filename.empty())
555 return;
556
557 g_log.debug() << "readExpIni(" << filename << ", wksp)\n";
558
559 const size_t rowCount = wksp->rowCount();
560 if (rowCount == 0)
561 throw std::runtime_error("Characterizations file does not have any "
562 "characterizations information");
563
564 std::ifstream file(filename.c_str(), std::ios_base::binary);
565 if (!file.is_open()) {
566 throw Exception::FileError("Unable to open exp.ini file", filename);
567 }
568
569 // parse the file
570 for (std::string line = Strings::getLine(file); !file.eof(); Strings::getLine(file, line)) {
571 line = Strings::strip(line);
572 // skip empty lines and "comments"
573 if (line.empty())
574 continue;
575 if (line.substr(0, 1) == "#")
576 continue;
577
578 // split the line and see if it has something meaningful
579 std::vector<std::string> splitted;
580 boost::split(splitted, line, boost::is_any_of("\t "), boost::token_compress_on);
581 if (splitted.size() < 2)
582 continue;
583
584 // update the various charaterization runs in every row
585 for (size_t row = 0; row < rowCount; ++row) {
586 if (splitted[0] == EXP_INI_VAN_KEY) {
587 wksp->getRef<std::string>("vanadium", row) = splitted[1];
588 } else if (splitted[0] == EXP_INI_EMPTY_KEY) {
589 wksp->getRef<std::string>("vanadium_background", row) = splitted[1];
590 } else if (splitted[0] == EXP_INI_CAN_KEY) {
591 wksp->getRef<std::string>("container", row) = splitted[1];
592 }
593 }
594 }
595}
596
597} // namespace Mantid::DataHandling
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double value
The value of the point.
Definition FitMW.cpp:51
double left
double right
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:422
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
TableRow represents a row in a TableWorkspace.
Definition TableRow.h:39
A property class for workspaces.
LoadPDCharacterizations : Load a characterization file used in Powder Diffraction Reduction.
void readExpIni(const std::string &filename, API::ITableWorkspace_sptr &wksp)
Parse the (optional) exp.ini file found on NOMAD.
const std::string name() const override
Algorithm's name for identification.
void readVersion1(const std::string &filename, API::ITableWorkspace_sptr &wksp)
void init() override
Initialize the algorithm's properties.
void readCharInfo(std::ifstream &file, API::ITableWorkspace_sptr &wksp, const std::string &filename, int linenum)
Parse the stream for the characterization file information.
void readVersion0(const std::string &filename, API::ITableWorkspace_sptr &wksp)
int readFocusInfo(std::ifstream &file, const std::string &filename)
Parse the stream for the focus positions and instrument parameter filename.
int version() const override
Algorithm's version for identification.
const std::string category() const override
Algorithm's category for identification.
std::vector< std::string > getFilenames()
This ignores the traditional interpretation of Mantid::API::MultipleFileProperty and flattens the arr...
Support for a property that holds an array of values.
Records the filename and the description of failure.
Definition Exception.h:98
Records the filename, the description of failure and the line on which it happened.
Definition Exception.h:115
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Iterator begin()
Iterator referring to first element in the container.
@ TOK_IGNORE_EMPTY
ignore empty tokens
Iterator end()
Iterator referring to the past-the-end element in the container.
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
Mantid::Kernel::StringTokenizer tokenizer
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
Definition Strings.cpp:419
MANTID_KERNEL_DLL std::string peekLine(std::istream &fh)
Peek at a line without extracting it from the stream.
Definition Strings.cpp:366
MANTID_KERNEL_DLL std::string getLine(std::istream &fh)
Get a line and strip comments Use only for a single call.
Definition Strings.cpp:341
MANTID_KERNEL_DLL bool withinRelativeDifference(T const x, T const y, S const tolerance)
Test whether x, y are within relative tolerance tol.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
@ Output
An output workspace.
Definition Property.h:54