20#include "MantidHistogramData/Histogram.h"
29#include <boost/algorithm/string.hpp>
40const std::map<std::string, std::string> MONTHS{{
"JAN",
"01"}, {
"FEB",
"02"}, {
"MAR",
"03"}, {
"APR",
"04"},
41 {
"MAY",
"05"}, {
"JUN",
"06"}, {
"JUL",
"07"}, {
"AUG",
"08"},
42 {
"SEP",
"09"}, {
"OCT",
"10"}, {
"NOV",
"11"}, {
"DEC",
"12"}};
43const std::vector<std::string> PSI_MONTHS{
"JAN",
"FEB",
"MAR",
"APR",
"MAY",
"JUN",
44 "JUL",
"AUG",
"SEP",
"OCT",
"NOV",
"DEC"};
45constexpr int TEMPERATURE_FILE_MAX_SEARCH_DEPTH = 3;
46constexpr auto TEMPERATURE_FILE_EXT =
".mon";
58 return "Loads a data file that is in PSI Muon Binary format into a "
59 "workspace (Workspace2D class).";
66 auto &stream = descriptor.
data();
68 std::string fileFormat;
69 streamReader.
read(fileFormat, 2);
70 if (fileFormat !=
"1N") {
77 const std::vector<std::string> exts{
".bin"};
79 "The name of the Bin file to load");
81 const std::vector<std::string> extsTemps{
".mon"};
82 declareProperty(std::make_unique<Mantid::API::FileProperty>(
"TemperatureFilename",
"",
84 "The name of the temperature file to be loaded, this is optional as it "
85 "will be automatically searched for if not provided.");
89 "An output workspace.");
92 "If no temp file has been given decide whether the algorithm "
93 "will search for the temperature file.");
103 "This property should only be set in the GUI and is present to work with "
104 "the Muon GUI preprocessor.");
106 declareProperty(
"MainFieldDirection", 0,
"The field direction of the magnetic field on the instrument",
110 "A vector of time zero values");
114 "TableWorkspace of time zeros for each spectra");
116 declareProperty(
"CorrectTime",
true,
"Boolean flag controlling whether time should be corrected by timezero.",
121 "Table or a group of tables with information about the "
122 "detector grouping stored in the file (if any).");
123 auto mustBePositive = std::make_shared<Kernel::BoundedValidator<specnum_t>>();
124 mustBePositive->setLower(0);
126 "Index number of the first spectrum to read\n");
128 "Index of last spectrum to read\n"
129 "(default the last spectrum)");
134 if (
sizeof(
float) != 4) {
138 throw std::runtime_error(
"A float on this machine is not 32 bits");
143 std::ifstream binFile(binFilename, std::ios::in | std::ios::binary);
147 std::string fileFormat;
148 streamReader.
read(fileFormat, 2);
149 if (fileFormat !=
"1N") {
150 throw std::runtime_error(
"Loaded file is not of PSIMuonBin type (First 2 bytes != 1N)");
164 Mantid::HistogramData::Histogram(Mantid::HistogramData::BinEdges(sizeOfXForHistograms)));
166 for (
auto specNum = 0u; specNum <
m_histograms.size(); ++specNum) {
167 outputWorkspace->mutableX(specNum) =
m_xAxis;
168 outputWorkspace->mutableY(specNum) =
m_histograms[specNum];
169 outputWorkspace->mutableE(specNum) =
m_eAxis[specNum];
170 outputWorkspace->getSpectrum(specNum).setDetectorID(specNum + 1);
179 auto largestBinValue = outputWorkspace->x(0)[outputWorkspace->x(0).size() - 1];
184 setProperty(
"LastGoodData", outputWorkspace->x(0)[lastGoodDataSpecIndex]);
186 double timeZero = 0.0;
187 std::vector<double> timeZeroList;
199 double absTimeZero = timeZero;
200 std::vector<double> correctedTimeZeroList;
201 if (timeZero > largestBinValue) {
202 absTimeZero = outputWorkspace->x(0)[
static_cast<int>(std::floor(timeZero))];
203 std::transform(timeZeroList.cbegin(), timeZeroList.cend(), std::back_inserter(correctedTimeZeroList),
204 [&outputWorkspace](
const auto timeZeroValue) {
205 return outputWorkspace->x(0)[static_cast<int>(std::floor(timeZeroValue))];
208 correctedTimeZeroList = timeZeroList;
212 setProperty(
"TimeZeroList", correctedTimeZeroList);
222 setProperty(
"FirstGoodData", outputWorkspace->x(0)[firstGoodDataSpecIndex]);
229 for (
auto specNum = 0u; specNum <
m_histograms.size(); ++specNum) {
230 auto &xData = outputWorkspace->mutableX(specNum);
231 std::transform(xData.cbegin(), xData.cend(), xData.begin(),
232 [absTimeZero](
const auto &xValue) { return xValue - absTimeZero; });
245 std::dynamic_pointer_cast<Mantid::DataObjects::TableWorkspace>(
247 detectorTable->addColumn(
"vector_int",
"detector");
248 for (
size_t i = 0; i < numSpec; i++) {
249 std::vector<int> dets{
static_cast<int>(i) + 1};
253 setProperty(
"DetectorGroupingTable", detectorTable);
260 std::dynamic_pointer_cast<Mantid::DataObjects::TableWorkspace>(
262 assert(deadTimeTable);
263 deadTimeTable->addColumn(
"int",
"spectrum");
264 deadTimeTable->addColumn(
"double",
"dead-time");
266 for (
size_t i = 0; i < numSpec; i++) {
268 row << static_cast<int>(i) + 1 << 0.0;
275 if (date.size() == 11) {
276 year = date.substr(7, 4);
278 year =
"20" + date.substr(7, 2);
280 return year +
"-" + MONTHS.find(date.substr(3, 3))->second +
"-" + date.substr(0, 2) +
"T" + time;
310 static_cast<float>((625.E-6) / 8. * pow(
static_cast<float>(2.),
static_cast<float>(
m_header.
tdcResolution)));
383 for (
auto i = 0u; i <= 5; ++i) {
391 for (
auto i = 6u; i < 18; ++i) {
399 for (
auto i = 0u; i <= 15; ++i) {
416 for (
auto i = 0u; i < 4; ++i) {
438 constexpr auto sizeInt32_t =
sizeof(int32_t);
439 const auto headerSize = 1024;
443 std::vector<double> &nextHistogram =
m_histograms[histogramIndex];
447 int32_t nextReadValue;
448 streamReader >> nextReadValue;
449 nextHistogram.emplace_back(nextReadValue);
457 for (
auto xIndex = 0u; xIndex <=
m_histograms[0].size(); ++xIndex) {
463 std::vector<double> newEAxis;
464 for (
auto eIndex = 0u; eIndex <
m_histograms[0].size(); ++eIndex) {
465 newEAxis.emplace_back(sqrt(histogram[eIndex]));
467 m_eAxis.emplace_back(newEAxis);
473 logAlg->setProperty(
"Workspace", ws);
479 alg->setProperty(
"InputWorkspace", ws);
480 alg->setProperty(
"OutputWorkspace",
"not_used");
483 alg->executeAsChildAlg();
484 return alg->getProperty(
"OutputWorkspace");
490 alg->setProperty(
"LogType",
"String");
491 alg->setProperty(
"LogName", logName);
492 alg->setProperty(
"LogText", logText);
493 alg->executeAsChildAlg();
499 alg->setProperty(
"LogType",
"Number");
500 alg->setProperty(
"NumberType",
"Double");
501 alg->setProperty(
"LogName", logName);
503 alg->executeAsChildAlg();
509 alg->setProperty(
"LogType",
"Number");
510 alg->setProperty(
"NumberType",
"Int");
511 alg->setProperty(
"LogName", logName);
513 alg->executeAsChildAlg();
522 outputWorkspace->mutableRun().addProperty(
"run_number",
static_cast<int>(
m_header.
numberOfRuns));
525 outputWorkspace->setYUnit(
"Counts");
526 std::shared_ptr<Kernel::Units::Label> lblUnit =
527 std::dynamic_pointer_cast<Kernel::Units::Label>(Kernel::UnitFactory::Instance().
create(
"Label"));
529 outputWorkspace->getAxis(0)->unit() = lblUnit;
535 Mantid::Types::Core::DateAndTime start(startDate);
536 Mantid::Types::Core::DateAndTime end(endDate);
537 outputWorkspace->mutableRun().setStartAndEndTime(start, end);
538 }
catch (
const std::logic_error &) {
539 Mantid::Types::Core::DateAndTime start;
540 Mantid::Types::Core::DateAndTime end;
541 outputWorkspace->mutableRun().setStartAndEndTime(start, end);
558 }
catch (std::invalid_argument &) {
559 g_log.
warning(
"The \"sample_temp\" could not be converted to a number for "
560 "the sample log so has been added as a string");
566 for (
auto tempNum = 1u; tempNum < sizeOfTemps + 1; ++tempNum) {
588 }
catch (std::invalid_argument &) {
589 g_log.
warning(
"The \"Field\" could not be converted to a number for "
590 "the sample log so has been added as a string");
596 for (
auto i = 0u; i < sizeOfScalars; ++i) {
605 for (
auto i = 0u; i < sizeOfLabels; ++i) {
612 const bool isSpace = labelName.find_first_not_of(
" ") == std::string::npos;
622 for (
size_t i = 0; i < sizeOfFirstGood; ++i) {
642 for (
auto i = 0u; i < sizeOfMonLow; ++i) {
655 for (
auto i = 0u; i < 16; ++i) {
664 for (
auto i = 0u; i < 16; ++i) {
674 }
catch (std::invalid_argument &e) {
675 g_log.
warning(
"Temperature file was not be loaded: " + std::string(e.what()));
676 }
catch (std::runtime_error &e) {
677 g_log.
warning(
"Temperature file was not be loaded:" + std::string(e.what()));
682std::string findTitlesFromLine(
const std::string &line) {
683 bool titlesFound =
false;
684 std::string foundTitles =
"";
685 for (
const auto &charecter : line) {
686 if (charecter ==
':') {
688 }
else if (titlesFound) {
689 foundTitles += charecter;
697 auto foundTitles = findTitlesFromLine(line);
698 boost::trim(foundTitles);
699 if (foundTitles.find(
"\\") == std::string::npos) {
713 auto date = line.substr(2, 11);
714 auto _time = line.substr(14, 8);
719 if (line.find(
"Title") != std::string::npos) {
722 }
else if (std::find(std::begin(PSI_MONTHS), std::end(PSI_MONTHS), line.substr(5, 3)) != std::end(PSI_MONTHS)) {
731 const int uselessLines = 6;
733 std::string line =
"";
734 for (
const auto charecter : contents) {
735 if (charecter ==
'\n') {
736 if (line.empty() || line[0] !=
'!') {
738 }
else if (lineNo > uselessLines) {
750 std::vector<std::string> segments;
751 boost::split(segments, line, boost::is_any_of(
"\\"));
754 if (segments.size() != 5) {
755 throw std::runtime_error(
"Line does not have 5 segments delimited by \\: '" + line +
"'");
757 const auto recordTime = segments[0];
758 const auto numValues = std::stoi(segments[1]);
759 std::vector<std::string> firstValues;
760 boost::split(firstValues, segments[2], boost::is_any_of(
" "));
761 std::vector<std::string> secondValues;
762 boost::split(secondValues, segments[3], boost::is_any_of(
" "));
766 double secondsInRecordTime = (std::stoi(recordTime.substr(0, 2)) * 60 * 60) +
767 (std::stoi(recordTime.substr(3, 2)) * 60) +
768 (std::stoi(recordTime.substr(6, 2)));
772 logAlg->setProperty(
"Workspace", ws);
773 logAlg->setProperty(
"Time", timeLog);
775 for (
auto i = 0; i < numValues; ++i) {
777 logAlg->setProperty(
"Type",
"double");
778 logAlg->setProperty(
"Value", firstValues[i]);
779 logAlg->executeAsChildAlg();
783 logAlg->setProperty(
"Type",
"double");
784 logAlg->setProperty(
"Value", firstValues[0]);
785 logAlg->executeAsChildAlg();
788 logAlg->setProperty(
"Type",
"double");
789 logAlg->setProperty(
"Value", secondValues[0]);
790 logAlg->executeAsChildAlg();
799 namespace fs = std::filesystem;
800 const fs::path searchDir{fs::path{
getPropertyValue(
"Filename")}.parent_path()};
802 std::deque<fs::path> queue{fs::path{searchDir}};
803 while (!queue.empty()) {
804 const auto first = queue.front();
806 for (fs::directory_iterator dirIter{first}; dirIter != fs::directory_iterator(); ++dirIter) {
807 const auto &entry{dirIter->path()};
809 if (fs::is_directory(entry)) {
810 const auto relPath{entry.lexically_relative(searchDir)};
811 if (std::distance(relPath.begin(), relPath.end()) < TEMPERATURE_FILE_MAX_SEARCH_DEPTH) {
814 queue.push_back(entry);
816 }
else if (entry.extension() == TEMPERATURE_FILE_EXT &&
818 return entry.string();
828 const bool searchForTempFile =
getProperty(
"SearchForTempFile");
829 if (fileName ==
"" && searchForTempFile) {
833 if (fileName ==
"") {
834 throw std::invalid_argument(
"No temperature file could be found/was provided");
837 g_log.
notice(
"Temperature file in use by LoadPSIMuonBin: '" + fileName +
"'");
839 std::ifstream in(fileName, std::ios::in);
840 std::string contents;
841 in.seekg(0, std::ios::end);
842 contents.resize(in.tellg());
843 in.seekg(0, std::ios::beg);
844 in.read(&contents[0], contents.size());
849 std::string line =
"";
850 for (
const auto &character : contents) {
851 if (character ==
'\n') {
852 if (!line.empty() && line[0] ==
'!') {
#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.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
@ Load
allowed here which will be passed to the algorithm
TableRow represents a row in a TableWorkspace.
A property class for workspaces.
std::vector< std::vector< double > > m_eAxis
void readInHeader(Mantid::Kernel::BinaryStreamReader &streamReader)
int version() const override
function to return a version of the algorithm, must be overridden in all algorithms
void exec() override
Virtual method - must be overridden by concrete algorithm.
void readArrayVariables(Mantid::Kernel::BinaryStreamReader &streamReader)
void readInTemperatureFileHeader(const std::string &contents)
void processDateHeaderLine(const std::string &line)
struct headerData m_header
struct temperatureHeaderData m_tempHeader
const std::string summary() const override
function returns a summary message that will be displayed in the default GUI, and in the help.
void readInHistograms(Mantid::Kernel::BinaryStreamReader &streamReader)
void readInTemperatureFile(DataObjects::Workspace2D_sptr &ws)
void init() override
Virtual method - must be overridden by concrete algorithm.
std::vector< std::vector< double > > m_histograms
void processLine(const std::string &line, DataObjects::Workspace2D_sptr &ws)
void readSingleVariables(Mantid::Kernel::BinaryStreamReader &streamReader)
void processTitleHeaderLine(const std::string &line)
Mantid::API::Algorithm_sptr createSampleLogAlgorithm(DataObjects::Workspace2D_sptr &ws)
void processHeaderLine(const std::string &line)
void assignOutputWorkspaceParticulars(DataObjects::Workspace2D_sptr &outputWorkspace)
int confidence(Kernel::FileDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
void generateUnknownAxis()
const std::string category() const override
function to return a category of the algorithm.
std::string detectTempFile()
void makeDeadTimeTable(const size_t &numSpec)
API::MatrixWorkspace_sptr extractSpectra(DataObjects::Workspace2D_sptr &ws)
void addToSampleLog(const std::string &logName, const std::string &logText, DataObjects::Workspace2D_sptr &ws)
void setDetectorGroupingTable(const size_t &numSpec)
std::vector< double > m_xAxis
std::string getFormattedDateTime(const std::string &date, const std::string &time)
void readStringVariables(Mantid::Kernel::BinaryStreamReader &streamReader)
Support for a property that holds an array of values.
Assists with reading a binary file by providing standard overloads for the istream operators (>>) to ...
BinaryStreamReader & read(std::vector< int16_t > &value, const size_t nvals)
Read an array of int16_t into the given vector.
void moveStreamToPosition(size_t nbytes)
Move the stream to nbytes past the beginning of the file.
Defines a wrapper around an open file.
std::istream & data()
Access the open file stream.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void notice(const std::string &msg)
Logs at notice level.
void warning(const std::string &msg)
Logs at warning level.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
static const UnitLabel Microsecond
Microsecond.
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
DataObjects::TableWorkspace_sptr createTimeZeroTable(const size_t numSpec, const std::vector< double > &timeZeros)
Creates a timezero table for the loaded detectors.
std::shared_ptr< Workspace2D > Workspace2D_sptr
shared pointer to Mantid::DataObjects::Workspace2D
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
int32_t specnum_t
Typedef for a spectrum Number.
std::string to_string(const wide_integer< Bits, Signed > &n)
int16_t numberOfDataRecordsHistogram
int16_t lengthOfDataRecordsBin
std::string labels_scalars[18]
float temperatureDeviation[4]
int16_t lengthOfHistograms
int16_t numberOfHistograms
std::string labelsOfHistograms[16]
int16_t numberOfHistogramsPerRecord
int32_t monNumberOfevents
int16_t numberOfDataRecordsFile
bool delimeterOfTitlesIsBackSlash
std::string startDateTime
std::vector< std::string > titles
@ Input
An input workspace.
@ Output
An output workspace.