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 called instrument,
62 }
63 instr.close();
64 }
65 entry.close();
66 }
67 return result;
68}
69
70} // namespace
71
73const std::string LoadNexusProcessed2::name() const { return "LoadNexusProcessed"; }
74
76int LoadNexusProcessed2::version() const { return 2; }
77
80
81 m_instrumentLayout = instrumentFormat(mtd_entry);
83 // Now assign the spectra-detector map
84 readInstrumentGroup(mtd_entry, ws);
86 extractMappingInfoNew(mtd_entry);
87 } else {
88 g_log.information() << "Instrument layout not recognised. Spectra mappings not loaded.";
89 }
90}
92 using namespace Mantid::NeXus;
93 auto result = findEntriesOfType(mtd_entry, "NXinstrument");
94 if (result.size() != 1) {
95 g_log.warning("We are expecting a single NXinstrument. No mappings loaded");
96 }
97 auto inst = mtd_entry.openNXInstrument(result[0].nxname);
98
99 auto &spectrumNumbers = m_spectrumNumbers;
100 auto &detectorIds = m_detectorIds;
101 auto &detectorCounts = m_detectorCounts;
102 for (const auto &group : inst.groups()) {
103 if (group.nxclass == "NXdetector" || group.nxclass == "NXmonitor") {
104 NXDetector detgroup = inst.openNXDetector(group.nxname);
105
106 NXInt spectra_block = detgroup.openNXInt("spectra");
107 try {
108 spectra_block.load();
109 } catch (std::runtime_error &) { // Throws if dataset zero-sized
110 detgroup.close();
111 continue;
112 }
113 const size_t nSpecEntries = spectra_block.dim0();
114 auto data = spectra_block.vecBuffer();
115 size_t currentSize = spectrumNumbers.size();
116 spectrumNumbers.resize(currentSize + nSpecEntries, 0);
117 // Append spectrum numbers
118 for (size_t i = 0; i < nSpecEntries; ++i) {
119 spectrumNumbers[i + currentSize] = data[i];
120 }
121
122 NXInt det_index = detgroup.openNXInt("detector_list");
123 det_index.load();
124 size_t nDetEntries = det_index.dim0();
125 currentSize = detectorIds.size();
126 data = det_index.vecBuffer();
127 detectorIds.resize(currentSize + nDetEntries, 0);
128 for (size_t i = 0; i < nDetEntries; ++i) {
129 detectorIds[i + currentSize] = data[i];
130 }
131
132 // Load the number of detectors per spectra
133 NXInt det_counts = detgroup.openNXInt("detector_count");
134 det_counts.load();
135 size_t nDetCounts = det_counts.dim0();
136 currentSize = detectorCounts.size();
137 data = det_counts.vecBuffer();
138 detectorCounts.resize(currentSize + nDetCounts, 0);
139 size_t dataSum = 0;
140 for (size_t i = 0; i < nDetCounts; ++i) {
141 const int dataVal = data[i];
142 dataSum += dataVal;
143 detectorCounts[i + currentSize] = dataVal;
144 }
145
146 if (nDetCounts != nSpecEntries) {
147 throw std::runtime_error("Bad file. Has different number of entries in "
148 "spec and detector_count datasets");
149 }
150 if (dataSum != nDetEntries) {
151 throw std::runtime_error("Bad file. detector_counts sum does not match "
152 "the number of detectors given by number of "
153 "detector_list entries");
154 }
155
156 detgroup.close();
157 }
158 }
159 inst.close();
160}
161
179bool LoadNexusProcessed2::loadNexusGeometry(API::Workspace &ws, const int nWorkspaceEntries, Kernel::Logger &logger,
180 const std::string &filename) {
181 if (m_instrumentLayout == InstrumentLayout::NexusFormat && nWorkspaceEntries == 1) {
182 if (auto *matrixWs = dynamic_cast<API::MatrixWorkspace *>(&ws)) {
183 try {
184 using namespace Mantid::NexusGeometry;
185 auto instrument =
186 NexusGeometry::NexusGeometryParser::createInstrument(filename, NexusGeometry::makeLogger(&logger));
187 matrixWs->setInstrument(Geometry::Instrument_const_sptr(std::move(instrument)));
188
189 auto &detInfo = matrixWs->detectorInfo();
190 Indexing::IndexInfo info(m_spectrumNumbers);
191 std::vector<SpectrumDefinition> definitions;
192 definitions.reserve(m_spectrumNumbers.size());
193 size_t detCounter = 0;
194 for (size_t i = 0; i < m_spectrumNumbers.size(); ++i) {
195 // counts gives number of detectors per spectrum
196 size_t counts = m_detectorCounts[i];
197 SpectrumDefinition def;
198 // Add the number of detectors known to be associated with this
199 // spectrum
200 for (size_t j = 0; j < counts; ++j, ++detCounter) {
201 def.add(detInfo.indexOf(m_detectorIds[detCounter]));
202 }
203 definitions.emplace_back(def);
204 }
205 info.setSpectrumDefinitions(definitions);
206 matrixWs->setIndexInfo(info);
207 return true;
208 } catch (std::exception &e) {
209 logger.warning(e.what());
210 } catch (H5::Exception &e) {
211 logger.warning(e.getDetailMsg());
212 }
213 }
214 }
215 return false;
216}
217
219 if (descriptor.pathExists("/mantid_workspace_1"))
220 return LoadNexusProcessed::confidence(descriptor) + 1; // incrementally better than v1.
221 else
222 return 0;
223}
224
225} // 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:30
void extractMappingInfoNew(const Mantid::NeXus::NXEntry &mtd_entry)
Extract mapping information where it is build across NXDetectors.
void readSpectraToDetectorMapping(Mantid::NeXus::NXEntry &mtd_entry, Mantid::API::MatrixWorkspace &ws) override
InstrumentLayout m_instrumentLayout
Load nexus geometry and apply to workspace Local caches.
int confidence(Kernel::NexusDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
int version() const override
Algorithm's version for identification.
bool loadNexusGeometry(Mantid::API::Workspace &ws, const int nWorkspaceEntries, Kernel::Logger &logger, const std::string &filename) override
Attempt to load nexus geometry.
std::vector< Indexing::SpectrumNumber > m_spectrumNumbers
const std::string name() const override
Algorithms name for identification.
std::vector< Mantid::detid_t > m_detectorIds
int confidence(Kernel::NexusDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
void readInstrumentGroup(Mantid::NeXus::NXEntry &mtd_entry, API::MatrixWorkspace &local_workspace)
Read the spectra.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
Defines a wrapper around a file whose internal structure can be accessed using the NeXus API.
bool pathExists(const std::string &path) const
Query if a path exists.
NXInt openNXInt(const std::string &name) const
Creates and opens an integer dataset.
Definition: NexusClasses.h:546
void close()
Close this class.
bool containsGroup(const std::string &query) const
Returns whether an individual group (or group) is present.
Templated class implementation of NXDataSet.
Definition: NexusClasses.h:203
container_T< T > & vecBuffer()
Returns a the internal buffer.
Definition: NexusClasses.h:265
void load(const int blocksize=1, int i=-1, int j=-1, int k=-1, int l=-1) override
Implementation of the virtual NXDataSet::load(...) method.
Definition: NexusClasses.h:289
int dim0() const
Returns the number of elements along the first dimension.
Implements NXdetector Nexus class.
Definition: NexusClasses.h:837
Implements NXentry Nexus class.
Definition: NexusClasses.h:898
NXInstrument openNXInstrument(const std::string &name) const
Opens a NXInstrument.
Definition: NexusClasses.h:917
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.
Describes the direction (within an algorithm) of a Property.
Definition: Property.h:50