Mantid
Loading...
Searching...
No Matches
LoadNexusProcessed2.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2019 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 +
10#include "MantidAPI/Workspace.h"
13#include "MantidIndexing/IndexInfo.h"
15#include "MantidNexusGeometry/AbstractLogger.h"
16#include "MantidNexusGeometry/NexusGeometryParser.h"
17#include "MantidTypes/SpectrumDefinition.h"
18
19#include <H5Cpp.h>
20#include <algorithm>
21
22namespace Mantid::DataHandling {
25
26// Register the algorithm into the AlgorithmFactory
27DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadNexusProcessed2)
28//----------------------------------------------------------------------------------------------
29
30namespace {
31template <typename T> int countEntriesOfType(const T &entry, const std::string &nxClass) {
32 return static_cast<int>(std::count_if(entry.groups().cbegin(), entry.groups().cend(),
33 [&nxClass](const auto &group) { return group.nxclass == nxClass; }));
34}
35
36template <typename T>
37std::vector<Mantid::Nexus::NXClassInfo> findEntriesOfType(const T &entry, const std::string &nxClass) {
38 std::vector<Mantid::Nexus::NXClassInfo> result;
39 std::copy_if(entry.groups().cbegin(), entry.groups().cend(), std::back_inserter(result),
40 [&nxClass](const auto &group) { return group.nxclass == nxClass; });
41 return result;
42}
50InstrumentLayout instrumentFormat(Mantid::Nexus::NXEntry &entry) {
52 const auto instrumentsCount = countEntriesOfType(entry, "NXinstrument");
53 if (instrumentsCount == 1) {
54 // Can now assume nexus format
56
57 if (entry.containsGroup("instrument")) {
58 auto instr = entry.openNXInstrument("instrument");
59 if (instr.containsGroup("detector") ||
60 (instr.containsGroup("physical_detectors") && instr.containsGroup("physical_monitors"))) {
61 result = InstrumentLayout::Mantid; // 1 NXinstrument group called "instrument",
62 }
63 instr.close();
64 }
65 entry.close();
66 }
67 return result;
68}
69
70} // namespace
71
73int LoadNexusProcessed2::version() const { return 2; }
74
77
78 m_instrumentLayout = instrumentFormat(mtd_entry);
80 // Now assign the spectra-detector map
81 readInstrumentGroup(mtd_entry, ws);
83 extractMappingInfoNew(mtd_entry);
84 } else {
85 g_log.information() << "Instrument layout not recognised. Spectra mappings not loaded.";
86 }
87}
88
90 using namespace Mantid::Nexus;
91
92 const std::string &parent = mtd_entry.name();
93 auto result = findEntriesOfType(mtd_entry, "NXinstrument");
94 if (result.size() != 1) {
95 g_log.warning("We are expecting a single NXinstrument. No mappings will be loaded");
96 }
97 auto inst = mtd_entry.openNXInstrument(result[0].nxname);
98
99 // For workspace groups, the spectral mapping information is keyed by the name of the parent NXentry.
100 // Normally, we would not expect this key to have already been entered into these maps.
101 // However there is a known defect (EWM#7910): in that for a workspace group, the first NXentry is loaded twice.
102 // For this reason, at the moment, `std::unordered_map<..>::emplace` should not be used in the following.
103
104 m_spectrumNumberss[parent] = std::vector<Indexing::SpectrumNumber>();
105 auto &spectrumNumbers = m_spectrumNumberss[parent];
106 m_detectorIdss[parent] = std::vector<Mantid::detid_t>();
107 auto &detectorIds = m_detectorIdss[parent];
108 m_detectorCountss[parent] = std::vector<int>();
109 auto &detectorCounts = m_detectorCountss[parent];
110
111 // Read and collate the spectrum-mapping information.
112 for (const auto &group : inst.groups()) {
113 if (group.nxclass == "NXdetector" || group.nxclass == "NXmonitor") {
114 NXDetector detgroup = inst.openNXDetector(group.nxname);
115
116 NXInt spectra_block = detgroup.openNXInt("spectra");
117 try {
118 spectra_block.load();
119 } catch (std::runtime_error &) { // Throws if dataset zero-sized
120 detgroup.close();
121 continue;
122 }
123 const size_t nSpecEntries = spectra_block.dim0();
124 auto data = spectra_block.vecBuffer();
125 size_t currentSize = spectrumNumbers.size();
126 spectrumNumbers.resize(currentSize + nSpecEntries, 0);
127 // Append spectrum numbers
128 for (size_t i = 0; i < nSpecEntries; ++i) {
129 spectrumNumbers[i + currentSize] = data[i];
130 }
131
132 NXInt det_index = detgroup.openNXInt("detector_list");
133 det_index.load();
134 size_t nDetEntries = det_index.dim0();
135 currentSize = detectorIds.size();
136 data = det_index.vecBuffer();
137 detectorIds.resize(currentSize + nDetEntries, 0);
138 for (size_t i = 0; i < nDetEntries; ++i) {
139 detectorIds[i + currentSize] = data[i];
140 }
141
142 // Load the number of detectors per spectra
143 NXInt det_counts = detgroup.openNXInt("detector_count");
144 det_counts.load();
145 size_t nDetCounts = det_counts.dim0();
146 currentSize = detectorCounts.size();
147 data = det_counts.vecBuffer();
148 detectorCounts.resize(currentSize + nDetCounts, 0);
149 size_t dataSum = 0;
150 for (size_t i = 0; i < nDetCounts; ++i) {
151 const int dataVal = data[i];
152 dataSum += dataVal;
153 detectorCounts[i + currentSize] = dataVal;
154 }
155
156 if (nDetCounts != nSpecEntries) {
157 throw std::runtime_error("Bad file. Has different number of entries in "
158 "spec and detector_count datasets");
159 }
160 if (dataSum != nDetEntries) {
161 throw std::runtime_error("Bad file. detector_counts sum does not match "
162 "the number of detectors given by number of "
163 "detector_list entries");
164 }
165
166 detgroup.close();
167 }
168 }
169 inst.close();
170}
171
188 const std::string &filePath) {
190 if (auto *matrixWs = dynamic_cast<API::MatrixWorkspace *>(&ws)) {
191 try {
192 using namespace Mantid::NexusGeometry;
193
194 std::ostringstream parent_;
195 parent_ << "mantid_workspace_" << entryNumber;
196 const std::string &parent(parent_.str());
197 auto instrument =
198 NexusGeometry::NexusGeometryParser::createInstrument(filePath, parent, NexusGeometry::makeLogger(&logger));
199 matrixWs->setInstrument(Geometry::Instrument_const_sptr(std::move(instrument)));
200
201 // Apply the previously-collated mapping information to the workspace.
202 const auto &detInfo = matrixWs->detectorInfo();
203 auto &spectrumNumbers = m_spectrumNumberss[parent];
204 Indexing::IndexInfo info(spectrumNumbers);
205
206 const auto &detectorIds = m_detectorIdss[parent];
207 const auto &detectorCounts = m_detectorCountss[parent];
208
209 std::vector<SpectrumDefinition> definitions;
210 definitions.reserve(spectrumNumbers.size());
211 size_t detCounter = 0;
212 for (size_t i = 0; i < spectrumNumbers.size(); ++i) {
213 // counts gives number of detectors per spectrum
214 size_t counts = detectorCounts[i];
215 SpectrumDefinition def;
216
217 // Add the number of detectors known to be associated with this
218 // spectrum
219 for (size_t j = 0; j < counts; ++j, ++detCounter) {
220 def.add(detInfo.indexOf(detectorIds[detCounter]));
221 }
222 definitions.emplace_back(def);
223 }
224 info.setSpectrumDefinitions(definitions);
225 matrixWs->setIndexInfo(info);
226
227 return true;
228 } catch (std::exception &e) {
229 logger.warning(e.what());
230 } catch (H5::Exception &e) {
231 logger.warning(e.getDetailMsg());
232 }
233 }
234 }
235 return false;
236}
237
239 if (descriptor.isEntry("/mantid_workspace_1"))
240 return LoadNexusProcessed::confidence(descriptor) + 1; // incrementally better than v1.
241 else
242 return 0;
243}
244
245} // namespace Mantid::DataHandling
#define DECLARE_NEXUS_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro wh...
Base MatrixWorkspace Abstract Class.
A property class for workspaces.
Base Workspace Abstract Class.
Definition Workspace.h:29
bool loadNexusGeometry(Mantid::API::Workspace &ws, size_t entryNumber, Kernel::Logger &logger, const std::string &filePath) override
Load nexus geometry and apply to workspace.
void extractMappingInfoNew(const Mantid::Nexus::NXEntry &mtd_entry)
Extract mapping information where it is build across NXDetectors.
std::unordered_map< std::string, std::vector< Indexing::SpectrumNumber > > m_spectrumNumberss
void readSpectraToDetectorMapping(Mantid::Nexus::NXEntry &mtd_entry, Mantid::API::MatrixWorkspace &ws) override
int version() const override
Algorithm's version for identification.
std::unordered_map< std::string, std::vector< int > > m_detectorCountss
int confidence(Nexus::NexusDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
std::unordered_map< std::string, std::vector< Mantid::detid_t > > m_detectorIdss
void readInstrumentGroup(Mantid::Nexus::NXEntry &mtd_entry, API::MatrixWorkspace &local_workspace)
Read the spectra.
int confidence(Nexus::NexusDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
bool containsGroup(const std::string &query) const
Returns whether an individual group (or group) is present.
void close()
Close this class.
NXInt openNXInt(const std::string &name) const
Creates and opens an integer dataset.
Templated class implementation of NXDataSet.
void load()
Read all of the datablock in.
container_T< T > & vecBuffer()
Returns a the internal buffer.
dimsize_t dim0() const
Returns the number of elements along the first dimension.
Implements NXdetector Nexus class.
Implements NXentry Nexus class.
NXInstrument openNXInstrument(const std::string &name) const
Opens a NXInstrument.
std::string name() const
Returns the name of the object.
bool isEntry(const std::string &entryName, const std::string &groupClass) const noexcept
Checks if a full-address entry exists for a particular groupClass in a Nexus dataset.
Kernel::Logger g_log("ExperimentInfo")
static logger object
InstrumentLayout
Layout information relating to detector-spectra mappings.
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
Header for a base Nexus::Exception.
Describes the direction (within an algorithm) of a Property.
Definition Property.h:50