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
14namespace Mantid::API {
15namespace {
16//----------------------------------------------------------------------------------------------
17// Anonymous namespace helpers
18//----------------------------------------------------------------------------------------------
20template <typename T> struct DescriptorCallback {
21 void apply(std::shared_ptr<T> & /*unused*/) {} // general one does nothing
22};
23template <> struct DescriptorCallback<Kernel::FileDescriptor> {
24 void apply(std::shared_ptr<Kernel::FileDescriptor> &descriptor) { descriptor->resetStreamToStart(); }
25};
27
29template <typename T> struct DescriptorSetter {
30 // general one does nothing
31 void apply(std::shared_ptr<NexusFileLoader> & /*unused*/, std::shared_ptr<T> & /*unused*/) {}
32};
33template <> struct DescriptorSetter<Nexus::NexusDescriptor> {
34 void apply(std::shared_ptr<NexusFileLoader> &loader, const std::shared_ptr<Nexus::NexusDescriptor> &descriptor) {
35 loader->setFileInfo(descriptor);
36 }
37};
39
48template <typename DescriptorType, typename FileLoaderType>
49std::pair<IAlgorithm_sptr, int> searchForLoader(const std::string &filename,
50 const std::multimap<std::string, int> &names, Kernel::Logger &logger) {
51 const auto &factory = AlgorithmFactory::Instance();
52 IAlgorithm_sptr bestLoader;
53 int maxConfidence(0);
54 auto descriptor = std::make_shared<DescriptorType>(filename);
55 DescriptorCallback<DescriptorType> callback;
56 DescriptorSetter<DescriptorType> setdescriptor;
57
58 auto iend = names.end();
59 for (auto it = names.begin(); it != iend; ++it) {
60 const std::string &name = it->first;
61 const int version = it->second;
62 logger.debug() << "Checking " << name << " version " << version << '\n';
63
64 // Use static cast for speed. Checks have been done at registration to check
65 // the types
66 auto alg = std::static_pointer_cast<FileLoaderType>(factory.create(name, version)); // highest version
67 try {
68 const int confidence = alg->confidence(*(descriptor.get()));
69 logger.debug() << name << " returned with confidence=" << confidence << '\n';
70 if (confidence > maxConfidence) // strictly greater
71 {
72 bestLoader = alg;
73 maxConfidence = confidence;
74 }
75 } catch (std::exception &exc) {
76 logger.warning() << "Checking loader '" << name << "' raised an error: '" << exc.what() << "'. Loader skipped.\n";
77 }
78 callback.apply(descriptor);
79 }
80
81 auto nxsLoader = std::dynamic_pointer_cast<NexusFileLoader>(bestLoader);
82 if (nxsLoader)
83 setdescriptor.apply(nxsLoader, descriptor);
84
85 return {bestLoader, maxConfidence};
86}
87} // namespace
88
89//----------------------------------------------------------------------------------------------
90// Public members
91//----------------------------------------------------------------------------------------------
92
99void FileLoaderRegistryImpl::unsubscribe(const std::string &name, const int version) {
100 auto iend = m_names.end();
101 for (auto it = m_names.begin(); it != iend; ++it) {
102 removeAlgorithm(name, version, *it);
103 }
104}
105
114const std::shared_ptr<IAlgorithm> FileLoaderRegistryImpl::chooseLoader(const std::string &filename) const {
118 m_log.debug() << "Trying to find loader for '" << filename << "'\n";
119
120 IAlgorithm_sptr bestLoader;
121
122 if (H5::H5File::isHdf5(filename)) {
123 std::pair<IAlgorithm_sptr, int> NexusResult =
124 searchForLoader<NexusDescriptor, IFileLoader<NexusDescriptor>>(filename, m_names[Nexus], m_log);
125
126 if (NexusResult.second < 80) {
127 // must also try LegacyNexusDescriptor algorithms because LoadMuonNexus can load both HDF4 and HDF5 files
128 // but only need to do this if confidence is less than 80, i.e. not loaded by LoadEventNexus, LoadNexusProcessed,
129 // LoadMuonNexusV2 or LoadMD
130 std::pair<IAlgorithm_sptr, int> LegacyNexusResult =
131 searchForLoader<LegacyNexusDescriptor, IFileLoader<LegacyNexusDescriptor>>(filename, m_names[LegacyNexus],
132 m_log);
133
134 if (NexusResult.second > LegacyNexusResult.second)
135 bestLoader = NexusResult.first;
136 else
137 bestLoader = LegacyNexusResult.first;
138 } else
139 bestLoader = NexusResult.first;
140 } else {
141 try {
142 bestLoader = searchForLoader<LegacyNexusDescriptor, IFileLoader<LegacyNexusDescriptor>>(
143 filename, m_names[LegacyNexus], m_log)
144 .first;
145 } catch (std::exception const &e) {
146 m_log.debug() << "Error in looking for NeXus files: " << e.what() << '\n';
147 }
148 }
149
150 if (!bestLoader)
151 bestLoader = searchForLoader<FileDescriptor, IFileLoader<FileDescriptor>>(filename, m_names[Generic], m_log).first;
152
153 if (!bestLoader) {
154 throw Kernel::Exception::NotFoundError(filename, "Unable to find loader");
155 }
156 m_log.debug() << "Found loader " << bestLoader->name() << " for file '" << filename << "'\n";
157 return bestLoader;
158}
159
167bool FileLoaderRegistryImpl::canLoad(const std::string &algorithmName, const std::string &filename) const {
171
172 // Check if it is in one of our lists
173 const bool legacynexus = (m_names[LegacyNexus].find(algorithmName) != m_names[LegacyNexus].end());
174 const bool nexus = (m_names[Nexus].find(algorithmName) != m_names[Nexus].end());
175 const bool nonHDF = (m_names[Generic].find(algorithmName) != m_names[Generic].end());
176
177 if (!(legacynexus || nexus || nonHDF))
178 throw std::invalid_argument("FileLoaderRegistryImpl::canLoad - Algorithm '" + algorithmName +
179 "' is not registered as a loader.");
180
181 std::multimap<std::string, int> names{{algorithmName, -1}};
182 IAlgorithm_sptr loader;
183 if (legacynexus) {
184 try {
185 loader = searchForLoader<LegacyNexusDescriptor, IFileLoader<LegacyNexusDescriptor>>(filename, names, m_log).first;
186 } catch (std::exception const &e) {
187 m_log.debug() << "Error in looking for NeXus files: " << e.what() << '\n';
188 }
189 } else if (nexus) {
190 if (H5::H5File::isHdf5(filename)) {
191 try {
192 loader = searchForLoader<NexusDescriptor, IFileLoader<NexusDescriptor>>(filename, names, m_log).first;
193 } catch (const std::invalid_argument &e) {
194 m_log.debug() << "Error in looking for HDF5 based NeXus files: " << e.what() << '\n';
195 }
196 }
197 } else if (nonHDF) {
198 loader = searchForLoader<FileDescriptor, IFileLoader<FileDescriptor>>(filename, names, m_log).first;
199 }
200 return static_cast<bool>(loader);
201}
202
203//----------------------------------------------------------------------------------------------
204// Private members
205//----------------------------------------------------------------------------------------------
211FileLoaderRegistryImpl::FileLoaderRegistryImpl() : m_totalSize(0), m_log("FileLoaderRegistry") {}
212
214
220void FileLoaderRegistryImpl::removeAlgorithm(const std::string &name, const int version,
221 std::multimap<std::string, int> &typedLoaders) {
222 if (version == -1) // remove all
223 {
224 typedLoaders.erase(name);
225 } else // find the right version
226 {
227 auto range = typedLoaders.equal_range(name);
228 for (auto ritr = range.first; ritr != range.second; ++ritr) {
229 if (ritr->second == version) {
230 typedLoaders.erase(ritr);
231 break;
232 }
233 }
234 }
235}
236
237} // namespace Mantid::API
std::string name
Definition Run.cpp:60
std::array< std::multimap< std::string, int >, 3 > 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