Newer
Older
Roman Tolchenov
committed
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/InstrumentInfo.h"
#include "MantidKernel/FacilityInfo.h"
#include "MantidKernel/Exception.h"
#include "MantidKernel/Logger.h"
Janik Zikovsky
committed
#include "MantidKernel/Strings.h"
Roman Tolchenov
committed
#include <Poco/DOM/Element.h>
#include <Poco/DOM/NodeList.h>
#include <Poco/DOM/Text.h>
#include <Poco/DOM/AutoPtr.h>
Roman Tolchenov
committed
#include <boost/lexical_cast.hpp>
Roman Tolchenov
committed
#include <algorithm>
namespace Mantid
{
Gigg, Martyn Anthony
committed
namespace Kernel
{
namespace
{
// static logger object
Logger g_log("InstrumentInfo");
}
Roman Tolchenov
committed
Gigg, Martyn Anthony
committed
/** Constructor.
Janik Zikovsky
committed
* @param f :: The facility
* @param elem :: The Poco::XML::Element to read the data from
* @throw std::runtime_error if name or at least one technique are not defined
Gigg, Martyn Anthony
committed
*/
InstrumentInfo::InstrumentInfo(const FacilityInfo* f,const Poco::XML::Element* elem)
: m_facility(f), m_liveListener(), m_liveDataAddress()
Gigg, Martyn Anthony
committed
{
Roman Tolchenov
committed
Gigg, Martyn Anthony
committed
m_name = elem->getAttribute("name");
if (m_name.empty())
{
throw std::runtime_error("Instrument name is not defined");
}
Roman Tolchenov
committed
// The string to separate the instrument name and the run number.
m_delimiter = elem->getAttribute("delimiter");
if (m_delimiter.empty())
{
m_delimiter = f->delimiter();
}
Gigg, Martyn Anthony
committed
m_shortName = elem->getAttribute("shortname");
if (m_shortName.empty())
{
m_shortName = m_name;
}
Roman Tolchenov
committed
fillTechniques(elem);
fillLiveData(elem);
Roman Tolchenov
committed
}
Gigg, Martyn Anthony
committed
/**
* Equality operator. Two objects are considered equal if their names and short names are the same.
Janik Zikovsky
committed
* @param rhs :: The object to compare this with
Gigg, Martyn Anthony
committed
* @returns True if the objects are considered equal, false otherwise
*/
bool InstrumentInfo::operator==(const InstrumentInfo & rhs) const
{
return (this->name() == rhs.name() && this->shortName() == rhs.shortName());
Gigg, Martyn Anthony
committed
}
Roman Tolchenov
committed
/// Returns the default delimiter between instrument name and run number
std::string InstrumentInfo::delimiter() const
{
return m_delimiter;
}
/// Return the name of the instrument
const std::string InstrumentInfo::name() const
{
return m_name;
}
/// Return the short name of the instrument
const std::string InstrumentInfo::shortName() const
{
return m_shortName;
}
/// Returns zero padding for this instrument
int InstrumentInfo::zeroPadding(unsigned int runNumber) const
{
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
if ( m_zeroPadding.empty() ) return m_facility->zeroPadding();
if ( m_zeroPadding.size() == 1 )
{
auto padding = m_zeroPadding.begin();
if ( runNumber >= padding->first )
return getZeroPadding(padding);
else
return m_facility->zeroPadding();
}
auto last = m_zeroPadding.end(); --last;
for(auto it = m_zeroPadding.begin(); it != last; ++it)
{
auto next = it; ++next;
if ( runNumber >= it->first && runNumber < next->first )
{
return getZeroPadding(it);
}
}
return getZeroPadding(last);
}
/**
* Returns file prefix for this instrument and a run number.
* @param runNumber :: A run number.
*/
std::string InstrumentInfo::filePrefix(unsigned int runNumber) const
{
if ( m_zeroPadding.empty() ) return m_shortName;
if ( m_zeroPadding.size() == 1 )
{
auto padding = m_zeroPadding.begin();
if ( runNumber >= padding->first )
return getPrefix(padding);
else
return m_shortName;
}
auto last = m_zeroPadding.end(); --last;
for(auto it = m_zeroPadding.begin(); it != last; ++it)
{
auto next = it; ++next;
if ( runNumber >= it->first && runNumber < next->first )
{
return getPrefix(it);
}
}
return getPrefix(last);
}
/// Returns the name of the live listener
const std::string & InstrumentInfo::liveListener() const
{
return m_liveListener;
}
/** Returns the host & port to connect to for a live data stream
* No guarantees are given that the provided string is well-formed and valid
* - the caller should check this themselves
*/
const std::string & InstrumentInfo::liveDataAddress() const
{
return m_liveDataAddress;
}
/// Return list of techniques
const std::set<std::string>& InstrumentInfo::techniques() const
{
return m_technique;
}
/// Return the facility
const FacilityInfo& InstrumentInfo::facility() const
{
return *m_facility;
}
/// Called from constructor to fill zero padding
void InstrumentInfo::fillZeroPadding(const Poco::XML::Element* elem)
{
Poco::AutoPtr<Poco::XML::NodeList> pNL_zeropadding = elem->getElementsByTagName("zeropadding");
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
unsigned long n = pNL_zeropadding->length();
for (unsigned long i = 0; i < n; ++i)
{
auto elem = dynamic_cast<Poco::XML::Element*>( pNL_zeropadding->item(i) );
if ( !elem ) continue;
// read the zero padding size
if ( !elem->hasAttribute("size") )
{
throw std::runtime_error("Zeropadding size is missing for instrument "+m_name);
}
auto& sizeStr = elem->getAttribute("size");
int size = 0;
if ( !Mantid::Kernel::Strings::convert(sizeStr,size) )
{
throw std::runtime_error("Zeropadding size must be an integer value (instrument "+m_name+")");
}
// read the start run number
unsigned int startRunNumber = 0;
if ( !elem->hasAttribute("startRunNumber") )
{
if ( !m_zeroPadding.empty() )
{
throw std::runtime_error("Zeropadding size is missing for instrument "+m_name);
}
}
else
{
auto& startRunNumberStr = elem->getAttribute("startRunNumber");
try
{
startRunNumber = boost::lexical_cast<unsigned int>( startRunNumberStr );
}
catch(...)
{
throw std::runtime_error("Zeropadding start run number must be an integer value (instrument "+m_name+")");
}
}
// read the file prefix
std::string prefix = m_shortName;
if ( elem->hasAttribute("prefix") )
{
prefix = elem->getAttribute("prefix");
}
m_zeroPadding[startRunNumber] = std::make_pair(prefix,size);
}
if (m_zeroPadding.empty())
{
m_zeroPadding[0] = std::make_pair(m_shortName,m_facility->zeroPadding());
}
}
/// Called from constructor to fill live listener name
void InstrumentInfo::fillTechniques(const Poco::XML::Element* elem)
{
Poco::AutoPtr<Poco::XML::NodeList> pNL_technique = elem->getElementsByTagName("technique");
unsigned long n = pNL_technique->length();
for (unsigned long i = 0; i < n; ++i)
{
Poco::AutoPtr<Poco::XML::NodeList> pNL = pNL_technique->item(i)->childNodes();
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
if (pNL->length() > 0)
{
Poco::XML::Text* txt = dynamic_cast<Poco::XML::Text*>(pNL->item(0));
if (txt)
{
std::string tech = txt->getData();
if ( !tech.empty() )
{
m_technique.insert(tech);
}
}
}
}
if (m_technique.empty())
{
throw std::runtime_error("No technique is defined for instrument "+m_name);
}
}
/// Called from constructor to fill live listener name
void InstrumentInfo::fillLiveData(const Poco::XML::Element* elem)
{
// Get the first livedata element (will be NULL if there's none)
Poco::XML::Element * live = elem->getChildElement("livedata");
if ( live )
{
// Get the name of the listener - empty string will be returned if missing
m_liveListener = live->getAttribute("listener");
// Get the host+port. Would have liked to put straight into a Poco::Net::SocketAddress
// but that tries to contact the given address on construction, which won't always be possible (or scalable)
m_liveDataAddress = live->getAttribute("address");
// Warn rather than throw if there are problems with the address
if ( m_liveDataAddress.empty() )
{
g_log.warning() << "No connection details specified for live data listener of " << m_name << "\n";
}
// Check for a colon, which would suggest that a host & port are present
else if ( m_liveDataAddress.find(":") == std::string::npos )
{
g_log.warning() << "Live data address for " << m_name << " appears not to have both host and port specified.\n";
}
}
// Apply the facility default listener if none specified for this instrument
if ( m_liveListener.empty() )
{
m_liveListener = m_facility->liveListener();
}
}
//-------------------------------------------------------------------------
// Non-member functions
//-------------------------------------------------------------------------
/**
* Prints the instrument name to the stream
* @param buffer :: A reference to an output stream
* @param instrumentDescriptor :: A reference to an InstrumentInfo object
* @return A reference to the stream written to
*/
std::ostream & operator<<(std::ostream & buffer, const InstrumentInfo & instrumentDescriptor)
{
buffer << instrumentDescriptor.name();
return buffer;
}
Gigg, Martyn Anthony
committed
} // namespace Kernel
Roman Tolchenov
committed
} // namespace Mantid