Commit 4be908e0 authored by Whitfield, Ross's avatar Whitfield, Ross
Browse files

Make PeakColumn templated and switch LeanElasticPeaksWorkspace

parent 55041ab8
......@@ -31,7 +31,6 @@ set(SRC_FILES
src/LeanElasticPeak.cpp
src/BasePeak.cpp
src/PeakColumn.cpp
src/LeanElasticPeakColumn.cpp
src/PeakNoShapeFactory.cpp
src/PeakShapeBase.cpp
src/PeakShapeEllipsoid.cpp
......@@ -115,7 +114,6 @@ set(INC_FILES
inc/MantidDataObjects/LeanElasticPeak.h
inc/MantidDataObjects/BasePeak.h
inc/MantidDataObjects/PeakColumn.h
inc/MantidDataObjects/LeanElasticPeakColumn.h
inc/MantidDataObjects/PeakNoShapeFactory.h
inc/MantidDataObjects/PeakShapeBase.h
inc/MantidDataObjects/PeakShapeEllipsoid.h
......@@ -177,7 +175,6 @@ set(TEST_FILES
NoShapeTest.h
OffsetsWorkspaceTest.h
PeakColumnTest.h
LeanElasticPeakColumnTest.h
PeakNoShapeFactoryTest.h
PeakShapeEllipsoidFactoryTest.h
PeakShapeEllipsoidTest.h
......
......@@ -32,9 +32,6 @@ namespace DataObjects {
*/
class DLLExport BasePeak : public Geometry::IPeak {
public:
/// Allow PeakColumn class to directly access members.
friend class PeakColumn;
BasePeak();
BasePeak(const Mantid::Kernel::Matrix<double> &goniometer);
/// Copy constructor
......
......@@ -30,8 +30,6 @@ namespace DataObjects {
*/
class DLLExport LeanElasticPeak : public BasePeak {
public:
/// Allow PeakColumn class to directly access members.
friend class PeakColumn;
LeanElasticPeak();
LeanElasticPeak(const Mantid::Kernel::V3D &QSampleFrame);
......
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#pragma once
#include "MantidAPI/Column.h"
#include "MantidDataObjects/LeanElasticPeak.h"
#include <boost/variant.hpp>
#include <list>
namespace Mantid {
namespace DataObjects {
/** PeakColumn : a Column sub-class used to display
* peak information as a TableWorkspace.
*
* The column holds a reference to a vector of Peak objects.
* Values in the column are taken directly from those Peak objects.
*
* @author Janik Zikovsky
* @date 2011-04-25 18:06:32.952258
*/
class DLLExport LeanElasticPeakColumn : public Mantid::API::Column {
public:
/// Construct a column with a reference to the peaks list, a name & type
LeanElasticPeakColumn(std::vector<LeanElasticPeak> &peaks,
const std::string &name);
/// Number of individual elements in the column.
size_t size() const override { return m_peaks.size(); }
/// Returns typeid for the data in the column
const std::type_info &get_type_info() const override;
/// Returns typeid for the pointer type to the data element in the column
const std::type_info &get_pointer_type_info() const override;
bool getReadOnly() const override;
/// Prints
void print(size_t index, std::ostream &s) const override;
void read(size_t index, const std::string &text) override;
/// Sets item from a stream
void read(const size_t index, std::istringstream &in) override;
/// Specialized type check
bool isBool() const override;
bool isNumber() const override;
/// Must return overall memory size taken by the column.
long int sizeOfData() const override;
/// Clone.
LeanElasticPeakColumn *clone() const override;
/// Cast to double
double toDouble(size_t i) const override;
/// Assign from double
void fromDouble(size_t i, double value) override;
/// Reference to the data.
const std::vector<LeanElasticPeak> &data() const { return m_peaks; }
bool equals(const Column &otherColumn, double tolerance) const override {
(void)otherColumn;
(void)tolerance;
throw std::runtime_error(
"equals not implemented, to compare use CompareWorkspace");
}
protected:
/// Sets the new column size.
void resize(size_t count) override;
/// Inserts an item.
void insert(size_t index) override;
/// Removes an item.
void remove(size_t index) override;
/// Pointer to a data element
void *void_pointer(size_t index) override;
/// Pointer to a data element
const void *void_pointer(size_t index) const override;
private:
/// Reference to the peaks object saved in the PeaksWorkspace.
std::vector<LeanElasticPeak> &m_peaks;
/// Precision of hkl in table workspace
int m_hklPrec;
/// Type of the row cache value
using CacheValueType = boost::variant<double, int, std::string, Kernel::V3D>;
///
mutable std::list<CacheValueType> m_oldRows;
/// Sets the correct value in the referenced peak.
void setPeakHKLOrRunNumber(const size_t index, const double val);
};
} // namespace DataObjects
} // namespace Mantid
......@@ -10,7 +10,7 @@
#include "MantidAPI/ITableWorkspace.h"
#include "MantidDataObjects/DllConfig.h"
#include "MantidDataObjects/LeanElasticPeak.h"
#include "MantidDataObjects/LeanElasticPeakColumn.h"
#include "MantidDataObjects/PeakColumn.h"
#include "MantidGeometry/Crystal/IPeak.h"
#include "MantidKernel/SpecialCoordinateSystem.h"
#include "MantidKernel/V3D.h"
......@@ -277,7 +277,7 @@ private:
std::vector<LeanElasticPeak> peaks;
/** Column shared pointers. */
std::vector<std::shared_ptr<Mantid::DataObjects::LeanElasticPeakColumn>>
std::vector<std::shared_ptr<Mantid::DataObjects::PeakColumn<LeanElasticPeak>>>
columns;
/** Column names */
......
......@@ -34,9 +34,6 @@ namespace DataObjects {
*/
class DLLExport Peak : public BasePeak {
public:
/// Allow PeakColumn class to directly access members.
friend class PeakColumn;
Peak();
Peak(const Geometry::Instrument_const_sptr &m_inst,
const Mantid::Kernel::V3D &QLabFrame,
......
......@@ -7,6 +7,7 @@
#pragma once
#include "MantidAPI/Column.h"
#include "MantidDataObjects/LeanElasticPeak.h"
#include "MantidDataObjects/Peak.h"
#include <boost/variant.hpp>
......@@ -24,11 +25,11 @@ namespace DataObjects {
* @author Janik Zikovsky
* @date 2011-04-25 18:06:32.952258
*/
class DLLExport PeakColumn : public Mantid::API::Column {
template <class T> class DLLExport PeakColumn : public Mantid::API::Column {
public:
/// Construct a column with a reference to the peaks list, a name & type
PeakColumn(std::vector<Peak> &peaks, const std::string &name);
PeakColumn(std::vector<T> &peaks, const std::string &name);
/// Number of individual elements in the column.
size_t size() const override { return m_peaks.size(); }
......@@ -67,7 +68,7 @@ public:
void fromDouble(size_t i, double value) override;
/// Reference to the data.
const std::vector<Peak> &data() const { return m_peaks; }
const std::vector<T> &data() const { return m_peaks; }
bool equals(const Column &otherColumn, double tolerance) const override {
(void)otherColumn;
......@@ -90,7 +91,7 @@ protected:
private:
/// Reference to the peaks object saved in the PeaksWorkspace.
std::vector<Peak> &m_peaks;
std::vector<T> &m_peaks;
/// Precision of hkl in table workspace
int m_hklPrec;
......
......@@ -269,7 +269,7 @@ private:
std::vector<Peak> peaks;
/** Column shared pointers. */
std::vector<std::shared_ptr<Mantid::DataObjects::PeakColumn>> columns;
std::vector<std::shared_ptr<Mantid::DataObjects::PeakColumn<Peak>>> columns;
/** Column names */
std::vector<std::string> columnNames;
......
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidDataObjects/LeanElasticPeakColumn.h"
#include "MantidKernel/ConfigService.h"
#include "MantidKernel/Exception.h"
#include "MantidKernel/MultiThreaded.h"
#include "MantidKernel/Strings.h"
#include "MantidKernel/System.h"
#include <boost/variant/get.hpp>
using namespace Mantid::Kernel;
namespace Mantid {
namespace DataObjects {
namespace {
/// static logger
Kernel::Logger g_log("LeanElasticPeakColumn");
/// Number of items to keep around in the cell cache (see void_pointer())
size_t NCELL_ITEM_CACHED = 100;
/**
* Private implementation to wrap a map such that it can be
* initialized in a thread-safe manner with a local static
*/
class ColumnNameToType {
public:
ColumnNameToType() {
// Assume double if not in this map
m_type_index.emplace("DetID", "int");
m_type_index.emplace("RunNumber", "int");
m_type_index.emplace("h", "double");
m_type_index.emplace("k", "double");
m_type_index.emplace("l", "double");
m_type_index.emplace("Wavelength", "double");
m_type_index.emplace("Energy", "double");
m_type_index.emplace("TOF", "double");
m_type_index.emplace("DSpacing", "double");
m_type_index.emplace("Intens", "double");
m_type_index.emplace("SigInt", "double");
m_type_index.emplace("Intens/SigInt", "double");
m_type_index.emplace("BinCount", "double");
m_type_index.emplace("BankName", "str");
m_type_index.emplace("Row", "double");
m_type_index.emplace("Col", "double");
m_type_index.emplace("QLab", "V3D");
m_type_index.emplace("QSample", "V3D");
m_type_index.emplace("PeakNumber", "int");
m_type_index.emplace("TBar", "double");
}
inline const auto &data() const { return m_type_index; }
private:
std::unordered_map<std::string, std::string> m_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) {
static ColumnNameToType typeIndex;
auto iter = typeIndex.data().find(name);
if (iter != typeIndex.data().end()) {
return iter->second;
} else {
throw std::runtime_error("LeanElasticPeakColumn - Unknown column name: \"" +
name +
"\""
"Peak column names/types must be explicitly "
"marked in LeanElasticPeakColumn.cpp");
}
}
} // namespace
//----------------------------------------------------------------------------------------------
/** Constructor
* @param peaks :: vector of peaks
* @param name :: name for the column
*/
LeanElasticPeakColumn::LeanElasticPeakColumn(
std::vector<LeanElasticPeak> &peaks, const std::string &name)
: m_peaks(peaks), m_oldRows() {
this->m_name = name;
this->m_type = typeFromName(name); // Throws if the name is unknown
const std::string key = "PeakColumn.hklPrec";
auto hklPrec = ConfigService::Instance().getValue<int>(key);
this->m_hklPrec = hklPrec.get_value_or(2);
if (!hklPrec.is_initialized()) {
g_log.information()
<< "In LeanElasticPeakColumn constructor, did not find any value for '"
<< key
<< "' from the Config Service. Using default: " << this->m_hklPrec
<< "\n";
}
}
/// Returns typeid for the data in the column
const std::type_info &LeanElasticPeakColumn::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(
"LeanElasticPeakColumn::get_type_info() - Unknown column type: " +
m_name);
}
}
/// Returns typeid for the pointer type to the data element in the column
const std::type_info &LeanElasticPeakColumn::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(
"LeanElasticPeakColumn::get_pointer_type_info() -: " + m_name);
}
}
//-------------------------------------------------------------------------------------
/** Prints out the column string at the given row index.
*
* @param s :: stream to output
* @param index :: row index
*/
void LeanElasticPeakColumn::print(size_t index, std::ostream &s) const {
LeanElasticPeak &peak = m_peaks[index];
s.imbue(std::locale("C"));
std::ios::fmtflags fflags(s.flags());
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 if (m_name == "h") {
s << std::fixed << std::setprecision(m_hklPrec) << peak.getH();
} else if (m_name == "k") {
s << std::fixed << std::setprecision(m_hklPrec) << peak.getK();
} else if (m_name == "l") {
s << std::fixed << std::setprecision(m_hklPrec) << peak.getL();
} else if (m_name == "PeakNumber") {
s << peak.getPeakNumber();
} else
s << peak.getValueByColName(m_name);
s.flags(fflags);
}
//-------------------------------------------------------------------------------------
/** 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 LeanElasticPeakColumn::read(size_t index, const std::string &text) {
// Don't modify read-only ones
if (this->getReadOnly() || index >= m_peaks.size())
return;
// Convert to a double
double val = 0;
int success = Strings::convert(text, val);
if (success == 0) {
g_log.error() << "Could not convert string '" << text << "' to a number.\n";
return;
}
setPeakHKLOrRunNumber(index, val);
}
/** Read in from stream and convert to a number in the PeaksWorkspace
*
* @param index :: index of the peak to modify
* @param in :: input stream
*/
void LeanElasticPeakColumn::read(const size_t index, std::istringstream &in) {
if (this->getReadOnly() || index >= m_peaks.size())
return;
double val;
try {
in >> val;
} catch (std::exception &e) {
g_log.error() << "Could not convert input to a number. " << e.what()
<< '\n';
return;
}
setPeakHKLOrRunNumber(index, val);
}
//-------------------------------------------------------------------------------------
/** @return true if the column is read-only */
bool LeanElasticPeakColumn::getReadOnly() const {
return !((m_name == "h") || (m_name == "k") || (m_name == "l") ||
(m_name == "RunNumber"));
}
//-------------------------------------------------------------------------------------
/// Specialized type check
bool LeanElasticPeakColumn::isBool() const { return false; }
bool LeanElasticPeakColumn::isNumber() const { return false; }
/// @returns overall memory size taken by the column.
long int LeanElasticPeakColumn::sizeOfData() const {
return sizeof(double) * static_cast<long int>(m_peaks.size());
}
/**
* 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 LeanElasticPeakColumn::resize(size_t count) {
UNUSED_ARG(count);
throw Exception::NotImplementedError(
"LeanElasticPeakColumn::resize - Peaks must be "
"added through the PeaksWorkspace "
"interface.");
}
/**
* 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 LeanElasticPeakColumn::insert(size_t index) {
UNUSED_ARG(index);
throw Exception::NotImplementedError(
"LeanElasticPeakColumn::insert - Peaks must be "
"inserted through the PeaksWorkspace "
"interface.");
}
/**
* 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 LeanElasticPeakColumn::remove(size_t index) {
UNUSED_ARG(index);
throw Exception::NotImplementedError(
"LeanElasticPeakColumn::remove - Peaks must be "
"remove through the PeaksWorkspace "
"interface.");
}
/**
* 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 *LeanElasticPeakColumn::void_pointer(size_t index) {
const auto *constThis = const_cast<const LeanElasticPeakColumn *>(this);
return const_cast<void *>(constThis->void_pointer(index));
}
/**
* 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 *LeanElasticPeakColumn::void_pointer(size_t index) const {
const LeanElasticPeak &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 == "PeakNumber") {
value = peak.getPeakNumber();
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);
}
}
LeanElasticPeakColumn *LeanElasticPeakColumn::clone() const {
auto temp = new LeanElasticPeakColumn(this->m_peaks, this->m_name);
return temp;
}
double LeanElasticPeakColumn::toDouble(size_t /*index*/) const {
throw std::runtime_error("LeanElasticPeakColumn::toDouble() not implemented, "
"LeanElasticPeakColumn "
"is has no general write access");
}
void LeanElasticPeakColumn::fromDouble(size_t /*index*/, double /*value*/) {
throw std::runtime_error(
"fromDouble() not implemented, LeanElasticPeakColumn is has no "
"general write access");
}
void LeanElasticPeakColumn::setPeakHKLOrRunNumber(const size_t index,
const double val) {
LeanElasticPeak &peak = m_peaks[index];
if (m_name == "h")
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(static_cast<int>(val));
else
throw std::runtime_error("Unexpected column " + m_name + " being set.");
}