Mantid
Loading...
Searching...
No Matches
InstrumentInfo.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 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
10#include <algorithm>
11
14#include "MantidKernel/Logger.h"
16
17#include <boost/algorithm/string.hpp>
18#include <boost/lexical_cast.hpp>
19
20#include <Poco/AutoPtr.h>
21#include <Poco/DOM/Element.h>
22#include <Poco/DOM/NodeList.h>
23#include <Poco/DOM/Text.h>
24
25namespace Mantid::Kernel {
26namespace {
27// static logger object
28Logger g_log("InstrumentInfo");
29} // namespace
30
36InstrumentInfo::InstrumentInfo(const FacilityInfo *f, const Poco::XML::Element *elem)
37 : m_facility(f), m_name(elem->getAttribute("name")), m_shortName(elem->getAttribute("shortname")),
38 m_delimiter(elem->getAttribute("delimiter")) {
39
40 if (m_delimiter.empty())
42 if (m_shortName.empty())
44
45 fillTechniques(elem);
46 fillLiveData(elem);
47 fillZeroPadding(elem);
48}
49
57 return (this->name() == rhs.name() && this->shortName() == rhs.shortName());
58}
59
61std::string InstrumentInfo::delimiter() const { return m_delimiter; }
62
64const std::string InstrumentInfo::name() const { return m_name; }
65
67const std::string InstrumentInfo::shortName() const { return m_shortName; }
68
70int InstrumentInfo::zeroPadding(unsigned int runNumber) const {
71 if (m_zeroPadding.empty())
72 return m_facility->zeroPadding();
73 if (m_zeroPadding.size() == 1) {
74 auto padding = m_zeroPadding.begin();
75 if (runNumber >= padding->first)
76 return getZeroPadding(padding);
77 else
78 return m_facility->zeroPadding();
79 }
80 auto last = m_zeroPadding.end();
81 --last;
82 for (auto it = m_zeroPadding.begin(); it != last; ++it) {
83 auto next = it;
84 ++next;
85 if (runNumber >= it->first && runNumber < next->first) {
86 return getZeroPadding(it);
87 }
88 }
89 return getZeroPadding(last);
90}
91
96std::string InstrumentInfo::filePrefix(unsigned int runNumber) const {
97 if (m_zeroPadding.empty())
98 return m_shortName;
99 if (m_zeroPadding.size() == 1) {
100 auto padding = m_zeroPadding.begin();
101 if (runNumber >= padding->first)
102 return getPrefix(padding);
103 else
104 return m_shortName;
105 }
106 auto last = m_zeroPadding.end();
107 --last;
108 for (auto it = m_zeroPadding.begin(); it != last; ++it) {
109 auto next = it;
110 ++next;
111 if (runNumber >= it->first && runNumber < next->first) {
112 return getPrefix(it);
113 }
114 }
115 return getPrefix(last);
116}
117
119std::string InstrumentInfo::liveListener(const std::string &name) const {
120 if (!hasLiveListenerInfo())
121 return "";
122
124}
125
130std::string InstrumentInfo::liveDataAddress(const std::string &name) const {
131 if (!hasLiveListenerInfo())
132 return "";
133
134 return liveListenerInfo(name).address();
135}
136
145 if (!hasLiveListenerInfo())
146 throw std::runtime_error("Attempted to access live listener for " + m_name +
147 " instrument, which has no listeners.");
148
149 // Default to specified default connection
150 if (name.empty())
152
153 // If no default connection specified, fallback to first connection
154 if (name.empty())
155 return m_listeners.front();
156
157 // Name specified, find requested connection
158 auto it = std::find_if(m_listeners.cbegin(), m_listeners.cend(),
159 [&name](const auto &listener) { return boost::iequals(listener.name(), name); });
160 if (it != m_listeners.end())
161 return *it;
162
163 // The provided name was not valid / did not match any listeners
164 throw std::runtime_error("Could not find connection " + name + " for instrument " + m_name);
165}
166
167bool InstrumentInfo::hasLiveListenerInfo() const { return !m_listeners.empty(); }
168
169const std::vector<LiveListenerInfo> &InstrumentInfo::liveListenerInfoList() const { return m_listeners; }
170
172const std::set<std::string> &InstrumentInfo::techniques() const { return m_technique; }
173
176
178void InstrumentInfo::fillZeroPadding(const Poco::XML::Element *elem) {
179 Poco::AutoPtr<Poco::XML::NodeList> pNL_zeropadding = elem->getElementsByTagName("zeropadding");
180 unsigned long n = pNL_zeropadding->length();
181
182 for (unsigned long i = 0; i < n; ++i) {
183 auto elemenent = dynamic_cast<Poco::XML::Element *>(pNL_zeropadding->item(i));
184 if (!elemenent)
185 continue;
186 // read the zero padding size
187 if (!elemenent->hasAttribute("size")) {
188 throw std::runtime_error("Zeropadding size is missing for instrument " + m_name);
189 }
190 auto &sizeStr = elemenent->getAttribute("size");
191 int size = 0;
192 if (!Mantid::Kernel::Strings::convert(sizeStr, size)) {
193 throw std::runtime_error("Zeropadding size must be an integer value (instrument " + m_name + ")");
194 }
195 // read the start run number
196 unsigned int startRunNumber = 0;
197 if (!elemenent->hasAttribute("startRunNumber")) {
198 if (!m_zeroPadding.empty()) {
199 throw std::runtime_error("Zeropadding size is missing for instrument " + m_name);
200 }
201 } else {
202 auto &startRunNumberStr = elemenent->getAttribute("startRunNumber");
203 try {
204 startRunNumber = boost::lexical_cast<unsigned int>(startRunNumberStr);
205 } catch (...) {
206 throw std::runtime_error("Zeropadding start run number must be an "
207 "integer value (instrument " +
208 m_name + ")");
209 }
210 }
211 // read the file prefix
212 std::string prefix = m_shortName;
213 if (elemenent->hasAttribute("prefix")) {
214 prefix = elemenent->getAttribute("prefix");
215 }
216 m_zeroPadding[startRunNumber] = std::make_pair(prefix, size);
217 }
218
219 if (m_zeroPadding.empty()) {
220 m_zeroPadding[0] = std::make_pair(m_shortName, m_facility->zeroPadding());
221 }
222}
223
225void InstrumentInfo::fillTechniques(const Poco::XML::Element *elem) {
226 Poco::AutoPtr<Poco::XML::NodeList> pNL_technique = elem->getElementsByTagName("technique");
227 unsigned long n = pNL_technique->length();
228
229 for (unsigned long i = 0; i < n; ++i) {
230 Poco::AutoPtr<Poco::XML::NodeList> pNL = pNL_technique->item(i)->childNodes();
231 if (pNL->length() > 0) {
232 auto *txt = dynamic_cast<Poco::XML::Text *>(pNL->item(0));
233 if (txt) {
234 const std::string &tech = txt->getData();
235 if (!tech.empty()) {
236 m_technique.insert(tech);
237 }
238 }
239 }
240 }
241
242 if (m_technique.empty()) {
243 throw std::runtime_error("No technique is defined for instrument " + m_name);
244 }
245}
246
248void InstrumentInfo::fillLiveData(const Poco::XML::Element *elem) {
249 // See if we have a <livedata> element (will be NULL if there's none)
250 Poco::XML::Element *live = elem->getChildElement("livedata");
251 if (!live)
252 return;
253
254 // Load default connection name attribute
255 m_defaultListener = live->getAttribute("default");
256
257 // Get connections under <livedata>
258 Poco::AutoPtr<Poco::XML::NodeList> connections = elem->getElementsByTagName("connection");
259
260 // Load connection info for each child element
261 for (unsigned long i = 0; i < connections->length(); ++i) {
262 auto *conn = dynamic_cast<Poco::XML::Element *>(connections->item(i));
263 try {
264 m_listeners.emplace_back(this, conn);
265 } catch (...) {
266 g_log.error() << "Exception occurred while loading livedata for " << m_name
267 << " instrument. Skipping faulty connection.\n";
268 }
269 }
270
271 // Get kafka topics under <livedata>
272 Poco::AutoPtr<Poco::XML::NodeList> topics = elem->getElementsByTagName("topic");
273 for (unsigned long i = 0; i < topics->length(); ++i) {
274 auto *topic = dynamic_cast<Poco::XML::Element *>(topics->item(i));
275 try {
276 m_kafkaTopics.emplace_back(this, topic);
277 } catch (...) {
278 g_log.error() << "Exception occured while loading livedata for " << m_name
279 << " instrument. Skipping kafka topic.\n";
280 }
281 }
282}
283
284//-------------------------------------------------------------------------
285// Non-member functions
286//-------------------------------------------------------------------------
293std::ostream &operator<<(std::ostream &buffer, const InstrumentInfo &instrumentDescriptor) {
294 buffer << instrumentDescriptor.name();
295 return buffer;
296}
297
298} // namespace Mantid::Kernel
const std::vector< double > & rhs
A class that holds information about a facility.
Definition: FacilityInfo.h:36
int zeroPadding() const
Returns default zero padding for this facility.
Definition: FacilityInfo.h:44
const std::string & delimiter() const
Returns the default delimiter between instrument name and run number.
Definition: FacilityInfo.h:46
A class that holds information about an instrument.
void fillLiveData(const Poco::XML::Element *elem)
Called from constructor to fill live listener name.
std::string filePrefix(unsigned int runNumber) const
Returns file prefix for this instrument and a run number.
bool hasLiveListenerInfo() const
Returns true if this instrument has at least one live listener defined.
std::vector< TopicInfo > m_kafkaTopics
Kafka topics.
std::string m_name
Instrument name.
void fillZeroPadding(const Poco::XML::Element *elem)
Called from constructor to fill zero padding.
std::string m_shortName
Instrument short name.
std::string m_defaultListener
Default LiveListener connection to use.
const FacilityInfo * m_facility
Facility.
const std::string & getPrefix(ZeroPaddingMap::const_iterator it) const
get the prefix part
int getZeroPadding(ZeroPaddingMap::const_iterator it) const
get the zeropadding part
std::string liveDataAddress(const std::string &name="") const
Returns a string containing the "host:port" for default live listener.
const FacilityInfo & facility() const
The facility to which this instrument belongs.
const std::string name() const
Return the name of the instrument.
const std::set< std::string > & techniques() const
Return list of techniques.
std::set< std::string > m_technique
List of techniques the instrument can do.
const std::vector< LiveListenerInfo > & liveListenerInfoList() const
Returns all available LiveListenerInfos as a vector.
InstrumentInfo(const FacilityInfo *f, const Poco::XML::Element *elem)
Constructor.
std::string m_delimiter
Delimiter between instrument name and run number.
int zeroPadding(unsigned int runNumber) const
Returns zero padding for this instrument and a run number.
std::string delimiter() const
Returns the default delimiter between instrument name and run number.
ZeroPaddingMap m_zeroPadding
Run number-dependent zero padding.
bool operator==(const InstrumentInfo &rhs) const
Equality operator.
std::string liveListener(const std::string &name="") const
Returns the name of the default live listener.
std::vector< LiveListenerInfo > m_listeners
LiveListener connections.
const LiveListenerInfo & liveListenerInfo(std::string name="") const
Returns LiveListenerInfo for specified connection name (or default)
const std::string shortName() const
Return the short name of the instrument.
void fillTechniques(const Poco::XML::Element *elem)
Called from constructor to fill live listener name.
A class that holds information about a LiveListener connection.
const std::string & address() const
Returns the address string of this LiveListener connection.
const std::string & listener() const
Returns the classname of the specific LiveListener to use.
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
int convert(const std::string &A, T &out)
Convert a string into a number.
Definition: Strings.cpp:665
MANTID_KERNEL_DLL std::ostream & operator<<(std::ostream &, CPUTimer &)
Convenience function to provide for easier debug printing.
Definition: CPUTimer.cpp:86