Skip to content

Commit

Permalink
PeakShapeDetectorBin added with boost::python bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
warunawickramasingha committed Nov 21, 2024
1 parent 8fe9b3d commit 3454d1c
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 52 deletions.
9 changes: 7 additions & 2 deletions Framework/DataHandling/src/LoadNexusProcessed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "MantidDataObjects/LeanElasticPeaksWorkspace.h"
#include "MantidDataObjects/Peak.h"
#include "MantidDataObjects/PeakNoShapeFactory.h"
#include "MantidDataObjects/PeakShapeDetectorBinFactory.h"
#include "MantidDataObjects/PeakShapeEllipsoidFactory.h"
#include "MantidDataObjects/PeakShapeSphericalFactory.h"
#include "MantidDataObjects/PeaksWorkspace.h"
Expand Down Expand Up @@ -1164,10 +1165,12 @@ API::Workspace_sptr LoadNexusProcessed::loadLeanElasticPeaksEntry(const NXEntry

PeakShapeFactory_sptr peakFactoryEllipsoid = std::make_shared<PeakShapeEllipsoidFactory>();
PeakShapeFactory_sptr peakFactorySphere = std::make_shared<PeakShapeSphericalFactory>();
PeakShapeFactory_sptr peakFactoryDetectorBin = std::make_shared<PeakShapeDetectorBinFactory>();
PeakShapeFactory_sptr peakFactoryNone = std::make_shared<PeakNoShapeFactory>();

peakFactoryEllipsoid->setSuccessor(peakFactorySphere);
peakFactorySphere->setSuccessor(peakFactoryNone);
peakFactorySphere->setSuccessor(peakFactoryDetectorBin);
peakFactoryDetectorBin->setSuccessor(peakFactoryNone);

NXInfo info = nx_tw.getDataSetInfo(str);
NXChar data = nx_tw.openNXChar(str);
Expand Down Expand Up @@ -1456,10 +1459,12 @@ API::Workspace_sptr LoadNexusProcessed::loadPeaksEntry(const NXEntry &entry) {

PeakShapeFactory_sptr peakFactoryEllipsoid = std::make_shared<PeakShapeEllipsoidFactory>();
PeakShapeFactory_sptr peakFactorySphere = std::make_shared<PeakShapeSphericalFactory>();
PeakShapeFactory_sptr peakFactoryDetectorBin = std::make_shared<PeakShapeDetectorBinFactory>();
PeakShapeFactory_sptr peakFactoryNone = std::make_shared<PeakNoShapeFactory>();

peakFactoryEllipsoid->setSuccessor(peakFactorySphere);
peakFactorySphere->setSuccessor(peakFactoryNone);
peakFactorySphere->setSuccessor(peakFactoryDetectorBin);
peakFactoryDetectorBin->setSuccessor(peakFactoryNone);

NXInfo info = nx_tw.getDataSetInfo(str);
NXChar data = nx_tw.openNXChar(str);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#pragma once

#include "MantidDataObjects/PeakShapeBase.h"
#include <vector>

namespace Mantid {
namespace DataObjects {
Expand All @@ -15,8 +16,7 @@ namespace DataObjects {
*/
class MANTID_DATAOBJECTS_DLL PeakShapeDetectorBin : public PeakShapeBase {
public:
/// Constructor
PeakShapeDetectorBin(std::vector<std::tuple<int32_t, double, double>> detectorXList,
PeakShapeDetectorBin(std::vector<std::tuple<int32_t, double, double>> detectorBinList,
Kernel::SpecialCoordinateSystem frame, std::string algorithmName = std::string(),
int algorithmVersion = -1);
/// Equals operator
Expand All @@ -34,10 +34,10 @@ class MANTID_DATAOBJECTS_DLL PeakShapeDetectorBin : public PeakShapeBase {

static const std::string detectorBinShapeName();

const std::vector<std::tuple<int32_t, double, double>> &getDetectorXList() const { return m_detectorXList; }
const std::vector<std::tuple<int32_t, double, double>> &getDetectorBinList() const { return m_detectorBinList; }

private:
std::vector<std::tuple<int32_t, double, double>> m_detectorXList;
std::vector<std::tuple<int32_t, double, double>> m_detectorBinList;
};

using PeakShapeDetectorTOF_sptr = std::shared_ptr<PeakShapeDetectorBin>;
Expand Down
32 changes: 20 additions & 12 deletions Framework/DataObjects/src/PeakShapeDetectorBin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,41 @@

namespace Mantid::DataObjects {

PeakShapeDetectorBin::PeakShapeDetectorBin(std::vector<std::tuple<int32_t, double, double>> detectorXList,
/**
* Create PeakShapeDetectorBin
* @param detectorBinList The list containing each detector Ids associated with its start and end points in TOF or
* dSpacing domains
* @param frame SpecialCoordinateSystem frame, default is None
* @param algorithmName Name of the algorithm using this shape
* @param algorithmVersion Version of the above algorithm
*/
PeakShapeDetectorBin::PeakShapeDetectorBin(std::vector<std::tuple<int32_t, double, double>> detectorBinList,
Kernel::SpecialCoordinateSystem frame, std::string algorithmName,
int algorithmVersion)
: PeakShapeBase(frame, std::move(algorithmName), algorithmVersion), m_detectorXList(detectorXList) {
: PeakShapeBase(frame, std::move(algorithmName), algorithmVersion), m_detectorBinList(detectorBinList) {

if (detectorXList.size() == 0) {
if (detectorBinList.size() == 0) {
throw std::invalid_argument("No data provided for detector data");
}
}

bool PeakShapeDetectorBin::operator==(const PeakShapeDetectorBin &other) const {
return PeakShapeBase::operator==(other) && (this->m_detectorXList == other.m_detectorXList);
return PeakShapeBase::operator==(other) && (this->m_detectorBinList == other.m_detectorBinList);
}

std::string PeakShapeDetectorBin::toJSON() const {
Json::Value root;
PeakShapeBase::buildCommon(root);
Json::Value detXList;
for (auto const &[detectorId, startX, endX] : m_detectorXList) {
Json::Value detXVal;
detXVal["detId"] = Json::Value(detectorId);
detXVal["startX"] = Json::Value(startX);
detXVal["endX"] = Json::Value(endX);
detXList.append(detXVal);
Json::Value detBinList;
for (auto const &[detectorId, startX, endX] : m_detectorBinList) {
Json::Value detBinVal;
detBinVal["detId"] = Json::Value(detectorId);
detBinVal["startX"] = Json::Value(startX);
detBinVal["endX"] = Json::Value(endX);
detBinList.append(detBinVal);
}

root["detectors"] = detXList;
root["detectors"] = detBinList;
return Mantid::JsonHelpers::jsonToString(root);
}

Expand Down
9 changes: 5 additions & 4 deletions Framework/DataObjects/src/PeakShapeDetectorBinFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ Mantid::Geometry::PeakShape *PeakShapeDetectorBinFactory::create(const std::stri
const int algorithmVersion(root["algorithm_version"].asInt());
const auto frame(static_cast<SpecialCoordinateSystem>(root["frame"].asInt()));

std::vector<std::tuple<int32_t, double, double>> detectorXList;
std::vector<std::tuple<int32_t, double, double>> detectorBinList;
const Json::Value detectorList = root["detectors"];
for (int index = 0; index < detectorList.size(); index++) {
const Json::Value detXVal = detectorList[index];
detectorXList.emplace_back(detXVal["detId"].asInt(), detXVal["startX"].asDouble(), detXVal["endX"].asDouble());
const Json::Value detBinVal = detectorList[index];
detectorBinList.emplace_back(detBinVal["detId"].asInt(), detBinVal["startX"].asDouble(),
detBinVal["endX"].asDouble());
}
peakShape = new PeakShapeDetectorBin(detectorXList, frame, algorithmName, algorithmVersion);
peakShape = new PeakShapeDetectorBin(detectorBinList, frame, algorithmName, algorithmVersion);
} else {
if (m_successor) {
peakShape = m_successor->create(source);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,6 @@ class PeakShapeDetectorBinFactoryTest : public CxxTest::TestSuite {
TS_ASSERT(factoryShape);

TS_ASSERT_EQUALS(shape, *factoryShape);
TS_ASSERT_EQUALS(factoryShape->getDetectorXList(), shape.getDetectorXList())
TS_ASSERT_EQUALS(factoryShape->getDetectorBinList(), shape.getDetectorBinList())
}
};
54 changes: 27 additions & 27 deletions Framework/DataObjects/test/PeakShapeDetectorBinTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,21 @@ class PeakShapeDetectorBinTest : public CxxTest::TestSuite {
static void destroySuite(PeakShapeDetectorBinTest *suite) { delete suite; }

void test_constructor() {
std::vector<std::tuple<int32_t, double, double>> detPeakXList = {
std::vector<std::tuple<int32_t, double, double>> detPeakBinList = {
{100, 20.55, 40.52}, {102, 33.0, 55.67}, {104, 50.9, 70.5}};
std::string algorithmName = "TestSuite";
int version = 1;
auto coordinateSys = SpecialCoordinateSystem::None;

std::shared_ptr<DataObjects::PeakShapeBase> peakShape =
std::make_shared<PeakShapeDetectorBin>(detPeakXList, coordinateSys, algorithmName, version);
std::make_shared<PeakShapeDetectorBin>(detPeakBinList, coordinateSys, algorithmName, version);

TS_ASSERT_EQUALS(algorithmName, peakShape->algorithmName());
TS_ASSERT_EQUALS(version, peakShape->algorithmVersion());
TS_ASSERT_EQUALS(coordinateSys, peakShape->frame());
TS_ASSERT_EQUALS("PeakShapeDetectorBin", peakShape->shapeName());
TS_ASSERT_EQUALS(std::nullopt, peakShape->radius(Mantid::Geometry::PeakShape::RadiusType::Radius));
TS_ASSERT_EQUALS(std::dynamic_pointer_cast<PeakShapeDetectorBin>(peakShape)->getDetectorXList(), detPeakXList);
TS_ASSERT_EQUALS(std::dynamic_pointer_cast<PeakShapeDetectorBin>(peakShape)->getDetectorBinList(), detPeakBinList);

std::shared_ptr<Mantid::Geometry::PeakShape> cloneShape(peakShape->clone());

Expand All @@ -50,14 +50,14 @@ class PeakShapeDetectorBinTest : public CxxTest::TestSuite {
TS_ASSERT_EQUALS(coordinateSys, cloneShape->frame());
TS_ASSERT_EQUALS("PeakShapeDetectorBin", cloneShape->shapeName());
TS_ASSERT_EQUALS(std::nullopt, cloneShape->radius(Mantid::Geometry::PeakShape::RadiusType::Radius));
TS_ASSERT_EQUALS(std::dynamic_pointer_cast<PeakShapeDetectorBin>(cloneShape)->getDetectorXList(), detPeakXList);
TS_ASSERT_EQUALS(std::dynamic_pointer_cast<PeakShapeDetectorBin>(cloneShape)->getDetectorBinList(), detPeakBinList);
}

void test_json_serialization() {
std::vector<std::tuple<int32_t, double, double>> detPeakXList = {
std::vector<std::tuple<int32_t, double, double>> detPeakBinList = {
{100, 20.55, 40.52}, {102, 33.0, 55.67}, {104, 50.9, 70.5}};
std::shared_ptr<DataObjects::PeakShapeBase> peakShape =
std::make_shared<PeakShapeDetectorBin>(detPeakXList, SpecialCoordinateSystem::None, "TestSuite", 1);
std::make_shared<PeakShapeDetectorBin>(detPeakBinList, SpecialCoordinateSystem::None, "TestSuite", 1);

std::string jsonStr = peakShape->toJSON();
Json::Value output;
Expand All @@ -67,48 +67,48 @@ class PeakShapeDetectorBinTest : public CxxTest::TestSuite {
TS_ASSERT_EQUALS(1, output["algorithm_version"].asInt());
TS_ASSERT_EQUALS(0, output["frame"].asInt());

Json::Value detectorXList = output["detectors"];
TS_ASSERT_EQUALS(detectorXList[0]["detId"].asInt(), 100);
TS_ASSERT_EQUALS(detectorXList[0]["startX"].asDouble(), 20.55);
TS_ASSERT_EQUALS(detectorXList[0]["endX"].asDouble(), 40.52);
Json::Value detectorBinList = output["detectors"];
TS_ASSERT_EQUALS(detectorBinList[0]["detId"].asInt(), 100);
TS_ASSERT_EQUALS(detectorBinList[0]["startX"].asDouble(), 20.55);
TS_ASSERT_EQUALS(detectorBinList[0]["endX"].asDouble(), 40.52);

TS_ASSERT_EQUALS(detectorXList[1]["detId"].asInt(), 102);
TS_ASSERT_EQUALS(detectorXList[1]["startX"].asDouble(), 33.0);
TS_ASSERT_EQUALS(detectorXList[1]["endX"].asDouble(), 55.67);
TS_ASSERT_EQUALS(detectorBinList[1]["detId"].asInt(), 102);
TS_ASSERT_EQUALS(detectorBinList[1]["startX"].asDouble(), 33.0);
TS_ASSERT_EQUALS(detectorBinList[1]["endX"].asDouble(), 55.67);

TS_ASSERT_EQUALS(detectorXList[2]["detId"].asInt(), 104);
TS_ASSERT_EQUALS(detectorXList[2]["startX"].asDouble(), 50.9);
TS_ASSERT_EQUALS(detectorXList[2]["endX"].asDouble(), 70.5);
TS_ASSERT_EQUALS(detectorBinList[2]["detId"].asInt(), 104);
TS_ASSERT_EQUALS(detectorBinList[2]["startX"].asDouble(), 50.9);
TS_ASSERT_EQUALS(detectorBinList[2]["endX"].asDouble(), 70.5);
}

void test_constructor_throws() {
std::vector<std::tuple<int32_t, double, double>> detPeakXList = {};
std::vector<std::tuple<int32_t, double, double>> detPeakBinList = {};

TSM_ASSERT_THROWS("Should throw, bad directions",
PeakShapeDetectorBin(detPeakXList, SpecialCoordinateSystem::None, "test", 1);
PeakShapeDetectorBin(detPeakBinList, SpecialCoordinateSystem::None, "test", 1);
, std::invalid_argument &);
}

void test_copy_constructor() {
std::vector<std::tuple<int32_t, double, double>> detPeakXList = {{100, 10, 50}, {200, 34, 55}};
PeakShapeDetectorBin shape1(detPeakXList, SpecialCoordinateSystem::None, "test", 1);
std::vector<std::tuple<int32_t, double, double>> detPeakBinList = {{100, 10, 50}, {200, 34, 55}};
PeakShapeDetectorBin shape1(detPeakBinList, SpecialCoordinateSystem::None, "test", 1);
PeakShapeDetectorBin shape2(shape1);

TS_ASSERT_EQUALS(shape1.getDetectorXList(), detPeakXList);
TS_ASSERT_EQUALS(shape2.getDetectorXList(), detPeakXList);
TS_ASSERT_EQUALS(shape1.getDetectorBinList(), detPeakBinList);
TS_ASSERT_EQUALS(shape2.getDetectorBinList(), detPeakBinList);
TS_ASSERT_EQUALS(shape1, shape2);
}

void test_assignment() {
std::vector<std::tuple<int32_t, double, double>> detPeakXList1 = {{100, 10, 50}, {200, 34, 55}};
PeakShapeDetectorBin shape1(detPeakXList1, SpecialCoordinateSystem::None, "test", 1);
std::vector<std::tuple<int32_t, double, double>> detPeakBinList1 = {{100, 10, 50}, {200, 34, 55}};
PeakShapeDetectorBin shape1(detPeakBinList1, SpecialCoordinateSystem::None, "test", 1);

std::vector<std::tuple<int32_t, double, double>> detPeakXList2 = {{500, 68, 77}};
PeakShapeDetectorBin shape2(detPeakXList2, SpecialCoordinateSystem::None, "test", 1);
std::vector<std::tuple<int32_t, double, double>> detPeakBinList2 = {{500, 68, 77}};
PeakShapeDetectorBin shape2(detPeakBinList2, SpecialCoordinateSystem::None, "test", 1);

shape2 = shape1;

TS_ASSERT_EQUALS(shape2.getDetectorXList(), shape1.getDetectorXList());
TS_ASSERT_EQUALS(shape2.getDetectorBinList(), shape1.getDetectorBinList());
TS_ASSERT_EQUALS(shape2.toJSON(), shape1.toJSON());
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ set(EXPORT_FILES
src/Exports/PeakShapeSpherical.cpp
src/Exports/PeakShapeEllipsoid.cpp
src/Exports/WorkspaceValidators.cpp
src/Exports/PeakShapeDetectorBin.cpp
)

set(MODULE_DEFINITION ${CMAKE_CURRENT_BINARY_DIR}/dataobjects.cpp)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright &copy; 2024 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/PeakShapeDetectorBin.h"
#include "MantidPythonInterface/core/Converters/PySequenceToVector.h"
#include <boost/python/class.hpp>
#include <boost/python/list.hpp>
#include <boost/python/make_constructor.hpp>
#include <boost/python/tuple.hpp>
#include <vector>

using namespace boost::python;
using namespace Mantid::DataObjects;
using Mantid::Kernel::SpecialCoordinateSystem;
using Mantid::PythonInterface::Converters::PySequenceToVector;

PeakShapeDetectorBin *createPeakShapeDetectorBin(const boost::python::list &pyList, SpecialCoordinateSystem frame,
const std::string &algorithmName = std::string(),
int algorithmVersion = -1) {
// Convert Python list of tuples to std::vector<std::tuple<int32_t, double, double>>
std::vector<std::tuple<int32_t, double, double>> detectorBinList;

for (int i = 0; i < boost::python::len(pyList); ++i) {
boost::python::tuple pyTuple = boost::python::extract<boost::python::tuple>(pyList[i]);
int32_t detectorID = boost::python::extract<int32_t>(pyTuple[0]);
double startX = boost::python::extract<double>(pyTuple[1]);
double endX = boost::python::extract<double>(pyTuple[2]);
detectorBinList.emplace_back(detectorID, startX, endX);
}

return new PeakShapeDetectorBin(detectorBinList, frame, algorithmName, algorithmVersion);
}

void export_PeakShapeDetectorBin() {
class_<PeakShapeDetectorBin, bases<Mantid::Geometry::PeakShape>, boost::noncopyable>("PeakShapeDetectorBin", no_init)
.def("__init__", make_constructor(&createPeakShapeDetectorBin, default_call_policies(),
(arg("detectorBinList"), arg("frame") = SpecialCoordinateSystem::None,
arg("algorithmName") = "", arg("algorithmVersion") = -1)));
}
17 changes: 15 additions & 2 deletions Framework/PythonInterface/test/python/mantid/geometry/IPeakTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
# Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
# SPDX - License - Identifier: GPL - 3.0 +
import unittest
from mantid.kernel import V3D
from mantid.dataobjects import NoShape, PeakShapeSpherical, PeakShapeEllipsoid
from mantid.kernel import V3D, SpecialCoordinateSystem
from mantid.dataobjects import NoShape, PeakShapeSpherical, PeakShapeEllipsoid, PeakShapeDetectorBin
from mantid.simpleapi import CreateSimulationWorkspace, CreatePeaksWorkspace, LoadInstrument
import numpy as np
import numpy.testing as npt
import json


class IPeakTest(unittest.TestCase):
Expand Down Expand Up @@ -173,6 +174,8 @@ def test_set_peak_shape(self):
no_shape = NoShape()
sphere = PeakShapeSpherical(1)
ellipse = PeakShapeEllipsoid([V3D(1, 0, 0), V3D(0, 1, 0), V3D(0, 0, 1)], [0.1, 0.2, 0.3], [0.4, 0.5, 0.6], [0.7, 0.8, 0.9])
detectorXList = [(14500, 20.45, 50.89), (45670, 109.88, 409.56), (60995, 56009.89, 70988.89)]
detectorBin = PeakShapeDetectorBin(detectorXList, SpecialCoordinateSystem.NONE, "test", 1)

self.assertEqual(self._peak.getPeakShape().shapeName(), "none")

Expand All @@ -185,6 +188,16 @@ def test_set_peak_shape(self):
self._peak.setPeakShape(no_shape)
self.assertEqual(self._peak.getPeakShape().shapeName(), "none")

self._peak.setPeakShape(detectorBin)
self.assertEqual(self._peak.getPeakShape().shapeName(), "PeakShapeDetectorBin")
self.assertEqual(self._peak.getPeakShape().algorithmVersion(), 1)
self.assertEqual(self._peak.getPeakShape().algorithmName(), "test")
det_bin_dict = json.loads(self._peak.getPeakShape().toJSON())
for i in range(3):
self.assertEqual(det_bin_dict["detectors"][i]["detId"], detectorXList[i][0])
self.assertEqual(det_bin_dict["detectors"][i]["startX"], detectorXList[i][1])
self.assertEqual(det_bin_dict["detectors"][i]["endX"], detectorXList[i][2])


if __name__ == "__main__":
unittest.main()
14 changes: 14 additions & 0 deletions docs/source/api/python/mantid/dataobjects/PeakShapeDetectorBin.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
======================
PeakShapeDetectorBin
======================

This is a Python binding to the C++ class Mantid::DataObjects::PeakShapeDetectorBin.

*bases:* :py:obj:`mantid.geometry.PeakShape`

.. module:`mantid.dataobjects`
.. autoclass:: mantid.dataobjects.PeakShapeDetectorBin
:members:
:undoc-members:
:inherited-members:
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- A new peak shape named PeakShapeDetectorBin was introduced to save the detector IDs and bin indices of either TOF or dSpacing domains. This peak shape could be used for Overlap detection, Two-step integration and Eventual visualisation on instrument view.

0 comments on commit 3454d1c

Please sign in to comment.