Newer
Older
Janik Zikovsky
committed
#include "MantidDataObjects/PeakColumn.h"
#include "MantidKernel/System.h"
Janik Zikovsky
committed
#include "MantidKernel/Strings.h"
#include <Poco/Mutex.h>
#include <boost/variant/get.hpp>
Janik Zikovsky
committed
using namespace Mantid::Kernel;
Janik Zikovsky
committed
namespace Mantid
{
namespace DataObjects
{
namespace
{
/// Number of items to keep around in the cell cache (see void_pointer())
size_t NCELL_ITEM_CACHED = 100;
/// Type lookup: key=name,value=type. Moved here from static inside typeFromName
/// to avoid the need for locks with the initialisation problem across multiple threads
std::map<std::string, std::string> TYPE_INDEX;
/**
* Returns a string type identifier from the given name
* @param name :: The name of the column
* @returns A string identifier for the column type
*/
const std::string typeFromName(const std::string & name)
{
if(TYPE_INDEX.empty())
{
PARALLEL_CRITICAL(fill_column_index_map)
{
if (TYPE_INDEX.empty()) // check again inside the critical block
{
// Assume double if not in this map
TYPE_INDEX.insert(std::make_pair("DetID", "int"));
TYPE_INDEX.insert(std::make_pair("RunNumber", "int"));
TYPE_INDEX.insert(std::make_pair("h", "double"));
TYPE_INDEX.insert(std::make_pair("k", "double"));
TYPE_INDEX.insert(std::make_pair("l", "double"));
TYPE_INDEX.insert(std::make_pair("Wavelength", "double"));
TYPE_INDEX.insert(std::make_pair("Energy", "double"));
TYPE_INDEX.insert(std::make_pair("TOF", "double"));
TYPE_INDEX.insert(std::make_pair("DSpacing", "double"));
TYPE_INDEX.insert(std::make_pair("Intens", "double"));
TYPE_INDEX.insert(std::make_pair("SigInt", "double"));
TYPE_INDEX.insert(std::make_pair("BinCount", "double"));
TYPE_INDEX.insert(std::make_pair("BankName", "str"));
TYPE_INDEX.insert(std::make_pair("Row", "double"));
TYPE_INDEX.insert(std::make_pair("Col", "double"));
TYPE_INDEX.insert(std::make_pair("QLab", "V3D"));
TYPE_INDEX.insert(std::make_pair("QSample", "V3D"));
}
}
}
auto iter = TYPE_INDEX.find(name);
if(iter != TYPE_INDEX.end())
{
return iter->second;
}
else
{
throw std::runtime_error("PeakColumn - Unknown column name: \"" + name + "\""
"Peak column names/types must be explicitly marked in PeakColumn.cpp");
}
};
}
Janik Zikovsky
committed
//----------------------------------------------------------------------------------------------
/** Constructor
* @param peaks :: vector of peaks
* @param name :: name for the column
Janik Zikovsky
committed
*/
PeakColumn::PeakColumn(std::vector<Peak> & peaks, const std::string & name) :
m_peaks(peaks), m_oldRows()
Janik Zikovsky
committed
{
this->m_name = name;
this->m_type = typeFromName(name); // Throws if the name is unknown
Janik Zikovsky
committed
}
//----------------------------------------------------------------------------------------------
/** Destructor
*/
PeakColumn::~PeakColumn()
{
}
/// Returns typeid for the data in the column
const std::type_info& PeakColumn::get_type_info()const
{
// This is horrible copy-and-paste with the method below. The whole thing
// around columns could be much better implemented using templates & traits to avoid this
// type of thing!
if(type() == "double")
{
return typeid(double);
}
else if(type() == "int")
{
return typeid(int);
}
else if(type() == "str")
{
return typeid(std::string);
}
else if(type() == "V3D")
{
return typeid(V3D);
}
else
{
throw std::runtime_error("PeakColumn::get_type_info() - Unknown column type: " + m_name);
}
Janik Zikovsky
committed
}
/// Returns typeid for the pointer type to the data element in the column
const std::type_info& PeakColumn::get_pointer_type_info()const
{
if(type() == "double")
{
return typeid(double*);
}
else if(type() == "int")
{
return typeid(int*);
}
else if(type() == "str")
{
return typeid(std::string*);
}
else if(type() == "V3D")
{
return typeid(V3D*);
}
else
{
throw std::runtime_error("PeakColumn::get_pointer_type_info() -: " + m_name);
}
Janik Zikovsky
committed
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------
Janik Zikovsky
committed
/** Prints out the column string at the given row index.
*
* @param s :: stream to output
* @param index :: row index
*/
void PeakColumn::print(size_t index, std::ostream& s) const
Janik Zikovsky
committed
{
Peak & peak = m_peaks[index];
Janik Zikovsky
committed
if (m_name == "RunNumber")
s << peak.getRunNumber();
else if (m_name == "DetID")
s << peak.getDetectorID();
else if (m_name == "BankName")
s << peak.getBankName();
else if (m_name == "QLab")
s << peak.getQLabFrame();
else if (m_name == "QSample")
s << peak.getQSampleFrame();
else
Janik Zikovsky
committed
s << peak.getValueByColName(m_name);
Janik Zikovsky
committed
}
Janik Zikovsky
committed
//-------------------------------------------------------------------------------------
/** Read in some text and convert to a number in the PeaksWorkspace
*
* @param text :: string to read
* @param index :: index of the peak to modify
*/
void PeakColumn::read(size_t index, const std::string & text)
Janik Zikovsky
committed
{
// Don't modify read-only ones
if (this->getReadOnly())
return;
// Avoid going out of bounds
if (size_t(index) >= m_peaks.size())
Janik Zikovsky
committed
return;
// Reference to the peak in the workspace
Peak & peak = m_peaks[index];
Janik Zikovsky
committed
// Convert to a double
double val = 0;
int success = Strings::convert(text, val);
Janik Zikovsky
committed
int ival = static_cast<int>(val);
if (success == 0)
Janik Zikovsky
committed
{
g_log.error() << "Could not convert string '" << text << "' to a number.\n";
return;
}
if (m_name == "h")
Janik Zikovsky
committed
peak.setH(val);
else if (m_name == "k")
peak.setK(val);
else if (m_name == "l")
peak.setL(val);
else if (m_name == "RunNumber")
peak.setRunNumber(ival);
else
throw std::runtime_error("Unexpected column " + m_name + " being set.");
}
//-------------------------------------------------------------------------------------
/** @return true if the column is read-only */
bool PeakColumn::getReadOnly() const
{
if (
(m_name == "h") || (m_name == "k") || (m_name == "l") ||
(m_name == "RunNumber")
)
Janik Zikovsky
committed
return false;
else
// Default to true for most columns
return true;
Janik Zikovsky
committed
}
//-------------------------------------------------------------------------------------
Janik Zikovsky
committed
/// Specialized type check
bool PeakColumn::isBool()const
{
return false;
}
/// @returns overall memory size taken by the column.
Janik Zikovsky
committed
long int PeakColumn::sizeOfData()const
{
return sizeof(double) * static_cast<long int>(m_peaks.size());
Janik Zikovsky
committed
}
/**
* Sets a new size for the column. Not implemented as this is controlled
* by the PeaksWorkspace
* @param count :: Count of new column size (unused)
* @throw Exception::NotImplementedError
*/
void PeakColumn::resize(size_t count)
Janik Zikovsky
committed
{
UNUSED_ARG(count);
throw Exception::NotImplementedError("PeakColumn::resize - Peaks must be added through the PeaksWorkspace interface.");
Janik Zikovsky
committed
}
/**
* Inserts an item into the column. Not implemented as this is controlled by the PeaksWorkspace
* @param index :: The new index position (unused)
* @throw Exception::NotImplementedError
*/
void PeakColumn::insert(size_t index)
Janik Zikovsky
committed
{
UNUSED_ARG(index);
throw Exception::NotImplementedError("PeakColumn::insert - Peaks must be inserted through the PeaksWorkspace interface.");
Janik Zikovsky
committed
}
/**
* Removes an item from the column. Not implemented as this is controlled by the PeaksWorkspace
* @param index :: The index position removed(unused)
* @throw Exception::NotImplementedError
*/
void PeakColumn::remove(size_t index)
Janik Zikovsky
committed
{
UNUSED_ARG(index);
throw Exception::NotImplementedError("PeakColumn::remove - Peaks must be remove through the PeaksWorkspace interface.");
Janik Zikovsky
committed
}
/**
* Pointer to a data element in the PeaksWorkspace (non-const version)
* @param index :: A row index pointing to the PeaksWorkspace
* @returns A pointer to the data element at that index from this column
*/
void* PeakColumn::void_pointer(size_t index)
Janik Zikovsky
committed
{
const PeakColumn * constThis = const_cast<const PeakColumn*>(this);
return const_cast<void*>(constThis->void_pointer(index));
Janik Zikovsky
committed
}
/**
* Pointer to a data element in the PeaksWorkspace (const version)
* @param index :: A row index pointing to the PeaksWorkspace
* @returns A pointer to the data element at that index from this column
*/
const void* PeakColumn::void_pointer(size_t index) const
Anders Markvardsen
committed
{
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
const Peak & peak = m_peaks[index];
// The cell() api requires that the value exist somewhere in memory, however,
// some of the values from a Peak are calculated on the fly so a reference
// cannot be returned. Instead we cache a value for the last NCELL_ITEM_CACHED
// accesses and return a reference to this
m_oldRows.push_front(CacheValueType());
if(m_oldRows.size() > NCELL_ITEM_CACHED)
{
m_oldRows.pop_back();
}
auto &value = m_oldRows.front(); // A reference to the actual stored variant
if( type() == "double" )
{
value = peak.getValueByColName(m_name); // Assign the value to the store
return boost::get<double>(&value); // Given a pointer it will return a pointer
}
else if(m_name == "RunNumber")
{
value = peak.getRunNumber();
return boost::get<int>(&value);
}
else if(m_name == "DetID")
{
value = peak.getDetectorID();
return boost::get<int>(&value);
}
else if(m_name == "BankName")
{
value = peak.getBankName();
return boost::get<std::string>(&value);
}
else if(m_name == "QLab")
{
value = peak.getQLabFrame();
return boost::get<Kernel::V3D>(&value);
}
else if(m_name == "QSample")
{
value = peak.getQSampleFrame();
return boost::get<Kernel::V3D>(&value);
}
else
{
throw std::runtime_error("void_pointer() - Unknown peak column name or type: " + m_name);
}
Anders Markvardsen
committed
}
PeakColumn* PeakColumn::clone() const
{
PeakColumn* temp = new PeakColumn(this->m_peaks, this->m_name);
return temp;
}
double PeakColumn::toDouble(size_t /*index*/)const
{
throw std::runtime_error("PeakColumn::toDouble() not implemented, PeakColumn is has no general write access");
}
void PeakColumn::fromDouble(size_t /*index*/, double /*value*/)
{
throw std::runtime_error("fromDouble() not implemented, PeakColumn is has no general write access");
Janik Zikovsky
committed
} // namespace Mantid
} // namespace DataObjects