25#include <boost/math/special_functions/round.hpp>
47 auto latticeValidator = std::make_shared<OrientedLatticeValidator>();
49 "Workspace of Peaks with orientation matrix that indexed the peaks and "
53 "Workspace of Peaks with peaks with fractional h,k, and/or l values");
57 declareProperty(
"GetModVectorsFromUB",
false,
"If false Modulation Vectors will be read from input");
59 declareProperty(
"IncludeIntegerHKL",
true,
"If false order 0 peaks are not included in workspace (integer HKL)");
62 "If false only offsets from "
63 "peaks from Peaks workspace "
67 "Minimum wavelength limit at which to start looking for "
68 "single-crystal peaks.");
70 "Maximum wavelength limit at which to start looking for "
71 "single-crystal peaks.");
73 "Minimum d-spacing of peaks to consider. Default = 0.1");
75 "Maximum d-spacing of peaks to consider");
77 setPropertySettings(
"WavelengthMin", std::make_unique<Kernel::EnabledWhenProperty>(
string(
"IncludeAllPeaksInRange"),
80 setPropertySettings(
"WavelengthMax", std::make_unique<Kernel::EnabledWhenProperty>(
string(
"IncludeAllPeaksInRange"),
82 setPropertySettings(
"MinDSpacing", std::make_unique<Kernel::EnabledWhenProperty>(
string(
"IncludeAllPeaksInRange"),
85 setPropertySettings(
"MaxDSpacing", std::make_unique<Kernel::EnabledWhenProperty>(
string(
"IncludeAllPeaksInRange"),
91 bool includePeaksInRange =
getProperty(
"IncludeAllPeaksInRange");
95 throw std::invalid_argument(
"Input workspace is not a IPeaksWorkspace. Type=" +
Peaks->id());
96 if (!includePeaksInRange) {
106 bool includeOrderZero =
getProperty(
"IncludeIntegerHKL");
108 bool notOrderZero =
false;
115 offsets1 = lattice->getModVec(0);
116 offsets2 = lattice->getModVec(1);
117 offsets3 = lattice->getModVec(2);
122 lattice->setModVec1(offsets1);
123 lattice->setModVec2(offsets2);
124 lattice->setModVec3(offsets3);
131 outPeaks->mutableSample().setOrientedLattice(std::move(lattice));
136 const double lambdaMin =
getProperty(
"WavelengthMin");
137 const double lambdaMax =
getProperty(
"WavelengthMax");
139 std::vector<V3D> possibleHKLs;
143 auto dSpacingFilter = std::make_shared<HKLFilterDRange>(
outPeaks->sample().getOrientedLattice(), dMin, dMax);
146 g_log.
information() <<
"HKL range for d_min of " << dMin <<
" to d_max of " << dMax <<
" is from " << hkl_begin
147 <<
" to " << hkl_begin * -1.0 <<
", a total of " << gen.
size() <<
" possible HKL's\n";
149 throw std::invalid_argument(
"More than 10 billion HKLs to search. Is "
150 "your d_min value too small?");
152 possibleHKLs.clear();
153 possibleHKLs.reserve(gen.
size());
154 std::remove_copy_if(gen.
begin(), gen.
end(), std::back_inserter(possibleHKLs), (~dSpacingFilter)->fn());
156 size_t N = possibleHKLs.size();
157 N = max<size_t>(100, N);
158 const auto &UB =
outPeaks->sample().getOrientedLattice().getUB();
159 goniometer =
Peaks->run().getGoniometerMatrix();
160 int runNumber =
Peaks->getRunNumber();
162 vector<vector<int>> alreadyDonePeaks;
163 auto orientedUB = goniometer * UB;
165 outPeaks->mutableRun().addProperty<std::vector<double>>(
"Offset1", offsets1,
true);
166 outPeaks->mutableRun().addProperty<std::vector<double>>(
"Offset2", offsets2,
true);
167 outPeaks->mutableRun().addProperty<std::vector<double>>(
"Offset3", offsets3,
true);
168 for (
auto &hkl : possibleHKLs) {
171 includePeaksInRange, includeOrderZero, alreadyDonePeaks);
174 includeOrderZero, alreadyDonePeaks);
175 predictOffsets(1, offsets2,
maxOrder, runNumber, goniometer, hkl, lambdaFilter, includePeaksInRange, notOrderZero,
177 predictOffsets(2, offsets3,
maxOrder, runNumber, goniometer, hkl, lambdaFilter, includePeaksInRange, notOrderZero,
183 std::vector<std::pair<std::string, bool>> criteria;
184 criteria.emplace_back(
"RunNumber",
true);
185 auto isPeaksWorkspace = std::dynamic_pointer_cast<PeaksWorkspace>(
outPeaks);
186 if (isPeaksWorkspace)
187 criteria.emplace_back(
"BankName",
true);
188 criteria.emplace_back(
"h",
true);
189 criteria.emplace_back(
"k",
true);
190 criteria.emplace_back(
"l",
true);
193 for (
int i = 0; i < static_cast<int>(
outPeaks->getNumberPeaks()); ++i) {
194 outPeaks->getPeak(i).setPeakNumber(i);
213 offsets1 = lattice->getModVec(0);
214 offsets2 = lattice->getModVec(1);
215 offsets3 = lattice->getModVec(2);
220 lattice->setModVec1(offsets1);
221 lattice->setModVec2(offsets2);
222 lattice->setModVec3(offsets3);
227 bool includePeaksInRange =
false;
228 bool includeOrderZero =
getProperty(
"IncludeIntegerHKL");
230 bool notOrderZero =
false;
232 if (
Peaks->getNumberPeaks() <= 0) {
233 g_log.
error() <<
"There are No peaks in the input PeaksWorkspace\n";
239 outPeaks->mutableSample().setOrientedLattice(std::move(lattice));
241 vector<vector<int>> alreadyDonePeaks;
243 outPeaks->mutableRun().addProperty<std::vector<double>>(
"Offset1", offsets1,
true);
244 outPeaks->mutableRun().addProperty<std::vector<double>>(
"Offset2", offsets2,
true);
245 outPeaks->mutableRun().addProperty<std::vector<double>>(
"Offset3", offsets3,
true);
247 for (
int i = 0; i < static_cast<int>(
Peaks->getNumberPeaks()); ++i) {
251 int runNumber =
Peaks->getPeak(i).getRunNumber();
253 V3D hkl =
Peaks->getPeak(i).getHKL();
257 lambdaFilter, includePeaksInRange, includeOrderZero, alreadyDonePeaks);
259 predictOffsets(0, offsets1,
maxOrder, runNumber, peakGoniometerMatrix, hkl, lambdaFilter, includePeaksInRange,
260 includeOrderZero, alreadyDonePeaks);
262 predictOffsets(1, offsets2,
maxOrder, runNumber, peakGoniometerMatrix, hkl, lambdaFilter, includePeaksInRange,
263 notOrderZero, alreadyDonePeaks);
265 predictOffsets(2, offsets3,
maxOrder, runNumber, peakGoniometerMatrix, hkl, lambdaFilter, includePeaksInRange,
266 notOrderZero, alreadyDonePeaks);
271 std::vector<std::pair<std::string, bool>> criteria;
272 criteria.emplace_back(
"RunNumber",
true);
276 criteria.emplace_back(
"BankName",
true);
279 criteria.emplace_back(
"h",
true);
280 criteria.emplace_back(
"k",
true);
281 criteria.emplace_back(
"l",
true);
284 for (
int i = 0; i < static_cast<int>(
outPeaks->getNumberPeaks()); ++i) {
285 outPeaks->getPeak(i).setPeakNumber(i);
293 if (std::dynamic_pointer_cast<PeaksWorkspace>(iPeaksWorkspace) !=
nullptr) {
297 else if (std::dynamic_pointer_cast<LeanElasticPeaksWorkspace>(iPeaksWorkspace) !=
nullptr) {
309 const bool includePeaksInRange,
const bool includeOrderZero,
310 vector<vector<int>> &alreadyDonePeaks) {
311 if (offsets ==
V3D(0, 0, 0) && !includeOrderZero)
314 if (order == 0 && !includeOrderZero)
316 V3D satelliteHKL(hkl);
318 satelliteHKL += offsets * order;
319 if (!lambdaFilter.
isAllowed(satelliteHKL) && includePeaksInRange)
325 mnp[indexModulatedVector] = order;
335 const bool includePeaksInRange,
const bool includeOrderZero,
336 vector<vector<int>> &alreadyDonePeaks) {
337 if (offsets1 ==
V3D(0, 0, 0) && offsets2 ==
V3D(0, 0, 0) && offsets3 ==
V3D(0, 0, 0) && !includeOrderZero)
344 if (offsets1 ==
V3D(0, 0, 0))
347 if (offsets2 ==
V3D(0, 0, 0))
350 if (offsets3 ==
V3D(0, 0, 0))
352 for (
int m = -maxOrder1;
m <= maxOrder1;
m++)
353 for (
int n = -maxOrder2;
n <= maxOrder2;
n++)
354 for (
int p = -maxOrder3; p <= maxOrder3; p++) {
355 if (
m == 0 &&
n == 0 && p == 0 && !includeOrderZero)
357 V3D satelliteHKL(hkl);
359 satelliteHKL -= offsetsMat * mnp;
360 if (!lambdaFilter.
isAllowed(satelliteHKL) && includePeaksInRange)
370std::shared_ptr<Geometry::IPeak>
383 std::shared_ptr<IPeak> satellite_iPeak =
Peaks->createPeak(Qs, 1);
385 return satellite_iPeak;
391 std::shared_ptr<IPeak> satellite_iPeak =
Peaks->createPeakQSample(Qs);
393 return satellite_iPeak;
404 std::vector<std::vector<int>> &alreadyDonePeaks,
406 if (satellite_iPeak ==
nullptr)
414 const std::shared_ptr<Peak> peak = std::dynamic_pointer_cast<Peak>(satellite_iPeak);
416 if (!peak->findDetector(tracer))
420 const std::vector<int> savPk{runNumber, boost::math::iround(1000.0 * satelliteHKL[0]),
421 boost::math::iround(1000.0 * satelliteHKL[1]),
422 boost::math::iround(1000.0 * satelliteHKL[2])};
424 const bool foundPeak = binary_search(alreadyDonePeaks.begin(), alreadyDonePeaks.end(), savPk);
427 alreadyDonePeaks.emplace_back(savPk);
433 satellite_iPeak->setGoniometerMatrix(peak_goniometer_matrix);
436 satellite_iPeak->setRunNumber(runNumber);
439 outPeaks->addPeak(*satellite_iPeak);
446 if (offsets.empty()) {
447 offsets.emplace_back(0.0);
448 offsets.emplace_back(0.0);
449 offsets.emplace_back(0.0);
451 V3D offsets1 =
V3D(offsets[0], offsets[1], offsets[2]);
#define DECLARE_ALGORITHM(classname)
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.
Helper class for reporting progress from algorithms.
This class stores information about the sample used in particular run.
const Geometry::OrientedLattice & getOrientedLattice() const
Get a reference to the sample's OrientedLattice.
A property class for workspaces.
PredictSatellitePeaks : Algorithm to create a PeaksWorkspace with peaks corresponding to fractional h...
const size_t MAX_NUMBER_HKLS
void predictOffsetsWithCrossTerms(Kernel::V3D offsets1, Kernel::V3D offsets2, Kernel::V3D offsets3, const int maxOrder, const int RunNumber, Kernel::Matrix< double > const &peakGoniometerMatrix, Kernel::V3D &hkl, const Geometry::HKLFilterWavelength &lambdaFilter, const bool includePeaksInRange, const bool includeOrderZero, std::vector< std::vector< int > > &alreadyDonePeaks)
double m_qConventionFactor
workspace_type_enum determineWorkspaceType(const API::IPeaksWorkspace_sptr &iPeaksWorkspace) const
void init() override
Initialise the properties.
std::shared_ptr< Geometry::IPeak > createPeakForOutputWorkspace(const Kernel::Matrix< double > &peakGoniometerMatrix, const Kernel::V3D &satelliteHKL)
API::IPeaksWorkspace_sptr outPeaks
void predictOffsets(const int indexModulatedVector, const Kernel::V3D &offsets, const int maxOrder, const int runNumber, const Kernel::Matrix< double > &goniometer, const Kernel::V3D &hkl, const Geometry::HKLFilterWavelength &lambdaFilter, const bool includePeaksInRange, const bool includeOrderZero, std::vector< std::vector< int > > &alreadyDonePeaks)
void addPeakToOutputWorkspace(const std::shared_ptr< Geometry::IPeak > &iPeak, const Kernel::Matrix< double > &peak_goniometer_matrix, const Kernel::V3D &hkl, const Kernel::V3D &satelliteHKL, const int runNumber, std::vector< std::vector< int > > &alreadyDonePeaks, const Kernel::V3D &mnp)
void exec() override
Run the algorithm.
Kernel::V3D getOffsetVector(const std::string &label)
API::IPeaksWorkspace_sptr Peaks
bool isAllowed(const Kernel::V3D &hkl) const noexcept override
Returns true if lambda of the reflection is within the limits.
const const_iterator & end() const
Returns an iterator which "points at" one element past the end.
const const_iterator & begin() const
Returns an iterator to the beginning of the sequence.
size_t size() const
Returns the number of HKLs to be generated.
This class is responsible for tracking rays and accumulating a list of objects that are intersected a...
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.
void information(const std::string &msg)
Logs at information level.
void identityMatrix()
Makes the matrix an idenity matrix.
void setColumn(const size_t nCol, const std::vector< T > &newCol)
The concrete, templated class for properties.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
constexpr double Z() const noexcept
Get z.
std::shared_ptr< IPeaksWorkspace > IPeaksWorkspace_sptr
shared pointer to Mantid::API::IPeaksWorkspace
double qConventionFactor()
convenience overload to pull the convention from the config service
Mantid::Kernel::Matrix< double > DblMatrix
Helper class which provides the Collimation Length for SANS instruments.
static const std::string ModVector3
static const std::string MaxOrder
static const std::string ModVector2
static const std::string CrossTerms
static const std::string ModVector1
static void appendTo(API::IAlgorithm *alg)
Append the common set of properties that relate to modulation vectors to the given algorithm.
@ Input
An input workspace.
@ Output
An output workspace.