Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for multiple oriented lattices to Sample API #36654

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Framework/API/inc/MantidAPI/Sample.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ class MANTID_API_DLL Sample {
/// orientation
void setOrientedLattice(std::unique_ptr<Geometry::OrientedLattice> lattice);
bool hasOrientedLattice() const;

void addOrientedLattice(std::unique_ptr<Geometry::OrientedLattice> lattice);
void setOrientedLattices(std::vector<std::shared_ptr<Geometry::OrientedLattice>> lattices);
std::vector<std::shared_ptr<Geometry::OrientedLattice>> &getOrientedLattices();
const std::vector<std::shared_ptr<Geometry::OrientedLattice>> &getOrientedLattices() const;
//@}

/** @name Access the sample's crystal structure */
Expand Down Expand Up @@ -129,8 +134,8 @@ class MANTID_API_DLL Sample {
Geometry::IObject_sptr m_shape;
/// An owned pointer to the SampleEnvironment object
std::shared_ptr<Geometry::SampleEnvironment> m_environment;
/// Pointer to the OrientedLattice of the sample, NULL if not set.
std::unique_ptr<Geometry::OrientedLattice> m_lattice;
/// Vector of oriented lattices
std::vector<std::shared_ptr<Geometry::OrientedLattice>> m_lattices;

/// CrystalStructure of the sample
std::unique_ptr<Geometry::CrystalStructure> m_crystalStructure;
Expand Down
86 changes: 60 additions & 26 deletions Framework/API/src/Sample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@ using Geometry::ShapeFactory;
* Default constructor. Required for cow_ptr.
*/
Sample::Sample()
: m_name(), m_shape(ShapeFactory().createShape("")), m_environment(), m_lattice(nullptr), m_crystalStructure(),
: m_name(), m_shape(ShapeFactory().createShape("")), m_environment(), m_lattices(), m_crystalStructure(),
m_samples(), m_geom_id(0), m_thick(0.0), m_height(0.0), m_width(0.0) {}

/**
* Copy constructor
* @param copy :: const reference to the sample object
*/
Sample::Sample(const Sample &copy)
: m_name(copy.m_name), m_shape(copy.m_shape), m_environment(copy.m_environment), m_lattice(nullptr),
m_crystalStructure(), m_samples(copy.m_samples), m_geom_id(copy.m_geom_id), m_thick(copy.m_thick),
m_height(copy.m_height), m_width(copy.m_width) {
if (copy.m_lattice)
m_lattice = std::make_unique<OrientedLattice>(copy.getOrientedLattice());
: m_name(copy.m_name), m_shape(copy.m_shape), m_environment(copy.m_environment), m_lattices(), m_crystalStructure(),
m_samples(copy.m_samples), m_geom_id(copy.m_geom_id), m_thick(copy.m_thick), m_height(copy.m_height),
m_width(copy.m_width) {
std::transform(copy.m_lattices.begin(), copy.m_lattices.end(), std::back_inserter(m_lattices),
[](const auto &lattice) { return std::make_shared<Geometry::OrientedLattice>(*lattice); });

if (copy.hasCrystalStructure()) {
m_crystalStructure = std::make_unique<Geometry::CrystalStructure>(copy.getCrystalStructure());
Expand All @@ -66,10 +66,9 @@ Sample &Sample::operator=(const Sample &rhs) {
m_thick = rhs.m_thick;
m_height = rhs.m_height;
m_width = rhs.m_width;
if (rhs.m_lattice)
m_lattice = std::make_unique<OrientedLattice>(rhs.getOrientedLattice());
else
m_lattice.reset(nullptr);
m_lattices = std::vector<std::shared_ptr<Geometry::OrientedLattice>>();
std::transform(rhs.m_lattices.begin(), rhs.m_lattices.end(), std::back_inserter(m_lattices),
[](const auto &lattice) { return std::make_shared<Geometry::OrientedLattice>(*lattice); });

m_crystalStructure.reset();
if (rhs.hasCrystalStructure()) {
Expand Down Expand Up @@ -152,31 +151,62 @@ void Sample::setEnvironment(std::shared_ptr<SampleEnvironment> env) { m_environm
* @throw std::runtime_error If the OrientedLattice has not been defined
*/
const OrientedLattice &Sample::getOrientedLattice() const {
if (!m_lattice) {
if (m_lattices.empty()) {
throw std::runtime_error("Sample::getOrientedLattice - No OrientedLattice has been defined.");
}
return *m_lattice;
return *(m_lattices[0]);
}

/** Return a reference to the OrientedLattice of this sample
* @return A reference to a OrientedLattice object
* @throw std::runtime_error If the OrientedLattice has not been defined
*/
OrientedLattice &Sample::getOrientedLattice() {
if (!m_lattice) {
if (m_lattices.empty()) {
throw std::runtime_error("Sample::getOrientedLattice - No OrientedLattice has been defined.");
}
return *m_lattice;
return *(m_lattices[0]);
}

/** Attach an OrientedLattice onto this sample
*
* @param lattice :: A pointer to a OrientedLattice.
*/
void Sample::setOrientedLattice(std::unique_ptr<Geometry::OrientedLattice> lattice) { m_lattice = std::move(lattice); }
void Sample::setOrientedLattice(std::unique_ptr<Geometry::OrientedLattice> lattice) {
m_lattices.clear();
if (lattice) {
m_lattices.push_back(std::move(lattice));
}
}

/** @return true if the sample has an OrientedLattice */
bool Sample::hasOrientedLattice() const { return (m_lattice != nullptr); }
bool Sample::hasOrientedLattice() const { return !(m_lattices.empty()); }

void Sample::addOrientedLattice(std::unique_ptr<Geometry::OrientedLattice> lattice) {
if (lattice) {
m_lattices.push_back(std::move(lattice));
}
}

void Sample::setOrientedLattices(std::vector<std::shared_ptr<Geometry::OrientedLattice>> lattices) {
m_lattices = std::move(lattices);
}

std::vector<std::shared_ptr<Geometry::OrientedLattice>> &Sample::getOrientedLattices() {
if (m_lattices.empty()) {
throw std::runtime_error("Sample::getOrientedLattices - No OrientedLattice has been defined.");
}

return m_lattices;
}

const std::vector<std::shared_ptr<Geometry::OrientedLattice>> &Sample::getOrientedLattices() const {
if (m_lattices.empty()) {
throw std::runtime_error("Sample::getOrientedLattices - No OrientedLattice has been defined.");
}

return m_lattices;
}

const Geometry::CrystalStructure &Sample::getCrystalStructure() const {
if (!hasCrystalStructure()) {
Expand Down Expand Up @@ -305,7 +335,7 @@ void Sample::saveNexus(::NeXus::File *file, const std::string &group) const {
// OrientedLattice
if (hasOrientedLattice()) {
file->writeData("num_oriented_lattice", 1);
m_lattice->saveNexus(file, "oriented_lattice");
m_lattices[0]->saveNexus(file, "oriented_lattice");
} else
file->writeData("num_oriented_lattice", 0);

Expand Down Expand Up @@ -383,8 +413,9 @@ int Sample::loadNexus(::NeXus::File *file, const std::string &group) {
int num_oriented_lattice;
file->readData("num_oriented_lattice", num_oriented_lattice);
if (num_oriented_lattice > 0) {
m_lattice = std::make_unique<OrientedLattice>();
m_lattice->loadNexus(file, "oriented_lattice");
std::unique_ptr<Geometry::OrientedLattice> lattice = std::make_unique<Geometry::OrientedLattice>();
lattice->loadNexus(file, "oriented_lattice");
setOrientedLattice(std::move(lattice));
}
}

Expand All @@ -405,19 +436,22 @@ int Sample::loadNexus(::NeXus::File *file, const std::string &group) {
/**
* Delete the oriented lattice.
*/
void Sample::clearOrientedLattice() {
if (m_lattice) {
m_lattice.reset(nullptr);
}
}
void Sample::clearOrientedLattice() { m_lattices.clear(); }

bool Sample::operator==(const Sample &other) const {
if (m_samples.size() != other.m_samples.size())
if (m_samples.size() != other.m_samples.size() || m_lattices.size() != other.m_lattices.size())
return false;

for (size_t i = 0; i < m_samples.size(); ++i) {
if (*m_samples[i] != *other.m_samples[i])
return false;
}

for (size_t i = 0; i < m_lattices.size(); ++i) {
if (*m_lattices[i] != *other.m_lattices[i])
return false;
}

auto compare = [](const auto &a, const auto &b, auto call_on) {
// both null or both not null
if (bool(a) ^ bool(b))
Expand All @@ -427,7 +461,7 @@ bool Sample::operator==(const Sample &other) const {
else
return true;
};
return *m_lattice == *other.m_lattice && this->m_name == other.m_name && this->m_height == other.m_height &&
return m_lattices == other.m_lattices && this->m_name == other.m_name && this->m_height == other.m_height &&
this->m_width == other.m_width && this->m_thick == other.m_thick && m_geom_id == other.m_geom_id &&
compare(m_environment, other.m_environment, [](const auto &x) { return x->name(); }) &&
compare(m_shape, other.m_shape, [](const auto &x) { return x->shape(); }) &&
Expand Down
5 changes: 4 additions & 1 deletion Framework/PythonInterface/mantid/api/src/Exports/Sample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ void export_Sample() {
.def("getName", &Sample::getName, return_value_policy<copy_const_reference>(), arg("self"),
"Returns the string name of the sample")
.def("getOrientedLattice", (const OrientedLattice &(Sample::*)() const) & Sample::getOrientedLattice, arg("self"),
return_value_policy<reference_existing_object>(), "Get the oriented lattice for this sample")
return_value_policy<reference_existing_object>(), "Get the first oriented lattice for this sample")
.def("getOrientedLattices",
Copy link
Contributor

@RichardWaiteSTFC RichardWaiteSTFC Jan 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I try ws.sample().getOrientedLattices() I get this error

TypeError: No Python class registered for C++ class class std::vector<class Mantid::Geometry::OrientedLattice,class std::allocator<class Mantid::Geometry::OrientedLattice> >

Copy link
Contributor

@RichardWaiteSTFC RichardWaiteSTFC Jan 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the output has to be converted into a boost::python::list?
Sometimes you have to write a wrapper like this

boost::python::list getEquivalents(const PointGroup &self, const object &hkl) {
const auto &equivalents = self.getEquivalents(Converters::PyObjectToV3D(hkl)());
boost::python::list pythonEquivalents;
for (const auto &equivalent : equivalents) {
pythonEquivalents.append(equivalent);
}
return pythonEquivalents;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right, I will add this converter

(const std::vector<std::shared_ptr<OrientedLattice>> &(Sample::*)() const) & Sample::getOrientedLattices,
return_value_policy<reference_existing_object>(), "Get the oriented lattices for this sample")
.def("hasOrientedLattice", &Sample::hasOrientedLattice, arg("self"),
"Returns True if this sample has an oriented lattice, false "
"otherwise")
Expand Down
6 changes: 3 additions & 3 deletions buildconfig/CMake/CppCheck_Suppressions.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,8 @@ constVariablePointer:${CMAKE_SOURCE_DIR}/Framework/API/src/Run.cpp:302
constVariablePointer:${CMAKE_SOURCE_DIR}/Framework/API/src/Run.cpp:668
constVariablePointer:${CMAKE_SOURCE_DIR}/Framework/API/src/Run.cpp:701
uselessOverride:${CMAKE_SOURCE_DIR}/Framework/Geometry/inc/MantidGeometry/Crystal/BraggScatterer.h:71
knownConditionTrueFalse:${CMAKE_SOURCE_DIR}/Framework/API/src/Sample.cpp:338
knownConditionTrueFalse:${CMAKE_SOURCE_DIR}/Framework/API/src/Sample.cpp:347
knownConditionTrueFalse:${CMAKE_SOURCE_DIR}/Framework/API/src/Sample.cpp:368
knownConditionTrueFalse:${CMAKE_SOURCE_DIR}/Framework/API/src/Sample.cpp:377
constVariableReference:${CMAKE_SOURCE_DIR}/Framework/API/src/ScriptBuilder.cpp:209
constVariableReference:${CMAKE_SOURCE_DIR}/Framework/API/src/MultiPeriodGroupWorker.cpp:91
constParameterPointer:${CMAKE_SOURCE_DIR}/Framework/API/src/MultiPeriodGroupWorker.cpp:151
Expand Down Expand Up @@ -919,7 +919,7 @@ passedByValue:${CMAKE_SOURCE_DIR}/Framework/PythonInterface/mantid/api/src/Expor
passedByValue:${CMAKE_SOURCE_DIR}/Framework/PythonInterface/mantid/api/src/Exports/IPeak.cpp:36
passedByValue:${CMAKE_SOURCE_DIR}/Framework/PythonInterface/mantid/api/src/Exports/IPeak.cpp:41
passedByValue:${CMAKE_SOURCE_DIR}/Framework/PythonInterface/mantid/api/src/Exports/IPeak.cpp:46
syntaxError:${CMAKE_SOURCE_DIR}/Framework/PythonInterface/mantid/api/src/Exports/Sample.cpp:81
syntaxError:${CMAKE_SOURCE_DIR}/Framework/PythonInterface/mantid/api/src/Exports/Sample.cpp:84
syntaxError:${CMAKE_SOURCE_DIR}/Framework/PythonInterface/mantid/api/src/Exports/Run.cpp:251
unknownMacro:${CMAKE_SOURCE_DIR}/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceFactory.cpp:58
unknownMacro:${CMAKE_SOURCE_DIR}/Framework/PythonInterface/mantid/api/src/Exports/IFunction.cpp:90
Expand Down