Mantid
Loading...
Searching...
No Matches
FileLoaderRegistry.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 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
11#include <H5Cpp.h>
12#include <Poco/File.h>
13#include <algorithm>
14
15namespace Mantid::API {
16namespace {
17//----------------------------------------------------------------------------------------------
18// Anonymous namespace helpers
19//----------------------------------------------------------------------------------------------
21template <typename T> struct DescriptorCallback {
22 void apply(std::shared_ptr<T> & /*unused*/) {} // general one does nothing
23};
24template <> struct DescriptorCallback<Kernel::FileDescriptor> {
25 void apply(std::shared_ptr<Kernel::FileDescriptor> &descriptor) { descriptor->resetStreamToStart(); }
26};
28
30template <typename T> struct DescriptorSetter {
31 // general one does nothing
32 void apply(std::shared_ptr<NexusFileLoader> & /*unused*/, std::shared_ptr<T> & /*unused*/) {}
33};
34template <> struct DescriptorSetter<Nexus::NexusDescriptor> {
35 void apply(std::shared_ptr<NexusFileLoader> &loader, const std::shared_ptr<Nexus::NexusDescriptor> &descriptor) {
36 loader->setFileInfo(descriptor);
37 }
38};
40
49template <typename DescriptorType, typename FileLoaderType>
50std::pair<IAlgorithm_sptr, int> searchForLoader(const std::string &filename,
51 const std::multimap<std::string, int> &names, Kernel::Logger &logger) {
52 const auto &factory = AlgorithmFactory::Instance();
53 IAlgorithm_sptr bestLoader;
54 int maxConfidence(0);
55 auto descriptor = std::make_shared<DescriptorType>(filename);
56 DescriptorCallback<DescriptorType> callback;
57 DescriptorSetter<DescriptorType> setdescriptor;
58
59 auto iend = names.end();
60 for (auto it = names.begin(); it != iend; ++it) {
61 const std::string &name = it->first;
62 const int version = it->second;
63 logger.debug() << "Checking " << name << " version " << version << '\n';
64
65 // Use static cast for speed. Checks have been done at registration to check
66 // the types
67 auto alg = std::static_pointer_cast<FileLoaderType>(factory.create(name, version)); // highest version
68 try {
69 const int confidence = alg->confidence(*(descriptor.get()));
70 logger.debug() << name << " returned with confidence=" << confidence << '\n';
71 if (confidence > maxConfidence) // strictly greater
72 {
73 bestLoader = alg;
74 maxConfidence = confidence;
75 }
76 } catch (std::exception &exc) {
77 logger.warning() << "Checking loader '" << name << "' raised an error: '" << exc.what() << "'. Loader skipped.\n";
78 }
79 callback.apply(descriptor);
80 }
81
82 auto nxsLoader = std::dynamic_pointer_cast<NexusFileLoader>(bestLoader);
83 if (nxsLoader)
84 setdescriptor.apply(nxsLoader, descriptor);
85
86 return {bestLoader, maxConfidence};
87}
88} // namespace
89
90//----------------------------------------------------------------------------------------------
91// Public members
92//----------------------------------------------------------------------------------------------
93
100void FileLoaderRegistryImpl::unsubscribe(const std::string &name, const int version) {
101 auto iend = m_names.end();
102 for (auto it = m_names.begin(); it != iend; ++it) {
103 removeAlgorithm(name, version, *it);
104 }
105}
106
115const std::shared_ptr<IAlgorithm> FileLoaderRegistryImpl::chooseLoader(const std::string &filename) const {
119 m_log.debug() << "Trying to find loader for '" << filename << "'\n";
120
121 IAlgorithm_sptr bestLoader;
122
123 if (H5::H5File::isHdf5(filename)) {
124
125 // first, try search with lazy descriptor
126 std::pair<IAlgorithm_sptr, int> NexusLazyResult =
127 searchForLoader<Nexus::NexusDescriptorLazy, IFileLoader<Nexus::NexusDescriptorLazy>>(filename,
129 // if not found with lazy descriptor, try normal descriptor
130 if (NexusLazyResult.second < 80) {
131 std::pair<IAlgorithm_sptr, int> NexusResult =
132 searchForLoader<NexusDescriptor, IFileLoader<NexusDescriptor>>(filename, m_names[Nexus], m_log);
133
134 // and if not found with normal HDF5 descriptor, try legacy nexus descriptor
135 if (NexusResult.second < 80) {
136 // must also try LegacyNexusDescriptor algorithms because LoadMuonNexus can load both HDF4 and HDF5 files
137 // but only need to do this if confidence is less than 80, i.e. not loaded by LoadEventNexus,
138 // LoadNexusProcessed, LoadMuonNexusV2 or LoadMD
139 std::pair<IAlgorithm_sptr, int> LegacyNexusResult =
140 searchForLoader<LegacyNexusDescriptor, IFileLoader<LegacyNexusDescriptor>>(filename, m_names[LegacyNexus],
141 m_log);
142 // select best loaded of three
143 bestLoader = std::max({NexusResult, NexusLazyResult, LegacyNexusResult}, [](const auto &a, const auto &b) {
144 return a.second < b.second;
145 }).first;
146 } else {
147 bestLoader = std::max({NexusResult, NexusLazyResult}, [](const auto &a, const auto &b) {
148 return a.second < b.second;
149 }).first;
150 }
151 } else {
152 bestLoader = NexusLazyResult.first;
153 }
154 } else {
155 try {
156 bestLoader = searchForLoader<LegacyNexusDescriptor, IFileLoader<LegacyNexusDescriptor>>(
157 filename, m_names[LegacyNexus], m_log)
158 .first;
159 } catch (std::exception const &e) {
160 m_log.debug() << "Error in looking for NeXus files: " << e.what() << '\n';
161 }
162 }
163
164 if (!bestLoader)
165 bestLoader = searchForLoader<FileDescriptor, IFileLoader<FileDescriptor>>(filename, m_names[Generic], m_log).first;
166
167 if (!bestLoader) {
168 throw Kernel::Exception::NotFoundError(filename, "Unable to find loader");
169 }
170 m_log.debug() << "Found loader " << bestLoader->name() << " for file '" << filename << "'\n";
171 return bestLoader;
172}
173
181bool FileLoaderRegistryImpl::canLoad(const std::string &algorithmName, const std::string &filename) const {
185
186 // Check if it is in one of our lists
187 const bool legacynexus = (m_names[LegacyNexus].find(algorithmName) != m_names[LegacyNexus].end());
188 const bool lazyNexus = (m_names[NexusLazy].find(algorithmName) != m_names[NexusLazy].end());
189 const bool nexus = (m_names[Nexus].find(algorithmName) != m_names[Nexus].end());
190 const bool nonHDF = (m_names[Generic].find(algorithmName) != m_names[Generic].end());
191
192 if (!(legacynexus || nexus || nonHDF || lazyNexus))
193 throw std::invalid_argument("FileLoaderRegistryImpl::canLoad - Algorithm '" + algorithmName +
194 "' is not registered as a loader.");
195
196 std::multimap<std::string, int> names{{algorithmName, -1}};
197 IAlgorithm_sptr loader;
198 if (legacynexus) {
199 try {
200 loader = searchForLoader<LegacyNexusDescriptor, IFileLoader<LegacyNexusDescriptor>>(filename, names, m_log).first;
201 } catch (std::exception const &e) {
202 m_log.debug() << "Error in looking for NeXus files: " << e.what() << '\n';
203 }
204 } else if (nexus) {
205 if (H5::H5File::isHdf5(filename)) {
206 try {
207 loader = searchForLoader<NexusDescriptor, IFileLoader<NexusDescriptor>>(filename, names, m_log).first;
208 } catch (const std::invalid_argument &e) {
209 m_log.debug() << "Error in looking for HDF5 based NeXus files: " << e.what() << '\n';
210 }
211 }
212 } else if (lazyNexus) {
213 if (H5::H5File::isHdf5(filename)) {
214 try {
215 loader =
216 searchForLoader<Nexus::NexusDescriptorLazy, IFileLoader<Nexus::NexusDescriptorLazy>>(filename, names, m_log)
217 .first;
218 } catch (const std::invalid_argument &e) {
219 m_log.debug() << "Error in looking for lazy HDF5 based NeXus files: " << e.what() << '\n';
220 }
221 }
222 } else if (nonHDF) {
223 loader = searchForLoader<FileDescriptor, IFileLoader<FileDescriptor>>(filename, names, m_log).first;
224 }
225 return static_cast<bool>(loader);
226}
227
228//----------------------------------------------------------------------------------------------
229// Private members
230//----------------------------------------------------------------------------------------------
236FileLoaderRegistryImpl::FileLoaderRegistryImpl() : m_totalSize(0), m_log("FileLoaderRegistry") {}
237
239
245void FileLoaderRegistryImpl::removeAlgorithm(const std::string &name, const int version,
246 std::multimap<std::string, int> &typedLoaders) {
247 if (version == -1) // remove all
248 {
249 typedLoaders.erase(name);
250 } else // find the right version
251 {
252 auto range = typedLoaders.equal_range(name);
253 for (auto ritr = range.first; ritr != range.second; ++ritr) {
254 if (ritr->second == version) {
255 typedLoaders.erase(ritr);
256 break;
257 }
258 }
259 }
260}
261
262} // namespace Mantid::API
std::string name
Definition Run.cpp:60
std::array< std::multimap< std::string, int >, enum_count > m_names
The list of names.
const std::shared_ptr< IAlgorithm > chooseLoader(const std::string &filename) const
Returns the name of an Algorithm that can load the given filename.
FileLoaderRegistryImpl()
Default constructor (for singleton)
void unsubscribe(const std::string &name, const int version=-1)
Unsubscribe a named algorithm and version from the loader registration.
bool canLoad(const std::string &algorithmName, const std::string &filename) const
Checks whether the given algorithm can load the file.
void removeAlgorithm(const std::string &name, const int version, std::multimap< std::string, int > &typedLoaders)
Remove a named algorithm & version from the given map.
Kernel::Logger m_log
Reference to a logger.
Exception for when an item is not found in a collection.
Definition Exception.h:145
Defines a wrapper around an open file.
Defines a wrapper around a file whose internal structure can be accessed using the NeXus API.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm