Mantid
Loading...
Searching...
No Matches
CombinePeaksWorkspaces.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
9#include "MantidAPI/Sample.h"
16
17namespace Mantid::Crystal {
18// Register the algorithm into the AlgorithmFactory
19DECLARE_ALGORITHM(CombinePeaksWorkspaces)
20
21using namespace Kernel;
22using namespace API;
23
25const std::string CombinePeaksWorkspaces::name() const { return "CombinePeaksWorkspaces"; }
27int CombinePeaksWorkspaces::version() const { return 1; }
29const std::string CombinePeaksWorkspaces::category() const { return "Crystal\\Peaks"; }
30
34 declareProperty(std::make_unique<WorkspaceProperty<IPeaksWorkspace>>("LHSWorkspace", "", Direction::Input),
35 "The first set of peaks.");
36 declareProperty(std::make_unique<WorkspaceProperty<IPeaksWorkspace>>("RHSWorkspace", "", Direction::Input),
37 "The second set of peaks.");
38 declareProperty(std::make_unique<WorkspaceProperty<IPeaksWorkspace>>("OutputWorkspace", "", Direction::Output),
39 "The combined peaks list.");
40
41 declareProperty("CombineMatchingPeaks", false,
42 "Whether to combine peaks that are identical across the two workspaces");
43 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
44 mustBePositive->setLower(0.0);
45 // N.B. Andrei reckons it should be delta_q/q
46 declareProperty("Tolerance", EMPTY_DBL(), mustBePositive,
47 "Maximum difference in each component of Q for which peaks "
48 "are considered identical");
49 setPropertySettings("Tolerance", std::make_unique<EnabledWhenProperty>("CombineMatchingPeaks", IS_EQUAL_TO, "1"));
50}
51
55 IPeaksWorkspace_const_sptr LHSWorkspace = getProperty("LHSWorkspace");
56 IPeaksWorkspace_const_sptr RHSWorkspace = getProperty("RHSWorkspace");
57
58 const bool CombineMatchingPeaks = getProperty("CombineMatchingPeaks");
59
60 // Warn if not the same instrument, sample
61 if (LHSWorkspace->getInstrument()->getName() != RHSWorkspace->getInstrument()->getName()) {
62 g_log.warning("The two input workspaces do not appear to come from data "
63 "take on the same instrument");
64 }
65 if (LHSWorkspace->sample().getName() != RHSWorkspace->sample().getName()) {
66 g_log.warning("The two input workspaces do not appear to relate to the same sample");
67 }
68
69 // Copy the first workspace to our output workspace
70 IPeaksWorkspace_sptr output(LHSWorkspace->clone());
71 // Get hold of the peaks in the second workspace
72 const int rhs_n_peaks = RHSWorkspace->getNumberPeaks();
73
74 Progress progress(this, 0.0, 1.0, rhs_n_peaks);
75
76 // Combine modulation vectors
77 // Currently, the lattice can only support up to 3 modulation vectors. If any
78 // more than that are combined, a warning is shown and the LHS values are
79 // used.
80 try {
81 std::vector<Kernel::V3D> rhsModVectors;
82 std::vector<Kernel::V3D> lhsModVectors;
83
84 // Collect modulation vectors for both workspaces.
85 for (int i = 0; i < 3; ++i) { // Currently contains up to 3 vectors.
86 const auto modVecR = RHSWorkspace->sample().getOrientedLattice().getModVec(i);
87 // Each vector contains 3 values, check that at least one is not 0.
88 if (!(modVecR[0] == 0 && modVecR[1] == 0 && modVecR[2] == 0)) {
89 rhsModVectors.push_back(modVecR);
90 }
91 const auto modVecL = LHSWorkspace->sample().getOrientedLattice().getModVec(i);
92 if (!(modVecL[0] == 0 && modVecL[1] == 0 && modVecL[2] == 0)) {
93 lhsModVectors.push_back(modVecL);
94 }
95 }
96
97 // Add only unique mod vectors from the rhs list to the lhs list.
98 std::remove_copy_if(rhsModVectors.begin(), rhsModVectors.end(), back_inserter(lhsModVectors),
99 [lhsModVectors](Kernel::V3D modVec) {
100 return lhsModVectors.end() != std::find(lhsModVectors.begin(), lhsModVectors.end(), modVec);
101 });
102
103 // Hard limit of 3 mod vectors until PeaksWorkspace is refactored.
104 if (lhsModVectors.size() > 3) {
105 g_log.warning("There are too many modulation vectors. Using vectors from "
106 "LHSWorkspace");
107 } else {
108 // This is horrible, but setting mod vectors has to be done by 3 separate
109 // methods.
110 for (size_t i = 0; i < lhsModVectors.size(); ++i) {
111 if (i == 0) {
112 output->mutableSample().getOrientedLattice().setModVec1(lhsModVectors[i]);
113 } else if (i == 1) {
114 output->mutableSample().getOrientedLattice().setModVec2(lhsModVectors[i]);
115 } else if (i == 2) {
116 output->mutableSample().getOrientedLattice().setModVec3(lhsModVectors[i]);
117 }
118 }
119 }
120 } catch (std::runtime_error &e) {
121 g_log.error() << "Failed to combine modulation vectors with the following "
122 "error: "
123 << e.what();
124 }
125
126 // If not checking for matching peaks, then it's easy...
127 if (!CombineMatchingPeaks) {
128 // Loop over the peaks in the second workspace, appending each one to the
129 // output
130 for (int i = 0; i < rhs_n_peaks; i++) {
131 output->addPeak(RHSWorkspace->getPeak(i));
132 progress.report();
133 }
134 } else // Check for matching peaks
135 {
136 const double Tolerance = getProperty("Tolerance");
137
138 // Get hold of the peaks in the first workspace as we'll need to examine
139 // them
140 const int lhs_n_peaks = LHSWorkspace->getNumberPeaks();
141 std::vector<V3D> q_vectors;
142 for (int i = 0; i < lhs_n_peaks; i++)
143 q_vectors.emplace_back(LHSWorkspace->getPeak(i).getQSampleFrame());
144
145 // Loop over the peaks in the second workspace, appending ones that don't
146 // match any in first workspace
147 for (int j = 0; j < rhs_n_peaks; j++) {
148 const Geometry::IPeak &currentPeak = RHSWorkspace->getPeak(j);
149 // Now have to go through the first workspace checking for matches
150 // Not doing anything clever as peaks workspace are typically not large -
151 // just a linear search
152 bool match = false;
153 for (int i = 0; i < lhs_n_peaks; i++) {
154 const V3D deltaQ = currentPeak.getQSampleFrame() - q_vectors[i];
155 if (deltaQ.nullVector(Tolerance)) // Using a V3D method that does the job
156 {
157 match = true;
158 break;
159 }
160 }
161 // Only add the peak if there was no match
162 if (!match)
163 output->addPeak(currentPeak);
164 progress.report();
165 }
166 }
167
168 setProperty("OutputWorkspace", output);
169}
170
171} // namespace Mantid::Crystal
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
Kernel::Logger & g_log
Definition: Algorithm.h:451
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
const std::string category() const override
Algorithm's category for identification.
const std::string name() const override
Algorithm's name for identification.
int version() const override
Algorithm's version for identification.
void init() override
Initialises the algorithm's properties.
void exec() override
Executes the algorithm.
Structure describing a single-crystal peak.
Definition: IPeak.h:26
virtual Mantid::Kernel::V3D getQSampleFrame() const =0
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
Class for 3D vectors.
Definition: V3D.h:34
bool nullVector(const double tolerance=1e-3) const noexcept
Determine if the point is null.
Definition: V3D.cpp:241
std::shared_ptr< IPeaksWorkspace > IPeaksWorkspace_sptr
shared pointer to Mantid::API::IPeaksWorkspace
std::shared_ptr< const IPeaksWorkspace > IPeaksWorkspace_const_sptr
shared pointer to Mantid::API::IPeaksWorkspace (const version)
constexpr double Tolerance
Standard tolerance value.
Definition: Tolerance.h:12
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54