19#include <nexus/NeXusFile.hpp>
21#include <boost/algorithm/string/detail/classification.hpp>
22#include <boost/algorithm/string/split.hpp>
29using namespace Kernel;
31using namespace DataObjects;
32using HistogramData::BinEdges;
33using HistogramData::Counts;
34using HistogramData::CountStandardDeviations;
37 : m_numPixels(0), m_signalNo(0), pulseTimes(0), m_numBins(0), m_spec_min(0), m_spec_max(0), m_dataField(
""),
38 m_axisField(
""), m_xUnits(
""), m_fileMutex(), m_assumeOldFile(false) {}
43 "The name of the NeXus file to load");
45 "The name of the Workspace2D to create.");
47 "Number of the signal to load from the file. Default is 1 = "
49 "Some NXS files have multiple data fields giving binning in "
50 "other units (e.g. d-spacing or momentum).\n"
51 "Enter the right signal number for your desired field.");
52 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
53 mustBePositive->setLower(1);
55 "The index number of the first spectrum to read. Only used if\n"
56 "spectrum_max is set.");
58 "The number of the last spectrum to read. Only used if explicitly\n"
73 if (hasData && hasEventData)
76 else if (hasData && !hasEventData)
94 std::vector<std::string> &bankNames) {
102 auto file = ::NeXus::File(nexusfilename);
105 file.openGroup(entry_name,
"NXentry");
107 file.openGroup(
"instrument",
"NXinstrument");
110 std::map<std::string, std::string> entries = file.getEntries();
111 std::map<std::string, std::string>::iterator it;
112 for (it = entries.begin(); it != entries.end(); ++it) {
113 std::string
name = it->first;
114 if (
name.size() > 4) {
115 if (
name.substr(0, 4) ==
"bank") {
117 file.openGroup(
name, it->second);
121 std::map<std::string, std::string> dataEntries = file.getEntries();
122 for (
auto dataEntryIt = dataEntries.begin(); dataEntryIt != dataEntries.end(); ++dataEntryIt) {
123 if (dataEntryIt->second ==
"SDS") {
124 file.openData(dataEntryIt->first);
125 if (file.hasAttr(
"signal")) {
127 file.getAttr(
"signal", signal);
134 if (!file.hasAttr(
"axes")) {
137 ", corresponds to the data field '" +
m_dataField +
138 "' has no 'axes' attribute specifying.");
141 axes =
"x_pixel_offset,y_pixel_offset,time_of_flight";
146 file.getAttr(
"axes", axes);
149 std::vector<std::string> allAxes;
150 boost::split(allAxes, axes, boost::algorithm::detail::is_any_ofF<char>(
","));
151 if (allAxes.size() != 3)
153 ", corresponds to the data field '" +
m_dataField +
"' which has only " +
174 ", was not found in any of the data fields of any "
175 "'bankX' group. Cannot load file.");
177 for (it = entries.begin(); it != entries.end(); ++it) {
178 std::string
name = it->first;
179 if (
name.size() > 4) {
180 if (
name.substr(0, 4) ==
"bank") {
182 file.openGroup(
name, it->second);
183 const auto bankEntries = file.getEntries();
185 if (bankEntries.find(
"pixel_id") != bankEntries.end()) {
186 bankNames.emplace_back(
name);
189 file.openData(
"pixel_id");
190 std::vector<int64_t> dims = file.getInfo().dims;
194 const size_t newPixels = std::accumulate(dims.cbegin(), dims.cend(),
static_cast<size_t>(1),
195 [](
size_t product,
auto dim) { return product * dim; });
199 bankNames.emplace_back(
name);
202 file.openData(
"x_pixel_offset");
203 std::vector<int64_t> xdim = file.getInfo().dims;
206 file.openData(
"y_pixel_offset");
207 std::vector<int64_t> ydim = file.getInfo().dims;
210 if (!xdim.empty() && !ydim.empty()) {
215 if (bankEntries.find(
m_axisField) != bankEntries.end()) {
218 std::vector<int64_t> dims = file.getInfo().dims;
220 if (file.hasAttr(
"units"))
254 return (wi + 1 < m_min || wi + 1 > m_max);
275 g_log.
debug() <<
"Loading bank " << bankName <<
'\n';
280 auto file = ::NeXus::File(nexusfilename);
281 file.openGroup(entry_name,
"NXentry");
282 file.openGroup(
"instrument",
"NXinstrument");
283 file.openGroup(bankName,
"NXdetector");
286 std::vector<uint32_t> pixel_id;
290 file.readData(
"pixel_id", pixel_id);
295 g_log.
warning() <<
"Invalid pixel_id data in " << bankName <<
'\n';
300 std::vector<float> xoffsets;
301 std::vector<float> yoffsets;
302 file.readData(
"x_pixel_offset", xoffsets);
303 file.readData(
"y_pixel_offset", yoffsets);
309 g_log.
warning() <<
"Invalid (x,y) offsets in " << bankName <<
'\n';
314 if (bankName.size() > 4) {
315 if (bankName.substr(0, 4) ==
"bank") {
316 bankNum = boost::lexical_cast<size_t>(bankName.substr(4));
321 g_log.
warning() <<
"Invalid bank number for " << bankName <<
'\n';
327 size_t numX = xoffsets.size();
328 size_t numY = yoffsets.size();
330 for (
size_t i = 0; i < numX; i++) {
331 for (
size_t j = 0; j < numY; j++) {
332 pixel_id.emplace_back(
static_cast<uint32_t
>(j + numY * (i + numX * bankNum)));
339 uint32_t ifirst = pixel_id[0];
341 auto newEnd = std::remove_if(pixel_id.begin(), pixel_id.end(), out_range);
342 pixel_id.erase(newEnd, pixel_id.end());
344 if (ifirst != pixel_id[0])
350 g_log.
warning() <<
"No pixels from " << bankName <<
'\n';
355 std::vector<float> tof;
358 if (tof.size() <= 1) {
365 BinEdges
X(tof.begin(), tof.end());
368 std::string errorsField;
369 std::vector<double> data;
371 file.getDataCoerce(data);
372 if (file.hasAttr(
"errors"))
373 file.getAttr(
"errors", errorsField);
377 bool hasErrors = !errorsField.empty();
378 std::vector<double> errors;
381 file.openData(errorsField);
382 file.getDataCoerce(errors);
385 g_log.
information() <<
"Error loading the errors field, '" << errorsField <<
"' for bank " << bankName
386 <<
". Will use sqrt(counts). \n";
395 for (
size_t i = iPart; i < iPart +
m_numPixels; i++) {
397 detid_t pixelID = pixel_id[i - iPart];
398 size_t wi = id_to_wi.find(pixelID)->second;
401 auto &spec = WS->getSpectrum(wi);
403 spec.setDetectorID(pixel_id[i - iPart]);
404 auto from = data.begin() + i *
m_numBins;
408 auto eFrom = errors.begin() + i *
m_numBins;
410 spec.setHistogram(
X, Counts(from, to), CountStandardDeviations(eFrom, eTo));
412 spec.setHistogram(
X, Counts(from, to));
421 std::string entry_name =
"entry";
422 auto file = ::NeXus::File(filename);
423 std::map<std::string, std::string> entries = file.getEntries();
427 throw std::runtime_error(
"No entries in the NXS file!");
431 if (entries.find(entry_name) == entries.end())
432 entry_name =
"entry-state0";
434 if (entries.find(entry_name) == entries.end())
435 entry_name = entries.begin()->first;
462 auto prog = std::make_unique<Progress>(
this, 0.0, 1.0, 10);
463 prog->doReport(
"Counting pixels");
464 std::vector<std::string> bankNames;
468 prog->setNumSteps(bankNames.size() + 5);
470 prog->doReport(
"Creating workspace");
475 prog->doReport(
"Loading DAS logs");
479 auto periodLog = std::make_unique<const TimeSeriesProperty<int>>(
"period_log");
480 LoadEventNexus::runLoadNexusLogs<MatrixWorkspace_sptr>(filename, WS, *
this,
false, nPeriods, periodLog);
483 prog->report(
"Loading instrument");
485 LoadEventNexus::runLoadInstrument<MatrixWorkspace_sptr>(filename, WS, entry_name,
this);
488 prog->report(
"Loading metadata");
494 }
catch (std::exception &e) {
495 g_log.
warning() <<
"Error while loading meta data: " << e.what() <<
'\n';
500 prog->report(
"Building Spectra Mapping");
501 g_log.
debug() <<
"Building Spectra Mapping\n";
502 WS->rebuildSpectraMapping(
false);
505 const auto id_to_wi = WS->getDetectorIDToWorkspaceIndexMap();
508 for (
const auto &bankName : bankNames) {
509 prog->report(
"Loading bank " + bankName);
510 g_log.
debug() <<
"Loading bank " << bankName <<
'\n';
511 loadBank(filename, entry_name, bankName, WS, id_to_wi);
516 WS->getAxis(0)->setUnit(
"dSpacing");
518 WS->getAxis(0)->setUnit(
"MomentumTransfer");
521 WS->getAxis(0)->setUnit(
"TOF");
522 WS->setYUnit(
"Counts");
detid2index_map m_id_to_wi
#define DECLARE_NEXUS_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro wh...
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.
@ Load
allowed here which will be passed to the algorithm
A property class for workspaces.
static void loadEntryMetadata(const std::string &nexusfilename, T WS, const std::string &entry_name, const Kernel::NexusHDF5Descriptor &descriptor)
Load the run number and other meta data from the given bank.
size_t m_numBins
Number of bins.
std::string m_dataField
Name of the 'data' field to load (depending on Signal)
int m_signalNo
Signal # to load. Default 1.
bool m_assumeOldFile
Flag for whether or not to assume the data is old SNS raw files;.
int confidence(Kernel::NexusDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
static std::string getEntryName(const std::string &filename)
std::mutex m_fileMutex
Mutex to avoid simultaneous file access.
void countPixels(const std::string &nexusfilename, const std::string &entry_name, std::vector< std::string > &bankNames)
Goes thoguh a histogram NXS file and counts the number of pixels.
LoadTOFRawNexus()
Default Constructor.
void exec() override
Executes the algorithm.
const std::string name() const override
Algorithm's name for identification overriding a virtual method.
specnum_t m_spec_min
Interval of chunk.
size_t m_numPixels
Number of pixels.
void loadBank(const std::string &nexusfilename, const std::string &entry_name, const std::string &bankName, const API::MatrixWorkspace_sptr &WS, const detid2index_map &id_to_wi)
Load a single bank into the workspace.
void init() override
Initialisation method.
std::string m_axisField
Name of the 'axis' field to load (depending on Signal)
std::string m_xUnits
Units of the X axis found.
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 warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
Defines a wrapper around a file whose internal structure can be accessed using the NeXus API.
bool classTypeExists(const std::string &classType) const
Query if a given type exists somewhere in the file.
bool pathOfTypeExists(const std::string &path, const std::string &type) const
Query if a path exists of a given type.
The concrete, templated class for properties.
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 toString(const T &value)
Convert a number to a string.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
int32_t detid_t
Typedef for a detector ID.
std::unordered_map< detid_t, size_t > detid2index_map
Map with key = detector ID, value = workspace index.
int32_t specnum_t
Typedef for a spectrum Number.
@ Output
An output workspace.