19#include <boost/algorithm/string.hpp>
20#include <boost/regex.hpp>
34static const std::string IPARM_KEY(
"Instrument parameter file:");
35static const std::string L1_KEY(
"L1");
36static const std::string ZERO(
"0.");
37static const std::string EXP_INI_VAN_KEY(
"Vana");
38static const std::string EXP_INI_EMPTY_KEY(
"VanaBg");
39static const std::string EXP_INI_CAN_KEY(
"MTc");
42static const size_t INFO_OFFSET_V1(6);
44static const int F_INDEX_V0 = 0;
45static const int F_INDEX_V1 = 1;
46static const int F_INDEX_EXPINI = 2;
47static const int F_INDEX_SIZE = 3;
49const boost::regex V1_TABLE_REG_EXP{
"^freq.*\\s+w.*l.*\\s+"
51 "mt_env\\s+mt_instr(.+)"};
52const boost::regex VERSION_REG_EXP{
"^version=([0-9]+)"};
58std::vector<std::string> extra_columns(
const std::vector<std::string> &filenames) {
60 if (filenames[F_INDEX_V1].empty())
61 return std::vector<std::string>();
63 std::set<std::string> columnSet;
66 std::ifstream file(filenames[F_INDEX_V1].c_str(), std::ios_base::binary);
74 if (boost::regex_search(line, result, V1_TABLE_REG_EXP)) {
75 if (result.size() == 2) {
79 columnSet.insert(token);
88 std::vector<std::string> columnnames;
89 std::copy(columnSet.begin(), columnSet.end(), std::back_inserter(columnnames));
90 std::sort(columnnames.begin(), columnnames.end());
110 const auto exts = std::vector<std::string>({
".txt"});
111 declareProperty(std::make_unique<MultipleFileProperty>(
"Filename", exts),
"Characterizations file");
113 "(Optional) exp.ini file used at NOMAD");
116 "Output for the information of characterizations and runs");
122 "Spectrum Nos (note that it is not detector ID or workspace "
123 "indices). The list must be either empty or have a size "
124 "equal to input workspace's histogram number. ");
126 "Secondary flight (L2) paths for each detector. Number of L2 "
127 "given must be same as number of histogram.");
129 "Polar angles (two thetas) for detectors. Number of 2theta "
130 "given must be same as number of histogram.");
132 "Azimuthal angles (out-of-plane) for detectors. "
133 "Number of azimuthal angles given must be same as number of histogram.");
141 const std::vector<std::string> canColumnNames = extra_columns(filenames);
145 wksp->addColumn(
"double",
"frequency");
146 wksp->addColumn(
"double",
"wavelength");
147 wksp->addColumn(
"int",
"bank");
148 wksp->addColumn(
"str",
"vanadium");
149 wksp->addColumn(
"str",
"vanadium_background");
150 wksp->addColumn(
"str",
"container");
151 wksp->addColumn(
"str",
"empty_environment");
152 wksp->addColumn(
"str",
"empty_instrument");
153 wksp->addColumn(
"str",
"d_min");
154 wksp->addColumn(
"str",
"d_max");
155 wksp->addColumn(
"double",
"tof_min");
156 wksp->addColumn(
"double",
"tof_max");
157 wksp->addColumn(
"double",
"wavelength_min");
158 wksp->addColumn(
"double",
"wavelength_max");
159 for (
const auto &
name : canColumnNames) {
160 wksp->addColumn(
"str",
name);
170 this->
readExpIni(filenames[F_INDEX_EXPINI], wksp);
176int getVersion(
const std::string &filename) {
177 std::ifstream file(filename.c_str(), std::ios_base::binary);
178 if (!file.is_open()) {
185 boost::smatch result;
186 if (boost::regex_search(line, result, VERSION_REG_EXP) && result.size() == 2) {
187 return boost::lexical_cast<int>(result[1]);
195T lexical_cast(
const std::string &
value,
const std::string &filename,
const int linenum,
196 const std::string &label =
"") {
198 return boost::lexical_cast<T>(
value);
199 }
catch (boost::bad_lexical_cast &e) {
217 std::vector<std::string> filenamesFromPropertyUnraveld;
218 std::vector<std::vector<std::string>> filenamesFromProperty = this->
getProperty(
"Filename");
219 for (
const auto &outer : filenamesFromProperty) {
220 filenamesFromPropertyUnraveld.insert(filenamesFromPropertyUnraveld.end(), outer.cbegin(), outer.cend());
223 if (filenamesFromPropertyUnraveld.size() > 2) {
224 throw std::runtime_error(
"Can only specify up to 2 characterization files");
230 for (
size_t i = 0; i < filenamesFromPropertyUnraveld.size(); ++i) {
231 const int version = getVersion(filenamesFromPropertyUnraveld[i]);
232 g_log.
debug() <<
"Found version " <<
version <<
" in \"" << filenamesFromPropertyUnraveld[i] <<
"\"\n";
234 v0_index =
static_cast<int>(i);
236 v1_index =
static_cast<int>(i);
240 std::vector<std::string> filenames(F_INDEX_SIZE);
242 filenames[F_INDEX_V0] = filenamesFromPropertyUnraveld[v0_index];
244 filenames[F_INDEX_V1] = filenamesFromPropertyUnraveld[v1_index];
247 std::string iniFilename = this->
getProperty(
"ExpIniFilename");
248 if (!iniFilename.empty()) {
249 filenames[F_INDEX_EXPINI] = iniFilename;
253 for (
const auto &filename : filenames) {
254 if (filename.empty())
257 Poco::File file(filename);
260 Poco::Path path(filename);
282 if (peek ==
"#S" || peek ==
"#L")
285 std::vector<int32_t> specIds;
286 std::vector<double>
l2;
287 std::vector<double> polar;
288 std::vector<double> azi;
299 if (line.substr(0, 1) ==
"#")
302 std::vector<std::string> splitted;
303 boost::split(splitted, line, boost::is_any_of(
"\t "), boost::token_compress_on);
304 if (splitted[0] == L1_KEY) {
305 this->
setProperty(
"PrimaryFlightPath", lexical_cast<double>(splitted[1], filename, linenum,
"l1"));
307 }
else if (splitted.size() >= 3) {
308 specIds.emplace_back(lexical_cast<int32_t>(splitted[0], filename, linenum,
"spectrum number"));
309 l2.emplace_back(lexical_cast<double>(splitted[1], filename, linenum,
"l2"));
310 polar.emplace_back(lexical_cast<double>(splitted[2], filename, linenum,
"polar"));
311 if (splitted.size() >= 4 && (!splitted[3].empty())) {
312 azi.emplace_back(lexical_cast<double>(splitted[3], filename, linenum,
"azimuthal"));
314 azi.emplace_back(0.);
319 if (specIds.size() !=
l2.size() || specIds.size() != polar.size() || specIds.size() != azi.size())
347 g_log.
debug() <<
"readCharInfo(file, wksp)\n";
349 const size_t num_of_columns = wksp->columnCount();
358 if (line.substr(0, 1) ==
"#")
362 std::vector<std::string> splitted;
363 boost::split(splitted, line, boost::is_any_of(
"\t "), boost::token_compress_on);
364 while (splitted.size() < 12)
365 splitted.emplace_back(ZERO);
369 row << lexical_cast<double>(splitted[0], filename, linenum,
"frequency");
370 row << lexical_cast<double>(splitted[1], filename, linenum,
"wavelength");
371 row << lexical_cast<int32_t>(splitted[2], filename, linenum,
"bank");
379 row << lexical_cast<double>(splitted[8], filename, linenum,
"tof_min");
380 row << lexical_cast<double>(splitted[9], filename, linenum,
"tof_max");
381 row << lexical_cast<double>(splitted[10], filename, linenum,
"wavelength_min");
382 row << lexical_cast<double>(splitted[11], filename, linenum,
"wavelength_max");
385 for (
size_t i = 14; i < num_of_columns; ++i) {
393 if (filename.empty())
396 g_log.
debug() <<
"readVersion0(" << filename <<
", wksp)\n";
398 std::ifstream file(filename.c_str(), std::ios_base::binary);
399 if (!file.is_open()) {
406 if (firstLine.substr(0, IPARM_KEY.size()) == IPARM_KEY) {
422bool closeEnough(
const double left,
const double right) {
429 const double relativeDiff = diff * 2 / (
left +
right);
430 return relativeDiff < .05;
435 const auto frequency = boost::lexical_cast<double>(values[0]);
436 const auto wavelength = boost::lexical_cast<double>(values[1]);
439 const size_t numRows = wksp->rowCount();
440 for (
size_t i = 0; i < numRows; ++i) {
441 const double frequencyRow = wksp->getRef<
double>(
"frequency", i);
442 const double wavelengthRow = wksp->getRef<
double>(
"wavelength", i);
443 if (closeEnough(frequency, frequencyRow) && closeEnough(wavelength, wavelengthRow)) {
444 return static_cast<int>(i);
452 const std::vector<std::string> &values) {
453 wksp->getRef<std::string>(
"vanadium", rowNum) = values[2];
454 wksp->getRef<std::string>(
"vanadium_background", rowNum) = values[3];
455 wksp->getRef<std::string>(
"empty_environment", rowNum) = values[4];
456 wksp->getRef<std::string>(
"empty_instrument", rowNum) = values[5];
457 for (
size_t i = 0; i < names.size(); ++i) {
458 const auto name = names[i];
459 wksp->getRef<std::string>(name, rowNum) = values[i + INFO_OFFSET_V1];
466 if (filename.empty())
469 g_log.
debug() <<
"readVersion1(" << filename <<
", wksp)\n";
471 g_log.
information() <<
"Opening \"" << filename <<
"\" as a version 1 file\n";
472 std::ifstream file(filename.c_str(), std::ios_base::binary);
473 if (!file.is_open()) {
479 boost::smatch versionSearch;
480 if (boost::regex_search(line, versionSearch, VERSION_REG_EXP) && versionSearch.size() == 2) {
481 g_log.
debug() <<
"Found version " << versionSearch[1] <<
"\n";
489 std::vector<std::string> columnNames;
495 if (line.substr(0, 1) ==
"#")
499 boost::smatch v1TableSearch;
501 if (boost::regex_search(line, v1TableSearch, V1_TABLE_REG_EXP)) {
502 if (v1TableSearch.size() == 2) {
508 if (columnNames.empty())
513 std::vector<std::string> valuesAsStr;
515 if (valuesAsStr.size() < columnNames.size() + INFO_OFFSET_V1) {
516 std::stringstream msg;
517 msg <<
"Number of data columns (" << valuesAsStr.size() <<
") not compatible with number of column labels ("
518 << (columnNames.size() + INFO_OFFSET_V1) <<
")";
522 const int rowIndex = findRow(wksp, valuesAsStr);
525 updateRow(wksp,
static_cast<size_t>(rowIndex), columnNames, valuesAsStr);
529 row << lexical_cast<double>(valuesAsStr[0], filename, linenum,
"frequency");
530 row << lexical_cast<double>(valuesAsStr[1], filename, linenum,
"wavelength");
531 row << boost::lexical_cast<int32_t>(1);
532 row << valuesAsStr[2];
533 row << valuesAsStr[3];
535 row << valuesAsStr[4];
536 row << valuesAsStr[5];
544 for (
size_t i = INFO_OFFSET_V1; i < valuesAsStr.size(); ++i) {
545 row << valuesAsStr[i];
562 if (filename.empty())
565 g_log.
debug() <<
"readExpIni(" << filename <<
", wksp)\n";
567 const size_t rowCount = wksp->rowCount();
569 throw std::runtime_error(
"Characterizations file does not have any "
570 "characterizations information");
572 std::ifstream file(filename.c_str(), std::ios_base::binary);
573 if (!file.is_open()) {
583 if (line.substr(0, 1) ==
"#")
587 std::vector<std::string> splitted;
588 boost::split(splitted, line, boost::is_any_of(
"\t "), boost::token_compress_on);
589 if (splitted.size() < 2)
593 for (
size_t row = 0; row < rowCount; ++row) {
594 if (splitted[0] == EXP_INI_VAN_KEY) {
595 wksp->getRef<std::string>(
"vanadium", row) = splitted[1];
596 }
else if (splitted[0] == EXP_INI_EMPTY_KEY) {
597 wksp->getRef<std::string>(
"vanadium_background", row) = splitted[1];
598 }
else if (splitted[0] == EXP_INI_CAN_KEY) {
599 wksp->getRef<std::string>(
"container", row) = splitted[1];
#define DECLARE_ALGORITHM(classname)
double value
The value of the point.
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.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
TableRow represents a row in a TableWorkspace.
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.
void exec() override
Execute the algorithm.
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.
Records the filename, the description of failure and the line on which it happened.
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.
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...
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
MANTID_KERNEL_DLL std::string peekLine(std::istream &fh)
Peek at a line without extracting it from the stream.
MANTID_KERNEL_DLL std::string getLine(std::istream &fh)
Get a line and strip comments Use only for a single call.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
@ Output
An output workspace.