22#include <boost/algorithm/string.hpp>
32constexpr int NUM_OF_SPECTRA = 16384;
42uint64_t swapUint64(uint64_t word) {
43 word = ((word << 8) & 0xFF00FF00FF00FF00ULL) | ((word >> 8) & 0x00FF00FF00FF00FFULL);
44 word = ((word << 16) & 0xFFFF0000FFFF0000ULL) | ((word >> 16) & 0x0000FFFF0000FFFFULL);
45 return (word << 32) | (word >> 32);
55void correctForBigEndian(
const EventUnion &bigEndian, EventUnion &smallEndian) {
56 smallEndian.splitWord.words[0] = swapUint64(bigEndian.splitWord.words[1]);
57 smallEndian.splitWord.words[1] = swapUint64(bigEndian.splitWord.words[0]);
72void addFrameToOutputWorkspace(
int &rawFrames,
int &goodFrames,
const int eventCountInFrame,
const int minEventsReq,
73 const int maxEventsReq, MantidVec &frameEventCounts,
74 std::vector<DataObjects::EventList> &events,
75 std::vector<DataObjects::EventList> &eventsInFrame) {
77 if (eventCountInFrame >= minEventsReq && eventCountInFrame <= maxEventsReq) {
79 frameEventCounts.emplace_back(eventCountInFrame);
84 for (auto i = 0; i < NUM_OF_SPECTRA; ++i) {
85 if (eventsInFrame[i].getNumberEvents() > 0) {
86 events[i] += eventsInFrame[i];
87 eventsInFrame[i].clear();
94 for (auto i = 0; i < NUM_OF_SPECTRA; ++i) {
95 eventsInFrame[i].clear();
112void addFrameToOutputWorkspace(
int &rawFrames,
int &goodFrames,
const int eventCountInFrame,
const int minEventsReq,
113 const int maxEventsReq, MantidVec &frameEventCounts,
114 std::vector<std::vector<double>> &counts,
115 std::vector<std::vector<double>> &countsInFrame) {
117 if (eventCountInFrame >= minEventsReq && eventCountInFrame <= maxEventsReq) {
119 frameEventCounts.emplace_back(eventCountInFrame);
124 for (auto i = 0; i < NUM_OF_SPECTRA; ++i) {
125 auto &countsInFramePixel = countsInFrame[i];
126 for (
size_t j = 0; j < countsInFramePixel.size(); ++j) {
127 auto &countsInFramePixelByBin = countsInFramePixel[j];
128 if (countsInFramePixelByBin > 0) {
129 counts[i][j] += countsInFramePixelByBin;
130 countsInFramePixelByBin = 0;
137 for (auto i = 0; i < NUM_OF_SPECTRA; ++i) {
138 auto &countsInFramePixel = countsInFrame[i];
139 std::fill(countsInFramePixel.begin(), countsInFramePixel.end(), 0);
152 const std::vector<DataObjects::EventList> &events) {
154 std::vector<double> xAxis(
int(std::ceil(maxToF / binWidth)));
155 std::generate(xAxis.begin(), xAxis.end(), [i = 0, &binWidth]()
mutable { return binWidth * i++; });
158 NUM_OF_SPECTRA, HistogramData::Histogram(HistogramData::BinEdges(xAxis)));
160 for (auto i = 0; i < NUM_OF_SPECTRA; ++i) {
161 dataWorkspace->getSpectrum(i) = events[i];
162 dataWorkspace->getSpectrum(i).setSpectrumNo(i + 1);
163 dataWorkspace->getSpectrum(i).setDetectorID(i + 1);
165 dataWorkspace->setAllX(HistogramData::BinEdges{xAxis});
166 dataWorkspace->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create(
"TOF");
167 dataWorkspace->setYUnit(
"Counts");
168 return std::dynamic_pointer_cast<API::MatrixWorkspace>(dataWorkspace);
178 std::vector<std::vector<double>> &&counts) {
179 const HistogramData::BinEdges bins{std::move(binEdges)};
182 for (auto i = 0; i < NUM_OF_SPECTRA; ++i) {
183 dataWorkspace->setHistogram(i, bins, HistogramData::Counts{std::move(counts[i])});
184 dataWorkspace->getSpectrum(i).setSpectrumNo(i + 1);
185 dataWorkspace->getSpectrum(i).setDetectorID(i + 1);
187 dataWorkspace->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create(
"TOF");
188 dataWorkspace->setYUnit(
"Counts");
189 return dataWorkspace;
199template <
typename ValueType>
201 ws->mutableRun().addProperty(
name,
value,
false);
209void insertValidationResult(
const std::vector<std::pair<std::string, std::string>> &result,
210 std::map<std::string, std::string> &results) {
211 std::copy(result.cbegin(), result.cend(), std::inserter(results, results.end()));
221std::vector<double> calculateBinEdges(
const double minToF,
const double maxToF,
const double binWidth) {
222 const int numBins =
static_cast<int>(std::ceil((maxToF - minToF) / binWidth));
224 std::views::iota(0) | std::views::transform([&binWidth, &minToF](
int n) {
return minToF + (
n * binWidth); });
225 return {custom_range.begin(), custom_range.begin() + numBins + 1};
249 const std::vector<std::string> extentions{
".edb"};
250 declareProperty(std::make_unique<API::MultipleFileProperty>(
"Filename", extentions),
251 "The name of the nGEM file to load. Selecting multiple files will "
252 "combine them into one workspace.");
256 "The output workspace");
258 auto mustBePositive = std::make_shared<Kernel::BoundedValidator<int>>();
259 mustBePositive->setLower(0);
261 auto mustBePositiveDbl = std::make_shared<Kernel::BoundedValidator<double>>();
262 mustBePositiveDbl->setLower(0.0);
265 declareProperty(
"BinWidth", 10.0, mustBePositiveDbl,
"The width of the time bins in the output.");
267 "The minimum ToF bin edge, inclusive. Required if PreserveEvents=False. If PreserveEvents=True and "
268 "MinToF is default, value will "
269 "be dervied from event data.");
271 "The maximum ToF bin edge, exclusive. Required if PreserveEvents=False. If PreserveEvents=True and "
272 "MaxToF is default, value will "
273 "be dervied from event data.");
276 "The minimum number of events required in a frame before a "
277 "it is considered 'good'.");
279 "The maximum number of events allowed in a frame to be "
280 "considered 'good'.");
283 "Generate a workspace to show the number of events captured by each "
284 "frame. (optional, default False).");
286 "Algorithm preserves events, generating an event workspace. If False, events are not preserved and a "
287 "Workspace 2D is generated (reduced memory usage). "
288 "(optional, default True).");
297 std::vector<std::vector<std::string>> filePaths =
getProperty(
"Filename");
298 const int minEventsReq(
getProperty(
"MinEventsPerFrame"));
299 const int maxEventsReq(
getProperty(
"MaxEventsPerFrame"));
303 const bool preserveEvents(
getProperty(
"PreserveEvents"));
306 if (preserveEvents) {
307 res =
readDataAsEvents(minToF, maxToF, binWidth, minEventsReq, maxEventsReq, filePaths);
344 double &maxToF,
const double binWidth,
int &rawFrames,
int &goodFrames,
345 const int minEventsReq,
const int maxEventsReq, MantidVec &frameEventCounts,
346 const size_t totalFilePaths, std::shared_ptr<LoadDataStrategyBase> strategy) {
348 if (filePath.size() > 1) {
349 throw std::runtime_error(
"Invalid filename parameter.");
351 std::ifstream file(filePath[0].c_str(), std::ifstream::binary);
352 if (!file.is_open()) {
353 throw std::runtime_error(
"File could not be found.");
357 constexpr size_t SKIP_WORD_SIZE = 4;
358 size_t numProcessedEvents = 0;
359 size_t numWordsSkipped = 0;
367 bool isEventInvalid =
true;
368 bool isNotEOFAfterSkip =
true;
370 file.read(
reinterpret_cast<char *
>(&eventBigEndian),
sizeof(eventBigEndian));
372 correctForBigEndian(eventBigEndian, event);
373 isEventInvalid = !
event.generic.check();
374 if (isEventInvalid) {
375 isNotEOFAfterSkip = !file.seekg(SKIP_WORD_SIZE, std::ios_base::cur).eof();
376 if (isNotEOFAfterSkip) {
380 }
while (isEventInvalid && isNotEOFAfterSkip);
386 size_t pixel =
event.coincidence.getPixel();
388 const double tof =
event.coincidence.timeOfFlight / 1000.0;
389 strategy->addEvent(minToF, maxToF, tof, binWidth,
392 strategy->addFrame(rawFrames, goodFrames, eventCountInFrame, minEventsReq, maxEventsReq, frameEventCounts);
397 g_log.
warning() <<
"Unexpected event type ID=" <<
event.generic.id <<
" loaded.\n";
402 if (numWordsSkipped > 0) {
404 <<
" bytes of file data were skipped when locating valid events.\n";
418 file.seekg(0, file.end);
419 size_t size = file.tellg();
420 if (size % 16 != 0) {
421 g_log.
warning() <<
"Invalid file size. File is size is " << size
422 <<
" bytes which is not a multiple of 16. There may be some bytes "
423 "missing from the data. \n";
440 const size_t totalNumEvents,
const size_t totalFilePaths) {
441 numProcessedEvents += eventCountInFrame;
443 progress(
double(numProcessedEvents) /
double(totalNumEvents) / 1.11111, message);
444 eventCountInFrame = 0;
456 std::vector<double> xAxisCounts(frameEventCounts.size() + 1);
457 std::generate(xAxisCounts.begin(), xAxisCounts.end(), [
n = 0.0]()
mutable { return ++n; });
460 DataObjects::create<DataObjects::Workspace2D>(1, HistogramData::Histogram(HistogramData::BinEdges(xAxisCounts)));
462 countsWorkspace->mutableY(0) = frameEventCounts;
463 std::string countsWorkspaceName(this->
getProperty(
"OutputWorkspace"));
464 countsWorkspaceName.append(
"_event_counts");
465 countsWorkspace->setYUnit(
"Counts");
466 std::shared_ptr<Kernel::Units::Label> XLabel =
467 std::dynamic_pointer_cast<Kernel::Units::Label>(Kernel::UnitFactory::Instance().
create(
"Label"));
468 XLabel->setLabel(
"Frame");
469 countsWorkspace->getAxis(0)->unit() = XLabel;
473 "Counts of events per frame.");
475 this->
setProperty(
"CountsWorkspace", countsWorkspace);
499 std::map<std::string, std::string> results;
511 const int MinEventsPerFrame =
getProperty(
"MinEventsPerFrame");
512 const int MaxEventsPerFrame =
getProperty(
"MaxEventsPerFrame");
513 if (MaxEventsPerFrame < MinEventsPerFrame) {
514 return {{
"MaxEventsPerFrame",
"MaxEventsPerFrame is less than MinEvents per frame"}};
527 const bool preserveEvents =
getProperty(
"PreserveEvents");
528 std::vector<std::pair<std::string, std::string>> result;
529 if (preserveEvents) {
534 result.emplace_back(
"MinToF",
"Please supply both, or neither, Min and MaxToF if PreserveEvents is True");
537 result.emplace_back(
"MaxToF",
"Please supply both, or neither, Min and MaxToF if PreserveEvents is True");
541 result.emplace_back(
"MinToF",
"MinToF must be supplied if PreserveEvents is False");
544 result.emplace_back(
"MaxToF",
"MaxToF must be supplied if PreserveEvents is False");
547 if (maxToF <= minToF) {
548 result.emplace_back(
"MaxToF",
"MaxToF is less than or equal to MinToF");
565 const int maxEventsReq,
566 const std::vector<std::vector<std::string>> &filePaths) {
567 int eventCountInFrame{0};
570 std::vector<double> frameEventCounts;
572 size_t totalFilePaths(filePaths.size());
575 auto strategy = std::make_shared<LoadDataStrategyEvent>();
576 for (
const auto &filePath : filePaths) {
577 loadSingleFile(filePath, eventCountInFrame, minToF, maxToF, binWidth, rawFrames, goodFrames, minEventsReq,
578 maxEventsReq, frameEventCounts, totalFilePaths, strategy);
581 strategy->addFrame(rawFrames, goodFrames, eventCountInFrame, minEventsReq, maxEventsReq, frameEventCounts);
583 dataWorkspace = createEventWorkspace(maxToF, binWidth, strategy->getEvents());
585 return {rawFrames, goodFrames, frameEventCounts, dataWorkspace};
600 const int minEventsReq,
const int maxEventsReq,
601 const std::vector<std::vector<std::string>> &filePaths) {
604 int eventCountInFrame{0};
605 std::vector<double> frameEventCounts;
607 size_t totalFilePaths(filePaths.size());
610 auto strategy = std::make_shared<LoadDataStrategyHisto>(minToF, maxToF, binWidth);
611 for (
const auto &filePath : filePaths) {
612 loadSingleFile(filePath, eventCountInFrame, minToF, maxToF, binWidth, rawFrames, goodFrames, minEventsReq,
613 maxEventsReq, frameEventCounts, totalFilePaths, strategy);
616 strategy->addFrame(rawFrames, goodFrames, eventCountInFrame, minEventsReq, maxEventsReq, frameEventCounts);
618 dataWorkspace = createHistogramWorkspace(std::move(strategy->getBinEdges()), std::move(strategy->getCounts()));
619 return {rawFrames, goodFrames, frameEventCounts, dataWorkspace};
632 const size_t pixel) {
633 if (tof >= maxToF || tof < minToF) {
636 const int bin_idx =
static_cast<int>(std::floor((tof - minToF) / binWidth));
651 const int minEventsReq,
const int maxEventsReq, MantidVec &frameEventCounts) {
652 addFrameToOutputWorkspace(rawFrames, goodFrames, eventCountInFrame, minEventsReq, maxEventsReq, frameEventCounts,
657 : m_binEdges{calculateBinEdges(minToF, maxToF, binWidth)} {
675 const size_t pixel) {
697 const int minEventsReq,
const int maxEventsReq, MantidVec &frameEventCounts) {
698 addFrameToOutputWorkspace(rawFrames, goodFrames, eventCountInFrame, minEventsReq, maxEventsReq, frameEventCounts,
double value
The value of the point.
#define PARALLEL_FOR_NO_WSP_CHECK()
#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.
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.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
bool isDefault(const std::string &name) const
bool getCancel() const
Returns the cancellation state.
A property class for workspaces.
void addFrame(int &rawFrames, int &goodFrames, const int eventCountInFrame, const int minEventsReq, const int maxEventsReq, MantidVec &frameEventCounts) override
Add a completed frame to the event list.
std::vector< DataObjects::EventList > m_eventsInFrame
std::vector< DataObjects::EventList > m_events
void addEvent(double &minToF, double &maxToF, const double tof, const double binWidth, const size_t pixel) override
Add an event to the event list.
void addEvent(double &minToF, double &maxToF, const double tof, const double binWidth, const size_t pixel) override
Add an event to the relevant histogram.
void addFrame(int &rawFrames, int &goodFrames, const int eventCountInFrame, const int minEventsReq, const int maxEventsReq, MantidVec &frameEventCounts) override
Add a completed frame to the count-by-spectra vector.
std::vector< std::vector< double > > m_counts
LoadDataStrategyHisto(const double minToF, const double maxToF, const double binWidth)
std::vector< std::vector< double > > m_countsInFrame
std::vector< double > m_binEdges
int confidence(Kernel::FileDescriptor &descriptor) const override
The confidence that an algorithm is able to load the file.
LoadDataResult readDataAsEvents(double &minToF, double &maxToF, const double binWidth, const int minEventsReq, const int maxEventsReq, const std::vector< std::vector< std::string > > &filePaths)
Read data from files into an event workspace, preserving events.
void createCountWorkspace(const std::vector< double > &frameEventCounts)
Create a workspace to store the number of counts per frame.
void exec() override
Execute the algorithm.
LoadDataResult readDataAsHistograms(double &minToF, double &maxToF, const double binWidth, const int minEventsReq, const int maxEventsReq, const std::vector< std::vector< std::string > > &filePaths)
Read data from files into as histograms into a workspace2D.
void loadInstrument(API::MatrixWorkspace_sptr &dataWorkspace)
Load the instrument and attach to the data workspace.
std::vector< std::pair< std::string, std::string > > validateMinMaxToF()
Validate minimum and maximum TOF.
std::map< std::string, std::string > validateInputs() override
Validate the imputs into the algorithm, overrides.
void loadSingleFile(const std::vector< std::string > &filePath, int &eventCountInFrame, double &minToF, double &maxToF, const double binWidth, int &rawFrames, int &goodFrames, const int minEventsReq, const int maxEventsReq, MantidVec &frameEventCounts, const size_t totalFilePaths, std::shared_ptr< LoadDataStrategyBase > strategy)
Load a file into the event lists.
size_t verifyFileSize(std::ifstream &file)
Check that a file to be loaded is in 128 bit words.
bool reportProgressAndCheckCancel(size_t &numProcessedEvents, int &eventCountInFrame, const size_t totalNumEvents, const size_t totalFilePaths)
Reports progress and checks cancel flag.
std::vector< std::pair< std::string, std::string > > validateEventsPerFrame()
Validate events per frame inputs.
void init() override
Initialise the algorithm.
Defines a wrapper around an open file.
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 warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
OptionalBool : Tri-state bool.
The concrete, templated class for properties.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< Workspace2D > Workspace2D_sptr
shared pointer to Mantid::DataObjects::Workspace2D
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
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.
Mantid::DataObjects::EventWorkspace_sptr createEventWorkspace()
Create event workspace with: 500 pixels 1000 histogrammed bins.
std::string to_string(const wide_integer< Bits, Signed > &n)
Holds variables tracking the data load across all files.
API::MatrixWorkspace_sptr dataWorkspace
std::vector< double > frameEventCounts
@ Input
An input workspace.
@ Output
An output workspace.
Is able to hold all versions of the data words in the same memory location.
CoincidenceEvent coincidence