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"
17
18namespace Mantid::Crystal {
19// Register the algorithm into the AlgorithmFactory
20DECLARE_ALGORITHM(CombinePeaksWorkspaces)
21
22using namespace Kernel;
23using namespace API;
24
26const std::string CombinePeaksWorkspaces::name() const { return "CombinePeaksWorkspaces"; }
28int CombinePeaksWorkspaces::version() const { return 1; }
30const std::string CombinePeaksWorkspaces::category() const { return "Crystal\\Peaks"; }
31
35 declareProperty(std::make_unique<WorkspaceProperty<IPeaksWorkspace>>("LHSWorkspace", "", Direction::Input),
36 "The first set of peaks.");
37 declareProperty(std::make_unique<WorkspaceProperty<IPeaksWorkspace>>("RHSWorkspace", "", Direction::Input),
38 "The second set of peaks.");
39 declareProperty(std::make_unique<WorkspaceProperty<IPeaksWorkspace>>("OutputWorkspace", "", Direction::Output),
40 "The combined peaks list.");
41
42 declareProperty("CombineMatchingPeaks", false,
43 "Whether to combine peaks that are identical across the two workspaces");
44 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
45 mustBePositive->setLower(0.0);
46 // N.B. Andrei reckons it should be delta_q/q
47 declareProperty("Tolerance", EMPTY_DBL(), mustBePositive,
48 "Maximum difference in each component of Q for which peaks "
49 "are considered identical");
50 setPropertySettings("Tolerance", std::make_unique<EnabledWhenProperty>("CombineMatchingPeaks", IS_EQUAL_TO, "1"));
51}
52
56 IPeaksWorkspace_const_sptr LHSWorkspace = getProperty("LHSWorkspace");
57 IPeaksWorkspace_const_sptr RHSWorkspace = getProperty("RHSWorkspace");
58
59 const bool CombineMatchingPeaks = getProperty("CombineMatchingPeaks");
60
61 // Warn if not the same instrument, sample
62 if (LHSWorkspace->getInstrument()->getName() != RHSWorkspace->getInstrument()->getName()) {
63 g_log.warning("The two input workspaces do not appear to come from data "
64 "take on the same instrument");
65 }
66 if (LHSWorkspace->sample().getName() != RHSWorkspace->sample().getName()) {
67 g_log.warning("The two input workspaces do not appear to relate to the same sample");
68 }
69
70 // Copy the first workspace to our output workspace
71 IPeaksWorkspace_sptr output(LHSWorkspace->clone());
72 // Get hold of the peaks in the second workspace
73 const int rhs_n_peaks = RHSWorkspace->getNumberPeaks();
74
75 Progress progress(this, 0.0, 1.0, rhs_n_peaks);
76
77 // Combine modulation vectors
78 // Currently, the lattice can only support up to 3 modulation vectors. If any
79 // more than that are combined, a warning is shown and the LHS values are
80 // used.
81 try {
82 std::vector<Kernel::V3D> rhsModVectors;
83 std::vector<Kernel::V3D> lhsModVectors;
84
85 // Collect modulation vectors for both workspaces.
86 for (int i = 0; i < 3; ++i) { // Currently contains up to 3 vectors.
87 const auto modVecR = RHSWorkspace->sample().getOrientedLattice().getModVec(i);
88 // Each vector contains 3 values, check that at least one is not 0.
89 if (!(modVecR[0] == 0 && modVecR[1] == 0 && modVecR[2] == 0)) {
90 rhsModVectors.push_back(modVecR);
91 }
92 const auto modVecL = LHSWorkspace->sample().getOrientedLattice().getModVec(i);
93 if (!(modVecL[0] == 0 && modVecL[1] == 0 && modVecL[2] == 0)) {
94 lhsModVectors.push_back(modVecL);
95 }
96 }
97
98 // Add only unique mod vectors from the rhs list to the lhs list.
99 std::remove_copy_if(rhsModVectors.begin(), rhsModVectors.end(), back_inserter(lhsModVectors),
100 [lhsModVectors](Kernel::V3D modVec) {
101 return lhsModVectors.end() != std::find(lhsModVectors.begin(), lhsModVectors.end(), modVec);
102 });
103
104 // Hard limit of 3 mod vectors until PeaksWorkspace is refactored.
105 if (lhsModVectors.size() > 3) {
106 g_log.warning("There are too many modulation vectors. Using vectors from "
107 "LHSWorkspace");
108 } else {
109 // This is horrible, but setting mod vectors has to be done by 3 separate
110 // methods.
111 for (size_t i = 0; i < lhsModVectors.size(); ++i) {
112 if (i == 0) {
113 output->mutableSample().getOrientedLattice().setModVec1(lhsModVectors[i]);
114 } else if (i == 1) {
115 output->mutableSample().getOrientedLattice().setModVec2(lhsModVectors[i]);
116 } else if (i == 2) {
117 output->mutableSample().getOrientedLattice().setModVec3(lhsModVectors[i]);
118 }
119 }
120 }
121 } catch (std::runtime_error &e) {
122 g_log.error() << "Failed to combine modulation vectors with the following "
123 "error: "
124 << e.what();
125 }
126
127 // If not checking for matching peaks, then it's easy...
128 if (!CombineMatchingPeaks) {
129 // Loop over the peaks in the second workspace, appending each one to the
130 // output
131 for (int i = 0; i < rhs_n_peaks; i++) {
132 output->addPeak(RHSWorkspace->getPeak(i));
133 progress.report();
134 }
135 } else // Check for matching peaks
136 {
137 const double Tolerance = getProperty("Tolerance");
138
139 // Get hold of the peaks in the first workspace as we'll need to examine
140 // them
141 const int lhs_n_peaks = LHSWorkspace->getNumberPeaks();
142 std::vector<V3D> q_vectors;
143 for (int i = 0; i < lhs_n_peaks; i++)
144 q_vectors.emplace_back(LHSWorkspace->getPeak(i).getQSampleFrame());
145
146 // Loop over the peaks in the second workspace, appending ones that don't
147 // match any in first workspace
148 for (int j = 0; j < rhs_n_peaks; j++) {
149 const Geometry::IPeak &currentPeak = RHSWorkspace->getPeak(j);
150 // Now have to go through the first workspace checking for matches
151 // Not doing anything clever as peaks workspace are typically not large -
152 // just a linear search
153 bool match = false;
154 for (int i = 0; i < lhs_n_peaks; i++) {
155 const V3D deltaQ = currentPeak.getQSampleFrame() - q_vectors[i];
156 if (deltaQ.nullVector(Tolerance)) // Using a V3D method that does the job
157 {
158 match = true;
159 break;
160 }
161 }
162 // Only add the peak if there was no match
163 if (!match)
164 output->addPeak(currentPeak);
165 progress.report();
166 }
167 }
168
169 setProperty("OutputWorkspace", output);
170}
171
172} // namespace Mantid::Crystal
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:422
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
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:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
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:238
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:42
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54